Minecraft Fabric 1.21.1模组开发:如何阻止玩家实体播放指定声音(Vibral模组需求)
Minecraft Fabric 1.21.1模组开发:如何阻止玩家实体播放指定声音(Vibral模组需求)
嘿,我看了你这段Vibral模组的Mixin代码,问题主要出在对声音拦截的逻辑太“一刀切”,而且没有精准区分你要拦截的「环境音」和「主动工具音」场景。咱们一步步调整,让逻辑更精准,同时满足你的需求:
一、现有代码的核心问题
- PlayerEntityMixin里的
playSound注入太粗暴:直接在HEAD就cancel所有声音,会把玩家的所有声音(比如喝药水、穿盔甲的提示音)都拦截,这显然不是你要的效果 - 没有区分「穿盔甲」和「持工具」的不同拦截规则:目前只处理了游泳声音,还没覆盖走路、进食、工具使用等核心场景
- EntityMixin的代码冗余且不完整:玩家的游泳声音逻辑完全可以在PlayerEntityMixin里处理,没必要在EntityMixin里重复写,而且你贴的EntityMixin代码还截断了
二、修正后的完整代码
1. 优化后的PlayerEntityMixin
这个Mixin负责处理穿全套Vibral盔甲时的环境音拦截,以及持Vibral工具时的主动操作音拦截,逻辑更精准:
package net.zadezapper.vibral.mixin; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.sound.SoundEvent; import net.zadezapper.vibral.item.ModItems; import net.zadezapper.vibral.sound.ModSoundEvents; 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(PlayerEntity.class) public abstract class PlayerEntityMixin { // 直接获取当前玩家实例,无需多余强转 @Unique private final PlayerEntity self = (PlayerEntity) this; // ============================================== // 场景1:穿全套Vibral盔甲时,拦截环境类声音 // ============================================== // 拦截游泳/浮水声音 @Inject(at = @At("HEAD"), method = "getSwimSound", cancellable = true) public void interceptSwimSound(CallbackInfoReturnable<SoundEvent> cir) { if (isWearingFullVibralArmor(self)) { cir.setReturnValue(ModSoundEvents.SILENT); } } // 拦截走路/跑步声音 @Inject(at = @At("HEAD"), method = "getWalkSound", cancellable = true) public void interceptWalkSound(CallbackInfoReturnable<SoundEvent> cir) { if (isWearingFullVibralArmor(self)) { cir.setReturnValue(ModSoundEvents.SILENT); } } // 拦截进食/喝水声音 @Inject(at = @At("HEAD"), method = "getEatSound", cancellable = true) public void interceptEatSound(ItemStack stack, CallbackInfoReturnable<SoundEvent> cir) { if (isWearingFullVibralArmor(self)) { cir.setReturnValue(ModSoundEvents.SILENT); } } // 拦截望远镜使用声音 @Inject(at = @At("HEAD"), method = "getSpyglassSound", cancellable = true) public void interceptSpyglassSound(CallbackInfoReturnable<SoundEvent> cir) { if (isWearingFullVibralArmor(self)) { cir.setReturnValue(ModSoundEvents.SILENT); } } // ============================================== // 场景2:手持Vibral工具时,拦截主动操作音 // ============================================== // 拦截近战攻击声音 @Inject(at = @At("HEAD"), method = "getAttackSound", cancellable = true) public void interceptAttackSound(CallbackInfoReturnable<SoundEvent> cir) { if (isHoldingVibralTool(self)) { cir.setReturnValue(ModSoundEvents.SILENT); } } // 拦截挖掘方块的声音 @Inject(at = @At("HEAD"), method = "getDiggingSound", cancellable = true) public void interceptDiggingSound(CallbackInfoReturnable<SoundEvent> cir) { if (isHoldingVibralTool(self)) { cir.setReturnValue(ModSoundEvents.SILENT); } } // ============================================== // 工具方法:判断是否穿全套Vibral盔甲 // ============================================== @Unique private boolean isWearingFullVibralArmor(LivingEntity entity) { return entity.getEquippedStack(EquipmentSlot.HEAD).isOf(ModItems.VIBRAL_HELMET) && entity.getEquippedStack(EquipmentSlot.CHEST).isOf(ModItems.VIBRAL_CHESTPLATE) && entity.getEquippedStack(EquipmentSlot.LEGS).isOf(ModItems.VIBRAL_LEGGINGS) && entity.getEquippedStack(EquipmentSlot.FEET).isOf(ModItems.VIBRAL_BOOTS); } // ============================================== // 工具方法:判断是否手持Vibral工具 // ============================================== @Unique private boolean isHoldingVibralTool(LivingEntity entity) { ItemStack mainHand = entity.getEquippedStack(EquipmentSlot.MAINHAND); return mainHand.isOf(ModItems.VIBRAL_SWORD) || mainHand.isOf(ModItems.VIBRAL_PICKAXE) || mainHand.isOf(ModItems.VIBRAL_AXE) || mainHand.isOf(ModItems.VIBRAL_SHOVEL) || mainHand.isOf(ModItems.VIBRAL_HOE); } }
2. 简化后的EntityMixin(可选)
如果不需要给其他穿盔甲的生物加静音效果,这个Mixin可以直接删掉;如果需要保留,就用下面的简化版:
package net.zadezapper.vibral.mixin; import net.minecraft.entity.Entity; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.sound.SoundEvent; import net.zadezapper.vibral.item.ModItems; import net.zadezapper.vibral.sound.ModSoundEvents; 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(Entity.class) public abstract class EntityMixin { @Unique private final Entity self = (Entity) this; // 给穿全套Vibral盔甲的生物拦截游泳声音 @Inject(at = @At("HEAD"), method = "getSwimSound", cancellable = true) public void interceptEntitySwimSound(CallbackInfoReturnable<SoundEvent> cir) { if (self instanceof LivingEntity livingEntity) { boolean fullArmor = livingEntity.getEquippedStack(EquipmentSlot.HEAD).isOf(ModItems.VIBRAL_HELMET) && livingEntity.getEquippedStack(EquipmentSlot.CHEST).isOf(ModItems.VIBRAL_CHESTPLATE) && livingEntity.getEquippedStack(EquipmentSlot.LEGS).isOf(ModItems.VIBRAL_LEGGINGS) && livingEntity.getEquippedStack(EquipmentSlot.FEET).isOf(ModItems.VIBRAL_BOOTS); if (fullArmor) { cir.setReturnValue(ModSoundEvents.SILENT); } } } }
三、关键修改点解释
- 放弃一刀切拦截
playSound:转而拦截生成特定声音的方法(比如getWalkSound、getEatSound),这样只会拦截你需要的声音类型,不会影响其他正常游戏声音(比如玩家受伤、打开箱子的声音) - 分场景处理逻辑:明确区分「穿盔甲拦环境音」和「持工具拦操作音」的不同规则,每个规则对应单独的注入方法,逻辑更清晰
- 简化实例引用:直接用
(PlayerEntity) this获取当前玩家实例,不需要额外定义冗余的entity变量 - 抽离工具方法:把盔甲和工具判断抽成独立的工具方法,代码更整洁,后续扩展新的盔甲/工具也更方便
四、额外的补充说明
- 关于
ModSoundEvents.SILENT的定义:确保你定义的静音事件是一个无音频的空事件,在ModSoundEvents里注册:
public static final SoundEvent SILENT = SoundEvent.of(new Identifier("vibral", "silent"));
然后在assets/vibral/sounds.json里配置(不需要音频文件):
{ "silent": { "subtitle": "sound.vibral.silent", "sounds": [] } }
- 工具使用声音的额外处理:如果有些工具声音是由Item类触发的(比如斧头砍树的特殊声音),可以额外Mixin到
Item类的mineBlock方法,判断是否为Vibral工具后拦截声音 - Mixin优先级:除非需要和其他模组的Mixin竞争执行顺序,否则不需要设置
priority = 4096这种极端值,默认优先级就足够了
这样修改后,你的Vibral模组就能精准拦截指定的声音,同时不影响其他正常的游戏体验啦!




