Часть функционала WayPanel & WayCommand | Expensive 3.1 Ready

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
23 Сен 2024
Сообщения
301
Реакции
0
Выберите загрузчик игры
  1. Прочие моды
Дароу yougame
Вот сливаю вам WayPanel и WayCommand
ss way command: прикреплён ниже
ss
way panel: прикреплён ниже
-------------------------------------------
Также скажу: утилки с литки (ноад), и другая система шрифтов
-------------------------------------------
Тутор:
1. Создаём класс в папке с RCTComand и т.д

WayCommand:
Expand Collapse Copy
package client.main.command.impl.feature;

import client.events.EventRenderer2D;
import client.main.Vesence;
import client.main.command.*;
import client.main.command.impl.CommandException;
import client.main.module.impl.misc.Theme;
import client.util.client.IMinecraft;
import client.util.display.render.ColorUtil;
import client.util.display.render.RenderUtil;
import client.util.display.render.Round;
import client.util.display.render.font.Fonts;
import client.util.player.projections.ProjectionUtil;
import com.google.common.eventbus.Subscribe;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.vector.Vector2f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraft.util.text.TextFormatting;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class WayCommand implements Command, CommandWithAdvice, MultiNamedCommand, IMinecraft {
    final Prefix prefix;
    final Logger logger;
    private final Map<String, Vector3i> waysMap = new LinkedHashMap<>();

    public WayCommand(Prefix prefix, Logger logger) {
        this.prefix = prefix;
        this.logger = logger;
        Vesence.getInstance().getEventBus().register(this);
    }

    @Override
    public void execute(Parameters parameters) {
        String commandType = parameters.asString(0).orElse("");

        switch (commandType) {
            case "add" -> addGPS(parameters);
            case "remove" -> removeGPS(parameters);
            case "clear" -> {
                waysMap.clear();
                logger.log("Все пути были удалены!");
            }
            case "list" -> {
                logger.log("Список путей:");

                for (String s : waysMap.keySet()) {
                    logger.log(s + " " + waysMap.get(s));
                }
            }
            default ->
                    throw new CommandException(TextFormatting.RED + "Укажите тип команды:" + TextFormatting.GRAY + " add, remove, clear");
        }
    }

    private void addGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));
        int x = param.asInt(2)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите первую координату!"));

        int y = param.asInt(3)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите вторую координату!"));

        int z = param.asInt(4)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите третью координату!"));

        Vector3i vec = new Vector3i(x, y, z);
        waysMap.put(name, vec);
        logger.log("Путь " + name + " был добавлен!");
    }

    private void removeGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));

        waysMap.remove(name);
        logger.log("Путь " + name + " был удалён!");
    }

    @Override
    public String name() {
        return "way";
    }

    @Override
    public String description() {
        return "Позволяет работать с координатами путей";
    }

    @Override
    public List<String> adviceMessage() {
        String commandPrefix = prefix.get();
        return List.of(commandPrefix + "way add <имя, x, y, z> - Проложить путь к WayPoint'у",
                commandPrefix + "way remove <имя> - Удалить WayPoint",
                commandPrefix + "way list - Список WayPoint'ов",
                commandPrefix + "way clear - Очистить список WayPoint'ов",
                "Пример: " + TextFormatting.RED + commandPrefix + "way add Имя КоординатаX КоординатаY КоординатаZ"
        );
    }
    Vector3i vec3i;
    Vector3d vec3d;
    Vector2f vec2f;
    int distance;

    @Subscribe
    private void onDisplay(EventRenderer2D e) {

        if (waysMap.isEmpty()) {
            return;
        }
        for (String name : waysMap.keySet()) {
            vec3i = waysMap.get(name);

            vec3d = new Vector3d(
                    vec3i.getX() + 0.5,
                    vec3i.getY() + 0.5,
                    vec3i.getZ() + 0.5
            );

            vec2f = ProjectionUtil.project(vec3d.x, vec3d.y, vec3d.z);
            distance = (int) Minecraft.getInstance().player.getPositionVec().distanceTo(vec3d);
            String text = name + ": До точки: " + distance + "M";

            float textWith = client.util.screenUtil.normalFont.Fonts.SF_REGULAR.getWidth(text, 7.5f);
            float fontHeight = Fonts.sf_medium.getHeight(8);

            float posX = vec2f.x - textWith / 2;
            float posY = vec2f.y - fontHeight / 2;
            float posY2 = vec2f.y - fontHeight / 10;
            float padding = 2;

            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding + 17, posY - padding - 0.5f, padding + textWith + padding + 3, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding, posY - padding - 0.5f, Fonts.iconDANQ.getWidth("B", 8) + 8, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            Fonts.iconDANQ.drawText(e.getMatrixStack(), "B", posX - padding + 3.75f, posY2 - 2, Theme.ClientColor(), 7);
            client.util.screenUtil.normalFont.Fonts.SF_REGULAR.draw(e.getMatrixStack(), text, posX - padding + 20, posY2 - 3f, -1, 7.5f);
        }
    }

    @Override
    public List<String> aliases() {
        return List.of("w");
    }
}
2. Создаём в ui папку WayPanel
3.Создаём класс WayPanel в этой папке:

WayPoint:
Expand Collapse Copy
package client.display.waypointScreen;

import client.util.client.IMinecraft;
import client.util.client.SoundPlayer;
import client.util.display.render.*;
import client.util.screenUtil.normalFont.Fonts;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import org.lwjgl.glfw.GLFW;
import ru.hogoshi.Animation;
import ru.hogoshi.util.Easings;

import java.util.ArrayList;
import java.util.List;

public class WayPoint extends Screen implements IMinecraft {
    private double targetScrollOffset = 0;
    private double smoothScrollOffset = 0;
    private boolean escPressed = false;
    private TextField textFieldName;
    private TextField textFieldCoords;
    private int scrollOffset = 0;
    private int maxScroll = 0;
    private CustomButton addPointButton;
    @Getter
    private static Animation animation = new Animation();
    private final List<WaypointEntry> waypoints = new ArrayList<>();

    public WayPoint() {
        super(new StringTextComponent("Waypoint GUI"));
    }

    @Override
    protected void init() {
        SoundPlayer.playSound("guiopen.wav", 0.1f);

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.setValue(0);
        animation.animate(1, 0.5, Easings.QUAD_OUT);

        int rectWidth = 300;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2;
        int rectY = (screenHeight - rectHeight) / 2 - 40;

        textFieldName = new TextField(rectX + 25, rectY + rectHeight / 2 - 10, rectWidth - 50, 20);
        textFieldName.setFocused(false);

        textFieldCoords = new TextField(rectX + 25, rectY + rectHeight / 2 + 35, rectWidth - 50, 20);
        textFieldCoords.setFocused(false);

        int buttonWidth = 100;
        int buttonHeight = 17;
        int buttonX = rectX + (rectWidth - buttonWidth) / 2;
        int buttonY = rectY + rectHeight / 2 + 70;

        addPointButton = this.addButton(new CustomButton(buttonX + 50,  buttonY, buttonWidth, buttonHeight, "Установить метку", button -> {
            onAddPoint();
        }));
    }

    private void onAddPoint() {
        String name = textFieldName.getText().trim();
        String coords = textFieldCoords.getText().trim();

        if (name.isEmpty() || coords.isEmpty()) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String[] parts = coords.split("\\s+");
        if (parts.length < 3) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String x = parts[0];
        String y = parts[1];
        String z = parts[2];

        waypoints.add(new WaypointEntry(name, x, y, z));
        mc.player.sendChatMessage(".way add " + name + " " + x + " " + y + " " + z);
        int totalHeight = waypoints.size() * 30;
        int listHeight = 150;
        maxScroll = Math.max(0, totalHeight - listHeight);
    }

    @Override
    public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.update();

