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...

Some Difference Of Opinion About Using A "Common" Proxy


In the example implementation for the @SidedProxy annotation, cpw gives an explanation that he intended people to make a CommonProxy class and then extend it for a ClientProxy (and ServerProxy if needed, although rarer).

However, since then some prominent Forge community folk such as diesieben07 have objected to the logic -- by definition "common" stuff doesn't need to be in a proxy.

So while I've historically used the common proxy approach, I have now modified it to an interface-based approach to satisfy the dissenters.

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 an interface called IProxy. This interface has prototype methods to handle each of the FML lifestyle events ("pre-init", "init", etc.) as well as any other methods my mod might have where behavior differs between sides (such as context processing for custom packets).
  2. Create a class called ClientProxy that extends IProxy.
  3. Create a class called ServerProxy that extends IProxy.
  4. In my main mod class, I create a field called proxy of type IProxy that uses the @SidedProxy annotation to point to these proxy classes.
  5. In my main mod class, I also handle the FML lifestyle events which includes all common (to both sides) code but also call the proxy instance's version of the same method to add any side-specific implementations. 
  6. In the ClientProxy and ServeryProxy I implement all the IProxy interface methods, with side-specific code as appropriate.

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

public interface IProxy
{
    /**
     * Fml life cycle event for Pre-Initialization. Historically (before registry events) 
     * this was where blocks, items, etc. were registered. There are still things 
     * like entities and networking which should still be registered here.
     *
     * @param event the event
     */
    void preInit(FMLPreInitializationEvent event);

    /**
     * Fml life cycle event for Initialization. This phase is good for registering event listeners, for registering things that depend on things in pre-init from other mods (like
     * recipes, advancements and such.)
     *
     * @param event the event
     */
    void init(FMLInitializationEvent event);

    /**
     * Fml life cycle event Post Initialization. This phase is useful For doing inter-mod stuff like checking which mods are loaded or if you want a complete view of things across
     * mods like having a list of all registered items to aid random item generation.
     *
     * @param event the event
     */
    void postInit(FMLPostInitializationEvent event);

    /**
     * Fml life cycle event. Server commands should be registered here.
     *
     * @param event the event
     */
    void serverStarting(FMLServerStartingEvent event);

    /*
     * Thanks to CoolAlias for this tip!
     */
    /**
     * Returns a side-appropriate EntityPlayer for use during message handling.
     *
     * @param parContext the context
     * @return the player entity from context
     */
    EntityPlayer getPlayerEntityFromContext(MessageContext parContext);
}

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.

Create A ClientProxy Class That Implements IProxy


And here is a typical ClientProxy:

public class ClientProxy implements IProxy
{
    // mouse helper
    public static MouseHelper mouseHelperAI = new MouseHelperAI(); // used to intercept user mouse movement for "bot" functionality

    @Override
    public void preInit(FMLPreInitializationEvent event)
    {
        // DEBUG
        System.out.println("on Client side");
        
        Minecraft.getMinecraft().mouseHelper = ClientProxy.mouseHelperAI;
        RenderFactories.registerEntityRenderers();
    }

    @Override
    public void init(FMLInitializationEvent event)
    {
        // DEBUG
        System.out.println("on Client side");

        // register key bindings
        ModKeyBindings.registerKeyBindings();
    }

    @Override
    public void postInit(FMLPostInitializationEvent event)
    {
        // DEBUG
        System.out.println("on Client side");
    }

    @Override
    public EntityPlayer getPlayerEntityFromContext(MessageContext ctx)
    {
        return (ctx.side.isClient() ? Minecraft.getMinecraft().player : MainMod.proxy.getPlayerEntityFromContext(ctx));
    }

    @Override
    public void serverStarting(FMLServerStartingEvent event)
    {
        // This will never get called on client side
    }
}

The code should be self-explanatory. In this case we're overriding the methods with the the client-specific stuff.

In this example I refer to classes I'm not showing here, such as RenderFactories where I have put my registration code for my entity render class mapping -- you would replace that with code that is appropriate to your mod.

Create A ServerProxy Class That Implements IProxy


And here is a typical ServerProxy:

public class ServerProxy implements IProxy
{
    @Override
    public void preInit(FMLPreInitializationEvent event)
    {
    }

    @Override
    public void init(FMLInitializationEvent event)
    {
    }
    
    @Override
    public void postInit(FMLPostInitializationEvent event)
    {
    }
    
    @Override
    public void serverStarting(FMLServerStartingEvent event)
    {
        event.registerServerCommand(new CommandStructureCapture());
    }
    
    @Override
    public EntityPlayer getPlayerEntityFromContext(MessageContext ctx)
    {
        return ctx.getServerHandler().player;
    }
}

The code should be self-explanatory. In this case we're overriding the methods with the the server-specific stuff which is typically not much.

Annotate And Instantiate The Proxy In Your Mod's Main Class


In your mod's main class (i.e. the one annotated with @Mod) 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.ServerProxy"
    )
