Minecraft Modding: Organizing Your Proxy

Introduction


The concept of a "proxy" in Minecraft modding is very important but difficult to understand at first. For the general idea, you should look at TheGreyGhost's Explanation Of Proxies Tutorial.

Got that? Good now let's make the proxies...

When You Need The Proxy


Key PointYou need to put code in the proxy whenever the same method (i.e. same method name and parameter list) is supposed to act differently on the client versus the server (or common).

If you have a method that is only on one side, it doesn't need to go into the proxy, rather it just can use the @SideOnly annotation.

But for almost all mods, there is a need for the FML life cycle process (which goes through stages of pre-initialization, initialization, post-initialization) to use a proxy because you need to call event handling methods that have the same name and parameters but need to act differently on common and client.

Organizing The Proxies


There are many ways to do organize the proxies, but this works for me:
  1. Create a class called CommonProxy
  2. Create a class called ClientProxy that extends CommonProxy.
  3. In each of my main mod class, CommonProxy and ClientProxy, I create methods to handle the FML life cycle events. The ClientProxy methods are annotated with @Override.
  4. I fill the methods as appropriate with registration of items, blocks, entities, networking, etc. See my code examples below for ideas on what should go where. In the main class you will call the proxy instance methods and in the ClientProxy you will call the super-method then do any client-specific stuff.
  5. In my main mod class, I annotate to point to these proxy classes.
  6. In my main mod class I instantiate the CommonProxy.

Create A Class Called CommonProxy


Here is an example of a typical CommonProxy, showing what sort of things should go into each FML life cycle event handling method:

public class CommonProxy 
{
    
    protected int modEntityID = 0;
     
    public void fmlLifeCycleEvent(FMLPreInitializationEvent event)
    { 
        // load configuration before doing anything else, because might use 
        // config values during registration
        initConfig(event);
        // register stuff
        registerBlocks();
        registerItems();
        registerTileEntities();
        registerModEntities();
        registerEntitySpawns();
        registerFuelHandlers();
        registerSimpleNetworking();
        registerVillagers();
    }

    public void fmlLifeCycleEvent(FMLInitializationEvent event)
    {
        // register custom event listeners
        registerEventListeners();
         
        // register recipes here to allow use of items from other mods
        registerRecipes();
        
        // register achievements here to allow use of items from other mods
        registerAchievements();
        
        // register gui handlers
        registerGuiHandlers();
    }

    public void fmlLifeCycleEvent(FMLPostInitializationEvent event)
    {
    }

    public void fmlLifeCycleEvent(FMLServerAboutToStartEvent event) 
    {
    }

    public void fmlLifeCycleEvent(FMLServerStartedEvent event) 
    {
    }

    public void fmlLifeCycleEvent(FMLServerStoppingEvent event) 
    {
    }

    public void fmlLifeCycleEvent(FMLServerStoppedEvent event) 
    {
    }

    public void fmlLifeCycleEvent(FMLServerStartingEvent event) 
    {
        // register server commands
        event.registerServerCommand(new CommandStructureCapture());
    }
}

In the above code, the various methods called like registerBlocks() would be methods you'd add to this same class to do what is appropriate for your mod.

Note that it is okay to call all the methods the same name (fmlLifeCycleEvent) because the parameter lists differ so Java considers them distinct methods.

Create ClientProxy Class That Extends CommonProxy


And here is a typical ClientProxy:

public class ClientProxy extends CommonProxy 
{   
    @Override
    public void fmlLifeCycleEvent(FMLPreInitializationEvent event)
    {
        // do common stuff
        super.fmlLifeCycleEvent(event);


        // do client-specific stuff
    }
@Override public void fmlLifeCycleEvent(FMLInitializationEvent event) { // do common stuff super.fmlLifeCycleEvent(event); // do client-specific stuff registerKeyBindings(); registerEntityRenderers(); registerItemRenderers(); registerBlockRenderers(); } @Override public void fmlLifeCycleEvent(FMLPostInitializationEvent event) { // do common stuff super.fmlLifeCycleEvent(event); // do client-specific stuff BlockSmith.versionChecker = new VersionChecker(); Thread versionCheckThread = new Thread(BlockSmith.versionChecker, 
              "Version Check");
        versionCheckThread.start();
    }
}

The code should be self-explanatory. In this case we're overriding the methods but also calling the super-method (i.e. the "common" stuff), then doing all the client-specific stuff.

Again, for your mod you would make the various methods (e.g. registerEntityRenderers()) with code that is appropriate to your mod.

Warning: You need to call the super-method before the client-specific stuff because you can't, for example, register block renderers unless the actual blocks have been registered first.

Annotate And Instantiate The Proxy


In your mod's main class you need to put in an annotation to indicate where the two proxies are. For example, put something like this in the fields list area of your main mod class:

@SidedProxy(
      clientSide="com.blogspot.jabelarminecraft.blocksmith.proxy.ClientProxy", 
      serverSide="com.blogspot.jabelarminecraft.blocksmith.proxy.CommonProxy"
    )
public static CommonProxy proxy;

Warning: You must change the strings to be the exact package location and name of each of your classes.

Call Your Proxy Methods From Mod's Main Class


So the proxy instance will change based on the side, and so if you call proxy from your mod's main class it will call the appropriate one.  So in my main class I have the following:

@EventHandler
public void fmlLifeCycleEvent(FMLPreInitializationEvent event) 
{    
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycleEvent(FMLInitializationEvent event) 
{
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLPostInitializationEvent event) 
{
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerAboutToStartEvent event)
{
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStartingEvent event)
{
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStartedEvent event)
{
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStoppingEvent event)
{
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStoppedEvent event)
{
    proxy.fmlLifeCycleEvent(event);
}


Conclusion


I know the concept can be a bit confusing but hopefully this gives you starting point for exploring how to use a proxy in your mod.

As always, please feel free to comment to ask for clarification or to give corrections. Happy modding!

1 comment:

  1. Thank you, very helpful getting me started.

    ReplyDelete