        RenderUtil.drawRoundedRect(0, 0, screenWidth, screenHeight, 0, ColorUtil.rgba(0, 0, 0, (int) (155 * animation.getValue())));

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        RenderUtil.Rounded.smooth(matrixStack, rectX, rectY, rectWidth, rectHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, rectX, rectY, rectWidth, rectHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Управление метками", rectX + rectWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Название метки", rectX + rectWidth / 2 - 3, rectY + 10, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldName.render(matrixStack, mouseX, mouseY, partialTicks);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Координаты метки", rectX + rectWidth / 2 + 3, rectY + 55, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldCoords.render(matrixStack, mouseX, mouseY, partialTicks);

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;
        smoothScrollOffset += (targetScrollOffset - smoothScrollOffset) * 0.1;
        scrollOffset = (int) smoothScrollOffset;

        RenderUtil.Rounded.smooth(matrixStack, listX, listY, listWidth, listHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, listX, listY, listWidth, listHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Сохранённые метки", listX + listWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        int offsetY = listY + 10 - scrollOffset;
        int lineHeight = 30;
        int visibleCount = listHeight / lineHeight;

        Scissor.push();
        Scissor.setFromComponentCoordinates(listX, listY, listWidth, listHeight);

        for (int i = 0; i < waypoints.size(); i++) {
            WaypointEntry entry = waypoints.get(i);

            int entryTop = offsetY;
            int entryBottom = offsetY + lineHeight;

            if (entryBottom >= listY && entryTop <= listY + listHeight) {
                RenderUtil.Rounded.smooth(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, ColorUtil.rgba(20, 20, 20, (int) (255 * animation.getValue())), Round.of(4));
                RenderUtil.Rounded.roundedOutline(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, 1, ColorUtil.rgba(40, 40, 40, (int) (255 * animation.getValue())), Round.of(4));
                Fonts.SF_MEDIUM.draw(matrixStack, "§f" + entry.name, listX + 10, offsetY, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
                Fonts.SF_MEDIUM.draw(matrixStack, "X: " + entry.x +" Y: " + entry.y + " Z: " + entry.z, listX + 10, offsetY + 10, ColorUtil.rgba(125, 125, 125, (int) (255 * animation.getValue())), 7.5f);
            }

            offsetY += lineHeight;
        }

        Scissor.pop();


        super.render(matrixStack, mouseX, mouseY, partialTicks);
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        boolean clickedName = textFieldName.mouseClicked(mouseX, mouseY, button);
        boolean clickedCoords = textFieldCoords.mouseClicked(mouseX, mouseY, button);

        if (clickedName) {
            textFieldName.setFocused(true);
            textFieldCoords.setFocused(false);
            return true;
        }
        if (clickedCoords) {
            textFieldCoords.setFocused(true);
            textFieldName.setFocused(false);
            return true;
        }

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;

        if (button == 1) {
            int offsetY = listY + 10 - scrollOffset;
            int lineHeight = 30;

            for (int i = 0; i < waypoints.size(); i++) {
                int entryTop = offsetY;
                int entryBottom = offsetY + lineHeight;

                if (mouseX >= listX + 6 && mouseX <= listX + listWidth - 6 &&
                        mouseY >= entryTop && mouseY <= entryBottom) {
                    WaypointEntry removed = waypoints.remove(i);

                    mc.player.sendChatMessage(".way remove " + removed.name);

                    int totalHeight = waypoints.size() * 30;
                    maxScroll = Math.max(0, totalHeight - listHeight);

                    targetScrollOffset = Math.min(targetScrollOffset, maxScroll);
                    smoothScrollOffset = Math.min(smoothScrollOffset, maxScroll);
                    scrollOffset = (int) smoothScrollOffset;

                    return true;
                }

                offsetY += lineHeight;
            }
        }

        textFieldName.setFocused(false);
        textFieldCoords.setFocused(false);

        return super.mouseClicked(mouseX, mouseY, button);
    }
    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        int listWidth = 180;
        int listHeight = 140;
        int listX = (mc.getMainWindow().getScaledWidth() - 200) / 2 + 50 - listWidth - 20;
        int listY = (mc.getMainWindow().getScaledHeight() - 150) / 2;

        if (mouseX >= listX && mouseX <= listX + listWidth &&
                mouseY >= listY && mouseY <= listY + listHeight) {

            int totalHeight = waypoints.size() * 30;
            int maxScrollAmount = Math.max(0, totalHeight - listHeight);

            targetScrollOffset -= delta * 30;
            targetScrollOffset = Math.max(0, Math.min(targetScrollOffset, maxScrollAmount));

            return true;
        }

        return super.mouseScrolled(mouseX, mouseY, delta);
    }


    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        if (keyCode == GLFW.GLFW_KEY_W ||
                keyCode == GLFW.GLFW_KEY_A ||
                keyCode == GLFW.GLFW_KEY_S ||
                keyCode == GLFW.GLFW_KEY_D ||
                keyCode == GLFW.GLFW_KEY_SPACE ||
                keyCode == GLFW.GLFW_KEY_LEFT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_LEFT_CONTROL ||
                keyCode == GLFW.GLFW_KEY_RIGHT_CONTROL) {
            return true;
        }

        if (textFieldName.isFocused() && textFieldName.keyPressed(keyCode, scanCode, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.keyPressed(keyCode, scanCode, modifiers)) return true;

        if (keyCode == GLFW.GLFW_KEY_ESCAPE && !escPressed) {
            super.closeScreen();
            animation = animation.animate(0, 0.3, Easings.QUART_OUT);
            GLFW.glfwSetCursor(Minecraft.getInstance().getMainWindow().getHandle(), Cursors.ARROW);
        }

        return super.keyPressed(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean charTyped(char codePoint, int modifiers) {
        if (textFieldName.isFocused() && textFieldName.charTyped(codePoint, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.charTyped(codePoint, modifiers)) return true;

        return super.charTyped(codePoint, modifiers);
    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }


    public static class WaypointEntry {
        public final String name;
        public final String x, y, z;

        public WaypointEntry(String name, String x, String y, String z) {
            this.name = name;
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }

    public class CustomButton extends Button {

        private static final int ARC_RADIUS = 5;
        private static final int TEXT_SIZE = 8;

        public CustomButton(int x, int y, int width, int height, String text, IPressable onPress) {
            super(x, y, width, height, new StringTextComponent(text), onPress);
        }

        @Override
        public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
            int bgColor;
            if (!this.active) {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // неактивная кнопка — темнее
            } else if (this.isHovered()) {
                bgColor = ColorUtil.rgba(35, 35, 35, (int) (255 * animation.getValue())); // при наведении — синий оттенок
            } else {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // обычное состояние — синий темный
            }

            RenderUtil.Rounded.smooth(matrixStack, this.x, this.y, this.width, this.height, bgColor, Round.of(4.5f));
            RenderUtil.Rounded.roundedOutline(matrixStack, this.x, this.y, this.width, this.height, 1, ColorUtil.rgba(45, 45, 45, (int) (255 * animation.getValue())), Round.of(4.5f));

            int textColor = ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue()));
            Fonts.SF_MEDIUM.drawCenter(matrixStack, this.getMessage().getString(), this.x + width / 2, this.y + (this.height / 2) - (TEXT_SIZE / 2) + 0.5f, textColor, TEXT_SIZE);
        }
    }
}
4. Дальше заходим в главный класс клиент, и пишем в начале класса
private WayPoint wayPoint;
5. Дальше в метод clientLoad() добавляем
wayPoint = new WayPoint();
6. После этого в метод onKeyPressed() добавляем
if (key == moduleManager.getWayPanel().openGui.get()) {
Minecraft.getInstance().displayGuiScreen(wayPoint);
}
7.Дальше добавляем функцию
WayPanel:
Expand Collapse Copy
package client.main.module.impl.misc;

import client.main.module.api.Category;
import client.main.module.api.Module;
import client.main.module.api.ModuleRegister;
import client.main.module.settings.implObjects.ActionButtonObject;
import client.main.module.settings.implObjects.BindSetObject;

@ModuleRegister(name = "WayPanel", type = Category.Misc,desc = "test")
public class WayPanel extends Module {
    public BindSetObject openGui = new BindSetObject("Кнопка открытия", -1);
    public WayPanel() {
        addSettings(openGui);
    }
}
Дальше регаем модуль в FunctionRegistry (не буду показывать как, потому что вы не тупые я думаю)
-----------------------------------------------
Теперь разберёмся с WayCommand:
В том же самом главном классе в методе initCommands вставляем эту строку

commands.add(new WayCommand(prefix, logger));
-----------------------------------------------
Ну короче вроде всё нормас вы спастили!!!!!!!

Давайте сразу тему одобрите просто как с ActionButton
 

Вложения

  • 1754674632407.png
    1754674632407.png
    14.8 KB · Просмотры: 513
  • 1754674703023.png
    1754674703023.png
    59.8 KB · Просмотры: 514
Дароу yougame
Вот сливаю вам WayPanel и WayCommand
ss way command: прикреплён ниже
ss
way panel: прикреплён ниже
-------------------------------------------
Также скажу: утилки с литки (ноад), и другая система шрифтов
-------------------------------------------
Тутор:
1. Создаём класс в папке с RCTComand и т.д

WayCommand:
Expand Collapse Copy
package client.main.command.impl.feature;

import client.events.EventRenderer2D;
import client.main.Vesence;
import client.main.command.*;
import client.main.command.impl.CommandException;
import client.main.module.impl.misc.Theme;
import client.util.client.IMinecraft;
import client.util.display.render.ColorUtil;
import client.util.display.render.RenderUtil;
import client.util.display.render.Round;
import client.util.display.render.font.Fonts;
import client.util.player.projections.ProjectionUtil;
import com.google.common.eventbus.Subscribe;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.vector.Vector2f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraft.util.text.TextFormatting;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class WayCommand implements Command, CommandWithAdvice, MultiNamedCommand, IMinecraft {
    final Prefix prefix;
    final Logger logger;
    private final Map<String, Vector3i> waysMap = new LinkedHashMap<>();

    public WayCommand(Prefix prefix, Logger logger) {
        this.prefix = prefix;
        this.logger = logger;
        Vesence.getInstance().getEventBus().register(this);
    }

    @Override
    public void execute(Parameters parameters) {
        String commandType = parameters.asString(0).orElse("");

        switch (commandType) {
            case "add" -> addGPS(parameters);
            case "remove" -> removeGPS(parameters);
            case "clear" -> {
                waysMap.clear();
                logger.log("Все пути были удалены!");
            }
            case "list" -> {
                logger.log("Список путей:");

                for (String s : waysMap.keySet()) {
                    logger.log(s + " " + waysMap.get(s));
                }
            }
            default ->
                    throw new CommandException(TextFormatting.RED + "Укажите тип команды:" + TextFormatting.GRAY + " add, remove, clear");
        }
    }

    private void addGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));
        int x = param.asInt(2)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите первую координату!"));

        int y = param.asInt(3)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите вторую координату!"));

        int z = param.asInt(4)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите третью координату!"));

        Vector3i vec = new Vector3i(x, y, z);
        waysMap.put(name, vec);
        logger.log("Путь " + name + " был добавлен!");
    }

    private void removeGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));

        waysMap.remove(name);
        logger.log("Путь " + name + " был удалён!");
    }

    @Override
    public String name() {
        return "way";
    }

    @Override
    public String description() {
        return "Позволяет работать с координатами путей";
    }

    @Override
    public List<String> adviceMessage() {
        String commandPrefix = prefix.get();
        return List.of(commandPrefix + "way add <имя, x, y, z> - Проложить путь к WayPoint'у",
                commandPrefix + "way remove <имя> - Удалить WayPoint",
                commandPrefix + "way list - Список WayPoint'ов",
                commandPrefix + "way clear - Очистить список WayPoint'ов",
                "Пример: " + TextFormatting.RED + commandPrefix + "way add Имя КоординатаX КоординатаY КоординатаZ"
        );
    }
    Vector3i vec3i;
    Vector3d vec3d;
    Vector2f vec2f;
    int distance;

    @Subscribe
    private void onDisplay(EventRenderer2D e) {

        if (waysMap.isEmpty()) {
            return;
        }
        for (String name : waysMap.keySet()) {
            vec3i = waysMap.get(name);

            vec3d = new Vector3d(
                    vec3i.getX() + 0.5,
                    vec3i.getY() + 0.5,
                    vec3i.getZ() + 0.5
            );

            vec2f = ProjectionUtil.project(vec3d.x, vec3d.y, vec3d.z);
            distance = (int) Minecraft.getInstance().player.getPositionVec().distanceTo(vec3d);
            String text = name + ": До точки: " + distance + "M";

            float textWith = client.util.screenUtil.normalFont.Fonts.SF_REGULAR.getWidth(text, 7.5f);
            float fontHeight = Fonts.sf_medium.getHeight(8);

            float posX = vec2f.x - textWith / 2;
            float posY = vec2f.y - fontHeight / 2;
            float posY2 = vec2f.y - fontHeight / 10;
            float padding = 2;

            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding + 17, posY - padding - 0.5f, padding + textWith + padding + 3, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding, posY - padding - 0.5f, Fonts.iconDANQ.getWidth("B", 8) + 8, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            Fonts.iconDANQ.drawText(e.getMatrixStack(), "B", posX - padding + 3.75f, posY2 - 2, Theme.ClientColor(), 7);
            client.util.screenUtil.normalFont.Fonts.SF_REGULAR.draw(e.getMatrixStack(), text, posX - padding + 20, posY2 - 3f, -1, 7.5f);
        }
    }

    @Override
    public List<String> aliases() {
        return List.of("w");
    }
}
2. Создаём в ui папку WayPanel
3.Создаём класс WayPanel в этой папке:

WayPoint:
Expand Collapse Copy
package client.display.waypointScreen;

import client.util.client.IMinecraft;
import client.util.client.SoundPlayer;
import client.util.display.render.*;
import client.util.screenUtil.normalFont.Fonts;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import org.lwjgl.glfw.GLFW;
import ru.hogoshi.Animation;
import ru.hogoshi.util.Easings;

import java.util.ArrayList;
import java.util.List;

public class WayPoint extends Screen implements IMinecraft {
    private double targetScrollOffset = 0;
    private double smoothScrollOffset = 0;
    private boolean escPressed = false;
    private TextField textFieldName;
    private TextField textFieldCoords;
    private int scrollOffset = 0;
    private int maxScroll = 0;
    private CustomButton addPointButton;
    @Getter
    private static Animation animation = new Animation();
    private final List<WaypointEntry> waypoints = new ArrayList<>();

    public WayPoint() {
        super(new StringTextComponent("Waypoint GUI"));
    }

    @Override
    protected void init() {
        SoundPlayer.playSound("guiopen.wav", 0.1f);

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.setValue(0);
        animation.animate(1, 0.5, Easings.QUAD_OUT);

        int rectWidth = 300;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2;
        int rectY = (screenHeight - rectHeight) / 2 - 40;

        textFieldName = new TextField(rectX + 25, rectY + rectHeight / 2 - 10, rectWidth - 50, 20);
        textFieldName.setFocused(false);

        textFieldCoords = new TextField(rectX + 25, rectY + rectHeight / 2 + 35, rectWidth - 50, 20);
        textFieldCoords.setFocused(false);

        int buttonWidth = 100;
        int buttonHeight = 17;
        int buttonX = rectX + (rectWidth - buttonWidth) / 2;
        int buttonY = rectY + rectHeight / 2 + 70;

        addPointButton = this.addButton(new CustomButton(buttonX + 50,  buttonY, buttonWidth, buttonHeight, "Установить метку", button -> {
            onAddPoint();
        }));
    }

    private void onAddPoint() {
        String name = textFieldName.getText().trim();
        String coords = textFieldCoords.getText().trim();

        if (name.isEmpty() || coords.isEmpty()) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String[] parts = coords.split("\\s+");
        if (parts.length < 3) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String x = parts[0];
        String y = parts[1];
        String z = parts[2];

        waypoints.add(new WaypointEntry(name, x, y, z));
        mc.player.sendChatMessage(".way add " + name + " " + x + " " + y + " " + z);
        int totalHeight = waypoints.size() * 30;
        int listHeight = 150;
        maxScroll = Math.max(0, totalHeight - listHeight);
    }

    @Override
    public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.update();

        RenderUtil.drawRoundedRect(0, 0, screenWidth, screenHeight, 0, ColorUtil.rgba(0, 0, 0, (int) (155 * animation.getValue())));

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        RenderUtil.Rounded.smooth(matrixStack, rectX, rectY, rectWidth, rectHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, rectX, rectY, rectWidth, rectHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Управление метками", rectX + rectWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Название метки", rectX + rectWidth / 2 - 3, rectY + 10, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldName.render(matrixStack, mouseX, mouseY, partialTicks);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Координаты метки", rectX + rectWidth / 2 + 3, rectY + 55, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldCoords.render(matrixStack, mouseX, mouseY, partialTicks);

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;
        smoothScrollOffset += (targetScrollOffset - smoothScrollOffset) * 0.1;
        scrollOffset = (int) smoothScrollOffset;

        RenderUtil.Rounded.smooth(matrixStack, listX, listY, listWidth, listHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, listX, listY, listWidth, listHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Сохранённые метки", listX + listWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        int offsetY = listY + 10 - scrollOffset;
        int lineHeight = 30;
        int visibleCount = listHeight / lineHeight;

        Scissor.push();
        Scissor.setFromComponentCoordinates(listX, listY, listWidth, listHeight);

        for (int i = 0; i < waypoints.size(); i++) {
            WaypointEntry entry = waypoints.get(i);

            int entryTop = offsetY;
            int entryBottom = offsetY + lineHeight;

            if (entryBottom >= listY && entryTop <= listY + listHeight) {
                RenderUtil.Rounded.smooth(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, ColorUtil.rgba(20, 20, 20, (int) (255 * animation.getValue())), Round.of(4));
                RenderUtil.Rounded.roundedOutline(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, 1, ColorUtil.rgba(40, 40, 40, (int) (255 * animation.getValue())), Round.of(4));
                Fonts.SF_MEDIUM.draw(matrixStack, "§f" + entry.name, listX + 10, offsetY, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
                Fonts.SF_MEDIUM.draw(matrixStack, "X: " + entry.x +" Y: " + entry.y + " Z: " + entry.z, listX + 10, offsetY + 10, ColorUtil.rgba(125, 125, 125, (int) (255 * animation.getValue())), 7.5f);
            }

            offsetY += lineHeight;
        }

        Scissor.pop();


        super.render(matrixStack, mouseX, mouseY, partialTicks);
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        boolean clickedName = textFieldName.mouseClicked(mouseX, mouseY, button);
        boolean clickedCoords = textFieldCoords.mouseClicked(mouseX, mouseY, button);

        if (clickedName) {
            textFieldName.setFocused(true);
            textFieldCoords.setFocused(false);
            return true;
        }
        if (clickedCoords) {
            textFieldCoords.setFocused(true);
            textFieldName.setFocused(false);
            return true;
        }

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;

        if (button == 1) {
            int offsetY = listY + 10 - scrollOffset;
            int lineHeight = 30;

            for (int i = 0; i < waypoints.size(); i++) {
                int entryTop = offsetY;
                int entryBottom = offsetY + lineHeight;

                if (mouseX >= listX + 6 && mouseX <= listX + listWidth - 6 &&
                        mouseY >= entryTop && mouseY <= entryBottom) {
                    WaypointEntry removed = waypoints.remove(i);

                    mc.player.sendChatMessage(".way remove " + removed.name);

                    int totalHeight = waypoints.size() * 30;
                    maxScroll = Math.max(0, totalHeight - listHeight);

                    targetScrollOffset = Math.min(targetScrollOffset, maxScroll);
                    smoothScrollOffset = Math.min(smoothScrollOffset, maxScroll);
                    scrollOffset = (int) smoothScrollOffset;

                    return true;
                }

                offsetY += lineHeight;
            }
        }

        textFieldName.setFocused(false);
        textFieldCoords.setFocused(false);

        return super.mouseClicked(mouseX, mouseY, button);
    }
    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        int listWidth = 180;
        int listHeight = 140;
        int listX = (mc.getMainWindow().getScaledWidth() - 200) / 2 + 50 - listWidth - 20;
        int listY = (mc.getMainWindow().getScaledHeight() - 150) / 2;

        if (mouseX >= listX && mouseX <= listX + listWidth &&
                mouseY >= listY && mouseY <= listY + listHeight) {

            int totalHeight = waypoints.size() * 30;
            int maxScrollAmount = Math.max(0, totalHeight - listHeight);

            targetScrollOffset -= delta * 30;
            targetScrollOffset = Math.max(0, Math.min(targetScrollOffset, maxScrollAmount));

            return true;
        }

        return super.mouseScrolled(mouseX, mouseY, delta);
    }


    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        if (keyCode == GLFW.GLFW_KEY_W ||
                keyCode == GLFW.GLFW_KEY_A ||
                keyCode == GLFW.GLFW_KEY_S ||
                keyCode == GLFW.GLFW_KEY_D ||
                keyCode == GLFW.GLFW_KEY_SPACE ||
                keyCode == GLFW.GLFW_KEY_LEFT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_LEFT_CONTROL ||
                keyCode == GLFW.GLFW_KEY_RIGHT_CONTROL) {
            return true;
        }

        if (textFieldName.isFocused() && textFieldName.keyPressed(keyCode, scanCode, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.keyPressed(keyCode, scanCode, modifiers)) return true;

        if (keyCode == GLFW.GLFW_KEY_ESCAPE && !escPressed) {
            super.closeScreen();
            animation = animation.animate(0, 0.3, Easings.QUART_OUT);
            GLFW.glfwSetCursor(Minecraft.getInstance().getMainWindow().getHandle(), Cursors.ARROW);
        }

        return super.keyPressed(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean charTyped(char codePoint, int modifiers) {
        if (textFieldName.isFocused() && textFieldName.charTyped(codePoint, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.charTyped(codePoint, modifiers)) return true;

        return super.charTyped(codePoint, modifiers);
    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }


    public static class WaypointEntry {
        public final String name;
        public final String x, y, z;

        public WaypointEntry(String name, String x, String y, String z) {
            this.name = name;
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }

    public class CustomButton extends Button {

        private static final int ARC_RADIUS = 5;
        private static final int TEXT_SIZE = 8;

        public CustomButton(int x, int y, int width, int height, String text, IPressable onPress) {
            super(x, y, width, height, new StringTextComponent(text), onPress);
        }

        @Override
        public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
            int bgColor;
            if (!this.active) {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // неактивная кнопка — темнее
            } else if (this.isHovered()) {
                bgColor = ColorUtil.rgba(35, 35, 35, (int) (255 * animation.getValue())); // при наведении — синий оттенок
            } else {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // обычное состояние — синий темный
            }

            RenderUtil.Rounded.smooth(matrixStack, this.x, this.y, this.width, this.height, bgColor, Round.of(4.5f));
            RenderUtil.Rounded.roundedOutline(matrixStack, this.x, this.y, this.width, this.height, 1, ColorUtil.rgba(45, 45, 45, (int) (255 * animation.getValue())), Round.of(4.5f));

            int textColor = ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue()));
            Fonts.SF_MEDIUM.drawCenter(matrixStack, this.getMessage().getString(), this.x + width / 2, this.y + (this.height / 2) - (TEXT_SIZE / 2) + 0.5f, textColor, TEXT_SIZE);
        }
    }
}
4. Дальше заходим в главный класс клиент, и пишем в начале класса
private WayPoint wayPoint;
5. Дальше в метод clientLoad() добавляем
wayPoint = new WayPoint();
6. После этого в метод onKeyPressed() добавляем
if (key == moduleManager.getWayPanel().openGui.get()) {
Minecraft.getInstance().displayGuiScreen(wayPoint);
}
7.Дальше добавляем функцию
WayPanel:
Expand Collapse Copy
package client.main.module.impl.misc;

import client.main.module.api.Category;
import client.main.module.api.Module;
import client.main.module.api.ModuleRegister;
import client.main.module.settings.implObjects.ActionButtonObject;
import client.main.module.settings.implObjects.BindSetObject;

@ModuleRegister(name = "WayPanel", type = Category.Misc,desc = "test")
public class WayPanel extends Module {
    public BindSetObject openGui = new BindSetObject("Кнопка открытия", -1);
    public WayPanel() {
        addSettings(openGui);
    }
}
Дальше регаем модуль в FunctionRegistry (не буду показывать как, потому что вы не тупые я думаю)
-----------------------------------------------
Теперь разберёмся с WayCommand:
В том же самом главном классе в методе initCommands вставляем эту строку

commands.add(new WayCommand(prefix, logger));
-----------------------------------------------
Ну короче вроде всё нормас вы спастили!!!!!!!

Давайте сразу тему одобрите просто как с ActionButton
под 3.1 не перенесут половина, так же не вижу смысла потому что нету в любимам нурпукане
 
вы заебали тупорылые свиньи вы руками нихуя не можете сделать только через свой чат гпт и еще постите эту хуйню на югейм конченые пастеры
 
Дароу yougame
Вот сливаю вам WayPanel и WayCommand
ss way command: прикреплён ниже
ss
way panel: прикреплён ниже
-------------------------------------------
Также скажу: утилки с литки (ноад), и другая система шрифтов
-------------------------------------------
Тутор:
1. Создаём класс в папке с RCTComand и т.д

WayCommand:
Expand Collapse Copy
package client.main.command.impl.feature;

import client.events.EventRenderer2D;
import client.main.Vesence;
import client.main.command.*;
import client.main.command.impl.CommandException;
import client.main.module.impl.misc.Theme;
import client.util.client.IMinecraft;
import client.util.display.render.ColorUtil;
import client.util.display.render.RenderUtil;
import client.util.display.render.Round;
import client.util.display.render.font.Fonts;
import client.util.player.projections.ProjectionUtil;
import com.google.common.eventbus.Subscribe;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.vector.Vector2f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraft.util.text.TextFormatting;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class WayCommand implements Command, CommandWithAdvice, MultiNamedCommand, IMinecraft {
    final Prefix prefix;
    final Logger logger;
    private final Map<String, Vector3i> waysMap = new LinkedHashMap<>();

    public WayCommand(Prefix prefix, Logger logger) {
        this.prefix = prefix;
        this.logger = logger;
        Vesence.getInstance().getEventBus().register(this);
    }

    @Override
    public void execute(Parameters parameters) {
        String commandType = parameters.asString(0).orElse("");

        switch (commandType) {
            case "add" -> addGPS(parameters);
            case "remove" -> removeGPS(parameters);
            case "clear" -> {
                waysMap.clear();
                logger.log("Все пути были удалены!");
            }
            case "list" -> {
                logger.log("Список путей:");

                for (String s : waysMap.keySet()) {
                    logger.log(s + " " + waysMap.get(s));
                }
            }
            default ->
                    throw new CommandException(TextFormatting.RED + "Укажите тип команды:" + TextFormatting.GRAY + " add, remove, clear");
        }
    }

    private void addGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));
        int x = param.asInt(2)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите первую координату!"));