public static IProxy 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 get loaded 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:

    /**
     * Pre-Initialization FML Life Cycle event handling method which is automatically
     * called by Forge. It must be annotated as an event handler.
     *
     * @param event the event
     */
    @EventHandler
    // preInit "Run before anything else. Read your config, create blocks, items, etc, and register them with the GameRegistry."
    public void preInit(FMLPreInitializationEvent event)
    {
        // DEBUG
        System.out.println("preInit() " + event.getModMetadata().name);

        Utilities.setModInfo(event);
        ModConfig.initConfig(event); // load configuration before doing anything else that may be controlled by it.
        // register stuff
        ModTileEntities.registerTileEntities();
        ModFluids.registerFluids();
        ModNetworking.registerSimpleNetworking();

        proxy.preInit(event);
    }

    /**
     * Initialization FML Life Cycle event handling method which is automatically
     * called by Forge. It must be annotated as an event handler.
     *
     * @param event the event
     */
    @EventHandler
    // Do your mod setup. Build whatever data structures you care about.
    // Register network handlers
    public void init(FMLInitializationEvent event)
    {
        // DEBUG
        System.out.println("init()");
        
        // DEBUG
        System.out.println("Registering gui handler");
        NetworkRegistry.INSTANCE.registerGuiHandler(instance, new GuiHandler());

        ModAdvancements.registerAdvancements();
        ModWorldGenerators.registerWorldGenerators();

        proxy.init(event);
    }

    /**
     * Post-Initialization FML Life Cycle event handling method which is automatically
     * called by Forge. It must be annotated as an event handler.
     *
     * @param event the event
     */
    @EventHandler
    // postInit "Handle interaction with other mods, complete your setup based on this."
    public void postInit(FMLPostInitializationEvent event)
    {
        // DEBUG
        System.out.println("postInit()");

        proxy.postInit(event);
    }


    /**
     * Fml life cycle.
     *
     * @param event the event
     */
    @EventHandler
    public void serverStarting(FMLServerStartingEvent event)
    {
        // DEBUG
        System.out.println("Server starting");

        proxy.serverStarting(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!

18 comments:

  1. Thank you, very helpful getting me started.

    ReplyDelete
  2. Even i do not have any knowledge about proxy and how we can use this in coding section. But as you are explain in a way from starts to end will have little bit idea about it. I am new to project and i want to work on project which is based on Microleaves proxy dedicated ip project and hope will get some success to setup and works fine with it. Great job and waiting for articles which is related to education and all. Keep sharing.

    ReplyDelete
  3. Great explanation, really answered a lot of my questions. Thank you very much!

    ReplyDelete
  4. If you don"t mind proceed with this extraordinary work and I anticipate a greater amount of your magnificent blog entries.  vpnveteran

    ReplyDelete
  5. I can set up my new idea from this post. It gives in depth information. Thanks for this valuable information for all,.. visita il sito

    ReplyDelete
  6. You guardians do an astounding web diary, and have some unfathomable substance. Continue doing extraordinary. besuche die Website

    ReplyDelete
  7. bookmarking and checking back frequently!it people processing it really is another person's renowned company, you will never in the world of the 55 and other lavishness brands supra to uncover which.. https://allertaprivacy.it

    ReplyDelete
  8. I'm constantly searching on the internet for posts that will help me. Too much is clearly to learn about this. I believe you created good quality items in Functions also. Keep working, congrats! privacyenbescherming

    ReplyDelete
  9. Regular visits listed here are the easiest method to appreciate your energy, which is why why I am going to the website everyday, searching for new, interesting info. Many, thank you https://privatnostonline.com

    ReplyDelete
  10. I needed to thank you for this phenomenal read!! I unquestionably adored each and every piece of it. I have you bookmarked your site to look at the new stuff you post. https://internetprivatsphare.ch

    ReplyDelete
  11. So luck to come across your excellent blog. Your blog brings me a great deal of fun.. Good luck with the site. les meilleurs vpn

    ReplyDelete
  12. I might want to thank you for the endeavors you have made in composing this article. I am trusting the same best work from you later on too..  netflix vpn

    ReplyDelete
  13. Assume paid for with the help of center, have discovered modern society; believed that protect on your playlists, you could potentially know most of the hassle; assumed ones step quit, much more is unable to drive; Imagine I would like adore, merely the caress. https://privacyonline.fi

    ReplyDelete
  14. Your post is very helpful to get some effective tips to reduce weight properly. You have shared various nice photos of the same. I would like to thank you for sharing these tips. Surely I will try this at home. Keep updating more simple tips like this.  lesmeilleursvpn.com

    ReplyDelete
  15. Your post is very helpful to get some effective tips to reduce weight properly. You have shared various nice photos of the same. I would like to thank you for sharing these tips. Surely I will try this at home. Keep updating more simple tips like this.  Klik hier

    ReplyDelete
  16. my forge isn't recognizing the "new MouseHelperAI()" code and my IDE it's me to create the MouseHelperAI class

    ReplyDelete
  17. Go to photo compressor to 70kb and Select a picture on your computer or phone then specify the desired size in kilobytes, megabytes or percentages and then click the compress button.

    ReplyDelete