diff --git a/common/src/main/java/org/orecruncher/dsurround/config/DimensionInfo.java b/common/src/main/java/org/orecruncher/dsurround/config/DimensionInfo.java index baa9d2f9..33d85bd9 100644 --- a/common/src/main/java/org/orecruncher/dsurround/config/DimensionInfo.java +++ b/common/src/main/java/org/orecruncher/dsurround/config/DimensionInfo.java @@ -19,6 +19,7 @@ public class DimensionInfo { protected int spaceHeight; protected boolean alwaysOutside = false; protected boolean playBiomeSounds = true; + protected boolean compassWobble = false; DimensionInfo() { this.name = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "no_dimension"); @@ -37,6 +38,8 @@ public DimensionInfo(final Level world) { // Force sea level based on known world types that give heartburn if (this.isFlatWorld) this.seaLevel = 0; + + this.compassWobble = !world.dimensionType().natural(); } public void update(DimensionConfigRule config) { @@ -49,6 +52,8 @@ public void update(DimensionConfigRule config) { v -> this.cloudHeight = v, () -> this.cloudHeight = this.skyHeight / 2); + config.compassWobble().ifPresent(v -> this.compassWobble = v); + this.spaceHeight = this.skyHeight + SPACE_HEIGHT_OFFSET; } } @@ -85,4 +90,8 @@ public boolean isFlatWorld() { return this.isFlatWorld; } + public boolean getCompassWobble() { + return this.compassWobble; + } + } diff --git a/common/src/main/java/org/orecruncher/dsurround/config/data/DimensionConfigRule.java b/common/src/main/java/org/orecruncher/dsurround/config/data/DimensionConfigRule.java index ff5284c6..b33bfa3c 100644 --- a/common/src/main/java/org/orecruncher/dsurround/config/data/DimensionConfigRule.java +++ b/common/src/main/java/org/orecruncher/dsurround/config/data/DimensionConfigRule.java @@ -12,7 +12,8 @@ public record DimensionConfigRule( Optional skyHeight, Optional cloudHeight, Optional alwaysOutside, - Optional playBiomeSounds) { + Optional playBiomeSounds, + Optional compassWobble) { public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance.group( ResourceLocation.CODEC.fieldOf("dimId").forGetter(DimensionConfigRule::dimensionId), @@ -20,7 +21,8 @@ public record DimensionConfigRule( Codec.INT.optionalFieldOf("skyHeight").forGetter(DimensionConfigRule::skyHeight), Codec.INT.optionalFieldOf("cloudHeight").forGetter(DimensionConfigRule::cloudHeight), Codec.BOOL.optionalFieldOf("alwaysOutside").forGetter(DimensionConfigRule::alwaysOutside), - Codec.BOOL.optionalFieldOf("playBiomeSounds").forGetter(DimensionConfigRule::playBiomeSounds)) + Codec.BOOL.optionalFieldOf("playBiomeSounds").forGetter(DimensionConfigRule::playBiomeSounds), + Codec.BOOL.optionalFieldOf("compassWobble").forGetter(DimensionConfigRule::compassWobble)) .apply(instance, DimensionConfigRule::new)); @Override @@ -32,6 +34,7 @@ public String toString() { this.cloudHeight.ifPresent(v -> builder.append(" cloudHeight: ").append(v)); this.alwaysOutside.ifPresent(v -> builder.append(" alwaysOutside: ").append(v)); this.playBiomeSounds.ifPresent(v -> builder.append(" playBiomeSounds: ").append(v)); + this.compassWobble.ifPresent(v -> builder.append(" compassWobble: ").append(v)); return builder.toString(); } diff --git a/common/src/main/java/org/orecruncher/dsurround/config/libraries/IDimensionInformation.java b/common/src/main/java/org/orecruncher/dsurround/config/libraries/IDimensionInformation.java index 97144953..389f1e8d 100644 --- a/common/src/main/java/org/orecruncher/dsurround/config/libraries/IDimensionInformation.java +++ b/common/src/main/java/org/orecruncher/dsurround/config/libraries/IDimensionInformation.java @@ -28,4 +28,9 @@ public interface IDimensionInformation { * The veritical Y level where clouds are expected to be */ int getCloudHeight(); + + /** + * Indicates whether the compass should "wobble" making the bearing unreadable + */ + boolean getCompassWobble(); } diff --git a/common/src/main/java/org/orecruncher/dsurround/config/libraries/impl/DimensionInformation.java b/common/src/main/java/org/orecruncher/dsurround/config/libraries/impl/DimensionInformation.java index 10b8b0ee..e89c0c4f 100644 --- a/common/src/main/java/org/orecruncher/dsurround/config/libraries/impl/DimensionInformation.java +++ b/common/src/main/java/org/orecruncher/dsurround/config/libraries/impl/DimensionInformation.java @@ -48,6 +48,10 @@ public int getCloudHeight() { return this.getInfo().getCloudHeight(); } + public boolean getCompassWobble() { + return this.getInfo().getCompassWobble(); + } + private DimensionInfo getInfo() { if (this.info == null) this.info = this.dimensionLibrary.getData(this.level()); diff --git a/common/src/main/java/org/orecruncher/dsurround/gui/overlay/CompassOverlay.java b/common/src/main/java/org/orecruncher/dsurround/gui/overlay/CompassOverlay.java index 29ed7556..c9a2f63b 100644 --- a/common/src/main/java/org/orecruncher/dsurround/gui/overlay/CompassOverlay.java +++ b/common/src/main/java/org/orecruncher/dsurround/gui/overlay/CompassOverlay.java @@ -11,8 +11,10 @@ import org.joml.Matrix4f; import org.orecruncher.dsurround.Constants; import org.orecruncher.dsurround.Configuration; +import org.orecruncher.dsurround.config.libraries.IDimensionInformation; import org.orecruncher.dsurround.config.libraries.ITagLibrary; import org.orecruncher.dsurround.lib.GameUtils; +import org.orecruncher.dsurround.lib.random.Randomizer; import org.orecruncher.dsurround.tags.ItemEffectTags; public class CompassOverlay extends AbstractOverlay { @@ -30,14 +32,19 @@ public class CompassOverlay extends AbstractOverlay { private static final ResourceLocation COMPASS_TEXTURE = ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "textures/compass.png"); private final ITagLibrary tagLibrary; + private final IDimensionInformation dimensionInformation; private final Configuration config; + private final CompassWobble wobbler; private boolean showCompass; + private boolean spinRandomly; private float scale; private float spriteOffset; - public CompassOverlay(Configuration config, ITagLibrary tagLibrary) { + public CompassOverlay(Configuration config, ITagLibrary tagLibrary, IDimensionInformation dimensionInformation) { this.tagLibrary = tagLibrary; + this.dimensionInformation = dimensionInformation; this.config = config; + this.wobbler = new CompassWobble(); this.showCompass = false; this.spriteOffset = this.config.compassAndClockOptions.compassStyle.getSpriteNumber(); this.scale = (float)this.config.compassAndClockOptions.scale; @@ -53,7 +60,20 @@ public void tick(Minecraft client) { var player = GameUtils.getPlayer().orElseThrow(); var mainHandItem = player.getMainHandItem(); var offHandItem = player.getOffhandItem(); - this.showCompass = this.doShowCompass(mainHandItem) || this.doShowCompass(offHandItem); + + var mainHandShow = this.doShowCompass(mainHandItem); + var offHandShow = this.doShowCompass(offHandItem); + this.showCompass = mainHandShow || offHandShow; + + if (mainHandShow) { + this.spinRandomly = this.doCompassSpin(mainHandItem); + } + + if (offHandShow && !this.spinRandomly) { + this.spinRandomly = this.doCompassSpin(offHandItem); + } + + this.wobbler.update(player.level().getGameTime()); } } @@ -61,6 +81,10 @@ private boolean doShowCompass(ItemStack stack) { return this.tagLibrary.is(ItemEffectTags.COMPASSES, stack); } + private boolean doCompassSpin(ItemStack stack) { + return this.dimensionInformation.getCompassWobble() && this.tagLibrary.is(ItemEffectTags.COMPASS_WOBBLE, stack); + } + @Override public void render(GuiGraphics context, float partialTick) { if (!this.showCompass) @@ -72,9 +96,16 @@ public void render(GuiGraphics context, float partialTick) { matrixStack.pushPose(); - final var player = GameUtils.getPlayer().orElseThrow(); + float rotation; - int direction = Mth.floor(((player.getViewYRot(partialTick) * TEXTURE_SIZE) / 360F) + 0.5D) & (TEXTURE_SIZE - 1); + if (this.spinRandomly) { + rotation = this.wobbler.getRandomlySpinningRotation(partialTick); + } else { + final var player = GameUtils.getPlayer().orElseThrow(); + rotation = player.getViewYRot(partialTick); + } + + int direction = Mth.floor(((rotation * TEXTURE_SIZE) / 360F) + 0.5D) & (TEXTURE_SIZE - 1); float x = (context.guiWidth() - BAND_WIDTH * this.scale) / 2F; float y = (context.guiHeight() - CROSSHAIR_OFFSET - BAND_HEIGHT * this.scale) / 2F; @@ -117,4 +148,56 @@ void drawTexturedQuad(PoseStack stack, ResourceLocation texture, float x1, float if (mesh != null) BufferUploader.drawWithShader(mesh); } + + /** + * Cloned from the Minecraft compass code + */ + static class CompassWobble { + private static int TICK_DELAY = 5; + private static float MAX_DELTA_TICK = 1F / 20F; + private float targetRotation; + private float lastRotation; + private float rotation; + private float rotationStep; + private long lastUpdateTick; + private int tickWait; + + public float getRandomlySpinningRotation(float partialTick) { + return Mth.lerp(partialTick, this.lastRotation, this.rotation) * 360F; + } + + public void update(long tickCount) { + if (this.lastUpdateTick != tickCount) { + this.updateRotation(tickCount); + } + } + + private void updateRotation(long tickCount) { + this.lastUpdateTick = tickCount; + this.lastRotation = this.rotation; + + if (this.rotation < this.targetRotation) { + this.rotation += this.rotationStep; + if (this.rotation > this.targetRotation) { + this.rotation = this.targetRotation; + } + } else if (this.rotation > this.targetRotation) { + this.rotation -= this.rotationStep; + if (this.rotation < this.targetRotation) { + this.rotation = this.targetRotation; + } + } + + // If we reached the target rotation, we need to set a new one + // and calculate the stepping to get there. + if (this.rotation == this.targetRotation) { + if (this.tickWait < 0 ) { + this.tickWait = Randomizer.current().nextInt(TICK_DELAY); + } else if (--this.tickWait == 0) { + this.targetRotation = Randomizer.current().nextFloat(); + this.rotationStep = MAX_DELTA_TICK; + } + } + } + } } diff --git a/common/src/main/java/org/orecruncher/dsurround/tags/ItemEffectTags.java b/common/src/main/java/org/orecruncher/dsurround/tags/ItemEffectTags.java index 6b0e6763..ccff63d3 100644 --- a/common/src/main/java/org/orecruncher/dsurround/tags/ItemEffectTags.java +++ b/common/src/main/java/org/orecruncher/dsurround/tags/ItemEffectTags.java @@ -22,6 +22,7 @@ public class ItemEffectTags { public static final TagKey SWORDS = of("swords"); public static final TagKey TOOLS = of("tools"); public static final TagKey COMPASSES = of("compasses"); + public static final TagKey COMPASS_WOBBLE = of("compass_wobble"); public static final TagKey CLOCKS = of("clocks"); private static TagKey of(String id) { diff --git a/common/src/main/resources/assets/dsurround/dsconfigs/tags/item/effects/compass_wobble.json b/common/src/main/resources/assets/dsurround/dsconfigs/tags/item/effects/compass_wobble.json new file mode 100644 index 00000000..4e104c81 --- /dev/null +++ b/common/src/main/resources/assets/dsurround/dsconfigs/tags/item/effects/compass_wobble.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:compass" + ] +} \ No newline at end of file