setBlockFast method using reflection?

Discussion in 'Plugin Development' started by Hanii Puppy, Nov 19, 2013.

Thread Status:
Not open for further replies.
  1. A while ago, Codename_B posted a thread with an object that allows the creation of a firework effect in a given location, calling NMS code via reflection rather than normally, meaning that the code doesn't need updating with every new version. (The thread can be found here)

    I would like to add Desht's setBlockFast method to my personal library, but rather than accessing the NMS code directly, access it in the same fashion as Codename_B's FireworkEffectPlayer class so that references don't need to be updated and there's no chance that a change in obfuscation will break the method. (setBlockFast can be found here)

    I tried to use FireworkEffectPlayer as a guide on modifying setBlockFast to use NMS calls through reflection, but ran into a couple of snags. Mostly that I couldn't understand how he makes the jump from access a method on a bukkit class to a native class, and how to determine the names of the methods I want to call.

    If anyone could help me with this, or point me in the direction of a tutorial on doing this, it would be a massive help ^_^
  2. Offline


    The problem with setBlockFast, is that it uses methods which change every update - so it must be updated every time.

    Edit: Also, you can only make NMS calls from craftbukkit
  3. Hanii Puppy You could try with this method:
    (Note: It requires my BukkitTool lib which can be found here:
    1. public void setBlockFast(Block b, int typeId, byte data){
    3. Object handle = getHandle(b.getChunk());
    4. //I guess the params are ints here since it's kinda pointless to use doubles when you're referring to blocks in a //chunk, I'm not sure tho so you probably need to look at the source code.
    6. SafeMethod a = new SafeMethod(handle.getClass(), new Class[]{int.class, int.class, int.class, int.class, byte.class});
    7. a.invoke(handle, b.getX() & 15, b.getY(), b.getZ() & 15, typeId, data);
    8. }
    10. public Object getChunkHandle(Chunk chunk){
    11. return new ServerMethod(chunk.getClass(), "getHandle").invoke(chunk);
    12. }

    I'm not sure if it would work but it's worth a try...
    Hanii Puppy likes this.
  4. Offline


    Hanii Puppy You could also utilize my ReflectionUtil class for this. I just tested it and it works, but the block seems to be invisible for the player until he relogs. That's my code:

    1. public static boolean setBlockFast(Block b, int typeId, byte data) {
    2. Chunk c = b.getChunk();
    3. try {
    4. Object chunk = ReflectionUtil.invokeMethod("getHandle", c.getClass(), c);
    5. return (boolean) ReflectionUtil.invokeMethod("a", chunk.getClass(), chunk, b.getX() & 15, b.getY(), b.getZ() & 15, typeId, (int) data);
    6. } catch (Exception e) {
    7. return false;
    8. }
    9. }
    Hanii Puppy likes this.
  5. Offline


    Yes, the change won't be sent to the client automatically. You need to take care of that yourself (either send block changes for the block you've changed, or chunk changes might be more efficient for large changes).
  6. Is there not a chance that the "a" method could change in the future depending on obfuscation? The FireworkEffectPlayer class doesn't seem to make any references to obfuscated forms of method names.
  7. Offline


    Yes, there is absolutely a chance that it will, which is why reflection tricks are not a terribly good idea, especially for obfuscated methods and fields. It's dangerous.
    ZeusAllMighty11 likes this.
  8. So why does FireworkEffectPlayer not need to make direct references to the obfuscated methods?
  9. Offline


    It's lucky enough to only need methods which happen to have been deobfuscated.
    Hanii Puppy and ZeusAllMighty11 like this.
  10. Offline


    Hanii Puppy
  11. Ah :\ That's a pain. Thanks anyway for the help ^_^ I really dislike using native, obfuscated code :\ Mostly because of the constant reference updates required and the uncertainty that the same code will even be valid in the next version.

    It's a shame Bukkit doesn't offer an API for queueing update packets then performing collective ones.
  12. Offline


    Hanii Puppy
    Bukkit doesn't plan on using any features that would constantly change each update and weight down development.
  13. Offline


    I actually put in a PR for this some time ago, but it wasn't accepted. In hindsight, the team were probably right not to - the concept of queuing packets and sending updates like this is very much an implementation detail, and Bukkit does not like to expose implementation details.

    What would have a better chance of being pulled is some sort of schematic-based API where regions of the world could be pasted from some data source (read from file, generated in-memory...). The implementation of that could use a fast block update system, although users of course could not rely on the implementation remaining fast.
Thread Status:
Not open for further replies.

Share This Page