This commit is contained in:
BRanulf_Explode 2025-08-23 18:37:08 +08:00
parent f06eb27f06
commit 7a8834d003
7 changed files with 416 additions and 89 deletions

View File

@ -6,7 +6,7 @@ minecraft_version=1.21.4
yarn_mappings=1.21.4+build.8 yarn_mappings=1.21.4+build.8
loader_version=0.16.10 loader_version=0.16.10
# Mod Properties # Mod Properties
mod_version=1.14.514.003 mod_version=1.14.514.004
maven_group=org.branulf maven_group=org.branulf
archives_base_name=branulf_toolbox archives_base_name=branulf_toolbox
# Dependencies # Dependencies

View File

@ -4,6 +4,7 @@ import org.branulf.toolbox.autocrossbow.AutoCrossbowHandler;
import org.branulf.toolbox.crazylook.CrazyLookHandler; import org.branulf.toolbox.crazylook.CrazyLookHandler;
import org.branulf.toolbox.elytraboost.ElytraBoostCommon; import org.branulf.toolbox.elytraboost.ElytraBoostCommon;
import org.branulf.toolbox.elytraboost.ElytraBoostHandler; import org.branulf.toolbox.elytraboost.ElytraBoostHandler;
import org.branulf.toolbox.playerdetector.PlayerDetectorHandler;
import org.branulf.toolbox.scrafitiptyplus.ScrafitiptyPlusHandler; import org.branulf.toolbox.scrafitiptyplus.ScrafitiptyPlusHandler;
import me.shedaniel.autoconfig.AutoConfig; import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.serializer.GsonConfigSerializer; import me.shedaniel.autoconfig.serializer.GsonConfigSerializer;
@ -39,6 +40,7 @@ public class Main implements ClientModInitializer {
public ScrafitiptyPlusHandler scrafitiptyPlusHandler; public ScrafitiptyPlusHandler scrafitiptyPlusHandler;
public CrazyLookHandler crazyLookHandler; public CrazyLookHandler crazyLookHandler;
public ElytraBoostHandler elytraBoostHandler; public ElytraBoostHandler elytraBoostHandler;
public PlayerDetectorHandler playerDetectorHandler;
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
@ -58,6 +60,7 @@ public class Main implements ClientModInitializer {
scrafitiptyPlusHandler = new ScrafitiptyPlusHandler(config); scrafitiptyPlusHandler = new ScrafitiptyPlusHandler(config);
crazyLookHandler = new CrazyLookHandler(config); crazyLookHandler = new CrazyLookHandler(config);
elytraBoostHandler = new ElytraBoostHandler(config); elytraBoostHandler = new ElytraBoostHandler(config);
playerDetectorHandler = new PlayerDetectorHandler(config);
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(client -> {
while (openMainGuiKeyBinding.wasPressed()) { while (openMainGuiKeyBinding.wasPressed()) {
@ -70,6 +73,7 @@ public class Main implements ClientModInitializer {
crazyLookHandler.onClientTick(client); crazyLookHandler.onClientTick(client);
elytraBoostHandler.onClientTick(client); elytraBoostHandler.onClientTick(client);
scrafitiptyPlusHandler.onClientTick(client); scrafitiptyPlusHandler.onClientTick(client);
playerDetectorHandler.onClientTick(client);
}); });
new ElytraBoostCommon().onInitialize(); new ElytraBoostCommon().onInitialize();

View File

@ -1,5 +1,7 @@
package org.branulf.toolbox; package org.branulf.toolbox;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.util.math.MathHelper;
import org.branulf.toolbox.autocrossbow.AutoCrossbowMode; import org.branulf.toolbox.autocrossbow.AutoCrossbowMode;
import org.branulf.toolbox.scrafitiptyplus.ScrafitiptyPlusHandler; import org.branulf.toolbox.scrafitiptyplus.ScrafitiptyPlusHandler;
import me.shedaniel.autoconfig.AutoConfig; import me.shedaniel.autoconfig.AutoConfig;
@ -7,8 +9,10 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.client.gui.Element;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -19,8 +23,17 @@ public class MainScreen extends Screen {
private static final int BUTTON_HEIGHT = 20; private static final int BUTTON_HEIGHT = 20;
private static final int PADDING = 5; private static final int PADDING = 5;
private static final int SECTION_SPACING = 15; private static final int SECTION_SPACING = 15;
private static final int SCROLL_SPEED = 10;
private final List<ButtonWidget> modButtons = new ArrayList<>(); private double scrollY;
private int totalContentHeight;
private int scrollableAreaHeight;
private int scrollableAreaYStart;
private int scrollableAreaYEnd;
private final List<ClickableWidget> scrollableWidgets = new ArrayList<>();
private ButtonWidget configButton;
private TextFieldWidget playerDetectorRangeField;
public MainScreen(Text title) { public MainScreen(Text title) {
super(title); super(title);
@ -29,49 +42,69 @@ public class MainScreen extends Screen {
@Override @Override
protected void init() { protected void init() {
super.init(); super.init();
modButtons.clear(); this.clearChildren();
scrollableWidgets.clear();
scrollY = 0;
int currentY = 40; int titleAreaHeight = this.textRenderer.fontHeight + PADDING * 2;
int configButtonAreaHeight = BUTTON_HEIGHT + PADDING * 2;
scrollableAreaYStart = 10 + titleAreaHeight;
scrollableAreaYEnd = this.height - configButtonAreaHeight;
scrollableAreaHeight = scrollableAreaYEnd - scrollableAreaYStart;
int currentContentY = 30;
// 诸葛连弩 // 诸葛连弩
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.autocrossbow.title").formatted(Formatting.AQUA), currentY); currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.autocrossbow.title").formatted(Formatting.AQUA), currentContentY);
addAutoCrossbowButtons(currentY); currentContentY = addAutoCrossbowButtons(currentContentY);
currentY += (BUTTON_HEIGHT + PADDING) * 2 + SECTION_SPACING; currentContentY += SECTION_SPACING;
// Scrafitipty Plus // Scrafitipty Plus
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.title").formatted(Formatting.YELLOW), currentY); currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.title").formatted(Formatting.YELLOW), currentContentY);
addScrafitiptyPlusButtons(currentY); currentContentY = addScrafitiptyPlusButtons(currentContentY);
currentY += (BUTTON_HEIGHT + PADDING) + SECTION_SPACING; currentContentY += SECTION_SPACING;
// 视角 // 视角
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.crazylook.title").formatted(Formatting.LIGHT_PURPLE), currentY); currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.crazylook.title").formatted(Formatting.LIGHT_PURPLE), currentContentY);
addCrazyLookButtons(currentY); currentContentY = addCrazyLookButtons(currentContentY);
currentY += (BUTTON_HEIGHT + PADDING) + SECTION_SPACING; currentContentY += SECTION_SPACING;
// 鞘翅推进 // 鞘翅推进
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.elytraboost.title").formatted(Formatting.GOLD), currentY); currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.elytraboost.title").formatted(Formatting.GOLD), currentContentY);
addElytraBoostButtons(currentY); currentContentY = addElytraBoostButtons(currentContentY);
currentY += (BUTTON_HEIGHT + PADDING) + SECTION_SPACING; currentContentY += SECTION_SPACING;
this.addDrawableChild(ButtonWidget.builder( // 玩家探测器
currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.player_detector.title").formatted(Formatting.BLUE), currentContentY);
currentContentY = addPlayerDetectorButtons(currentContentY);
currentContentY += SECTION_SPACING;
totalContentHeight = currentContentY;
// 配置
configButton = ButtonWidget.builder(
Text.translatable("gui.branulf_toolbox.open_config"), Text.translatable("gui.branulf_toolbox.open_config"),
button -> MinecraftClient.getInstance().setScreen(AutoConfig.getConfigScreen(ModConfig.class, this).get())) button -> MinecraftClient.getInstance().setScreen(AutoConfig.getConfigScreen(ModConfig.class, this).get()))
.dimensions(this.width / 2 - BUTTON_WIDTH / 2, this.height - 30, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(this.width / 2 - BUTTON_WIDTH / 2, this.height - 30, BUTTON_WIDTH, BUTTON_HEIGHT)
.build()); .build();
this.addDrawableChild(configButton);
clampScroll();
updateButtonStates(); updateButtonStates();
} }
private int addSectionTitle(Text title, int y) { private int addSectionTitle(Text title, int currentContentY) {
ButtonWidget titleButton = ButtonWidget.builder(title, button -> {}) ButtonWidget titleButton = ButtonWidget.builder(title, button -> {})
.dimensions(this.width / 2 - BUTTON_WIDTH, y, BUTTON_WIDTH * 2, BUTTON_HEIGHT) .dimensions(this.width / 2 - BUTTON_WIDTH, currentContentY, BUTTON_WIDTH * 2, BUTTON_HEIGHT)
.build(); .build();
titleButton.active = false; titleButton.active = false;
this.addDrawableChild(titleButton); scrollableWidgets.add(titleButton);
return y + BUTTON_HEIGHT + PADDING; return currentContentY + BUTTON_HEIGHT + PADDING;
} }
private void addAutoCrossbowButtons(int startY) { // 诸葛连弩
private int addAutoCrossbowButtons(int currentContentY) {
ModConfig.AutoCrossbowConfig config = Main.getConfig().autocrossbow; ModConfig.AutoCrossbowConfig config = Main.getConfig().autocrossbow;
int centerX = this.width / 2; int centerX = this.width / 2;
int row1StartX = centerX - (BUTTON_WIDTH * 2 + PADDING) / 2; int row1StartX = centerX - (BUTTON_WIDTH * 2 + PADDING) / 2;
@ -84,10 +117,9 @@ public class MainScreen extends Screen {
Main.saveConfig(); Main.saveConfig();
updateButtonStates(); updateButtonStates();
}) })
.dimensions(row1StartX, startY, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(row1StartX, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(autoCrossbowEnabledOnButton); scrollableWidgets.add(autoCrossbowEnabledOnButton);
this.addDrawableChild(autoCrossbowEnabledOnButton);
ButtonWidget autoCrossbowEnabledOffButton = ButtonWidget.builder( ButtonWidget autoCrossbowEnabledOffButton = ButtonWidget.builder(
Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").formatted(Formatting.RED), Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").formatted(Formatting.RED),
@ -96,12 +128,11 @@ public class MainScreen extends Screen {
Main.saveConfig(); Main.saveConfig();
updateButtonStates(); updateButtonStates();
}) })
.dimensions(row1StartX + BUTTON_WIDTH + PADDING, startY, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(row1StartX + BUTTON_WIDTH + PADDING, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(autoCrossbowEnabledOffButton); scrollableWidgets.add(autoCrossbowEnabledOffButton);
this.addDrawableChild(autoCrossbowEnabledOffButton);
int row2Y = startY + BUTTON_HEIGHT + PADDING; int row2Y = currentContentY + BUTTON_HEIGHT + PADDING;
int row2StartX = centerX - (BUTTON_WIDTH * 3 + PADDING * 2) / 2; int row2StartX = centerX - (BUTTON_WIDTH * 3 + PADDING * 2) / 2;
// 模式选择 // 模式选择
@ -114,8 +145,7 @@ public class MainScreen extends Screen {
}) })
.dimensions(row2StartX, row2Y, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(row2StartX, row2Y, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(normalModeButton); scrollableWidgets.add(normalModeButton);
this.addDrawableChild(normalModeButton);
ButtonWidget rapidShootModeButton = ButtonWidget.builder( ButtonWidget rapidShootModeButton = ButtonWidget.builder(
Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot"), Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot"),
@ -126,8 +156,7 @@ public class MainScreen extends Screen {
}) })
.dimensions(row2StartX + BUTTON_WIDTH + PADDING, row2Y, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(row2StartX + BUTTON_WIDTH + PADDING, row2Y, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(rapidShootModeButton); scrollableWidgets.add(rapidShootModeButton);
this.addDrawableChild(rapidShootModeButton);
ButtonWidget rapidLoadModeButton = ButtonWidget.builder( ButtonWidget rapidLoadModeButton = ButtonWidget.builder(
Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load"), Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load"),
@ -138,12 +167,13 @@ public class MainScreen extends Screen {
}) })
.dimensions(row2StartX + 2 * (BUTTON_WIDTH + PADDING), row2Y, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(row2StartX + 2 * (BUTTON_WIDTH + PADDING), row2Y, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(rapidLoadModeButton); scrollableWidgets.add(rapidLoadModeButton);
this.addDrawableChild(rapidLoadModeButton);
return row2Y + BUTTON_HEIGHT + PADDING;
} }
// Scrafitipty // Scrafitipty
private void addScrafitiptyPlusButtons(int startY) { private int addScrafitiptyPlusButtons(int currentContentY) {
ScrafitiptyPlusHandler handler = Main.getInstance().scrafitiptyPlusHandler; ScrafitiptyPlusHandler handler = Main.getInstance().scrafitiptyPlusHandler;
ButtonWidget toggleServerButton = ButtonWidget.builder( ButtonWidget toggleServerButton = ButtonWidget.builder(
@ -152,14 +182,14 @@ public class MainScreen extends Screen {
handler.toggleWebSocketServer(); handler.toggleWebSocketServer();
updateButtonStates(); updateButtonStates();
}) })
.dimensions(this.width / 2 - BUTTON_WIDTH / 2, startY, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(this.width / 2 - BUTTON_WIDTH / 2, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(toggleServerButton); scrollableWidgets.add(toggleServerButton);
this.addDrawableChild(toggleServerButton); return currentContentY + BUTTON_HEIGHT + PADDING;
} }
// 视角 // 挂机
private void addCrazyLookButtons(int startY) { private int addCrazyLookButtons(int currentContentY) {
ModConfig.CrazyLookConfig config = Main.getConfig().crazyLook; ModConfig.CrazyLookConfig config = Main.getConfig().crazyLook;
ButtonWidget toggleCrazyLookButton = ButtonWidget.builder( ButtonWidget toggleCrazyLookButton = ButtonWidget.builder(
@ -169,14 +199,14 @@ public class MainScreen extends Screen {
Main.saveConfig(); Main.saveConfig();
updateButtonStates(); updateButtonStates();
}) })
.dimensions(this.width / 2 - BUTTON_WIDTH / 2, startY, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(this.width / 2 - BUTTON_WIDTH / 2, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(toggleCrazyLookButton); scrollableWidgets.add(toggleCrazyLookButton);
this.addDrawableChild(toggleCrazyLookButton); return currentContentY + BUTTON_HEIGHT + PADDING;
} }
// 鞘翅推进 // 鞘翅推进
private void addElytraBoostButtons(int startY) { private int addElytraBoostButtons(int currentContentY) {
ModConfig.ElytraBoostConfigPart config = Main.getConfig().elytraBoostConfig; ModConfig.ElytraBoostConfigPart config = Main.getConfig().elytraBoostConfig;
ButtonWidget toggleElytraBoostButton = ButtonWidget.builder( ButtonWidget toggleElytraBoostButton = ButtonWidget.builder(
@ -186,62 +216,251 @@ public class MainScreen extends Screen {
Main.saveConfig(); Main.saveConfig();
updateButtonStates(); updateButtonStates();
}) })
.dimensions(this.width / 2 - BUTTON_WIDTH / 2, startY, BUTTON_WIDTH, BUTTON_HEIGHT) .dimensions(this.width / 2 - BUTTON_WIDTH / 2, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build(); .build();
modButtons.add(toggleElytraBoostButton); scrollableWidgets.add(toggleElytraBoostButton);
this.addDrawableChild(toggleElytraBoostButton); return currentContentY + BUTTON_HEIGHT + PADDING;
}
// 玩家探测器
private int addPlayerDetectorButtons(int currentContentY) {
ModConfig.PlayerDetectorConfig config = Main.getConfig().playerDetector;
int centerX = this.width / 2;
int row1StartX = centerX - BUTTON_WIDTH / 2;
ButtonWidget toggleButton = ButtonWidget.builder(
Text.translatable("gui.branulf_toolbox.player_detector.toggle"),
button -> {
config.enabled = !config.enabled;
Main.saveConfig();
updateButtonStates();
})
.dimensions(row1StartX, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build();
scrollableWidgets.add(toggleButton);
int row2Y = currentContentY + BUTTON_HEIGHT + PADDING;
Text rangeLabelText = Text.translatable("gui.branulf_toolbox.player_detector.range_label");
int labelWidth = this.textRenderer.getWidth(rangeLabelText);
int totalWidth = BUTTON_WIDTH;
int fieldWidth = totalWidth - labelWidth - PADDING;
int startX = centerX - totalWidth / 2;
ButtonWidget rangeLabelButton = ButtonWidget.builder(rangeLabelText, button -> {})
.dimensions(startX, row2Y, labelWidth, BUTTON_HEIGHT)
.build();
rangeLabelButton.active = false;
scrollableWidgets.add(rangeLabelButton);
playerDetectorRangeField = new TextFieldWidget(
this.textRenderer,
startX + labelWidth + PADDING,
row2Y,
fieldWidth,
BUTTON_HEIGHT,
Text.translatable("gui.branulf_toolbox.player_detector.range_field")
);
playerDetectorRangeField.setMaxLength(2);
playerDetectorRangeField.setText(String.valueOf(config.detectionRange));
playerDetectorRangeField.setChangedListener(s -> {
try {
int value = Integer.parseInt(s);
value = MathHelper.clamp(value, 1, 128);
config.detectionRange = value;
Main.saveConfig();
playerDetectorRangeField.setSuggestion(null);
} catch (NumberFormatException e) {
playerDetectorRangeField.setSuggestion(Text.translatable("gui.branulf_toolbox.player_detector.range_invalid").getString());
}
});
scrollableWidgets.add(playerDetectorRangeField);
return row2Y + BUTTON_HEIGHT + PADDING;
} }
private void updateButtonStates() { private void updateButtonStates() {
ModConfig config = Main.getConfig(); ModConfig config = Main.getConfig();
ScrafitiptyPlusHandler scrafitiptyPlusHandler = Main.getInstance().scrafitiptyPlusHandler; ScrafitiptyPlusHandler scrafitiptyPlusHandler = Main.getInstance().scrafitiptyPlusHandler;
for (ButtonWidget button : modButtons) { for (ClickableWidget widget : scrollableWidgets) {
// 诸葛连弩 if (widget instanceof ButtonWidget button) {
if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_on").getString())) { // 诸葛连弩
button.active = !config.autocrossbow.enabled; if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_on").getString())) {
} else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").getString())) { button.active = !config.autocrossbow.enabled;
button.active = config.autocrossbow.enabled; } else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").getString())) {
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.normal").getString())) { button.active = config.autocrossbow.enabled;
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.NORMAL; } else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.normal").getString())) {
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.normal") button.active = config.autocrossbow.currentMode != AutoCrossbowMode.NORMAL;
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.NORMAL ? Formatting.GOLD : Formatting.WHITE)); button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.normal")
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot").getString())) { .formatted(config.autocrossbow.currentMode == AutoCrossbowMode.NORMAL ? Formatting.GOLD : Formatting.WHITE));
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_SHOOT; } else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot").getString())) {
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot") button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_SHOOT;
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.RAPID_FIRE_SHOOT ? Formatting.GOLD : Formatting.WHITE)); button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot")
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load").getString())) { .formatted(config.autocrossbow.currentMode == AutoCrossbowMode.RAPID_FIRE_SHOOT ? Formatting.GOLD : Formatting.WHITE));
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_LOAD; } else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load").getString())) {
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load") button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_LOAD;
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.RAPID_FIRE_LOAD ? Formatting.GOLD : Formatting.WHITE)); button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load")
} .formatted(config.autocrossbow.currentMode == AutoCrossbowMode.RAPID_FIRE_LOAD ? Formatting.GOLD : Formatting.WHITE));
// Scrafitipty }
else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.toggle_server").getString())) { // Scrafitipty
button.setMessage(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.toggle_server") else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.toggle_server").getString())) {
.append(Text.literal(" (" + (scrafitiptyPlusHandler.isServerRunning() ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")")) button.setMessage(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.toggle_server")
.formatted(scrafitiptyPlusHandler.isServerRunning() ? Formatting.GREEN : Formatting.RED)); .append(Text.literal(" (" + (scrafitiptyPlusHandler.isServerRunning() ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")"))
} .formatted(scrafitiptyPlusHandler.isServerRunning() ? Formatting.GREEN : Formatting.RED));
// 视角 }
else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.crazylook.toggle").getString())) { // 视角
button.setMessage(Text.translatable("gui.branulf_toolbox.crazylook.toggle") else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.crazylook.toggle").getString())) {
.append(Text.literal(" (" + (config.crazyLook.enabled ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")")) button.setMessage(Text.translatable("gui.branulf_toolbox.crazylook.toggle")
.formatted(config.crazyLook.enabled ? Formatting.GREEN : Formatting.RED)); .append(Text.literal(" (" + (config.crazyLook.enabled ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")"))
} .formatted(config.crazyLook.enabled ? Formatting.GREEN : Formatting.RED));
// 鞘翅推进 }
else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.elytraboost.toggle").getString())) { // 鞘翅推进
button.setMessage(Text.translatable("gui.branulf_toolbox.elytraboost.toggle") else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.elytraboost.toggle").getString())) {
.append(Text.literal(" (" + (config.elytraBoostConfig.modEnabled ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")")) button.setMessage(Text.translatable("gui.branulf_toolbox.elytraboost.toggle")
.formatted(config.elytraBoostConfig.modEnabled ? Formatting.GREEN : Formatting.RED)); .append(Text.literal(" (" + (config.elytraBoostConfig.modEnabled ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")"))
.formatted(config.elytraBoostConfig.modEnabled ? Formatting.GREEN : Formatting.RED));
}
// 玩家探测器
else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.player_detector.toggle").getString())) {
button.setMessage(Text.translatable("gui.branulf_toolbox.player_detector.toggle")
.append(Text.literal(" (" + (config.playerDetector.enabled ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")"))
.formatted(config.playerDetector.enabled ? Formatting.GREEN : Formatting.RED));
}
} }
} }
if (playerDetectorRangeField != null) {
playerDetectorRangeField.setText(String.valueOf(config.playerDetector.detectionRange));
}
} }
@Override @Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
this.renderBackground(context, mouseX, mouseY, delta); this.renderBackground(context, mouseX, mouseY, delta);
super.render(context, mouseX, mouseY, delta);
context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 15, 0xFFFFFF); context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 15, 0xFFFFFF);
context.enableScissor(0, scrollableAreaYStart, this.width, scrollableAreaHeight);
context.getMatrices().push();
context.getMatrices().translate(0, -scrollY, 0);
for (ClickableWidget widget : scrollableWidgets) {
if (widget.getY() + widget.getHeight() >= scrollY && widget.getY() <= scrollY + scrollableAreaHeight) {
widget.render(context, mouseX, (int)(mouseY + scrollY), delta);
}
}
context.getMatrices().pop();
context.disableScissor();
configButton.render(context, mouseX, mouseY, delta);
renderScrollbar(context);
}
private void clampScroll() {
scrollY = MathHelper.clamp(scrollY, 0, Math.max(0, totalContentHeight - scrollableAreaHeight));
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
if (mouseY >= scrollableAreaYStart && mouseY <= scrollableAreaYEnd) {
scrollY = MathHelper.clamp(scrollY - verticalAmount * SCROLL_SPEED, 0, Math.max(0, totalContentHeight - scrollableAreaHeight));
return true;
}
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (configButton.mouseClicked(mouseX, mouseY, button)) {
this.setFocused(configButton);
return true;
}
if (mouseY >= scrollableAreaYStart && mouseY <= scrollableAreaYEnd) {
double adjustedMouseY = mouseY + scrollY;
for (ClickableWidget widget : scrollableWidgets) {
if (widget.getY() + widget.getHeight() >= scrollY && widget.getY() <= scrollY + scrollableAreaHeight) {
if (widget.mouseClicked(mouseX, adjustedMouseY, button)) {
this.setFocused(widget);
return true;
}
}
}
}
return super.mouseClicked(mouseX, mouseY, button);
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (configButton.mouseReleased(mouseX, mouseY, button)) {
return true;
}
if (mouseY >= scrollableAreaYStart && mouseY <= scrollableAreaYEnd) {
double adjustedMouseY = mouseY + scrollY;
for (ClickableWidget widget : scrollableWidgets) {
if (widget.mouseReleased(mouseX, adjustedMouseY, button)) {
return true;
}
}
}
return super.mouseReleased(mouseX, mouseY, button);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
if (configButton.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) {
return true;
}
if (this.getFocused() instanceof ClickableWidget focusedWidget && scrollableWidgets.contains(focusedWidget)) {
double adjustedMouseY = mouseY + scrollY;
if (focusedWidget.mouseDragged(mouseX, adjustedMouseY, button, deltaX, deltaY)) {
return true;
}
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (this.getFocused() instanceof ClickableWidget focusedWidget && scrollableWidgets.contains(focusedWidget)) {
if (focusedWidget.keyPressed(keyCode, scanCode, modifiers)) {
return true;
}
}
return super.keyPressed(keyCode, scanCode, modifiers);
}
@Override
public boolean charTyped(char chr, int modifiers) {
if (this.getFocused() instanceof ClickableWidget focusedWidget && scrollableWidgets.contains(focusedWidget)) {
if (focusedWidget.charTyped(chr, modifiers)) {
return true;
}
}
return super.charTyped(chr, modifiers);
}
private void renderScrollbar(DrawContext context) {
if (totalContentHeight <= scrollableAreaHeight) {
return;
}
int scrollbarWidth = 6;
int scrollbarX = this.width - PADDING - scrollbarWidth;
int scrollbarYStart = scrollableAreaYStart;
int scrollbarHeight = scrollableAreaHeight;
double visibleRatio = (double) scrollableAreaHeight / totalContentHeight;
int thumbHeight = (int) (scrollbarHeight * visibleRatio);
thumbHeight = MathHelper.clamp(thumbHeight, 10, scrollbarHeight);
double scrollRatio = scrollY / (totalContentHeight - scrollableAreaHeight);
int thumbY = (int) (scrollbarYStart + (scrollbarHeight - thumbHeight) * scrollRatio);
context.fill(scrollbarX, scrollbarYStart, scrollbarX + scrollbarWidth, scrollbarYStart + scrollbarHeight, 0x80000000);
context.fill(scrollbarX + 1, thumbY, scrollbarX + scrollbarWidth - 1, thumbY + thumbHeight, 0xFFFFFFFF);
} }
@Override @Override

