From 6893f3428957367d9e514af4378357dddc04d0c6 Mon Sep 17 00:00:00 2001 From: Myles Date: Thu, 31 Mar 2016 22:45:15 +0100 Subject: [PATCH] Support reloading to some extent, if you use protocol lib it will kick all your players... (So you probably should just get a PluginManager...) One day i'll fully patch to work... (If I don't kick the players it ends up that ProtocolLib implodes and nobody can connect.) --- .../us/myles/ViaVersion/ViaVersionPlugin.java | 70 ++++++++++++++++--- .../ViaVersion/handlers/ViaDecodeHandler.java | 1 + .../handlers/ViaVersionInitializer.java | 10 ++- .../us/myles/ViaVersion/util/ListWrapper.java | 4 ++ 4 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index dccebeade..fc144eb77 100644 --- a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java +++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -9,6 +9,7 @@ import lombok.NonNull; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import us.myles.ViaVersion.api.Pair; import us.myles.ViaVersion.api.ViaVersion; import us.myles.ViaVersion.api.ViaVersionAPI; import us.myles.ViaVersion.api.ViaVersionConfig; @@ -31,6 +32,7 @@ import us.myles.ViaVersion.util.ReflectionUtil; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -42,19 +44,36 @@ import java.util.concurrent.TimeUnit; public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVersionConfig { private final Map portedPlayers = new ConcurrentHashMap<>(); + private List injectedFutures = new ArrayList<>(); + private List> injectedLists = new ArrayList<>(); private ViaCommandHandler commandHandler; private boolean debug = false; @Override - public void onEnable() { + public void onLoad() { ViaVersion.setInstance(this); generateConfig(); if (System.getProperty("ViaVersion") != null) { - getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update."); - getLogger().severe("Some features may not work."); - return; + if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) { + getLogger().severe("ViaVersion is already loaded, we're going to kick all the players... because otherwise we'll crash because of ProtocolLib."); + for (Player player : Bukkit.getOnlinePlayers()) { + player.kickPlayer("Server reload, please rejoin!"); + } + + } else { + getLogger().severe("ViaVersion is already loaded, this should work fine... Otherwise reboot the server!!!"); + + } } + getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded, injecting."); + injectPacketHandler(); + } + + @Override + public void onEnable() { + if (isCheckForUpdates()) + UpdateUtil.sendUpdateMessage(this); // Gather version :) Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @Override @@ -70,12 +89,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe } }); - getLogger().info("ViaVersion " + getDescription().getVersion() + " is now enabled, injecting."); - injectPacketHandler(); - - - if (isCheckForUpdates()) - UpdateUtil.sendUpdateMessage(this); Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this); @@ -83,6 +96,12 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe getCommand("viaversion").setTabCompleter(commandHandler); } + @Override + public void onDisable() { + getLogger().info("ViaVersion is disabling, if this is a reload it may not work."); + uninject(); + } + public void gatherProtocolVersion() { try { Class serverClazz = ReflectionUtil.nms("MinecraftServer"); @@ -185,6 +204,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe } } }; + injectedLists.add(new Pair<>(field, connection)); field.set(connection, wrapper); // Iterate through current list synchronized (wrapper) { @@ -213,6 +233,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe ChannelInitializer newInit = new ViaVersionInitializer(oldInit); ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit); + injectedFutures.add(future); } catch (NoSuchFieldException e) { // field not found throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName()); @@ -223,6 +244,35 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe } } + private void uninject() { + // TODO: Uninject from players currently online to prevent protocol lib issues. + for (ChannelFuture future : injectedFutures) { + ChannelHandler bootstrapAcceptor = future.channel().pipeline().first(); + try { + ChannelInitializer oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class); + if (oldInit instanceof ViaVersionInitializer) { + ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((ViaVersionInitializer) oldInit).getOriginal()); + } + } catch (Exception e) { + System.out.println("Failed to remove injection... reload won't work with connections sorry"); + } + } + injectedFutures.clear(); + + for (Pair pair : injectedLists) { + try { + Object o = pair.getKey().get(pair.getValue()); + if (o instanceof ListWrapper) { + pair.getKey().set(pair.getValue(), ((ListWrapper) o).getOriginalList()); + } + } catch (IllegalAccessException e) { + System.out.println("Failed to remove injection... reload might not work with connections sorry"); + } + } + + injectedLists.clear(); + } + @Override public boolean isPorted(Player player) { return isPorted(player.getUniqueId()); diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java index 95532b996..06a33a134 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java @@ -56,6 +56,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder { throw e; } } + // call minecraft decoder try { list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf)); diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java b/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java index ec897bc32..019ee4fd3 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java @@ -12,11 +12,11 @@ import java.lang.reflect.Method; public class ViaVersionInitializer extends ChannelInitializer { - private final ChannelInitializer oldInit; + private final ChannelInitializer original; private Method method; public ViaVersionInitializer(ChannelInitializer oldInit) { - this.oldInit = oldInit; + this.original = oldInit; try { this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class); this.method.setAccessible(true); @@ -25,13 +25,17 @@ public class ViaVersionInitializer extends ChannelInitializer { } } + public ChannelInitializer getOriginal() { + return original; + } + @Override protected void initChannel(SocketChannel socketChannel) throws Exception { UserConnection info = new UserConnection(socketChannel); // init protocol new ProtocolPipeline(info); // Add originals - this.method.invoke(this.oldInit, socketChannel); + this.method.invoke(this.original, socketChannel); // Add our transformers ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder")); ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder")); diff --git a/src/main/java/us/myles/ViaVersion/util/ListWrapper.java b/src/main/java/us/myles/ViaVersion/util/ListWrapper.java index 4d620296d..9127b30a2 100644 --- a/src/main/java/us/myles/ViaVersion/util/ListWrapper.java +++ b/src/main/java/us/myles/ViaVersion/util/ListWrapper.java @@ -14,6 +14,10 @@ public abstract class ListWrapper implements List { public abstract void handleAdd(Object o); + public List getOriginalList() { + return list; + } + @Override public synchronized int size() { return this.list.size();