        int y = param.asInt(3)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите вторую координату!"));

        int z = param.asInt(4)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите третью координату!"));

        Vector3i vec = new Vector3i(x, y, z);
        waysMap.put(name, vec);
        logger.log("Путь " + name + " был добавлен!");
    }

    private void removeGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));

        waysMap.remove(name);
        logger.log("Путь " + name + " был удалён!");
    }

    @Override
    public String name() {
        return "way";
    }

    @Override
    public String description() {
        return "Позволяет работать с координатами путей";
    }

    @Override
    public List<String> adviceMessage() {
        String commandPrefix = prefix.get();
        return List.of(commandPrefix + "way add <имя, x, y, z> - Проложить путь к WayPoint'у",
                commandPrefix + "way remove <имя> - Удалить WayPoint",
                commandPrefix + "way list - Список WayPoint'ов",
                commandPrefix + "way clear - Очистить список WayPoint'ов",
                "Пример: " + TextFormatting.RED + commandPrefix + "way add Имя КоординатаX КоординатаY КоординатаZ"
        );
    }
    Vector3i vec3i;
    Vector3d vec3d;
    Vector2f vec2f;
    int distance;

    @Subscribe
    private void onDisplay(EventRenderer2D e) {

        if (waysMap.isEmpty()) {
            return;
        }
        for (String name : waysMap.keySet()) {
            vec3i = waysMap.get(name);

            vec3d = new Vector3d(
                    vec3i.getX() + 0.5,
                    vec3i.getY() + 0.5,
                    vec3i.getZ() + 0.5
            );

            vec2f = ProjectionUtil.project(vec3d.x, vec3d.y, vec3d.z);
            distance = (int) Minecraft.getInstance().player.getPositionVec().distanceTo(vec3d);
            String text = name + ": До точки: " + distance + "M";

            float textWith = client.util.screenUtil.normalFont.Fonts.SF_REGULAR.getWidth(text, 7.5f);
            float fontHeight = Fonts.sf_medium.getHeight(8);

            float posX = vec2f.x - textWith / 2;
            float posY = vec2f.y - fontHeight / 2;
            float posY2 = vec2f.y - fontHeight / 10;
            float padding = 2;

            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding + 17, posY - padding - 0.5f, padding + textWith + padding + 3, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding, posY - padding - 0.5f, Fonts.iconDANQ.getWidth("B", 8) + 8, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            Fonts.iconDANQ.drawText(e.getMatrixStack(), "B", posX - padding + 3.75f, posY2 - 2, Theme.ClientColor(), 7);
            client.util.screenUtil.normalFont.Fonts.SF_REGULAR.draw(e.getMatrixStack(), text, posX - padding + 20, posY2 - 3f, -1, 7.5f);
        }
    }

    @Override
    public List<String> aliases() {
        return List.of("w");
    }
}
2. Создаём в ui папку WayPanel
3.Создаём класс WayPanel в этой папке:

WayPoint:
Expand Collapse Copy
package client.display.waypointScreen;

import client.util.client.IMinecraft;
import client.util.client.SoundPlayer;
import client.util.display.render.*;
import client.util.screenUtil.normalFont.Fonts;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import org.lwjgl.glfw.GLFW;
import ru.hogoshi.Animation;
import ru.hogoshi.util.Easings;

import java.util.ArrayList;
import java.util.List;

public class WayPoint extends Screen implements IMinecraft {
    private double targetScrollOffset = 0;
    private double smoothScrollOffset = 0;
    private boolean escPressed = false;
    private TextField textFieldName;
    private TextField textFieldCoords;
    private int scrollOffset = 0;
    private int maxScroll = 0;
    private CustomButton addPointButton;
    @Getter
    private static Animation animation = new Animation();
    private final List<WaypointEntry> waypoints = new ArrayList<>();

    public WayPoint() {
        super(new StringTextComponent("Waypoint GUI"));
    }

    @Override
    protected void init() {
        SoundPlayer.playSound("guiopen.wav", 0.1f);

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.setValue(0);
        animation.animate(1, 0.5, Easings.QUAD_OUT);

        int rectWidth = 300;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2;
        int rectY = (screenHeight - rectHeight) / 2 - 40;

        textFieldName = new TextField(rectX + 25, rectY + rectHeight / 2 - 10, rectWidth - 50, 20);
        textFieldName.setFocused(false);

        textFieldCoords = new TextField(rectX + 25, rectY + rectHeight / 2 + 35, rectWidth - 50, 20);
        textFieldCoords.setFocused(false);

        int buttonWidth = 100;
        int buttonHeight = 17;
        int buttonX = rectX + (rectWidth - buttonWidth) / 2;
        int buttonY = rectY + rectHeight / 2 + 70;

        addPointButton = this.addButton(new CustomButton(buttonX + 50,  buttonY, buttonWidth, buttonHeight, "Установить метку", button -> {
            onAddPoint();
        }));
    }

    private void onAddPoint() {
        String name = textFieldName.getText().trim();
        String coords = textFieldCoords.getText().trim();

        if (name.isEmpty() || coords.isEmpty()) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String[] parts = coords.split("\\s+");
        if (parts.length < 3) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String x = parts[0];
        String y = parts[1];
        String z = parts[2];

        waypoints.add(new WaypointEntry(name, x, y, z));
        mc.player.sendChatMessage(".way add " + name + " " + x + " " + y + " " + z);
        int totalHeight = waypoints.size() * 30;
        int listHeight = 150;
        maxScroll = Math.max(0, totalHeight - listHeight);
    }

    @Override
    public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.update();