View File

@ -30,6 +30,11 @@ public class ModConfig implements ConfigData {
@ConfigEntry.Gui.TransitiveObject @ConfigEntry.Gui.TransitiveObject
public ElytraBoostConfigPart elytraBoostConfig = new ElytraBoostConfigPart(); public ElytraBoostConfigPart elytraBoostConfig = new ElytraBoostConfigPart();
// 玩家探测器
@ConfigEntry.Category("player_detector_settings")
@ConfigEntry.Gui.TransitiveObject
public PlayerDetectorConfig playerDetector = new PlayerDetectorConfig();
public static class AutoCrossbowConfig implements ConfigData { public static class AutoCrossbowConfig implements ConfigData {
@ -76,4 +81,17 @@ public class ModConfig implements ConfigData {
public boolean modEnabled = true; public boolean modEnabled = true;
} }
public static class PlayerDetectorConfig implements ConfigData {
@ConfigEntry.Gui.Tooltip(count = 0)
public boolean enabled = false;
@ConfigEntry.Gui.Tooltip(count = 1)
@ConfigEntry.BoundedDiscrete(min = 1, max = 64)
public int detectionRange = 16;
@ConfigEntry.Gui.Tooltip(count = 1)
@ConfigEntry.BoundedDiscrete(min = 1, max = 20)
public int alertFrequency = 1;
}
} }

