diff --git a/src/main/java/com/listmore/ListMore.java b/src/main/java/com/listmore/ListMore.java index 2e92161..958ec9f 100644 --- a/src/main/java/com/listmore/ListMore.java +++ b/src/main/java/com/listmore/ListMore.java @@ -4,7 +4,6 @@ import com.listmore.config.ListMoreConfigs; import com.listmore.input.CopyTargetIdInputHandler; import com.listmore.render.InvalidFurnaceInputRenderer; -import com.listmore.render.PlayerTracerHudRenderer; import com.listmore.render.ProjectileLandingRenderer; import com.listmore.render.TntExplosionPreviewRenderer; @@ -15,9 +14,6 @@ import fi.dy.masa.malilib.registry.Registry; import fi.dy.masa.malilib.util.data.ModInfo; import net.fabricmc.api.ClientModInitializer; -import net.minecraft.client.Minecraft; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,11 +30,6 @@ public void registerModHandlers() { initializeConfigs(); CopyTargetIdInputHandler.getInstance().init(); InputEventHandler.getKeybindManager().registerKeybindProvider(CopyTargetIdInputHandler.getInstance()); - //#if MC >= 26.1 - //$$ RenderEventHandler.getInstance().registerInGameGuiRenderer(PlayerTracerHudRenderer.getInstance()); - //#else - RenderEventHandler.getInstance().registerGameOverlayRenderer(PlayerTracerHudRenderer.getInstance()); - //#endif RenderEventHandler.getInstance().registerWorldLastRenderer(ProjectileLandingRenderer.getInstance()); RenderEventHandler.getInstance().registerWorldLastRenderer(InvalidFurnaceInputRenderer.getInstance()); RenderEventHandler.getInstance().registerWorldLastRenderer(TntExplosionPreviewRenderer.getInstance()); @@ -54,26 +45,4 @@ public static void initializeConfigs() { } } - public static boolean shouldRenderPlayerTracer(Entity entity) { - if (!(entity instanceof Player)) { - return false; - } - if (!ListMoreConfigs.Generic.PLAYER_TRACER.getBooleanValue()) { - return false; - } - - Minecraft client = Minecraft.getInstance(); - if (client.player == null || client.level == null) { - return false; - } - if (entity == client.player || entity.isRemoved()) { - return false; - } - - return client.player.distanceToSqr(entity) <= 96.0D * 96.0D; - } - - public static int getPlayerTracerColorArgb() { - return ListMoreConfigs.Generic.PLAYER_TRACER_COLOR.getIntegerValue(); - } } diff --git a/src/main/java/com/listmore/config/ListMoreConfigs.java b/src/main/java/com/listmore/config/ListMoreConfigs.java index f04b729..1a65950 100644 --- a/src/main/java/com/listmore/config/ListMoreConfigs.java +++ b/src/main/java/com/listmore/config/ListMoreConfigs.java @@ -48,8 +48,6 @@ public static class Generic { public static final ConfigInteger INVALID_FURNACE_INPUT_HIGHLIGHTER_RANGE = createInvalidFurnaceInputHighlighterRange(); public static final ConfigBoolean TNT_EXPLOSION_PREVIEW = createTntExplosionPreview(); public static final ConfigOptionList TNT_EXPLOSION_PREVIEW_MODE = createTntExplosionPreviewMode(); - public static final ConfigBoolean PLAYER_TRACER = createPlayerTracer(); - public static final ConfigColor PLAYER_TRACER_COLOR = createPlayerTracerColor(); public static final ConfigBoolean PROJECTILE_LANDING_PREDICTION = createProjectileLandingPrediction(); public static final ImmutableList OPTIONS = ImmutableList.of( @@ -64,8 +62,6 @@ public static class Generic { INVALID_FURNACE_INPUT_HIGHLIGHTER_RANGE, TNT_EXPLOSION_PREVIEW, TNT_EXPLOSION_PREVIEW_MODE, - PLAYER_TRACER, - PLAYER_TRACER_COLOR, PROJECTILE_LANDING_PREDICTION ); } @@ -120,14 +116,6 @@ private static ConfigOptionList createTntExplosionPreviewMode() { return createConfig(new ConfigOptionList("tntExplosionPreviewMode", TntExplosionPreviewMode.FULL)); } - private static ConfigBoolean createPlayerTracer() { - return createConfig(new ConfigBoolean("playerTracer", false)); - } - - private static ConfigColor createPlayerTracerColor() { - return createConfig(new ConfigColor("playerTracerColor", "#FFFFFFFF")); - } - private static ConfigBoolean createProjectileLandingPrediction() { return createConfig(new ConfigBoolean("projectileLandingPrediction", false)); } diff --git a/src/main/java/com/listmore/render/PlayerTracerHudRenderer.java b/src/main/java/com/listmore/render/PlayerTracerHudRenderer.java deleted file mode 100644 index 9701871..0000000 --- a/src/main/java/com/listmore/render/PlayerTracerHudRenderer.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.listmore.render; - -import com.listmore.ListMore; -import com.listmore.config.ListMoreConfigs; - -import fi.dy.masa.malilib.interfaces.IRenderer; -//#if MC >= 1.21.11 -//$$ import fi.dy.masa.malilib.render.GuiContext; -//#else -import net.minecraft.client.gui.GuiGraphics; -//#endif -import fi.dy.masa.malilib.render.RenderUtils; - -import net.minecraft.client.Minecraft; -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.Vec3; - -public class PlayerTracerHudRenderer implements IRenderer { - private static final PlayerTracerHudRenderer INSTANCE = new PlayerTracerHudRenderer(); - private static final int LINE_THICKNESS = 1; - - private PlayerTracerHudRenderer() { - } - - public static PlayerTracerHudRenderer getInstance() { - return INSTANCE; - } - - //#if MC >= 26.1 - //$$ @Override - //$$ public void onExtractGuiOverlayPost(GuiContext ctx, float partialTicks, ProfilerFiller profiler) { - //$$ render(ctx, partialTicks); - //$$ } - //#elseif MC >= 1.21.11 - //$$ @Override - //$$ public void onRenderGameOverlayPostAdvanced(GuiContext ctx, float partialTicks, ProfilerFiller profiler) { - //$$ render(ctx, partialTicks); - //$$ } - //#else - @Override - public void onRenderGameOverlayPostAdvanced(GuiGraphics ctx, float partialTicks, ProfilerFiller profiler, Minecraft client) { - render(ctx, partialTicks); - } - //#endif - - private static void render( - //#if MC >= 1.21.11 - //$$ GuiContext ctx, - //#else - GuiGraphics ctx, - //#endif - float partialTicks) { - Minecraft client = Minecraft.getInstance(); - - if (client.player == null || client.level == null || - //#if MC >= 26.2 - //$$ client.gui.screen() != null || - //#else - client.screen != null || - //#endif - !ListMoreConfigs.Generic.PLAYER_TRACER.getBooleanValue()) { - return; - } - - int guiWidth = client.getWindow().getGuiScaledWidth(); - int guiHeight = client.getWindow().getGuiScaledHeight(); - float physicalPixelScale = guiWidth / (float) client.getWindow().getWidth(); - float startX = guiWidth * 0.5F; - float startY = 0.0F; - int color = ListMore.getPlayerTracerColorArgb(); - - for (Player player : client.level.players()) { - if (!ListMore.shouldRenderPlayerTracer(player)) { - continue; - } - - // 将玩家碰撞箱顶部中心投影到屏幕坐标 - ProjectedPoint target = projectBoundingBoxTopCenter(player, partialTicks, guiWidth, guiHeight); - if (target == null) { - continue; - } - if (target.x < 0 || target.x > guiWidth || target.y < 0 || target.y > guiHeight) { - continue; - } - - drawLine(ctx, startX, startY, target.x, target.y, color, physicalPixelScale); - } - } - - private static ProjectedPoint projectBoundingBoxTopCenter(Player player, float partialTicks, - int guiWidth, int guiHeight) { - Vec3 basePos = player.getPosition(partialTicks); - double halfWidth = player.getBbWidth() * 0.5D + 0.05D; - double height = player.getBbHeight() + 0.05D; - - ProjectedPoint center = projectPoint(basePos.x, basePos.y + height, basePos.z, guiWidth, guiHeight); - if (center != null) { - return center; - } - - Vec3[] candidates = new Vec3[]{ - new Vec3(basePos.x - halfWidth, basePos.y + height, basePos.z - halfWidth), - new Vec3(basePos.x - halfWidth, basePos.y + height, basePos.z + halfWidth), - new Vec3(basePos.x + halfWidth, basePos.y + height, basePos.z - halfWidth), - new Vec3(basePos.x + halfWidth, basePos.y + height, basePos.z + halfWidth) - }; - - ProjectedPoint best = null; - for (Vec3 candidate : candidates) { - ProjectedPoint projected = projectPoint(candidate.x, candidate.y, candidate.z, guiWidth, guiHeight); - if (projected == null) { - continue; - } - if (best == null || projected.y < best.y) { - best = projected; - } - } - - return best; - } - - private static ProjectedPoint projectPoint(double x, double y, double z, int guiWidth, int guiHeight) { - Minecraft client = Minecraft.getInstance(); - //projectPointToScreen返回NDC坐标 - Vec3 screenPos = client.gameRenderer.projectPointToScreen(new Vec3(x, y, z)); - - if (!Double.isFinite(screenPos.x) || !Double.isFinite(screenPos.y) || !Double.isFinite(screenPos.z)) { - return null; - } - if (screenPos.z < 0.0D || screenPos.z > 1.0D) { - return null; - } - - float scaledX = (float) ((screenPos.x * 0.5D + 0.5D) * guiWidth); - float scaledY = (float) ((1.0D - (screenPos.y * 0.5D + 0.5D)) * guiHeight); - return new ProjectedPoint(scaledX, scaledY); - } - - private static void drawLine( - //#if MC >= 1.21.11 - //$$ GuiContext ctx, - //#else - GuiGraphics ctx, - //#endif - float startX, float startY, float endX, float endY, int color, float physicalPixelScale) { - float pixelStartX = startX / physicalPixelScale; - float pixelStartY = startY / physicalPixelScale; - float pixelEndX = endX / physicalPixelScale; - float pixelEndY = endY / physicalPixelScale; - float dx = pixelEndX - pixelStartX; - float dy = pixelEndY - pixelStartY; - int steps = Math.max(1, (int) Math.ceil(Math.max(Math.abs(dx), Math.abs(dy)))); - - for (int i = 0; i <= steps; i++) { - float progress = (float) i / (float) steps; - int x = Math.round(pixelStartX + dx * progress); - int y = Math.round(pixelStartY + dy * progress); - RenderUtils.drawRect(ctx, x, y, LINE_THICKNESS, LINE_THICKNESS, color, physicalPixelScale); - } - } - - private record ProjectedPoint(float x, float y) { - } -} diff --git a/src/main/java/com/listmore/utils/ScreenRenderUtils.java b/src/main/java/com/listmore/utils/ScreenRenderUtils.java new file mode 100644 index 0000000..0399f34 --- /dev/null +++ b/src/main/java/com/listmore/utils/ScreenRenderUtils.java @@ -0,0 +1,122 @@ +package com.listmore.utils; + +import fi.dy.masa.malilib.render.RenderUtils; + +//#if MC >= 1.21.11 +//$$ import fi.dy.masa.malilib.render.GuiContext; +//#else +import net.minecraft.client.gui.GuiGraphics; +//#endif + +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +/** TODO:该类暂时没有具体用处,只是抽离出来的一个工具类。 (-玩家追踪线) + * 屏幕渲染相关的通用工具。 + * projectWorldPoint() 用于将任意世界坐标投影到 GUI 坐标。 + * projectBoundingBoxTopCenter() 用于将实体碰撞箱顶部中心投影到 GUI 坐标。 + * drawLine() 用于在 GUI 层绘制两个屏幕坐标之间的线段。 + */ +public final class ScreenRenderUtils { + private static final int LINE_THICKNESS = 1; + + private ScreenRenderUtils() { + } + + /** + * @param worldPosition 世界空间坐标 + * @return 投影后的 GUI 坐标;不可见或投影无效时返回 null + */ + public static ProjectedPoint projectWorldPoint(Vec3 worldPosition) { + Minecraft client = Minecraft.getInstance(); + Vec3 screenPos = client.gameRenderer.projectPointToScreen(worldPosition); + + if (!Double.isFinite(screenPos.x) || !Double.isFinite(screenPos.y) || !Double.isFinite(screenPos.z)) { + return null; + } + if (screenPos.z < 0.0D || screenPos.z > 1.0D) { + return null; + } + + int guiWidth = client.getWindow().getGuiScaledWidth(); + int guiHeight = client.getWindow().getGuiScaledHeight(); + float scaledX = (float) ((screenPos.x * 0.5D + 0.5D) * guiWidth); + float scaledY = (float) ((1.0D - (screenPos.y * 0.5D + 0.5D)) * guiHeight); + return new ProjectedPoint(scaledX, scaledY); + } + + /** + * 将实体碰撞箱顶部中心投影到当前窗口的 GUI 缩放坐标。 + * 如果顶部中心无法投影,则从四个顶部角点中选择屏幕 Y 坐标最小的可见点。 + * + * @param entity 要投影的实体 + * @param partialTicks 当前渲染帧的部分 tick,用于插值实体位置 + * @return 投影后的 GUI 坐标;所有候选点均不可见时返回 null + */ + public static ProjectedPoint projectBoundingBoxTopCenter(Entity entity, float partialTicks) { + Vec3 basePos = entity.getPosition(partialTicks); + double halfWidth = entity.getBbWidth() * 0.5D + 0.05D; + double height = entity.getBbHeight() + 0.05D; + + ProjectedPoint center = projectWorldPoint(new Vec3(basePos.x, basePos.y + height, basePos.z)); + if (center != null) { + return center; + } + + Vec3[] candidates = new Vec3[]{ + new Vec3(basePos.x - halfWidth, basePos.y + height, basePos.z - halfWidth), + new Vec3(basePos.x - halfWidth, basePos.y + height, basePos.z + halfWidth), + new Vec3(basePos.x + halfWidth, basePos.y + height, basePos.z - halfWidth), + new Vec3(basePos.x + halfWidth, basePos.y + height, basePos.z + halfWidth) + }; + + ProjectedPoint best = null; + for (Vec3 candidate : candidates) { + ProjectedPoint projected = projectWorldPoint(candidate); + if (projected != null && (best == null || projected.y() < best.y())) { + best = projected; + } + } + + return best; + } + + /** + * 绘制一条只有描边的 HUD 线段。 + * + * @param context 当前版本的 GUI 绘制上下文 + * @param startX 线段起点相对于 GUI 缩放坐标的 X 坐标 + * @param startY 线段起点相对于 GUI 缩放坐标的 Y 坐标 + * @param endX 线段终点相对于 GUI 缩放坐标的 X 坐标 + * @param endY 线段终点相对于 GUI 缩放坐标的 Y 坐标 + * @param color 线段颜色,使用 ARGB 格式 + * @param physicalPixelScale GUI 缩放像素与物理像素的比例 + */ + public static void drawLine( + //#if MC >= 1.21.11 + //$$ GuiContext context, + //#else + GuiGraphics context, + //#endif + float startX, float startY, float endX, float endY, int color, float physicalPixelScale) { + float pixelStartX = startX / physicalPixelScale; + float pixelStartY = startY / physicalPixelScale; + float pixelEndX = endX / physicalPixelScale; + float pixelEndY = endY / physicalPixelScale; + float dx = pixelEndX - pixelStartX; + float dy = pixelEndY - pixelStartY; + int steps = Math.max(1, (int) Math.ceil(Math.max(Math.abs(dx), Math.abs(dy)))); + + for (int i = 0; i <= steps; i++) { + float progress = (float) i / (float) steps; + int x = Math.round(pixelStartX + dx * progress); + int y = Math.round(pixelStartY + dy * progress); + RenderUtils.drawRect(context, x, y, LINE_THICKNESS, LINE_THICKNESS, color, physicalPixelScale); + } + } + + /** 世界坐标经过投影后得到的 GUI 缩放坐标。 */ + public record ProjectedPoint(float x, float y) { + } +} diff --git a/src/main/resources/assets/listmore/lang/en_us.json b/src/main/resources/assets/listmore/lang/en_us.json index d7f6a7d..bad3f23 100644 --- a/src/main/resources/assets/listmore/lang/en_us.json +++ b/src/main/resources/assets/listmore/lang/en_us.json @@ -4,12 +4,6 @@ "listmore.hotkeys.category.generic": "General Hotkeys", "listmore.gui.tab.all": "All", "listmore.gui.tab.generic": "General", - "listmore.config.generic.name.playerTracer": "Player Tracers", - "listmore.config.generic.prettyName.playerTracer": "Player Tracers", - "listmore.config.generic.comment.playerTracer": "Draw lines leading to nearby players", - "listmore.config.generic.name.playerTracerColor": "Player Tracer Color", - "listmore.config.generic.prettyName.playerTracerColor": "Player Tracer Color", - "listmore.config.generic.comment.playerTracerColor": "Set the color of tracer lines", "listmore.config.generic.name.projectileLandingPrediction": "Projectile Landing Prediction", "listmore.config.generic.prettyName.projectileLandingPrediction": "Projectile Landing Prediction", "listmore.config.generic.comment.projectileLandingPrediction": "Show the predicted landing point for supported projectiles", diff --git a/src/main/resources/assets/listmore/lang/zh_cn.json b/src/main/resources/assets/listmore/lang/zh_cn.json index eae161b..a4aa27e 100644 --- a/src/main/resources/assets/listmore/lang/zh_cn.json +++ b/src/main/resources/assets/listmore/lang/zh_cn.json @@ -4,12 +4,6 @@ "listmore.hotkeys.category.generic": "通用快捷键", "listmore.gui.tab.all": "全部", "listmore.gui.tab.generic": "通用", - "listmore.config.generic.name.playerTracer": "玩家追踪线", - "listmore.config.generic.prettyName.playerTracer": "玩家追踪线", - "listmore.config.generic.comment.playerTracer": "连线到附近玩家", - "listmore.config.generic.name.playerTracerColor": "玩家追踪线-颜色", - "listmore.config.generic.prettyName.playerTracerColor": "玩家追踪线颜色", - "listmore.config.generic.comment.playerTracerColor": "设置追踪线的颜色", "listmore.config.generic.name.projectileLandingPrediction": "投射物落点预测", "listmore.config.generic.prettyName.projectileLandingPrediction": "投射物落点预测", "listmore.config.generic.comment.projectileLandingPrediction": "显示支持投射物的预测落点",