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.)
This commit is contained in:
Myles 2016-03-31 22:45:15 +01:00
parent 5e0096aa2c
commit 6893f34289
4 changed files with 72 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.ViaVersion; import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionAPI; import us.myles.ViaVersion.api.ViaVersionAPI;
import us.myles.ViaVersion.api.ViaVersionConfig; import us.myles.ViaVersion.api.ViaVersionConfig;
@ -31,6 +32,7 @@ import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.File; import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -42,19 +44,36 @@ import java.util.concurrent.TimeUnit;
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVersionConfig { public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVersionConfig {
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>(); private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
private List<ChannelFuture> injectedFutures = new ArrayList<>();
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
private ViaCommandHandler commandHandler; private ViaCommandHandler commandHandler;
private boolean debug = false; private boolean debug = false;
@Override @Override
public void onEnable() { public void onLoad() {
ViaVersion.setInstance(this); ViaVersion.setInstance(this);
generateConfig(); generateConfig();
if (System.getProperty("ViaVersion") != null) { if (System.getProperty("ViaVersion") != null) {
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update."); if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
getLogger().severe("Some features may not work."); getLogger().severe("ViaVersion is already loaded, we're going to kick all the players... because otherwise we'll crash because of ProtocolLib.");
return; 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 :) // Gather version :)
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override @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); Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this);
@ -83,6 +96,12 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
getCommand("viaversion").setTabCompleter(commandHandler); 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() { public void gatherProtocolVersion() {
try { try {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer"); 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); field.set(connection, wrapper);
// Iterate through current list // Iterate through current list
synchronized (wrapper) { synchronized (wrapper) {
@ -213,6 +233,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
ChannelInitializer newInit = new ViaVersionInitializer(oldInit); ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit); ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
injectedFutures.add(future);
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
// field not found // field not found
throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName()); 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<SocketChannel> 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<Field, Object> 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 @Override
public boolean isPorted(Player player) { public boolean isPorted(Player player) {
return isPorted(player.getUniqueId()); return isPorted(player.getUniqueId());

View File

@ -56,6 +56,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
throw e; throw e;
} }
} }
// call minecraft decoder // call minecraft decoder
try { try {
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf)); list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));

View File

@ -12,11 +12,11 @@ import java.lang.reflect.Method;
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> { public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelInitializer<SocketChannel> oldInit; private final ChannelInitializer<SocketChannel> original;
private Method method; private Method method;
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) { public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
this.oldInit = oldInit; this.original = oldInit;
try { try {
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class); this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
this.method.setAccessible(true); this.method.setAccessible(true);
@ -25,13 +25,17 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
} }
} }
public ChannelInitializer<SocketChannel> getOriginal() {
return original;
}
@Override @Override
protected void initChannel(SocketChannel socketChannel) throws Exception { protected void initChannel(SocketChannel socketChannel) throws Exception {
UserConnection info = new UserConnection(socketChannel); UserConnection info = new UserConnection(socketChannel);
// init protocol // init protocol
new ProtocolPipeline(info); new ProtocolPipeline(info);
// Add originals // Add originals
this.method.invoke(this.oldInit, socketChannel); this.method.invoke(this.original, socketChannel);
// Add our transformers // Add our transformers
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder")); ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder")); ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));

View File

@ -14,6 +14,10 @@ public abstract class ListWrapper implements List {
public abstract void handleAdd(Object o); public abstract void handleAdd(Object o);
public List getOriginalList() {
return list;
}
@Override @Override
public synchronized int size() { public synchronized int size() {
return this.list.size(); return this.list.size();