Jump to content

[1.7] Overwrite Vanilla Items


mrkirby153

Recommended Posts

I am working on aliasing.

 

It will be possible to force the "minecraft:milk" name to point at a different block/item, as an example. The original block/item won't be replaced, so much as any requests for it will become diverted. This is not in FML yet.

Link to comment
Share on other sites

You can rename items and blocks through the language files.

But what Railcraft probably do is replacing the recipe.

Write your recipe like the original one, then put your item for the result.

 

I suppose I could do that however whenever rail craft loads up "[fml.itemtracker] A mod "Railcraft" is overwriting item rail" or something similar to that comes up. And you can't find the original rails in the creative menu or nei

Link to comment
Share on other sites

  • 4 weeks later...

I belive RailCraft overwrote the vanilla rails with the itemList[] that existed in 1.6.4. But since that registered items/itemblocks using ID's it was removed in the update. Therefor that wouldn't work in 1.7.4. So we have to wait for cpw's amazing wonders of awesomeness  :D

Link to comment
Share on other sites

My only suggestion is to get into class transformation with core modding. It does require an enormous amount of effort to properly get into, but I find it to be extremely valuable for certain tasks, and it opens up vast amounts of possibilities. This is the tutorial that got me into it: http://www.minecraftforum.net/topic/1854988-/

 

In my mod, I replace both bedrock and coal ore with blocks of a new class to add new behaviour to them. Yes, they aren't items, but it's very much the same process with the same result. To do so, I edit the very code in net.minecraft.block.Block as it is loaded by the JVM. If you follow this method, you will be editing the code in net.minecraft.item.Item, which is very similar. The method you need to modify is the registerItems() method.

 

Iterating through the bytecode instructions, you will be looking for the LDC instruction that loads a string equal to whatever the name of the item you are looking for is. The string name should be equal to the name that is used in net.minecraft.init.Items. You will use this string as an anchor to locate and modify the respective instructions. You should make sure that the string should only be found once, because it is not unusual to see the string two times while the item is being constructed.

 

Say you wish to replace the vanilla feather by replacing the vanilla feather item with your custom ItemFeather item. You will be looking for the LDC instructions that loads the highlighed string below:

itemRegistry.addObject(288, "feather", (new Item()).setUnlocalizedName("feather").setCreativeTab(CreativeTabs.tabMaterials).setTextureName("feather"));

 

After your class transformation, it would programmatically be changed to this:

itemRegistry.addObject(288, "feather", (new ItemFeather()).setUnlocalizedName("feather").setCreativeTab(CreativeTabs.tabMaterials).setTextureName("feather"));

 

The instruction after the LDC would be a NEW instruction of type "net/minecraft/item/Item". You would have to change that to "package/package/etc/ItemFeather". The instruction after that would be a DUP instruction. Instructions after this one will vary. It depends on the amount of constructor parameters, but it usually takes only one instruction to load each parameter. The feather uses no constructor parameters, meaning the instruction after the DUP instruction will be INVOKESPECIAL, which is the constructor call. The owner of this would have to be changed to "package/package/etc/ItemFeather".

 

To apply this example to other cases, here are some tips: If you want to override an item with a new class, make sure your new class extends the original class. The constructor of your new class should have the same parameters as well.

 

This is how I replaced the two blocks in my mod:

public byte[] patchClassBlock(byte[] data, boolean obfuscated)
{
String classBlock = obfuscated ? c.get("Block") : "net/minecraft/block/Block";

String methodRegisterBlocks = obfuscated ? "p" : "registerBlocks";
String methodSetHardness = obfuscated ? "c" : "setHardness";

ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(data);
classReader.accept(classNode, 0);

boolean bedrockFound = false;
boolean coal_oreFound = false;

for(int i = 0; i < classNode.methods.size(); i++)
{
	MethodNode method = classNode.methods.get(i);
	if(method.name.equals(methodRegisterBlocks) && method.desc.equals("()V"))
	{
		for(int j = 0; j < method.instructions.size(); j++)
		{
			AbstractInsnNode instruction = method.instructions.get(j);
			if(instruction.getOpcode() == LDC)
			{
				LdcInsnNode ldcInstruction = (LdcInsnNode)instruction;
				if(ldcInstruction.cst.equals("bedrock"))
				{
					if(!bedrockFound)
					{
						((TypeInsnNode)method.instructions.get(j + 1)).desc = "glenn/gases/BlockBedrock";
						((MethodInsnNode)method.instructions.get(j + 4)).owner = "glenn/gases/BlockBedrock";
					}
					bedrockFound = true;
				}
				else if(ldcInstruction.cst.equals("coal_ore"))
				{
					if(!coal_oreFound)
					{
						((TypeInsnNode)method.instructions.get(j + 1)).desc = "glenn/gases/BlockCoalOre";
						((MethodInsnNode)method.instructions.get(j + 3)).owner = "glenn/gases/BlockCoalOre";
					}
					coal_oreFound = true;
				}
			}
		}
	}
}

ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
return writer.toByteArray();
}

 

Have fun!

Link to comment
Share on other sites

  • 11 months later...

This is how I replaced the two blocks in my mod:

public byte[] patchClassBlock(byte[] data, boolean obfuscated)
{
String classBlock = obfuscated ? c.get("Block") : "net/minecraft/block/Block";

String methodRegisterBlocks = obfuscated ? "p" : "registerBlocks";
String methodSetHardness = obfuscated ? "c" : "setHardness";

ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(data);
classReader.accept(classNode, 0);

boolean bedrockFound = false;
boolean coal_oreFound = false;

for(int i = 0; i < classNode.methods.size(); i++)
{
	MethodNode method = classNode.methods.get(i);
	if(method.name.equals(methodRegisterBlocks) && method.desc.equals("()V"))
	{
		for(int j = 0; j < method.instructions.size(); j++)
		{
			AbstractInsnNode instruction = method.instructions.get(j);
			if(instruction.getOpcode() == LDC)
			{
				LdcInsnNode ldcInstruction = (LdcInsnNode)instruction;
				if(ldcInstruction.cst.equals("bedrock"))
				{
					if(!bedrockFound)
					{
						((TypeInsnNode)method.instructions.get(j + 1)).desc = "glenn/gases/BlockBedrock";
						((MethodInsnNode)method.instructions.get(j + 4)).owner = "glenn/gases/BlockBedrock";
					}
					bedrockFound = true;
				}
				else if(ldcInstruction.cst.equals("coal_ore"))
				{
					if(!coal_oreFound)
					{
						((TypeInsnNode)method.instructions.get(j + 1)).desc = "glenn/gases/BlockCoalOre";
						((MethodInsnNode)method.instructions.get(j + 3)).owner = "glenn/gases/BlockCoalOre";
					}
					coal_oreFound = true;
				}
			}
		}
	}
}

ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
return writer.toByteArray();
}

 

Have fun!

 

When I try to use the "c.get("Block")" function in my code, I get the error: "c cannot be resolved." Have you defined the variable c offscreen, or is my eclipse debug profiler just buggy?

Link to comment
Share on other sites

I actually tried to figure out the same thing just yesterday, and I managed to do it without a Core Mod. I'm using 1.8, so I'm not sure if my code will work in 1.7.

 

First add those to attributes to your mod class:

private FMLControlledNamespacedRegistry<Item> iItemRegistry;
private Method addObjectRaw;

 

Second add this to your preInit:

try {
    Method getMain = GameData.class.getDeclaredMethod("getMain");
    getMain.setAccessible(true);
    GameData gameData = (GameData) getMain.invoke(null);

    Field f = GameData.class.getDeclaredField("iItemRegistry");
    f.setAccessible(true);
    iItemRegistry = (FMLControlledNamespacedRegistry<Item>) f.get(gameData);

    addObjectRaw = FMLControlledNamespacedRegistry.class.getDeclaredMethod("addObjectRaw", Integer.TYPE, Object.class, Object.class);
    addObjectRaw.setAccessible(true);

} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

 

The last thing you have to do is call addObjectRaw.invoke in your init:

addObjectRaw.invoke(iItemRegistry, <item it to overwrite>, new ResourceLocation(<resource name>), <item to overwrite with>);

 

 

NOTE: You have to manually replace the Method and Field names with their obfuscated names before releasing the mod or do something like this:

Method getMain;
try {
    try {
        getMain = GameData.class.getDeclaredMethod("getMain");
    } catch(NoSuchMethodException e) {
        getMain = GameData.class.getDeclaredMethod("<Obfuscated name>");
    }
} catch(Exception e) {
}

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hey folks. I am working on a custom "Mecha" entity (extended from LivingEntity) that the player builds up from blocks that should get modular stats depending on the used blocks. e.g. depending on what will be used for the legs, the entity will have a different jump strength. However, something unexpected is happening when trying to override a few of LivingEntity's functions and using my new own "Mecha" specific fields: instead of their actual instance-specific value, the default value is used (0f for a float, null for an object...) This is especially strange as when executing with the same entity from a point in the code specific to the mecha entity, the correct value is used. Here are some code snippets to better illustrate what I mean: protected float jumpMultiplier; //somewhere later during the code when spawning the entity, jumpMultiplier is set to something like 1.5f //changing the access to public didn't help @Override //Overridden from LivingEntity, this function is only used in the jumpFromGround() function, used in the aiStep() function, used in the LivingEntity tick() function protected float getJumpPower() { //something is wrong with this function //for some reason I can't correctly access the fields and methods from the instanciated entity when I am in one of those overridden protected functions. this is very annoying LogUtils.getLogger().info(String.valueOf(this.jumpMultiplier))) //will print 0f return this.jumpMultiplier * super.getJumpPower(); } //The code above does not operate properly. Written as is, the entity will not jump, and adding debug logs shows that when executing the code, the value of this.jumpMultiplier is 0f //in contrast, it will be the correct value when done here: @Override public void tick() { super.tick(); //inherited LivingEntity logic //Custom logic LogUtils.getLogger().info(String.valueOf(this.jumpMultiplier))) //will print 1.5f } My actual code is slightly different, as the jumpMuliplier is stored in another object (so I am calling "this.legModule.getJumpPower()" instead of the float), but even using a simple float exactly like in the code above didn't help. When running my usual code, the object I try to use is found to be null instead, leading to a crash from a nullPointerException. Here is the stacktrace of said crash: The full code can be viewed here. I have found a workaround in the case of jump strength, but have already found the same problem for another parameter I want to do, and I do not understand why the code is behaving as such, and I would very much like to be able to override those methods as intended - they seemed to work just fine like that for vanilla mobs... Any clues as to what may be happening here?
    • Please delete post. Had not noticed the newest edition for 1.20.6 which resolves the issue.
    • https://paste.ee/p/GTgAV Here's my debug log, I'm on 1.18.2 with forge 40.2.4 and I just want to get it to work!! I cant find any mod names in the error part and I would like some help from the pros!! I have 203 mods at the moment.
    • In 1.20.6 any potion brewed in the brewing stand disappears upon completion.
    • My game crashes whenever I click on Singleplayer then it crashes after the "Saving world". I'm playing on fabric 1.20.1 on forge for the easy instance loading. My game is using 12GB of RAM, I tried deleting the options.txt, and also renaming the saves file but neither worked. Here's the crash report link: https://mclo.gs/qByOqVK
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.