        RenderUtil.drawRoundedRect(0, 0, screenWidth, screenHeight, 0, ColorUtil.rgba(0, 0, 0, (int) (155 * animation.getValue())));

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        RenderUtil.Rounded.smooth(matrixStack, rectX, rectY, rectWidth, rectHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, rectX, rectY, rectWidth, rectHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Управление метками", rectX + rectWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Название метки", rectX + rectWidth / 2 - 3, rectY + 10, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldName.render(matrixStack, mouseX, mouseY, partialTicks);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Координаты метки", rectX + rectWidth / 2 + 3, rectY + 55, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldCoords.render(matrixStack, mouseX, mouseY, partialTicks);

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;
        smoothScrollOffset += (targetScrollOffset - smoothScrollOffset) * 0.1;
        scrollOffset = (int) smoothScrollOffset;

        RenderUtil.Rounded.smooth(matrixStack, listX, listY, listWidth, listHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, listX, listY, listWidth, listHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Сохранённые метки", listX + listWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        int offsetY = listY + 10 - scrollOffset;
        int lineHeight = 30;
        int visibleCount = listHeight / lineHeight;

        Scissor.push();
        Scissor.setFromComponentCoordinates(listX, listY, listWidth, listHeight);

        for (int i = 0; i < waypoints.size(); i++) {
            WaypointEntry entry = waypoints.get(i);

            int entryTop = offsetY;
            int entryBottom = offsetY + lineHeight;

            if (entryBottom >= listY && entryTop <= listY + listHeight) {
                RenderUtil.Rounded.smooth(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, ColorUtil.rgba(20, 20, 20, (int) (255 * animation.getValue())), Round.of(4));
                RenderUtil.Rounded.roundedOutline(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, 1, ColorUtil.rgba(40, 40, 40, (int) (255 * animation.getValue())), Round.of(4));
                Fonts.SF_MEDIUM.draw(matrixStack, "§f" + entry.name, listX + 10, offsetY, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
                Fonts.SF_MEDIUM.draw(matrixStack, "X: " + entry.x +" Y: " + entry.y + " Z: " + entry.z, listX + 10, offsetY + 10, ColorUtil.rgba(125, 125, 125, (int) (255 * animation.getValue())), 7.5f);
            }

            offsetY += lineHeight;
        }

        Scissor.pop();


        super.render(matrixStack, mouseX, mouseY, partialTicks);
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        boolean clickedName = textFieldName.mouseClicked(mouseX, mouseY, button);
        boolean clickedCoords = textFieldCoords.mouseClicked(mouseX, mouseY, button);

        if (clickedName) {
            textFieldName.setFocused(true);
            textFieldCoords.setFocused(false);
            return true;
        }
        if (clickedCoords) {
            textFieldCoords.setFocused(true);
            textFieldName.setFocused(false);
            return true;
        }

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;

        if (button == 1) {
            int offsetY = listY + 10 - scrollOffset;
            int lineHeight = 30;

            for (int i = 0; i < waypoints.size(); i++) {
                int entryTop = offsetY;
                int entryBottom = offsetY + lineHeight;

                if (mouseX >= listX + 6 && mouseX <= listX + listWidth - 6 &&
                        mouseY >= entryTop && mouseY <= entryBottom) {
                    WaypointEntry removed = waypoints.remove(i);

                    mc.player.sendChatMessage(".way remove " + removed.name);

                    int totalHeight = waypoints.size() * 30;
                    maxScroll = Math.max(0, totalHeight - listHeight);

                    targetScrollOffset = Math.min(targetScrollOffset, maxScroll);
                    smoothScrollOffset = Math.min(smoothScrollOffset, maxScroll);
                    scrollOffset = (int) smoothScrollOffset;

                    return true;
                }

                offsetY += lineHeight;
            }
        }

        textFieldName.setFocused(false);
        textFieldCoords.setFocused(false);

        return super.mouseClicked(mouseX, mouseY, button);
    }
    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        int listWidth = 180;
        int listHeight = 140;
        int listX = (mc.getMainWindow().getScaledWidth() - 200) / 2 + 50 - listWidth - 20;
        int listY = (mc.getMainWindow().getScaledHeight() - 150) / 2;

        if (mouseX >= listX && mouseX <= listX + listWidth &&
                mouseY >= listY && mouseY <= listY + listHeight) {

            int totalHeight = waypoints.size() * 30;
            int maxScrollAmount = Math.max(0, totalHeight - listHeight);

            targetScrollOffset -= delta * 30;
            targetScrollOffset = Math.max(0, Math.min(targetScrollOffset, maxScrollAmount));

            return true;
        }

        return super.mouseScrolled(mouseX, mouseY, delta);
    }


    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        if (keyCode == GLFW.GLFW_KEY_W ||
                keyCode == GLFW.GLFW_KEY_A ||
                keyCode == GLFW.GLFW_KEY_S ||
                keyCode == GLFW.GLFW_KEY_D ||
                keyCode == GLFW.GLFW_KEY_SPACE ||
                keyCode == GLFW.GLFW_KEY_LEFT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_LEFT_CONTROL ||
                keyCode == GLFW.GLFW_KEY_RIGHT_CONTROL) {
            return true;
        }

        if (textFieldName.isFocused() && textFieldName.keyPressed(keyCode, scanCode, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.keyPressed(keyCode, scanCode, modifiers)) return true;

        if (keyCode == GLFW.GLFW_KEY_ESCAPE && !escPressed) {
            super.closeScreen();
            animation = animation.animate(0, 0.3, Easings.QUART_OUT);
            GLFW.glfwSetCursor(Minecraft.getInstance().getMainWindow().getHandle(), Cursors.ARROW);
        }

        return super.keyPressed(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean charTyped(char codePoint, int modifiers) {
        if (textFieldName.isFocused() && textFieldName.charTyped(codePoint, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.charTyped(codePoint, modifiers)) return true;

        return super.charTyped(codePoint, modifiers);
    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }


    public static class WaypointEntry {
        public final String name;
        public final String x, y, z;

        public WaypointEntry(String name, String x, String y, String z) {
            this.name = name;
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }

    public class CustomButton extends Button {

        private static final int ARC_RADIUS = 5;
        private static final int TEXT_SIZE = 8;

        public CustomButton(int x, int y, int width, int height, String text, IPressable onPress) {
            super(x, y, width, height, new StringTextComponent(text), onPress);
        }

        @Override
        public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
            int bgColor;
            if (!this.active) {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // неактивная кнопка — темнее
            } else if (this.isHovered()) {
                bgColor = ColorUtil.rgba(35, 35, 35, (int) (255 * animation.getValue())); // при наведении — синий оттенок
            } else {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // обычное состояние — синий темный
            }

            RenderUtil.Rounded.smooth(matrixStack, this.x, this.y, this.width, this.height, bgColor, Round.of(4.5f));
            RenderUtil.Rounded.roundedOutline(matrixStack, this.x, this.y, this.width, this.height, 1, ColorUtil.rgba(45, 45, 45, (int) (255 * animation.getValue())), Round.of(4.5f));

            int textColor = ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue()));
            Fonts.SF_MEDIUM.drawCenter(matrixStack, this.getMessage().getString(), this.x + width / 2, this.y + (this.height / 2) - (TEXT_SIZE / 2) + 0.5f, textColor, TEXT_SIZE);
        }
    }
}
4. Дальше заходим в главный класс клиент, и пишем в начале класса
private WayPoint wayPoint;
5. Дальше в метод clientLoad() добавляем
wayPoint = new WayPoint();
6. После этого в метод onKeyPressed() добавляем
if (key == moduleManager.getWayPanel().openGui.get()) {
Minecraft.getInstance().displayGuiScreen(wayPoint);
}
7.Дальше добавляем функцию
WayPanel:
Expand Collapse Copy
package client.main.module.impl.misc;

import client.main.module.api.Category;
import client.main.module.api.Module;
import client.main.module.api.ModuleRegister;
import client.main.module.settings.implObjects.ActionButtonObject;
import client.main.module.settings.implObjects.BindSetObject;

@ModuleRegister(name = "WayPanel", type = Category.Misc,desc = "test")
public class WayPanel extends Module {
    public BindSetObject openGui = new BindSetObject("Кнопка открытия", -1);
    public WayPanel() {
        addSettings(openGui);
    }
}
Дальше регаем модуль в FunctionRegistry (не буду показывать как, потому что вы не тупые я думаю)
-----------------------------------------------
Теперь разберёмся с WayCommand:
В том же самом главном классе в методе initCommands вставляем эту строку

commands.add(new WayCommand(prefix, logger));
-----------------------------------------------
Ну короче вроде всё нормас вы спастили!!!!!!!

Давайте сразу тему одобрите просто как с ActionButton
максимально не удобно реализовать через меню отдельную
 
Дароу yougame
Вот сливаю вам WayPanel и WayCommand
ss way command: прикреплён ниже
ss
way panel: прикреплён ниже
-------------------------------------------
Также скажу: утилки с литки (ноад), и другая система шрифтов
-------------------------------------------
Тутор:
1. Создаём класс в папке с RCTComand и т.д

WayCommand:
Expand Collapse Copy
package client.main.command.impl.feature;

import client.events.EventRenderer2D;
import client.main.Vesence;
import client.main.command.*;
import client.main.command.impl.CommandException;
import client.main.module.impl.misc.Theme;
import client.util.client.IMinecraft;
import client.util.display.render.ColorUtil;
import client.util.display.render.RenderUtil;
import client.util.display.render.Round;
import client.util.display.render.font.Fonts;
import client.util.player.projections.ProjectionUtil;
import com.google.common.eventbus.Subscribe;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.vector.Vector2f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraft.util.text.TextFormatting;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class WayCommand implements Command, CommandWithAdvice, MultiNamedCommand, IMinecraft {
    final Prefix prefix;
    final Logger logger;
    private final Map<String, Vector3i> waysMap = new LinkedHashMap<>();

    public WayCommand(Prefix prefix, Logger logger) {
        this.prefix = prefix;
        this.logger = logger;
        Vesence.getInstance().getEventBus().register(this);
    }

    @Override
    public void execute(Parameters parameters) {
        String commandType = parameters.asString(0).orElse("");

        switch (commandType) {
            case "add" -> addGPS(parameters);
            case "remove" -> removeGPS(parameters);
            case "clear" -> {
                waysMap.clear();
                logger.log("Все пути были удалены!");
            }
            case "list" -> {
                logger.log("Список путей:");

                for (String s : waysMap.keySet()) {
                    logger.log(s + " " + waysMap.get(s));
                }
            }
            default ->
                    throw new CommandException(TextFormatting.RED + "Укажите тип команды:" + TextFormatting.GRAY + " add, remove, clear");
        }
    }

    private void addGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));
        int x = param.asInt(2)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите первую координату!"));

        int y = param.asInt(3)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите вторую координату!"));

        int z = param.asInt(4)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите третью координату!"));

