Merge branch 'master' into dev

This commit is contained in:
Myles 2019-03-18 11:30:19 +00:00
commit 49205f0361
9 changed files with 256 additions and 30 deletions

View File

@ -1,5 +1,7 @@
package us.myles.ViaVersion.bukkit.platform;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
@ -16,7 +18,6 @@ import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class BukkitViaInjector implements ViaInjector {
@ -275,4 +276,65 @@ public class BukkitViaInjector implements ViaInjector {
}
return false;
}
@Override
public JsonObject getDump() {
JsonObject data = new JsonObject();
// Generate information about current injections
JsonArray injectedChannelInitializers = new JsonArray();
for (ChannelFuture cf : injectedFutures) {
JsonObject info = new JsonObject();
info.addProperty("futureClass", cf.getClass().getName());
info.addProperty("channelClass", cf.channel().getClass().getName());
// Get information about the pipes for this channel future
JsonArray pipeline = new JsonArray();
for (String pipeName : cf.channel().pipeline().names()) {
JsonObject pipe = new JsonObject();
pipe.addProperty("name", pipeName);
if (cf.channel().pipeline().get(pipeName) != null) {
pipe.addProperty("class", cf.channel().pipeline().get(pipeName).getClass().getName());
try {
Object child = ReflectionUtil.get(cf.channel().pipeline().get(pipeName), "childHandler", ChannelInitializer.class);
pipe.addProperty("childClass", child.getClass().getName());
if (child instanceof BukkitChannelInitializer) {
pipe.addProperty("oldInit", ((BukkitChannelInitializer) child).getOriginal().getClass().getName());
}
} catch (Exception e) {
// Don't display
}
}
// Add to the pipeline array
pipeline.add(pipe);
}
info.add("pipeline", pipeline);
// Add to the list
injectedChannelInitializers.add(info);
}
data.add("injectedChannelInitializers", injectedChannelInitializers);
// Generate information about lists we've injected into
JsonObject wrappedLists = new JsonObject();
JsonObject currentLists = new JsonObject();
try {
for (Pair<Field, Object> pair : injectedLists) {
Object list = pair.getKey().get(pair.getValue());
// Note down the current value (could be overridden by another plugin)
currentLists.addProperty(pair.getKey().getName(), list.getClass().getName());
// Also if it's not overridden we can display what's inside our list (possibly another plugin)
if (list instanceof ListWrapper) {
wrappedLists.addProperty(pair.getKey().getName(), ((ListWrapper) list).getOriginalList().getClass().getName());
}
}
data.add("wrappedLists", wrappedLists);
data.add("currentLists", currentLists);
} catch (Exception e) {
// Ignored, fields won't be present
}
data.addProperty("binded", isBinded());
return data;
}
}

View File

