diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperEffectsHandler.java b/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperEffectsHandler.java new file mode 100644 index 000000000..4b2d01ecb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperEffectsHandler.java @@ -0,0 +1,54 @@ +package com.simibubi.create.content.curiosities.tools; + +import java.util.Random; + +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +public class SandPaperEffectsHandler { + public static void onUseTick(LivingEntity entity, Random random) { + + spawnItemParticles(entity, random); + + if (shouldPlaySound(entity)) + entity.playSound(entity.getEatingSound(entity.getUseItem()), 0.9F + 0.2F * random.nextFloat(), random.nextFloat() * 0.2F + 0.9F); + } + + private static boolean shouldPlaySound(LivingEntity entity) { + // after 6 ticks play the sound every 7th + return (getTicksUsed(entity) - 6) % 7 == 0; + } + + private static int getTicksUsed(LivingEntity entity) { + int useDuration = entity.getUseItem() + .getUseDuration(); + return useDuration - entity.getUseItemRemainingTicks(); + } + + private static void spawnItemParticles(LivingEntity entity, Random random) { + ItemStack sanding = entity.getItemInHand(getNonInteractionHand(entity)); + + Vec3 vec3 = new Vec3(((double)random.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D); + vec3 = vec3.xRot(-entity.getXRot() * ((float)Math.PI / 180F)); + vec3 = vec3.yRot(-entity.getYRot() * ((float)Math.PI / 180F)); + double d0 = (double)(-random.nextFloat()) * 0.6D - 0.3D; + Vec3 vec31 = new Vec3(((double)random.nextFloat() - 0.5D) * 0.3D, d0, 0.6D); + vec31 = vec31.xRot(-entity.getXRot() * ((float)Math.PI / 180F)); + vec31 = vec31.yRot(-entity.getYRot() * ((float)Math.PI / 180F)); + vec31 = vec31.add(entity.getX(), entity.getEyeY(), entity.getZ()); + if (entity.level instanceof ServerLevel) //Forge: Fix MC-2518 spawnParticle is nooped on server, need to use server specific variant + ((ServerLevel)entity.level).sendParticles(new ItemParticleOption(ParticleTypes.ITEM, sanding), vec31.x, vec31.y, vec31.z, 1, vec3.x, vec3.y + 0.05D, vec3.z, 0.0D); + else + entity.level.addParticle(new ItemParticleOption(ParticleTypes.ITEM, sanding), vec31.x, vec31.y, vec31.z, vec3.x, vec3.y + 0.05D, vec3.z); + + } + + private static InteractionHand getNonInteractionHand(LivingEntity entity) { + return entity.getUsedItemHand() == InteractionHand.MAIN_HAND ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/mixin/SandPaperSoundMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/SandPaperSoundMixin.java new file mode 100644 index 000000000..0a9f63718 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/SandPaperSoundMixin.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.mixin; + +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.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.simibubi.create.content.curiosities.tools.SandPaperEffectsHandler; +import com.simibubi.create.content.curiosities.tools.SandPaperItem; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +@Mixin(LivingEntity.class) +public abstract class SandPaperSoundMixin extends Entity { + + @Shadow + public abstract ItemStack getUseItem(); + + private SandPaperSoundMixin(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + @Inject(method = "triggerItemUseEffects", cancellable = true, + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getUseAnimation()Lnet/minecraft/world/item/UseAnim;", ordinal = 0)) + private void onTriggerUseEffects(ItemStack pStack, int pCount, CallbackInfo ci) { + LivingEntity self = (LivingEntity) (Object) this; + + Item item = pStack.getItem(); + if (item instanceof SandPaperItem) { + SandPaperEffectsHandler.onUseTick(self, this.random); + ci.cancel(); + } + } + + // Trigger every tick for sandpaper, so that we have more fine grain control over the animation + @Inject(method = "shouldTriggerItemUseEffects", cancellable = true, at = @At("HEAD")) + private void alwaysTriggerUseEffects(CallbackInfoReturnable cir) { + ItemStack using = this.getUseItem(); + Item item = using.getItem(); + if (item instanceof SandPaperItem) { + cir.setReturnValue(true); + } + } +} diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json index 3d4eb4a19..d23a75275 100644 --- a/src/main/resources/create.mixins.json +++ b/src/main/resources/create.mixins.json @@ -5,7 +5,8 @@ "compatibilityLevel": "JAVA_16", "refmap": "create.refmap.json", "mixins": [ - "PlayerListMixin" + "PlayerListMixin", + "SandPaperSoundMixin" ], "client": [ "BreakProgressMixin",