Package com.comphenix.protocol.utility

Source Code of com.comphenix.protocol.utility.MinecraftMethods$ReadMethodException

package com.comphenix.protocol.utility;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.buffer.UnpooledByteBufAllocator;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.util.concurrent.GenericFutureListener;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.FuzzyReflection;

/**
* Static methods for accessing Minecraft methods.
*
* @author Kristian
*/
public class MinecraftMethods {
  // For player connection
  private volatile static Method sendPacketMethod;
 
  // For network manager
  private volatile static Method networkManagerHandle;
  private volatile static Method networkManagerPacketRead;
 
  // For packet
  private volatile static Method packetReadByteBuf;
  private volatile static Method packetWriteByteBuf;
 
  /**
   * Retrieve the send packet method in PlayerConnection/NetServerHandler.
   * @return The send packet method.
   */
  public static Method getSendPacketMethod() {
    if (sendPacketMethod == null) {
      Class<?> serverHandlerClass = MinecraftReflection.getNetServerHandlerClass();

      try {
        sendPacketMethod = FuzzyReflection.fromClass(serverHandlerClass).getMethodByName("sendPacket.*");
      } catch (IllegalArgumentException e) {
        // We can't use the method below on Netty
        if (MinecraftReflection.isUsingNetty()) {
          sendPacketMethod = FuzzyReflection.fromClass(serverHandlerClass).
            getMethodByParameters("sendPacket", MinecraftReflection.getPacketClass());
          return sendPacketMethod;
        }
       
        Map<String, Method> netServer = getMethodList(
            serverHandlerClass, MinecraftReflection.getPacketClass());
        Map<String, Method> netHandler = getMethodList(
            MinecraftReflection.getNetHandlerClass(), MinecraftReflection.getPacketClass());
       
        // Remove every method in net handler from net server
        for (String methodName : netHandler.keySet()) {
          netServer.remove(methodName);
        }
       
        // The remainder is the send packet method
        if (netServer.size() ==  1) {
          Method[] methods = netServer.values().toArray(new Method[0]);
          sendPacketMethod = methods[0];
        } else {
          throw new IllegalArgumentException("Unable to find the sendPacket method in NetServerHandler/PlayerConnection.");
        }
      }
    }
    return sendPacketMethod;
  }
 
  /**
   * Retrieve the disconnect method for a given player connection.
   * @param playerConnection - the player connection.
   * @return The
   */
  public static Method getDisconnectMethod(Class<? extends Object> playerConnection) {
    try {
      return FuzzyReflection.fromClass(playerConnection).getMethodByName("disconnect.*");
    } catch (IllegalArgumentException e) {
      // Just assume it's the first String method
      return FuzzyReflection.fromObject(playerConnection).getMethodByParameters("disconnect", String.class);
    }
  }
 
  /**
   * Retrieve the handle(Packet, GenericFutureListener[]) method of network manager.
   * <p>
   * This only exists in version 1.7.2 and above.
   * @return The handle method.
   */
  public static Method getNetworkManagerHandleMethod() {
    if (networkManagerHandle == null) {
      networkManagerHandle = FuzzyReflection.fromClass(MinecraftReflection.getNetworkManagerClass(), true).
          getMethodByParameters("handle", MinecraftReflection.getPacketClass(), GenericFutureListener[].class);
      networkManagerHandle.setAccessible(true);
    }
    return networkManagerHandle;
  }
 
  /**
   * Retrieve the packetRead(ChannelHandlerContext, Packet) method of NetworkMananger.
   * <p>
   * This only exists in version 1.7.2 and above.
   * @return The packetRead method.
   */
  public static Method getNetworkManagerReadPacketMethod() {
    if (networkManagerPacketRead == null) {
      networkManagerPacketRead = FuzzyReflection.fromClass(MinecraftReflection.getNetworkManagerClass(), true).
          getMethodByParameters("packetRead", ChannelHandlerContext.class, MinecraftReflection.getPacketClass());
      networkManagerPacketRead.setAccessible(true);
    }
    return networkManagerPacketRead;
  }

  /**
   * Retrieve a method mapped list of every method with the given signature.
   * @param source - class source.
   * @param params - parameters.
   * @return Method mapped list.
   */
  private static Map<String, Method> getMethodList(Class<?> source, Class<?>... params) {
    FuzzyReflection reflect = FuzzyReflection.fromClass(source, true);
   
    return reflect.getMappedMethods(
      reflect.getMethodListByParameters(Void.TYPE, params)
    );
  }

  /**
   * Retrieve the Packet.read(PacketDataSerializer) method.
   * <p>
   * This only exists in version 1.7.2 and above.
   * @return The packet read method.
   */
  public static Method getPacketReadByteBufMethod()  {
    initializePacket();
    return packetReadByteBuf;
  }
 
  /**
   * Retrieve the Packet.write(PacketDataSerializer) method.
   * <p>
   * This only exists in version 1.7.2 and above.
   * @return The packet write method.
   */
  public static Method getPacketWriteByteBufMethod()  {
    initializePacket();
    return packetWriteByteBuf;
  }
 
  /**
   * Initialize the two read() and write() methods.
   */
  private static void initializePacket() {
    // Initialize the methods
    if (packetReadByteBuf == null || packetWriteByteBuf == null) {
      // This object will allow us to detect which methods were called
      Enhancer enhancer = EnhancerFactory.getInstance().createEnhancer();
      enhancer.setSuperclass(MinecraftReflection.getPacketDataSerializerClass());
      enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
            throws Throwable {
          if (method.getName().contains("read"))
            throw new ReadMethodException();
          if (method.getName().contains("write"))
            throw new WriteMethodException();
          return proxy.invokeSuper(obj, args);
        }
      });
     
      // Create our proxy object
      Object javaProxy = enhancer.create(
        new Class<?>[] { ByteBuf.class },
        new Object[]   { UnpooledByteBufAllocator.DEFAULT.buffer() }
      );
     
      Object lookPacket = new PacketContainer(PacketType.Play.Client.BLOCK_PLACE).getHandle();
      List<Method> candidates = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).
        getMethodListByParameters(Void.TYPE, new Class<?>[] { MinecraftReflection.getPacketDataSerializerClass() });
     
      // Look through all the methods
      for (Method method : candidates) {
        try {
          method.invoke(lookPacket, javaProxy);
        } catch (InvocationTargetException e) {
          if (e.getCause() instanceof ReadMethodException)
            // Must be the reader
            packetReadByteBuf = method;
          else if (e.getCause() instanceof WriteMethodException)
            packetWriteByteBuf = method;
          else
            throw new RuntimeException("Inner exception.", e);
        } catch (Exception e) {
          throw new RuntimeException("Generic reflection error.", e);
        }
      }
     
      if (packetReadByteBuf == null)
        throw new IllegalStateException("Unable to find Packet.read(PacketDataSerializer)");
      if (packetWriteByteBuf == null)
        throw new IllegalStateException("Unable to find Packet.write(PacketDataSerializer)");
    }
  }
 
  /**
   * An internal exception used to detect read methods.
   * @author Kristian
   */
  private static class ReadMethodException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public ReadMethodException() {
      super("A read method was executed.");
   
  }
 
  /**
   * An internal exception used to detect write methods.
   * @author Kristian
   */
  private static class WriteMethodException extends RuntimeException {
    private static final long serialVersionUID = 1L;
   
    public WriteMethodException() {
      super("A write method was executed.");
   
  }
}
TOP

Related Classes of com.comphenix.protocol.utility.MinecraftMethods$ReadMethodException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.