        Vector3i vec = new Vector3i(x, y, z);
        waysMap.put(name, vec);
        logger.log("Путь " + name + " был добавлен!");
    }

    private void removeGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));

        waysMap.remove(name);
        logger.log("Путь " + name + " был удалён!");
    }

    @Override
    public String name() {
        return "way";
    }

    @Override
    public String description() {
        return "Позволяет работать с координатами путей";
    }

    @Override
    public List<String> adviceMessage() {
        String commandPrefix = prefix.get();
        return List.of(commandPrefix + "way add <имя, x, y, z> - Проложить путь к WayPoint'у",
                commandPrefix + "way remove <имя> - Удалить WayPoint",
                commandPrefix + "way list - Список WayPoint'ов",
                commandPrefix + "way clear - Очистить список WayPoint'ов",
                "Пример: " + TextFormatting.RED + commandPrefix + "way add Имя КоординатаX КоординатаY КоординатаZ"
        );
    }
    Vector3i vec3i;
    Vector3d vec3d;
    Vector2f vec2f;
    int distance;

    @Subscribe
    private void onDisplay(EventRenderer2D e) {

        if (waysMap.isEmpty()) {
            return;
        }
        for (String name : waysMap.keySet()) {
            vec3i = waysMap.get(name);

            vec3d = new Vector3d(
                    vec3i.getX() + 0.5,
                    vec3i.getY() + 0.5,
                    vec3i.getZ() + 0.5
            );

            vec2f = ProjectionUtil.project(vec3d.x, vec3d.y, vec3d.z);
            distance = (int) Minecraft.getInstance().player.getPositionVec().distanceTo(vec3d);
            String text = name + ": До точки: " + distance + "M";

            float textWith = client.util.screenUtil.normalFont.Fonts.SF_REGULAR.getWidth(text, 7.5f);
            float fontHeight = Fonts.sf_medium.getHeight(8);

            float posX = vec2f.x - textWith / 2;
            float posY = vec2f.y - fontHeight / 2;
            float posY2 = vec2f.y - fontHeight / 10;
            float padding = 2;

            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding + 17, posY - padding - 0.5f, padding + textWith + padding + 3, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding, posY - padding - 0.5f, Fonts.iconDANQ.getWidth("B", 8) + 8, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            Fonts.iconDANQ.drawText(e.getMatrixStack(), "B", posX - padding + 3.75f, posY2 - 2, Theme.ClientColor(), 7);
            client.util.screenUtil.normalFont.Fonts.SF_REGULAR.draw(e.getMatrixStack(), text, posX - padding + 20, posY2 - 3f, -1, 7.5f);
        }
    }

    @Override
    public List<String> aliases() {
        return List.of("w");
    }
}
2. Создаём в ui папку WayPanel
3.Создаём класс WayPanel в этой папке:

WayPoint:
Expand Collapse Copy
package client.display.waypointScreen;

import client.util.client.IMinecraft;
import client.util.client.SoundPlayer;
import client.util.display.render.*;
import client.util.screenUtil.normalFont.Fonts;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import org.lwjgl.glfw.GLFW;
import ru.hogoshi.Animation;
import ru.hogoshi.util.Easings;

import java.util.ArrayList;
import java.util.List;

public class WayPoint extends Screen implements IMinecraft {
    private double targetScrollOffset = 0;
    private double smoothScrollOffset = 0;
    private boolean escPressed = false;
    private TextField textFieldName;
    private TextField textFieldCoords;
    private int scrollOffset = 0;
    private int maxScroll = 0;
    private CustomButton addPointButton;
    @Getter
    private static Animation animation = new Animation();
    private final List<WaypointEntry> waypoints = new ArrayList<>();

    public WayPoint() {
        super(new StringTextComponent("Waypoint GUI"));
    }

    @Override
    protected void init() {
        SoundPlayer.playSound("guiopen.wav", 0.1f);

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.setValue(0);
        animation.animate(1, 0.5, Easings.QUAD_OUT);

        int rectWidth = 300;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2;
        int rectY = (screenHeight - rectHeight) / 2 - 40;

        textFieldName = new TextField(rectX + 25, rectY + rectHeight / 2 - 10, rectWidth - 50, 20);
        textFieldName.setFocused(false);

        textFieldCoords = new TextField(rectX + 25, rectY + rectHeight / 2 + 35, rectWidth - 50, 20);
        textFieldCoords.setFocused(false);

        int buttonWidth = 100;
        int buttonHeight = 17;
        int buttonX = rectX + (rectWidth - buttonWidth) / 2;
        int buttonY = rectY + rectHeight / 2 + 70;

        addPointButton = this.addButton(new CustomButton(buttonX + 50,  buttonY, buttonWidth, buttonHeight, "Установить метку", button -> {
            onAddPoint();
        }));
    }

    private void onAddPoint() {
        String name = textFieldName.getText().trim();
        String coords = textFieldCoords.getText().trim();

        if (name.isEmpty() || coords.isEmpty()) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String[] parts = coords.split("\\s+");
        if (parts.length < 3) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String x = parts[0];
        String y = parts[1];
        String z = parts[2];

        waypoints.add(new WaypointEntry(name, x, y, z));
        mc.player.sendChatMessage(".way add " + name + " " + x + " " + y + " " + z);
        int totalHeight = waypoints.size() * 30;
        int listHeight = 150;
        maxScroll = Math.max(0, totalHeight - listHeight);
    }

    @Override
    public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.update();

        RenderUtil.drawRoundedRect(0, 0, screenWidth, screenHeight, 0, ColorUtil.rgba(0, 0, 0, (int) (155 * animation.getValue())));

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        RenderUtil.Rounded.smooth(matrixStack, rectX, rectY, rectWidth, rectHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, rectX, rectY, rectWidth, rectHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Управление метками", rectX + rectWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Название метки", rectX + rectWidth / 2 - 3, rectY + 10, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldName.render(matrixStack, mouseX, mouseY, partialTicks);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Координаты метки", rectX + rectWidth / 2 + 3, rectY + 55, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldCoords.render(matrixStack, mouseX, mouseY, partialTicks);

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;
        smoothScrollOffset += (targetScrollOffset - smoothScrollOffset) * 0.1;
        scrollOffset = (int) smoothScrollOffset;

        RenderUtil.Rounded.smooth(matrixStack, listX, listY, listWidth, listHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, listX, listY, listWidth, listHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Сохранённые метки", listX + listWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        int offsetY = listY + 10 - scrollOffset;
        int lineHeight = 30;
        int visibleCount = listHeight / lineHeight;

        Scissor.push();
        Scissor.setFromComponentCoordinates(listX, listY, listWidth, listHeight);

        for (int i = 0; i < waypoints.size(); i++) {
            WaypointEntry entry = waypoints.get(i);

            int entryTop = offsetY;
            int entryBottom = offsetY + lineHeight;

            if (entryBottom >= listY && entryTop <= listY + listHeight) {
                RenderUtil.Rounded.smooth(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, ColorUtil.rgba(20, 20, 20, (int) (255 * animation.getValue())), Round.of(4));
                RenderUtil.Rounded.roundedOutline(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, 1, ColorUtil.rgba(40, 40, 40, (int) (255 * animation.getValue())), Round.of(4));
                Fonts.SF_MEDIUM.draw(matrixStack, "§f" + entry.name, listX + 10, offsetY, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
                Fonts.SF_MEDIUM.draw(matrixStack, "X: " + entry.x +" Y: " + entry.y + " Z: " + entry.z, listX + 10, offsetY + 10, ColorUtil.rgba(125, 125, 125, (int) (255 * animation.getValue())), 7.5f);
            }

            offsetY += lineHeight;
        }

        Scissor.pop();


        super.render(matrixStack, mouseX, mouseY, partialTicks);
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        boolean clickedName = textFieldName.mouseClicked(mouseX, mouseY, button);
        boolean clickedCoords = textFieldCoords.mouseClicked(mouseX, mouseY, button);

        if (clickedName) {
            textFieldName.setFocused(true);
            textFieldCoords.setFocused(false);
            return true;
        }
        if (clickedCoords) {
            textFieldCoords.setFocused(true);
            textFieldName.setFocused(false);
            return true;
        }

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;

        if (button == 1) {
            int offsetY = listY + 10 - scrollOffset;
            int lineHeight = 30;

            for (int i = 0; i < waypoints.size(); i++) {
                int entryTop = offsetY;
                int entryBottom = offsetY + lineHeight;

                if (mouseX >= listX + 6 && mouseX <= listX + listWidth - 6 &&
                        mouseY >= entryTop && mouseY <= entryBottom) {
                    WaypointEntry removed = waypoints.remove(i);

                    mc.player.sendChatMessage(".way remove " + removed.name);

                    int totalHeight = waypoints.size() * 30;
                    maxScroll = Math.max(0, totalHeight - listHeight);

                    targetScrollOffset = Math.min(targetScrollOffset, maxScroll);
                    smoothScrollOffset = Math.min(smoothScrollOffset, maxScroll);
                    scrollOffset = (int) smoothScrollOffset;

                    return true;
                }

                offsetY += lineHeight;
            }
        }

        textFieldName.setFocused(false);
        textFieldCoords.setFocused(false);

        return super.mouseClicked(mouseX, mouseY, button);
    }
    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        int listWidth = 180;
        int listHeight = 140;
        int listX = (mc.getMainWindow().getScaledWidth() - 200) / 2 + 50 - listWidth - 20;
        int listY = (mc.getMainWindow().getScaledHeight() - 150) / 2;

        if (mouseX >= listX && mouseX <= listX + listWidth &&
                mouseY >= listY && mouseY <= listY + listHeight) {

            int totalHeight = waypoints.size() * 30;
            int maxScrollAmount = Math.max(0, totalHeight - listHeight);

            targetScrollOffset -= delta * 30;
            targetScrollOffset = Math.max(0, Math.min(targetScrollOffset, maxScrollAmount));

            return true;
        }

        return super.mouseScrolled(mouseX, mouseY, delta);
    }


    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        if (keyCode == GLFW.GLFW_KEY_W ||
                keyCode == GLFW.GLFW_KEY_A ||
                keyCode == GLFW.GLFW_KEY_S ||
                keyCode == GLFW.GLFW_KEY_D ||
                keyCode == GLFW.GLFW_KEY_SPACE ||
                keyCode == GLFW.GLFW_KEY_LEFT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_LEFT_CONTROL ||
                keyCode == GLFW.GLFW_KEY_RIGHT_CONTROL) {
            return true;
        }

        if (textFieldName.isFocused() && textFieldName.keyPressed(keyCode, scanCode, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.keyPressed(keyCode, scanCode, modifiers)) return true;

        if (keyCode == GLFW.GLFW_KEY_ESCAPE && !escPressed) {
            super.closeScreen();
            animation = animation.animate(0, 0.3, Easings.QUART_OUT);
            GLFW.glfwSetCursor(Minecraft.getInstance().getMainWindow().getHandle(), Cursors.ARROW);
        }

        return super.keyPressed(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean charTyped(char codePoint, int modifiers) {
        if (textFieldName.isFocused() && textFieldName.charTyped(codePoint, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.charTyped(codePoint, modifiers)) return true;

        return super.charTyped(codePoint, modifiers);
    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }


    public static class WaypointEntry {
        public final String name;
        public final String x, y, z;

        public WaypointEntry(String name, String x, String y, String z) {
            this.name = name;
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }

    public class CustomButton extends Button {

        private static final int ARC_RADIUS = 5;
        private static final int TEXT_SIZE = 8;

        public CustomButton(int x, int y, int width, int height, String text, IPressable onPress) {
            super(x, y, width, height, new StringTextComponent(text), onPress);
        }

        @Override
        public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
            int bgColor;
            if (!this.active) {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // неактивная кнопка — темнее
            } else if (this.isHovered()) {
                bgColor = ColorUtil.rgba(35, 35, 35, (int) (255 * animation.getValue())); // при наведении — синий оттенок
            } else {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // обычное состояние — синий темный
            }

            RenderUtil.Rounded.smooth(matrixStack, this.x, this.y, this.width, this.height, bgColor, Round.of(4.5f));
            RenderUtil.Rounded.roundedOutline(matrixStack, this.x, this.y, this.width, this.height, 1, ColorUtil.rgba(45, 45, 45, (int) (255 * animation.getValue())), Round.of(4.5f));

            int textColor = ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue()));
            Fonts.SF_MEDIUM.drawCenter(matrixStack, this.getMessage().getString(), this.x + width / 2, this.y + (this.height / 2) - (TEXT_SIZE / 2) + 0.5f, textColor, TEXT_SIZE);
        }
    }
}
4. Дальше заходим в главный класс клиент, и пишем в начале класса
private WayPoint wayPoint;
5. Дальше в метод clientLoad() добавляем
wayPoint = new WayPoint();
6. После этого в метод onKeyPressed() добавляем
if (key == moduleManager.getWayPanel().openGui.get()) {
Minecraft.getInstance().displayGuiScreen(wayPoint);
}
7.Дальше добавляем функцию
WayPanel:
Expand Collapse Copy
package client.main.module.impl.misc;

import client.main.module.api.Category;
import client.main.module.api.Module;
import client.main.module.api.ModuleRegister;
import client.main.module.settings.implObjects.ActionButtonObject;
import client.main.module.settings.implObjects.BindSetObject;

@ModuleRegister(name = "WayPanel", type = Category.Misc,desc = "test")
public class WayPanel extends Module {
    public BindSetObject openGui = new BindSetObject("Кнопка открытия", -1);
    public WayPanel() {
        addSettings(openGui);
    }
}
Дальше регаем модуль в FunctionRegistry (не буду показывать как, потому что вы не тупые я думаю)
-----------------------------------------------
Теперь разберёмся с WayCommand:
В том же самом главном классе в методе initCommands вставляем эту строку

commands.add(new WayCommand(prefix, logger));
-----------------------------------------------
Ну короче вроде всё нормас вы спастили!!!!!!!

Давайте сразу тему одобрите просто как с ActionButton
эм, зачем вторая команда для .gps
 
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
del no import 3.1 egpenzive
 
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Дароу yougame
Вот сливаю вам WayPanel и WayCommand
ss way command: прикреплён ниже
ss
way panel: прикреплён ниже
-------------------------------------------
Также скажу: утилки с литки (ноад), и другая система шрифтов
-------------------------------------------
Тутор:
1. Создаём класс в папке с RCTComand и т.д

WayCommand:
Expand Collapse Copy
package client.main.command.impl.feature;

import client.events.EventRenderer2D;
import client.main.Vesence;
import client.main.command.*;
import client.main.command.impl.CommandException;
import client.main.module.impl.misc.Theme;
import client.util.client.IMinecraft;
import client.util.display.render.ColorUtil;
import client.util.display.render.RenderUtil;
import client.util.display.render.Round;
import client.util.display.render.font.Fonts;
import client.util.player.projections.ProjectionUtil;
import com.google.common.eventbus.Subscribe;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.vector.Vector2f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraft.util.text.TextFormatting;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@FieldDefaults(level = AccessLevel.PRIVATE)
public class WayCommand implements Command, CommandWithAdvice, MultiNamedCommand, IMinecraft {
    final Prefix prefix;
    final Logger logger;
    private final Map<String, Vector3i> waysMap = new LinkedHashMap<>();

    public WayCommand(Prefix prefix, Logger logger) {
        this.prefix = prefix;
        this.logger = logger;
        Vesence.getInstance().getEventBus().register(this);
    }

    @Override
    public void execute(Parameters parameters) {
        String commandType = parameters.asString(0).orElse("");

        switch (commandType) {
            case "add" -> addGPS(parameters);
            case "remove" -> removeGPS(parameters);
            case "clear" -> {
                waysMap.clear();
                logger.log("Все пути были удалены!");
            }
            case "list" -> {
                logger.log("Список путей:");

                for (String s : waysMap.keySet()) {
                    logger.log(s + " " + waysMap.get(s));
                }
            }
            default ->
                    throw new CommandException(TextFormatting.RED + "Укажите тип команды:" + TextFormatting.GRAY + " add, remove, clear");
        }
    }

    private void addGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));
        int x = param.asInt(2)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите первую координату!"));

