diff --git a/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClient.java b/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClient.java index 8888bdbd..036182e8 100644 --- a/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClient.java +++ b/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClient.java @@ -1,17 +1,13 @@ package top.hendrixshen.tweakmyclient; -//#if MC >= 11600 import fi.dy.masa.malilib.event.RenderEventHandler; -//#endif import net.fabricmc.api.ClientModInitializer; import net.minecraft.client.Minecraft; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import top.hendrixshen.tweakmyclient.config.ConfigHandler; import top.hendrixshen.tweakmyclient.config.Configs; -//#if MC >= 11600 import top.hendrixshen.tweakmyclient.event.RenderHandler; -//#endif public class TweakMyClient implements ClientModInitializer { private static final Logger logger = LogManager.getLogger(TweakMyClientReference.getModId()); @@ -31,9 +27,7 @@ public void onInitializeClient() { configHandler.configManager.parseConfigClass(Configs.class); ConfigHandler.register(configHandler); Configs.initCallbacks(configHandler.configManager); - //#if MC >= 11600 RenderEventHandler.getInstance().registerWorldLastRenderer(RenderHandler.getInstance()); - //#endif logger.info("[{}]: Mod initialized - Version: {} ({})", TweakMyClientReference.getModName(), TweakMyClientReference.getModVersion(), TweakMyClientReference.getModVersionType()); } diff --git a/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClientPredicate.java b/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClientPredicate.java new file mode 100644 index 00000000..c78afb67 --- /dev/null +++ b/src/main/java/top/hendrixshen/tweakmyclient/TweakMyClientPredicate.java @@ -0,0 +1,21 @@ +package top.hendrixshen.tweakmyclient; + +import top.hendrixshen.magiclib.config.Option; +import top.hendrixshen.magiclib.dependency.annotation.OptionDependencyPredicate; +import top.hendrixshen.tweakmyclient.config.Configs; + +public class TweakMyClientPredicate { + public static class DebugMode implements OptionDependencyPredicate { + @Override + public boolean test(Option option) { + return Configs.debugMode; + } + } + + public static class ExperimentalMode implements OptionDependencyPredicate { + @Override + public boolean test(Option option) { + return Configs.debugExperimentalMode; + } + } +} diff --git a/src/main/java/top/hendrixshen/tweakmyclient/config/Configs.java b/src/main/java/top/hendrixshen/tweakmyclient/config/Configs.java index 386e749e..8a7c0e0a 100644 --- a/src/main/java/top/hendrixshen/tweakmyclient/config/Configs.java +++ b/src/main/java/top/hendrixshen/tweakmyclient/config/Configs.java @@ -11,6 +11,7 @@ import top.hendrixshen.magiclib.dependency.annotation.Dependencies; import top.hendrixshen.magiclib.dependency.annotation.Dependency; import top.hendrixshen.tweakmyclient.TweakMyClient; +import top.hendrixshen.tweakmyclient.TweakMyClientPredicate; import top.hendrixshen.tweakmyclient.event.CallBacks; import top.hendrixshen.tweakmyclient.fakeInterface.IMinecraft; import top.hendrixshen.tweakmyclient.helper.AutoDropListType; @@ -30,6 +31,9 @@ public class Configs { @Config(category = ConfigCategory.GENERIC) public static int autoDropInterval = 0; + @Config(category = ConfigCategory.GENERIC) + public static boolean customBlockHitBoxOverlayLinkedAdapter = true; + @Config(category = ConfigCategory.GENERIC) public static String customWindowTitle = "Minecraft {mc_version} with TweakMyClient {tmc_version} | Player {mc_username} | FPS: {mc_fps}"; @@ -116,6 +120,9 @@ public class Configs { @Config(category = ConfigCategory.COLOR) public static Color4f colorBlockOutside = Color4f.fromColor(StringUtils.getColor("#66000000", 0)); + @Config(category = ConfigCategory.COLOR) + public static Color4f colorBlockHitBoxOverlayFill = Color4f.fromColor(StringUtils.getColor("#4CFFFF10", 0)); + @Config(category = ConfigCategory.COLOR) public static Color4f colorGuiStart = Color4f.fromColor(StringUtils.getColor("#C00F0F0F", 0)); @@ -151,6 +158,10 @@ public class Configs { @Config(category = ConfigCategory.FEATURE) public static boolean featureAutoRespawn = false; + @Hotkey() + @Config(category = ConfigCategory.FEATURE) + public static boolean featureCustomBlockHitBoxOverlayFill = false; + @Hotkey() @Config(category = ConfigCategory.FEATURE) public static boolean featureCustomBlockOutsideColor = false; @@ -280,6 +291,12 @@ public class Configs { @Config(category = ConfigCategory.DEBUG) public static boolean debugMode = false; + @Config(category = ConfigCategory.DEBUG, predicate = TweakMyClientPredicate.DebugMode.class) + public static boolean debugExperimentalMode = false; + + @Config(category = ConfigCategory.DEBUG, dependencies = @Dependencies(and = @Dependency(value = "minecraft", versionPredicate = ">=1.17")), predicate = TweakMyClientPredicate.ExperimentalMode.class) + public static boolean expCustomBlockHitBoxOverlayLinkedAdapterSupportPointedDripstoneBlock = false; + public static void initCallbacks(ConfigManager cm) { // Set callback for all BooleanHotkeyed config. /* TODO @@ -312,6 +329,7 @@ public static void initCallbacks(ConfigManager cm) { // Debug config callbacks. cm.setValueChangeCallback("debugMode", CallBacks::debugModeCallBack); + cm.setValueChangeCallback("debugExperimentalMode", CallBacks::debugExperimentalModeCallBack); CallBacks.debugModeCallBack(null); } diff --git a/src/main/java/top/hendrixshen/tweakmyclient/event/CallBacks.java b/src/main/java/top/hendrixshen/tweakmyclient/event/CallBacks.java index 9c7e78f1..c7ab03c4 100644 --- a/src/main/java/top/hendrixshen/tweakmyclient/event/CallBacks.java +++ b/src/main/java/top/hendrixshen/tweakmyclient/event/CallBacks.java @@ -86,13 +86,17 @@ public void run() { return true; } - public static void debugModeCallBack(Option option) { - Configurator.setLevel(TweakMyClientReference.getModId(), Level.toLevel((Configs.debugMode ? "DEBUG" : "INFO"))); + public static void debugExperimentalModeCallBack(Option option) { if (option != null) { TweakMyClientConfigGui.getInstance().reDraw(); } } + public static void debugModeCallBack(Option option) { + Configurator.setLevel(TweakMyClientReference.getModId(), Level.toLevel((Configs.debugMode ? "DEBUG" : "INFO"))); + CallBacks.debugExperimentalModeCallBack(option); + } + public static boolean syncInventoryCallback(KeyAction keyAction, IKeybind keybind) { InventoryUtil.refreshInventory(); return true; diff --git a/src/main/java/top/hendrixshen/tweakmyclient/event/RenderHandler.java b/src/main/java/top/hendrixshen/tweakmyclient/event/RenderHandler.java index 9628ec63..dcea1942 100644 --- a/src/main/java/top/hendrixshen/tweakmyclient/event/RenderHandler.java +++ b/src/main/java/top/hendrixshen/tweakmyclient/event/RenderHandler.java @@ -1,7 +1,8 @@ package top.hendrixshen.tweakmyclient.event; -//#if MC >= 11600 +//#if MC >= 11500 import com.mojang.blaze3d.vertex.PoseStack; +//#endif //#if MC > 11600 import com.mojang.math.Matrix4f; //#endif @@ -10,9 +11,7 @@ import top.hendrixshen.tweakmyclient.TweakMyClient; import top.hendrixshen.tweakmyclient.config.Configs; import top.hendrixshen.tweakmyclient.util.render.OverlayRenderer; -//#endif -//#if MC >= 11600 public class RenderHandler implements IRenderer { private static final RenderHandler INSTANCE = new RenderHandler(); private final Minecraft minecraft; @@ -28,14 +27,18 @@ public static RenderHandler getInstance() { @Override //#if MC >= 11700 public void onRenderWorldLast(PoseStack poseStack, Matrix4f matrix4f) { - //#else + //#elseif MC >= 11500 //$$ public void onRenderWorldLast(float partialTicks, PoseStack poseStack) { + //#else + //$$ public void onRenderWorldLast(float partialTicks) { //#endif + //#if MC >= 11600 if (Configs.featureOpenWaterHelper) { OverlayRenderer.getInstance().renderOpenWater(minecraft); } + //#endif + if (Configs.featureCustomBlockHitBoxOverlayFill) { + OverlayRenderer.getInstance().renderBlockOverlay(minecraft); + } } -//#else -//$$ public class RenderHandler { -//#endif } diff --git a/src/main/java/top/hendrixshen/tweakmyclient/util/render/OverlayRenderer.java b/src/main/java/top/hendrixshen/tweakmyclient/util/render/OverlayRenderer.java index 16c621b3..d7c2adeb 100644 --- a/src/main/java/top/hendrixshen/tweakmyclient/util/render/OverlayRenderer.java +++ b/src/main/java/top/hendrixshen/tweakmyclient/util/render/OverlayRenderer.java @@ -2,30 +2,57 @@ //#if MC >= 11600 import fi.dy.masa.malilib.util.Color4f; +//#endif import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +//#if MC >= 11600 +import net.minecraft.client.player.LocalPlayer; +//#endif import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.Entity; +//#if MC >= 11600 import net.minecraft.world.entity.projectile.FishingHook; +//#endif +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.piston.PistonBaseBlock; +import net.minecraft.world.level.block.piston.PistonHeadBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BedPart; +import net.minecraft.world.level.block.state.properties.PistonType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.lwjgl.opengl.GL11; import top.hendrixshen.tweakmyclient.config.Configs; +//#if MC >= 11600 import top.hendrixshen.tweakmyclient.fakeInterface.IFishingHookEntity; //#endif public class OverlayRenderer { - //#if MC >= 11600 private static final OverlayRenderer INSTANCE = new OverlayRenderer(); public static OverlayRenderer getInstance() { return INSTANCE; } + //#if MC >= 11600 public void renderOpenWater(Minecraft minecraft) { - assert minecraft.player != null; - FishingHook fishHook = minecraft.player.fishing; - if (fishHook != null) { - BlockPos fishHookPos = fishHook.blockPosition(); - Color4f color = isInOpenWater(fishHook) ? Configs.colorWaterOpen : Configs.colorWaterShallow; - BlockPos pos1 = new BlockPos(fishHookPos.getX() - 2, fishHookPos.getY() - 3, fishHookPos.getZ() - 2); - BlockPos pos2 = new BlockPos(fishHookPos.getX() + 2, fishHookPos.getY(), fishHookPos.getZ() + 2); - RenderUtil.renderAreaOutline(pos1, pos2, 3.0f, color, color, color, minecraft); + LocalPlayer localPlayer = minecraft.player; + if (localPlayer != null) { + FishingHook fishHook = localPlayer.fishing; + if (fishHook != null) { + BlockPos fishHookPos = fishHook.blockPosition(); + Color4f color = isInOpenWater(fishHook) ? Configs.colorWaterOpen : Configs.colorWaterShallow; + BlockPos pos1 = new BlockPos(fishHookPos.getX() - 2, fishHookPos.getY() - 3, fishHookPos.getZ() - 2); + BlockPos pos2 = new BlockPos(fishHookPos.getX() + 2, fishHookPos.getY(), fishHookPos.getZ() + 2); + GL11.glEnable(GL11.GL_LINE_SMOOTH); + RenderUtil.renderAreaOutline(pos1, pos2, 3.0f, color, color, color, minecraft); + GL11.glDisable(GL11.GL_LINE_SMOOTH); + } } } @@ -33,4 +60,111 @@ private boolean isInOpenWater(FishingHook fishHook) { return ((IFishingHookEntity) fishHook).checkOpenWaterAround(fishHook.blockPosition()); } //#endif + + public void renderBlockOverlay(Minecraft minecraft) { + HitResult hitResult = minecraft.hitResult; + ClientLevel clientLevel = minecraft.level; + Entity cameraEntity = minecraft.cameraEntity; + Vec3 vec3 = minecraft.gameRenderer.getMainCamera().getPosition(); + if (hitResult instanceof BlockHitResult && clientLevel != null && cameraEntity != null) { + BlockHitResult blockHitResult = (BlockHitResult) hitResult; + BlockPos blockPos = blockHitResult.getBlockPos(); + BlockState blockState = clientLevel.getBlockState(blockPos); + VoxelShape voxelShape = blockState.getShape(clientLevel, blockHitResult.getBlockPos(), CollisionContext.of(cameraEntity)); + if (Configs.customBlockHitBoxOverlayLinkedAdapter) { + voxelShape = linkedBlockAdapter(clientLevel, blockState, blockPos, voxelShape); + } + RenderUtil.renderShapeOverlay(voxelShape, blockPos.getX() - vec3.x(), blockPos.getY() - vec3.y(), blockPos.getZ() - vec3.z(), Configs.colorBlockHitBoxOverlayFill); + } + } + + private VoxelShape linkedBlockAdapter(ClientLevel clientLevel, BlockState blockState, BlockPos blockPos, VoxelShape shape) { + try { + if (blockState.getBlock() instanceof ChestBlock) { + Block block = blockState.getBlock(); + Direction direction = ChestBlock.getConnectedDirection(blockState); + BlockState connectBlock = clientLevel.getBlockState(blockPos.relative(direction, 1)); + if (connectBlock.getBlock() == block && blockPos.relative(direction, 1).relative(ChestBlock.getConnectedDirection(connectBlock)).equals(blockPos)) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos).move(direction.getStepX(), direction.getStepY(), direction.getStepZ())); + } + } else if (blockState.getBlock() instanceof DoorBlock) { + Block block = blockState.getBlock(); + if (clientLevel.getBlockState(blockPos.above(1)).getBlock() == block) { + BlockState connectBlock = clientLevel.getBlockState(blockPos.above(1)); + if (connectBlock.getValue(DoorBlock.POWERED).equals(blockState.getValue(DoorBlock.POWERED)) + && connectBlock.getValue(DoorBlock.FACING).equals(blockState.getValue(DoorBlock.FACING)) + && connectBlock.getValue(DoorBlock.HINGE).equals(connectBlock.getValue(DoorBlock.HINGE))) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos).move(0, 1,0)); + } + } else if (clientLevel.getBlockState(blockPos.below(1)).getBlock() == block) { + BlockState connectBlock = clientLevel.getBlockState(blockPos.below(1)); + if (connectBlock.getValue(DoorBlock.POWERED).equals(blockState.getValue(DoorBlock.POWERED)) + && connectBlock.getValue(DoorBlock.FACING).equals(blockState.getValue(DoorBlock.FACING)) + && connectBlock.getValue(DoorBlock.HINGE).equals(connectBlock.getValue(DoorBlock.HINGE))) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos).move(0, -1,0)); + } + } + } else if (blockState.getBlock() instanceof BedBlock) { + Block block = blockState.getBlock(); + Direction direction = blockState.getValue(HorizontalDirectionalBlock.FACING); + BlockState connectBlock = clientLevel.getBlockState(blockPos.relative(direction)); + if (blockState.getValue(BedBlock.PART).equals(BedPart.FOOT) + && connectBlock.getBlock() == block + && connectBlock.getValue(BedBlock.PART).equals(BedPart.HEAD)) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos).move(direction.getStepX(), direction.getStepY(), direction.getStepZ())); + } + connectBlock = clientLevel.getBlockState(blockPos.relative(direction.getOpposite())); + direction = direction.getOpposite(); + if (blockState.getValue(BedBlock.PART).equals(BedPart.HEAD) + && connectBlock.getBlock() == block + && connectBlock.getValue(BedBlock.PART).equals(BedPart.FOOT)) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos).move(direction.getStepX(), direction.getStepY(), direction.getStepZ())); + } + } else if (blockState.getBlock() instanceof PistonBaseBlock && blockState.getValue(PistonBaseBlock.EXTENDED)) { + Block block = blockState.getBlock(); + Direction direction = blockState.getValue(DirectionalBlock.FACING); + BlockState connectBlock = clientLevel.getBlockState(blockPos.relative(direction)); + if (connectBlock.getValue(PistonHeadBlock.TYPE).equals(block == Blocks.PISTON ? PistonType.DEFAULT : PistonType.STICKY) + && direction.equals(connectBlock.getValue(DirectionalBlock.FACING))) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos).move(direction.getStepX(), direction.getStepY(), direction.getStepZ())); + } + } else if (blockState.getBlock() instanceof PistonHeadBlock) { + Direction direction = blockState.getValue(DirectionalBlock.FACING); + BlockState connectBlock = clientLevel.getBlockState(blockPos.relative(direction.getOpposite())); + if (connectBlock.getBlock() instanceof PistonBaseBlock && direction == connectBlock.getValue(DirectionalBlock.FACING) && connectBlock.getValue(PistonBaseBlock.EXTENDED)) { + return Shapes.or(shape, connectBlock.getShape(clientLevel, blockPos.relative(direction.getOpposite())).move(direction.getOpposite().getStepX(), direction.getOpposite().getStepY(), direction.getOpposite().getStepZ())); + } + //#if MC >= 11700 + } else if (blockState.getBlock() instanceof PointedDripstoneBlock && Configs.expCustomBlockHitBoxOverlayLinkedAdapterSupportPointedDripstoneBlock) { + Direction direction = blockState.getValue(PointedDripstoneBlock.TIP_DIRECTION); + + BlockPos connectBlockPos = blockPos.above(); + while (true) { + BlockState connectBlock = clientLevel.getBlockState(connectBlockPos); + if (connectBlock.getBlock() instanceof PointedDripstoneBlock && connectBlock.getValue(PointedDripstoneBlock.TIP_DIRECTION).equals(direction)) { + shape = Shapes.or(shape, connectBlock.getShape(clientLevel, connectBlockPos).move(0, connectBlockPos.getY() - blockPos.getY(), 0)); + connectBlockPos = connectBlockPos.above(); + } else { + break; + } + } + + connectBlockPos = blockPos.below(); + while (true) { + BlockState connectBlock = clientLevel.getBlockState(connectBlockPos); + if (connectBlock.getBlock() instanceof PointedDripstoneBlock && connectBlock.getValue(PointedDripstoneBlock.TIP_DIRECTION).equals(direction)) { + shape = Shapes.or(shape, connectBlock.getShape(clientLevel, connectBlockPos).move(0, connectBlockPos.getY() - blockPos.getY(), 0)); + connectBlockPos = connectBlockPos.below(); + } else { + break; + } + } + + return shape; + //#endif + } + } catch (Exception ignore) { + } + return shape; + } } diff --git a/src/main/java/top/hendrixshen/tweakmyclient/util/render/RenderUtil.java b/src/main/java/top/hendrixshen/tweakmyclient/util/render/RenderUtil.java index 98425837..b2fa2f54 100644 --- a/src/main/java/top/hendrixshen/tweakmyclient/util/render/RenderUtil.java +++ b/src/main/java/top/hendrixshen/tweakmyclient/util/render/RenderUtil.java @@ -1,23 +1,27 @@ package top.hendrixshen.tweakmyclient.util.render; -//#if MC >= 11600 import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.Tesselator; -//#if MC >= 11700 -import com.mojang.blaze3d.vertex.VertexFormat; -//#endif +import com.mojang.blaze3d.vertex.*; +import fi.dy.masa.malilib.render.RenderUtils; import fi.dy.masa.malilib.util.Color4f; +//#if MC >= 11600 import net.minecraft.client.Minecraft; +//#endif //#if MC >= 11700 import net.minecraft.client.renderer.GameRenderer; //#endif +//#if MC >= 11600 import net.minecraft.core.BlockPos; +//#endif +import net.minecraft.world.phys.AABB; +//#if MC >= 11600 import net.minecraft.world.phys.Vec3; -//#if MC < 11700 -import org.lwjgl.opengl.GL11; //#endif +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import top.hendrixshen.magiclib.compat.minecraft.blaze3d.vertex.VertexFormatCompatApi; +//#if MC < 11700 +//$$ import org.lwjgl.opengl.GL11; //#endif public class RenderUtil { @@ -100,5 +104,34 @@ private static void drawBoundingBoxLinesZ(BufferBuilder buffer, double minX, dou buffer.vertex(maxX, maxY, minZ).color(color.r, color.g, color.b, color.a).endVertex(); buffer.vertex(maxX, maxY, maxZ).color(color.r, color.g, color.b, color.a).endVertex(); } + //#endif + public static void renderShapeOverlay(VoxelShape voxelShape, double x, double y, double z, Color4f color4f) { + //#if MC < 11700 + //$$ RenderSystem.disableTexture(); + //#endif + RenderSystem.enableBlend(); + RenderSystem.disableCull(); + //#if MC >= 11700 + RenderSystem.setShader(GameRenderer::getPositionColorShader); + //#endif + Tesselator tesselator = Tesselator.getInstance(); + BufferBuilder buffer = tesselator.getBuilder(); + buffer.begin(VertexFormatCompatApi.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + VoxelShape optimizedVoxelShape = voxelShape.toAabbs().stream() + .map(box -> box.inflate(0.005, 0.005, 0.005)) + .map(Shapes::create) + .reduce(Shapes::or) + .orElse(Shapes.empty()).optimize(); + for (AABB aabb : optimizedVoxelShape.toAabbs()) { + RenderUtils.drawBoxAllSidesBatchedQuads(aabb.minX + x, aabb.minY + y, aabb.minZ + z, + aabb.maxX + x, aabb.maxY + y, aabb.maxZ + z, color4f, buffer); + } + tesselator.end(); + RenderSystem.enableCull(); + RenderSystem.disableBlend(); + //#if MC < 11700 + //$$ RenderSystem.enableTexture(); + //#endif + } } diff --git a/src/main/resources/assets/tweakmyclient/lang/zh_cn.json b/src/main/resources/assets/tweakmyclient/lang/zh_cn.json index 22e22d98..3ca32a4c 100644 --- a/src/main/resources/assets/tweakmyclient/lang/zh_cn.json +++ b/src/main/resources/assets/tweakmyclient/lang/zh_cn.json @@ -10,6 +10,8 @@ "tweakmyclient.gui.button.tab.list": "列表", "tweakmyclient.gui.button.tab.patch": "修补", + "tweakmyclient.config.color.colorBlockHitBoxOverlayFill.name": "方块覆盖颜色", + "tweakmyclient.config.color.colorBlockHitBoxOverlayFill.comment": "自定义方块碰撞箱的覆盖层填充颜色.", "tweakmyclient.config.color.colorBlockOutside.name": "方块轮廓颜色", "tweakmyclient.config.color.colorBlockOutside.comment": "自定义方块轮廓颜色.", "tweakmyclient.config.color.colorGuiStart.name": "界面渐变背景起始颜色", @@ -78,6 +80,8 @@ "tweakmyclient.config.feature.featureAutoRespawn.comment": "死亡时自动重生.", "tweakmyclient.config.feature.featureCustomBlockOutsideColor.name": "自定义方块轮廓", "tweakmyclient.config.feature.featureCustomBlockOutsideColor.comment": "启用方块轮廓颜色覆写.", + "tweakmyclient.config.feature.featureCustomBlockHitBoxOverlayFill.name": "自定义方块碰撞箱覆盖填充", + "tweakmyclient.config.feature.featureCustomBlockHitBoxOverlayFill.comment": "启用指向方块碰撞箱的覆盖层填充.", "tweakmyclient.config.feature.featureCustomGuiBackgroundColor.name": "自定义界面背景颜色", "tweakmyclient.config.feature.featureCustomGuiBackgroundColor.comment": "启用计分板界面背景色覆写.", "tweakmyclient.config.feature.featureCustomSidebarBackgroundColor.name": "自定义计分板背景颜色", @@ -101,6 +105,8 @@ "tweakmyclient.config.generic.autoDropInterval.comment": "每隔多少刻执行一次自动丢弃.", "tweakmyclient.config.generic.autoReconnectTimer.name": "自动重连计时器", "tweakmyclient.config.generic.autoReconnectTimer.comment": "等待多少秒后自动重连.", + "tweakmyclient.config.generic.customBlockHitBoxOverlayLinkedAdapter.name": "自定义方块碰撞箱覆盖连接体方块适配", + "tweakmyclient.config.generic.customBlockHitBoxOverlayLinkedAdapter.comment": "启用 自定义方块碰撞箱覆盖 对连接体方块的优化.", "tweakmyclient.config.generic.customWindowTitle.name": "自定义窗口标题", "tweakmyclient.config.generic.customWindowTitle.comment": "修改当前窗口标题.\n可用的占位符如下:\n{fabric_loader_asm_version}\n{fabric_loader_version}\n{fabric_mod_ver:}\n{mc_fps}\n{mc_protocol_version}\n{mc_username}\n{mc_version}\n{tmc_version}\n{tmc_version_type}", "tweakmyclient.config.generic.customWindowTitleWithActivity.name": "自定义带当前活动的窗口标题", @@ -152,8 +158,12 @@ "tweakmyclient.config.patch.forcePistonWithoutAffectByTool.name": "强制活塞不受镐子影响", "tweakmyclient.config.patch.forcePistonWithoutAffectByTool.comment": "镐子将不再作为活塞的有效开采工具.", - "tweakmyclient.config.debugMode.name": "调试模式", - "tweakmyclient.config.debugMode.comment": "启用调试模式.", + "tweakmyclient.config.debug.debugMode.name": "调试模式", + "tweakmyclient.config.debug.debugMode.comment": "启用调试模式.", + "tweakmyclient.config.debug.debugExperimentalMode.name": "实验性模式", + "tweakmyclient.config.debug.debugExperimentalMode.comment": "启用实验性功能.", + "tweakmyclient.config.debug.expCustomBlockHitBoxOverlayLinkedAdapterSupportPointedDripstoneBlock.name": "§e自定义方块碰撞箱覆盖连接体方块适配支持滴水石锥", + "tweakmyclient.config.debug.expCustomBlockHitBoxOverlayLinkedAdapterSupportPointedDripstoneBlock.comment": "实验性功能.", "tweakmyclient.label.autoDropListType.blackList": "黑名单", "tweakmyclient.label.autoDropListType.whiteList": "白名单",