CreativeMD Posted August 22, 2013 Share Posted August 22, 2013 Hi, Is there i way to add a field to a base class? I read this tutorial http://www.minecraftforge.net/wiki/Using_Access_Transformers. The auhtor writes about editing field, but not adding a field. I'm not really in this topic, i just started, because since 1.6 jar mods are really hard to install. So i have to transform my both jar mods to core mods: http://www.minecraftforum.net/topic/1795185-162universalrandom-additions-v056-pillar-air-jump-jetpack-and-much-more-2000-downloads/#entry22245488 http://www.minecraftforum.net/topic/1879772-162-world-generation-manager-v02-regenerate-a-specific-mod/ Thanks previously Quote Link to comment Share on other sites More sharing options...
Mazetar Posted August 22, 2013 Share Posted August 22, 2013 Coremod: http://www.minecraftforum.net/topic/1854988-tutorial-162-changing-vanilla-without-editing-base-classes-coremods-and-events-very-advanced/ Quote If you guys dont get it.. then well ya.. try harder... Link to comment Share on other sites More sharing options...
CreativeMD Posted August 22, 2013 Author Share Posted August 22, 2013 Thanks, i have only one question more, can i also edit or replace Forge Files? I will try it out, but i would be very good to know this. Quote Link to comment Share on other sites More sharing options...
Mazetar Posted August 22, 2013 Share Posted August 22, 2013 I believe you can, but you should make sure you know what you are doing before attempting to use ASM Also if you feel there's a very good and valid reason for the change to forge, please do write a post about it explaining the change and why it's useful, there may be that this change could be added later if it's useful to more than just your specific case Quote If you guys dont get it.. then well ya.. try harder... Link to comment Share on other sites More sharing options...
CreativeMD Posted August 22, 2013 Author Share Posted August 22, 2013 First, you probadly think that I'm not so much experienced in programming, but i had just no clue about this specific topic. (Don't understand that wrong!!!!!!!!! ) So my mod RandomAdditions adds a new items physic, to see how it works just visit my mod topic. Therefore i only have to overwrite some methods, but for my second mod this isn't possible. It allows you to regenerate a mod's worldgenerator. So i have to edit GameRegistry and overwrite the method registerWorldGenerator and change the field worldgenerators to public (need it for other things). I also have to replace the class Chunk because i have to add a new field for the mods that were generated in it. The last methods are the onChunkLoad and onChunkUnload (or some thing like that) in the AnvilChunkLoader class. I hope i could give you a little overview about this problem. Quote Link to comment Share on other sites More sharing options...
GotoLink Posted August 22, 2013 Share Posted August 22, 2013 You may want to look at the ChunkEvent. Quote Link to comment Share on other sites More sharing options...
CreativeMD Posted August 22, 2013 Author Share Posted August 22, 2013 You may want to look at the ChunkEvent. Yes, i'm using it, but for regnerate the needed mods. I have no access to the NBTData of the chunk so i can't save the information in the chunks data. So far so good, i will have to try it out. Thanks for fast and good answers. Quote Link to comment Share on other sites More sharing options...
hydroflame Posted August 22, 2013 Share Posted August 22, 2013 you could also maybe use only reflection, maybe this would be simpler then ASM (which usually hit people like a truck) Quote how to debug 101:http://www.minecraftforge.net/wiki/Debug_101 -hydroflame, author of the forge revolution- Link to comment Share on other sites More sharing options...
ILuvYouCompanionCube Posted August 23, 2013 Share Posted August 23, 2013 First of all, you need to create a coremod. One of the pages people linked probably already show you how to do that. Then you'll have to have a class that implements IClassTransformer. The only method this interface defines is transform: public class Transformer implements IClassTransformer { @Override //Imagine we wanted to add the field to the EntityPlayer class public byte[] transform(String className, String dontKnowWhatThisIs, byte[] bytecodeForClass) { //note that this will only work in a non obfuscated environment (i.e. running minecraft from eclipse). To make it work within an //obfuscated envirionment, you'll have to find out the obfuscated name for the class you want to add your field to. If you don't know //how to do that, I can elaborate the answer to show you how. if(className.equals("net.minecraft.entity.player.EntityPlayer")) { return patchEntityPlayer(bytecodeForClass); } //note that we return the bytecodes for every class other than the one(s) we need to alter unchanged return bytecodeForClass; } private byte[] patchEntityPlayer(byte[] bytecode, boolean isObfuscated) { //A ClassNode represents a class in a tree-like structure ClassNode classNode = new ClassNode(); //A ClassReader is able to read the java bytecode. It kinda foward events to the ClassVisitor it receaves through it's accept method. ClassReader classReader = new ClassReader(bytecode); //the method accept of the ClassReader let's a ClassVisitor in (ClassNode is a subclass of the abstract class ClassVisitor) //he ClassReader will now read the bytecode on behalf of the ClassVisitor (ClassNode) and call a lot of visit*something* method for it classReader.accept(classNode, 0); //to create a field we instantiate a FieldNode. The first argument is mandatory, the second is the access flag to the field, the third is //the name of the field, the fourth is the descriptor of the field (basically, you need to call Type.getDescriptor and pass the class of //the field as argument. In this case, we're creating a field of type String. The fifth argument is the signature of the field. Since I don't //know what's a signature in the context of a field, and since there's no problem in letting it be null, I set it as null. //The last argument is the initial value of the field. Since this value isn't inherited (I don't know why), we can't set it, //because EntityPlayer is, in game, EntityPlayerSP or EntityPlayerMP FieldNode newField = new FieldNode(Opcodes.ASM4, Opcodes.ACC_PUBLIC, "TheNewField", Type.getDescriptor(String.class), null, null); //ClassNode has a List<FieldNode> that you can access through it's "fields" field. I add my new field to it. classNode.fields.add(newField); //the ClassWriter will actually write the new bytecode. Think of this as a chain. from ClassReader to ClassNode to ClassWriter ClassWriter writer = new ClassWriter(0); classNode.accept(writer); //here we actually return the new bytecode for EntityPlayer, containing the new Field. return writer.toByteArray(); } I made a very basic item to test this Transformer: public class TestItem extends Item { public TestItem(int par1) { super(par1); setMaxDamage(100); } @Override public ItemStack onItemRightClick(ItemStack par1ItemStack, World world, EntityPlayer player) { par1ItemStack.setItemDamage(par1ItemStack.getItemDamage() + 1); Field theField; try { theField = player.getClass().getField("TheNewField"); String theFieldValue = (String)theField.get(player); player.addChatMessage("TheNewField had the value of " + theFieldValue); player.addChatMessage("Altering the TheNewField value to \"MAAATHEMATICAL!!\""); theField.set(player, "MAAATHEMATICAL!!"); theFieldValue = (String)theField.get(player); player.addChatMessage("TheNewField now has the value had the value of " + theFieldValue); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return par1ItemStack; } } Of course, using reflection everytime you'd need to access the item may not be a good idea. To minimize this problem we could at least make a field of type Field in our item class, and we'd avoid the call to Class.getField everytime, by making it just once and storing the return in our field of type Field. All sets and gets would still need reflection though (probably). Quote Link to comment Share on other sites More sharing options...
CreativeMD Posted August 23, 2013 Author Share Posted August 23, 2013 Hm, i think you understood me wrong, i have an idea how this could work, but i just have to try it out. This could take some time. But thanks for every help. Quote Link to comment Share on other sites More sharing options...
ILuvYouCompanionCube Posted August 23, 2013 Share Posted August 23, 2013 ILuvYouCompanionCube: How I solve this particular problem: Make an Interface which contains an abstract setter and getter method for your new field. Then with ASM not only add the field but also implement the interface (quite easy: just 2 new methods one GETFIELD one PUTFIELD). In your code you can then cast the minecraft class you transformed to your interface and call the getter/setter methods without needing reflection. Would look something like this: World world = // whatever String awesomeField = ((WorldProxy)world).getMyAwesomeField(); awesomeField = awesomeField.toLowerCase(); ((WorldProxy)world).setMyAwesomeField(awesomeField); I said it once and I'll say it again. You, my friend, are very smart. Loved the interface idea. Quote Link to comment Share on other sites More sharing options...
ILuvYouCompanionCube Posted August 23, 2013 Share Posted August 23, 2013 Hm, i think you understood me wrong, i have an idea how this could work, but i just have to try it out. This could take some time. But thanks for every help. I did understand you wrong. If you know how to do it, I have no idea why you made this question then... Quote Link to comment Share on other sites More sharing options...
hydroflame Posted August 23, 2013 Share Posted August 23, 2013 @dies, you could also make the change in your dev env, so that it compiles thinking there will be a field called "myAwesomeField" and make sure the coremod insert that field. this is how I would solve that. Quote how to debug 101:http://www.minecraftforge.net/wiki/Debug_101 -hydroflame, author of the forge revolution- Link to comment Share on other sites More sharing options...
CreativeMD Posted September 1, 2013 Author Share Posted September 1, 2013 @ILuvYouCompanionCube Sorry, that it takes me so long to answer: You already give me the solution to this problem, so i didn't understand why you still helped me. Thanks to all, for the fast and really god help. Quote Link to comment Share on other sites More sharing options...
hydroflame Posted September 1, 2013 Share Posted September 1, 2013 btw the easy way is to make a static hashmap .... Quote how to debug 101:http://www.minecraftforge.net/wiki/Debug_101 -hydroflame, author of the forge revolution- Link to comment Share on other sites More sharing options...
hydroflame Posted September 2, 2013 Share Posted September 2, 2013 number 1 youre right number 2 you can prevent by overriding the "finalize" method and removing the object just saying hashmap are easier to use then asm Quote how to debug 101:http://www.minecraftforge.net/wiki/Debug_101 -hydroflame, author of the forge revolution- Link to comment Share on other sites More sharing options...
hydroflame Posted September 2, 2013 Share Posted September 2, 2013 Therefore you would need to edit the class again. And also: ewww finalizers. oh .... right .... DERP MODE ACTIVATE !! Quote how to debug 101:http://www.minecraftforge.net/wiki/Debug_101 -hydroflame, author of the forge revolution- Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.