View File

@ -0,0 +1,62 @@
package org.branulf.toolbox.playerdetector;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import org.branulf.toolbox.ModConfig;
public class PlayerDetectorHandler {
private final ModConfig config;
private int ticksSinceLastAlert = 0;
public PlayerDetectorHandler(ModConfig config) {
this.config = config;
}
public void onClientTick(MinecraftClient client) {
if (client.player == null || client.world == null || !config.playerDetector.enabled) {
return;
}
ModConfig.PlayerDetectorConfig pdConfig = config.playerDetector;
int ticksPerAlert = (int) (20.0f / pdConfig.alertFrequency);
if (ticksPerAlert <= 0) ticksPerAlert = 1;
ticksSinceLastAlert++;
if (ticksSinceLastAlert < ticksPerAlert) {
return;
}
ticksSinceLastAlert = 0;
double range = pdConfig.detectionRange;
Vec3d playerPos = client.player.getPos();
Box searchBox = new Box(
playerPos.x - range, playerPos.y - range, playerPos.z - range,
playerPos.x + range, playerPos.y + range, playerPos.z + range
);
boolean playerFound = client.world.getPlayers().stream()
.filter(p -> p != client.player)
.anyMatch(p -> p.squaredDistanceTo(playerPos) <= range * range);
if (playerFound) {
client.world.playSound(
client.player,
client.player.getX(),
client.player.getY(),
client.player.getZ(),
SoundEvents.BLOCK_NOTE_BLOCK_PLING.value(),
SoundCategory.MASTER,
1.0f,
2.0f
);
}
}
}

