Minecraft fabric overriding existing blocks 1.20

128 Views Asked by At

I have been trying to find a way online to find any way to modify existing blocks in minecraft fabric and there properties, and yet all I could find was how to create new blocks. Any that I do find a for versions below 1.20.

I aactually could not find a way to override existing block properties at all.overriding did not work either

1

There are 1 best solutions below

0
Samū On

What you essentially want to do is re-register a Block instance that Minecraft already registered. But there is a reason why nobody ever documented how to do that: you shouldn't.

Re-registering a block in Minecraft can cause to weird issues, especially when your mod will be used in large mod packs. This has to do with compatibility with other mods, and even Minecraft itself. Preferably, you want to avoid that. There are a dozen other solutions to alter the behaviour of a specific block without causing too much issues. They include but aren't limited to:

  • Simply adding your block to one of Minecraft's built in tags - you don't even need Java code for this, just a JSON file in your data pack: https://minecraft.fandom.com/wiki/Tag. This can, for example, make stone mineable with a shovel.
  • Use one of the callbacks provided by the Fabric API to listen for certain events you wanna handle. This can, for example, turn grass blocks into dirt when the player clicks on it.
  • Make a so called "extension block", which can behave as a custom state property of a block. I.e. if you want to give minecraft:stone an age property (for whatever reason that may be useful), treat minecraft:stone as age=0 and create a custom block (e.g. modid:aged_stone) with an age property from 1 to whatever max age to extend the age range.

Another, more generic approach is building a Mixin into the Block class or an appropriate subclass, and do something like the following to target a specific block (stone in this case):

Block self = (Block) (Object) this;
if (BuiltInRegistries.BLOCK.getKey(self).equals(new ResourceLocation("stone"))) {
    // Do something only if this block is stone
}

However, if you really really really wanna replace a block instance entirely, here's a suggestion: Use a Mixin to inject in Registry.register that replaces a specific block instance with a custom one:

@Mixin(Registry.class)
public class RegistryMixin {
    @Inject(
        // You may need to specify the correct signature after the method
        // name because there are two `register` methods.
        method="register",
        at=@At("HEAD"),
        cancelable=true
    )
    // Note that this is a generic method, in Mixin you'll have to use
    // Object to replace type parameters
    private static void onRegister(Registry reg, ResourceLocation id, Object value, CallbackInfoReturnable<Object> cir) {
        if (reg != BuiltInRegistries.BLOCK) return;
        if (!id.toString().equals("minecraft:stone")) return;

        // Now that you've filtered out the minecraft:stone block,
        // you can re-register it
        Block myCustomBlock = new Block(.......);
        ((WritableRegistry) reg).register(id, myCustomBlock);
        cir.setReturnValue(myCustomBlock);
    }
}

But once again, try to avoid this solution. Here be dragons.

Note, I have not tested any of the code fragments because I don't have a modding environment at hand at the time of writing. It may need tweaking in order to work. Also, I used Mojang's official mappings, things may be named differently if you use Yarn mappings. For example, ResourceLocation is named Identifier in Yarn.


I hope this helps. Happy coding!