XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

MyDimension

【Java】我的维度模组

公开
关注 0 Fork 0 Star 0
UTF-8
package com.xfestudio.mydimension.client.builder;

import com.mojang.blaze3d.platform.Window;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;

import java.util.List;

/** Compact mode/progress HUD plus the Alt blueprint action wheel. */
public final class BuilderHudRenderer {
    private BuilderHudRenderer() {
    }

    public static void render(GuiGraphics graphics, Window window,
                              BlueprintAltActionController controller) {
        Minecraft minecraft = Minecraft.getInstance();
        boolean holdingScepter = BuilderClientServices.isHoldingRealmwright(minecraft);
        boolean blueprintWorkflow = BuilderPreviewState.get().hasBlueprintWheelActions();
        controller.updateVisibility(Screen.hasAltDown(), minecraft.screen == null
                && holdingScepter && blueprintWorkflow);
        if (minecraft.options.hideGui || !holdingScepter) {
            return;
        }
        BuilderClientSnapshot snapshot = BuilderClientServices.snapshot();
        int modeColor = snapshot.mode() == com.xfestudio.mydimension.builder.BuilderMode.BUILD
                ? 0xFF39D46A : 0xFFF04B45;
        Component mode = Component.translatable(snapshot.mode()
                == com.xfestudio.mydimension.builder.BuilderMode.BUILD
                ? "hud.mydimension.realmwright.build" : "hud.mydimension.realmwright.demolish");
        graphics.fill(7, 7, 15 + minecraft.font.width(mode), 23, 0xA0101620);
        graphics.fill(7, 7, 10, 23, modeColor);
        graphics.drawString(minecraft.font, mode, 13, 11, 0xFFFFFFFF, false);

        if (snapshot.totalBlocks() > 0) {
            String progress = snapshot.completedBlocks() + " / " + snapshot.totalBlocks();
            graphics.drawString(minecraft.font, progress, 8, 27, 0xFFE7EDF7, true);
        }

        if (controller.phase() != BlueprintAltActionController.Phase.CLOSED && blueprintWorkflow) {
            renderActionWheel(graphics, window, controller);
        }
    }

    private static void renderActionWheel(GuiGraphics graphics, Window window,
                                          BlueprintAltActionController controller) {
        Minecraft minecraft = Minecraft.getInstance();
        int screenWidth = window.getGuiScaledWidth();
        int screenHeight = window.getGuiScaledHeight();
        int centerX = screenWidth / 2;
        int minimumDimension = Math.min(screenWidth, screenHeight);
        int outerRadius = Mth.clamp(minimumDimension / 3, 44, 76);
        outerRadius = Math.min(outerRadius, Math.max(32, (screenHeight - 24) / 2));
        int innerRadius = Mth.clamp(Mth.floor(outerRadius * 0.46F), 22, 35);
        int crosshairClearance = Math.min(26, Math.max(16, innerRadius - 7));
        int centerY = Mth.clamp(screenHeight / 2 + crosshairClearance,
                outerRadius + 7, Math.max(outerRadius + 7, screenHeight - outerRadius - 7));
        List<BlueprintAltActionController.Action> actions = controller.actions();
        BlueprintAltActionController.Action active = controller.phase()
                == BlueprintAltActionController.Phase.ADJUSTING
                ? controller.adjusting() : controller.highlighted();
        int selectedIndex = Math.max(0, actions.indexOf(active));
        boolean adjusting = controller.phase() == BlueprintAltActionController.Phase.ADJUSTING;

        // Rift-like outer aura and an enlarged selected wedge sit behind the opaque wheel sectors.
        BuilderRadialWheelPainter.drawRing(graphics, centerX, centerY, outerRadius + 1,
                outerRadius + 4, 0x284FE6D2);
        BuilderRadialWheelPainter.drawRing(graphics, centerX, centerY, outerRadius - 1,
                outerRadius + 1, 0x7A8A61DC);
        BuilderRadialWheelPainter.drawSector(graphics, centerX, centerY, innerRadius - 2,
                outerRadius + 3, actions.size(), selectedIndex, adjusting ? 0x664DE7D1 : 0x5A9469EF);
        BuilderRadialWheelPainter.drawSectors(graphics, centerX, centerY, innerRadius, outerRadius,
                actions.size(), index -> {
                    if (index == selectedIndex) return adjusting ? 0xE03C7F91 : 0xDF594AA0;
                    return (index & 1) == 0 ? 0xBD21152F : 0xBD29183A;
                });
        BuilderRadialWheelPainter.drawSector(graphics, centerX, centerY, innerRadius + 2,
                outerRadius - 2, actions.size(), selectedIndex, adjusting ? 0x6B61E9D4 : 0x5F9C72F2);
        BuilderRadialWheelPainter.drawRing(graphics, centerX, centerY, innerRadius - 1,
                innerRadius + 1, adjusting ? 0xB855E4D1 : 0xA68D69E8);

        int labelRadius = (innerRadius + outerRadius) / 2;
        int pulse = 1 + Mth.floor((Math.sin(System.nanoTime() / 180_000_000.0D) + 1.0D) * 0.75D);
        for (int index = 0; index < actions.size(); index++) {
            double angle = -Math.PI / 2.0D + (Math.PI * 2.0D * index / actions.size());
            boolean selected = index == selectedIndex;
            int radialOffset = selected ? 3 : 0;
            int x = centerX + Mth.floor(Math.cos(angle) * (labelRadius + radialOffset));
            int y = centerY + Mth.floor(Math.sin(angle) * (labelRadius + radialOffset));
            int badgeRadius = selected ? 11 + pulse : 8;
            if (selected) {
                BuilderRadialWheelPainter.drawDisc(graphics, x, y, badgeRadius + 4,
                        adjusting ? 0x4559E6D2 : 0x42966EF0);
            }
            BuilderRadialWheelPainter.drawDisc(graphics, x, y, badgeRadius,
                    selected ? 0xE0192036 : 0xC0181324);
            BuilderRadialWheelPainter.drawRing(graphics, x, y, badgeRadius - 1, badgeRadius + 1,
                    selected ? (adjusting ? 0xFF67E9D5 : 0xFFC09AFF) : 0xA35D5077);
            BuilderWheelIconPainter.draw(graphics, actions.get(index), x, y,
                    selected ? 0.90F : 0.72F,
                    selected ? 0xFFFFFFFF : 0xFFD2CBE2,
                    selected ? (adjusting ? 0xFF6EF5DE : 0xFFD2AFFF) : 0xFFA58EC5);
        }

        // No action labels: the centre repeats the active pictogram at a larger scale.  In
        // adjustment mode, opposing chevrons communicate that the wheel changes its value.
        BuilderRadialWheelPainter.drawDisc(graphics, centerX, centerY, innerRadius - 4, 0xB0181027);
        BuilderRadialWheelPainter.drawRing(graphics, centerX, centerY, innerRadius - 5,
                innerRadius - 3, adjusting ? 0xB861E9D4 : 0x9A8D69E8);
        BuilderWheelIconPainter.draw(graphics, active, centerX, centerY - 2, 1.12F,
                0xFFFFFFFF, adjusting ? 0xFF67E9D5 : 0xFFC9A8FF);
        if (adjusting) {
            drawChevron(graphics, centerX - innerRadius + 7, centerY - 2, false, 0xFF73EAD7);
            drawChevron(graphics, centerX + innerRadius - 7, centerY - 2, true, 0xFF73EAD7);
        }

        // One dot per action preserves position feedback without textual page numbers.
        int indicatorY = centerY + innerRadius - 9;
        int indicatorSpacing = 3;
        int indicatorStart = centerX - (actions.size() - 1) * indicatorSpacing / 2;
        for (int index = 0; index < actions.size(); index++) {
            int dotX = indicatorStart + index * indicatorSpacing;
            int dotRadius = index == selectedIndex ? 1 : 0;
            BuilderRadialWheelPainter.drawDisc(graphics, dotX, indicatorY, dotRadius,
                    index == selectedIndex
                            ? (adjusting ? 0xFF65E9D5 : 0xFFC5A1FF)
                            : 0x8E78688E);
        }

        // Keep the sectors pictogram-only, but identify the one focused action in a compact
        // tooltip outside the wheel.  This is intentionally not drawn in the centre: the icon
        // and adjustment chevrons remain readable, and the crosshair area stays unobstructed.
        renderSelectedActionHint(graphics, minecraft, screenWidth, screenHeight, centerX, centerY,
                outerRadius, active, adjusting);
    }

