Página 1 de 1

[Minecraft Java] Increasing the "item range" / "item reach" of an item in a Fabric mod (DRAFT)

Enviado: 07 Jun 2023, 00:22
por Legacy
Increasing the reach of an item with Fabric:
-- This is not a complete tutorial, this text assumes you already know how to create simple Fabric mods. --
-- I've just written how I increased it in my mod --

I'm currently writing a Fabric mod to add custom weapons to Minecraft, such as war axes, halberds, and spears, and I decided to increase the attack reach of certain added weapons - such as daggers, halberds and spears - to balance them out and not to make some overpowered. After looking for a way to do so, the reach-entity-attributes library written by JamiesWhiteShirt was found.

However, I decided against using it due to its complexity and the fact that it would become a dependency to my mod, potentially causing issues. e.g. If the Maven repository set up by the author on his own server (!) gets taken down, or the library no longer gets updated for new Minecraft versions, it'd prevent me from compiling (without extra steps) or updating a mod I created. So I went ahead and did a little more research to find a simpler solution - this time by looking at game classes, and found a way to increase the attack reach without external libraries.

By changing the return value of the getPickRange() method in the MultiPlayerGameMode class: (⚠: RED = Mojang mappings)
(For yarn - Fabric's default - it's onGetReachDistance() and ClientPlayerInteractionManager) it's possible to extend the player reach if any condition you specify is met by the player!

To do so, you need to write a "Mixin".
(The Mixin framework created by the Sponge project developers is a tool which allows mod creators to modify already existing game code.)
SpoilerAbrir
(Yarn is the default one, and the one you'd be interested if making a Minecraft mod, it's the one used by fabric-example-mod and the Minecraft Development IDEA plugin.)
(The Mojang obfuscation map is only USED if working w/ MCP Reborn - for editing classes without using Mixins (discouraged), studying the original game code -- or.. if you're stubborn like me and insist on using it - I use it because it forces me to figure things out in my own, as there aren't many mods made with Mojang names.)

This is how I did it in my mod:

Código: Selecionar tudo

// MultiPlayerGameModeMixin.java
@Mixin(MultiPlayerGameMode.class)
public class MultiPlayerGameModeMixin {
    @Inject(method="getPickRange", at=@At("HEAD"), cancellable = true)
    public void getPickRange(CallbackInfoReturnable<Float> cir){
        Player player = Minecraft.getInstance().player;
        if(player != null && player.getMainHandItem().getItem() instanceof Halberd){
            cir.setReturnValue(6.0f);
        }
    }
}
The code I wrote, increases the player reach while using any "Halberd" from my Minecraft mod and is added to the beggining of the "MultiPlayerGameMode" class by the Mixin framework.

SpoilerAbrir
This is how the original class looks like:
SpoilerAbrir

Código: Selecionar tudo

public float getPickRange() {
    if (this.localPlayerMode.isCreative()) {
        return 5.0f;
    }
    return 4.5f;
}
After the Mixin injection:
SpoilerAbrir

Código: Selecionar tudo

public float getPickRange() {
    Player player = Minecraft.getInstance().player;
    if(player != null && player.getMainHandItem().getItem() instanceof Halberd){
        cir.setReturnValue(6.0f);
    }
    if (this.localPlayerMode.isCreative()) {
        return 5.0f;
    }
    return 4.5f;
}
It can be adapted to any other item by changing the if condition, 6.0f is the block distance.

I don't expect MixMods forums users to use this information. But I felt essential to share this information here as it easily gets indexed by Google. If someone ever faces the exact same issue while writing a mod, this post will pop-in the results. It seems that nowadays, Minecraft mod developers rely heavily on Discord, which often results in valuable information getting lost in the vast sea of conversations. While searching on the internet, I often find 2014-2015 modding information in the Forge Mod Loader Forums, but almost never up to date information because of this particular issue!

Adapting it to yarn mappings shouldn't be difficult w/ IntelliJ IDEA or Eclipse code suggestions & the yarn names.



@EDIT 12-jun-2023:
The game renderer also has a check to see if you're able to "aim" at an entity.
It basically gets the pickRange we've modified, and if it's greater than 3.0, sets a boolean variable called to true:
SpoilerAbrir

Código: Selecionar tudo

double d = this.minecraft.gameMode.getPickRange();
double e = d;

if (this.minecraft.gameMode.hasFarPickRange()) {
    d = e = 6.0;
} else {
    if (e > 3.0) {
        bl = true;
    }
    d = e;
}
and later, if that variable is true, cancels out the hit -- if you're not in creative mode: (Creative has "hasFarPickRange()" set to true, bl gets set to false.)
SpoilerAbrir

Código: Selecionar tudo

if (bl && h > 9.0) {
    this.minecraft.hitResult = BlockHitResult.miss(vec34, Direction.getNearest(vec32.x, vec32.y, vec32.z), BlockPos.containing(vec34));
} else if (h < e || this.minecraft.hitResult == null) {
    this.minecraft.hitResult = entityHitResult;
}
So, to extend the attack reach in survival, the '3.0' constant needs to be modified:

Código: Selecionar tudo

@Mixin(GameRenderer.class)
public class GameRendererMixin {
    // mudar o range no GameRenderer para conseguir pôr a mira nos mobs:
    // if (e > 3.0)   --->   if (e > 6.0)
    @ModifyConstant(method="pick", constant = @Constant(doubleValue = 3.0))
    public double injected(double constant){
        return 6.0;
    }
}
Without doing this change, it'd only change the BLOCK REACH.
I've made this mistake because I tested the mod solely in creative mode.

DEMO:


This is only a "quick" and "simple" solution, "quicky and dirty", as some'd say.
By creating event callbacks and triggering them from the Mixin files it's possible to write a cleaner code.