diff --git a/common/src/main/java/xaeroplus/feature/render/WaypointBeaconRenderer.java b/common/src/main/java/xaeroplus/feature/render/WaypointBeaconRenderer.java new file mode 100644 index 00000000..0d4b225e --- /dev/null +++ b/common/src/main/java/xaeroplus/feature/render/WaypointBeaconRenderer.java @@ -0,0 +1,114 @@ +package xaeroplus.feature.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BeaconRenderer; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import xaero.common.HudMod; +import xaero.common.minimap.waypoints.Waypoint; +import xaero.common.minimap.waypoints.WaypointVisibilityType; +import xaero.common.settings.ModSettings; +import xaero.hud.minimap.BuiltInHudModules; +import xaero.hud.minimap.module.MinimapSession; +import xaeroplus.settings.Settings; + +import java.util.ArrayList; +import java.util.List; + +import static net.minecraft.client.renderer.blockentity.BeaconRenderer.BEAM_LOCATION; + +public class WaypointBeaconRenderer { + public static final WaypointBeaconRenderer INSTANCE = new WaypointBeaconRenderer(); + private final List waypointList = new ArrayList<>(); + private long lastWaypointRenderListUpdate = -1L; + + public void updateWaypointRenderList(final MinimapSession session, final ModSettings settings) { + waypointList.clear(); + session.getWaypointSession().getCollector().collect(waypointList); + waypointList.removeIf(w -> { + if (w.isDisabled() + || w.getVisibility() == WaypointVisibilityType.WORLD_MAP_LOCAL + || w.getVisibility() == WaypointVisibilityType.WORLD_MAP_GLOBAL) { + return true; + } + return !settings.getDeathpoints() && w.getPurpose().isDeath(); + }); + waypointList.sort(Waypoint::compareTo); + } + + public void renderWaypointBeacons(float tickDelta, PoseStack matrixStack) { + var session = BuiltInHudModules.MINIMAP.getCurrentSession(); + if (session == null) return; + var settings = HudMod.INSTANCE.getSettings(); + if (settings == null) return; + if (!settings.getShowIngameWaypoints()) return; + var currentWorld = session.getWorldManager().getCurrentWorld(); + if (currentWorld == null) return; + if (System.currentTimeMillis() - lastWaypointRenderListUpdate > 50L) { + updateWaypointRenderList(session, settings); + lastWaypointRenderListUpdate = System.currentTimeMillis(); + } + var dimDiv = session.getDimensionHelper().getDimensionDivision(currentWorld); + var mc = Minecraft.getInstance(); + if (mc.level == null || mc.cameraEntity == null) return; + var cameraPos = mc.cameraEntity.position(); + double distanceScale = settings.dimensionScaledMaxWaypointDistance ? mc.level.dimensionType().coordinateScale() : 1.0; + double waypointsDistance = settings.getMaxWaypointsDistance(); + double waypointsDistanceMin = settings.waypointsDistanceMin; + for (int i = 0; i < waypointList.size(); i++) { + final var w = waypointList.get(i); + double offX = (double)w.getX(dimDiv) - cameraPos.x + 0.5; + double offZ = (double)w.getZ(dimDiv) - cameraPos.z + 0.5; + double unscaledDistance2D = Math.sqrt(offX * offX + offZ * offZ); + double distance2D = unscaledDistance2D * distanceScale; + var shouldRender = w.isDestination() + || (w.getPurpose().isDeath() + || w.isGlobal() + || w.isTemporary() && settings.temporaryWaypointsGlobal + || waypointsDistance == 0.0 + || !(distance2D > waypointsDistance) + ) && (waypointsDistanceMin == 0.0 || !(unscaledDistance2D < waypointsDistanceMin));; + if (shouldRender) + renderWaypointBeacon(w, dimDiv, tickDelta, matrixStack); + } + } + + public void renderWaypointBeacon(final Waypoint waypoint, final double dimDiv, float tickDelta, PoseStack matrixStack) { + final Minecraft mc = Minecraft.getInstance(); + if (mc.level == null || mc.cameraEntity == null) return; + final Vec3 playerVec = mc.cameraEntity.position(); + Vec3 waypointVec = new Vec3(waypoint.getX(dimDiv), playerVec.y, waypoint.getZ(dimDiv)); + final double xzDistance = playerVec.distanceTo(waypointVec); + if (xzDistance < Settings.REGISTRY.waypointBeaconDistanceMin.getAsInt()) return; + final int farScale = Settings.REGISTRY.waypointBeaconScaleMin.getAsInt(); + final double maxRenderDistance = Math.min(mc.options.renderDistance().get() << 4, farScale == 0 ? Integer.MAX_VALUE : farScale << 4); + if (xzDistance > maxRenderDistance) { + final Vec3 delta = waypointVec.subtract(playerVec).normalize(); + waypointVec = playerVec.add(new Vec3(delta.x * maxRenderDistance, delta.y * maxRenderDistance, delta.z * maxRenderDistance)); + } + final EntityRenderDispatcher entityRenderDispatcher = mc.getEntityRenderDispatcher(); + final Camera camera = entityRenderDispatcher.camera; + final Frustum frustum = mc.levelRenderer.cullingFrustum; + if (camera == null || frustum == null) return; + final double viewX = camera.getPosition().x(); + final double viewZ = camera.getPosition().z(); + final double x = waypointVec.x - viewX; + final double z = waypointVec.z - viewZ; + final double y = -100; + if (!frustum.isVisible(new AABB(waypointVec.x-1, -100, waypointVec.z-1, waypointVec.x+1, 500, waypointVec.z+1))) return; + final int color = waypoint.getWaypointColor().getHex(); + final MultiBufferSource.BufferSource entityVertexConsumers = mc.renderBuffers().bufferSource(); + final long time = mc.level.getGameTime(); + matrixStack.pushPose(); + matrixStack.translate(x, y, z); + BeaconRenderer.renderBeaconBeam( + matrixStack, entityVertexConsumers, BEAM_LOCATION, tickDelta, 1.0f, time, 0, 355, + color, 0.2f, 0.25f); + matrixStack.popPose(); + } +} diff --git a/common/src/main/java/xaeroplus/mixin/client/MixinMinimapFBORenderer.java b/common/src/main/java/xaeroplus/mixin/client/MixinMinimapFBORenderer.java index fab6ea23..c5dc68e1 100644 --- a/common/src/main/java/xaeroplus/mixin/client/MixinMinimapFBORenderer.java +++ b/common/src/main/java/xaeroplus/mixin/client/MixinMinimapFBORenderer.java @@ -15,6 +15,8 @@ import net.minecraft.world.entity.player.Player; import org.joml.Matrix4f; import org.joml.Matrix4fStack; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -81,9 +83,9 @@ public void reloadMapFrameBuffers() { @ModifyArg(method = "renderChunks", at = @At( value = "INVOKE", - target = "Lxaero/common/minimap/render/MinimapFBORenderer;renderChunksToFBO(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;DDIIFFIZZZIDDZZLxaero/common/graphics/CustomVertexConsumers;)V" + target = "Lxaero/common/minimap/render/MinimapFBORenderer;renderChunksToFBO(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/resources/ResourceKey;DIFIZZIDDZLxaero/common/graphics/CustomVertexConsumers;)V" ), - index = 9, + index = 6, remap = true) // $REMAP public int modifyViewW(final int viewW) { return viewW * Globals.minimapScaleMultiplier; @@ -93,7 +95,7 @@ public int modifyViewW(final int viewW) { value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;pose()Lcom/mojang/blaze3d/vertex/PoseStack;" ), remap = true) - public void modifyScaledSize(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Player player, final Entity renderEntity, final Vec3 renderPos, final double playerDimDiv, final double mapDimensionScale, final int bufferSize, final int viewW, final float sizeFix, final float partial, final int level, final boolean retryIfError, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final boolean circle, final CustomVertexConsumers cvc, final CallbackInfo ci, + public void modifyScaledSize(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Vec3 renderPos, final ResourceKey mapDimension, final double mapDimensionScale, final int viewW, final float partial, final int level, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final CustomVertexConsumers cvc, final CallbackInfo ci, @Share("scaledSize") LocalIntRef scaledSize) { int s = 256 * Globals.minimapScaleMultiplier * Globals.minimapSizeMultiplier; if (Globals.minimapSizeMultiplier > 1) { @@ -143,7 +145,7 @@ public float modifyChunkGridLineWidth(final float original) { target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch()V", ordinal = 0 ), remap = true) - public void drawRenderDistanceSquare(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Player player, final Entity renderEntity, final Vec3 renderPos, final double playerDimDiv, final double mapDimensionScale, final int bufferSize, final int viewW, final float sizeFix, final float partial, final int level, final boolean retryIfError, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final boolean circle, final CustomVertexConsumers cvc, final CallbackInfo ci, + public void drawRenderDistanceSquare(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Vec3 renderPos, final ResourceKey mapDimension, final double mapDimensionScale, final int viewW, final float partial, final int level, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final CustomVertexConsumers cvc, final CallbackInfo ci, @Local(name = "xFloored") int xFloored, @Local(name = "zFloored") int zFloored, @Local(name = "renderTypeBuffers") MultiBufferSource.BufferSource renderTypeBuffers, @@ -204,11 +206,11 @@ public void drawRenderDistanceSquare(final MinimapSession minimapSession, final target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endBatch()V", ordinal = 0 ), remap = true) - public void drawWorldBorderSquare(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Player player, final Entity renderEntity, final Vec3 renderPos, final double playerDimDiv, final double mapDimensionScale, final int bufferSize, final int viewW, final float sizeFix, final float partial, final int level, final boolean retryIfError, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final boolean circle, final CustomVertexConsumers cvc, final CallbackInfo ci, - @Local(name = "xFloored") int xFloored, - @Local(name = "zFloored") int zFloored, - @Local(name = "renderTypeBuffers") MultiBufferSource.BufferSource renderTypeBuffers, - @Local(name = "matrixStack") PoseStack matrixStack + public void drawWorldBorderSquare(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Vec3 renderPos, final ResourceKey mapDimension, final double mapDimensionScale, final int viewW, final float partial, final int level, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final CustomVertexConsumers cvc, final CallbackInfo ci, + @Local(name = "xFloored") int xFloored, + @Local(name = "zFloored") int zFloored, + @Local(name = "renderTypeBuffers") MultiBufferSource.BufferSource renderTypeBuffers, + @Local(name = "matrixStack") PoseStack matrixStack ) { final boolean isDimensionSwitched = Globals.getCurrentDimensionId() != Minecraft.getInstance().level.dimension(); if (!Settings.REGISTRY.showWorldBorderSetting.get() || isDimensionSwitched) return; @@ -279,7 +281,7 @@ public Matrix4f correctPreRotationTranslationForSizeMult(final Matrix4fStack ins target = "Lxaero/common/graphics/ImprovedFramebuffer;bindRead()V" ) ), remap = true) - public void correctPostRotationTranslationForSizeMult(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Player player, final Entity renderEntity, final Vec3 renderPos, final double playerDimDiv, final double mapDimensionScale, final int bufferSize, final int viewW, final float sizeFix, final float partial, final int level, final boolean retryIfError, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final boolean circle, final CustomVertexConsumers cvc, final CallbackInfo ci, + public void correctPostRotationTranslationForSizeMult(final MinimapSession minimapSession, final GuiGraphics guiGraphics, final MinimapProcessor minimap, final Vec3 renderPos, final ResourceKey mapDimension, final double mapDimensionScale, final int viewW, final float partial, final int level, final boolean useWorldMap, final boolean lockedNorth, final int shape, final double ps, final double pc, final boolean cave, final CustomVertexConsumers cvc, final CallbackInfo ci, @Local(name = "halfWView") float halfWView, @Local(name = "shaderMatrixStack") Matrix4fStack shaderMatrixStack) { float sizeMultTranslation = (halfWView / Globals.minimapSizeMultiplier) * (Globals.minimapSizeMultiplier - 1); diff --git a/common/src/main/java/xaeroplus/mixin/client/MixinMinimapRenderer.java b/common/src/main/java/xaeroplus/mixin/client/MixinMinimapRenderer.java index 43ed2403..f5186836 100644 --- a/common/src/main/java/xaeroplus/mixin/client/MixinMinimapRenderer.java +++ b/common/src/main/java/xaeroplus/mixin/client/MixinMinimapRenderer.java @@ -2,21 +2,18 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import xaero.common.IXaeroMinimap; import xaero.common.graphics.CustomVertexConsumers; -import xaero.common.graphics.renderer.multitexture.MultiTextureRenderTypeRendererProvider; import xaero.common.minimap.MinimapProcessor; import xaero.common.minimap.radar.MinimapRadar; import xaero.common.minimap.render.MinimapFBORenderer; @@ -68,7 +65,7 @@ public void renderMinimap( slice = @Slice( from = @At( value = "INVOKE", - target = "Lxaero/common/minimap/render/MinimapRenderer;renderChunks(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;DDIIFFIZZIDDZZLxaero/common/settings/ModSettings;Lxaero/common/graphics/CustomVertexConsumers;)V" + target = "Lxaero/common/minimap/render/MinimapRenderer;renderChunks(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/resources/ResourceKey;DIIFFIZZIDDZZLxaero/common/settings/ModSettings;Lxaero/common/graphics/CustomVertexConsumers;)V" ) ) ) @@ -89,7 +86,7 @@ public int modifyMinimapSizeConstantI(final int constant) { slice = @Slice( from = @At( value = "INVOKE", - target = "Lxaero/common/minimap/render/MinimapRenderer;renderChunks(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;DDIIFFIZZIDDZZLxaero/common/settings/ModSettings;Lxaero/common/graphics/CustomVertexConsumers;)V" + target = "Lxaero/common/minimap/render/MinimapRenderer;renderChunks(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/resources/ResourceKey;DIIFFIZZIDDZZLxaero/common/settings/ModSettings;Lxaero/common/graphics/CustomVertexConsumers;)V" ) ) ) @@ -110,7 +107,7 @@ public float modifyMinimapSizeConstantF(final float constant) { slice = @Slice( from = @At( value = "INVOKE", - target = "Lxaero/common/minimap/render/MinimapRenderer;renderChunks(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;DDIIFFIZZIDDZZLxaero/common/settings/ModSettings;Lxaero/common/graphics/CustomVertexConsumers;)V" + target = "Lxaero/common/minimap/render/MinimapRenderer;renderChunks(Lxaero/hud/minimap/module/MinimapSession;Lnet/minecraft/client/gui/GuiGraphics;Lxaero/common/minimap/MinimapProcessor;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/resources/ResourceKey;DIIFFIZZIDDZZLxaero/common/settings/ModSettings;Lxaero/common/graphics/CustomVertexConsumers;)V" ) ) ) @@ -124,38 +121,33 @@ public float modifyMinimapSizeConstantFCircle(final float constant) { @Redirect(method = "renderMinimap", at = @At( value = "INVOKE", - target = "Lxaero/hud/minimap/element/render/over/MinimapElementOverMapRendererHandler;render(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/phys/Vec3;DDDDZFLcom/mojang/blaze3d/pipeline/RenderTarget;Lxaero/common/graphics/renderer/multitexture/MultiTextureRenderTypeRendererProvider;)V"), + target = "Lxaero/hud/minimap/element/render/over/MinimapElementOverMapRendererHandler;prepareRender(DDDIIIIZF)V"), remap = true) // $REMAP - public void editOvermapRender(final MinimapElementOverMapRendererHandler instance, - final GuiGraphics guiGraphics, - final Entity entity, - final Player player, - final Vec3 renderPos, - final double playerDimDiv, - final double ps, - final double pc, - double zoom, - final boolean cave, - final float partialTicks, - final RenderTarget framebuffer, - final MultiTextureRenderTypeRendererProvider multiTextureRenderTypeRenderers + public void editOvermapRender( + final MinimapElementOverMapRendererHandler instance, + final double ps, + final double pc, + double zoom, + final int specW, + final int specH, + final int halfViewW, + final int halfViewH, + final boolean circle, + final float minimapScale ) { if (this.minimap.usingFBO()) { zoom = (zoom / Globals.minimapScaleMultiplier) * Globals.minimapSizeMultiplier; } - instance.render( - guiGraphics, - entity, - player, - renderPos, - playerDimDiv, + instance.prepareRender( ps, pc, zoom, - cave, - partialTicks, - framebuffer, - multiTextureRenderTypeRenderers + specW, + specH, + halfViewW, + halfViewH, + circle, + minimapScale ); } diff --git a/common/src/main/java/xaeroplus/mixin/client/MixinWaypointWorldRenderer.java b/common/src/main/java/xaeroplus/mixin/client/MixinWaypointWorldRenderer.java new file mode 100644 index 00000000..1e4c3ef0 --- /dev/null +++ b/common/src/main/java/xaeroplus/mixin/client/MixinWaypointWorldRenderer.java @@ -0,0 +1,141 @@ +package xaeroplus.mixin.client; + +import com.llamalad7.mixinextras.sugar.Local; +import it.unimi.dsi.fastutil.doubles.DoubleArrayFIFOQueue; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +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.ModifyArg; +import xaero.common.minimap.waypoints.Waypoint; +import xaero.hud.minimap.BuiltInHudModules; +import xaero.hud.minimap.module.MinimapSession; +import xaero.hud.minimap.waypoint.render.world.WaypointWorldRenderer; +import xaeroplus.settings.Settings; +import xaeroplus.util.ChunkUtils; + +import static net.minecraft.world.level.Level.NETHER; +import static net.minecraft.world.level.Level.OVERWORLD; + +@Mixin(value = WaypointWorldRenderer.class, remap = false) +public class MixinWaypointWorldRenderer { + + @Shadow private String subWorldName; + + @ModifyArg(method = "renderElement(Lxaero/common/minimap/waypoints/Waypoint;ZZDFDDLxaero/hud/minimap/element/render/MinimapElementRenderInfo;Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;)Z", at = @At( + value = "INVOKE", + target = "Lxaero/hud/minimap/waypoint/render/world/WaypointWorldRenderer;renderIconWithLabels(Lxaero/common/minimap/waypoints/Waypoint;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;FIILnet/minecraft/client/gui/Font;ILcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;)V"), + index = 4, + remap = true) // $REMAP + public String preferOwWaypointsRemoveSubworldText(final String name) { + if (!Settings.REGISTRY.owAutoWaypointDimension.get()) return name; + if (this.subWorldName == null) return name; + ResourceKey actualDimension = ChunkUtils.getActualDimension(); + ResourceKey currentWpWorldDim = BuiltInHudModules.MINIMAP.getCurrentSession().getWorldManager().getCurrentWorld().getDimId(); + if (actualDimension == NETHER && currentWpWorldDim == OVERWORLD) { + return null; + } + return name; + } + + /** + * todo: separate out rendering so it is independent of when distance text is rendered + * and put it on its own line + */ + @ModifyArg(method = "renderElement(Lxaero/common/minimap/waypoints/Waypoint;ZZDFDDLxaero/hud/minimap/element/render/MinimapElementRenderInfo;Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;)Z", at = @At( + value = "INVOKE", + target = "Lxaero/hud/minimap/waypoint/render/world/WaypointWorldRenderer;renderIconWithLabels(Lxaero/common/minimap/waypoints/Waypoint;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;FIILnet/minecraft/client/gui/Font;ILcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;)V"), + index = 3, + remap = true) // $REMAP + public String modifyDistanceText(final String text, @Local(argsOnly = true) Waypoint waypoint) { + if (!Settings.REGISTRY.waypointEta.get()) return text; + if (text == null || text.isBlank()) return text; + var eta = getEtaSecondsToReachWaypoint(waypoint); + if (eta <= 0) return text; + String etaText = " - "; + if (eta > 86400) { + int days = (int) (eta / 86400); + int hours = (int) ((eta % 86400) / 3600); + etaText += days + "d"; + if (hours > 0) etaText += " " + hours + "h"; + } else if (eta > 3600) { + int hours = (int) (eta / 3600); + int minutes = (int) ((eta % 3600) / 60); + etaText += hours + "h"; + if (minutes > 0) etaText += " " + minutes + "m"; + } else if (eta > 60) { + int minutes = (int) (eta / 60); + int seconds = (int) (eta % 60); + etaText += minutes + "m"; + if (seconds > 0) etaText += " " + seconds + "s"; + } else { + etaText += eta + "s"; + } + return text + etaText; + } + + // average out and smoothen speed updates so they aren't tied directly to fps + @Unique + long xaeroPlus$lastSpeedUpdate = 0; + @Unique public final DoubleArrayFIFOQueue xaeroPlus$speedQueue = new DoubleArrayFIFOQueue(15); + + @Unique + public long getEtaSecondsToReachWaypoint(Waypoint waypoint) { + final Minecraft mc = Minecraft.getInstance(); + if (mc.level == null || mc.player == null) return 0; + try { + final Vec3 playerVec = mc.player.position(); + MinimapSession minimapSession = BuiltInHudModules.MINIMAP.getCurrentSession(); + if (minimapSession == null) return 0; + double dimDiv = minimapSession.getDimensionHelper().getDimensionDivision(minimapSession.getWorldManager().getCurrentWorld()); + int wpX = waypoint.getX(dimDiv); + int wpZ = waypoint.getZ(dimDiv); + double directionX = wpX - playerVec.x; + double directionZ = wpZ - playerVec.z; + double movementX = playerVec.x - mc.player.xOld; + double movementZ = playerVec.z - mc.player.zOld; + double dot = directionX * movementX + directionZ * movementZ; + double distance = Math.sqrt(directionX * directionX + directionZ * directionZ); + double speed = xaeroPlus$speedQueue.isEmpty() ? 0.0 : xaeroPlus$avgSpeed(xaeroPlus$speedQueue); + double cos = dot / (distance * speed); + double time = distance / speed; + double etaTicks = time / cos; + double etaSeconds = etaTicks / 20.0; + + // update avg speed measurements + var updateDeltaMs = System.currentTimeMillis() - xaeroPlus$lastSpeedUpdate; + if (updateDeltaMs > 50) { + xaeroPlus$lastSpeedUpdate = System.currentTimeMillis(); + double s = Math.sqrt(movementX * movementX + movementZ * movementZ); + if (s > 0 || mc.player.tickCount % 4 == 0) { + xaeroPlus$speedQueue.enqueue(s); + } else if (!xaeroPlus$speedQueue.isEmpty()) { + xaeroPlus$speedQueue.dequeueDouble(); + } + while (xaeroPlus$speedQueue.size() > 10) xaeroPlus$speedQueue.dequeueDouble(); + } + if (etaSeconds == Double.POSITIVE_INFINITY || etaSeconds == Double.NEGATIVE_INFINITY || Double.isNaN(etaSeconds)) return 0; + return (long) etaSeconds; + } catch (final Exception e) { + // fall through + } + return 0; + } + + @Unique + private double xaeroPlus$avgSpeed(final DoubleArrayFIFOQueue speedQueue) { + double sum = 0; + for (int i = 0; i < speedQueue.size(); i++) { + var v = speedQueue.dequeueDouble(); + speedQueue.enqueue(v); + sum += v; + } + var s = sum / speedQueue.size(); + if (s < 0.05) return 0.0; // floor very low speeds + return s; + } +} diff --git a/common/src/main/java/xaeroplus/mixin/client/MixinWaypointsIngameRenderer.java b/common/src/main/java/xaeroplus/mixin/client/MixinWaypointsIngameRenderer.java deleted file mode 100644 index 8002b1e7..00000000 --- a/common/src/main/java/xaeroplus/mixin/client/MixinWaypointsIngameRenderer.java +++ /dev/null @@ -1,242 +0,0 @@ -package xaeroplus.mixin.client; - -import com.llamalad7.mixinextras.sugar.Local; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexConsumer; -import it.unimi.dsi.fastutil.doubles.DoubleArrayFIFOQueue; -import net.minecraft.client.Camera; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BeaconRenderer; -import net.minecraft.client.renderer.culling.Frustum; -import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; -import org.joml.Vector3f; -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.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import xaero.common.minimap.MinimapProcessor; -import xaero.common.minimap.render.MinimapRendererHelper; -import xaero.common.minimap.waypoints.Waypoint; -import xaero.common.minimap.waypoints.WaypointVisibilityType; -import xaero.common.minimap.waypoints.render.WaypointsIngameRenderer; -import xaero.hud.minimap.BuiltInHudModules; -import xaero.hud.minimap.module.MinimapSession; -import xaero.hud.minimap.waypoint.render.WaypointFilterParams; -import xaeroplus.feature.extensions.CustomWaypointsIngameRenderer; -import xaeroplus.settings.Settings; -import xaeroplus.util.ChunkUtils; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static net.minecraft.client.renderer.blockentity.BeaconRenderer.BEAM_LOCATION; -import static net.minecraft.world.level.Level.NETHER; -import static net.minecraft.world.level.Level.OVERWORLD; - -@Mixin(value = WaypointsIngameRenderer.class, remap = false) -public class MixinWaypointsIngameRenderer implements CustomWaypointsIngameRenderer { - @Shadow private List sortingList; - @Shadow private WaypointFilterParams filterParams; - @Unique List beaconWaypoints = new ArrayList<>(); - @Unique final Predicate beaconViewFilter = (w) -> { - boolean deathpoints = filterParams.deathpoints; - if (!w.isDisabled() - && w.getVisibility() != WaypointVisibilityType.WORLD_MAP_LOCAL - && w.getVisibility() != WaypointVisibilityType.WORLD_MAP_GLOBAL - && (!w.getPurpose().isDeath() || deathpoints)) { - double offX = (double)w.getX(filterParams.dimDiv) - filterParams.cameraPos.x + 0.5; - double offZ = (double)w.getZ(filterParams.dimDiv) - filterParams.cameraPos.z + 0.5; - double distanceScale = filterParams.dimensionScaleDistance ? Minecraft.getInstance().level.dimensionType().coordinateScale() : 1.0; - double unscaledDistance2D = Math.sqrt(offX * offX + offZ * offZ); - double distance2D = unscaledDistance2D * distanceScale; - double waypointsDistance = filterParams.waypointsDistance; - double waypointsDistanceMin = filterParams.waypointsDistanceMin; - return w.isDestination() - || ( - w.getPurpose().isDeath() - || w.isGlobal() - || w.isTemporary() && filterParams.temporaryWaypointsGlobal - || waypointsDistance == 0.0 - || !(distance2D > waypointsDistance) - ) - && (waypointsDistanceMin == 0.0 || !(unscaledDistance2D < waypointsDistanceMin)); - } else { - return false; - } - }; - - @Inject(method = "render", at = @At( - value = "INVOKE", - target = "Lxaero/hud/minimap/waypoint/render/WaypointDeleter;begin()V" - )) - public void preferOwWaypointsRemoveSubworldText(final MinimapSession session, final float partial, final MinimapProcessor minimap, final Matrix4f waypointsProjection, final Matrix4f worldModelView, final CallbackInfo ci, - @Local(name = "subworldName") LocalRef subWorldNameRef) { - if (!Settings.REGISTRY.owAutoWaypointDimension.get()) return; - if (subWorldNameRef.get() == null) return; - ResourceKey actualDimension = ChunkUtils.getActualDimension(); - ResourceKey currentWpWorldDim = session.getWorldManager().getCurrentWorld().getDimId(); - if (actualDimension == NETHER && currentWpWorldDim == OVERWORLD) { - subWorldNameRef.set(null); - } - } - - @Inject(method = "renderWaypointsIterator", at = @At("HEAD")) - public void collectBeaconWaypointsList(final PoseStack matrixStack, final PoseStack matrixStackOverlay, final MinimapRendererHelper helper, final Iterator iter, final double d3, final double d4, final double d5, final Entity entity, final Tesselator tessellator, final double dimDiv, final double actualEntityX, final double actualEntityY, final double actualEntityZ, final double smoothEntityY, final double fov, final int screenHeight, final float cameraAngleYaw, final float cameraAnglePitch, final Vector3f lookVector, final double clampDepth, final MultiBufferSource.BufferSource renderTypeBuffer, final VertexConsumer waypointBackgroundConsumer, final Font fontrenderer, final Matrix4f waypointsProjection, final int screenWidth, final boolean detailedDisplayAllowed, final double minDistance, final String subworldName, final CallbackInfo ci) { - beaconWaypoints = sortingList.stream().filter(beaconViewFilter).sorted().collect(Collectors.toList()); - } - - @Override - public void renderWaypointBeacons(final MinimapSession minimapSession, final PoseStack matrixStack, final float tickDelta) { - double dimDiv = minimapSession.getDimensionHelper().getDimensionDivision(minimapSession.getWorldManager().getCurrentWorld()); - beaconWaypoints.forEach(w -> renderWaypointBeacon(w, dimDiv, tickDelta, matrixStack)); - beaconWaypoints.clear(); - } - - @Unique - public void renderWaypointBeacon(final Waypoint waypoint, final double dimDiv, float tickDelta, PoseStack matrixStack) { - final Minecraft mc = Minecraft.getInstance(); - if (mc.level == null || mc.player == null) return; - final Vec3 playerVec = mc.player.position(); - Vec3 waypointVec = new Vec3(waypoint.getX(dimDiv), playerVec.y, waypoint.getZ(dimDiv)); - final double xzDistance = playerVec.distanceTo(waypointVec); - if (xzDistance < Settings.REGISTRY.waypointBeaconDistanceMin.getAsInt()) return; - final int farScale = Settings.REGISTRY.waypointBeaconScaleMin.getAsInt(); - final double maxRenderDistance = Math.min(mc.options.renderDistance().get() << 4, farScale == 0 ? Integer.MAX_VALUE : farScale << 4); - if (xzDistance > maxRenderDistance) { - final Vec3 delta = waypointVec.subtract(playerVec).normalize(); - waypointVec = playerVec.add(new Vec3(delta.x * maxRenderDistance, delta.y * maxRenderDistance, delta.z * maxRenderDistance)); - } - final EntityRenderDispatcher entityRenderDispatcher = mc.getEntityRenderDispatcher(); - final Camera camera = entityRenderDispatcher.camera; - final Frustum frustum = mc.levelRenderer.cullingFrustum; - if (camera == null || frustum == null) return; - final double viewX = camera.getPosition().x(); - final double viewZ = camera.getPosition().z(); - final double x = waypointVec.x - viewX; - final double z = waypointVec.z - viewZ; - final double y = -100; - if (!frustum.isVisible(new AABB(waypointVec.x-1, -100, waypointVec.z-1, waypointVec.x+1, 500, waypointVec.z+1))) return; - final int color = waypoint.getWaypointColor().getHex(); - final MultiBufferSource.BufferSource entityVertexConsumers = mc.renderBuffers().bufferSource(); - final long time = mc.level.getGameTime(); - matrixStack.pushPose(); - matrixStack.translate(x, y, z); - BeaconRenderer.renderBeaconBeam( - matrixStack, entityVertexConsumers, BEAM_LOCATION, tickDelta, - 1.0f, time, 0, 355, - color, 0.2f, 0.25f); - matrixStack.popPose(); - } - - /** - * todo: separate out rendering so it is independent of when distance text is rendered - * and put it on its own line - */ - @ModifyArg(method = "renderWaypointIngame", at = @At( - value = "INVOKE", - target = "Lxaero/common/minimap/waypoints/render/WaypointsIngameRenderer;drawAsOverlay(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/PoseStack;Lxaero/common/minimap/render/MinimapRendererHelper;Lxaero/common/minimap/waypoints/Waypoint;Lxaero/common/settings/ModSettings;Lcom/mojang/blaze3d/vertex/Tesselator;Lnet/minecraft/client/gui/Font;Ljava/lang/String;Ljava/lang/String;FZLnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lorg/joml/Matrix4f;IIDDZLjava/lang/String;)V"), - index = 8, - remap = true) // $REMAP - public String modifyDistanceText(final String text, @Local(argsOnly = true) Waypoint waypoint) { - if (!Settings.REGISTRY.waypointEta.get()) return text; - if (text.isBlank()) return text; - var eta = getEtaSecondsToReachWaypoint(waypoint); - if (eta <= 0) return text; - String etaText = " - "; - if (eta > 86400) { - int days = (int) (eta / 86400); - int hours = (int) ((eta % 86400) / 3600); - etaText += days + "d"; - if (hours > 0) etaText += " " + hours + "h"; - } else if (eta > 3600) { - int hours = (int) (eta / 3600); - int minutes = (int) ((eta % 3600) / 60); - etaText += hours + "h"; - if (minutes > 0) etaText += " " + minutes + "m"; - } else if (eta > 60) { - int minutes = (int) (eta / 60); - int seconds = (int) (eta % 60); - etaText += minutes + "m"; - if (seconds > 0) etaText += " " + seconds + "s"; - } else { - etaText += eta + "s"; - } - return text + etaText; - } - - // average out and smoothen speed updates so they aren't tied directly to fps - @Unique long xaeroPlus$lastSpeedUpdate = 0; - @Unique public final DoubleArrayFIFOQueue xaeroPlus$speedQueue = new DoubleArrayFIFOQueue(15); - - @Unique - public long getEtaSecondsToReachWaypoint(Waypoint waypoint) { - final Minecraft mc = Minecraft.getInstance(); - if (mc.level == null || mc.player == null) return 0; - try { - final Vec3 playerVec = mc.player.position(); - MinimapSession minimapSession = BuiltInHudModules.MINIMAP.getCurrentSession(); - if (minimapSession == null) return 0; - double dimDiv = minimapSession.getDimensionHelper().getDimensionDivision(minimapSession.getWorldManager().getCurrentWorld()); - int wpX = waypoint.getX(dimDiv); - int wpZ = waypoint.getZ(dimDiv); - double directionX = wpX - playerVec.x; - double directionZ = wpZ - playerVec.z; - double movementX = playerVec.x - mc.player.xOld; - double movementZ = playerVec.z - mc.player.zOld; - double dot = directionX * movementX + directionZ * movementZ; - double distance = Math.sqrt(directionX * directionX + directionZ * directionZ); - double speed = xaeroPlus$speedQueue.isEmpty() ? 0.0 : xaeroPlus$avgSpeed(xaeroPlus$speedQueue); - double cos = dot / (distance * speed); - double time = distance / speed; - double etaTicks = time / cos; - double etaSeconds = etaTicks / 20.0; - - // update avg speed measurements - var updateDeltaMs = System.currentTimeMillis() - xaeroPlus$lastSpeedUpdate; - if (updateDeltaMs > 50) { - xaeroPlus$lastSpeedUpdate = System.currentTimeMillis(); - double s = Math.sqrt(movementX * movementX + movementZ * movementZ); - if (s > 0 || mc.player.tickCount % 4 == 0) { - xaeroPlus$speedQueue.enqueue(s); - } else if (!xaeroPlus$speedQueue.isEmpty()) { - xaeroPlus$speedQueue.dequeueDouble(); - } - while (xaeroPlus$speedQueue.size() > 10) xaeroPlus$speedQueue.dequeueDouble(); - } - if (etaSeconds == Double.POSITIVE_INFINITY || etaSeconds == Double.NEGATIVE_INFINITY || Double.isNaN(etaSeconds)) return 0; - return (long) etaSeconds; - } catch (final Exception e) { - // fall through - } - return 0; - } - - @Unique - private double xaeroPlus$avgSpeed(final DoubleArrayFIFOQueue speedQueue) { - double sum = 0; - for (int i = 0; i < speedQueue.size(); i++) { - var v = speedQueue.dequeueDouble(); - speedQueue.enqueue(v); - sum += v; - } - var s = sum / speedQueue.size(); - if (s < 0.05) return 0.0; // floor very low speeds - return s; - } -} diff --git a/common/src/main/java/xaeroplus/mixin/client/mc/MixinWorldRenderer.java b/common/src/main/java/xaeroplus/mixin/client/mc/MixinWorldRenderer.java index 0dc18396..7fe4a712 100644 --- a/common/src/main/java/xaeroplus/mixin/client/mc/MixinWorldRenderer.java +++ b/common/src/main/java/xaeroplus/mixin/client/mc/MixinWorldRenderer.java @@ -13,12 +13,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import xaero.common.HudMod; -import xaero.common.minimap.waypoints.render.WaypointsIngameRenderer; import xaero.hud.minimap.BuiltInHudModules; -import xaero.hud.minimap.Minimap; import xaero.hud.minimap.module.MinimapSession; import xaeroplus.XaeroPlus; -import xaeroplus.feature.extensions.CustomWaypointsIngameRenderer; +import xaeroplus.feature.render.WaypointBeaconRenderer; import xaeroplus.settings.Settings; @Mixin(value = LevelRenderer.class) @@ -29,16 +27,16 @@ public class MixinWorldRenderer { public void renderBlockEntitiesInject(final DeltaTracker deltaTracker, final boolean renderBlockOutline, final Camera camera, final GameRenderer gameRenderer, final LightTexture lightTexture, final Matrix4f projectionMatrix, final Matrix4f frustumMatrix, final CallbackInfo ci, @Local PoseStack poseStack) { if (!Settings.REGISTRY.waypointBeacons.get()) return; - HudMod hudMod = HudMod.INSTANCE; + var hudMod = HudMod.INSTANCE; if (hudMod == null) return; - Minimap minimap = hudMod.getMinimap(); + var minimap = hudMod.getMinimap(); if (minimap == null) return; - WaypointsIngameRenderer waypointsIngameRenderer = minimap.getWaypointsIngameRenderer(); + var waypointsIngameRenderer = minimap.getWaypointWorldRenderer(); if (waypointsIngameRenderer == null) return; MinimapSession minimapSession = BuiltInHudModules.MINIMAP.getCurrentSession(); if (minimapSession == null) return; try { - ((CustomWaypointsIngameRenderer) waypointsIngameRenderer).renderWaypointBeacons(minimapSession, poseStack, deltaTracker.getGameTimeDeltaPartialTick(false)); + WaypointBeaconRenderer.INSTANCE.renderWaypointBeacons(deltaTracker.getGameTimeDeltaPartialTick(false), poseStack); } catch (final Exception e) { if (errorCount++ < 2) XaeroPlus.LOGGER.error("Error rendering waypoints", e); } diff --git a/common/src/main/resources/assets/xaeroplus/lang/ja_jp.json b/common/src/main/resources/assets/xaeroplus/lang/ja_jp.json index 07324a84..9eb0885a 100644 --- a/common/src/main/resources/assets/xaeroplus/lang/ja_jp.json +++ b/common/src/main/resources/assets/xaeroplus/lang/ja_jp.json @@ -192,7 +192,7 @@ "xaeroplus.gui.minimap_incompatible.currently_installed_version": "現在のバージョン: ", "xaeroplus.gui.minimap_incompatible.required_version": "必要なバージョン: ", "xaeroplus.gui.minimap_incompatible.download_minimap": "Xaero's Minimapをダウンロード", - "xaeroplus.gui.minimap_incompatible.exit": "出口", + "xaeroplus.gui.minimap_incompatible.exit": "終了", "xaeroplus.gui.world_map.copy_coordinates": " [XP] 座標をコピー", "xaeroplus.gui.world_map.go_to_coordinates": "この座標に行く", "xaeroplus.gui.world_map.baritone_goal_here": "§2%s§r [XP] Baritoneのゴール", diff --git a/common/src/main/resources/xaeroplus.mixins.json b/common/src/main/resources/xaeroplus.mixins.json index 17f167ff..531f1a2d 100644 --- a/common/src/main/resources/xaeroplus.mixins.json +++ b/common/src/main/resources/xaeroplus.mixins.json @@ -60,7 +60,7 @@ "MixinSupportXaeroWorldmap", "MixinWaypointReader", "MixinWaypointSharingHandler", - "MixinWaypointsIngameRenderer", + "MixinWaypointWorldRenderer", "MixinWidgetLoadingHandler", "MixinWorldDataReader", "MixinWorldMapGuiSettings", diff --git a/settings.gradle.kts b/settings.gradle.kts index af22015a..8e08e67d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,11 +13,11 @@ gradle.extra.apply { set("minecraft_version", "1.21") set("parchment_version", "2024.07.28") set("worldmap_version_fabric", "1.39.0") - set("minimap_version_fabric", "24.5.0") + set("minimap_version_fabric", "24.6.1") set("worldmap_version_forge", "1.39.0") - set("minimap_version_forge", "24.5.0") + set("minimap_version_forge", "24.6.1") set("worldmap_version_neo", "1.39.0") - set("minimap_version_neo", "24.5.0") + set("minimap_version_neo", "24.6.1") } dependencyResolutionManagement {