Created
April 10, 2026 20:10
-
-
Save Ensamisten/10fee1f235036566c81587ab829c94c3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package io.github.ensamisten.client.gui; | |
| import io.github.ensamisten.client.config.ButtonsConfig; | |
| import io.github.ensamisten.client.module.Extension; | |
| import io.github.ensamisten.client.module.ModuleManager; | |
| import io.github.ensamisten.client.module.screen.FriendGuardConfigScreen; | |
| import io.github.ensamisten.client.module.screen.KillAuraConfigScreen; | |
| import io.github.ensamisten.client.module.screen.WhomStruckMeLastScreen; | |
| import net.fabricmc.api.EnvType; | |
| import net.fabricmc.api.Environment; | |
| import net.minecraft.ChatFormatting; | |
| import net.minecraft.client.Minecraft; | |
| import net.minecraft.client.Options; | |
| import net.minecraft.client.gui.GuiGraphicsExtractor; | |
| import net.minecraft.client.gui.components.Button; | |
| import net.minecraft.client.gui.components.EditBox; | |
| import net.minecraft.client.gui.screens.Screen; | |
| import net.minecraft.client.gui.screens.options.OptionsScreen; | |
| import net.minecraft.client.input.CharacterEvent; | |
| import net.minecraft.client.input.KeyEvent; | |
| import net.minecraft.client.input.MouseButtonEvent; | |
| import net.minecraft.network.chat.Component; | |
| import org.lwjgl.glfw.GLFW; | |
| import java.util.*; | |
| @Environment(EnvType.CLIENT) | |
| public class AllyshipOptionsScreen extends OptionsScreen { | |
| // ── Hardcoded category order ────────────────────────────────── | |
| private static final List<String> CATEGORIES = List.of( | |
| "Combat", "Movement", "Render", "Exploit", "World", "Player" | |
| ); | |
| private static final int BUTTON_WIDTH = 80; | |
| private static final int BUTTON_HEIGHT = 20; | |
| private static final int DROPDOWN_WIDTH = BUTTON_WIDTH; | |
| private static final int BORDER_PADDING = 4; | |
| private static final int MAX_VISIBLE_ITEMS = 8; | |
| private static final int SEARCH_BAR_W = 160; | |
| private static final int SEARCH_BAR_H = 16; | |
| private static final int SEARCH_BAR_Y = 10; | |
| private final Map<String, DropdownContainer> dropdowns = new LinkedHashMap<>(); | |
| private final Map<String, Button> categoryButtons = new LinkedHashMap<>(); | |
| // ── Search state ─────────────────────────���──────────────────── | |
| private EditBox searchBar; | |
| private String searchQuery = ""; | |
| // Search results — populated when query is non-empty | |
| private final List<SearchResultItem> searchResults = new ArrayList<>(); | |
| // Drag state | |
| private Button draggedButton = null; | |
| private double initialClickX, initialClickY; | |
| private double dragOffsetX, dragOffsetY; | |
| private boolean isDragging = false; | |
| private final double dragThreshold = 5.0; | |
| private final Minecraft client; | |
| public AllyshipOptionsScreen(Screen parent, Options options) { | |
| super(parent, options, true); | |
| this.client = Minecraft.getInstance(); | |
| for (String category : CATEGORIES) { | |
| List<DropdownItem> items = buildItemsForCategory(category); | |
| dropdowns.put(category.toLowerCase(), new DropdownContainer(category, items)); | |
| } | |
| } | |
| // ── Build items ─────────────────────────────────────────────── | |
| private List<DropdownItem> buildItemsForCategory(String category) { | |
| List<DropdownItem> items = new ArrayList<>(); | |
| for (Extension module : ModuleManager.getAll()) { | |
| if (module.getCategory().equalsIgnoreCase(category)) { | |
| items.add(new DropdownItem(module.getName(), null, null)); | |
| } | |
| } | |
| return items; | |
| } | |
| // ── init ────────────────────────────────────────────────────── | |
| // ── init ────────────────────────────────────────────────────── | |
| @Override | |
| protected void init() { | |
| int sbX = width / 2 - SEARCH_BAR_W / 2; | |
| searchBar = new EditBox(font, sbX, SEARCH_BAR_Y, | |
| SEARCH_BAR_W, SEARCH_BAR_H, | |
| Component.literal("Search modules...")); | |
| searchBar.setMaxLength(32); | |
| searchBar.setHint(Component.literal("Search modules...")); | |
| searchBar.setResponder(this::onSearchTyped); | |
| addRenderableWidget(searchBar); | |
| int buttonY = 60; | |
| int buttonSpacing = 10; | |
| int currentX = 20; | |
| for (String categoryKey : dropdowns.keySet()) { | |
| DropdownContainer container = dropdowns.get(categoryKey); | |
| final int defaultX = currentX; | |
| final int defaultY = 60; | |
| // Restore saved position or fall back to default | |
| int[] saved = ButtonsConfig.getInstance().getPosition(categoryKey); | |
| final int x = saved != null ? saved[0] : defaultX; | |
| final int y = saved != null ? saved[1] : defaultY; | |
| Button button = Button.builder( | |
| Component.literal(container.getDisplayName()), | |
| btn -> {} | |
| ).bounds(x, y, BUTTON_WIDTH, BUTTON_HEIGHT).build(); | |
| addRenderableOnly(button); | |
| categoryButtons.put(categoryKey, button); | |
| currentX += BUTTON_WIDTH + buttonSpacing; | |
| } | |
| } | |
| // ── Search logic ────────────────────────────────────────────── | |
| private void onSearchTyped(String query) { | |
| searchQuery = query.trim().toLowerCase(); | |
| searchResults.clear(); | |
| if (searchQuery.isEmpty()) return; | |
| // Close all dropdowns while searching | |
| for (DropdownContainer dc : dropdowns.values()) { | |
| if (dc.isVisible()) dc.toggle(); | |
| } | |
| // Find all modules whose name contains the query | |
| for (Extension module : ModuleManager.getAll()) { | |
| if (module.getName().toLowerCase().contains(searchQuery)) { | |
| searchResults.add(new SearchResultItem(module.getName())); | |
| } | |
| } | |
| } | |
| // ── Mouse input ─────────────────────────────────────────────── | |
| @Override | |
| public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { | |
| double mouseX = event.x(); | |
| double mouseY = event.y(); | |
| if (!searchQuery.isEmpty()) { | |
| if (searchBar.isMouseOver(mouseX, mouseY)) { | |
| return super.mouseClicked(event, doubleClick); | |
| } | |
| for (SearchResultItem item : searchResults) { | |
| if (item.mouseClicked(event, doubleClick)) return true; | |
| } | |
| return true; | |
| } | |
| // Drag tracking — category buttons are renderableOnly so we handle them here | |
| for (Map.Entry<String, Button> entry : categoryButtons.entrySet()) { | |
| Button categoryButton = entry.getValue(); | |
| if (categoryButton.isMouseOver(mouseX, mouseY)) { | |
| draggedButton = categoryButton; | |
| initialClickX = mouseX; | |
| initialClickY = mouseY; | |
| dragOffsetX = mouseX - categoryButton.getX(); | |
| dragOffsetY = mouseY - categoryButton.getY(); | |
| return true; // consume — mouseReleased will toggle | |
| } | |
| } | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible() && dropdown.mouseClicked(event, doubleClick)) return true; | |
| } | |
| return super.mouseClicked(event, doubleClick); | |
| } | |
| @Override | |
| public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) { | |
| double mouseX = event.x(); | |
| double mouseY = event.y(); | |
| if (draggedButton != null) { | |
| double distance = Math.hypot(mouseX - initialClickX, mouseY - initialClickY); | |
| if (!isDragging && distance > dragThreshold) isDragging = true; | |
| if (isDragging) { | |
| int newX = (int)(mouseX - dragOffsetX); | |
| int newY = (int)(mouseY - dragOffsetY); | |
| String categoryKey = draggedButton.getMessage().getString().toLowerCase(); | |
| DropdownContainer dropdown = dropdowns.get(categoryKey); | |
| if (dropdown != null && dropdown.isVisible()) { | |
| int dropdownHeight = Math.min(dropdown.getDesiredHeight(), MAX_VISIBLE_ITEMS * BUTTON_HEIGHT); | |
| int maxY = this.height - BUTTON_HEIGHT - dropdownHeight - BORDER_PADDING; | |
| newX = Math.max(0, Math.min(this.width - BUTTON_WIDTH, newX)); | |
| newY = Math.max(0, Math.min(maxY, newY)); | |
| } else { | |
| newX = Math.max(-BUTTON_WIDTH, Math.min(this.width, newX)); | |
| newY = Math.max(-BUTTON_HEIGHT, Math.min(this.height, newY)); | |
| } | |
| draggedButton.setX(newX); | |
| draggedButton.setY(newY); | |
| if (dropdown != null && dropdown.isVisible()) dropdown.setPosition(newX, newY); | |
| return true; | |
| } | |
| } | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible() && dropdown.mouseDragged(mouseX, mouseY, event.button(), deltaX, deltaY)) return true; | |
| } | |
| return super.mouseDragged(event, deltaX, deltaY); | |
| } | |
| @Override | |
| public boolean mouseReleased(MouseButtonEvent event) { | |
| if (draggedButton != null) { | |
| if (!isDragging && event.button() == GLFW.GLFW_MOUSE_BUTTON_LEFT) { | |
| if (draggedButton.isMouseOver(event.x(), event.y())) { | |
| String categoryKey = draggedButton.getMessage().getString().toLowerCase(); | |
| toggleDropdown(categoryKey, draggedButton); | |
| } | |
| } | |
| if (isDragging) { | |
| // Save the new position after a completed drag | |
| String categoryKey = draggedButton.getMessage().getString().toLowerCase(); | |
| ButtonsConfig.getInstance().setPosition(categoryKey, | |
| draggedButton.getX(), draggedButton.getY()); | |
| ButtonsConfig.getInstance().save(); | |
| } | |
| draggedButton = null; | |
| isDragging = false; | |
| return true; | |
| } | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible() && dropdown.mouseReleased(event.x(), event.y(), event.button())) return true; | |
| } | |
| return super.mouseReleased(event); | |
| } | |
| @Override | |
| public boolean mouseScrolled(double mouseX, double mouseY, double hAmount, double vAmount) { | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible() && dropdown.mouseScrolled(mouseX, mouseY, hAmount, vAmount)) return true; | |
| } | |
| return super.mouseScrolled(mouseX, mouseY, hAmount, vAmount); | |
| } | |
| // ── Keyboard input ──────────────────────────────────────────── | |
| @Override | |
| public boolean keyPressed(KeyEvent event) { | |
| // ESC clears search first, then closes screen | |
| if (event.key() == GLFW.GLFW_KEY_ESCAPE && !searchQuery.isEmpty()) { | |
| searchBar.setValue(""); | |
| searchQuery = ""; | |
| searchResults.clear(); | |
| return true; | |
| } | |
| if (searchBar.isFocused() && searchBar.keyPressed(event)) return true; | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible() && dropdown.keyPressed(event)) return true; | |
| } | |
| return super.keyPressed(event); | |
| } | |
| @Override | |
| public boolean charTyped(CharacterEvent event) { | |
| if (searchBar.isFocused() && searchBar.charTyped(event)) return true; | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible() && dropdown.charTyped(event)) return true; | |
| } | |
| return super.charTyped(event); | |
| } | |
| // ── Rendering ───────────────────────────────────────────────── | |
| @Override | |
| public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { | |
| // transparent | |
| } | |
| @Override | |
| public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { | |
| super.extractRenderState(graphics, mouseX, mouseY, a); // renders searchBar automatically | |
| if (!searchQuery.isEmpty()) { | |
| int resultX = width / 2 - SEARCH_BAR_W / 2; | |
| int resultY = SEARCH_BAR_Y + SEARCH_BAR_H + 2; | |
| int panelW = SEARCH_BAR_W; | |
| if (searchResults.isEmpty()) { | |
| graphics.fill(resultX, resultY, resultX + panelW, resultY + BUTTON_HEIGHT, 0xAA000000); | |
| graphics.text(font, "§7No results found.", | |
| resultX + 4, resultY + (BUTTON_HEIGHT - 8) / 2, 0xFFAAAAAA); | |
| } else { | |
| int y = resultY; | |
| for (SearchResultItem item : searchResults) { | |
| item.setPosition(resultX, y, panelW); | |
| item.extractRenderState(graphics, mouseX, mouseY, a); | |
| y += BUTTON_HEIGHT; | |
| } | |
| } | |
| } else { | |
| updateDropdownPositions(); | |
| for (DropdownContainer dropdown : dropdowns.values()) { | |
| if (dropdown.isVisible()) dropdown.extractRenderState(graphics, mouseX, mouseY, a); | |
| } | |
| } | |
| // NOTE: do NOT call searchBar.extractRenderState manually — super already did it | |
| } | |
| // ── Helpers ─────────────────────────────────────────────────── | |
| private void toggleDropdown(String categoryKey, Button button) { | |
| DropdownContainer dropdown = dropdowns.get(categoryKey); | |
| if (dropdown != null) dropdown.toggle(); | |
| } | |
| private void updateDropdownPositions() { | |
| for (Map.Entry<String, DropdownContainer> entry : dropdowns.entrySet()) { | |
| DropdownContainer dropdown = entry.getValue(); | |
| if (dropdown.isVisible()) { | |
| Button button = categoryButtons.get(entry.getKey()); | |
| if (button != null) dropdown.setPosition(button.getX(), button.getY()); | |
| } | |
| } | |
| } | |
| private Screen getConfigScreen(String moduleName) { | |
| return switch (moduleName) { | |
| case "FriendGuard" -> new FriendGuardConfigScreen(AllyshipOptionsScreen.this); | |
| case "KillAura" -> new KillAuraConfigScreen(AllyshipOptionsScreen.this); | |
| case "WhomStruckMeLast" -> new WhomStruckMeLastScreen(AllyshipOptionsScreen.this); | |
| default -> null; | |
| }; | |
| } | |
| // ----------------------------------------------------------------------- | |
| // SearchResultItem — a single row in the search results panel | |
| // ----------------------------------------------------------------------- | |
| private class SearchResultItem { | |
| private final String name; | |
| private int posX, posY, rowW; | |
| SearchResultItem(String name) { this.name = name; } | |
| void setPosition(int x, int y, int w) { posX = x; posY = y; rowW = w; } | |
| boolean isMouseOver(double mx, double my) { | |
| return mx >= posX && mx <= posX + rowW | |
| && my >= posY && my <= posY + BUTTON_HEIGHT; | |
| } | |
| boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { | |
| if (!isMouseOver(event.x(), event.y())) return false; | |
| if (event.button() == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { | |
| Screen cfg = getConfigScreen(name); | |
| if (cfg != null) { client.setScreen(cfg); return true; } | |
| } | |
| // Left-click → toggle module | |
| Extension module = ModuleManager.getByName(name); | |
| if (module != null) { module.toggle(); return true; } | |
| return false; | |
| } | |
| void extractRenderState(GuiGraphicsExtractor graphics, | |
| int mouseX, int mouseY, float a) { | |
| boolean hovered = isMouseOver(mouseX, mouseY); | |
| graphics.fill(posX, posY, posX + rowW, posY + BUTTON_HEIGHT, | |
| hovered ? 0xCC333333 : 0xAA000000); | |
| Extension module = ModuleManager.getByName(name); | |
| int nameColor = (module != null && module.isEnabled()) ? 0xFF55FF55 : 0xFFAAAAAA; | |
| graphics.text(font, name, posX + 4, posY + (BUTTON_HEIGHT - 8) / 2, nameColor); | |
| // Category tag on the right | |
| if (module != null) { | |
| String cat = "§7[" + module.getCategory() + "]"; | |
| graphics.text(font, cat, | |
| posX + rowW - font.width(module.getCategory() + "[]") - 4, | |
| posY + (BUTTON_HEIGHT - 8) / 2, 0xFFAAAAAA); | |
| } | |
| } | |
| } | |
| // ----------------------------------------------------------------------- | |
| // DropdownContainer (unchanged from your original) | |
| // ----------------------------------------------------------------------- | |
| private class DropdownContainer { | |
| private final String displayName; | |
| private final List<DropdownItem> items; | |
| private boolean visible = false; | |
| private int posX, posY; | |
| private int scrollOffset = 0; | |
| DropdownContainer(String displayName, List<DropdownItem> items) { | |
| this.displayName = displayName; | |
| this.items = items; | |
| } | |
| public String getDisplayName() { return displayName; } | |
| public boolean isVisible() { return visible; } | |
| public int getHeight() { | |
| int maxContainer = MAX_VISIBLE_ITEMS * BUTTON_HEIGHT; | |
| int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); | |
| int maxBelowButton = screenHeight - posY - BORDER_PADDING; | |
| int maxHeight = Math.max(Math.min(maxContainer, maxBelowButton), BUTTON_HEIGHT); | |
| return Math.min(getDesiredHeight(), maxHeight); | |
| } | |
| // Add to DropdownContainer | |
| public int getWidth() { | |
| int maxW = DROPDOWN_WIDTH; | |
| for (DropdownItem item : items) { | |
| int textW = Minecraft.getInstance().font.width(item.getName()) + 8; // 4px padding each side | |
| if (textW > maxW) maxW = textW; | |
| } | |
| return maxW; | |
| } | |
| public int getDesiredHeight() { return calculateTotalHeight(); } | |
| public void toggle() { visible = !visible; updateItemPositions(); } | |
| public void setPosition(int x, int y) { | |
| this.posX = x; | |
| this.posY = y + BUTTON_HEIGHT; | |
| updateItemPositions(); | |
| } | |
| private void updateItemPositions() { | |
| int currentY = posY - scrollOffset; | |
| for (DropdownItem item : items) { | |
| boolean itemVis = currentY + item.getTotalHeight() > posY | |
| && currentY < posY + getHeight(); | |
| item.setVisible(itemVis); | |
| item.setPosition(posX, currentY); | |
| currentY += item.getTotalHeight(); | |
| if (item.hasSubOptions() && item.isSubOptionsVisible()) { | |
| for (DropdownItem sub : item.getSubOptions()) { | |
| boolean subVis = currentY + sub.getTotalHeight() > posY | |
| && currentY < posY + getHeight(); | |
| sub.setVisible(subVis); | |
| sub.setPosition(posX, currentY); | |
| currentY += sub.getTotalHeight(); | |
| } | |
| } | |
| } | |
| } | |
| public boolean mouseScrolled(double mouseX, double mouseY, double hAmount, double vAmount) { | |
| if (!visible) return false; | |
| if (mouseX < posX || mouseX > posX + getWidth() | |
| || mouseY < posY || mouseY > posY + getHeight()) return false; | |
| scrollOffset = Math.clamp( | |
| scrollOffset - (int)(vAmount * BUTTON_HEIGHT), | |
| 0, Math.max(0, calculateTotalHeight() - getHeight())); | |
| updateItemPositions(); | |
| return true; | |
| } | |
| public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { | |
| if (!visible) return false; | |
| if (event.x() < posX || event.x() > posX + getWidth() | |
| || event.y() < posY || event.y() > posY + getHeight()) return false; | |
| for (DropdownItem item : items) { | |
| if (item.isVisible() && item.mouseClicked(event, doubleClick)) return true; | |
| } | |
| return false; | |
| } | |
| public boolean mouseReleased(double mouseX, double mouseY, int button) { | |
| if (!visible) return false; | |
| for (DropdownItem item : items) { if (item.isVisible()) return true; } | |
| return false; | |
| } | |
| public boolean mouseDragged(double mouseX, double mouseY, int button, double dX, double dY) { | |
| if (!visible) return false; | |
| for (DropdownItem item : items) { if (item.isVisible()) return true; } | |
| return false; | |
| } | |
| public boolean keyPressed(KeyEvent event) { | |
| for (DropdownItem item : items) { | |
| if (item.isVisible() && item.keyPressed(event)) return true; | |
| } | |
| return false; | |
| } | |
| public boolean charTyped(CharacterEvent event) { | |
| for (DropdownItem item : items) { | |
| if (item.isVisible() && item.charTyped(event)) return true; | |
| } | |
| return false; | |
| } | |
| public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { | |
| if (!visible) return; | |
| int w = getWidth(); | |
| // Single unified background — no per-item fill stacking on top | |
| graphics.fill(posX, posY, posX + w, posY + getHeight(), 0xCC000000); | |
| for (DropdownItem item : items) { | |
| if (item.isVisible()) item.extractRenderState(graphics, mouseX, mouseY, a); | |
| } | |
| } | |
| private int calculateTotalHeight() { | |
| int h = 0; | |
| for (DropdownItem item : items) { | |
| h += item.getTotalHeight(); | |
| if (item.hasSubOptions() && item.isSubOptionsVisible()) { | |
| for (DropdownItem sub : item.getSubOptions()) h += sub.getTotalHeight(); | |
| } | |
| } | |
| return h; | |
| } | |
| } | |
| // ----------------------------------------------------------------------- | |
| // DropdownItem (unchanged from your original) | |
| // ----------------------------------------------------------------------- | |
| private class DropdownItem { | |
| private final String name; | |
| List<DropdownItem> subOptions; | |
| private boolean subOptionsVisible = false; | |
| private boolean visible = false; | |
| private int posX, posY; | |
| private EditBox textField; | |
| private boolean textFieldVisible = false; | |
| DropdownItem(String name, List<DropdownItem> subOptions, DropdownItem parent) { | |
| this.name = name; | |
| this.subOptions = subOptions; | |
| if (name.equals("CopyChat") || name.equals("sierra") || name.equals("Title")) { | |
| this.textField = new EditBox( | |
| font, posX, posY + BUTTON_HEIGHT, | |
| DROPDOWN_WIDTH, BUTTON_HEIGHT, | |
| Component.literal("Enter Target")); | |
| this.textField.setVisible(false); | |
| addWidget(this.textField); | |
| } | |
| } | |
| public boolean hasSubOptions() { return subOptions != null && !subOptions.isEmpty(); } | |
| public List<DropdownItem> getSubOptions() { return subOptions; } | |
| public void toggleSubOptions() { if (hasSubOptions()) subOptionsVisible = !subOptionsVisible; } | |
| public boolean isSubOptionsVisible() { return subOptionsVisible; } | |
| public boolean isVisible() { return visible; } | |
| public String getName() { return name; } | |
| public void setPosition(int x, int y) { | |
| posX = x; posY = y; | |
| if (textField != null) { textField.setX(x); textField.setY(y + BUTTON_HEIGHT); } | |
| } | |
| public void setVisible(boolean visible) { | |
| this.visible = visible; | |
| if (textField != null) textField.setVisible(textFieldVisible && visible); | |
| } | |
| public int getTotalHeight() { | |
| int h = BUTTON_HEIGHT; | |
| if (textFieldVisible && textField != null) h += BUTTON_HEIGHT; | |
| return h; | |
| } | |
| public boolean isMouseOver(double mouseX, double mouseY) { | |
| return mouseX >= posX && mouseX <= posX + DROPDOWN_WIDTH | |
| && mouseY >= posY && mouseY <= posY + getTotalHeight(); | |
| } | |
| public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) { | |
| if (textFieldVisible && textField != null && textField.isMouseOver(event.x(), event.y())) | |
| return textField.mouseClicked(event, doubleClick); | |
| if (hasSubOptions() && isSubOptionsVisible()) { | |
| for (DropdownItem sub : subOptions) { | |
| if (sub.mouseClicked(event, doubleClick)) return true; | |
| } | |
| } | |
| if (isMouseOver(event.x(), event.y())) { | |
| Extension module = ModuleManager.getByName(name); | |
| if (event.button() == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { | |
| Screen configScreen = getConfigScreen(name); | |
| if (configScreen != null) { client.setScreen(configScreen); return true; } | |
| } | |
| if (module != null) { module.toggle(); return true; } | |
| toggleSubOptions(); | |
| return true; | |
| } | |
| return false; | |
| } | |
| public boolean keyPressed(KeyEvent event) { | |
| if (textFieldVisible && textField != null && textField.isFocused()) { | |
| int key = event.key(); | |
| if (key == GLFW.GLFW_KEY_ENTER || key == GLFW.GLFW_KEY_KP_ENTER) { | |
| onSaveTextField(); return true; | |
| } | |
| return textField.keyPressed(event); | |
| } | |
| return false; | |
| } | |
| public boolean charTyped(CharacterEvent event) { | |
| if (textFieldVisible && textField != null && textField.isFocused()) | |
| return textField.charTyped(event); | |
| return false; | |
| } | |
| private void onSaveTextField() { | |
| String input = textField.getValue().trim(); | |
| if (!input.isEmpty()) { | |
| switch (name) { | |
| case "sierra" -> client.player.sendSystemMessage( | |
| Component.literal(ChatFormatting.GREEN + "Now staring at entity type: " + input)); | |
| } | |
| } else { | |
| client.player.sendSystemMessage( | |
| Component.literal(ChatFormatting.RED + "Please enter a valid target.")); | |
| } | |
| textFieldVisible = false; | |
| textField.setVisible(false); | |
| textField.setFocused(false); | |
| setFocused(null); | |
| for (DropdownContainer d : dropdowns.values()) d.updateItemPositions(); | |
| } | |
| private Screen getConfigScreen(String moduleName) { | |
| return switch (moduleName) { | |
| case "FriendGuard" -> new FriendGuardConfigScreen(AllyshipOptionsScreen.this); | |
| case "KillAura" -> new KillAuraConfigScreen(AllyshipOptionsScreen.this); | |
| case "WhomStruckMeLast" -> new WhomStruckMeLastScreen(AllyshipOptionsScreen.this); | |
| default -> null; | |
| }; | |
| } | |
| public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { | |
| int w = Minecraft.getInstance().font.width(name) + 8; | |
| w = Math.max(w, DROPDOWN_WIDTH); | |
| Extension module = ModuleManager.getByName(name); | |
| int color = (module != null && module.isEnabled()) ? 0xFF55FF55 : 0xFFAAAAAA; | |
| // ── Removed: graphics.fill() here — container panel is the background ── | |
| graphics.text(font, name, posX + 4, posY + (BUTTON_HEIGHT - 8) / 2, color); | |
| if (textFieldVisible && textField != null) | |
| textField.extractRenderState(graphics, mouseX, mouseY, a); | |
| if (hasSubOptions() && isSubOptionsVisible() && subOptions != null) | |
| for (DropdownItem sub : subOptions) | |
| if (sub.isVisible()) sub.extractRenderState(graphics, mouseX, mouseY, a); | |
| } | |
| } | |
| @Override | |
| public void onClose() { | |
| // Persist all current button positions before leaving | |
| for (Map.Entry<String, Button> entry : categoryButtons.entrySet()) { | |
| ButtonsConfig.getInstance().setPosition(entry.getKey(), | |
| entry.getValue().getX(), | |
| entry.getValue().getY()); | |
| } | |
| ButtonsConfig.getInstance().save(); | |
| super.onClose(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment