package net.minecraft.client.renderer.item.properties.numeric; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder.Instance; import javax.annotation.Nullable; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.GlobalPos; import net.minecraft.core.component.DataComponents; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.LodestoneTracker; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class CompassAngleState extends NeedleDirectionHelper { public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec( p_377373_ -> p_377373_.group( Codec.BOOL.optionalFieldOf("wobble", true).forGetter(NeedleDirectionHelper::wobble), CompassAngleState.CompassTarget.CODEC.fieldOf("target").forGetter(CompassAngleState::target) ) .apply(p_377373_, CompassAngleState::new) ); private final NeedleDirectionHelper.Wobbler wobbler; private final NeedleDirectionHelper.Wobbler noTargetWobbler; private final CompassAngleState.CompassTarget compassTarget; private final RandomSource random = RandomSource.create(); public CompassAngleState(boolean p_375464_, CompassAngleState.CompassTarget p_375747_) { super(p_375464_); this.wobbler = this.newWobbler(0.8F); this.noTargetWobbler = this.newWobbler(0.8F); this.compassTarget = p_375747_; } @Override protected float calculate(ItemStack p_376712_, ClientLevel p_377258_, int p_377034_, Entity p_378312_) { GlobalPos globalpos = this.compassTarget.get(p_377258_, p_376712_, p_378312_); long i = p_377258_.getGameTime(); return !isValidCompassTargetPos(p_378312_, globalpos) ? this.getRandomlySpinningRotation(p_377034_, i) : this.getRotationTowardsCompassTarget(p_378312_, i, globalpos.pos()); } private float getRandomlySpinningRotation(int p_375455_, long p_378047_) { if (this.noTargetWobbler.shouldUpdate(p_378047_)) { this.noTargetWobbler.update(p_378047_, this.random.nextFloat()); } float f = this.noTargetWobbler.rotation() + hash(p_375455_) / 2.1474836E9F; return Mth.positiveModulo(f, 1.0F); } private float getRotationTowardsCompassTarget(Entity p_375736_, long p_375437_, BlockPos p_376106_) { float f = (float)getAngleFromEntityToPos(p_375736_, p_376106_); float f1 = getWrappedVisualRotationY(p_375736_); float f2; if (p_375736_ instanceof Player player && player.isLocalPlayer() && player.level().tickRateManager().runsNormally()) { if (this.wobbler.shouldUpdate(p_375437_)) { this.wobbler.update(p_375437_, 0.5F - (f1 - 0.25F)); } f2 = f + this.wobbler.rotation(); } else { f2 = 0.5F - (f1 - 0.25F - f); } return Mth.positiveModulo(f2, 1.0F); } private static boolean isValidCompassTargetPos(Entity p_378772_, @Nullable GlobalPos p_376149_) { return p_376149_ != null && p_376149_.dimension() == p_378772_.level().dimension() && !(p_376149_.pos().distToCenterSqr(p_378772_.position()) < 1.0E-5F); } private static double getAngleFromEntityToPos(Entity p_378685_, BlockPos p_375957_) { Vec3 vec3 = Vec3.atCenterOf(p_375957_); return Math.atan2(vec3.z() - p_378685_.getZ(), vec3.x() - p_378685_.getX()) / (float) (Math.PI * 2); } private static float getWrappedVisualRotationY(Entity p_376616_) { return Mth.positiveModulo(p_376616_.getVisualRotationYInDegrees() / 360.0F, 1.0F); } private static int hash(int p_376466_) { return p_376466_ * 1327217883; } protected CompassAngleState.CompassTarget target() { return this.compassTarget; } @OnlyIn(Dist.CLIENT) public static enum CompassTarget implements StringRepresentable { NONE("none") { @Nullable @Override public GlobalPos get(ClientLevel p_375914_, ItemStack p_376028_, Entity p_377752_) { return null; } }, LODESTONE("lodestone") { @Nullable @Override public GlobalPos get(ClientLevel p_376563_, ItemStack p_377548_, Entity p_378126_) { LodestoneTracker lodestonetracker = p_377548_.get(DataComponents.LODESTONE_TRACKER); return lodestonetracker != null ? lodestonetracker.target().orElse(null) : null; } }, SPAWN("spawn") { @Override public GlobalPos get(ClientLevel p_378146_, ItemStack p_377238_, Entity p_377273_) { return GlobalPos.of(p_378146_.dimension(), p_378146_.getSharedSpawnPos()); } }, RECOVERY("recovery") { @Nullable @Override public GlobalPos get(ClientLevel p_375618_, ItemStack p_378046_, Entity p_376523_) { return p_376523_ instanceof Player player ? player.getLastDeathLocation().orElse(null) : null; } }; public static final Codec CODEC = StringRepresentable.fromEnum(CompassAngleState.CompassTarget::values); private final String name; CompassTarget(final String p_376851_) { this.name = p_376851_; } @Override public String getSerializedName() { return this.name; } @Nullable abstract GlobalPos get(ClientLevel p_375459_, ItemStack p_375402_, Entity p_376061_); } }