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
loader_version=0.16.10
# Mod Properties
mod_version=1.14.514.003
mod_version=1.14.514.004
maven_group=org.branulf
archives_base_name=branulf_toolbox
# Dependencies

View File

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

View File

@ -1,5 +1,7 @@
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.scrafitiptyplus.ScrafitiptyPlusHandler;
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.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.client.gui.Element;
import java.util.ArrayList;
import java.util.List;
@ -19,8 +23,17 @@ public class MainScreen extends Screen {
private static final int BUTTON_HEIGHT = 20;
private static final int PADDING = 5;
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) {
super(title);
@ -29,49 +42,69 @@ public class MainScreen extends Screen {
@Override
protected void 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);
addAutoCrossbowButtons(currentY);
currentY += (BUTTON_HEIGHT + PADDING) * 2 + SECTION_SPACING;
currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.autocrossbow.title").formatted(Formatting.AQUA), currentContentY);
currentContentY = addAutoCrossbowButtons(currentContentY);
currentContentY += SECTION_SPACING;
// Scrafitipty Plus
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.title").formatted(Formatting.YELLOW), currentY);
addScrafitiptyPlusButtons(currentY);
currentY += (BUTTON_HEIGHT + PADDING) + SECTION_SPACING;
currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.title").formatted(Formatting.YELLOW), currentContentY);
currentContentY = addScrafitiptyPlusButtons(currentContentY);
currentContentY += SECTION_SPACING;
// 视角
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.crazylook.title").formatted(Formatting.LIGHT_PURPLE), currentY);
addCrazyLookButtons(currentY);
currentY += (BUTTON_HEIGHT + PADDING) + SECTION_SPACING;
currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.crazylook.title").formatted(Formatting.LIGHT_PURPLE), currentContentY);
currentContentY = addCrazyLookButtons(currentContentY);
currentContentY += SECTION_SPACING;
// 鞘翅推进
currentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.elytraboost.title").formatted(Formatting.GOLD), currentY);
addElytraBoostButtons(currentY);
currentY += (BUTTON_HEIGHT + PADDING) + SECTION_SPACING;
currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.elytraboost.title").formatted(Formatting.GOLD), currentContentY);
currentContentY = addElytraBoostButtons(currentContentY);
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"),
button -> MinecraftClient.getInstance().setScreen(AutoConfig.getConfigScreen(ModConfig.class, this).get()))
.dimensions(this.width / 2 - BUTTON_WIDTH / 2, this.height - 30, BUTTON_WIDTH, BUTTON_HEIGHT)
.build());
.build();
this.addDrawableChild(configButton);
clampScroll();
updateButtonStates();
}
private int addSectionTitle(Text title, int y) {
private int addSectionTitle(Text title, int currentContentY) {
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();
titleButton.active = false;
this.addDrawableChild(titleButton);
return y + BUTTON_HEIGHT + PADDING;
scrollableWidgets.add(titleButton);
return currentContentY + BUTTON_HEIGHT + PADDING;
}
private void addAutoCrossbowButtons(int startY) {
// 诸葛连弩
private int addAutoCrossbowButtons(int currentContentY) {
ModConfig.AutoCrossbowConfig config = Main.getConfig().autocrossbow;
int centerX = this.width / 2;
int row1StartX = centerX - (BUTTON_WIDTH * 2 + PADDING) / 2;
@ -84,10 +117,9 @@ public class MainScreen extends Screen {
Main.saveConfig();
updateButtonStates();
})
.dimensions(row1StartX, startY, BUTTON_WIDTH, BUTTON_HEIGHT)
.dimensions(row1StartX, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build();
modButtons.add(autoCrossbowEnabledOnButton);
this.addDrawableChild(autoCrossbowEnabledOnButton);
scrollableWidgets.add(autoCrossbowEnabledOnButton);
ButtonWidget autoCrossbowEnabledOffButton = ButtonWidget.builder(
Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").formatted(Formatting.RED),
@ -96,12 +128,11 @@ public class MainScreen extends Screen {
Main.saveConfig();
updateButtonStates();
})
.dimensions(row1StartX + BUTTON_WIDTH + PADDING, startY, BUTTON_WIDTH, BUTTON_HEIGHT)
.dimensions(row1StartX + BUTTON_WIDTH + PADDING, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
.build();
modButtons.add(autoCrossbowEnabledOffButton);
this.addDrawableChild(autoCrossbowEnabledOffButton);
scrollableWidgets.add(autoCrossbowEnabledOffButton);
int row2Y = startY + BUTTON_HEIGHT + PADDING;
int row2Y = currentContentY + BUTTON_HEIGHT + PADDING;
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)
.build();
modButtons.add(normalModeButton);
this.addDrawableChild(normalModeButton);
scrollableWidgets.add(normalModeButton);
ButtonWidget rapidShootModeButton = ButtonWidget.builder(
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)
.build();
modButtons.add(rapidShootModeButton);
this.addDrawableChild(rapidShootModeButton);
scrollableWidgets.add(rapidShootModeButton);
ButtonWidget rapidLoadModeButton = ButtonWidget.builder(
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)
.build();
modButtons.add(rapidLoadModeButton);
this.addDrawableChild(rapidLoadModeButton);
scrollableWidgets.add(rapidLoadModeButton);
return row2Y + BUTTON_HEIGHT + PADDING;
}
// Scrafitipty
private void addScrafitiptyPlusButtons(int startY) {
private int addScrafitiptyPlusButtons(int currentContentY) {
ScrafitiptyPlusHandler handler = Main.getInstance().scrafitiptyPlusHandler;
ButtonWidget toggleServerButton = ButtonWidget.builder(
@ -152,14 +182,14 @@ public class MainScreen extends Screen {
handler.toggleWebSocketServer();
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();
modButtons.add(toggleServerButton);
this.addDrawableChild(toggleServerButton);
scrollableWidgets.add(toggleServerButton);
return currentContentY + BUTTON_HEIGHT + PADDING;
}
// 视角
private void addCrazyLookButtons(int startY) {
// 挂机
private int addCrazyLookButtons(int currentContentY) {
ModConfig.CrazyLookConfig config = Main.getConfig().crazyLook;
ButtonWidget toggleCrazyLookButton = ButtonWidget.builder(
@ -169,14 +199,14 @@ public class MainScreen extends Screen {
Main.saveConfig();
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();
modButtons.add(toggleCrazyLookButton);
this.addDrawableChild(toggleCrazyLookButton);
scrollableWidgets.add(toggleCrazyLookButton);
return currentContentY + BUTTON_HEIGHT + PADDING;
}
// 鞘翅推进
private void addElytraBoostButtons(int startY) {
private int addElytraBoostButtons(int currentContentY) {
ModConfig.ElytraBoostConfigPart config = Main.getConfig().elytraBoostConfig;
ButtonWidget toggleElytraBoostButton = ButtonWidget.builder(
@ -186,62 +216,251 @@ public class MainScreen extends Screen {
Main.saveConfig();
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();
modButtons.add(toggleElytraBoostButton);
this.addDrawableChild(toggleElytraBoostButton);
scrollableWidgets.add(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() {
ModConfig config = Main.getConfig();
ScrafitiptyPlusHandler scrafitiptyPlusHandler = Main.getInstance().scrafitiptyPlusHandler;
for (ButtonWidget button : modButtons) {
// 诸葛连弩
if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_on").getString())) {
button.active = !config.autocrossbow.enabled;
} else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").getString())) {
button.active = config.autocrossbow.enabled;
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.normal").getString())) {
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.NORMAL;
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.normal")
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.NORMAL ? Formatting.GOLD : Formatting.WHITE));
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot").getString())) {
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_SHOOT;
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot")
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.RAPID_FIRE_SHOOT ? Formatting.GOLD : Formatting.WHITE));
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load").getString())) {
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_LOAD;
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())) {
button.setMessage(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.toggle_server")
.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")
.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")
.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));
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;
} else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.autocrossbow.enabled_off").getString())) {
button.active = config.autocrossbow.enabled;
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.normal").getString())) {
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.NORMAL;
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.normal")
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.NORMAL ? Formatting.GOLD : Formatting.WHITE));
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot").getString())) {
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_SHOOT;
button.setMessage(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_shoot")
.formatted(config.autocrossbow.currentMode == AutoCrossbowMode.RAPID_FIRE_SHOOT ? Formatting.GOLD : Formatting.WHITE));
} else if (button.getMessage().getString().contains(Text.translatable("branulf_toolbox.autocrossbow.mode.rapid_load").getString())) {
button.active = config.autocrossbow.currentMode != AutoCrossbowMode.RAPID_FIRE_LOAD;
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())) {
button.setMessage(Text.translatable("gui.branulf_toolbox.scrafitipty_plus.toggle_server")
.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")
.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")
.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
public void render(DrawContext context, int mouseX, int mouseY, float 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.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

View File

@ -30,6 +30,11 @@ public class ModConfig implements ConfigData {
@ConfigEntry.Gui.TransitiveObject
public ElytraBoostConfigPart elytraBoostConfig = new ElytraBoostConfigPart();
// 玩家探测器
@ConfigEntry.Category("player_detector_settings")
@ConfigEntry.Gui.TransitiveObject
public PlayerDetectorConfig playerDetector = new PlayerDetectorConfig();
public static class AutoCrossbowConfig implements ConfigData {
@ -76,4 +81,17 @@ public class ModConfig implements ConfigData {
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.crazylook_settings": "Crazy Look 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.enabled_on": "Enable Auto Crossbow",
@ -65,5 +66,16 @@
"branulf_toolbox.elytraboost.notification.enabled": "§6[Elytra Boost] §fStatus: §aENABLED",
"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.@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.crazylook_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.enabled_on": "启用诸葛连弩",
@ -65,5 +66,16 @@
"branulf_toolbox.elytraboost.notification.enabled": "§6[鞘翅推进优化] §f当前状态: §a启用",
"branulf_toolbox.elytraboost.notification.disabled": "§6[鞘翅推进优化] §f当前状态: §c禁用",
"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。"
}