@ -3,13 +3,14 @@ package us.myles.ViaVersion.bungee.handlers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import java.lang.reflect.Method;
public class BungeeChannelInitializer extends ChannelInitializer<SocketChannel> {
public class BungeeChannelInitializer extends ChannelInitializer<Channel> {
@Getter
private final ChannelInitializer<Channel> original;
private Method method;
@ -24,7 +25,7 @@ public class BungeeChannelInitializer extends ChannelInitializer<SocketChannel>
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
protected void initChannel(Channel socketChannel) throws Exception {
UserConnection info = new UserConnection(socketChannel);
// init protocol
new ProtocolPipeline(info);

View File

@ -1,5 +1,6 @@
package us.myles.ViaVersion.bungee.platform;
import com.google.gson.JsonObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import us.myles.ViaVersion.api.Via;
@ -56,4 +57,31 @@ public class BungeeViaInjector implements ViaInjector {
public String getDecoderName() {
return "via-decoder";
}
private ChannelInitializer<Channel> getChannelInitializer() throws Exception {
Class<?> pipelineUtils = Class.forName("net.md_5.bungee.netty.PipelineUtils");
Field field = pipelineUtils.getDeclaredField("SERVER_CHILD");
field.setAccessible(true);
// Remove any final stuff
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
return (ChannelInitializer<Channel>) field.get(null);
}
@Override
public JsonObject getDump() {
JsonObject data = new JsonObject();
try {
ChannelInitializer<Channel> initializer = getChannelInitializer();
data.addProperty("currentInitializer", initializer.getClass().getName());
if (initializer instanceof BungeeChannelInitializer) {
data.addProperty("originalInitializer", ((BungeeChannelInitializer) initializer).getOriginal().getClass().getName());
}
} catch (Exception e) {
// Ignored, not printed in the dump
}
return data;
}
}

View File

@ -1,5 +1,7 @@
package us.myles.ViaVersion.api.platform;
import com.google.gson.JsonObject;
public interface ViaInjector {
/**
* Inject into the current Platform
@ -36,4 +38,11 @@ public interface ViaInjector {
* @return The name
*/
String getDecoderName();
/**
* Get any relevant data for debugging injection issues.
*
* @return JSONObject containing the data
*/
JsonObject getDump();
}

View File

@ -48,7 +48,7 @@ public class DumpSubCmd extends ViaSubCommand {
Map<String, Object> configuration = Via.getPlatform().getConfigurationProvider().getValues();
final DumpTemplate template = new DumpTemplate(version, configuration, Via.getPlatform().getDump());
final DumpTemplate template = new DumpTemplate(version, configuration, Via.getPlatform().getDump(), Via.getManager().getInjector().getDump());
Via.getPlatform().runAsync(new Runnable() {
@Override

View File

@ -12,4 +12,5 @@ public class DumpTemplate {
private VersionInfo versionInfo;
private Map<String, Object> configuration;
private JsonObject platformDump;
private JsonObject injectionDump;
}

View File

@ -20,39 +20,53 @@ public abstract class ListWrapper implements List {
@Override
public int size() {
return this.list.size();
synchronized (this) {
return this.list.size();
}
}
@Override
public boolean isEmpty() {
return this.list.isEmpty();
synchronized (this) {
return this.list.isEmpty();
}
}
@Override
public boolean contains(Object o) {
return this.list.contains(o);
synchronized (this) {
return this.list.contains(o);
}
}
@Override
public Iterator iterator() {
return listIterator();
synchronized (this) {
return listIterator();
}
}
@Override
public Object[] toArray() {
return this.list.toArray();
synchronized (this) {
return this.list.toArray();
}
}
@Override
public boolean add(Object o) {
handleAdd(o);
return this.list.add(o);
synchronized (this) {
return this.list.add(o);
}
}
@Override
public boolean remove(Object o) {
return this.list.remove(o);
synchronized (this) {
return this.list.remove(o);
}
}
@Override
@ -60,7 +74,9 @@ public abstract class ListWrapper implements List {
for (Object o : c) {
handleAdd(o);
}
return this.list.addAll(c);
synchronized (this) {
return this.list.addAll(c);
}
}
@Override
@ -68,76 +84,106 @@ public abstract class ListWrapper implements List {
for (Object o : c) {
handleAdd(o);
}
return this.list.addAll(index, c);
synchronized (this) {
return this.list.addAll(index, c);
}
}
@Override
public void clear() {
this.list.clear();
synchronized (this) {
this.list.clear();
}
}
@Override
public Object get(int index) {
return this.list.get(index);
synchronized (this) {
return this.list.get(index);
}
}
@Override
public Object set(int index, Object element) {
return this.list.set(index, element);
synchronized (this) {
return this.list.set(index, element);
}
}
@Override
public void add(int index, Object element) {
this.list.add(index, element);
synchronized (this) {
this.list.add(index, element);
}
}
@Override
public Object remove(int index) {
return this.list.remove(index);
synchronized (this) {
return this.list.remove(index);
}
}
@Override
public int indexOf(Object o) {
return this.list.indexOf(o);
synchronized (this) {
return this.list.indexOf(o);
}
}
@Override
public int lastIndexOf(Object o) {
return this.list.lastIndexOf(o);
synchronized (this) {
return this.list.lastIndexOf(o);
}
}
@Override
public ListIterator listIterator() {
return this.list.listIterator();
synchronized (this) {
return this.list.listIterator();
}
}
@Override
public ListIterator listIterator(int index) {
return this.list.listIterator(index);
synchronized (this) {
return this.list.listIterator(index);
}
}
@Override
public List subList(int fromIndex, int toIndex) {
return this.list.subList(fromIndex, toIndex);
synchronized (this) {
return this.list.subList(fromIndex, toIndex);
}
}
@Override
public boolean retainAll(Collection c) {
return this.list.retainAll(c);
synchronized (this) {
return this.list.retainAll(c);
}
}
@Override
public boolean removeAll(Collection c) {
return this.list.removeAll(c);
synchronized (this) {
return this.list.removeAll(c);
}
}
@Override
public boolean containsAll(Collection c) {
return this.list.containsAll(c);
synchronized (this) {
return this.list.containsAll(c);
}
}
@Override
public Object[] toArray(Object[] a) {
return this.list.toArray(a);
synchronized (this) {
return this.list.toArray(a);
}
}
}

View File

@ -1,5 +1,7 @@
package us.myles.ViaVersion.sponge.platform;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
@ -189,4 +191,63 @@ public class SpongeViaInjector implements ViaInjector {
return connection;
}
@Override
public JsonObject getDump() {
JsonObject data = new JsonObject();
// Generate information about current injections
JsonArray injectedChannelInitializers = new JsonArray();
for (ChannelFuture cf : injectedFutures) {
JsonObject info = new JsonObject();
info.addProperty("futureClass", cf.getClass().getName());
info.addProperty("channelClass", cf.channel().getClass().getName());
// Get information about the pipes for this channel future
JsonArray pipeline = new JsonArray();
for (String pipeName : cf.channel().pipeline().names()) {
JsonObject pipe = new JsonObject();
pipe.addProperty("name", pipeName);
if (cf.channel().pipeline().get(pipeName) != null) {
pipe.addProperty("class", cf.channel().pipeline().get(pipeName).getClass().getName());
try {
Object child = ReflectionUtil.get(cf.channel().pipeline().get(pipeName), "childHandler", ChannelInitializer.class);
pipe.addProperty("childClass", child.getClass().getName());
if (child instanceof SpongeChannelInitializer) {
pipe.addProperty("oldInit", ((SpongeChannelInitializer) child).getOriginal().getClass().getName());
}
} catch (Exception e) {
// Don't display
}
}
// Add to the pipeline array
pipeline.add(pipe);
}
info.add("pipeline", pipeline);
// Add to the list
injectedChannelInitializers.add(info);
}
data.add("injectedChannelInitializers", injectedChannelInitializers);
// Generate information about lists we've injected into
JsonObject wrappedLists = new JsonObject();
JsonObject currentLists = new JsonObject();
try {
for (Pair<Field, Object> pair : injectedLists) {
Object list = pair.getKey().get(pair.getValue());
// Note down the current value (could be overridden by another plugin)
currentLists.addProperty(pair.getKey().getName(), list.getClass().getName());
// Also if it's not overridden we can display what's inside our list (possibly another plugin)
if (list instanceof ListWrapper) {
wrappedLists.addProperty(pair.getKey().getName(), ((ListWrapper) list).getOriginalList().getClass().getName());
}
}
data.add("wrappedLists", wrappedLists);
data.add("currentLists", currentLists);
} catch (Exception e) {
// Ignored, fields won't be present
}
return data;
}
}

View File

@ -1,5 +1,6 @@
package us.myles.ViaVersion.velocity.platform;
import com.google.gson.JsonObject;
import io.netty.channel.ChannelInitializer;
import us.myles.ViaVersion.VelocityPlugin;
import us.myles.ViaVersion.api.Via;
@ -23,13 +24,19 @@ public class VelocityViaInjector implements ViaInjector {
}
}
private ChannelInitializer getInitializer() throws Exception {
Object connectionManager = ReflectionUtil.get(VelocityPlugin.PROXY, "cm", Object.class);
Object channelInitializerHolder = ReflectionUtil.invoke(connectionManager, "getServerChannelInitializer");
return (ChannelInitializer) ReflectionUtil.invoke(channelInitializerHolder, "get");
}
@Override
public void inject() throws Exception {
Object connectionManager = ReflectionUtil.get(VelocityPlugin.PROXY, "cm", Object.class);
Object channelInitializerHolder = ReflectionUtil.invoke(connectionManager, "getServerChannelInitializer");
ChannelInitializer originalIntializer = (ChannelInitializer) ReflectionUtil.invoke(channelInitializerHolder, "get");
ChannelInitializer originalInitializer = getInitializer();
channelInitializerHolder.getClass().getMethod("set", ChannelInitializer.class)
.invoke(channelInitializerHolder, new VelocityChannelInitializer(originalIntializer));
.invoke(channelInitializerHolder, new VelocityChannelInitializer(originalInitializer));
}
@Override
@ -62,4 +69,15 @@ public class VelocityViaInjector implements ViaInjector {
public String getDecoderName() {
return "via-decoder";
}
@Override
public JsonObject getDump() {
JsonObject data = new JsonObject();
try {
data.addProperty("currentInitializer", getInitializer().getClass().getName());
} catch (Exception e) {
// Ignored
}
return data;
}
}