From 99694c6ca2b8e957a073f50bcbbdf7edcd4e13da Mon Sep 17 00:00:00 2001 From: CampioneBase <1764544059@qq.com> Date: Sat, 20 Sep 2025 22:30:02 +0800 Subject: [PATCH] =?UTF-8?q?=E9=93=81=E5=82=80=E5=84=A1=E7=9A=84=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E7=94=9F=E9=94=88=EF=BC=8C=E5=8E=BB=E9=94=88=EF=BC=8C?= =?UTF-8?q?=E6=B6=82=E8=9C=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/adccadc/rust/manager/RustManager.java | 91 ++++++++++ .../com/adccadc/rust/manager/RustState.java | 9 + .../iromGolem/IronGolemEntityMixin.java | 169 ++++++++++++++++++ .../render/IronGolemEntityRendererMixin.java | 76 ++++++++ .../IronGolemEntityRenderStateMixin.java | 26 +++ .../rust/proxy/IronGolemEntityProxy.java | 15 ++ .../IronGolemEntityRenderStateProxy.java | 13 ++ src/main/resources/rust.mixins.json | 5 +- 8 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/adccadc/rust/manager/RustManager.java create mode 100644 src/main/java/com/adccadc/rust/manager/RustState.java create mode 100644 src/main/java/com/adccadc/rust/mixin/entity/iromGolem/IronGolemEntityMixin.java create mode 100644 src/main/java/com/adccadc/rust/mixin/render/IronGolemEntityRendererMixin.java create mode 100644 src/main/java/com/adccadc/rust/mixin/render/state/IronGolemEntityRenderStateMixin.java create mode 100644 src/main/java/com/adccadc/rust/proxy/IronGolemEntityProxy.java create mode 100644 src/main/java/com/adccadc/rust/proxy/IronGolemEntityRenderStateProxy.java diff --git a/src/main/java/com/adccadc/rust/manager/RustManager.java b/src/main/java/com/adccadc/rust/manager/RustManager.java new file mode 100644 index 0000000..c7c586f --- /dev/null +++ b/src/main/java/com/adccadc/rust/manager/RustManager.java @@ -0,0 +1,91 @@ +package com.adccadc.rust.manager; + +import com.adccadc.rust.Rust; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +/** + * 锈蚀管理器 + * @author CampioneBase + * @version 1.0 + */ +public class RustManager { + public static final String[] RUST_TEXT = {"", "斑驳的", "锈蚀的", "氧化的"}; + public static final String WAXED_TEXT = "涂蜡的"; + // 锈蚀状态 + private final RustState state = new RustState(); + // 锈蚀最大等级 + private final int maxLevel; + // 锈蚀物品类型 + private final ItemStack rust; + + /** + * @param rust 附着的锈蚀物品堆 + * @param max 锈蚀最大等级 + */ + public RustManager(ItemStack rust, int max){ + this.maxLevel = max; + this.rust = rust; + } + + public void setState(RustState state){ + this.state.level = state.level; + this.state.isWaxed = state.isWaxed; + } + + /** + * 尝试上锈 + * @return 是否成功上锈 + */ + public boolean tryRusted(){ + if (this.state.isWaxed) return false; + if (this.state.level >= maxLevel) return false; + this.state.level++; + return true; + } + + /** + * 尝试去锈 + * @return 去锈时的掉落物,null 表示失败 + */ + @Nullable + public ItemStack tryDerusted(){ + // 脱蜡 + if (this.state.isWaxed) { + this.state.isWaxed = false; + return ItemStack.EMPTY; + } + if (this.state.level <= 0) return null; + this.state.level--; + return rust.copy(); + } + + /** + * 上蜡 + * @return 是否成功上蜡 + */ + public boolean tryWaxed(){ + // 是否已经上蜡 + if (this.state.isWaxed) return false; + // 成功上蜡 + this.state.isWaxed = true; + return true; + } + + public RustState getState(){ + return state; + } + + public void setLevel(int level) { + this.state.level = level; + } + + public void setWaxed(boolean isWaxed){ + this.state.isWaxed = isWaxed; + } + + public String getName(){ + return (this.state.isWaxed ? WAXED_TEXT : "") + RUST_TEXT[this.state.level]; + } +} diff --git a/src/main/java/com/adccadc/rust/manager/RustState.java b/src/main/java/com/adccadc/rust/manager/RustState.java new file mode 100644 index 0000000..67a75ce --- /dev/null +++ b/src/main/java/com/adccadc/rust/manager/RustState.java @@ -0,0 +1,9 @@ +package com.adccadc.rust.manager; + +// 锈蚀状态 +public class RustState { + // 锈蚀等级 + public int level; + // 是否涂蜡 + public boolean isWaxed; +} diff --git a/src/main/java/com/adccadc/rust/mixin/entity/iromGolem/IronGolemEntityMixin.java b/src/main/java/com/adccadc/rust/mixin/entity/iromGolem/IronGolemEntityMixin.java new file mode 100644 index 0000000..b9356c6 --- /dev/null +++ b/src/main/java/com/adccadc/rust/mixin/entity/iromGolem/IronGolemEntityMixin.java @@ -0,0 +1,169 @@ +package com.adccadc.rust.mixin.entity.iromGolem; + +import com.adccadc.rust.Rust; +import com.adccadc.rust.item.Moditems; +import com.adccadc.rust.manager.RustManager; +import com.adccadc.rust.proxy.IronGolemEntityProxy; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.event.player.UseEntityCallback; +import net.minecraft.block.Blocks; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.passive.GolemEntity; +import net.minecraft.entity.passive.IronGolemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.*; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.registry.tag.ItemTags; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundEvents; +import net.minecraft.storage.ReadView; +import net.minecraft.storage.WriteView; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.world.World; +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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(IronGolemEntity.class) +public abstract class IronGolemEntityMixin extends GolemEntity implements IronGolemEntityProxy +{ + // 锈蚀控制器 + @Unique + public RustManager rust = new RustManager(new ItemStack(Moditems.IRON_RUST, 2), 3); + + public IronGolemEntityMixin(EntityType entityType, World world) { + super(entityType, world); + } + + @Unique + public IronGolemEntityProxy proxy(){ + return this; + } + + @Unique + public RustManager getRust(){ + return this.rust; + } + + @Inject(method = "writeCustomData", + /*at = @At(value = "INVOKE", + target = "Lnet/minecraft/iromGolem/mob/Angerable;writeAngerToData(Lnet/minecraft/world/World;Lnet/minecraft/storage/WriteView;)V", + shift = At.Shift.BEFORE + )*/ + at = @At("HEAD") + ) + private void writeCustomDataWithRust(WriteView view, CallbackInfo info){ + view.putInt("RustLevel", this.rust.getState().level); + view.putBoolean("IsWaxed", this.rust.getState().isWaxed); + } + + @Inject(method = "readCustomData", + /*at = @At(value = "INVOKE", + target = "Lnet/minecraft/iromGolem/mob/Angerable;readAngerFromData(Lnet/minecraft/world/World;Lnet/minecraft/storage/WriteView;)V", + shift = At.Shift.BEFORE + )*/ + at = @At("HEAD") + ) + private void readCustomDataWithRust(ReadView view, CallbackInfo info){ + this.rust.setLevel(view.getInt("RustLevel", 0)); + this.rust.setWaxed(view.getBoolean("IsWaxed", false)); + } + + @Inject( + method = "interactMob", + at = @At("HEAD"), + cancellable = true + ) + protected void interactMobWithRustActions(PlayerEntity player, Hand hand, CallbackInfoReturnable cir){ + ItemStack itemStack = player.getStackInHand(hand); + // 是否为水桶 + if (itemStack.isOf(Items.WATER_BUCKET)){ + // 处理物品 + if(!player.isCreative()){ + // 将水桶换成空桶 + ItemStack newItemStack = ItemUsage.exchangeStack(itemStack, player, Items.BUCKET.getDefaultStack()); + player.setStackInHand(hand, newItemStack); + } + // 尝试执行一次锈蚀 + if(!(this.rust.tryRusted())){ + // 生锈失败 + cir.setReturnValue(ActionResult.FAIL); + }else{ + cir.setReturnValue(ActionResult.SUCCESS); + } + // 物品是否含有斧头标签 + } else if (itemStack.isIn(ItemTags.AXES)){ + // 执行一次除锈 + ItemStack dropStack; + if (((dropStack = this.rust.tryDerusted()) == null)){ + // 除锈失败 + cir.setReturnValue(ActionResult.FAIL); + } else { + World world = this.getWorld(); + if (world instanceof ServerWorld serverWorld) { + // 生成掉落物 + ItemEntity drop = this.dropStack(serverWorld, dropStack, 1.5F); + // 播放音效 + this.playSound(SoundEvents.ITEM_AXE_WAX_OFF, 1.0F, 1.0F); + // 播放粒子 + serverWorld.spawnParticles( + ParticleTypes.WAX_OFF, + this.getX(), + this.getY() + 1.0F, + this.getZ(), + 35, + 0.4F, + 0.8F, + 0.4F, + 0.1F + ); + // 处理物品 + itemStack.damage(1, player); + cir.setReturnValue(ActionResult.SUCCESS); + } + } + // 物品是否为蜜脾 + } else if (itemStack.isOf(Items.HONEYCOMB) && itemStack.getCount() >= 2) { + // 尝试上蜡 + if (!this.rust.tryWaxed()){ + // 上蜡失败 + cir.setReturnValue(ActionResult.FAIL); + } else { + World world = this.getWorld(); + if(world instanceof ServerWorld serverWorld){ + // 播放音效 + this.playSound(SoundEvents.ITEM_HONEYCOMB_WAX_ON, 1.0F, 1.0F); + // 播放粒子 + serverWorld.spawnParticles( + ParticleTypes.WAX_ON, + this.getX(), + this.getY() + 1.0F, + this.getZ(), + 35, + 0.4F, + 0.8F, + 0.4F, + 0.1F + ); + // 处理物品 + itemStack.decrementUnlessCreative(2, player); + cir.setReturnValue(ActionResult.SUCCESS); + } + } + } + } + + @Override + // 在名称前添加锈蚀状态 + protected Text getDefaultName(){ + return Text.of(this.rust.getName() + this.getType().getName().getString()); + } +} diff --git a/src/main/java/com/adccadc/rust/mixin/render/IronGolemEntityRendererMixin.java b/src/main/java/com/adccadc/rust/mixin/render/IronGolemEntityRendererMixin.java new file mode 100644 index 0000000..6221bff --- /dev/null +++ b/src/main/java/com/adccadc/rust/mixin/render/IronGolemEntityRendererMixin.java @@ -0,0 +1,76 @@ +package com.adccadc.rust.mixin.render; + +import com.adccadc.rust.manager.RustState; +import com.adccadc.rust.proxy.IronGolemEntityProxy; +import com.adccadc.rust.proxy.IronGolemEntityRenderStateProxy; +import com.google.common.collect.ImmutableMap; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.render.entity.EntityRendererFactory; +import net.minecraft.client.render.entity.IronGolemEntityRenderer; +import net.minecraft.client.render.entity.MobEntityRenderer; +import net.minecraft.client.render.entity.model.IronGolemEntityModel; +import net.minecraft.client.render.entity.state.IronGolemEntityRenderState; +import net.minecraft.entity.passive.IronGolemEntity; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Environment(EnvType.CLIENT) +@Mixin(IronGolemEntityRenderer.class) +public abstract class IronGolemEntityRendererMixin extends MobEntityRenderer { + private static final ImmutableMap TEXTURES; + private static final ImmutableMap WAXED_TEXTURES; + + public IronGolemEntityRendererMixin(EntityRendererFactory.Context context, IronGolemEntityModel entityModel, float f) { + super(context, entityModel, f); + } + + @Inject( + method = "getTexture", + at = @At("HEAD"), + cancellable = true + ) + public void getTextureWithRust(IronGolemEntityRenderState state, CallbackInfoReturnable cir){ + IronGolemEntityRenderStateProxy stateProxy = ((IronGolemEntityRenderStateProxy) state); + RustState rustState = stateProxy.getRustState(); + int level = Math.max(0, Math.min(3, rustState.level)); + if(rustState.isWaxed) + cir.setReturnValue(WAXED_TEXTURES.get(level)); + else + cir.setReturnValue(TEXTURES.get(level)); + } + + @Inject( + method = "updateRenderState", + at = @At("TAIL") + ) + public void updateRenderStateWithRust( + IronGolemEntity entity, + IronGolemEntityRenderState state, + float f, + CallbackInfo ci + ){ + IronGolemEntityRenderStateProxy stateProxy = ((IronGolemEntityRenderStateProxy) state); + IronGolemEntityProxy entityProxy = ((IronGolemEntityProxy) entity); + stateProxy.setRustState(entityProxy.getRust().getState()); + } + + static { + TEXTURES = ImmutableMap.of( + 0, Identifier.ofVanilla("textures/entity/iron_golem/iron_golem.png"), + 1, Identifier.of("rust", "textures/entity/exposed_iron_golem.png"), + 2, Identifier.of("rust", "textures/entity/weathered_iron_golem.png"), + 3, Identifier.of("rust", "textures/entity/oxidized_iron_golem.png") + ); + WAXED_TEXTURES = ImmutableMap.of( + 0, Identifier.of("rust", "textures/entity/waxed_iron_golem.png"), + 1, Identifier.of("rust", "textures/entity/waxed_exposed_iron_golem.png"), + 2, Identifier.of("rust", "textures/entity/waxed_weathered_iron_golem.png"), + 3, Identifier.of("rust", "textures/entity/waxed_oxidized_iron_golem.png") + ); + } +} diff --git a/src/main/java/com/adccadc/rust/mixin/render/state/IronGolemEntityRenderStateMixin.java b/src/main/java/com/adccadc/rust/mixin/render/state/IronGolemEntityRenderStateMixin.java new file mode 100644 index 0000000..2386d12 --- /dev/null +++ b/src/main/java/com/adccadc/rust/mixin/render/state/IronGolemEntityRenderStateMixin.java @@ -0,0 +1,26 @@ +package com.adccadc.rust.mixin.render.state; + +import com.adccadc.rust.manager.RustState; +import com.adccadc.rust.proxy.IronGolemEntityRenderStateProxy; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.render.entity.state.IronGolemEntityRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Environment(EnvType.CLIENT) +@Mixin(IronGolemEntityRenderState.class) +public class IronGolemEntityRenderStateMixin implements IronGolemEntityRenderStateProxy { + @Unique + public RustState rustState; + + @Override + public void setRustState(RustState state) { + this.rustState = state; + } + + @Override + public RustState getRustState() { + return rustState; + } +} diff --git a/src/main/java/com/adccadc/rust/proxy/IronGolemEntityProxy.java b/src/main/java/com/adccadc/rust/proxy/IronGolemEntityProxy.java new file mode 100644 index 0000000..83e8ab0 --- /dev/null +++ b/src/main/java/com/adccadc/rust/proxy/IronGolemEntityProxy.java @@ -0,0 +1,15 @@ +package com.adccadc.rust.proxy; + +import com.adccadc.rust.manager.RustManager; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +@Environment(EnvType.CLIENT) +public interface IronGolemEntityProxy { + + default IronGolemEntityProxy proxy(){ + return this; + } + + RustManager getRust(); +} diff --git a/src/main/java/com/adccadc/rust/proxy/IronGolemEntityRenderStateProxy.java b/src/main/java/com/adccadc/rust/proxy/IronGolemEntityRenderStateProxy.java new file mode 100644 index 0000000..c7da3ad --- /dev/null +++ b/src/main/java/com/adccadc/rust/proxy/IronGolemEntityRenderStateProxy.java @@ -0,0 +1,13 @@ +package com.adccadc.rust.proxy; + +import com.adccadc.rust.manager.RustState; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +@Environment(EnvType.CLIENT) +public interface IronGolemEntityRenderStateProxy { + + void setRustState(RustState state); + + RustState getRustState(); +} diff --git a/src/main/resources/rust.mixins.json b/src/main/resources/rust.mixins.json index 9461fcf..a198c9d 100644 --- a/src/main/resources/rust.mixins.json +++ b/src/main/resources/rust.mixins.json @@ -4,9 +4,12 @@ "compatibilityLevel": "JAVA_21", "mixins": [ "BlocksMixin", + "CauldronBehaviorMixin", "ExampleMixin", "OxidizableMixin", - "CauldronBehaviorMixin" + "entity.iromGolem.IronGolemEntityMixin", + "render.IronGolemEntityRendererMixin", + "render.state.IronGolemEntityRenderStateMixin" ], "injectors": { "defaultRequire": 1