oi
This commit is contained in:
parent
7a8834d003
commit
8a64b024ef
@ -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.004
|
mod_version=1.14.514.005
|
||||||
maven_group=org.branulf
|
maven_group=org.branulf
|
||||||
archives_base_name=branulf_toolbox
|
archives_base_name=branulf_toolbox
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
@ -2,6 +2,7 @@ package org.branulf.toolbox;
|
|||||||
|
|
||||||
import org.branulf.toolbox.autocrossbow.AutoCrossbowHandler;
|
import org.branulf.toolbox.autocrossbow.AutoCrossbowHandler;
|
||||||
import org.branulf.toolbox.crazylook.CrazyLookHandler;
|
import org.branulf.toolbox.crazylook.CrazyLookHandler;
|
||||||
|
import org.branulf.toolbox.damagelogger.DamageLoggerHandler;
|
||||||
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.playerdetector.PlayerDetectorHandler;
|
||||||
@ -16,24 +17,28 @@ import net.minecraft.client.option.KeyBinding;
|
|||||||
import net.minecraft.client.util.InputUtil;
|
import net.minecraft.client.util.InputUtil;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class Main implements ClientModInitializer {
|
public class Main implements ClientModInitializer {
|
||||||
public static final String MOD_ID = "branulf_toolbox";
|
public static final String MOD_ID = "branulf_toolbox";
|
||||||
private static Main instance;
|
private static Main instance;
|
||||||
private static ModConfig config;
|
private static ModConfig config;
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
|
|
||||||
private static KeyBinding openMainGuiKeyBinding;
|
private static KeyBinding openMainGuiKeyBinding;
|
||||||
|
|
||||||
/** 该mod为多个mod组成的拼好mod
|
/** 该mod为多个mod组成的拼好mod
|
||||||
* 每个mod的处理程序均在单独的软件包(文件夹)中以便于维护
|
* 每个mod的处理程序均在单独的软件包(文件夹)中以便于维护。
|
||||||
* <p>
|
* <p>
|
||||||
* 为什么会存在这个mod?
|
* 为什么会存在这个mod?
|
||||||
* 因为作者制作了多个小mod,但是为了防止以后数量多导致的维护困难,作者决定将这些mod进行整合,并创建此mod
|
* 因为作者制作了多个小mod,但是为了防止以后数量多导致的维护困难,作者决定将这些mod进行整合,并创建此mod。
|
||||||
* 这不是个什么正经项目,只是作者想把一些小mod整合起来,方便管理
|
* 这不是个什么正经项目,只是作者想把一些小mod整合起来,方便管理。
|
||||||
* <p>
|
* <p>
|
||||||
* 我不确定以后我会不会做扩展包,就像carpet那样
|
* 我不确定以后我会不会做扩展包,就像carpet那样。
|
||||||
* 老实说,我能改掉一些开发中的坏习惯已经很累了,在这之前很多时候变量名我都是瞎写的,我有几个py的脚本写的全是屎山,从写jvav开始才改了我的部分坏习惯
|
* 老实说,我能改掉一些开发中的坏习惯已经很累了,在这之前很多时候变量名我都是瞎写的,我有几个py的脚本写的全是屎山,从写jvav开始才改了我的部分坏习惯。
|
||||||
* 同时,人工智能真好用(),哈哈哈。
|
* <p>
|
||||||
|
* 同时,人工智能真好用(之前很多部分都有依赖于AI,现在算是没之前那样了,之前真的啥都丢给AI,我是干啥的?不过话又说回来,没AI我也学不会这个),哈哈哈。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public AutoCrossbowHandler autoCrossbowHandler;
|
public AutoCrossbowHandler autoCrossbowHandler;
|
||||||
@ -41,6 +46,7 @@ public class Main implements ClientModInitializer {
|
|||||||
public CrazyLookHandler crazyLookHandler;
|
public CrazyLookHandler crazyLookHandler;
|
||||||
public ElytraBoostHandler elytraBoostHandler;
|
public ElytraBoostHandler elytraBoostHandler;
|
||||||
public PlayerDetectorHandler playerDetectorHandler;
|
public PlayerDetectorHandler playerDetectorHandler;
|
||||||
|
public DamageLoggerHandler damageLoggerHandler;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
@ -61,6 +67,7 @@ public class Main implements ClientModInitializer {
|
|||||||
crazyLookHandler = new CrazyLookHandler(config);
|
crazyLookHandler = new CrazyLookHandler(config);
|
||||||
elytraBoostHandler = new ElytraBoostHandler(config);
|
elytraBoostHandler = new ElytraBoostHandler(config);
|
||||||
playerDetectorHandler = new PlayerDetectorHandler(config);
|
playerDetectorHandler = new PlayerDetectorHandler(config);
|
||||||
|
damageLoggerHandler = new DamageLoggerHandler(config.damageLogger);
|
||||||
|
|
||||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||||
while (openMainGuiKeyBinding.wasPressed()) {
|
while (openMainGuiKeyBinding.wasPressed()) {
|
||||||
@ -74,6 +81,14 @@ public class Main implements ClientModInitializer {
|
|||||||
elytraBoostHandler.onClientTick(client);
|
elytraBoostHandler.onClientTick(client);
|
||||||
scrafitiptyPlusHandler.onClientTick(client);
|
scrafitiptyPlusHandler.onClientTick(client);
|
||||||
playerDetectorHandler.onClientTick(client);
|
playerDetectorHandler.onClientTick(client);
|
||||||
|
|
||||||
|
if (damageLoggerHandler != null) {
|
||||||
|
if (config.damageLogger.enabled && !damageLoggerHandler.isLogging()) {
|
||||||
|
damageLoggerHandler.startLogging();
|
||||||
|
} else if (!config.damageLogger.enabled && damageLoggerHandler.isLogging()) {
|
||||||
|
damageLoggerHandler.stopLogging();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new ElytraBoostCommon().onInitialize();
|
new ElytraBoostCommon().onInitialize();
|
||||||
|
@ -3,6 +3,7 @@ package org.branulf.toolbox;
|
|||||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import org.branulf.toolbox.autocrossbow.AutoCrossbowMode;
|
import org.branulf.toolbox.autocrossbow.AutoCrossbowMode;
|
||||||
|
import org.branulf.toolbox.damagelogger.DamageLoggerHandler;
|
||||||
import org.branulf.toolbox.scrafitiptyplus.ScrafitiptyPlusHandler;
|
import org.branulf.toolbox.scrafitiptyplus.ScrafitiptyPlusHandler;
|
||||||
import me.shedaniel.autoconfig.AutoConfig;
|
import me.shedaniel.autoconfig.AutoConfig;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
@ -35,6 +36,11 @@ public class MainScreen extends Screen {
|
|||||||
private ButtonWidget configButton;
|
private ButtonWidget configButton;
|
||||||
private TextFieldWidget playerDetectorRangeField;
|
private TextFieldWidget playerDetectorRangeField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用无法点击的按钮作为标题,是为了方便将所有UI元素(包括标题)都作为一个子类来管理,
|
||||||
|
* 尤其是在有滚动条的界面中,这样可以统一处理布局和渲染逻辑,绝对不是因为懒。
|
||||||
|
*/
|
||||||
|
|
||||||
public MainScreen(Text title) {
|
public MainScreen(Text title) {
|
||||||
super(title);
|
super(title);
|
||||||
}
|
}
|
||||||
@ -80,6 +86,11 @@ public class MainScreen extends Screen {
|
|||||||
currentContentY = addPlayerDetectorButtons(currentContentY);
|
currentContentY = addPlayerDetectorButtons(currentContentY);
|
||||||
currentContentY += SECTION_SPACING;
|
currentContentY += SECTION_SPACING;
|
||||||
|
|
||||||
|
// 伤害记录
|
||||||
|
currentContentY = addSectionTitle(Text.translatable("gui.branulf_toolbox.damage_logger.title").formatted(Formatting.RED), currentContentY);
|
||||||
|
currentContentY = addDamageLoggerButtons(currentContentY);
|
||||||
|
currentContentY += SECTION_SPACING;
|
||||||
|
|
||||||
totalContentHeight = currentContentY;
|
totalContentHeight = currentContentY;
|
||||||
|
|
||||||
// 配置
|
// 配置
|
||||||
@ -279,6 +290,50 @@ public class MainScreen extends Screen {
|
|||||||
return row2Y + BUTTON_HEIGHT + PADDING;
|
return row2Y + BUTTON_HEIGHT + PADDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 伤害记录
|
||||||
|
private int addDamageLoggerButtons(int currentContentY) {
|
||||||
|
DamageLoggerHandler handler = Main.getInstance().damageLoggerHandler;
|
||||||
|
ModConfig.DamageLoggerConfig config = Main.getConfig().damageLogger;
|
||||||
|
|
||||||
|
int centerX = this.width / 2;
|
||||||
|
int row1StartX = centerX - (BUTTON_WIDTH * 2 + PADDING) / 2;
|
||||||
|
|
||||||
|
// 启用
|
||||||
|
ButtonWidget damageLoggerOnButton = ButtonWidget.builder(
|
||||||
|
Text.translatable("gui.branulf_toolbox.damage_logger.enable").formatted(Formatting.GREEN),
|
||||||
|
button -> {
|
||||||
|
config.enabled = true;
|
||||||
|
Main.saveConfig();
|
||||||
|
updateButtonStates();
|
||||||
|
})
|
||||||
|
.dimensions(row1StartX, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
|
||||||
|
.build();
|
||||||
|
scrollableWidgets.add(damageLoggerOnButton);
|
||||||
|
|
||||||
|
// 禁用
|
||||||
|
ButtonWidget damageLoggerOffButton = ButtonWidget.builder(
|
||||||
|
Text.translatable("gui.branulf_toolbox.damage_logger.disable").formatted(Formatting.RED),
|
||||||
|
button -> {
|
||||||
|
config.enabled = false;
|
||||||
|
Main.saveConfig();
|
||||||
|
updateButtonStates();
|
||||||
|
})
|
||||||
|
.dimensions(row1StartX + BUTTON_WIDTH + PADDING, currentContentY, BUTTON_WIDTH, BUTTON_HEIGHT)
|
||||||
|
.build();
|
||||||
|
scrollableWidgets.add(damageLoggerOffButton);
|
||||||
|
|
||||||
|
// 打开文件夹
|
||||||
|
int row2Y = currentContentY + BUTTON_HEIGHT + PADDING;
|
||||||
|
ButtonWidget openLogFolderButton = ButtonWidget.builder(
|
||||||
|
Text.translatable("gui.branulf_toolbox.damage_logger.open_folder"),
|
||||||
|
button -> handler.openLogFolder())
|
||||||
|
.dimensions(centerX - BUTTON_WIDTH / 2, row2Y, BUTTON_WIDTH, BUTTON_HEIGHT)
|
||||||
|
.build();
|
||||||
|
scrollableWidgets.add(openLogFolderButton);
|
||||||
|
|
||||||
|
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;
|
||||||
@ -327,6 +382,12 @@ public class MainScreen extends Screen {
|
|||||||
.append(Text.literal(" (" + (config.playerDetector.enabled ? Text.translatable("branulf_toolbox.enabled").getString() : Text.translatable("branulf_toolbox.disabled").getString()) + ")"))
|
.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));
|
.formatted(config.playerDetector.enabled ? Formatting.GREEN : Formatting.RED));
|
||||||
}
|
}
|
||||||
|
// 伤害记录
|
||||||
|
else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.damage_logger.enable").getString())) {
|
||||||
|
button.active = !config.damageLogger.enabled;
|
||||||
|
} else if (button.getMessage().getString().contains(Text.translatable("gui.branulf_toolbox.damage_logger.disable").getString())) {
|
||||||
|
button.active = config.damageLogger.enabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (playerDetectorRangeField != null) {
|
if (playerDetectorRangeField != null) {
|
||||||
|
@ -35,8 +35,15 @@ public class ModConfig implements ConfigData {
|
|||||||
@ConfigEntry.Gui.TransitiveObject
|
@ConfigEntry.Gui.TransitiveObject
|
||||||
public PlayerDetectorConfig playerDetector = new PlayerDetectorConfig();
|
public PlayerDetectorConfig playerDetector = new PlayerDetectorConfig();
|
||||||
|
|
||||||
|
// 伤害记录
|
||||||
|
@ConfigEntry.Category("damage_logger_settings")
|
||||||
|
@ConfigEntry.Gui.TransitiveObject
|
||||||
|
public DamageLoggerConfig damageLogger = new DamageLoggerConfig();
|
||||||
|
|
||||||
|
|
||||||
|
// ————————————————————分割线————————————————————
|
||||||
|
|
||||||
|
// 诸葛连弩
|
||||||
public static class AutoCrossbowConfig implements ConfigData {
|
public static class AutoCrossbowConfig implements ConfigData {
|
||||||
@ConfigEntry.Gui.Tooltip(count = 0)
|
@ConfigEntry.Gui.Tooltip(count = 0)
|
||||||
public boolean enabled = false;
|
public boolean enabled = false;
|
||||||
@ -44,8 +51,15 @@ public class ModConfig implements ConfigData {
|
|||||||
@ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
|
@ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
|
||||||
@ConfigEntry.Gui.Tooltip(count = 0)
|
@ConfigEntry.Gui.Tooltip(count = 0)
|
||||||
public AutoCrossbowMode currentMode = AutoCrossbowMode.NORMAL;
|
public AutoCrossbowMode currentMode = AutoCrossbowMode.NORMAL;
|
||||||
|
|
||||||
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
|
public boolean compatibilityMode = false;
|
||||||
|
|
||||||
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
|
public boolean ultimateCompatibilityMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scrafitipty
|
||||||
public static class ScrafitiptyPlusConfigPart implements ConfigData {
|
public static class ScrafitiptyPlusConfigPart implements ConfigData {
|
||||||
@ConfigEntry.Gui.Tooltip(count = 1)
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
public int port = 8765;
|
public int port = 8765;
|
||||||
@ -68,6 +82,7 @@ public class ModConfig implements ConfigData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 挂机
|
||||||
public static class CrazyLookConfig implements ConfigData {
|
public static class CrazyLookConfig implements ConfigData {
|
||||||
@ConfigEntry.Gui.Tooltip(count = 0)
|
@ConfigEntry.Gui.Tooltip(count = 0)
|
||||||
public boolean enabled = false;
|
public boolean enabled = false;
|
||||||
@ -76,12 +91,14 @@ public class ModConfig implements ConfigData {
|
|||||||
public int shakeFrequency = 2;
|
public int shakeFrequency = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 鞘翅推进优化
|
||||||
public static class ElytraBoostConfigPart implements ConfigData {
|
public static class ElytraBoostConfigPart implements ConfigData {
|
||||||
@ConfigEntry.Gui.Tooltip(count = 1)
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
public boolean modEnabled = true;
|
public boolean modEnabled = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 玩家探测器
|
||||||
public static class PlayerDetectorConfig implements ConfigData {
|
public static class PlayerDetectorConfig implements ConfigData {
|
||||||
@ConfigEntry.Gui.Tooltip(count = 0)
|
@ConfigEntry.Gui.Tooltip(count = 0)
|
||||||
public boolean enabled = false;
|
public boolean enabled = false;
|
||||||
@ -94,4 +111,13 @@ public class ModConfig implements ConfigData {
|
|||||||
@ConfigEntry.BoundedDiscrete(min = 1, max = 20)
|
@ConfigEntry.BoundedDiscrete(min = 1, max = 20)
|
||||||
public int alertFrequency = 1;
|
public int alertFrequency = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 伤害记录
|
||||||
|
public static class DamageLoggerConfig implements ConfigData {
|
||||||
|
@ConfigEntry.Gui.Tooltip(count = 0)
|
||||||
|
public boolean enabled = false;
|
||||||
|
|
||||||
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
|
public boolean rememberState = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
|||||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.component.DataComponentTypes;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.item.CrossbowItem;
|
import net.minecraft.item.CrossbowItem;
|
||||||
@ -22,6 +23,7 @@ import net.minecraft.text.Text;
|
|||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AutoCrossbowHandler {
|
public class AutoCrossbowHandler {
|
||||||
|
|
||||||
@ -33,14 +35,19 @@ public class AutoCrossbowHandler {
|
|||||||
private long lastActionTime = 0;
|
private long lastActionTime = 0;
|
||||||
private static final long ACTION_COOLDOWN_MS = 50;
|
private static final long ACTION_COOLDOWN_MS = 50;
|
||||||
|
|
||||||
|
private boolean isCrossbowInternallyCharged = false;
|
||||||
|
private ItemStack lastHeldCrossbowStack = ItemStack.EMPTY;
|
||||||
|
|
||||||
public AutoCrossbowHandler(ModConfig mainConfig) {
|
public AutoCrossbowHandler(ModConfig mainConfig) {
|
||||||
this.config = mainConfig.autocrossbow;
|
this.config = mainConfig.autocrossbow;
|
||||||
registerCommands();
|
registerCommands();
|
||||||
|
Main.LOGGER.info("BRanulf的实用工具箱 - 诸葛连弩模块已加载!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClientTick(MinecraftClient client) {
|
public void onClientTick(MinecraftClient client) {
|
||||||
if (!config.enabled || client.player == null || client.interactionManager == null) {
|
if (!config.enabled || client.player == null || client.interactionManager == null) {
|
||||||
resetActionStates();
|
resetActionStates();
|
||||||
|
lastHeldCrossbowStack = ItemStack.EMPTY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +59,17 @@ public class AutoCrossbowHandler {
|
|||||||
|
|
||||||
if (!(stack.getItem() instanceof CrossbowItem)) {
|
if (!(stack.getItem() instanceof CrossbowItem)) {
|
||||||
resetActionStates();
|
resetActionStates();
|
||||||
|
lastHeldCrossbowStack = ItemStack.EMPTY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ItemStack.areItemsAndComponentsEqual(stack, lastHeldCrossbowStack)) {
|
||||||
|
isCrossbowInternallyCharged = false;
|
||||||
|
chargeProgress = 0;
|
||||||
|
lastHeldCrossbowStack = stack.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (config.currentMode) {
|
switch (config.currentMode) {
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
handleNormalMode(client, player, hand, stack);
|
handleNormalMode(client, player, hand, stack);
|
||||||
@ -74,27 +89,64 @@ public class AutoCrossbowHandler {
|
|||||||
wasRightClickPressed = false;
|
wasRightClickPressed = false;
|
||||||
chargeProgress = 0;
|
chargeProgress = 0;
|
||||||
lastActionTime = 0;
|
lastActionTime = 0;
|
||||||
|
isCrossbowInternallyCharged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCrossbowEffectivelyCharged(ItemStack stack) {
|
||||||
|
if (config.compatibilityMode) {
|
||||||
|
List<ItemStack> chargedProjectiles = stack.get(DataComponentTypes.CHARGED_PROJECTILES).getProjectiles();
|
||||||
|
return chargedProjectiles != null && !chargedProjectiles.isEmpty();
|
||||||
|
} else {
|
||||||
|
return CrossbowItem.isCharged(stack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleNormalMode(MinecraftClient client, PlayerEntity player, Hand hand, ItemStack stack) {
|
private void handleNormalMode(MinecraftClient client, PlayerEntity player, Hand hand, ItemStack stack) {
|
||||||
if (CrossbowItem.isCharged(stack) && isRightClickPressed) {
|
if (config.ultimateCompatibilityMode) {
|
||||||
client.interactionManager.interactItem(player, hand);
|
if (isRightClickPressed) {
|
||||||
return;
|
if (isCrossbowInternallyCharged) {
|
||||||
}
|
client.interactionManager.interactItem(player, hand);
|
||||||
|
isCrossbowInternallyCharged = false;
|
||||||
if (isRightClickPressed) {
|
chargeProgress = 0;
|
||||||
if (!player.isUsingItem()) {
|
} else {
|
||||||
client.interactionManager.interactItem(player, hand);
|
if (!player.isUsingItem()) {
|
||||||
chargeProgress = 0;
|
client.interactionManager.interactItem(player, hand);
|
||||||
} else if (player.getActiveHand() == hand) {
|
chargeProgress = 0;
|
||||||
chargeProgress++;
|
} else if (player.getActiveHand() == hand) {
|
||||||
int pullTime = CrossbowItem.getPullTime(stack, player);
|
chargeProgress++;
|
||||||
if (chargeProgress >= pullTime * 1.1f) {
|
int pullTime = CrossbowItem.getPullTime(stack, player);
|
||||||
client.interactionManager.stopUsingItem(player);
|
if (chargeProgress >= pullTime * 1.1f) {
|
||||||
|
client.interactionManager.stopUsingItem(player);
|
||||||
|
isCrossbowInternallyCharged = true;
|
||||||
|
chargeProgress = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wasRightClickPressed) {
|
||||||
|
chargeProgress = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (wasRightClickPressed) {
|
} else {
|
||||||
chargeProgress = 0;
|
if (isCrossbowEffectivelyCharged(stack) && isRightClickPressed) {
|
||||||
|
client.interactionManager.interactItem(player, hand);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRightClickPressed) {
|
||||||
|
if (!player.isUsingItem()) {
|
||||||
|
client.interactionManager.interactItem(player, hand);
|
||||||
|
chargeProgress = 0;
|
||||||
|
} else if (player.getActiveHand() == hand) {
|
||||||
|
chargeProgress++;
|
||||||
|
int pullTime = CrossbowItem.getPullTime(stack, player);
|
||||||
|
if (chargeProgress >= pullTime * 1.1f) {
|
||||||
|
client.interactionManager.stopUsingItem(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (wasRightClickPressed) {
|
||||||
|
chargeProgress = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +159,7 @@ public class AutoCrossbowHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CrossbowItem.isCharged(stack)) {
|
if (isCrossbowEffectivelyCharged(stack)) {
|
||||||
client.interactionManager.interactItem(player, hand);
|
client.interactionManager.interactItem(player, hand);
|
||||||
player.swingHand(hand);
|
player.swingHand(hand);
|
||||||
lastActionTime = System.currentTimeMillis();
|
lastActionTime = System.currentTimeMillis();
|
||||||
@ -118,7 +170,7 @@ public class AutoCrossbowHandler {
|
|||||||
swapToSlot(client, player, nextSlot);
|
swapToSlot(client, player, nextSlot);
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(Text.translatable("branulf_toolbox.autocrossbow.no_more_charged"), true);
|
player.sendMessage(Text.translatable("branulf_toolbox.autocrossbow.no_more_charged"), true);
|
||||||
config.currentMode = AutoCrossbowMode.NORMAL;
|
// config.currentMode = AutoCrossbowMode.NORMAL;
|
||||||
Main.saveConfig();
|
Main.saveConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,11 +194,11 @@ public class AutoCrossbowHandler {
|
|||||||
swapToSlot(client, player, nextSlot);
|
swapToSlot(client, player, nextSlot);
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(Text.translatable("branulf_toolbox.autocrossbow.no_more_uncharged"), true);
|
player.sendMessage(Text.translatable("branulf_toolbox.autocrossbow.no_more_uncharged"), true);
|
||||||
config.currentMode = AutoCrossbowMode.NORMAL;
|
// config.currentMode = AutoCrossbowMode.NORMAL;
|
||||||
Main.saveConfig();
|
Main.saveConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!CrossbowItem.isCharged(stack)) {
|
} else if (!isCrossbowEffectivelyCharged(stack)) {
|
||||||
if (System.currentTimeMillis() - lastActionTime < ACTION_COOLDOWN_MS) {
|
if (System.currentTimeMillis() - lastActionTime < ACTION_COOLDOWN_MS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -163,7 +215,7 @@ public class AutoCrossbowHandler {
|
|||||||
lastActionTime = System.currentTimeMillis();
|
lastActionTime = System.currentTimeMillis();
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(Text.translatable("branulf_toolbox.autocrossbow.no_more_uncharged"), true);
|
player.sendMessage(Text.translatable("branulf_toolbox.autocrossbow.no_more_uncharged"), true);
|
||||||
config.currentMode = AutoCrossbowMode.NORMAL;
|
// config.currentMode = AutoCrossbowMode.NORMAL;
|
||||||
Main.saveConfig();
|
Main.saveConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +226,7 @@ public class AutoCrossbowHandler {
|
|||||||
if (i == currentSelectedSlot) continue;
|
if (i == currentSelectedSlot) continue;
|
||||||
ItemStack stack = inventory.getStack(i);
|
ItemStack stack = inventory.getStack(i);
|
||||||
if (stack.getItem() instanceof CrossbowItem) {
|
if (stack.getItem() instanceof CrossbowItem) {
|
||||||
boolean isCharged = CrossbowItem.isCharged(stack);
|
boolean isCharged = isCrossbowEffectivelyCharged(stack);
|
||||||
if (chargedRequired == isCharged) {
|
if (chargedRequired == isCharged) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -183,7 +235,7 @@ public class AutoCrossbowHandler {
|
|||||||
for (int i = PlayerInventory.HOTBAR_SIZE; i < inventory.main.size(); i++) {
|
for (int i = PlayerInventory.HOTBAR_SIZE; i < inventory.main.size(); i++) {
|
||||||
ItemStack stack = inventory.getStack(i);
|
ItemStack stack = inventory.getStack(i);
|
||||||
if (stack.getItem() instanceof CrossbowItem) {
|
if (stack.getItem() instanceof CrossbowItem) {
|
||||||
boolean isCharged = CrossbowItem.isCharged(stack);
|
boolean isCharged = isCrossbowEffectivelyCharged(stack);
|
||||||
if (chargedRequired == isCharged) {
|
if (chargedRequired == isCharged) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,19 @@ import org.branulf.toolbox.ModConfig;
|
|||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
|
||||||
public class CrazyLookHandler {
|
public class CrazyLookHandler {
|
||||||
private ModConfig.CrazyLookConfig config;
|
private ModConfig.CrazyLookConfig config;
|
||||||
private int shakeCounter = 0;
|
private int shakeCounter = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 你来这里干啥?
|
||||||
|
* 我随便写的,我记得那天喝多了。
|
||||||
|
*/
|
||||||
|
|
||||||
public CrazyLookHandler(ModConfig mainConfig) {
|
public CrazyLookHandler(ModConfig mainConfig) {
|
||||||
this.config = mainConfig.crazyLook;
|
this.config = mainConfig.crazyLook;
|
||||||
|
Main.LOGGER.info("BRanulf的实用工具箱 - 夏季八看摇头晃脑挂机模块已加载!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClientTick(MinecraftClient client) {
|
public void onClientTick(MinecraftClient client) {
|
||||||
|
@ -0,0 +1,410 @@
|
|||||||
|
package org.branulf.toolbox.damagelogger;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||||
|
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.damage.DamageTypes;
|
||||||
|
import net.minecraft.entity.effect.StatusEffects;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.registry.tag.DamageTypeTags;
|
||||||
|
import net.minecraft.registry.tag.FluidTags;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import org.branulf.toolbox.Main;
|
||||||
|
import org.branulf.toolbox.ModConfig;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
public class DamageLoggerHandler {
|
||||||
|
private final ModConfig.DamageLoggerConfig config;
|
||||||
|
private boolean isLogging = false;
|
||||||
|
private String logFileName;
|
||||||
|
private FileWriter csvWriter;
|
||||||
|
private final Queue<DamageRecord> recordQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
|
private float lastKnownHealth = -1.0F;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 个人感觉,这里不需要进行本土化,所以这里直接使用中文。
|
||||||
|
* 主要还是懒,不想加太多键,也不想让语言文件乱七八糟。
|
||||||
|
* 部分方法使用了人工智能,因为我不喜欢繁琐的重复写这些乱七八糟的。
|
||||||
|
* <p>
|
||||||
|
* if ur Chinese not good, or u never learned Chinese, recommended to download Du####go.(or modify these method)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public DamageLoggerHandler(ModConfig.DamageLoggerConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
setupEventListeners();
|
||||||
|
Main.LOGGER.info("BRanulf的实用工具箱 - 伤害记录模块已加载!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupEventListeners() {
|
||||||
|
ServerLivingEntityEvents.AFTER_DAMAGE.register((entity, source, baseDamageTaken, damageTaken, blocked) -> {
|
||||||
|
if (entity instanceof PlayerEntity player && player == MinecraftClient.getInstance().player && isLogging) {
|
||||||
|
if (MinecraftClient.getInstance().isIntegratedServerRunning()) {
|
||||||
|
float newHealth = player.getHealth();
|
||||||
|
float originalHealth = newHealth + damageTaken;
|
||||||
|
recordDamage(source, damageTaken, originalHealth, newHealth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||||
|
if (client.player == null) {
|
||||||
|
lastKnownHealth = -1.0F;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLogging) {
|
||||||
|
float currentHealth = client.player.getHealth();
|
||||||
|
|
||||||
|
if (lastKnownHealth == -1.0F) {
|
||||||
|
lastKnownHealth = currentHealth;
|
||||||
|
} else if (currentHealth < lastKnownHealth) {
|
||||||
|
float damageAmount = lastKnownHealth - currentHealth;
|
||||||
|
if (!client.isIntegratedServerRunning()) {
|
||||||
|
recordClientSideDamage(damageAmount, lastKnownHealth, currentHealth);
|
||||||
|
}
|
||||||
|
lastKnownHealth = currentHealth;
|
||||||
|
} else if (currentHealth > lastKnownHealth) {
|
||||||
|
lastKnownHealth = currentHealth;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastKnownHealth = -1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLogging && !recordQueue.isEmpty()) {
|
||||||
|
processRecordQueue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||||
|
if (isLogging) {
|
||||||
|
stopLogging();
|
||||||
|
if (!config.rememberState) {
|
||||||
|
config.enabled = false;
|
||||||
|
Main.saveConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startLogging() {
|
||||||
|
if (isLogging) return;
|
||||||
|
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
if (client.player == null) {
|
||||||
|
if (client.inGameHud != null) {
|
||||||
|
client.inGameHud.getChatHud().addMessage(Text.literal("§c[伤害记录]§f 无法开始记录:玩家未加载或未进入世界。"));
|
||||||
|
} else {
|
||||||
|
System.err.println("[伤害记录] 无法开始记录:玩家未加载或未进入世界。");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client.isIntegratedServerRunning()) {
|
||||||
|
client.player.sendMessage(Text.literal("§e[伤害记录]§f 注意:此功能在专用服务器上只能通过客户端状态推断伤害,可能不完全准确。详细记录仅在单人/局域网游戏有效。"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
|
||||||
|
String timestamp = dateFormat.format(new Date());
|
||||||
|
logFileName = "伤害记录_" + timestamp + ".csv";
|
||||||
|
|
||||||
|
Path logDir = Paths.get("damage_logs");
|
||||||
|
if (!Files.exists(logDir)) {
|
||||||
|
Files.createDirectories(logDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path logFile = logDir.resolve(logFileName);
|
||||||
|
csvWriter = new FileWriter(logFile.toFile(), true);
|
||||||
|
|
||||||
|
csvWriter.write("时间,伤害来源,伤害类型,伤害数值,原血量,新血量,世界坐标,维度,原始伤害源数据\n");
|
||||||
|
csvWriter.flush();
|
||||||
|
|
||||||
|
isLogging = true;
|
||||||
|
lastKnownHealth = client.player.getHealth();
|
||||||
|
client.player.sendMessage(Text.literal("§a[伤害记录]§f 已开始记录伤害。"), false);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(Text.literal("§c[伤害记录]§f 启动失败: " + e.getMessage()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopLogging() {
|
||||||
|
if (!isLogging) return;
|
||||||
|
|
||||||
|
if (csvWriter != null) {
|
||||||
|
try {
|
||||||
|
processRecordQueue();
|
||||||
|
csvWriter.close();
|
||||||
|
csvWriter = null;
|
||||||
|
if (MinecraftClient.getInstance().player != null) {
|
||||||
|
MinecraftClient.getInstance().player.sendMessage(Text.literal("§a[伤害记录]§f 已停止记录伤害,日志已保存。"), false);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (MinecraftClient.getInstance().player != null) {
|
||||||
|
MinecraftClient.getInstance().player.sendMessage(Text.literal("§c[伤害记录]§f 停止失败: " + e.getMessage()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isLogging = false;
|
||||||
|
lastKnownHealth = -1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordDamage(DamageSource source, float amount, float originalHealth, float newHealth) {
|
||||||
|
if (MinecraftClient.getInstance().player == null) return;
|
||||||
|
|
||||||
|
String sourceName = getSourceName(source);
|
||||||
|
String damageType = getDamageType(source);
|
||||||
|
String rawSourceData = source.toString();
|
||||||
|
|
||||||
|
DamageRecord record = new DamageRecord(
|
||||||
|
new Date(),
|
||||||
|
sourceName,
|
||||||
|
damageType,
|
||||||
|
amount,
|
||||||
|
originalHealth,
|
||||||
|
newHealth,
|
||||||
|
MinecraftClient.getInstance().player.getBlockPos(),
|
||||||
|
MinecraftClient.getInstance().player.getWorld().getRegistryKey().getValue().toString(),
|
||||||
|
rawSourceData
|
||||||
|
);
|
||||||
|
recordQueue.add(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordClientSideDamage(float amount, float originalHealth, float newHealth) {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
if (client.player == null) return;
|
||||||
|
|
||||||
|
String sourceName = "未知来源 (客户端推断)";
|
||||||
|
String damageType = inferClientSideDamageType(client.player);
|
||||||
|
String rawSourceData = "客户端推断伤害,无原始DamageSource数据";
|
||||||
|
|
||||||
|
if (client.player.getLastAttacker() != null && client.player.age - client.player.getLastAttackedTime() < 20) {
|
||||||
|
sourceName = client.player.getLastAttacker().getName().getString() + " (客户端推断)";
|
||||||
|
damageType = "攻击伤害 (客户端推断)";
|
||||||
|
}
|
||||||
|
|
||||||
|
DamageRecord record = new DamageRecord(
|
||||||
|
new Date(),
|
||||||
|
sourceName,
|
||||||
|
damageType,
|
||||||
|
amount,
|
||||||
|
originalHealth,
|
||||||
|
newHealth,
|
||||||
|
client.player.getBlockPos(),
|
||||||
|
client.player.getWorld().getRegistryKey().getValue().toString(),
|
||||||
|
rawSourceData
|
||||||
|
);
|
||||||
|
recordQueue.add(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processRecordQueue() {
|
||||||
|
try {
|
||||||
|
while (!recordQueue.isEmpty()) {
|
||||||
|
DamageRecord record = recordQueue.poll();
|
||||||
|
if (record != null) {
|
||||||
|
String csvLine = String.format("%s,%s,%s,%.1f,%.1f,%.1f,%s,%s,%s\n",
|
||||||
|
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(record.timestamp),
|
||||||
|
escapeCsv(record.sourceName),
|
||||||
|
escapeCsv(record.damageType),
|
||||||
|
record.amount,
|
||||||
|
record.originalHealth,
|
||||||
|
record.newHealth,
|
||||||
|
escapeCsv(record.position.toString()),
|
||||||
|
escapeCsv(record.dimension),
|
||||||
|
escapeCsv(record.rawDamageSourceData)
|
||||||
|
);
|
||||||
|
csvWriter.write(csvLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
csvWriter.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (MinecraftClient.getInstance().player != null) {
|
||||||
|
MinecraftClient.getInstance().player.sendMessage(Text.literal("§c[伤害记录]§f 写入日志失败: " + e.getMessage()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String escapeCsv(String input) {
|
||||||
|
if (input == null) return "";
|
||||||
|
if (input.contains(",") || input.contains("\"") || input.contains("\n")) {
|
||||||
|
return "\"" + input.replace("\"", "\"\"") + "\"";
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLogging() {
|
||||||
|
return isLogging;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openLogFolder() {
|
||||||
|
Path logDir = Paths.get("damage_logs").toAbsolutePath();
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!Files.exists(logDir)) {
|
||||||
|
Files.createDirectories(logDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean opened = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
|
||||||
|
Desktop.getDesktop().open(logDir.toFile());
|
||||||
|
opened = true;
|
||||||
|
}
|
||||||
|
} catch (HeadlessException e) {
|
||||||
|
System.err.println("[伤害记录] 桌面API报告了无头环境。尝试替代方法。");
|
||||||
|
} catch (IOException | SecurityException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(Text.literal("§c[伤害记录]§f 尝试使用Java Desktop API打开日志文件夹失败: " + e.getMessage()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opened && System.getProperty("os.name").toLowerCase().contains("win")) {
|
||||||
|
try {
|
||||||
|
String command = "cmd /c start \"\" \"" + logDir.toAbsolutePath().toString() + "\"";
|
||||||
|
Process process = Runtime.getRuntime().exec(command);
|
||||||
|
opened = true;
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(Text.literal("§a[伤害记录]§f 已尝试使用Windows命令打开日志文件夹。"), false);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(Text.literal("§c[伤害记录]§f 尝试使用Windows命令打开日志文件夹失败: " + e.getMessage()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opened) {
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(Text.literal("§e[伤害记录]§f 自动打开日志文件夹失败。请手动前往: " + logDir.toAbsolutePath()), false);
|
||||||
|
}
|
||||||
|
System.err.println("[伤害记录] 无法自动打开日志文件夹。请手动打开: " + logDir.toAbsolutePath());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(Text.literal("§c[伤害记录]§f 创建日志文件夹失败: " + e.getMessage()), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSourceName(DamageSource source) {
|
||||||
|
if (source.getAttacker() != null) {
|
||||||
|
return source.getAttacker().getName().getString();
|
||||||
|
}
|
||||||
|
return source.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDamageType(DamageSource source) {
|
||||||
|
if (source.isOf(DamageTypes.OUT_OF_WORLD)) return "虚空伤害";
|
||||||
|
if (source.isOf(DamageTypes.BAD_RESPAWN_POINT)) return "错误重生点爆炸伤害";
|
||||||
|
if (source.isOf(DamageTypes.SONIC_BOOM)) return "音爆伤害";
|
||||||
|
if (source.isOf(DamageTypes.MACE_SMASH)) return "狼牙棒猛击伤害";
|
||||||
|
if (source.isOf(DamageTypes.WITHER)) return "凋零伤害";
|
||||||
|
if (source.isOf(DamageTypes.MAGIC) || source.isOf(DamageTypes.INDIRECT_MAGIC)) return "魔法伤害";
|
||||||
|
if (source.isOf(DamageTypes.DRAGON_BREATH)) return "龙息伤害";
|
||||||
|
if (source.isOf(DamageTypes.STARVE)) return "饥饿伤害";
|
||||||
|
if (source.isOf(DamageTypes.DROWN)) return "溺水伤害";
|
||||||
|
if (source.isOf(DamageTypes.FREEZE)) return "冰冻伤害";
|
||||||
|
if (source.isOf(DamageTypes.LIGHTNING_BOLT)) return "闪电伤害";
|
||||||
|
if (source.isOf(DamageTypes.THORNS)) return "荆棘伤害";
|
||||||
|
if (source.isOf(DamageTypes.CACTUS)) return "仙人掌伤害";
|
||||||
|
if (source.isOf(DamageTypes.SWEET_BERRY_BUSH)) return "甜浆果丛伤害";
|
||||||
|
if (source.isOf(DamageTypes.STALAGMITE)) return "钟乳石伤害";
|
||||||
|
if (source.isOf(DamageTypes.FLY_INTO_WALL)) return "撞墙伤害";
|
||||||
|
if (source.isOf(DamageTypes.IN_WALL)) return "窒息伤害 (卡墙)";
|
||||||
|
if (source.isOf(DamageTypes.CRAMMING)) return "挤压伤害";
|
||||||
|
if (source.isOf(DamageTypes.DRY_OUT)) return "脱水伤害";
|
||||||
|
if (source.isOf(DamageTypes.HOT_FLOOR)) return "热地板伤害";
|
||||||
|
if (source.isOf(DamageTypes.FALLING_ANVIL) || source.isOf(DamageTypes.FALLING_STALACTITE) || source.isOf(DamageTypes.FALLING_BLOCK)) return "掉落方块伤害";
|
||||||
|
|
||||||
|
if (source.isOf(DamageTypes.IN_FIRE) || source.isOf(DamageTypes.ON_FIRE) || source.isOf(DamageTypes.LAVA) || source.isOf(DamageTypes.CAMPFIRE) || source.isOf(DamageTypes.FIREBALL) || source.isOf(DamageTypes.UNATTRIBUTED_FIREBALL)) return "火焰/燃烧伤害";
|
||||||
|
|
||||||
|
if (source.isOf(DamageTypes.ARROW) || source.isOf(DamageTypes.TRIDENT) || source.isOf(DamageTypes.MOB_PROJECTILE) ||
|
||||||
|
source.isOf(DamageTypes.SPIT) || source.isOf(DamageTypes.WIND_CHARGE) || source.isOf(DamageTypes.FIREWORKS) ||
|
||||||
|
source.isOf(DamageTypes.WITHER_SKULL) || source.isOf(DamageTypes.THROWN) || source.isOf(DamageTypes.ENDER_PEARL)) return "弹射物伤害";
|
||||||
|
|
||||||
|
if (source.isOf(DamageTypes.EXPLOSION) || source.isOf(DamageTypes.PLAYER_EXPLOSION)) return "爆炸伤害";
|
||||||
|
|
||||||
|
if (source.isOf(DamageTypes.MOB_ATTACK) || source.isOf(DamageTypes.PLAYER_ATTACK) || source.isOf(DamageTypes.MOB_ATTACK_NO_AGGRO) || source.isOf(DamageTypes.STING)) return "近战/攻击伤害";
|
||||||
|
|
||||||
|
if (source.isIn(DamageTypeTags.IS_PROJECTILE)) return "弹射物伤害 (通用)";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_EXPLOSION)) return "爆炸伤害 (通用)";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_FIRE)) return "火焰伤害 (通用)";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_FALL)) return "坠落伤害";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_DROWNING)) return "溺水伤害 (通用)";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_FREEZING)) return "冰冻伤害 (通用)";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_LIGHTNING)) return "闪电伤害 (通用)";
|
||||||
|
if (source.isIn(DamageTypeTags.IS_PLAYER_ATTACK)) return "玩家攻击伤害";
|
||||||
|
if (source.isIn(DamageTypeTags.MACE_SMASH)) return "狼牙棒猛击伤害 (通用)";
|
||||||
|
|
||||||
|
if (source.isOf(DamageTypes.GENERIC)) return "环境伤害 (通用)";
|
||||||
|
if (source.isOf(DamageTypes.GENERIC_KILL)) return "通用击杀伤害";
|
||||||
|
if (source.isOf(DamageTypes.OUTSIDE_BORDER)) return "世界边界伤害";
|
||||||
|
if (source.isOf(DamageTypes.FALL)) return "坠落伤害 (通用)";
|
||||||
|
|
||||||
|
if (source.getAttacker() != null) {
|
||||||
|
return "攻击伤害 (未分类)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "其他伤害 (" + source.getName() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String inferClientSideDamageType(PlayerEntity player) {
|
||||||
|
if (player.isOnFire()) return "火焰/燃烧伤害 (推断)";
|
||||||
|
if (player.isInLava()) return "岩浆伤害 (推断)";
|
||||||
|
if (player.isSubmergedIn(FluidTags.WATER) && player.getAir() == 0) return "溺水伤害 (推断)";
|
||||||
|
if (player.hasStatusEffect(StatusEffects.POISON)) return "中毒伤害 (推断)";
|
||||||
|
if (player.hasStatusEffect(StatusEffects.WITHER)) return "凋零伤害 (推断)";
|
||||||
|
|
||||||
|
return "未知伤害 (客户端推断)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DamageRecord {
|
||||||
|
Date timestamp;
|
||||||
|
String sourceName;
|
||||||
|
String damageType;
|
||||||
|
float amount;
|
||||||
|
float originalHealth;
|
||||||
|
float newHealth;
|
||||||
|
BlockPos position;
|
||||||
|
String dimension;
|
||||||
|
String rawDamageSourceData;
|
||||||
|
|
||||||
|
public DamageRecord(Date timestamp, String sourceName, String damageType, float amount,
|
||||||
|
float originalHealth, float newHealth,
|
||||||
|
BlockPos position, String dimension, String rawDamageSourceData) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.sourceName = sourceName;
|
||||||
|
this.damageType = damageType;
|
||||||
|
this.amount = amount;
|
||||||
|
this.originalHealth = originalHealth;
|
||||||
|
this.newHealth = newHealth;
|
||||||
|
this.position = position;
|
||||||
|
this.dimension = dimension;
|
||||||
|
this.rawDamageSourceData = rawDamageSourceData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,15 +2,11 @@ package org.branulf.toolbox.elytraboost;
|
|||||||
|
|
||||||
import org.branulf.toolbox.Main;
|
import org.branulf.toolbox.Main;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ElytraBoostCommon implements ModInitializer {
|
public class ElytraBoostCommon implements ModInitializer {
|
||||||
public static final String MOD_ID = Main.MOD_ID;
|
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
LOGGER.info("BRanulf的实用工具箱 - 鞘翅推进优化模块已加载!");
|
Main.LOGGER.info("BRanulf的实用工具箱 - 鞘翅推进优化模块已加载!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,20 @@ import net.minecraft.sound.SoundCategory;
|
|||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.util.math.Box;
|
import net.minecraft.util.math.Box;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.branulf.toolbox.Main;
|
||||||
import org.branulf.toolbox.ModConfig;
|
import org.branulf.toolbox.ModConfig;
|
||||||
|
|
||||||
public class PlayerDetectorHandler {
|
public class PlayerDetectorHandler {
|
||||||
private final ModConfig config;
|
private final ModConfig config;
|
||||||
private int ticksSinceLastAlert = 0;
|
private int ticksSinceLastAlert = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 我已经不止一次在服务器挂机被偷屁股了。
|
||||||
|
*/
|
||||||
|
|
||||||
public PlayerDetectorHandler(ModConfig config) {
|
public PlayerDetectorHandler(ModConfig config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
Main.LOGGER.info("BRanulf的实用工具箱 - 玩家检测模块已加载!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClientTick(MinecraftClient client) {
|
public void onClientTick(MinecraftClient client) {
|
||||||
|
@ -10,7 +10,7 @@ import org.apache.logging.log4j.LogManager;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
public class ScrafitiptyPlusDebug {
|
public class ScrafitiptyPlusDebug {
|
||||||
private static Logger logger = LogManager.getLogger(Main.MOD_ID);
|
public static Logger logger = LogManager.getLogger(Main.MOD_ID);
|
||||||
|
|
||||||
public static void setLogger(String modId) {
|
public static void setLogger(String modId) {
|
||||||
logger = LogManager.getLogger(modId);
|
logger = LogManager.getLogger(modId);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.branulf.toolbox.scrafitiptyplus;
|
package org.branulf.toolbox.scrafitiptyplus;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.branulf.toolbox.Main;
|
import org.branulf.toolbox.Main;
|
||||||
import org.branulf.toolbox.ModConfig;
|
import org.branulf.toolbox.ModConfig;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@ -23,6 +25,7 @@ import java.util.*;
|
|||||||
|
|
||||||
public class ScrafitiptyPlusHandler {
|
public class ScrafitiptyPlusHandler {
|
||||||
public static final String MOD_ID = Main.MOD_ID;
|
public static final String MOD_ID = Main.MOD_ID;
|
||||||
|
private static Logger LOGGER = ScrafitiptyPlusDebug.logger;
|
||||||
private ModConfig.ScrafitiptyPlusConfigPart config;
|
private ModConfig.ScrafitiptyPlusConfigPart config;
|
||||||
|
|
||||||
private ScriptWebSocketServer webSocketServerInstance;
|
private ScriptWebSocketServer webSocketServerInstance;
|
||||||
@ -35,11 +38,13 @@ public class ScrafitiptyPlusHandler {
|
|||||||
public ScrafitiptyPlusHandler(ModConfig mainConfig) {
|
public ScrafitiptyPlusHandler(ModConfig mainConfig) {
|
||||||
this.config = mainConfig.scrafitiptyPlus;
|
this.config = mainConfig.scrafitiptyPlus;
|
||||||
ScrafitiptyPlusDebug.setLogger(Main.MOD_ID);
|
ScrafitiptyPlusDebug.setLogger(Main.MOD_ID);
|
||||||
ScrafitiptyPlusDebug.info("Scrafitipty Plus Mod 正在初始化...");
|
ScrafitiptyPlusDebug.info("Scrafitipty Plus 模块正在初始化...");
|
||||||
|
|
||||||
if (this.config.enableMode == ModConfig.ScrafitiptyPlusConfigPart.WebSocketEnableMode.ALWAYS) {
|
if (this.config.enableMode == ModConfig.ScrafitiptyPlusConfigPart.WebSocketEnableMode.ALWAYS) {
|
||||||
startWebSocketServer();
|
startWebSocketServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGGER.info("BRanulf的实用工具箱 - Scrafitipty Plus(Websocket控制)模块已加载!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isServerRunning() {
|
public boolean isServerRunning() {
|
||||||
|
@ -6,12 +6,15 @@
|
|||||||
"branulf_toolbox.enabled": "Enabled",
|
"branulf_toolbox.enabled": "Enabled",
|
||||||
"branulf_toolbox.disabled": "Disabled",
|
"branulf_toolbox.disabled": "Disabled",
|
||||||
|
|
||||||
|
"branulf_toolbox.commit": "im really frustrated, why i cant use comments on JSON!",
|
||||||
|
|
||||||
"text.autoconfig.branulf_toolbox.title": "BRanulf's Toolbox Configuration",
|
"text.autoconfig.branulf_toolbox.title": "BRanulf's Toolbox Configuration",
|
||||||
"text.autoconfig.branulf_toolbox.category.autocrossbow_settings": "Auto Crossbow Settings",
|
"text.autoconfig.branulf_toolbox.category.autocrossbow_settings": "Auto Crossbow Settings",
|
||||||
"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",
|
"text.autoconfig.branulf_toolbox.category.player_detector_settings": "Player Detector Settings",
|
||||||
|
"text.autoconfig.branulf_toolbox.category.damage_logger_settings": "Damage Logger 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",
|
||||||
@ -29,6 +32,10 @@
|
|||||||
"branulf_toolbox.autocrossbow.command.invalid_mode": "Invalid mode: '%s'. Available modes: normal, rapid_shoot, rapid_load.",
|
"branulf_toolbox.autocrossbow.command.invalid_mode": "Invalid mode: '%s'. Available modes: normal, rapid_shoot, rapid_load.",
|
||||||
"text.autoconfig.branulf_toolbox.option.autocrossbow.enabled": "Enable Auto Crossbow",
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.enabled": "Enable Auto Crossbow",
|
||||||
"text.autoconfig.branulf_toolbox.option.autocrossbow.currentMode": "Current Mode",
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.currentMode": "Current Mode",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.compatibilityMode": "Compatibility Mode",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.compatibilityMode.@Tooltip": "If enabled, a crossbow with any projectile loaded will be treated as charged, regardless of its visual state. Useful for servers where loaded crossbows don't visually update.",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.ultimateCompatibilityMode": "Ultimate Compatibility Mode (Normal Mode Only)",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.ultimateCompatibilityMode.@Tooltip": "Overrides all other crossbow charge checks in Normal Mode. If charging is complete, it's considered charged. If just fired, it's uncharged. Ignores actual item state.",
|
||||||
|
|
||||||
"gui.branulf_toolbox.scrafitipty_plus.title": "Scrafitipty Plus (WebSocket)",
|
"gui.branulf_toolbox.scrafitipty_plus.title": "Scrafitipty Plus (WebSocket)",
|
||||||
"gui.branulf_toolbox.scrafitipty_plus.toggle_server": "Toggle WebSocket Server",
|
"gui.branulf_toolbox.scrafitipty_plus.toggle_server": "Toggle WebSocket Server",
|
||||||
@ -77,5 +84,13 @@
|
|||||||
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange": "Detection Range (Blocks)",
|
"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.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": "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)."
|
"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).",
|
||||||
|
|
||||||
|
"gui.branulf_toolbox.damage_logger.title": "Damage Logger",
|
||||||
|
"gui.branulf_toolbox.damage_logger.enable": "Enable Damage Logger",
|
||||||
|
"gui.branulf_toolbox.damage_logger.disable": "Disable Damage Logger",
|
||||||
|
"gui.branulf_toolbox.damage_logger.open_folder": "Open Log Folder",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.damageLogger.enabled": "Enable Damage Logger",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.damageLogger.rememberState": "Remember Logging State",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.damageLogger.rememberState.@Tooltip": "If enabled, the damage logger will resume logging automatically when you restart the game if it was active. If disabled, it will turn off on game exit."
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,15 @@
|
|||||||
"branulf_toolbox.enabled": "已启用",
|
"branulf_toolbox.enabled": "已启用",
|
||||||
"branulf_toolbox.disabled": "已禁用",
|
"branulf_toolbox.disabled": "已禁用",
|
||||||
|
|
||||||
|
"branulf_toolbox.commit": "真的服了,为毛JSON不让我使用注释!",
|
||||||
|
|
||||||
"text.autoconfig.branulf_toolbox.title": "BRanulf的实用工具箱配置",
|
"text.autoconfig.branulf_toolbox.title": "BRanulf的实用工具箱配置",
|
||||||
"text.autoconfig.branulf_toolbox.category.autocrossbow_settings": "诸葛连弩设置",
|
"text.autoconfig.branulf_toolbox.category.autocrossbow_settings": "诸葛连弩设置",
|
||||||
"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": "玩家探测器设置",
|
"text.autoconfig.branulf_toolbox.category.player_detector_settings": "玩家探测器设置",
|
||||||
|
"text.autoconfig.branulf_toolbox.category.damage_logger_settings": "伤害记录设置",
|
||||||
|
|
||||||
"gui.branulf_toolbox.autocrossbow.title": "诸葛连弩",
|
"gui.branulf_toolbox.autocrossbow.title": "诸葛连弩",
|
||||||
"gui.branulf_toolbox.autocrossbow.enabled_on": "启用诸葛连弩",
|
"gui.branulf_toolbox.autocrossbow.enabled_on": "启用诸葛连弩",
|
||||||
@ -29,6 +32,10 @@
|
|||||||
"branulf_toolbox.autocrossbow.command.invalid_mode": "无效模式:“%s”。可用模式:normal, rapid_shoot, rapid_load。",
|
"branulf_toolbox.autocrossbow.command.invalid_mode": "无效模式:“%s”。可用模式:normal, rapid_shoot, rapid_load。",
|
||||||
"text.autoconfig.branulf_toolbox.option.autocrossbow.enabled": "启用诸葛连弩",
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.enabled": "启用诸葛连弩",
|
||||||
"text.autoconfig.branulf_toolbox.option.autocrossbow.currentMode": "当前模式",
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.currentMode": "当前模式",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.compatibilityMode": "兼容模式",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.compatibilityMode.@Tooltip": "启用时,只要弩有填充物(无论是否已装填完毕),就判断为已装填好的弩。适用于服务器插件导致已装填弩外观不改变的情况。",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.ultimateCompatibilityMode": "最终兼容模式 (仅正常模式)",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.autocrossbow.ultimateCompatibilityMode.@Tooltip": "在正常模式下,此选项会覆盖所有其他弩装填状态检查。如果蓄力完成,则视为已装填;如果刚射击过,则视为未装填。不依赖物品实际状态。",
|
||||||
|
|
||||||
"gui.branulf_toolbox.scrafitipty_plus.title": "Scrafitipty Plus (WebSocket)",
|
"gui.branulf_toolbox.scrafitipty_plus.title": "Scrafitipty Plus (WebSocket)",
|
||||||
"gui.branulf_toolbox.scrafitipty_plus.toggle_server": "切换WebSocket服务器",
|
"gui.branulf_toolbox.scrafitipty_plus.toggle_server": "切换WebSocket服务器",
|
||||||
@ -77,5 +84,13 @@
|
|||||||
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange": "探测范围(方块)",
|
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange": "探测范围(方块)",
|
||||||
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange.@Tooltip": "探测其他玩家的半径范围(1-64方块)。",
|
"text.autoconfig.branulf_toolbox.option.playerDetector.detectionRange.@Tooltip": "探测其他玩家的半径范围(1-64方块)。",
|
||||||
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency": "提示频率(次/秒)",
|
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency": "提示频率(次/秒)",
|
||||||
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency.@Tooltip": "当探测到玩家时,每秒播放提示音的次数(1-20)。"
|
"text.autoconfig.branulf_toolbox.option.playerDetector.alertFrequency.@Tooltip": "当探测到玩家时,每秒播放提示音的次数(1-20)。",
|
||||||
|
|
||||||
|
"gui.branulf_toolbox.damage_logger.title": "伤害记录",
|
||||||
|
"gui.branulf_toolbox.damage_logger.enable": "启用伤害记录",
|
||||||
|
"gui.branulf_toolbox.damage_logger.disable": "禁用伤害记录",
|
||||||
|
"gui.branulf_toolbox.damage_logger.open_folder": "打开日志文件夹",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.damageLogger.enabled": "启用伤害记录",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.damageLogger.rememberState": "记住开关状态",
|
||||||
|
"text.autoconfig.branulf_toolbox.option.damageLogger.rememberState.@Tooltip": "如果启用,当您退出游戏时,伤害记录功能将保存当前状态并在下次进入游戏时自动恢复。如果禁用,退出游戏后将关闭伤害记录功能。"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user