Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I add a method to a source file without editing the source file?

I am trying to add a method to a Minecraft source file, but I have to figure out how to do it without actually editing the source files, since it is illegal to redistribute source files which would have to be included in the mod I am creating. I need to add the method setInPortalZub() to the file "EntityPlayer located in net.minecraft.entity.player. I am using the MCP / Minecraft Forge API. I have tried creating an instance of EntityPlayer, but I'm not exactly sure how that would work.

like image 903
Andrew Graber Avatar asked Jan 12 '23 11:01

Andrew Graber


1 Answers

You are about to enter the wonderful and frustrating world of coremods! Coremods in FML (Forge ModLoader) are the "easiest" way to inject arbitrary code into vanilla Minecraft classes without having to distribute modified versions of those class files.

This is accomplished by utilizing the ASM Bytecode manipulation framework released by Object Web. This framework allows you to write java code that can read and manipulate the bytecode of a class at load time.

It is impossible for me to explain every step you must take to accomplish this feat, so instead I will post links to my own coremod injection classes and attempt to give an explanation of each.

Here is the CorePlugin class.

The CorePlugin class tells Forge ModLoader where to find your transformer class that does the actual code injection.

This class is found by FML based on your .jar file manifest:

Manifest-Version: 1.0
FMLCorePlugin: bspkrs.treecapitator.fml.asm.TreeCapitatorCorePlugin
FMLCorePluginContainsFMLMod: bspkrs.treecapitator.fml.TreeCapitatorMod
Created-By: 1.7.0 (Oracle Corporation)

FMLCorePlugin specifies the fully qualified path to your CorePlugin class. If your .jar file is to contain a regular @Mod style Forge ModLoader mod class as well you will also need to specify FMLCorePluginContainsFMLMod (although the expected value is unknown; I don't think it actually matters what you put for the value there, but the key must be there).

Now for the fun part... the actual bytecode transformer. Here is a link to the transformer for Treecapitator

Without going into too much detail, I wrote this class to be able to handle execution both in Eclipse as well as in "production". That's why there are two HashMaps; one for MCP execution and one for obfuscated execution. Every class that gets loaded is first passed into the transform() method. The code checks to see if it's a class we want to transform and transforms it if it is.

The end result of implementing all this is that whenever an instance of ItemInWorldManager is created the transformer runs and adds a single line to a specific location within the removeBlock() method. This single line serves as a cheap block break hook to allow for code to execute when a player breaks a block.


Tips:

  • Get the ByteCode Outline plugin for Eclipse. You can find it on the Object Web website.
  • Sometimes the class structure isn't the same in Eclipse/MCP as it is in an obfuscated environment
  • These are not easy concepts to wrap your head around. Use the Bytecode Outline plugin to view the class you are transforming both with and without the code you want it to contain. That should help you figure out what "landmarks" to look for and what ASM nodes you'll need to insert.

I hope that helps!

EDIT: fixed the broken links to reference an old branch that still contains the classes.

like image 109
bspkrs Avatar answered Jan 29 '23 20:01

bspkrs