如何使用SpongePowered Mixins修改Minecraft Forge 1.18.2中LevelReader接口的isEmptyBlock方法?
如何使用SpongePowered Mixins修改Minecraft Forge 1.18.2中LevelReader接口的isEmptyBlock方法?
兄弟,你碰到的这个问题太常见了——LevelReader是个接口啊,它本身根本没有方法的具体实现,你直接Mixin接口的话,你的代码根本不会被执行,因为游戏运行时实际调用的是实现了这个接口的类的方法,比如Level或者ChunkLevel这些具体类。
给你两个靠谱的解决方案,你可以根据需求选:
方案一:Mixin接口的核心实现类(推荐)
最直接的方式就是找到LevelReader最常用的实现类,比如net.minecraft.world.level.Level——游戏里绝大多数场景下的LevelReader实例都是Level对象。你只需要把你的Mixin目标换成这个类,然后正常写注入逻辑就行。
修改后的代码示例:
package net.iateminecraft.jetpacksfix.mixin; import com.mojang.logging.LogUtils; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Level.class) public abstract class MixinLevelReader implements LevelReader { @Unique private static final Logger LOGGER = LogUtils.getLogger(); @Inject(method = "isEmptyBlock", at = @At("HEAD"), cancellable = true) private void modifyIsEmptyBlock(BlockPos pos, CallbackInfoReturnable<Boolean> cir) { // 这里写你的自定义逻辑,比如修改返回值 // 举个例子:让空气方块也不算空(只是示例,你改成自己的需求) boolean customResult = !((Level)(Object)this).getBlockState(pos).isAir(); cir.setReturnValue(customResult); LOGGER.info("修改了isEmptyBlock的返回值,位置{}:{}", pos, customResult); } }
要是之后发现某些场景用的是其他实现类(比如ChunkLevel),你再给那个类写个对应的Mixin就行,逻辑和上面基本一致。
方案二:用@Overwrite直接替换方法实现
如果你想完全接管这个方法的逻辑,可以用@Overwrite注解,但要注意:这种方式容易和其他修改同方法的mod冲突,所以谨慎使用。
示例代码:
package net.iateminecraft.jetpacksfix.mixin; import com.mojang.logging.LogUtils; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Overwrite; @Mixin(Level.class) public abstract class MixinLevelReader implements LevelReader { @Unique private static final Logger LOGGER = LogUtils.getLogger(); @Overwrite public boolean isEmptyBlock(BlockPos pos) { // 这里写你的完整自定义逻辑 // 要是需要调用原来的逻辑,得这么写(避免递归) boolean originalResult = ((Level)(Object)this).getBlockState(pos).isAir(); // 加自己的判断条件 boolean customResult = originalResult && pos.getY() > 64; LOGGER.info("原结果{},自定义结果{}", originalResult, customResult); return customResult; } }
最后再提醒一句:千万别直接Mixin接口,接口只是个规范,没有实际执行的代码,你的修改根本落不了地。一定要找具体的实现类来Mixin才行!
备注:内容来源于stack exchange,提问作者I Ate Minecraft




