Minecraft Forge Modding: Using A Proxy

Introduction

In a client-server game, you ideally want:

  • All the game logic to only run on the server as that prevents cheating -- you wouldn't want people able to install a client that changed their health or similar.
  • All the user interface output (graphics and sound) to be generated only on the client -- you don't need to clutter the server file system with textures and sound files.
  • All the user interface input (mouse, keyboard, gamepad, touchpad, etc.) to be interpreted on the client because each user might want different key mappings and then relayed to the server.

However, in practice the game graphics update much more frequently and consistently than the network can keep up with so waiting for the server to give updates on the entire game state will cause lag and non-smooth movement.

Therefore, all modern networked client-server games need to run some game logic on the client side that smooths out the gameplay experience. For example, in Minecraft the player movement is actually processed on the client side and the server just checks to make sure the movement was "legal".

Key Point: In order to keep gameplay smooth, some server-side game logic is also run on the client and smooth player motion is entirely run on the client.

After figuring out which side each type of functionality needed to run on, the Minecraft developers decided they would like to not load certain classes on the server or client if not needed on that side and used an @SideOnly annotation for such classes. The @SideOnly annotation on vanilla source indicates that the code is not included in the JAR at build time. This allows the dedicated server JAR to be quite compact.

Key Point: The vanilla JAR files are stripped of unnecessary code based on the @SideOnly annotation. Modders can use @SideOnly annotation but it doesn't affect the build and is only informational and style-wise is typically only included for things that extend vanilla-annotated code.

WarningJava will crash if you try to access a class, method or field that is not loaded due to being annotated for the other side.

Tip: Modders mostly have trouble with the Side.CLIENT code as it is of common interest to modding. The Side.SERVER stuff is mostly things like user authentication and such which is rarely touched by modders.

All the above would be fairly simple, except Minecraft's Java implementation has a couple tricky points:
  • Minecraft is a client-server game even if it is running on a single player computer. However, when Minecraft runs on a single player computer they run both in the same Java executable, so really it is an "integrated client".

Key Point: The client and server always run in separate threads, but in single player mode both threads run in a single JVM so classes loaded on each side are available to both threads.

Therefore, mod developers can get confused because they might do their testing mostly on an integrated server. In the case of the integrated server, the Java execution needs both sides, so all the classes are available and it won't crash. But as soon as you take same code and run on dedicated server it might crash if you try to access classes from the wrong side.

Warning: On an integrated server, the @SideOnly problems will be "hidden" because the Java executable will load both sides.

Key PointAlways test your mod frequently as dedicated server and client to ensure you haven't made a mistake of calling @SideOnly from the wrong side.

Use The Proxies To Manage Sided Functionality


To help manage this for modding, they have come up with a "proxy" system. The proxy is a set of classes that group your common, client and sometimes server methods based on the side that is running. Basically with the proxy different versions of the "same" classes and methods will be loaded by Java, avoiding crashes due to missing classes and methods (since you always provide one)

When To Use @SideOnly In Your Own Code


Mostly you should not use @SideOnly in your own code unless you're forced to by inheritance (if you extend a class that is annotated you'll have to also annotate your class, etc.). Instead you should put any sided functionality into the proxy. 

However, sometimes if you're making a lot of client side code and feel strongly that you want the server JAR to be compact you can add the annotation. Just make sure you use it appropriately.

How To Organize Your Proxies


Check out my detailed tutorial: Jabelar's Organizing Your Proxies Tutorial.

Further Reading


There is now some documentation on the Forge site explaining the side concept.

No comments:

Post a Comment