-1

I need help using a method from a casted Type in Java. Without reflections it would look like PlayerConnection con = ((CraftPlayer) player).getHandle().playerConnection;, but due to the fact that the API I'm using for this program/plugin, the package suffix changes by version number, so I'm trying to figure out Reflections to get it to work. And later in the code, I'm trying to use the con variable to send it as a packet, using a method inside the PlayerConnection type. So without reflections it would look like con.sendPacket(packet); The packet variable I think I got it.

For background code information, I have already created a method to get the version of the server, and created another method to get the class. So instead of showing Class.forName(); can you type getClass(""), the getClass() method returns Class and already adds the package name inside. For more information this will be an example:

input:
getClass("Packet");

output:
net.minecraft.1_8R2.Packet;

It'll will return the class of that package.

Jojodmo
  • 23,357
  • 13
  • 65
  • 107
  • I suppose you are realizing "Decorator" pattern. Follow by [link][1] [1]: http://stackoverflow.com/questions/160970/how-do-i-invoke-a-java-method-when-given-the-method-name-as-a-string – Alexander Fedyukov Mar 23 '15 at 04:16

1 Answers1

0

You can get a new instance of a Class<?> by using .newInstance()

Class<?> clazz = getClass("Packet");
Object packet = clazz.newInstance();

Then, to get the CraftPlayer class, you could use:

Class<?> craftplayer = getClass("CraftPlayer"); 
//make another method that chooses the org.bukkit.* class
//instead of the net.minecraft.server.* class, and use that here
//in place of getClass()

Then, to get the handle of the player, you could use:

Method getHandle = craftplayer.getMethod("getHandle");
Object nms = getHandle.invoke(player);

Next, you could get the sendPacket() method by using:

Field connfield = nms.getClass().getField("playerConnection");
Object connection = connfield.get(nms);
Method sendPacket = connection.getClass().getMethod("sendPacket", clazz); 
//clazz is getClass("Packet");

and then you could invoke it with the packet using:

sendPacket.invoke(connection, packet);
//packet is getClass("Packet").newInstance()

So, you could use something like this:

try{
  Class<?> clazz = getClass("Packet");
  Object packet = clazz.newInstance();

  Class<?> craftplayer = getClass("CraftPlayer"); 
  //make another method that chooses the org.bukkit.* class instead of the net.minecraft.server.* class, and use that here

  Method getHandle = craftplayer.getMethod("getHandle");
  Object nms = getHandle.invoke(player);

  Field connfield = nms.getClass().getField("playerConnection");
  Object connection = connfield.get(nms);
  Method sendPacket = connection.getClass().getMethod("sendPacket", clazz); 
  sendPacket.invoke(connection, packet);
}
catch(Exception ex){
  //an error occurred, and the packet could not be sent.
  ex.printStackTrace();
}
Jojodmo
  • 23,357
  • 13
  • 65
  • 107
  • But the think is that `PlayerConnection` and `CraftPlayer` are both from the `net.minecraft.1_8R1;` package. So I need that 2nd to last line to be dynamic. Sorry If I wasn't being clear. – DennisOfficial Mar 24 '15 at 04:32
  • Correct me if I'm wrong, but if you just use `((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet)` I don't think you'll have to import anything... – Jojodmo Mar 24 '15 at 04:34
  • `CraftPlayer` will have to be imported to cast it `player` – DennisOfficial Mar 29 '15 at 06:57
  • @DennisOfficial I just edited the answer, you'll just need to make another method like `getClass()`, except make it get `org.bukkit.*` classes instead of `net.minecraft.server.*` classes, and use that in place of `getClass()` for `getClass("CraftPlayer")` – Jojodmo Mar 29 '15 at 19:11