PSN:
PSN, I'm assuming, stands for Psychic Super Narwhal.
Member Details
Hello folks!
First up, don't PM me for help about this tutorial, it's what this thread is for. Don't derail though - if you have an unrelated question, PM me.
That being said, I see quite a few requests on the Modification Development Thread for a way to modify vanilla values to make Gold stronger or give Diamonds less damage. In fact, I've even posted one such request. So, this is a tutorial on my findings. We'll explore Reflection in Java by editing Gold's properties to make it much better, somewhere between Iron and Gold.
The first thing you want to do whenever you are working on Reflection with a class is to find it's field indexes. A field is the name for a class-wide variable. They have names, and you can get a reference to the field through its name; however, as I found out the hard way, it won't work once you deploy the mod due to obfuscation. So, now down to the actual code, which should be placed in your preInit method:
(The forum hates me, so this is on pastebin) http://pastebin.com/61PnzivG
Obviously, change ToolMaterial.class to whatever class you are messing with. After typing any of the code in this post, do Ctrl+Shift+O and Ctrl+Shift+F, if you are in Eclipse. What the code does is ask the class to give us a list of every field it defines, whether it be public, protected, private, or other, then prints out that list and tells us the index that each field can be found at. The above code prints out:
[0] public static final net.minecraft.item.Item$ToolMaterial net.minecraft.item.Item$ToolMaterial.WOOD<br>[1] public static final net.minecraft.item.Item$ToolMaterial net.minecraft.item.Item$ToolMaterial.STONE<br>[2] public static final net.minecraft.item.Item$ToolMaterial net.minecraft.item.Item$ToolMaterial.IRON<br>[3] public static final net.minecraft.item.Item$ToolMaterial net.minecraft.item.Item$ToolMaterial.EMERALD<br>[4] public static final net.minecraft.item.Item$ToolMaterial net.minecraft.item.Item$ToolMaterial.GOLD<br>[5] private final int net.minecraft.item.Item$ToolMaterial.harvestLevel<br>[6] private final int net.minecraft.item.Item$ToolMaterial.maxUses<br>[7] private final float net.minecraft.item.Item$ToolMaterial.efficiencyOnProperMaterial<br>[8] private final float net.minecraft.item.Item$ToolMaterial.damageVsEntity<br>[9] private final int net.minecraft.item.Item$ToolMaterial.enchantability<br>[10] private static final java.lang.String net.minecraft.item.Item$ToolMaterial.__OBFID<br>[11] public net.minecraft.item.Item net.minecraft.item.Item$ToolMaterial.customCraftingMaterial<br>[12] private static final net.minecraft.item.Item$ToolMaterial[] net.minecraft.item.Item$ToolMaterial.$VALUES
So this tells us that enchantability is at index 9, whereas harvestLevel is at index 5. Remove that chunk of code from preInit now, but copy the output list to Notepad or your local variant for later reference.
Now, let's mess around with Gold a bit. We'll use ReflectionHelper to change the variables. It can deal with private, protected, and even static or final fields!
All of the following code will go in preInit.
Let's boost Gold's harvest level so it can mine diamonds. harvestLevel is found at index 5, and we need a harvestLevel of 2.
Efficiency on the proper material has to be set for each tool using ItemTool.class, because reasons.
Durability can be set using the public method setMaxDamage on each tool, no Reflection required.
Messing with Enchantability seems to break the ability to enchant Golden things, I'll look into this if anyone is interested.
Damage can be set in a similar way to Durability.
If anyone needs more help with this, post it here! I'll be glad to help.
PSN:
PSN, I'm assuming, stands for Psychic Super Narwhal.
Member Details
ReflectionHelper is offered by Forge directly, and it's a convenient shortcut. It's also easier to read and looks nicer. But normal Reflection classes will work just the same way.
Rollback Post to RevisionRollBack
If I'm being mean, tell me. Chances are, I'm not trying to be.
I reject your reality and substitute Minecraft.
Java means Coffee and Coding. Matrix means Math and Programmers who Fight Robots. Together, they mean me.
[18:14:02] [Client thread/ERROR] [FML]: Caught exception from wildbill22_draco
cpw.mods.fml.relauncher.ReflectionHelper$UnableToAccessFieldException: java.lang.IllegalAccessException: Can not set static final net.minecraft.item.Item field net.minecraft.init.Items.bone to net.wildbill22.draco.items.ItemMyBone
at cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(ReflectionHelper.java:135) ~[forgeSrc-1.7.10-10.13.2.1291.jar:?]
at net.wildbill22.draco.items.ItemMyBone.replaceItemBone(ItemMyBone.java:28) ~[main/:?]
For the 2nd parameter of setPrivateValue, I used null, since there is no instance available of the Items class. I think that was right, so why didn't this work?
Your tutorial says it will work with final objects, but I think after reading how the set method works in this helper function, it says: "If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this Field object and the field is non-static." So maybe it can't be done?
To change a final field, you'll need to remove the final keyword first, this can be done by changing the modifiers field of the Field class itself. There are instructions on how to do so on StackOverflow: http://stackoverflow.com/a/3301720
Rollback Post to RevisionRollBack
I AM NOT YOUR PERSONAL MINECRAFT MOD SUPPORT AGENT, SO PLEASE DO NOT PM ME ABOUT PROBLEMATIC MODS THAT ARE NOT MINE. If you're having trouble/crashes with a mod, you'll have better luck resolving it in this forum section than PMing me. If you already made a topic, be patient about responses. If you have troubles with anything non-Minecraft related on your PC, I might be able to help, though, but no promises. Even though I could wish to be, I'm not a wizard.
What bilde said. In addition, I think you have to use a separate method for static fields.
Hmm, not sure what you mean by separate method. I ended up with this funciton:
public static void replaceItemBone() {
try {
Field f = Items.class.getDeclaredFields()[96];
f.setAccessible(true);
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL); // Remove final
f.set(null, ModItems.bone);
}
catch (Exception e) {
throw new UnableToAccessFieldException(new String[0], e);
}
}
It doesn't throw an exception, but it also doesn't seem to actually replace the Items.bone like I wanted it to. This is something I'd like to add to my mod, but it is just a minor feature I can do without, but sure would be cool if I could get this to work
First up, don't PM me for help about this tutorial, it's what this thread is for. Don't derail though - if you have an unrelated question, PM me.
That being said, I see quite a few requests on the Modification Development Thread for a way to modify vanilla values to make Gold stronger or give Diamonds less damage. In fact, I've even posted one such request. So, this is a tutorial on my findings. We'll explore Reflection in Java by editing Gold's properties to make it much better, somewhere between Iron and Gold.
The first thing you want to do whenever you are working on Reflection with a class is to find it's field indexes. A field is the name for a class-wide variable. They have names, and you can get a reference to the field through its name; however, as I found out the hard way, it won't work once you deploy the mod due to obfuscation. So, now down to the actual code, which should be placed in your preInit method:
(The forum hates me, so this is on pastebin)
http://pastebin.com/61PnzivG
Obviously, change ToolMaterial.class to whatever class you are messing with. After typing any of the code in this post, do Ctrl+Shift+O and Ctrl+Shift+F, if you are in Eclipse. What the code does is ask the class to give us a list of every field it defines, whether it be public, protected, private, or other, then prints out that list and tells us the index that each field can be found at. The above code prints out:
So this tells us that enchantability is at index 9, whereas harvestLevel is at index 5. Remove that chunk of code from preInit now, but copy the output list to Notepad or your local variant for later reference.
Now, let's mess around with Gold a bit. We'll use ReflectionHelper to change the variables. It can deal with private, protected, and even static or final fields!
All of the following code will go in preInit.
Let's boost Gold's harvest level so it can mine diamonds. harvestLevel is found at index 5, and we need a harvestLevel of 2.
Efficiency on the proper material has to be set for each tool using ItemTool.class, because reasons.
Durability can be set using the public method setMaxDamage on each tool, no Reflection required.
Messing with Enchantability seems to break the ability to enchant Golden things, I'll look into this if anyone is interested.
Damage can be set in a similar way to Durability.
If anyone needs more help with this, post it here! I'll be glad to help.
ASM ASM ASM
I believe in the Invisible Pink Unicorn, bless her Invisible Pinkness.
Coming soon:
-HoverBoat port for 1.7.10 (Old version from ShaRose) - 90%
-TF2-like Killcam - 5%
-Simple Config File Block Adder - 50%
-Ender Pig - 80%
(Damn, I need to finish these!)
My mods:
-Ingame Account Switcher - Lets you change your account info ingame without having to restart Minecraft!
-Crafty Utils - Adds some random useful early-late game content
Arch Linux supporter since 2012!
Sorry, didn't see this post for some reason. Can you paste your list of fields from the first step? That is, if you still need help.
I found the fields in Items, and wanted to change this line:
[96] public static final net.minecraft.item.Item net.minecraft.init.Items.bone
I added this line:
ReflectionHelper.setPrivateValue(Items.class, null, ModItems.bone, 96);
It gets this error:
[18:14:02] [Client thread/ERROR] [FML]: Caught exception from wildbill22_draco
cpw.mods.fml.relauncher.ReflectionHelper$UnableToAccessFieldException: java.lang.IllegalAccessException: Can not set static final net.minecraft.item.Item field net.minecraft.init.Items.bone to net.wildbill22.draco.items.ItemMyBone
at cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(ReflectionHelper.java:135) ~[forgeSrc-1.7.10-10.13.2.1291.jar:?]
at net.wildbill22.draco.items.ItemMyBone.replaceItemBone(ItemMyBone.java:28) ~[main/:?]
For the 2nd parameter of setPrivateValue, I used null, since there is no instance available of the Items class. I think that was right, so why didn't this work?
Your tutorial says it will work with final objects, but I think after reading how the set method works in this helper function, it says: "If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this Field object and the field is non-static." So maybe it can't be done?
Thanks.
[url=2482915-wip-arkcraft-survival-evolved-dinos-taming]
To change a final field, you'll need to remove the final keyword first, this can be done by changing the modifiers field of the Field class itself. There are instructions on how to do so on StackOverflow: http://stackoverflow.com/a/3301720
I AM NOT YOUR PERSONAL MINECRAFT MOD SUPPORT AGENT, SO PLEASE DO NOT PM ME ABOUT PROBLEMATIC MODS THAT ARE NOT MINE. If you're having trouble/crashes with a mod, you'll have better luck resolving it in this forum section than PMing me. If you already made a topic, be patient about responses. If you have troubles with anything non-Minecraft related on your PC, I might be able to help, though, but no promises. Even though I could wish to be, I'm not a wizard.
What bilde said. In addition, I think you have to use a separate method for static fields.
Hmm, not sure what you mean by separate method. I ended up with this funciton:
public static void replaceItemBone() {
try {
Field f = Items.class.getDeclaredFields()[96];
f.setAccessible(true);
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL); // Remove final
f.set(null, ModItems.bone);
}
catch (Exception e) {
throw new UnableToAccessFieldException(new String[0], e);
}
}
It doesn't throw an exception, but it also doesn't seem to actually replace the Items.bone like I wanted it to. This is something I'd like to add to my mod, but it is just a minor feature I can do without, but sure would be cool if I could get this to work
[url=2482915-wip-arkcraft-survival-evolved-dinos-taming]
I'm fairly sure that there are guards in place against replacing vanilla items/blocks, since I've tried it myself to no avail... sorry