    private static void renderSelectedActionHint(GuiGraphics graphics, Minecraft minecraft,
                                                  int screenWidth, int screenHeight,
                                                  int centerX, int centerY, int outerRadius,
                                                  BlueprintAltActionController.Action active,
                                                  boolean adjusting) {
        Component label = Component.translatable(active.translationKey());
        int textWidth = minecraft.font.width(label);
        int panelWidth = Math.min(screenWidth - 12, Math.max(72, textWidth + 24));
        int panelHeight = 17;
        int preferredTop = centerY + outerRadius + 8;
        int top = preferredTop + panelHeight <= screenHeight - 4
                ? preferredTop
                : centerY - outerRadius - panelHeight - 8;
        int left = Mth.clamp(centerX - panelWidth / 2, 6, Math.max(6, screenWidth - panelWidth - 6));
        int right = left + panelWidth;

        int border = adjusting ? 0xD85DE6D2 : 0xD2A77BF2;
        int innerAccent = adjusting ? 0x6056D9C8 : 0x606D48A1;
        graphics.fill(left + 3, top, right - 3, top + panelHeight, 0xC8140E20);
        graphics.fill(left + 1, top + 3, right - 1, top + panelHeight - 3, 0xC8140E20);
        graphics.fill(left + 4, top, right - 4, top + 1, border);
        graphics.fill(left + 4, top + panelHeight - 1, right - 4, top + panelHeight, border);
        graphics.fill(left, top + 4, left + 1, top + panelHeight - 4, border);
        graphics.fill(right - 1, top + 4, right, top + panelHeight - 4, border);
        graphics.fill(left + 5, top + 2, left + 7, top + panelHeight - 2, innerAccent);
        graphics.fill(right - 7, top + 2, right - 5, top + panelHeight - 2, innerAccent);

        graphics.drawCenteredString(minecraft.font, label, left + panelWidth / 2, top + 5,
                adjusting ? 0xFFB6FFF1 : 0xFFF1E8FF);
    }

    private static void drawChevron(GuiGraphics graphics, int x, int y, boolean pointsRight,
                                    int color) {
        int direction = pointsRight ? 1 : -1;
        for (int offset = -2; offset <= 2; offset++) {
            int horizontal = x + direction * (2 - Math.abs(offset));
            graphics.fill(horizontal, y + offset, horizontal + 1, y + offset + 1, color);
        }
    }
}