View File

@ -11,6 +11,7 @@
"text.autoconfig.branulf_toolbox.category.scrafitipty_plus_settings": "Scrafitipty Plus Settings", "text.autoconfig.branulf_toolbox.category.scrafitipty_plus_settings": "Scrafitipty Plus Settings",
"text.autoconfig.branulf_toolbox.category.crazylook_settings": "Crazy Look Settings", "text.autoconfig.branulf_toolbox.category.crazylook_settings": "Crazy Look Settings",
"text.autoconfig.branulf_toolbox.category.elytraboost_settings": "Elytra Boost Settings", "text.autoconfig.branulf_toolbox.category.elytraboost_settings": "Elytra Boost Settings",
"text.autoconfig.branulf_toolbox.category.player_detector_settings": "Player Detector Settings",
"gui.branulf_toolbox.autocrossbow.title": "Auto Crossbow", "gui.branulf_toolbox.autocrossbow.title": "Auto Crossbow",
"gui.branulf_toolbox.autocrossbow.enabled_on": "Enable Auto Crossbow", "gui.branulf_toolbox.autocrossbow.enabled_on": "Enable Auto Crossbow",
@ -65,5 +66,16 @@
"branulf_toolbox.elytraboost.notification.enabled": "§6[Elytra Boost] §fStatus: §aENABLED", "branulf_toolbox.elytraboost.notification.enabled": "§6[Elytra Boost] §fStatus: §aENABLED",
"branulf_toolbox.elytraboost.notification.disabled": "§6[Elytra Boost] §fStatus: §cDISABLED", "branulf_toolbox.elytraboost.notification.disabled": "§6[Elytra Boost] §fStatus: §cDISABLED",
"text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled": "Enable Elytra Boost", "text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled": "Enable Elytra Boost",
"text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled.@Tooltip": "Toggle the elytra boost functionality" "text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled.@Tooltip": "Toggle the elytra boost functionality",
"gui.branulf_toolbox.player_detector.title": "Player Detector",
"gui.branulf_toolbox.player_detector.toggle": "Toggle Player Detector",
"gui.branulf_toolbox.player_detector.range_label": "Range:",
"gui.branulf_toolbox.player_detector.range_field": "Detection Range",
"gui.branulf_toolbox.player_detector.range_invalid": "Invalid number (1-64)",
"text.autoconfig.branulf_toolbox.option.playerDetector.enabled": "Enable Player Detector",
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange": "Detection Range (Blocks)",
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange.@Tooltip": "The radius in blocks to detect other players (1-64).",
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency": "Alert Frequency (times/sec)",
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency.@Tooltip": "How many times per second to play the alert sound when a player is detected (1-20)."
} }

