Minecraft 1.18.2模组开发:如何获取LivingEntity实现效果叠加?
解决Minecraft模组中Meth食物效果放大器叠加问题
我正在制作名为meth的食物物品,希望玩家食用时每次都能叠加效果放大器(Amplifier)。最初写了isAlreadyHigh方法判断玩家是否已有该效果,存在就把放大器设为2而非默认0,但调用时不知道怎么传入LivingEntity参数,也不清楚如何获取玩家实例。之后尝试重写update方法实现叠加,但也没成功。
原始尝试代码
最初的MethFood类
package net.tyrique.banhammermod.item.custom; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.food.FoodProperties; import net.tyrique.banhammermod.effect.ModEffects; public class MethFood { public static final FoodProperties METH = (new FoodProperties.Builder()).alwaysEat().nutrition(0).saturationMod(0F).effect( () -> new MobEffectInstance(ModEffects.METH_EFFECT.get(), 1500, isAlreadyHigh(**WHAT DO I PUT HERE!?**)), 1.0F).fast().build(); private static int isAlreadyHigh(LivingEntity player) { int lvl = 0; if (player.hasEffect(ModEffects.METH_EFFECT.get())) { lvl = 2; } return lvl; } }
尝试重写update方法的片段
@Override public boolean update(MobEffectInstance p_19559_) { int newamp = p_19559_.getAmplifier() + 1; p_19559_ = new MobEffectInstance(p_19559_.getEffect(), p_19559_.getDuration(), newamp); return super.update(p_19559_); }
自定义ModMobEffectInstance类
public class ModMobEffectInstance extends MobEffectInstance { public ModMobEffectInstance(MobEffect effect, int duration, int amplifier) { super(effect, duration, amplifier); } @Override public boolean update(MobEffectInstance p_19559_) { int newamp = p_19559_.getAmplifier() + 1; p_19559_ = new ModMobEffectInstance(p_19559_.getEffect(), p_19559_.getDuration(), newamp); return super.update(p_19559_); } }
修改后的MethFood类
public class MethFood { public static final FoodProperties METH = (new FoodProperties.Builder()).alwaysEat().nutrition(-1).saturationMod(0F).effect( () -> new ModMobEffectInstance(ModEffects.METH_EFFECT.get(), 1500, 0), 1.0F).fast().build(); }
正确解决方案
问题根源
FoodProperties.Builder.effect()的Supplier是在食物属性初始化时执行,而非玩家食用阶段,此时没有玩家上下文,根本拿不到LivingEntity实例。- 重写
MobEffectInstance.update()的思路方向对,但实现错误——该方法不能直接替换传入的实例对象,修改引用不会影响原有的效果实例。
方案一:自定义食物类,在食用时处理叠加
直接创建自定义Item类,重写finishUsingItem方法,这里能直接拿到食用的玩家实例,灵活处理效果叠加:
package net.tyrique.banhammermod.item.custom; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.UseAnim; import net.minecraft.world.level.Level; import net.tyrique.banhammermod.effect.ModEffects; public class MethItem extends Item { public MethItem(Properties properties) { // 仅设置基础食物属性,效果在食用时手动添加 super(properties.alwaysEat().food(new FoodProperties.Builder().nutrition(0).saturationMod(0F).fast().build())); } @Override public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) { if (entity instanceof net.minecraft.world.entity.player.Player player) { int amplifier = 0; // 检查玩家已有效果,叠加放大器(这里改成+1实现递增,你之前写的设为2可以按需调整) if (player.hasEffect(ModEffects.METH_EFFECT.get())) { amplifier = player.getEffect(ModEffects.METH_EFFECT.get()).getAmplifier() + 1; } // 添加效果,时长可选择叠加或重置,这里保持1500 ticks player.addEffect(new MobEffectInstance(ModEffects.METH_EFFECT.get(), 1500, amplifier, false, true)); } // 调用父类方法处理物品消耗逻辑 return super.finishUsingItem(stack, level, entity); } @Override public UseAnim getUseAnimation(ItemStack stack) { return UseAnim.EAT; } }
然后在模组注册类中注册这个自定义物品:
// 示例注册代码,替换成你的模组注册逻辑 public static final RegistryObject<Item> METH = ITEMS.register("meth", () -> new MethItem(new Item.Properties().tab(ModCreativeModeTabs.BANHAMMER_TAB)));
方案二:重写效果类实现自动叠加
如果希望所有该效果的应用场景都自动叠加放大器,可以重写MobEffect的updateEffectInstance方法,让效果本身支持合并叠加:
package net.tyrique.banhammermod.effect; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.effect.MobEffectInstance; public class MethEffect extends MobEffect { public MethEffect() { super(MobEffectCategory.BENEFICIAL, 0xFF00FF); // 自定义效果颜色 } @Override public void applyEffectTick(LivingEntity entity, int amplifier) { // 这里写效果每tick的执行逻辑 super.applyEffectTick(entity, amplifier); } @Override public boolean isDurationEffectTick(int duration, int amplifier) { return true; // 根据需求调整是否每tick生效 } @Override public boolean updateEffectInstance(MobEffectInstance oldInstance, MobEffectInstance newInstance) { // 合并效果:保留最长时长,放大器叠加+1 int newAmplifier = oldInstance.getAmplifier() + 1; int newDuration = Math.max(oldInstance.getDuration(), newInstance.getDuration()); oldInstance.setDuration(newDuration); oldInstance.setAmplifier(newAmplifier); return true; // 返回true表示已合并,无需添加新实例 } }
这种方式下,食物只需要正常配置基础效果即可,不需要自定义Item类:
public static final FoodProperties METH_FOOD = new FoodProperties.Builder() .alwaysEat() .nutrition(0) .saturationMod(0F) .effect(() -> new MobEffectInstance(ModEffects.METH_EFFECT.get(), 1500, 0), 1.0F) .fast() .build();
内容的提问来源于stack exchange,提问作者TheRatKing
相关产品推荐
相关产品推荐