        int y = param.asInt(3)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите вторую координату!"));

        int z = param.asInt(4)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите третью координату!"));

        Vector3i vec = new Vector3i(x, y, z);
        waysMap.put(name, vec);
        logger.log("Путь " + name + " был добавлен!");
    }

    private void removeGPS(Parameters param) {
        String name = param.asString(1)
                .orElseThrow(() -> new CommandException(TextFormatting.RED + "Укажите имя точки!"));

        waysMap.remove(name);
        logger.log("Путь " + name + " был удалён!");
    }

    @Override
    public String name() {
        return "way";
    }

    @Override
    public String description() {
        return "Позволяет работать с координатами путей";
    }

    @Override
    public List<String> adviceMessage() {
        String commandPrefix = prefix.get();
        return List.of(commandPrefix + "way add <имя, x, y, z> - Проложить путь к WayPoint'у",
                commandPrefix + "way remove <имя> - Удалить WayPoint",
                commandPrefix + "way list - Список WayPoint'ов",
                commandPrefix + "way clear - Очистить список WayPoint'ов",
                "Пример: " + TextFormatting.RED + commandPrefix + "way add Имя КоординатаX КоординатаY КоординатаZ"
        );
    }
    Vector3i vec3i;
    Vector3d vec3d;
    Vector2f vec2f;
    int distance;

    @Subscribe
    private void onDisplay(EventRenderer2D e) {

        if (waysMap.isEmpty()) {
            return;
        }
        for (String name : waysMap.keySet()) {
            vec3i = waysMap.get(name);

            vec3d = new Vector3d(
                    vec3i.getX() + 0.5,
                    vec3i.getY() + 0.5,
                    vec3i.getZ() + 0.5
            );

            vec2f = ProjectionUtil.project(vec3d.x, vec3d.y, vec3d.z);
            distance = (int) Minecraft.getInstance().player.getPositionVec().distanceTo(vec3d);
            String text = name + ": До точки: " + distance + "M";

            float textWith = client.util.screenUtil.normalFont.Fonts.SF_REGULAR.getWidth(text, 7.5f);
            float fontHeight = Fonts.sf_medium.getHeight(8);

            float posX = vec2f.x - textWith / 2;
            float posY = vec2f.y - fontHeight / 2;
            float posY2 = vec2f.y - fontHeight / 10;
            float padding = 2;

            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding + 17, posY - padding - 0.5f, padding + textWith + padding + 3, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            RenderUtil.Rounded.smooth(new MatrixStack(),posX - padding, posY - padding - 0.5f, Fonts.iconDANQ.getWidth("B", 8) + 8, padding + fontHeight + padding + 1,ColorUtil.setAlpha(ColorUtil.rgb(0,0,0),65), Round.of(1));
            Fonts.iconDANQ.drawText(e.getMatrixStack(), "B", posX - padding + 3.75f, posY2 - 2, Theme.ClientColor(), 7);
            client.util.screenUtil.normalFont.Fonts.SF_REGULAR.draw(e.getMatrixStack(), text, posX - padding + 20, posY2 - 3f, -1, 7.5f);
        }
    }

    @Override
    public List<String> aliases() {
        return List.of("w");
    }
}
2. Создаём в ui папку WayPanel
3.Создаём класс WayPanel в этой папке:

WayPoint:
Expand Collapse Copy
package client.display.waypointScreen;

import client.util.client.IMinecraft;
import client.util.client.SoundPlayer;
import client.util.display.render.*;
import client.util.screenUtil.normalFont.Fonts;
import com.mojang.blaze3d.matrix.MatrixStack;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import org.lwjgl.glfw.GLFW;
import ru.hogoshi.Animation;
import ru.hogoshi.util.Easings;

import java.util.ArrayList;
import java.util.List;

public class WayPoint extends Screen implements IMinecraft {
    private double targetScrollOffset = 0;
    private double smoothScrollOffset = 0;
    private boolean escPressed = false;
    private TextField textFieldName;
    private TextField textFieldCoords;
    private int scrollOffset = 0;
    private int maxScroll = 0;
    private CustomButton addPointButton;
    @Getter
    private static Animation animation = new Animation();
    private final List<WaypointEntry> waypoints = new ArrayList<>();

    public WayPoint() {
        super(new StringTextComponent("Waypoint GUI"));
    }

    @Override
    protected void init() {
        SoundPlayer.playSound("guiopen.wav", 0.1f);

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.setValue(0);
        animation.animate(1, 0.5, Easings.QUAD_OUT);

        int rectWidth = 300;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2;
        int rectY = (screenHeight - rectHeight) / 2 - 40;

        textFieldName = new TextField(rectX + 25, rectY + rectHeight / 2 - 10, rectWidth - 50, 20);
        textFieldName.setFocused(false);

        textFieldCoords = new TextField(rectX + 25, rectY + rectHeight / 2 + 35, rectWidth - 50, 20);
        textFieldCoords.setFocused(false);

        int buttonWidth = 100;
        int buttonHeight = 17;
        int buttonX = rectX + (rectWidth - buttonWidth) / 2;
        int buttonY = rectY + rectHeight / 2 + 70;

        addPointButton = this.addButton(new CustomButton(buttonX + 50,  buttonY, buttonWidth, buttonHeight, "Установить метку", button -> {
            onAddPoint();
        }));
    }

