Skip to content
This repository has been archived by the owner on Nov 8, 2021. It is now read-only.

How To Proxy

theminecoder edited this page Apr 16, 2019 · 6 revisions

Step 1 - Create proxy class

Creating NMS proxy classes is very simple, its just a matter of creating an interface with the right annotations and NMSPoxy will handle the rest. NMSProxy supports any class but is especially good at NMS & CraftBukkit/Spigot classes.

To start you will need an interface that extends NMSProxy and is annotated with @NMSClass. This is the marker to a valid proxy class and tells the api the class type we will be proxying. When proxying NMS (NMSClass.Type.NMS) and CraftBukkit/Spigot (NMSClass.Type.CRAFTBUKKIT) classes the api will automatically prefix the correct versioned package to the provided class name to save you time. If implimenting something outside these bounds, you can insert %version% into the class name and it will be replaced with the NMS version identifier used in many places in the bukkit ecosystem.

Next up is specifying methods and fields. For every method and field you want to access on the proxy instance you need to add a method onto the interface with either a @NMSMethod or @NMSField on it. The return type can either be another proxy class, the actual class type itself (useful for netty/game profile classes) or Object for anything else and the arguments can be proxy class instances or actual objects. This allows for the highest compatibility between real objects and proxy class instances.

For any static methods/fields you must add a @NMSStatic annotation. You can also add default methods which will run as you expect.

Example proxy class

CraftBukkit/Spigot

@NMSClass(type = NMSClass.Type.CRAFTBUKKIT, className = "entity.CraftPlayer")
public interface NMSCraftPlayer implements NMSProxy {
    
    default GameProfile getProfile() {
        return getHandle().getProfile();
    }
    
    @NMSMethod
    NMSEntityPlayer getHandle();
    
}

NMS

@NMSClass(type = NMSClass.Type.NMS, className = "EntityPlayer")
public interface NMSEntityPlayer implements NMSProxy {
    
    @NMSField(type = NMSField.Type.GETTER)
    NMSPlayerConnection playerConnection();
    
    @NMSMethod
    GameProfile getProfile();
    
}

Step 2 - Use it in your plugin

Now that you have created your proxy classes, you can start to use them inside your plugin. First, get your plugins instance of the NMSProxyProvider using NMSProxyProvider.get(JavaPlugin plugin).

From there you have a 2 options to get a proxy instance. The first is to wrap a current object that you have on hand. To do this you need to call NMSProxyProvider#getNMSObject(Class<? extends NMSProxy> proxyClass, Object object). This will type check the object to the proxy class and hand you back a proxy class instance of the object. From there you can use the object as normal.

The other option you have is to construct a NMS object from scratch. For this you need to call NMSProxyProvider#constructNMSObject(Class<? extends NMSProxy> proxyClass, Object... args). This will call the constructor on the proxied class type with the arguments you give it. You can use proxy instances as arguments and they will be converted back to their original types when used in the constructor. From there everything works as normal.

If at anytime you need to get the original object back from the proxy instance, you can call NMSProxy#getProxyHandle() on the proxy instance.

If you need to get a static instance of a class (you wont be able to use any methods/fields that arn't marked with @NMSStatic) you can call NMSProxyProvider#getStaticNMSObject(Class<? extends NMSProxy> proxyClass) or NMSProxy#getStaticProxyObject() on a proxy instance of the same type. Static proxy instances will return null for NMSProxy#getProxyHandle() calls.

Example Usage

public class MyPlugin extends JavaPlugin implements Listener {
    
    private NMSProxyProvider proxyProvider;
    
    public void onEnable() {
        proxyProvider = NMSProxyProvider.get(this);
        this.getServer().getPluginManager().registerEvents(this, this);
    }
    
    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        NMSCraftPlayer craftPlayer = proxyProvider.getNMSObject(NMSCraftPlayer.class, event.getPlayer());
        GameProfile gameProfile = craftPlayer.getProfile();
        
        // Use game profile/craft player proxy as needed.
    }
}