From c2269dc07d0c3ae89b1c1d678183847613249398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ampflower=20=F0=9F=8C=BA?= Date: Fri, 14 Mar 2025 01:07:46 -0700 Subject: [PATCH] fix: Pride Totem trampling over vanilla Fixes #65 Fixes #68 --- .../client/ClientPlayNetworkHandlerMixin.java | 57 ++++++------------ .../joy/data/JoyItemTagProvider.java | 4 ++ .../joy/item/ParticleEmittingItem.java | 23 ++++++++ .../pridecraft/joy/misc/ParticleEmitter.java | 11 ++++ .../joy/mixin/LivingEntityMixin.java | 59 ++++++++----------- .../gay/pridecraft/joy/registry/JoyItems.java | 3 +- .../gay/pridecraft/joy/tags/JoyItemTags.java | 3 +- 7 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 xplat/src/main/java/gay/pridecraft/joy/item/ParticleEmittingItem.java create mode 100644 xplat/src/main/java/gay/pridecraft/joy/misc/ParticleEmitter.java diff --git a/xplat/src/client/java/gay/pridecraft/joy/mixin/client/ClientPlayNetworkHandlerMixin.java b/xplat/src/client/java/gay/pridecraft/joy/mixin/client/ClientPlayNetworkHandlerMixin.java index e8ad753..af5d98d 100644 --- a/xplat/src/client/java/gay/pridecraft/joy/mixin/client/ClientPlayNetworkHandlerMixin.java +++ b/xplat/src/client/java/gay/pridecraft/joy/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -2,71 +2,48 @@ package gay.pridecraft.joy.mixin.client; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import gay.pridecraft.joy.registry.JoyItems; -import gay.pridecraft.joy.registry.JoyParticles; -import net.minecraft.client.MinecraftClient; +import gay.pridecraft.joy.misc.ParticleEmitter; +import gay.pridecraft.joy.tags.JoyItemTags; import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; -import net.minecraft.sound.SoundEvents; +import net.minecraft.particle.ParticleEffect; import net.minecraft.util.Hand; -import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; 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.ModifyArg; @Mixin(ClientPlayNetworkHandler.class) public abstract class ClientPlayNetworkHandlerMixin { - @Shadow - public abstract ClientWorld getWorld(); @WrapOperation(method = "getActiveTotemOfUndying", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isOf(Lnet/minecraft/item/Item;)Z")) private static boolean modifyTotemOfUndyingAnimation(ItemStack instance, Item item, Operation original) { - return instance.isOf(JoyItems.TOTEM_OF_PRIDE) || original.call(instance, item); + return instance.isIn(JoyItemTags.TOTEM_OF_UNDYING) || original.call(instance, item); } - @Inject(at = @At("HEAD"), method = "onEntityStatus") - private void onCustomEntityStatus(EntityStatusS2CPacket packet, CallbackInfo ci) { - if (this.getWorld() == null || packet.getStatus() != 36) { - return; + @ModifyArg(method = "onEntityStatus", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/particle/ParticleManager;addEmitter(Lnet/minecraft/entity/Entity;Lnet/minecraft/particle/ParticleEffect;I)V")) + private ParticleEffect changeTotemParticle(Entity entity, ParticleEffect original, int maxAge) { + if (entity instanceof LivingEntity living && + getActiveTotemOfUndying(living).getItem() instanceof ParticleEmitter emitter) { + return emitter.joy$getEffect(); } - - final var client = MinecraftClient.getInstance(); - - //noinspection ResultOfMethodCallIgnored - unnecessary - client.submit(() -> { - final World world = this.getWorld(); - final Entity entity = packet.getEntity(world); - if (entity == null) { - return; - } - - client.particleManager.addEmitter(entity, JoyParticles.TOTEM_OF_PRIDE_PARTICLE, 30); - - world.playSound(entity.getX(), entity.getY(), entity.getZ(), SoundEvents.ITEM_TOTEM_USE, entity.getSoundCategory(), 1.f, 1.f, false); - - if (entity == client.player) { - client.gameRenderer.showFloatingItem(modifyTotem(client.player)); - } - }); + return original; } @Unique - private static ItemStack modifyTotem(PlayerEntity player) { + private static ItemStack getActiveTotemOfUndying(LivingEntity player) { for (Hand hand : Hand.values()) { ItemStack itemStack = player.getStackInHand(hand); - if (itemStack.isOf(JoyItems.TOTEM_OF_PRIDE)) { + if (itemStack.isIn(JoyItemTags.TOTEM_OF_UNDYING)) { return itemStack; } } - return null; + return ItemStack.EMPTY; } } diff --git a/xplat/src/datagen/java/gay/pridecraft/joy/data/JoyItemTagProvider.java b/xplat/src/datagen/java/gay/pridecraft/joy/data/JoyItemTagProvider.java index 07f1428..55bda8a 100644 --- a/xplat/src/datagen/java/gay/pridecraft/joy/data/JoyItemTagProvider.java +++ b/xplat/src/datagen/java/gay/pridecraft/joy/data/JoyItemTagProvider.java @@ -27,5 +27,9 @@ public class JoyItemTagProvider extends FabricTagProvider.ItemTagProvider { getOrCreateTagBuilder(JoyItemTags.GLIDERS).addTag( JoyItemTags.ELYTRA ); + getOrCreateTagBuilder(JoyItemTags.TOTEM_OF_UNDYING).add( + Items.TOTEM_OF_UNDYING, + JoyItems.TOTEM_OF_PRIDE + ); } } diff --git a/xplat/src/main/java/gay/pridecraft/joy/item/ParticleEmittingItem.java b/xplat/src/main/java/gay/pridecraft/joy/item/ParticleEmittingItem.java new file mode 100644 index 0000000..d969181 --- /dev/null +++ b/xplat/src/main/java/gay/pridecraft/joy/item/ParticleEmittingItem.java @@ -0,0 +1,23 @@ +package gay.pridecraft.joy.item; + +import gay.pridecraft.joy.misc.ParticleEmitter; +import net.minecraft.item.Item; +import net.minecraft.particle.ParticleEffect; + +/** + * @author Ampflower + * @since 1.0.0 + **/ +public class ParticleEmittingItem extends Item implements ParticleEmitter { + private final ParticleEffect effect; + + public ParticleEmittingItem(final Settings settings, final ParticleEffect effect) { + super(settings); + this.effect = effect; + } + + @Override + public ParticleEffect joy$getEffect() { + return effect; + } +} diff --git a/xplat/src/main/java/gay/pridecraft/joy/misc/ParticleEmitter.java b/xplat/src/main/java/gay/pridecraft/joy/misc/ParticleEmitter.java new file mode 100644 index 0000000..d2255e3 --- /dev/null +++ b/xplat/src/main/java/gay/pridecraft/joy/misc/ParticleEmitter.java @@ -0,0 +1,11 @@ +package gay.pridecraft.joy.misc; + +import net.minecraft.particle.ParticleEffect; + +/** + * @author Ampflower + * @since 1.0.0 + **/ +public interface ParticleEmitter { + ParticleEffect joy$getEffect(); +} diff --git a/xplat/src/main/java/gay/pridecraft/joy/mixin/LivingEntityMixin.java b/xplat/src/main/java/gay/pridecraft/joy/mixin/LivingEntityMixin.java index d44c516..6a26bd0 100644 --- a/xplat/src/main/java/gay/pridecraft/joy/mixin/LivingEntityMixin.java +++ b/xplat/src/main/java/gay/pridecraft/joy/mixin/LivingEntityMixin.java @@ -1,56 +1,43 @@ package gay.pridecraft.joy.mixin; -import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import gay.pridecraft.joy.registry.JoyItems; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import gay.pridecraft.joy.tags.JoyItemTags; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.Hand; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; @Mixin(LivingEntity.class) public abstract class LivingEntityMixin extends Entity { - @Shadow public abstract ItemStack getStackInHand(Hand hand); - - @Shadow public abstract void setHealth(float health); - - @Shadow public abstract boolean clearStatusEffects(); - - @Shadow public abstract boolean addStatusEffect(StatusEffectInstance effect); public LivingEntityMixin(EntityType type, World world) { super(type, world); } - @WrapMethod(method = "tryUseTotem") - public boolean useCustomTotem(DamageSource source, Operation original) { - LivingEntityMixin entity = this; + @WrapOperation(method = "tryUseTotem", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;isOf(Lnet/minecraft/item/Item;)Z")) + private boolean onCheckTotem(ItemStack self, Item other, Operation operation) { + if (self.isIn(JoyItemTags.TOTEM_OF_UNDYING)) { + return true; + } + return operation.call(self, other); + } - ItemStack offhandStack = entity.getStackInHand(Hand.OFF_HAND); - ItemStack mainHandStack = entity.getStackInHand(Hand.MAIN_HAND); - - if (!offhandStack.isOf(JoyItems.TOTEM_OF_PRIDE) && !mainHandStack.isOf(JoyItems.TOTEM_OF_PRIDE)) return original.call(source); - - if (offhandStack.isOf(JoyItems.TOTEM_OF_PRIDE)) offhandStack.decrement(1); - else if (mainHandStack.isOf(JoyItems.TOTEM_OF_PRIDE)) mainHandStack.decrement(1); - - - this.setHealth(1.0F); - this.clearStatusEffects(); - - this.addStatusEffect(new StatusEffectInstance(StatusEffects.REGENERATION, 45 * 20, 1)); - this.addStatusEffect(new StatusEffectInstance(StatusEffects.FIRE_RESISTANCE, 40 * 20, 0)); - this.addStatusEffect(new StatusEffectInstance(StatusEffects.ABSORPTION, 5 * 20, 1)); - - this.getWorld().sendEntityStatus(entity, (byte) 36); - - return true; + @ModifyArg(method = "tryUseTotem", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/stat/StatType;getOrCreateStat(Ljava/lang/Object;)Lnet/minecraft/stat/Stat;")) + private Object modifyStatArgument(Object original, @Local ItemStack real) { + if (real != null && !real.isEmpty()) { + return real.getItem(); + } + return original; } } diff --git a/xplat/src/main/java/gay/pridecraft/joy/registry/JoyItems.java b/xplat/src/main/java/gay/pridecraft/joy/registry/JoyItems.java index e877a6a..9373d4e 100644 --- a/xplat/src/main/java/gay/pridecraft/joy/registry/JoyItems.java +++ b/xplat/src/main/java/gay/pridecraft/joy/registry/JoyItems.java @@ -4,6 +4,7 @@ package gay.pridecraft.joy.registry; import gay.pridecraft.joy.JoyUtil; import gay.pridecraft.joy.Pivot; import gay.pridecraft.joy.item.CustomElytraItem; +import gay.pridecraft.joy.item.ParticleEmittingItem; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.BundleContentsComponent; import net.minecraft.item.BrushItem; @@ -24,7 +25,7 @@ public final class JoyItems { public static final Item TOTEM_OF_PRIDE = registerItem( "totem_of_pride", - new Item(new Item.Settings().maxCount(1)) + new ParticleEmittingItem(new Item.Settings().maxCount(1), JoyParticles.TOTEM_OF_PRIDE_PARTICLE) ); public static final Item PRIDE_BRUSH = registerItem( diff --git a/xplat/src/main/java/gay/pridecraft/joy/tags/JoyItemTags.java b/xplat/src/main/java/gay/pridecraft/joy/tags/JoyItemTags.java index 9ab0b4b..86d6b5f 100644 --- a/xplat/src/main/java/gay/pridecraft/joy/tags/JoyItemTags.java +++ b/xplat/src/main/java/gay/pridecraft/joy/tags/JoyItemTags.java @@ -13,7 +13,8 @@ import net.minecraft.util.Identifier; public final class JoyItemTags { public static final TagKey GLIDERS = common("gliders"), - ELYTRA = common("elytra"); + ELYTRA = common("elytra"), + TOTEM_OF_UNDYING = common("totem_of_undying"); private static TagKey joy(String name) { return TagKey.of(RegistryKeys.ITEM, JoyUtil.id(name));