    private void onAddPoint() {
        String name = textFieldName.getText().trim();
        String coords = textFieldCoords.getText().trim();

        if (name.isEmpty() || coords.isEmpty()) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String[] parts = coords.split("\\s+");
        if (parts.length < 3) {
            print("Вы не указали один из параметров метки!\nПример: .way add Home 100 64 200");
            return;
        }

        String x = parts[0];
        String y = parts[1];
        String z = parts[2];

        waypoints.add(new WaypointEntry(name, x, y, z));
        mc.player.sendChatMessage(".way add " + name + " " + x + " " + y + " " + z);
        int totalHeight = waypoints.size() * 30;
        int listHeight = 150;
        maxScroll = Math.max(0, totalHeight - listHeight);
    }

    @Override
    public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();
        animation.update();

        RenderUtil.drawRoundedRect(0, 0, screenWidth, screenHeight, 0, ColorUtil.rgba(0, 0, 0, (int) (155 * animation.getValue())));

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        RenderUtil.Rounded.smooth(matrixStack, rectX, rectY, rectWidth, rectHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, rectX, rectY, rectWidth, rectHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Управление метками", rectX + rectWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Название метки", rectX + rectWidth / 2 - 3, rectY + 10, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldName.render(matrixStack, mouseX, mouseY, partialTicks);

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Координаты метки", rectX + rectWidth / 2 + 3, rectY + 55, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
        textFieldCoords.render(matrixStack, mouseX, mouseY, partialTicks);

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;
        smoothScrollOffset += (targetScrollOffset - smoothScrollOffset) * 0.1;
        scrollOffset = (int) smoothScrollOffset;

        RenderUtil.Rounded.smooth(matrixStack, listX, listY, listWidth, listHeight, ColorUtil.rgba(15, 15, 15, (int) (255 * animation.getValue())), Round.of(6));
        RenderUtil.Rounded.roundedOutline(matrixStack, listX, listY, listWidth, listHeight, 1, ColorUtil.rgba(30, 30, 30, (int) (255 * animation.getValue())), Round.of(6));

        Fonts.SF_MEDIUM.drawCenter(matrixStack, "Сохранённые метки", listX + listWidth / 2, rectY - 15, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);

        int offsetY = listY + 10 - scrollOffset;
        int lineHeight = 30;
        int visibleCount = listHeight / lineHeight;

        Scissor.push();
        Scissor.setFromComponentCoordinates(listX, listY, listWidth, listHeight);

        for (int i = 0; i < waypoints.size(); i++) {
            WaypointEntry entry = waypoints.get(i);

            int entryTop = offsetY;
            int entryBottom = offsetY + lineHeight;

            if (entryBottom >= listY && entryTop <= listY + listHeight) {
                RenderUtil.Rounded.smooth(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, ColorUtil.rgba(20, 20, 20, (int) (255 * animation.getValue())), Round.of(4));
                RenderUtil.Rounded.roundedOutline(matrixStack, listX + 6, offsetY - 4, listWidth - 12, 25, 1, ColorUtil.rgba(40, 40, 40, (int) (255 * animation.getValue())), Round.of(4));
                Fonts.SF_MEDIUM.draw(matrixStack, "§f" + entry.name, listX + 10, offsetY, ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue())), 8);
                Fonts.SF_MEDIUM.draw(matrixStack, "X: " + entry.x +" Y: " + entry.y + " Z: " + entry.z, listX + 10, offsetY + 10, ColorUtil.rgba(125, 125, 125, (int) (255 * animation.getValue())), 7.5f);
            }

            offsetY += lineHeight;
        }

        Scissor.pop();


        super.render(matrixStack, mouseX, mouseY, partialTicks);
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        boolean clickedName = textFieldName.mouseClicked(mouseX, mouseY, button);
        boolean clickedCoords = textFieldCoords.mouseClicked(mouseX, mouseY, button);

        if (clickedName) {
            textFieldName.setFocused(true);
            textFieldCoords.setFocused(false);
            return true;
        }
        if (clickedCoords) {
            textFieldCoords.setFocused(true);
            textFieldName.setFocused(false);
            return true;
        }

        int screenWidth = mc.getMainWindow().getScaledWidth();
        int screenHeight = mc.getMainWindow().getScaledHeight();

        int rectWidth = 200;
        int rectHeight = 150;
        int rectX = (screenWidth - rectWidth) / 2 + 50;
        int rectY = (screenHeight - rectHeight) / 2;

        int listWidth = 180;
        int listHeight = 150;
        int listX = rectX - listWidth - 20;
        int listY = rectY;

        if (button == 1) {
            int offsetY = listY + 10 - scrollOffset;
            int lineHeight = 30;

            for (int i = 0; i < waypoints.size(); i++) {
                int entryTop = offsetY;
                int entryBottom = offsetY + lineHeight;

                if (mouseX >= listX + 6 && mouseX <= listX + listWidth - 6 &&
                        mouseY >= entryTop && mouseY <= entryBottom) {
                    WaypointEntry removed = waypoints.remove(i);

                    mc.player.sendChatMessage(".way remove " + removed.name);

                    int totalHeight = waypoints.size() * 30;
                    maxScroll = Math.max(0, totalHeight - listHeight);

                    targetScrollOffset = Math.min(targetScrollOffset, maxScroll);
                    smoothScrollOffset = Math.min(smoothScrollOffset, maxScroll);
                    scrollOffset = (int) smoothScrollOffset;

                    return true;
                }

                offsetY += lineHeight;
            }
        }

        textFieldName.setFocused(false);
        textFieldCoords.setFocused(false);

        return super.mouseClicked(mouseX, mouseY, button);
    }
    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        int listWidth = 180;
        int listHeight = 140;
        int listX = (mc.getMainWindow().getScaledWidth() - 200) / 2 + 50 - listWidth - 20;
        int listY = (mc.getMainWindow().getScaledHeight() - 150) / 2;

        if (mouseX >= listX && mouseX <= listX + listWidth &&
                mouseY >= listY && mouseY <= listY + listHeight) {

            int totalHeight = waypoints.size() * 30;
            int maxScrollAmount = Math.max(0, totalHeight - listHeight);

            targetScrollOffset -= delta * 30;
            targetScrollOffset = Math.max(0, Math.min(targetScrollOffset, maxScrollAmount));

            return true;
        }

        return super.mouseScrolled(mouseX, mouseY, delta);
    }


    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        if (keyCode == GLFW.GLFW_KEY_W ||
                keyCode == GLFW.GLFW_KEY_A ||
                keyCode == GLFW.GLFW_KEY_S ||
                keyCode == GLFW.GLFW_KEY_D ||
                keyCode == GLFW.GLFW_KEY_SPACE ||
                keyCode == GLFW.GLFW_KEY_LEFT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT ||
                keyCode == GLFW.GLFW_KEY_LEFT_CONTROL ||
                keyCode == GLFW.GLFW_KEY_RIGHT_CONTROL) {
            return true;
        }

        if (textFieldName.isFocused() && textFieldName.keyPressed(keyCode, scanCode, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.keyPressed(keyCode, scanCode, modifiers)) return true;

        if (keyCode == GLFW.GLFW_KEY_ESCAPE && !escPressed) {
            super.closeScreen();
            animation = animation.animate(0, 0.3, Easings.QUART_OUT);
            GLFW.glfwSetCursor(Minecraft.getInstance().getMainWindow().getHandle(), Cursors.ARROW);
        }

        return super.keyPressed(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean charTyped(char codePoint, int modifiers) {
        if (textFieldName.isFocused() && textFieldName.charTyped(codePoint, modifiers)) return true;
        if (textFieldCoords.isFocused() && textFieldCoords.charTyped(codePoint, modifiers)) return true;

        return super.charTyped(codePoint, modifiers);
    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }


    public static class WaypointEntry {
        public final String name;
        public final String x, y, z;

        public WaypointEntry(String name, String x, String y, String z) {
            this.name = name;
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }

    public class CustomButton extends Button {

        private static final int ARC_RADIUS = 5;
        private static final int TEXT_SIZE = 8;

        public CustomButton(int x, int y, int width, int height, String text, IPressable onPress) {
            super(x, y, width, height, new StringTextComponent(text), onPress);
        }

        @Override
        public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
            int bgColor;
            if (!this.active) {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // неактивная кнопка — темнее
            } else if (this.isHovered()) {
                bgColor = ColorUtil.rgba(35, 35, 35, (int) (255 * animation.getValue())); // при наведении — синий оттенок
            } else {
                bgColor = ColorUtil.rgba(25, 25, 25, (int) (255 * animation.getValue())); // обычное состояние — синий темный
            }

            RenderUtil.Rounded.smooth(matrixStack, this.x, this.y, this.width, this.height, bgColor, Round.of(4.5f));
            RenderUtil.Rounded.roundedOutline(matrixStack, this.x, this.y, this.width, this.height, 1, ColorUtil.rgba(45, 45, 45, (int) (255 * animation.getValue())), Round.of(4.5f));

            int textColor = ColorUtil.rgba(255, 255, 255, (int) (255 * animation.getValue()));
            Fonts.SF_MEDIUM.drawCenter(matrixStack, this.getMessage().getString(), this.x + width / 2, this.y + (this.height / 2) - (TEXT_SIZE / 2) + 0.5f, textColor, TEXT_SIZE);
        }
    }
}
4. Дальше заходим в главный класс клиент, и пишем в начале класса
private WayPoint wayPoint;
5. Дальше в метод clientLoad() добавляем
wayPoint = new WayPoint();
6. После этого в метод onKeyPressed() добавляем
if (key == moduleManager.getWayPanel().openGui.get()) {
Minecraft.getInstance().displayGuiScreen(wayPoint);
}
7.Дальше добавляем функцию
WayPanel:
Expand Collapse Copy
package client.main.module.impl.misc;

import client.main.module.api.Category;
import client.main.module.api.Module;
import client.main.module.api.ModuleRegister;
import client.main.module.settings.implObjects.ActionButtonObject;
import client.main.module.settings.implObjects.BindSetObject;

@ModuleRegister(name = "WayPanel", type = Category.Misc,desc = "test")
public class WayPanel extends Module {
    public BindSetObject openGui = new BindSetObject("Кнопка открытия", -1);
    public WayPanel() {
        addSettings(openGui);
    }
}
Дальше регаем модуль в FunctionRegistry (не буду показывать как, потому что вы не тупые я думаю)
-----------------------------------------------
Теперь разберёмся с WayCommand:
В том же самом главном классе в методе initCommands вставляем эту строку

commands.add(new WayCommand(prefix, logger));
-----------------------------------------------
Ну короче вроде всё нормас вы спастили!!!!!!!

Давайте сразу тему одобрите просто как с ActionButton
Впервые вижу годную темку за месяц на югах, респект
 
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Назад
Сверху Снизу