View File

@ -11,6 +11,7 @@
"text.autoconfig.branulf_toolbox.category.scrafitipty_plus_settings": "Scrafitipty Plus 设置", "text.autoconfig.branulf_toolbox.category.scrafitipty_plus_settings": "Scrafitipty Plus 设置",
"text.autoconfig.branulf_toolbox.category.crazylook_settings": "疯狂视角设置", "text.autoconfig.branulf_toolbox.category.crazylook_settings": "疯狂视角设置",
"text.autoconfig.branulf_toolbox.category.elytraboost_settings": "鞘翅推进优化设置", "text.autoconfig.branulf_toolbox.category.elytraboost_settings": "鞘翅推进优化设置",
"text.autoconfig.branulf_toolbox.category.player_detector_settings": "玩家探测器设置",
"gui.branulf_toolbox.autocrossbow.title": "诸葛连弩", "gui.branulf_toolbox.autocrossbow.title": "诸葛连弩",
"gui.branulf_toolbox.autocrossbow.enabled_on": "启用诸葛连弩", "gui.branulf_toolbox.autocrossbow.enabled_on": "启用诸葛连弩",
@ -65,5 +66,16 @@
"branulf_toolbox.elytraboost.notification.enabled": "§6[鞘翅推进优化] §f当前状态: §a启用", "branulf_toolbox.elytraboost.notification.enabled": "§6[鞘翅推进优化] §f当前状态: §a启用",
"branulf_toolbox.elytraboost.notification.disabled": "§6[鞘翅推进优化] §f当前状态: §c禁用", "branulf_toolbox.elytraboost.notification.disabled": "§6[鞘翅推进优化] §f当前状态: §c禁用",
"text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled": "启用鞘翅推进优化", "text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled": "启用鞘翅推进优化",
"text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled.@Tooltip": "是否启用鞘翅推进优化功能" "text.autoconfig.branulf_toolbox.option.elytraBoostConfig.modEnabled.@Tooltip": "是否启用鞘翅推进优化功能",
"gui.branulf_toolbox.player_detector.title": "玩家探测器",
"gui.branulf_toolbox.player_detector.toggle": "切换玩家探测器",
"gui.branulf_toolbox.player_detector.range_label": "范围",
"gui.branulf_toolbox.player_detector.range_field": "探测范围",
"gui.branulf_toolbox.player_detector.range_invalid": "无效数字 (1-64)",
"text.autoconfig.branulf_toolbox.option.playerDetector.enabled": "启用玩家探测器",
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange": "探测范围(方块)",
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange.@Tooltip": "探测其他玩家的半径范围1-64方块。",
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency": "提示频率(次/秒)",
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency.@Tooltip": "当探测到玩家时每秒播放提示音的次数1-20。"
} }