From 0b8669547958ac2cc43a49ad53cd92f490bf81ba Mon Sep 17 00:00:00 2001 From: H31M5 <2211923909@qq.com> Date: Tue, 28 Oct 2025 12:41:29 +0800 Subject: [PATCH 01/33] Add configuration index support (#175) --- .../java/com/xtracr/realcamera/KeyMappings.java | 3 +++ .../com/xtracr/realcamera/RealCameraCore.java | 7 +++---- .../com/xtracr/realcamera/compat/YSMCompat.java | 10 ++++------ .../xtracr/realcamera/config/ConfigScreen.java | 7 +++++++ .../com/xtracr/realcamera/config/ModConfig.java | 15 ++++++++++++++- .../resources/assets/realcamera/lang/en_us.json | 5 +++++ .../resources/assets/realcamera/lang/zh_cn.json | 5 +++++ gradle.properties | 2 +- 8 files changed, 42 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java index a2e3d9d9..e455c979 100644 --- a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java +++ b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java @@ -31,6 +31,9 @@ public final class KeyMappings { createKeyMapping("adjustDOWN", client -> ConfigFile.config().adjustOffsetY(-1)); createKeyMapping("adjustLEFT", client -> ConfigFile.config().adjustOffsetZ(1)); createKeyMapping("adjustRIGHT", client -> ConfigFile.config().adjustOffsetZ(-1)); + createKeyMapping("activeConfigIndexNEXT", client -> ConfigFile.config().setActiveConfigIndex(1)); + createKeyMapping("activeConfigIndexPREV", client -> ConfigFile.config().setActiveConfigIndex(-1)); + createKeyMapping("activeConfigIndexRESET", client -> ConfigFile.config().setActiveConfigIndex(0)); } private static KeyMapping createKeyMapping(String id, Consumer whenPressed) { diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 9bc44394..62137bd6 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -152,10 +152,9 @@ public static void renderCameraEntity(Minecraft client, float deltaTick, MultiBu private static void computeBindResult(BuiltIterableBuffer builtBuffer) { if (newResult.available()) return; targetFor: - for (BindTarget target : ConfigFile.config().getBindTargetList()) { + for (BindTarget target : ConfigFile.config().getTargetList(builtBuffer.textureId())) { BindResult result = new BindResult(target, false); - if (!builtBuffer.textureId().contains(result.target.textureId())) continue; - BindTarget.TargetConfig config = result.target.targetConfig(); + BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV[] uvs = {new VertexData.UV(config.posU(), config.posV()), new VertexData.UV(config.forwardU(), config.forwardV()), new VertexData.UV(config.upwardU(), config.upwardV())}; VertexData[][] primitives = builtBuffer.findPrimitivesInCache(uvs); if (builtBuffer.anyNotCached(uvs)) { @@ -176,4 +175,4 @@ private static void computeBindResult(BuiltIterableBuffer builtBuffer) { return; } } -} +} \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index 7f1788ed..a87dfa79 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -78,10 +78,9 @@ public TransformedVertexRecorder setRotation(float pitch, float yaw) { public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; - for (BindTarget target : ConfigFile.config().getBindTargetList()) { + for (BindTarget target : ConfigFile.config().getTargetList(builtBuffer.textureId())) { BindResult result = resultMap.computeIfAbsent(target, k -> new BindResult(target, false)); - if (!builtBuffer.textureId().contains(result.target.textureId())) continue; - BindTarget.TargetConfig config = result.target.targetConfig(); + BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = new VertexData.UV(config.posU(), config.posV()); VertexData.UV forwardUV = new VertexData.UV(config.forwardU(), config.forwardV()); VertexData.UV upwardUV = new VertexData.UV(config.upwardU(), config.upwardV()); @@ -101,10 +100,9 @@ public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { public void computeBindResult(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; - for (BindTarget target : ConfigFile.config().getBindTargetList()) { + for (BindTarget target : ConfigFile.config().getTargetList(builtBuffer.textureId())) { BindResult result = resultMap.computeIfAbsent(target, k -> new BindResult(target, false)); - if (!builtBuffer.textureId().contains(result.target.textureId())) continue; - BindTarget.TargetConfig config = result.target.targetConfig(); + BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = result.getPosition() == Vec3.ZERO ? new VertexData.UV(config.posU(), config.posV()) : null; VertexData.UV forwardUV = result.getForward() == Vec3.ZERO ? new VertexData.UV(config.forwardU(), config.forwardV()) : null; VertexData.UV upwardUV = result.getUpward() == Vec3.ZERO ? new VertexData.UV(config.upwardU(), config.upwardV()) : null; diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 64375c20..050f25e0 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -200,6 +200,13 @@ public static Screen create(Screen parent) { .setTooltip(LocUtil.CONFIG_TOOLTIP("rotationSmoothFactor")) .setSaveConsumer(d -> config.binding.rotationSmoothFactor = d) .build()); + binding.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("activeConfigIndex"), config.binding.activeConfigIndex) + .setDefaultValue(0) + .setMin(0) + .setMax(Integer.MAX_VALUE) + .setTooltip(LocUtil.CONFIG_TOOLTIP("activeConfigIndex")) + .setSaveConsumer(i -> config.binding.activeConfigIndex = i) + .build()); binding.addEntry(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) .setDefaultValue(List.of()) .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 6f53b1ae..2b9f22a2 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -110,6 +110,10 @@ public void adjustOffsetZ(int count) { } } + public void setActiveConfigIndex(int value) { + binding.activeConfigIndex = value == 0 ? 0 : Mth.clamp(binding.activeConfigIndex += value, 0, Integer.MAX_VALUE); + } + // classic public boolean classicDisableWhenSneaking() { return classic.disableWhenSneaking; @@ -217,6 +221,14 @@ public List getBindTargetList() { return binding.targetList; } + public List getTargetList(String textureId) { + binding.clamp(); + int activeConfigIndex = binding.activeConfigIndex; + List matchedTargets = binding.targetList.stream().filter(target -> textureId.contains(target.textureId())).toList(); + if (activeConfigIndex == 0 || matchedTargets.isEmpty()) return matchedTargets; + return List.of(matchedTargets.get(Math.min(activeConfigIndex - 1, matchedTargets.size() - 1))); + } + public void putBindTarget(BindTarget target) { if (target.isEmpty()) return; List fixedList = binding.fixedTargetList; @@ -289,6 +301,7 @@ public static class Binding { public int bindResultRetentionFrames = 2; public double displacementSmoothFactor = 0.4; public double rotationSmoothFactor = 0.4; + public int activeConfigIndex = 0; public List disableMainFeatureItems = List.of(); public List disableRenderItems = defaultDisableRenderItems; public List fixedTargetList = new ArrayList<>(); @@ -315,4 +328,4 @@ private void clamp() { } } } -} +} \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 33202989..0e3c127d 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Open Model View Screen", "key.xtracr_realcamera.togglePerspective": "Enable/Disable", + "key.xtracr_realcamera.activeConfigIndexPREV": "Switch to previous configuration", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Switch to next configuration", + "key.xtracr_realcamera.activeConfigIndexRESET": "Reset configuration index", "key.xtracr_realcamera.toggleAdjustMode": "Toggle Adjust Mode", "key.xtracr_realcamera.toggleCameraMode": "Toggle Camera Mode", "key.xtracr_realcamera.adjustUP": "Adjust UP", @@ -49,6 +52,7 @@ "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bind Result Retention Frames", "config.option.xtracr_realcamera.displacementSmoothFactor": "Displacement Smooth Factor", "config.option.xtracr_realcamera.rotationSmoothFactor": "Rotation Smooth Factor", + "config.option.xtracr_realcamera.activeConfigIndex": "Active Configuration Index", "config.option.xtracr_realcamera.disableMainFeatureItems": "Disable main feature when holding", "config.option.xtracr_realcamera.disableRenderItems": "Disable rendering when holding", "config.tooltip.xtracr_realcamera.isClassic": "Classic mode only makes simple changes to the position and rotation of camera", @@ -65,6 +69,7 @@ "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "For several frames after the binding failure, continue to use the previous successful binding result", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Smooth factor of camera displacement, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Smooth factor of camera rotation, the higher the value, the smoother the movement", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Currently bound configuration index, 0 means allowing binding to any valid configuration", "config.tooltip.xtracr_realcamera.disableRenderItems": "Three matching methods are supported:\n1. Wildcard `*` matching (e.g., `minecraft:*sword`)\n2. Tag matching (starts with `#`, e.g., `#minecraft:swords`)\n3. Direct item ID (e.g., `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Binding failed, please go to the %s screen and configure manually (Key: %s)", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 8777e54a..282edaa1 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "打开模型视图界面", "key.xtracr_realcamera.togglePerspective": "开启/关闭", + "key.xtracr_realcamera.activeConfigIndexPREV": "切换到上一个配置", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切换到下一个配置", + "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", "key.xtracr_realcamera.toggleAdjustMode": "切换调整模式", "key.xtracr_realcamera.toggleCameraMode": "切换摄像头模式", "key.xtracr_realcamera.adjustUP": "向上调整", @@ -49,6 +52,7 @@ "config.option.xtracr_realcamera.bindResultRetentionFrames": "绑定结果保留帧数", "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", + "config.option.xtracr_realcamera.activeConfigIndex": "当前配置索引", "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...时禁用主要功能", "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用渲染", "config.tooltip.xtracr_realcamera.isClassic": "经典模式只对摄像头的位置和旋转做简单的修改", @@ -65,6 +69,7 @@ "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在绑定失败后的数帧内,沿用上个成功的绑定结果", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相机位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相机旋转平滑系数,值越大越平滑", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "当前绑定的配置索引,0表示允许绑定任何有效配置", "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三种匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 标签匹配以`#`开头(如`#minecraft:swords`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: 绑定失败,请前往%s界面手动设置(键位:%s)", diff --git a/gradle.properties b/gradle.properties index f72ce668..556d4a35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ fabric_loader_version=0.17.2 neoforge_version=21.1.194 #yarn_mappings=1.21.1+build.3 # Mod Properties -mod_version=0.7.4-beta +mod_version=0.7.5-beta maven_group=com.xtracr.realcamera archives_base_name=realcamera # Dependencies From 5ecd7a781e2c4c4bf7343fb68fb72a5a4133b528 Mon Sep 17 00:00:00 2001 From: xTracr Date: Sun, 2 Nov 2025 11:38:07 +0800 Subject: [PATCH 02/33] Exchanged the order of "Disable" and "Preview" in the screen --- .../com/xtracr/realcamera/KeyMappings.java | 6 +- .../com/xtracr/realcamera/RealCameraCore.java | 2 +- .../xtracr/realcamera/compat/YSMCompat.java | 4 +- .../realcamera/config/ConfigScreen.java | 13 +- .../xtracr/realcamera/config/ModConfig.java | 10 +- .../realcamera/gui/ModelViewScreen.java | 270 ++++++++++-------- fabric/src/main/resources/fabric.mod.json | 2 +- 7 files changed, 163 insertions(+), 144 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java index e455c979..a951ab39 100644 --- a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java +++ b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java @@ -31,9 +31,9 @@ public final class KeyMappings { createKeyMapping("adjustDOWN", client -> ConfigFile.config().adjustOffsetY(-1)); createKeyMapping("adjustLEFT", client -> ConfigFile.config().adjustOffsetZ(1)); createKeyMapping("adjustRIGHT", client -> ConfigFile.config().adjustOffsetZ(-1)); - createKeyMapping("activeConfigIndexNEXT", client -> ConfigFile.config().setActiveConfigIndex(1)); - createKeyMapping("activeConfigIndexPREV", client -> ConfigFile.config().setActiveConfigIndex(-1)); - createKeyMapping("activeConfigIndexRESET", client -> ConfigFile.config().setActiveConfigIndex(0)); + createKeyMapping("activeConfigIndexNEXT", client -> ConfigFile.config().binding.activeConfigIndex += 1); + createKeyMapping("activeConfigIndexPREV", client -> ConfigFile.config().binding.activeConfigIndex -= 1); + createKeyMapping("activeConfigIndexRESET", client -> ConfigFile.config().binding.activeConfigIndex = 0); } private static KeyMapping createKeyMapping(String id, Consumer whenPressed) { diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 62137bd6..62506e21 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -152,7 +152,7 @@ public static void renderCameraEntity(Minecraft client, float deltaTick, MultiBu private static void computeBindResult(BuiltIterableBuffer builtBuffer) { if (newResult.available()) return; targetFor: - for (BindTarget target : ConfigFile.config().getTargetList(builtBuffer.textureId())) { + for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { BindResult result = new BindResult(target, false); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV[] uvs = {new VertexData.UV(config.posU(), config.posV()), new VertexData.UV(config.forwardU(), config.forwardV()), new VertexData.UV(config.upwardU(), config.upwardV())}; diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index a87dfa79..4a9822dc 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -78,7 +78,7 @@ public TransformedVertexRecorder setRotation(float pitch, float yaw) { public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; - for (BindTarget target : ConfigFile.config().getTargetList(builtBuffer.textureId())) { + for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { BindResult result = resultMap.computeIfAbsent(target, k -> new BindResult(target, false)); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = new VertexData.UV(config.posU(), config.posV()); @@ -100,7 +100,7 @@ public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { public void computeBindResult(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; - for (BindTarget target : ConfigFile.config().getTargetList(builtBuffer.textureId())) { + for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { BindResult result = resultMap.computeIfAbsent(target, k -> new BindResult(target, false)); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = result.getPosition() == Vec3.ZERO ? new VertexData.UV(config.posU(), config.posV()) : null; diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 050f25e0..873926cb 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -186,6 +186,12 @@ public static Screen create(Screen parent) { .setTooltip(LocUtil.CONFIG_TOOLTIP("bindResultRetentionFrames")) .setSaveConsumer(i -> config.binding.bindResultRetentionFrames = i) .build()); + binding.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("activeConfigIndex"), config.binding.activeConfigIndex) + .setDefaultValue(0) + .setMin(0) + .setTooltip(LocUtil.CONFIG_TOOLTIP("activeConfigIndex")) + .setSaveConsumer(i -> config.binding.activeConfigIndex = i) + .build()); binding.addEntry(entryBuilder.startDoubleField(LocUtil.CONFIG_OPTION("displacementSmoothFactor"), config.binding.displacementSmoothFactor) .setDefaultValue(0.4) .setMin(0.0) @@ -200,13 +206,6 @@ public static Screen create(Screen parent) { .setTooltip(LocUtil.CONFIG_TOOLTIP("rotationSmoothFactor")) .setSaveConsumer(d -> config.binding.rotationSmoothFactor = d) .build()); - binding.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("activeConfigIndex"), config.binding.activeConfigIndex) - .setDefaultValue(0) - .setMin(0) - .setMax(Integer.MAX_VALUE) - .setTooltip(LocUtil.CONFIG_TOOLTIP("activeConfigIndex")) - .setSaveConsumer(i -> config.binding.activeConfigIndex = i) - .build()); binding.addEntry(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) .setDefaultValue(List.of()) .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 2b9f22a2..a84bb5b7 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -110,10 +110,6 @@ public void adjustOffsetZ(int count) { } } - public void setActiveConfigIndex(int value) { - binding.activeConfigIndex = value == 0 ? 0 : Mth.clamp(binding.activeConfigIndex += value, 0, Integer.MAX_VALUE); - } - // classic public boolean classicDisableWhenSneaking() { return classic.disableWhenSneaking; @@ -221,12 +217,12 @@ public List getBindTargetList() { return binding.targetList; } - public List getTargetList(String textureId) { + public List getBindTargetList(String textureId) { binding.clamp(); int activeConfigIndex = binding.activeConfigIndex; List matchedTargets = binding.targetList.stream().filter(target -> textureId.contains(target.textureId())).toList(); if (activeConfigIndex == 0 || matchedTargets.isEmpty()) return matchedTargets; - return List.of(matchedTargets.get(Math.min(activeConfigIndex - 1, matchedTargets.size() - 1))); + return List.of(matchedTargets.get(Math.clamp(activeConfigIndex - 1, 0, matchedTargets.size() - 1))); } public void putBindTarget(BindTarget target) { @@ -299,9 +295,9 @@ public static class Binding { public boolean disableWhenSwimming = false; public int swimOutTick = 13; public int bindResultRetentionFrames = 2; + public int activeConfigIndex = 0; public double displacementSmoothFactor = 0.4; public double rotationSmoothFactor = 0.4; - public int activeConfigIndex = 0; public List disableMainFeatureItems = List.of(); public List disableRenderItems = defaultDisableRenderItems; public List fixedTargetList = new ArrayList<>(); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index a61d5ecd..2c118263 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -1,5 +1,6 @@ package com.xtracr.realcamera.gui; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; import com.mojang.blaze3d.platform.InputConstants; import com.xtracr.realcamera.RealCameraCore; @@ -14,7 +15,6 @@ import com.xtracr.realcamera.util.VertexData; import io.netty.buffer.Unpooled; import net.minecraft.ChatFormatting; -import net.minecraft.client.OptionInstance; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.*; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -68,7 +68,6 @@ public class ModelViewScreen extends Screen { private final List disableConfigs = new ArrayList<>(); private final List rectWidgets = new ArrayList<>(); private final Map> hiddenNameMap = new HashMap<>(); - private final Map toggleConfigMap = Map.of(0, "disable", 1, "preview", 2, "configs"); private final CyclingTexturedButton showTextureButton = new CyclingTexturedButton(48, 16, 0, 2).setOnValueChange(i -> initWidgets(page)); private final CyclingTexturedButton pauseButton = new CyclingTexturedButton(0, 16, 0, 2); private final CyclingTexturedButton bindXButton = new CyclingTexturedButton(16, 16, 1, 2); @@ -83,24 +82,33 @@ public class ModelViewScreen extends Screen { private final DoubleSlider offsetPitchSlider = createSlider("pitch", widgetWidth * 2 - 18, -180.0, 180.0); private final DoubleSlider offsetYawSlider = createSlider("yaw", widgetWidth * 2 - 18, -180.0, 180.0); private final DoubleSlider offsetRollSlider = createSlider("roll", widgetWidth * 2 - 18, -180.0, 180.0); - private final CycleButton selectingButton = createCyclingButton(ImmutableSortedMap.of( + private final CycleButton selectingButton = createCyclingButtonBuilder(ImmutableSortedMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("forwardVector").withStyle(ChatFormatting.GREEN), 1, LocUtil.MODEL_VIEW_WIDGET("upwardVector").withStyle(ChatFormatting.RED), - 2, LocUtil.MODEL_VIEW_WIDGET("position").withStyle(ChatFormatting.BLUE)), - widgetWidth * 2 + 4, LocUtil.MODEL_VIEW_WIDGET("selecting"), i -> createTooltip("selecting", modifierKey.getDisplayName(), modifierKey.getDisplayName())); - private final CycleButton disableModeButton = createCyclingButton(ImmutableSortedMap.of( + 2, LocUtil.MODEL_VIEW_WIDGET("position").withStyle(ChatFormatting.BLUE))) + .withInitialValue(0) + .withTooltip(i -> createTooltip("selecting", modifierKey.getDisplayName(), modifierKey.getDisplayName())) + .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selecting")); + private final CycleButton disableModeButton = createCyclingButtonBuilder(ImmutableMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("all").withStyle(ChatFormatting.GREEN), - 1, LocUtil.MODEL_VIEW_WIDGET("part").withStyle(ChatFormatting.BLUE)), - widgetWidth * 2 + 4, LocUtil.MODEL_VIEW_WIDGET("disableMode"), i -> createTooltip("disableMode", modifierKey.getDisplayName())); - private final CycleButton selectionModeButton = createCyclingButton(ImmutableSortedMap.of( + 1, LocUtil.MODEL_VIEW_WIDGET("part").withStyle(ChatFormatting.BLUE))) + .withInitialValue(0) + .withTooltip(i -> createTooltip("disableMode", modifierKey.getDisplayName())) + .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("disableMode")); + private final CycleButton selectionModeButton = createCyclingButtonBuilder(ImmutableSortedMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("single"), 1, LocUtil.MODEL_VIEW_WIDGET("multiple"), - 2, LocUtil.MODEL_VIEW_WIDGET("range").withStyle(ChatFormatting.BLUE)), - widgetWidth * 2 + 4, LocUtil.MODEL_VIEW_WIDGET("selectionMode"), i -> createTooltip("selectionMode", modifierKey.getDisplayName(), modifierKey.getDisplayName())); - private final CycleButton toggleSliderButton = createCyclingButton(ImmutableSortedMap.of( + 2, LocUtil.MODEL_VIEW_WIDGET("range").withStyle(ChatFormatting.BLUE))) + .withInitialValue(0) + .withTooltip(i -> createTooltip("selectionMode", modifierKey.getDisplayName(), modifierKey.getDisplayName())) + .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selectionMode")); + private final CycleButton toggleSliderButton = createCyclingButtonBuilder(ImmutableMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("toggleSliderToField"), - 1, LocUtil.MODEL_VIEW_WIDGET("toggleFieldToSlider")), - widgetWidth * 2 + 4, i -> null, (button, i) -> { + 1, LocUtil.MODEL_VIEW_WIDGET("toggleFieldToSlider"))) + .withInitialValue(0) + .withTooltip(i -> createTooltip("toggleSlider")) + .displayOnlyValue() + .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("toggleSlider"), (button, i) -> { if (i == 1) { offsetXField.setNumber((float) offsetXSlider.getValue()); offsetYField.setNumber((float) offsetYSlider.getValue()); @@ -118,11 +126,14 @@ public class ModelViewScreen extends Screen { } initWidgets(page); }); - private final CycleButton toggleCategoryButton = createCyclingButton(ImmutableSortedMap.of( - 0, LocUtil.MODEL_VIEW_WIDGET(toggleConfigMap.get(0)), - 1, LocUtil.MODEL_VIEW_WIDGET(toggleConfigMap.get(1)), - 2, LocUtil.MODEL_VIEW_WIDGET(toggleConfigMap.get(2))), - widgetWidth * 2 - 18, i -> createTooltip(toggleConfigMap.get(i)), (button, i) -> initWidgets(0)); + private final CycleButton toggleCategoryButton = createCyclingButtonBuilder(ImmutableSortedMap.of( + Category.CONFIGS, LocUtil.MODEL_VIEW_WIDGET(Category.CONFIGS.next().id), + Category.PREVIEW, LocUtil.MODEL_VIEW_WIDGET(Category.PREVIEW.next().id), + Category.DISABLE, LocUtil.MODEL_VIEW_WIDGET(Category.DISABLE.next().id))) + .withInitialValue(Category.CONFIGS) + .withTooltip(category -> createTooltip(category.next().id)) + .displayOnlyValue() + .create(0, 0, widgetWidth * 2 - 18, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("toggleCategory"), (button, i) -> initWidgets(0)); public ModelViewScreen() { super(LocUtil.MODEL_VIEW_TITLE()); @@ -141,7 +152,7 @@ protected void init() { private void initWidgets(int page) { this.page = page; - if (toggleCategoryButton.getValue() == 1 && showTextureButton.getValue() == 0) { + if (toggleCategoryButton.getValue() == Category.DISABLE && showTextureButton.getValue() == 0) { modelViewArea = new ScreenRectangle(x + xSize / 2, y, middleWidth / 2, ySize); textureViewArea = new ScreenRectangle(x + (xSize - middleWidth) / 2, y, middleWidth / 2, ySize); } else { @@ -153,7 +164,7 @@ private void initWidgets(int page) { clearWidgets(); initLeftWidgets(); if (textureViewArea != null) rectWidgets.forEach(this::addRenderableWidget); - if (toggleCategoryButton.getValue() == 1) addRenderableWidget(showTextureButton).setPosition(x + (xSize - middleWidth) / 2 + 4, y + 4); + if (toggleCategoryButton.getValue() == Category.DISABLE) addRenderableWidget(showTextureButton).setPosition(x + (xSize - middleWidth) / 2 + 4, y + 4); addRenderableWidget(pauseButton).setPosition(x + (xSize + middleWidth) / 2 - 38, y + 4); addRenderableWidget(new TexturedButton(x + (xSize + middleWidth) / 2 - 20, y + 4, 16, 16, 0, 0, button -> { modelScale = textureScale = 80; @@ -193,91 +204,96 @@ private void initLeftWidgets() { grid.defaultCellSetting().padding(4, 2, 0, 0); LayoutSettings smallSettings = grid.newCellSettings().padding(5, 3, 1, 1); GridLayout.RowHelper rows = grid.createRowHelper(2); - if (toggleCategoryButton.getValue() == 0) { - rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("import"), widgetWidth, this::importBindTarget)).setTooltip(createTooltip("import")); - rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("export"), widgetWidth, this::exportBindTarget)).setTooltip(createTooltip("export")); - rows.addChild(entityPitchSlider, 2); - rows.addChild(entityYawSlider, 2); - rows.addChild(selectingButton, 2); - rows.addChild(forwardUField, smallSettings); - rows.addChild(forwardVField, smallSettings); - rows.addChild(upwardUField, smallSettings); - rows.addChild(upwardVField, smallSettings); - rows.addChild(posUField, smallSettings); - rows.addChild(posVField, smallSettings); - rows.addChild(textureIdField, 2, smallSettings).setTooltip(createTooltip("textureId")); - } else if (toggleCategoryButton.getValue() == 1) { - LayoutSettings offsetXSettings = grid.newCellSettings().padding(-13, 3, 1, 1); - rows.addChild(disableModeButton, 2); - rows.addChild(disabledIdField, 2, smallSettings).setTooltip(createTooltip("textureId")); - rows.addChild(selectionModeButton, 2); - rows.addChild(focusedRectWidgetNumberField, smallSettings).setOnValueChange(index -> { - if (index == 0) focusedRectWidget = null; - else if (index > 0 && index <= rectWidgets.size()) { - focusedRectWidget = rectWidgets.get(index - 1); - uMinField.setNumber(focusedRectWidget.uMin); - vMinField.setNumber(focusedRectWidget.vMin); - uMaxField.setNumber(focusedRectWidget.uMax); - vMaxField.setNumber(focusedRectWidget.vMax); - } - }).setTooltip(createTooltip("focusedRectangleNumber")); - addRenderableWidget(new StringWidget(x + 4 + widgetWidth + 3, y + 4 + (widgetHeight + 2) * 3, 6, widgetHeight, LocUtil.literal("/"), font)); - addRenderableWidget(rectWidgetsSizeWidget); - rows.addChild(new TexturedButton(48, 0, button -> deleteFocusedRectWidget()), grid.newCellSettings().padding(5 + widgetWidth - 18, 3, 1, 1)) - .setTooltip(createTooltip("deleteSelectedRectangle")); - rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("uMin:"), font)); - rows.addChild(uMinField, offsetXSettings).setOnValueChange(f -> { - if (focusedRectWidget != null) focusedRectWidget.uMin = f; - }); - rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("vMin:"), font)); - rows.addChild(vMinField, offsetXSettings).setOnValueChange(f -> { - if (focusedRectWidget != null) focusedRectWidget.vMin = f; - }); - rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("uMax:"), font)); - rows.addChild(uMaxField, offsetXSettings).setOnValueChange(f -> { - if (focusedRectWidget != null) focusedRectWidget.uMax = f; - }); - rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("vMax:"), font)); - rows.addChild(vMaxField, offsetXSettings).setOnValueChange(f -> { - if (focusedRectWidget != null) focusedRectWidget.vMax = f; - }); - } else { - boolean useSliderOffset = toggleSliderButton.getValue() == 0; - rows.addChild(toggleSliderButton, 2); - LayoutSettings sliderSettings = grid.newCellSettings().padding(-20, 2, 0, 0); - LayoutSettings fieldSettings = grid.newCellSettings().padding(-17, 3, 1, 1); - rows.addChild(bindXButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetXSlider, sliderSettings); - else rows.addChild(offsetXField, fieldSettings); - rows.addChild(bindYButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetYSlider, sliderSettings); - else rows.addChild(offsetYField, fieldSettings); - rows.addChild(bindZButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetZSlider, sliderSettings); - else rows.addChild(offsetZField, fieldSettings); - rows.addChild(bindRotButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetPitchSlider, sliderSettings); - else rows.addChild(offsetPitchField, fieldSettings); - if (useSliderOffset) rows.addChild(offsetYawSlider, 2, grid.newCellSettings().padding(26, 2, 0, 0)); - else rows.addChild(offsetYawField, 2, grid.newCellSettings().padding(29, 3, 1, 1)); - rows.addChild(new TexturedButton(0, 0, button -> { - offsetXField.setNumber(0f); - offsetYField.setNumber(0f); - offsetZField.setNumber(0f); - offsetPitchField.setNumber(0f); - offsetYawField.setNumber(0f); - offsetRollField.setNumber(0f); - offsetXSlider.setValue(0); - offsetYSlider.setValue(0); - offsetZSlider.setValue(0); - offsetPitchSlider.setValue(0); - offsetYawSlider.setValue(0); - offsetRollSlider.setValue(0); - }), smallSettings); - if (useSliderOffset) rows.addChild(offsetRollSlider, sliderSettings); - else rows.addChild(offsetRollField, fieldSettings); - rows.addChild(scaleField, smallSettings).setTooltip(createTooltip("scale")); - rows.addChild(depthField, smallSettings).setTooltip(createTooltip("depth")); + switch (toggleCategoryButton.getValue()) { + case CONFIGS -> { + rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("import"), widgetWidth, this::importBindTarget)).setTooltip(createTooltip("import")); + rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("export"), widgetWidth, this::exportBindTarget)).setTooltip(createTooltip("export")); + rows.addChild(entityPitchSlider, 2); + rows.addChild(entityYawSlider, 2); + rows.addChild(selectingButton, 2); + rows.addChild(forwardUField, smallSettings); + rows.addChild(forwardVField, smallSettings); + rows.addChild(upwardUField, smallSettings); + rows.addChild(upwardVField, smallSettings); + rows.addChild(posUField, smallSettings); + rows.addChild(posVField, smallSettings); + rows.addChild(textureIdField, 2, smallSettings).setTooltip(createTooltip("textureId")); + } + case PREVIEW -> { + boolean useSliderOffset = toggleSliderButton.getValue() == 0; + rows.addChild(toggleSliderButton, 2); + LayoutSettings sliderSettings = grid.newCellSettings().padding(-20, 2, 0, 0); + LayoutSettings fieldSettings = grid.newCellSettings().padding(-17, 3, 1, 1); + rows.addChild(bindXButton, smallSettings).setTooltip(createTooltip("bindButtons")); + if (useSliderOffset) rows.addChild(offsetXSlider, sliderSettings); + else rows.addChild(offsetXField, fieldSettings); + rows.addChild(bindYButton, smallSettings).setTooltip(createTooltip("bindButtons")); + if (useSliderOffset) rows.addChild(offsetYSlider, sliderSettings); + else rows.addChild(offsetYField, fieldSettings); + rows.addChild(bindZButton, smallSettings).setTooltip(createTooltip("bindButtons")); + if (useSliderOffset) rows.addChild(offsetZSlider, sliderSettings); + else rows.addChild(offsetZField, fieldSettings); + rows.addChild(bindRotButton, smallSettings).setTooltip(createTooltip("bindButtons")); + if (useSliderOffset) rows.addChild(offsetPitchSlider, sliderSettings); + else rows.addChild(offsetPitchField, fieldSettings); + if (useSliderOffset) rows.addChild(offsetYawSlider, 2, grid.newCellSettings().padding(26, 2, 0, 0)); + else rows.addChild(offsetYawField, 2, grid.newCellSettings().padding(29, 3, 1, 1)); + rows.addChild(new TexturedButton(0, 0, button -> { + offsetXField.setNumber(0f); + offsetYField.setNumber(0f); + offsetZField.setNumber(0f); + offsetPitchField.setNumber(0f); + offsetYawField.setNumber(0f); + offsetRollField.setNumber(0f); + offsetXSlider.setValue(0); + offsetYSlider.setValue(0); + offsetZSlider.setValue(0); + offsetPitchSlider.setValue(0); + offsetYawSlider.setValue(0); + offsetRollSlider.setValue(0); + }), smallSettings); + if (useSliderOffset) rows.addChild(offsetRollSlider, sliderSettings); + else rows.addChild(offsetRollField, fieldSettings); + rows.addChild(scaleField, smallSettings).setTooltip(createTooltip("scale")); + rows.addChild(depthField, smallSettings).setTooltip(createTooltip("depth")); + } + case DISABLE -> { + LayoutSettings offsetXSettings = grid.newCellSettings().padding(-13, 3, 1, 1); + rows.addChild(disableModeButton, 2); + rows.addChild(disabledIdField, 2, smallSettings).setTooltip(createTooltip("textureId")); + rows.addChild(selectionModeButton, 2); + rows.addChild(focusedRectWidgetNumberField, smallSettings).setOnValueChange(index -> { + if (index == 0) focusedRectWidget = null; + else if (index > 0 && index <= rectWidgets.size()) { + focusedRectWidget = rectWidgets.get(index - 1); + uMinField.setNumber(focusedRectWidget.uMin); + vMinField.setNumber(focusedRectWidget.vMin); + uMaxField.setNumber(focusedRectWidget.uMax); + vMaxField.setNumber(focusedRectWidget.vMax); + } + }).setTooltip(createTooltip("focusedRectangleNumber")); + addRenderableWidget(new StringWidget(x + 4 + widgetWidth + 3, y + 4 + (widgetHeight + 2) * 3, 6, widgetHeight, LocUtil.literal("/"), font)); + addRenderableWidget(rectWidgetsSizeWidget); + rows.addChild(new TexturedButton(48, 0, button -> deleteFocusedRectWidget()), grid.newCellSettings().padding(5 + widgetWidth - 18, 3, 1, 1)) + .setTooltip(createTooltip("deleteSelectedRectangle")); + rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("uMin:"), font)); + rows.addChild(uMinField, offsetXSettings).setOnValueChange(f -> { + if (focusedRectWidget != null) focusedRectWidget.uMin = f; + }); + rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("vMin:"), font)); + rows.addChild(vMinField, offsetXSettings).setOnValueChange(f -> { + if (focusedRectWidget != null) focusedRectWidget.vMin = f; + }); + rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("uMax:"), font)); + rows.addChild(uMaxField, offsetXSettings).setOnValueChange(f -> { + if (focusedRectWidget != null) focusedRectWidget.uMax = f; + }); + rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("vMax:"), font)); + rows.addChild(vMaxField, offsetXSettings).setOnValueChange(f -> { + if (focusedRectWidget != null) focusedRectWidget.vMax = f; + }); + } + default -> throw new IllegalStateException("Unexpected value: " + toggleCategoryButton.getValue()); } rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("save"), widgetWidth, button -> { if (nameField.getValue().isBlank()) { @@ -309,7 +325,7 @@ private void initRightWidgets() { if (CompatibilityHelper.isModLoaded("cloth-config")) minecraft.setScreen(ConfigScreen.create(this)); }), smallSettings).setTooltip(createTooltip("toConfigScreen")); final int widgetsPerPage, size; - if (toggleCategoryButton.getValue() == 1) { + if (toggleCategoryButton.getValue() == Category.DISABLE) { widgetsPerPage = 6; size = disableConfigs.size(); rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("copy"), widgetWidth, button -> configsInClipBoard = List.copyOf(disableConfigs)), 2).setTooltip(createTooltip("copy")); @@ -414,7 +430,7 @@ public boolean deleteFocusedRectWidget() { @Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { super.render(graphics, mouseX, mouseY, deltaTick); - if (toggleCategoryButton.getValue() == 1 && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) { + if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) { GUIHelper.enableScissor(graphics, modelViewArea); graphics.fill(mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius, 400, 0x4F3333CC); graphics.disableScissor(); @@ -442,20 +458,20 @@ public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float } protected void applyAnalyser(GuiGraphics graphics, int mouseX, int mouseY) { - String textureId = toggleCategoryButton.getValue() == 0 ? "" : disabledIdField.getValue(); + String textureId = toggleCategoryButton.getValue() == Category.DISABLE ? disabledIdField.getValue() : ""; Set hiddenNames = hiddenNameMap.getOrDefault(nameField.getValue(), Set.of()); analyser.applyDisableConfigs(textureId, hiddenNames); - if (toggleCategoryButton.getValue() == 1 && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) + if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius); if (inTextureViewArea(mouseX, mouseY)) analyser.computeFocusedOnTexture(mouseX, mouseY); if (inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(mouseX, mouseY, layers); - if (toggleCategoryButton.getValue() == 0 || selectionModeButton.getValue() == 1) analyser.computeFocusedPolyhedron(); + if (toggleCategoryButton.getValue() == Category.CONFIGS || selectionModeButton.getValue() == 1) analyser.computeFocusedPolyhedron(); focusedPolyhedron = analyser.focusedPolyhedron.toArray(new VertexData[0][]); focusedTextureId = analyser.getFocusedTextureId(); GUIHelper.enableScissor(graphics, modelViewArea); analyser.drawModel(graphics, analyser.modelPose); - if (toggleCategoryButton.getValue() != 2) analyser.drawFocusedInModelArea(graphics); - if (toggleCategoryButton.getValue() == 0) analyser.drawBindTarget(graphics); + if (toggleCategoryButton.getValue() != Category.PREVIEW) analyser.drawFocusedInModelArea(graphics); + if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics); else analyser.drawCameraDirections(graphics); graphics.disableScissor(); if (textureViewArea != null) { @@ -622,12 +638,8 @@ protected Button createButton(Component message, int width, Button.OnPress onPre return Button.builder(message, onPress).size(width, widgetHeight).build(); } - protected CycleButton createCyclingButton(SequencedMap messages, int width, Component optionText, OptionInstance.TooltipSupplier tooltipSupplier) { - return new CycleButton.Builder(messages::get).withValues(messages.sequencedKeySet()).withInitialValue(0).withTooltip(tooltipSupplier).create(0, 0, width, widgetHeight, optionText); - } - - protected CycleButton createCyclingButton(SequencedMap messages, int width, OptionInstance.TooltipSupplier tooltipSupplier, CycleButton.OnValueChange onValueChange) { - return new CycleButton.Builder(messages::get).withValues(messages.sequencedKeySet()).withInitialValue(0).withTooltip(tooltipSupplier).displayOnlyValue().create(0, 0, width, widgetHeight, Component.empty(), onValueChange); + protected CycleButton.Builder createCyclingButtonBuilder(Map messages) { + return new CycleButton.Builder(messages::get).withValues(messages.keySet()); } protected DoubleSlider createSlider(String key, int width, double min, double max) { @@ -655,7 +667,7 @@ protected boolean inTextureViewArea(double x, double y) { public boolean leftClickedWithModifier(double mouseX, double mouseY) { if (focusedPolyhedron.length == 0) return false; - if (inModelViewArea(mouseX, mouseY) && toggleCategoryButton.getValue() == 0) { + if (inModelViewArea(mouseX, mouseY) && toggleCategoryButton.getValue() == Category.CONFIGS) { float u = 0, v = 0; for (VertexData vertex : focusedPolyhedron[0]) { u += vertex.u(); @@ -675,7 +687,7 @@ public boolean leftClickedWithModifier(double mouseX, double mouseY) { } textureIdField.setValue(focusedTextureId); return true; - } else if ((inModelViewArea(mouseX, mouseY) || inTextureViewArea(mouseX, mouseY)) && toggleCategoryButton.getValue() == 1) { + } else if ((inModelViewArea(mouseX, mouseY) || inTextureViewArea(mouseX, mouseY)) && toggleCategoryButton.getValue() == Category.DISABLE) { String disabledId = disabledIdField.getValue(); if (disabledId.isBlank() || !focusedTextureId.contains(disabledId)) { disabledIdField.setValue(focusedTextureId); @@ -730,7 +742,7 @@ public boolean leftClickedWithModifier(double mouseX, double mouseY) { public boolean mouseClicked(double mouseX, double mouseY, int button) { double storedX = clickedX, storedY = clickedY; clickedX = clickedY = -1; - if (button == InputConstants.MOUSE_BUTTON_LEFT && toggleCategoryButton.getValue() != 2) { + if (button == InputConstants.MOUSE_BUTTON_LEFT && toggleCategoryButton.getValue() != Category.PREVIEW) { if (InputConstants.isKeyDown(minecraft.getWindow().getWindow(), modifierKey.getValue())) { if (leftClickedWithModifier(mouseX, mouseY)) return true; } else if (inTextureViewArea(mouseX, mouseY)) { @@ -775,7 +787,7 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { if (inModelViewArea(mouseX, mouseY)) { if (InputConstants.isKeyDown(minecraft.getWindow().getWindow(), modifierKey.getValue())) { - if (toggleCategoryButton.getValue() == 1 && selectionModeButton.getValue() == 2) + if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2) selectionRadius = Mth.clamp(selectionRadius + (int) verticalAmount * 2, 2, 48); else layers = Math.max(0, layers + (int) verticalAmount); } else { @@ -906,4 +918,16 @@ public void setFocused(boolean focused) { @Override protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { } } + + private enum Category { + CONFIGS, + PREVIEW, + DISABLE; + + public final String id = name().toLowerCase(); + + public Category next() { + return values()[(ordinal() + 1) % values().length]; + } + } } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 46562cf6..39d04c4d 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -30,7 +30,7 @@ "depends": { "fabricloader": "*", "fabric-api": "*", - "minecraft": "~1.21.1", + "minecraft": "1.21.1", "java": ">=21" }, "recommends": { From 331ffc9a16feb1d484add5b233c42012dc4259c2 Mon Sep 17 00:00:00 2001 From: H31M5 <2211923909@qq.com> Date: Sat, 22 Nov 2025 12:02:18 +0800 Subject: [PATCH 03/33] Added issues templates (#185) --- .github/ISSUE_TEMPLATE/bug_report_cn.yml | 79 ++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/bug_report_en.yml | 79 ++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report_cn.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report_en.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml new file mode 100644 index 00000000..6816f0ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -0,0 +1,79 @@ +name: Bug反馈 +description: 中文Bug反馈模板 +title: "[Bug]: " +labels: [ "bug" ] + +body: + - type: markdown + attributes: + value: | + 请确保您使用的是最新版的RC,您反馈的bug很可能已经在更新版本中修复 + (查看尾缀是否与最新工件相同) + 在反馈bug前,请先尝试搜索是否已有相似的问题,请不要重复打开相同的issue + + 所有有关YSM的问题,请您优先寻求他人的帮助,或者观看配置模型教程 + 而不是直接在issue中提问。 + + - type: checkboxes + id: preliminary + attributes: + label: 我已确认 ... + options: + - label: 我正在使用最新版的RC + required: true + - label: 无法在关闭主要功能时复现 + required: true + + - type: input + id: minecraft-version + attributes: + label: Minecraft版本 + description: | + 你所使用的Minecraft的版本. + + 你可以在游戏主界面作下角或者游戏启动时的日志开头等地方找到. + validations: + required: true + + - type: textarea + id: incompatible-mods + attributes: + label: 不兼容的mod + description: >- + 和bug相关的模组 +
请在反馈问题前尝试尽可能移除不相干的模组的情况下复现bug + placeholder: 'Mods list here' + render: 'raw' + validations: + required: true + + - type: textarea + id: description + attributes: + label: 错误描述 + description: >- + 请尽可能详细的描述遇到的问题. +
越清晰和详尽的描述会使该bug的处理优先级更高 + validations: + required: true + + - type: textarea + id: step + attributes: + label: 复现步骤 + placeholder: | + 1. Join the game... + + 2. Change some settings... + + 3. ... + + - type: textarea + id: logs + attributes: + label: 日志和崩溃报告 + description: >- + 你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能 +
你可以日志上传到类似 https://paste.ubuntu.com/ 或者 https://mclo.gs/ 的网站并在此贴出链接 +
**请不要在此此处直接粘贴大段的日志文本!!** + placeholder: '把日志文件往这丢或者使用外部链接' diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.yml b/.github/ISSUE_TEMPLATE/bug_report_en.yml new file mode 100644 index 00000000..e7b93934 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_en.yml @@ -0,0 +1,79 @@ +name: Bug Report +description: English template for reporting a bug +title: "[Bug]: " +labels: [ "bug" ] + +body: + - type: markdown + attributes: + value: | + Make sure you're using the latest version of RealCamera, the bug you're reporting has most likely been fixed in the latest update + (Check if the suffix matches the latest artifact) + Before reporting a bug, please search for similar issues first and avoid opening duplicate issues + + For all YSM-related questions, please seek help from others or watch configuration model tutorials first + instead of asking directly in the issue. + + - type: checkboxes + id: preliminary + attributes: + label: I have confirmed that ... + options: + - label: I am using the latest version of RealCamera + required: true + - label: Unable to reproduce when main feature is disabled + required: true + + - type: input + id: minecraft-version + attributes: + label: Minecraft Version + description: | + The Minecraft version you are using. + + You can find them at the corner of main menu or in the log while startup. + validations: + required: true + + - type: textarea + id: incompatible-mods + attributes: + label: Incompatible Mods + description: >- + The mods related to the bug. +
Try to remove unrelated plugins and mods before reporting + placeholder: 'Mods list here' + render: 'raw' + validations: + required: true + + - type: textarea + id: description + attributes: + label: Bug Description + description: >- + Please describe the issue you encountered in as much detail as possible. +
Clearer and more detailed descriptions will receive higher processing priority + validations: + required: true + + - type: textarea + id: step + attributes: + label: Reproduction Steps + placeholder: | + 1. Join the game... + + 2. Change some settings... + + 3. ... + + - type: textarea + id: logs + attributes: + label: Logs & Crash Reports + description: >- + You can find error reports in /logs/latest.log and /crash-reports, or use the launcher's export function +
You can upload logs to sites like https://paste.ubuntu.com/ or https://mclo.gs/ and post the link here +
**DO NOT PASTE LARGE LOGS DIRECTLY HERE!!** + placeholder: 'Drag log file here or use external link' \ No newline at end of file From 34db664907d8af8b62d856d0c4d0ed28bd96d753 Mon Sep 17 00:00:00 2001 From: xTracr Date: Fri, 28 Nov 2025 00:30:26 +0800 Subject: [PATCH 04/33] Added cache for DisableConfig --- .../com/xtracr/realcamera/RealCameraCore.java | 2 +- .../xtracr/realcamera/config/BindTarget.java | 108 +++++++++++++++++- .../xtracr/realcamera/config/ModConfig.java | 3 +- .../realcamera/gui/CyclingTexturedButton.java | 4 +- .../xtracr/realcamera/gui/ModelAnalyser.java | 2 +- .../realcamera/gui/ModelViewScreen.java | 11 +- .../xtracr/realcamera/gui/NumberField.java | 4 +- .../xtracr/realcamera/gui/TexturedButton.java | 4 +- 8 files changed, 119 insertions(+), 19 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 62506e21..a860ecf3 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -140,7 +140,7 @@ public static void renderCameraEntity(Minecraft client, float deltaTick, MultiBu for (VertexData vertex : primitive) { if (Math.fma(m02, vertex.x(), Math.fma(m12, vertex.y(), Math.fma(m22, vertex.z(), m32))) > -depth) continue; for (DisableConfig config : disableConfigs) { - if (config.test(vertex)) continue primitiveFor; + if (config.disable(vertex)) continue primitiveFor; } for (VertexData vertexData : primitive) vertexData.render(buffer); break; diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index c92c009c..290bae3f 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -1,9 +1,17 @@ package com.xtracr.realcamera.config; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; import com.xtracr.realcamera.util.VertexData; +import it.unimi.dsi.fastutil.floats.Float2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.floats.FloatOpenHashSet; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.util.Mth; +import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -14,9 +22,9 @@ public record BindTarget( BindConfig bindConfig, OffsetConfig offsets, DisableConfig[] disableConfigs) { - private static final short serialVersion = 703; public static final List defaultTargets; public static final BindTarget EMPTY = blank(null, null); + private static final short serialVersion = 703; static { defaultTargets = List.of( @@ -200,7 +208,22 @@ public void write(FriendlyByteBuf byteBuf) { } } - public record DisableConfig(String name, String textureId, boolean disableAll, UVRectangle[] rectangles) implements Predicate { + @JsonAdapter(DisableConfig.Adapter.class) + public static class DisableConfig { + private final Float2ObjectOpenHashMap disableCacheMap = new Float2ObjectOpenHashMap<>(); + private final String name; + private final String textureId; + private final boolean disableAll; + private final UVRectangle[] rectangles; + + public DisableConfig(String name, String textureId, boolean disableAll, UVRectangle[] rectangles) { + this.name = name; + this.textureId = textureId; + this.disableAll = disableAll; + this.rectangles = rectangles; + disableCacheMap.defaultReturnValue(FloatOpenHashSet.of()); + } + public static DisableConfig read(FriendlyByteBuf byteBuf) { String name = byteBuf.readUtf(); String textureId = byteBuf.readUtf(); @@ -212,6 +235,22 @@ public static DisableConfig read(FriendlyByteBuf byteBuf) { return new DisableConfig(name, textureId, disableAll, rectangles); } + public String name() { + return name; + } + + public String textureId() { + return textureId; + } + + public boolean disableAll() { + return disableAll; + } + + public UVRectangle[] rectangles() { + return rectangles; + } + public void write(FriendlyByteBuf byteBuf) { byteBuf.writeUtf(name); byteBuf.writeUtf(textureId); @@ -222,14 +261,73 @@ public void write(FriendlyByteBuf byteBuf) { } } - @Override - public boolean test(VertexData vertex) { + public boolean disable(VertexData vertex) { final float u = vertex.u(), v = vertex.v(); + final FloatOpenHashSet cachedVs = disableCacheMap.get(u); + if (!cachedVs.isEmpty()) { + if (cachedVs.contains(v)) return true; + if (cachedVs.contains(-v)) return false; + } for (UVRectangle rect : rectangles) { - if (rect.contains(u, v)) return true; + if (!rect.contains(u, v)) continue; + disableCacheMap.computeIfAbsent(u, k -> new FloatOpenHashSet()).add(v); + return true; } + disableCacheMap.computeIfAbsent(u, k -> new FloatOpenHashSet()).add(-v); return false; } + + public static class Adapter extends TypeAdapter { + @Override + public void write(JsonWriter out, DisableConfig value) throws IOException { + out.beginObject(); + out.name("name").value(value.name()); + out.name("textureId").value(value.textureId()); + out.name("disableAll").value(value.disableAll()); + out.name("rectangles"); + out.beginArray(); + for (UVRectangle rect : value.rectangles()) { + out.beginObject(); + out.name("uMin").value(rect.uMin()); + out.name("vMin").value(rect.vMin()); + out.name("uMax").value(rect.uMax()); + out.name("vMax").value(rect.vMax()); + out.endObject(); + } + out.endArray(); + out.endObject(); + } + + @Override + public DisableConfig read(JsonReader in) throws IOException { + in.beginObject(); + in.nextName(); + String name = in.nextString(); + in.nextName(); + String textureId = in.nextString(); + in.nextName(); + boolean disableAll = in.nextBoolean(); + in.nextName(); + in.beginArray(); + ArrayList rectangles = new ArrayList<>(); + while (in.hasNext()) { + in.beginObject(); + in.nextName(); + float uMin = (float) in.nextDouble(); + in.nextName(); + float vMin = (float) in.nextDouble(); + in.nextName(); + float uMax = (float) in.nextDouble(); + in.nextName(); + float vMax = (float) in.nextDouble(); + in.endObject(); + rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); + } + in.endArray(); + in.endObject(); + return new DisableConfig(name, textureId, disableAll, rectangles.toArray(UVRectangle[]::new)); + } + } } public record UVRectangle(float uMin, float vMin, float uMax, float vMax) { diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index a84bb5b7..8a4e186e 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -221,7 +221,7 @@ public List getBindTargetList(String textureId) { binding.clamp(); int activeConfigIndex = binding.activeConfigIndex; List matchedTargets = binding.targetList.stream().filter(target -> textureId.contains(target.textureId())).toList(); - if (activeConfigIndex == 0 || matchedTargets.isEmpty()) return matchedTargets; + if (activeConfigIndex <= 0 || matchedTargets.isEmpty()) return matchedTargets; return List.of(matchedTargets.get(Math.clamp(activeConfigIndex - 1, 0, matchedTargets.size() - 1))); } @@ -311,6 +311,7 @@ private void clamp() { } swimOutTick = Mth.clamp(swimOutTick, 0, 40); bindResultRetentionFrames = Math.max(bindResultRetentionFrames, 0); + activeConfigIndex = Math.max(activeConfigIndex, 0); displacementSmoothFactor = Mth.clamp(displacementSmoothFactor, 0.0, 1.0); rotationSmoothFactor = Mth.clamp(rotationSmoothFactor, 0.0, 1.0); if (disableMainFeatureItems == null) disableMainFeatureItems = List.of(); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java b/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java index f75d7be7..a10c17bf 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java @@ -4,7 +4,7 @@ import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; @@ -26,7 +26,7 @@ public CyclingTexturedButton(int x, int y, int width, int height, int u, int v, } public CyclingTexturedButton(int x, int y, int width, int height, int u, int v, int vOffset, int value, int size, ResourceLocation texture, int textureWidth, int textureHeight) { - super(x, y, width, height, Component.empty()); + super(x, y, width, height, CommonComponents.EMPTY); this.u = u; this.v = v; this.vOffset = vOffset; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 1c804ceb..151d8bec 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -98,7 +98,7 @@ public void applyDisableConfigs(String textureId, Set hiddenNames) { primitiveFor: for (VertexData vertex : primitive) { for (DisableConfig config : disableConfigs) { - if (config.test(vertex)) continue primitiveFor; + if (config.disable(vertex)) continue primitiveFor; } primitives.add(primitive); break; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 2c118263..b5a21cb6 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -26,6 +26,7 @@ import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; @@ -108,7 +109,7 @@ public class ModelViewScreen extends Screen { .withInitialValue(0) .withTooltip(i -> createTooltip("toggleSlider")) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("toggleSlider"), (button, i) -> { + .create(0, 0, widgetWidth * 2 + 4, widgetHeight, CommonComponents.EMPTY, (button, i) -> { if (i == 1) { offsetXField.setNumber((float) offsetXSlider.getValue()); offsetYField.setNumber((float) offsetYSlider.getValue()); @@ -133,7 +134,7 @@ public class ModelViewScreen extends Screen { .withInitialValue(Category.CONFIGS) .withTooltip(category -> createTooltip(category.next().id)) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 - 18, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("toggleCategory"), (button, i) -> initWidgets(0)); + .create(0, 0, widgetWidth * 2 - 18, widgetHeight, CommonComponents.EMPTY, (button, i) -> initWidgets(0)); public ModelViewScreen() { super(LocUtil.MODEL_VIEW_TITLE()); @@ -651,7 +652,7 @@ protected NumberField createFloatField(int width, float defaultValue, @Nu } protected EditBox createTextField(int width, int maxLength, @Nullable EditBox copyFrom) { - EditBox editBox = new EditBox(font, 0, 0, width - 2, widgetHeight - 2, Component.empty()); + EditBox editBox = new EditBox(font, 0, 0, width - 2, widgetHeight - 2, CommonComponents.EMPTY); editBox.setMaxLength(maxLength); if (copyFrom != null) editBox.setValue(copyFrom.getValue()); return editBox; @@ -818,7 +819,7 @@ public class UVRectangleWidget extends AbstractWidget { protected float uMin, vMin, uMax, vMax; public UVRectangleWidget(float uMin, float vMin, float uMax, float vMax) { - super(0, 0, 16, 16, Component.empty()); + super(0, 0, 16, 16, CommonComponents.EMPTY); this.uMin = uMin; this.vMin = vMin; this.uMax = uMax; @@ -826,7 +827,7 @@ public UVRectangleWidget(float uMin, float vMin, float uMax, float vMax) { } public UVRectangleWidget(float xMin, float yMin, float xMax, float yMax, @NotNull ScreenRectangle screenArea) { - super((int) xMin, (int) yMin, (int) (xMax - xMin), (int) (yMax - yMin), Component.empty()); + super((int) xMin, (int) yMin, (int) (xMax - xMin), (int) (yMax - yMin), CommonComponents.EMPTY); Vec2 minUV = translateXYToUV(xMin, yMin, screenArea), maxUV = translateXYToUV(xMax, yMax, screenArea); this.uMin = minUV.x; this.vMin = minUV.y; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/NumberField.java b/common/src/main/java/com/xtracr/realcamera/gui/NumberField.java index 93ffba2f..7a5534ee 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/NumberField.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/NumberField.java @@ -7,7 +7,7 @@ import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.navigation.CommonInputs; -import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Style; import net.minecraft.util.FormattedCharSequence; import org.jetbrains.annotations.Nullable; @@ -20,7 +20,7 @@ public abstract class NumberField> extends EditBox { private Tooltip tooltip; NumberField(Font font, int width, int height, T defaultValue, T maximum, T minimum, @Nullable NumberField copyFrom) { - super(font, 0, 0, width, height, Component.empty()); + super(font, 0, 0, width, height, CommonComponents.EMPTY); this.defaultValue = defaultValue; this.maximum = maximum; this.minimum = minimum; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java b/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java index b4882678..ec0a6447 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java @@ -4,7 +4,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.resources.ResourceLocation; import java.util.function.Consumer; @@ -24,7 +24,7 @@ public TexturedButton(int x, int y, int width, int height, int u, int v, Consume } public TexturedButton(int x, int y, int width, int height, int u, int v, ResourceLocation texture, int textureWidth, int textureHeight, Consumer onPress) { - super(x, y, width, height, Component.empty()); + super(x, y, width, height, CommonComponents.EMPTY); this.textureWidth = textureWidth; this.textureHeight = textureHeight; this.onPress = onPress; From 3805e0d1b5563f18c9582abf4a143861129cc2d8 Mon Sep 17 00:00:00 2001 From: xTracr Date: Fri, 26 Dec 2025 16:00:21 +0800 Subject: [PATCH 05/33] Update dependencies --- build.gradle | 7 +++---- fabric/build.gradle | 6 ++++-- gradle.properties | 17 ++++++++--------- gradle/wrapper/gradle-wrapper.jar | Bin 43705 -> 45633 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 7 ++----- gradlew.bat | 3 +-- neoforge/build.gradle | 6 ++++-- 8 files changed, 23 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index 9dc142f3..cd909ce2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.11-SNAPSHOT" apply false + id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false } architectury { @@ -18,7 +18,6 @@ subprojects { dependencies { minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" mappings loom.officialMojangMappings() - //mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2" } } @@ -28,11 +27,11 @@ allprojects { apply plugin: "maven-publish" base { - archivesName = rootProject.archives_base_name + archivesName = rootProject.mod_id } version = rootProject.mod_version + (findProperty("commitSHA") ? "-${(commitSHA as String).substring(0,7)}" : "") - group = rootProject.maven_group + group = rootProject.mod_group_id repositories { maven { url "https://maven.shedaniel.me/" } diff --git a/fabric/build.gradle b/fabric/build.gradle index 6e67a066..d3fa27df 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,8 +1,10 @@ plugins { - id "com.github.johnrengelman.shadow" version "8.1.1" + id "com.gradleup.shadow" version "9.3.0" } -archivesBaseName = rootProject.archives_base_name + "-" + rootProject.minecraft_version + "-fabric" +base { + archivesName = rootProject.mod_id + "-" + rootProject.minecraft_version + "-fabric" +} architectury { platformSetupLoomIde() diff --git a/gradle.properties b/gradle.properties index 556d4a35..8adf3338 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,17 +2,16 @@ org.gradle.jvmargs=-Xmx4G -XX:+UseG1GC org.gradle.parallel=true org.gradle.caching=true -# Loader Properties +## Environment Properties minecraft_version=1.21.1 enabled_platforms=fabric,neoforge -fabric_loader_version=0.17.2 -neoforge_version=21.1.194 -#yarn_mappings=1.21.1+build.3 -# Mod Properties +fabric_loader_version=0.18.4 +neoforge_version=21.1.217 +## Mod Properties +mod_id=realcamera mod_version=0.7.5-beta -maven_group=com.xtracr.realcamera -archives_base_name=realcamera -# Dependencies -fabric_api_version=0.116.5+1.21.1 +mod_group_id=com.xtracr.realcamera +## Dependencies +fabric_api_version=0.116.7+1.21.1 cloth_config_version=15.0.140 modmenu_version=11.0.3 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975c742b298b441bfb90dbc124400a3751b9..f8e1ee3125fe0768e9a76ee977ac089eb657005e 100644 GIT binary patch delta 37435 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 delta 35540 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%0A!3{ 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 D0|+Ag diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ca025c83..23449a2b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf93008..adff685a 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a218..c4bdd3ab 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/neoforge/build.gradle b/neoforge/build.gradle index cd74fd10..1a5e1213 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -1,8 +1,10 @@ plugins { - id "com.github.johnrengelman.shadow" version "8.1.1" + id "com.gradleup.shadow" version "9.3.0" } -archivesBaseName = rootProject.archives_base_name + "-" + rootProject.minecraft_version + "-neoforge" +base { + archivesName = rootProject.mod_id + "-" + rootProject.minecraft_version + "-neoforge" +} architectury { platformSetupLoomIde() From 312c8a8e18cc044f0ea2ca0084fdef60c302fe2b Mon Sep 17 00:00:00 2001 From: H31M5 <2211923909@qq.com> Date: Mon, 2 Mar 2026 22:57:45 +0800 Subject: [PATCH 06/33] Allowed to disable the main feature when crawling (#198) --- .github/ISSUE_TEMPLATE/bug_report_cn.yml | 8 +-- .github/ISSUE_TEMPLATE/bug_report_en.yml | 6 +- .../realcamera/compat/DisableHelper.java | 3 +- .../realcamera/config/ConfigScreen.java | 59 ++++++++++--------- .../xtracr/realcamera/config/ModConfig.java | 5 ++ .../realcamera/gui/ModelViewScreen.java | 7 ++- .../assets/realcamera/lang/en_us.json | 11 ++-- .../assets/realcamera/lang/zh_cn.json | 9 ++- 8 files changed, 64 insertions(+), 44 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml index 6816f0ff..02018ff9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_cn.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -25,11 +25,11 @@ body: required: true - type: input - id: minecraft-version + id: minecraft-version-loader attributes: - label: Minecraft版本 + label: Minecraft版本和加载器 description: | - 你所使用的Minecraft的版本. + 请填写游戏版本与所使用的加载器. 你可以在游戏主界面作下角或者游戏启动时的日志开头等地方找到. validations: @@ -76,4 +76,4 @@ body: 你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能
你可以日志上传到类似 https://paste.ubuntu.com/ 或者 https://mclo.gs/ 的网站并在此贴出链接
**请不要在此此处直接粘贴大段的日志文本!!** - placeholder: '把日志文件往这丢或者使用外部链接' + placeholder: '把日志文件往这丢或者使用外部链接' \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.yml b/.github/ISSUE_TEMPLATE/bug_report_en.yml index e7b93934..2be682d9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_en.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_en.yml @@ -25,11 +25,11 @@ body: required: true - type: input - id: minecraft-version + id: minecraft-version-loader attributes: - label: Minecraft Version + label: Minecraft Version and Loader description: | - The Minecraft version you are using. + Please specify the game version and your mod loader. You can find them at the corner of main menu or in the log while startup. validations: diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index d38b0d69..e0953e03 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -27,6 +27,7 @@ public class DisableHelper { MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSneaking() && player.isCrouching()); MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSwimming() && swimmingRecently(player, ConfigFile.config().getBindingSwimOutTick())); MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSwimming() && swimmingRecently(player, ConfigFile.config().getClassicSwimOutTick())); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenCrawling() && player.isVisuallyCrawling()); MAIN_FEATURE.registerOrInBinding(player -> { Item mainHand = player.getMainHandItem().getItem(); Item offHand = player.getOffhandItem().getItem(); @@ -133,4 +134,4 @@ public boolean disabled(Entity cameraEntity) { return ConfigFile.config().isClassic() ? predicateInClassic.test(player) : predicateInBinding.test(player); } } -} +} \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 873926cb..632e5e4c 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -165,21 +165,6 @@ public static Screen create(Screen parent) { .setTooltip(LocUtil.CONFIG_TOOLTIP("renderStuckObjects")) .setSaveConsumer(b -> config.binding.renderStuckObjects = b) .build()); - binding.addEntry(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSneaking"), config.binding.disableWhenSneaking) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenSneaking = b) - .build()); - binding.addEntry(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSwimming"), config.binding.disableWhenSwimming) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenSwimming = b) - .build()); - binding.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("swimOutTick"), config.binding.swimOutTick) - .setDefaultValue(13) - .setMin(0) - .setMax(40) - .setTooltip(LocUtil.CONFIG_TOOLTIP("swimOutTick")) - .setSaveConsumer(i -> config.binding.swimOutTick = i) - .build()); binding.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("bindResultRetentionFrames"), config.binding.bindResultRetentionFrames) .setDefaultValue(2) .setMin(0) @@ -206,17 +191,37 @@ public static Screen create(Screen parent) { .setTooltip(LocUtil.CONFIG_TOOLTIP("rotationSmoothFactor")) .setSaveConsumer(d -> config.binding.rotationSmoothFactor = d) .build()); - binding.addEntry(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) - .setDefaultValue(List.of()) - .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) - .setSaveConsumer(l -> config.binding.disableMainFeatureItems = l) - .build()); - binding.addEntry(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableRenderItems"), config.binding.disableRenderItems) - .setDefaultValue(ModConfig.Binding.defaultDisableRenderItems) - .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) - .setSaveConsumer(l -> config.binding.disableRenderItems = l) - .build()); - + SubCategoryBuilder disableConfig = entryBuilder.startSubCategory(LocUtil.CONFIG_OPTION("disableConfig")); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenCrawling"), config.binding.disableWhenCrawling) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenCrawling = b) + .build()); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSneaking"), config.binding.disableWhenSneaking) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenSneaking = b) + .build()); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSwimming"), config.binding.disableWhenSwimming) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenSwimming = b) + .build()); + disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("swimOutTick"), config.binding.swimOutTick) + .setDefaultValue(13) + .setMin(0) + .setMax(40) + .setTooltip(LocUtil.CONFIG_TOOLTIP("swimOutTick")) + .setSaveConsumer(i -> config.binding.swimOutTick = i) + .build()); + disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) + .setDefaultValue(List.of()) + .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) + .setSaveConsumer(l -> config.binding.disableMainFeatureItems = l) + .build()); + disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableRenderItems"), config.binding.disableRenderItems) + .setDefaultValue(ModConfig.Binding.defaultDisableRenderItems) + .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) + .setSaveConsumer(l -> config.binding.disableRenderItems = l) + .build()); + binding.addEntry(disableConfig.build()); return builder.build(); } -} +} \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 8a4e186e..da03938e 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -176,6 +176,10 @@ public boolean hideBindingFailureMessage() { return binding.hideFailureMessage; } + public boolean bindingDisableWhenCrawling() { + return binding.disableWhenCrawling; + } + public boolean bindingDisableWhenSneaking() { return binding.disableWhenSneaking; } @@ -291,6 +295,7 @@ public static class Binding { public boolean adjustOffset = true; public boolean hideFailureMessage = false; public boolean renderStuckObjects = true; + public boolean disableWhenCrawling = false; public boolean disableWhenSneaking = false; public boolean disableWhenSwimming = false; public int swimOutTick = 13; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index b5a21cb6..0d49c730 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -388,7 +388,10 @@ private void initRightWidgets() { for (int i = page * widgetsPerPage; i < Math.min((page + 1) * widgetsPerPage, size); i++) { BindTarget target = i < fixedTargetCount ? fixedTargetList.get(i) : targetList.get(i - fixedTargetCount); String name = target.name(); - rows.addChild(createButton(LocUtil.literal(name), widgetWidth * 2 - 18, button -> loadBindTarget(target)), 3).setTooltip(Tooltip.create(LocUtil.literal(name))); + Button configButton = createButton(LocUtil.literal(name), widgetWidth * 2 - 18, button -> loadBindTarget(target)); + if (name.equals(RealCameraCore.currentTarget().name())) configButton.setTooltip(Tooltip.create(LocUtil.literal(name + "\n").append(LocUtil.MODEL_VIEW_WIDGET("currentConfig")))); + else configButton.setTooltip(Tooltip.create(LocUtil.literal(name))); + rows.addChild(configButton, 3); if (i < fixedTargetCount) continue; rows.addChild(new TexturedButton(48, 0, button -> { targetList.remove(target); @@ -931,4 +934,4 @@ public Category next() { return values()[(ordinal() + 1) % values().length]; } } -} +} \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 0e3c127d..7fdb6d57 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -46,13 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Hide Binding Failure Message", "config.option.xtracr_realcamera.renderStuckObjects": "Render Stuck Objects", "config.option.xtracr_realcamera.rerenderModel": "Rerender Model", - "config.option.xtracr_realcamera.disableWhenSneaking": "Disable main feature when sneaking", - "config.option.xtracr_realcamera.disableWhenSwimming": "Disable main feature when swimming", - "config.option.xtracr_realcamera.swimOutTick": "Exiting swimming state delay (in ticks)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bind Result Retention Frames", "config.option.xtracr_realcamera.displacementSmoothFactor": "Displacement Smooth Factor", "config.option.xtracr_realcamera.rotationSmoothFactor": "Rotation Smooth Factor", "config.option.xtracr_realcamera.activeConfigIndex": "Active Configuration Index", + "config.option.xtracr_realcamera.disableConfig": "Disable Config", + "config.option.xtracr_realcamera.disableWhenCrawling": "Disable main feature when crawling", + "config.option.xtracr_realcamera.disableWhenSneaking": "Disable main feature when sneaking", + "config.option.xtracr_realcamera.disableWhenSwimming": "Disable main feature when swimming", + "config.option.xtracr_realcamera.swimOutTick": "Exiting swimming state delay (in ticks)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Disable main feature when holding", "config.option.xtracr_realcamera.disableRenderItems": "Disable rendering when holding", "config.tooltip.xtracr_realcamera.isClassic": "Classic mode only makes simple changes to the position and rotation of camera", @@ -65,11 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "When pressing the adjustment key, adjust the offset or rotation of camera", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Arrows, bee stings and other objects that can be stuck in the player's body", "config.tooltip.xtracr_realcamera.rerenderModel": "Render the model again at the original rendering time to avoid some visual problems caused by rendering early", - "config.tooltip.xtracr_realcamera.swimOutTick": "The time before enabling main feature after exiting swimming state (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "For several frames after the binding failure, continue to use the previous successful binding result", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Smooth factor of camera displacement, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Smooth factor of camera rotation, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.activeConfigIndex": "Currently bound configuration index, 0 means allowing binding to any valid configuration", + "config.tooltip.xtracr_realcamera.swimOutTick": "The time before enabling main feature after exiting swimming state (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Three matching methods are supported:\n1. Wildcard `*` matching (e.g., `minecraft:*sword`)\n2. Tag matching (starts with `#`, e.g., `#minecraft:swords`)\n3. Direct item ID (e.g., `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Binding failed, please go to the %s screen and configure manually (Key: %s)", @@ -102,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Configs", "screen.widget.xtracr_realcamera.modelView_copy": "Copy", "screen.widget.xtracr_realcamera.modelView_paste": "Paste", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Current Config", "screen.tooltip.xtracr_realcamera.modelView_import": "Import the config from the clipboard", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s succeeded!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import failed: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 282edaa1..7e5c9f9f 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -46,13 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "隐藏绑定失败消息", "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物体", "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", - "config.option.xtracr_realcamera.disableWhenSneaking": "潜行时禁用主要功能", - "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", - "config.option.xtracr_realcamera.swimOutTick": "游泳状态退出延迟(单位:tick)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "绑定结果保留帧数", "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", "config.option.xtracr_realcamera.activeConfigIndex": "当前配置索引", + "config.option.xtracr_realcamera.disableConfig": "禁用配置", + "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSneaking": "潜行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.swimOutTick": "游泳状态退出延迟(单位:tick)", "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...时禁用主要功能", "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用渲染", "config.tooltip.xtracr_realcamera.isClassic": "经典模式只对摄像头的位置和旋转做简单的修改", @@ -102,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "配置", "screen.widget.xtracr_realcamera.modelView_copy": "复制", "screen.widget.xtracr_realcamera.modelView_paste": "粘贴", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "当前配置", "screen.tooltip.xtracr_realcamera.modelView_import": "从剪贴板导入配置", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "导入失败:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "导入%s成功!", From 250109e90e0cae212351e983daebe8a6f8225cb4 Mon Sep 17 00:00:00 2001 From: H31M5 <2211923909@qq.com> Date: Mon, 9 Mar 2026 18:23:31 +0800 Subject: [PATCH 07/33] Add delay to main feature disable logic during crawling (#199) --- .../realcamera/compat/DisableHelper.java | 14 ++++++------- .../realcamera/config/ConfigScreen.java | 20 +++++++++---------- .../xtracr/realcamera/config/ModConfig.java | 16 +++++++-------- .../assets/realcamera/lang/en_us.json | 6 +++--- .../assets/realcamera/lang/zh_cn.json | 8 ++++---- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index e0953e03..dd189ced 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -25,9 +25,9 @@ public class DisableHelper { static { MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSneaking() && player.isCrouching()); MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSneaking() && player.isCrouching()); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSwimming() && swimmingRecently(player, ConfigFile.config().getBindingSwimOutTick())); - MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSwimming() && swimmingRecently(player, ConfigFile.config().getClassicSwimOutTick())); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenCrawling() && player.isVisuallyCrawling()); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSwimming() && checkCondition(player, player.isSwimming(), ConfigFile.config().getBindingOutTick())); + MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSwimming() && checkCondition(player, player.isSwimming(), ConfigFile.config().getClassicOutTick())); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenCrawling() && checkCondition(player, player.isVisuallyCrawling(), ConfigFile.config().getBindingOutTick())); MAIN_FEATURE.registerOrInBinding(player -> { Item mainHand = player.getMainHandItem().getItem(); Item offHand = player.getOffhandItem().getItem(); @@ -46,14 +46,14 @@ public class DisableHelper { }); } - private static boolean swimmingRecently(Player player, int swimOutTick) { - if (player.isSwimming()) { + private static boolean checkCondition(Player player, boolean condition, int outTick) { + if (condition) { exitTick = player.tickCount; return true; } - if (exitTick > 0 && !player.isSwimming()) { + if (exitTick > 0) { int elapsedTicks = player.tickCount - exitTick; - if (elapsedTicks <= swimOutTick) { + if (elapsedTicks <= outTick) { return true; } exitTick = 0; diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 632e5e4c..5c5a5859 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -60,12 +60,12 @@ public static Screen create(Screen parent) { .setDefaultValue(false) .setSaveConsumer(b -> config.classic.disableWhenSwimming = b) .build()); - classic.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("swimOutTick"), config.classic.swimOutTick) + classic.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("outTick"), config.classic.outTick) .setDefaultValue(13) .setMin(0) .setMax(40) - .setTooltip(LocUtil.CONFIG_TOOLTIP("swimOutTick")) - .setSaveConsumer(i -> config.classic.swimOutTick = i) + .setTooltip(LocUtil.CONFIG_TOOLTIP("outTick")) + .setSaveConsumer(i -> config.classic.outTick = i) .build()); classic.addEntry(entryBuilder.startDoubleField(LocUtil.CONFIG_OPTION("scale"), config.classic.scale) .setDefaultValue(8.0) @@ -192,24 +192,24 @@ public static Screen create(Screen parent) { .setSaveConsumer(d -> config.binding.rotationSmoothFactor = d) .build()); SubCategoryBuilder disableConfig = entryBuilder.startSubCategory(LocUtil.CONFIG_OPTION("disableConfig")); - disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenCrawling"), config.binding.disableWhenCrawling) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenCrawling = b) - .build()); disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSneaking"), config.binding.disableWhenSneaking) .setDefaultValue(false) .setSaveConsumer(b -> config.binding.disableWhenSneaking = b) .build()); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenCrawling"), config.binding.disableWhenCrawling) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenCrawling = b) + .build()); disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSwimming"), config.binding.disableWhenSwimming) .setDefaultValue(false) .setSaveConsumer(b -> config.binding.disableWhenSwimming = b) .build()); - disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("swimOutTick"), config.binding.swimOutTick) + disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("outTick"), config.binding.outTick) .setDefaultValue(13) .setMin(0) .setMax(40) - .setTooltip(LocUtil.CONFIG_TOOLTIP("swimOutTick")) - .setSaveConsumer(i -> config.binding.swimOutTick = i) + .setTooltip(LocUtil.CONFIG_TOOLTIP("outTick")) + .setSaveConsumer(i -> config.binding.outTick = i) .build()); disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) .setDefaultValue(List.of()) diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index da03938e..c6b2f490 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -119,8 +119,8 @@ public boolean classicDisableWhenSwimming() { return classic.disableWhenSwimming; } - public int getClassicSwimOutTick() { - return classic.swimOutTick; + public int getClassicOutTick() { + return classic.outTick; } public double getClassicX() { @@ -188,8 +188,8 @@ public boolean bindingDisableWhenSwimming() { return binding.disableWhenSwimming; } - public int getBindingSwimOutTick() { - return binding.swimOutTick; + public int getBindingOutTick() { + return binding.outTick; } public int getBindResultRetentionFrames() { @@ -250,7 +250,7 @@ public static class Classic { public AdjustMode adjustMode = AdjustMode.CAMERA; public boolean disableWhenSneaking = false; public boolean disableWhenSwimming = false; - public int swimOutTick = 13; + public int outTick = 13; public double scale = 8.0; public double cameraX = -0.5; public double cameraY = 0.04; @@ -264,7 +264,7 @@ public static class Classic { private void clamp() { if (adjustMode == null) adjustMode = AdjustMode.CAMERA; - swimOutTick = Mth.clamp(swimOutTick, 0, 40); + outTick = Mth.clamp(outTick, 0, 40); scale = Mth.clamp(scale, 0.0, 64.0); cameraX = Mth.clamp(cameraX, MIN_OFFSET_D, MAX_OFFSET_D); cameraY = Mth.clamp(cameraY, MIN_OFFSET_D, MAX_OFFSET_D); @@ -298,7 +298,7 @@ public static class Binding { public boolean disableWhenCrawling = false; public boolean disableWhenSneaking = false; public boolean disableWhenSwimming = false; - public int swimOutTick = 13; + public int outTick = 13; public int bindResultRetentionFrames = 2; public int activeConfigIndex = 0; public double displacementSmoothFactor = 0.4; @@ -314,7 +314,7 @@ private void clamp() { } catch (Exception e) { screenModifierKey = InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_LALT).getName(); } - swimOutTick = Mth.clamp(swimOutTick, 0, 40); + outTick = Mth.clamp(outTick, 0, 40); bindResultRetentionFrames = Math.max(bindResultRetentionFrames, 0); activeConfigIndex = Math.max(activeConfigIndex, 0); displacementSmoothFactor = Mth.clamp(displacementSmoothFactor, 0.0, 1.0); diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 7fdb6d57..1b9be4a3 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -51,10 +51,10 @@ "config.option.xtracr_realcamera.rotationSmoothFactor": "Rotation Smooth Factor", "config.option.xtracr_realcamera.activeConfigIndex": "Active Configuration Index", "config.option.xtracr_realcamera.disableConfig": "Disable Config", - "config.option.xtracr_realcamera.disableWhenCrawling": "Disable main feature when crawling", "config.option.xtracr_realcamera.disableWhenSneaking": "Disable main feature when sneaking", + "config.option.xtracr_realcamera.disableWhenCrawling": "Disable main feature when crawling", "config.option.xtracr_realcamera.disableWhenSwimming": "Disable main feature when swimming", - "config.option.xtracr_realcamera.swimOutTick": "Exiting swimming state delay (in ticks)", + "config.option.xtracr_realcamera.outTick": "Restriction exit delay (in ticks)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Disable main feature when holding", "config.option.xtracr_realcamera.disableRenderItems": "Disable rendering when holding", "config.tooltip.xtracr_realcamera.isClassic": "Classic mode only makes simple changes to the position and rotation of camera", @@ -71,7 +71,7 @@ "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Smooth factor of camera displacement, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Smooth factor of camera rotation, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.activeConfigIndex": "Currently bound configuration index, 0 means allowing binding to any valid configuration", - "config.tooltip.xtracr_realcamera.swimOutTick": "The time before enabling main feature after exiting swimming state (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.outTick": "The time before re-enabling main feature after exiting restricted states (e.g., swimming, crawling) (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Three matching methods are supported:\n1. Wildcard `*` matching (e.g., `minecraft:*sword`)\n2. Tag matching (starts with `#`, e.g., `#minecraft:swords`)\n3. Direct item ID (e.g., `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Binding failed, please go to the %s screen and configure manually (Key: %s)", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 7e5c9f9f..d81515cb 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -51,10 +51,10 @@ "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", "config.option.xtracr_realcamera.activeConfigIndex": "当前配置索引", "config.option.xtracr_realcamera.disableConfig": "禁用配置", - "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", "config.option.xtracr_realcamera.disableWhenSneaking": "潜行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", - "config.option.xtracr_realcamera.swimOutTick": "游泳状态退出延迟(单位:tick)", + "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...时禁用主要功能", "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用渲染", "config.tooltip.xtracr_realcamera.isClassic": "经典模式只对摄像头的位置和旋转做简单的修改", @@ -67,11 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "当前按下调整键时是调整摄像头的偏移还是旋转", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它会卡在玩家身体里的物体", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染时机重新渲染模型,以避免一些因提前渲染导致的视觉问题", - "config.tooltip.xtracr_realcamera.swimOutTick": "玩家停止游泳状态后重启主要功能的时间(1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在绑定失败后的数帧内,沿用上个成功的绑定结果", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相机位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相机旋转平滑系数,值越大越平滑", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "当前绑定的配置索引,0表示允许绑定任何有效配置", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "当前绑定的配置索引,0表示允许绑定任何有效配置", + "config.tooltip.xtracr_realcamera.outTick": "玩家停止某些状态(如游泳、爬行)后重启主要功能的时间(1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三种匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 标签匹配以`#`开头(如`#minecraft:swords`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: 绑定失败,请前往%s界面手动设置(键位:%s)", From 192611abd1cff209afa9633a165b820e4bf79d8d Mon Sep 17 00:00:00 2001 From: dqsk_zze <1935752350@qq.com> Date: Sun, 15 Mar 2026 00:05:09 +0800 Subject: [PATCH 08/33] languages updated (#201) Signed-off-by: dqsk_zze <1935752350@qq.com> --- .../assets/realcamera/lang/be_by.json | 20 ++++++++---- .../assets/realcamera/lang/es_es.json | 16 +++++++--- .../assets/realcamera/lang/fr_fr.json | 16 +++++++--- .../assets/realcamera/lang/ja_jp.json | 16 +++++++--- .../assets/realcamera/lang/ko_kr.json | 16 +++++++--- .../resources/assets/realcamera/lang/lzh.json | 32 ++++++++++++------- .../assets/realcamera/lang/pl_pl.json | 16 +++++++--- .../assets/realcamera/lang/pt_br.json | 16 +++++++--- .../assets/realcamera/lang/pt_pt.json | 16 +++++++--- .../assets/realcamera/lang/ru_ru.json | 16 +++++++--- .../assets/realcamera/lang/tr_tr.json | 16 +++++++--- .../assets/realcamera/lang/uk_ua.json | 16 +++++++--- .../assets/realcamera/lang/zh_hk.json | 22 +++++++++---- .../assets/realcamera/lang/zh_tw.json | 22 +++++++++---- 14 files changed, 184 insertions(+), 72 deletions(-) diff --git a/common/src/main/resources/assets/realcamera/lang/be_by.json b/common/src/main/resources/assets/realcamera/lang/be_by.json index 66e64585..283e40c5 100644 --- a/common/src/main/resources/assets/realcamera/lang/be_by.json +++ b/common/src/main/resources/assets/realcamera/lang/be_by.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Адкрыць экран прагляду мадэлі", "key.xtracr_realcamera.togglePerspective": "Уключыць/Выключыць", + "key.xtracr_realcamera.activeConfigIndexPREV": "Пераключыцца на папярэднюю канфігурацыю", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Пераключыцца на наступную канфігурацыю", + "key.xtracr_realcamera.activeConfigIndexRESET": "Скінуць індэкс канфігурацыі", "key.xtracr_realcamera.toggleAdjustMode": "Пераключыць рэжым налады", "key.xtracr_realcamera.toggleCameraMode": "Пераключыць рэжым камеры", "key.xtracr_realcamera.adjustUP": "Наладзіць УВЕРХ", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Хаваць паведамленні пра няўдалую прывязку", "config.option.xtracr_realcamera.renderStuckObjects": "Адлюстроўваць застряўшыя аб'екты", "config.option.xtracr_realcamera.rerenderModel": "Перамаляваць мадэль", - "config.option.xtracr_realcamera.disableWhenSneaking": "Адключыць асноўную функцыю пры крадзяжы", - "config.option.xtracr_realcamera.disableWhenSwimming": "Адключыць асноўную функцыю пры плаванні", - "config.option.xtracr_realcamera.swimOutTick": "Затрымка выхаду з стану плавання (у тіках)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадры захавання выніку прывязкі", "config.option.xtracr_realcamera.displacementSmoothFactor": "Каэфіцыент згладжвання зруху", "config.option.xtracr_realcamera.rotationSmoothFactor": "Каэфіцыент згладжвання павароту", + "config.option.xtracr_realcamera.activeConfigIndex": "Актыўны індэкс канфігурацыі", + "config.option.xtracr_realcamera.disableConfig": "Адключыць Канфігурацыю", + "config.option.xtracr_realcamera.disableWhenSneaking": "Адключыць асноўную функцыю пры крадзяжы", + "config.option.xtracr_realcamera.disableWhenCrawling": "Адключыць асноўную функцыю пры поўзанні", + "config.option.xtracr_realcamera.disableWhenSwimming": "Адключыць асноўную функцыю пры плаванні", + "config.option.xtracr_realcamera.outTick": "Затрымка выхаду з стану плавання (у тіках)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Адключыць асноўную функцыю пры трыманні...", "config.option.xtracr_realcamera.disableRenderItems": "Адключыць адлюстраванне пры трыманні...", "config.tooltip.xtracr_realcamera.isClassic": "Класічны рэжым уносіць толькі простыя змены ў становішча і паварот камеры", @@ -57,14 +63,15 @@ "config.tooltip.xtracr_realcamera.adjustStep": "Даўжыня або 1/100 вугла налады за крок", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Вызначае, што наладжваць пры націсканні клавішы налады", "config.tooltip.xtracr_realcamera.scale": "Кантраляваць памер зрухаў", - "config.tooltip.xtracr_realcamera.legacyBindingMode": "Выкарыстоўвае рэжым прывязкі састарэлай версіі (v0.5), падтрымліваюцца толькі стандартныя мадэлі і дзеянні на іх аснове\nПасля ўключэння ўласцівасці можна наладзіць у раздзеле 'LEGACY_MODE' экрана %s", + "config.tooltip.xtracr_realcamera.legacyBindingMode": "Выкарыстоўвае рэжым прывязкі састарэлай версіі (v0.5), падтрымліваюцца толькі стандартныя мадэлі і дзеянні на іх аснове\nПасля ўключэння ўласцівасціў выладывае дакладней прывязацца да мэтавай пазіцыі", "config.tooltip.xtracr_realcamera.adjustOffset": "Пры націсканні клавішы налады, рэгуляваць зрух або паварот камеры", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Стрэлы, джалы пчол і іншыя аб'екты, якія могуць застряць у целе гульца", "config.tooltip.xtracr_realcamera.rerenderModel": "Перамалёўваць мадэль у зыходны час рэндэрынгу, каб пазбегнуць візуальных праблем", - "config.tooltip.xtracr_realcamera.swimOutTick": "Затрымка ўключэння асноўнай функцыі пасля выхаду з стану плавання (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "На працягу некалькіх кадраў пасля няўдалай прывязкі працягваць выкарыстоўваць папярэдні паспяховы вынік прывязкі", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Каэфіцыент згладжвання зруху камеры, чым вышэй значэнне, тым больш плаўным будзе рух", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Каэфіцыент згладжвання павароту камеры, чым вышэй значэнне, тым больш плаўным будзе рух", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Текущий индекс привязанной конфигурации, 0 означает разрешение привязки к любой допустимой конфигурации", + "config.tooltip.xtracr_realcamera.outTick": "Затрымка ўключэння асноўнай функцыі пасля выхаду з стану плавання (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Падтрымліваюцца тры метады супадзення:\n1. Сімвал падстаноўкі `*` (напрыклад, `minecraft:*sword`)\n2. Супадзенне па тэгах (пачынаецца з `#`, напрыклад, `#minecraft:swords`)\n3. Прамы ID прадмета (напрыклад, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Памылка прывязкі, калі ласка, перайдзіце на экран %s і наладзьце ўручную (ключ: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Канфігурацыі", "screen.widget.xtracr_realcamera.modelView_copy": "Капіяваць", "screen.widget.xtracr_realcamera.modelView_paste": "Уставіць", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Бягучая Канфігурацыя", "screen.tooltip.xtracr_realcamera.modelView_import": "Імпартаваць канфіг з буфера абмену", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпарт %s паспяховы!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Імпарт не ўдаўся: \n%s", @@ -111,7 +119,7 @@ "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Выдаліць абраную прастакутную вобласць\n(Ці выкарыстайце клавішу Delete)", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Калі адключана, адноснае становішча камеры да мадэлі не мяняецца, але адпаведныя атрыбуты камеры не будуць зменены гэтым модам", "screen.tooltip.xtracr_realcamera.modelView_scale": "Маштаб, які кіруе памерам зрухаў", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскасці, адлегласць ад усіх вяршынь да экрана ў якіх меншая за гэта значэнне, не будуць адлюстроўвацца", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскасці, адлеглась ад усіх вяршынь да экрана ў якіх меншая за гэта значэнне, не будуць адлюстроўвацца", "screen.tooltip.xtracr_realcamera.modelView_priority": "Прыярытэт пры прывязцы, чым больш значэнне, тым вышэй прыярытэт і размяшчэнне справей у спісе", "screen.tooltip.xtracr_realcamera.modelView_targetName": "Назва канфігурацыі", "screen.tooltip.xtracr_realcamera.modelView_disable": "Налады адключэння\nГлабальныя налады адключэння знаходзяцца на экране канфігурацыі", diff --git a/common/src/main/resources/assets/realcamera/lang/es_es.json b/common/src/main/resources/assets/realcamera/lang/es_es.json index 17439863..580e31fa 100644 --- a/common/src/main/resources/assets/realcamera/lang/es_es.json +++ b/common/src/main/resources/assets/realcamera/lang/es_es.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Abrir Pantalla de Vista de Modelo", "key.xtracr_realcamera.togglePerspective": "Activar/Desactivar", + "key.xtracr_realcamera.activeConfigIndexPREV": "Cambiar a la configuración anterior", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Cambiar a la siguiente configuración", + "key.xtracr_realcamera.activeConfigIndexRESET": "Restablecer índice de configuración", "key.xtracr_realcamera.toggleAdjustMode": "Cambiar Modo de Ajuste", "key.xtracr_realcamera.toggleCameraMode": "Cambiar Modo de Cámara", "key.xtracr_realcamera.adjustUP": "Ajustar ARRIBA", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensajes de fallo de vinculación", "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Atascados", "config.option.xtracr_realcamera.rerenderModel": "Re-renderizar Modelo", - "config.option.xtracr_realcamera.disableWhenSneaking": "Desactivar función principal al agacharse", - "config.option.xtracr_realcamera.disableWhenSwimming": "Desactivar función principal al nadar", - "config.option.xtracr_realcamera.swimOutTick": "Retraso al salir del estado de natación (en ticks)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Marcos de retención de resultado de vinculación", "config.option.xtracr_realcamera.displacementSmoothFactor": "Factor de suavizado de desplazamiento", "config.option.xtracr_realcamera.rotationSmoothFactor": "Factor de suavizado de rotación", + "config.option.xtracr_realcamera.activeConfigIndex": "Índice de configuración activa", + "config.option.xtracr_realcamera.disableConfig": "Configuración Desactivada", + "config.option.xtracr_realcamera.disableWhenSneaking": "Desactivar función principal al agacharse", + "config.option.xtracr_realcamera.disableWhenCrawling": "Desactivar función principal al gatear", + "config.option.xtracr_realcamera.disableWhenSwimming": "Desactivar función principal al nadar", + "config.option.xtracr_realcamera.outTick": "Retraso al salir del estado de natación (en ticks)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Desactivar función principal al sostener...", "config.option.xtracr_realcamera.disableRenderItems": "Desactivar renderizado al sostener...", "config.tooltip.xtracr_realcamera.isClassic": "El modo clásico solo hace cambios simples a la posición y rotación de la cámara", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "Al presionar la tecla de ajuste, ajusta el desplazamiento o rotación de la cámara", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flechas, picaduras de abeja y otros objetos que pueden quedar atascados en el cuerpo del jugador", "config.tooltip.xtracr_realcamera.rerenderModel": "Renderizar el modelo nuevamente en el momento original de renderizado para evitar problemas visuales causados por renderizado temprano", - "config.tooltip.xtracr_realcamera.swimOutTick": "Tiempo antes de activar la función principal después de salir del estado de natación (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Durante varios fotogramas después del fallo de vinculación, continuar utilizando el resultado de vinculación exitoso anterior", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Factor de suavizado del desplazamiento de la cámara, cuanto mayor sea el valor, más suave será el movimiento", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Factor de suavizado de la rotación de la cámara, cuanto mayor sea el valor, más suave será el movimiento", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuración actualmente vinculada, 0 significa permitir la vinculación a cualquier configuración válida", + "config.tooltip.xtracr_realcamera.outTick": "Tiempo antes de activar la función principal después de salir del estado de natación (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Se admiten tres métodos de coincidencia:\n1. Coincidencia con comodín `*` (por ejemplo, `minecraft:*sword`)\n2. Coincidencia de etiquetas (comienza con `#`, por ejemplo, `#minecraft:swords`)\n3. ID de objeto directo (por ejemplo, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Vinculación fallida, por favor vaya a la pantalla %s y configure manualmente (tecla: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Configuraciones", "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", "screen.widget.xtracr_realcamera.modelView_paste": "Pegar", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuración Actual", "screen.tooltip.xtracr_realcamera.modelView_import": "Importar la configuración desde el portapapeles", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "¡Importación %s exitosa!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Importación fallida: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/fr_fr.json b/common/src/main/resources/assets/realcamera/lang/fr_fr.json index 51c25c84..581ef6b6 100644 --- a/common/src/main/resources/assets/realcamera/lang/fr_fr.json +++ b/common/src/main/resources/assets/realcamera/lang/fr_fr.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Ouvrir l'écran de visualisation du modèle", "key.xtracr_realcamera.togglePerspective": "Activer/Désactiver", + "key.xtracr_realcamera.activeConfigIndexPREV": "Passer à la configuration précédente", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Passer à la configuration suivante", + "key.xtracr_realcamera.activeConfigIndexRESET": "Réinitialiser l'index de configuration", "key.xtracr_realcamera.toggleAdjustMode": "Basculer le mode d'ajustement", "key.xtracr_realcamera.toggleCameraMode": "Basculer le mode caméra", "key.xtracr_realcamera.adjustUP": "Ajuster vers le HAUT", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Masquer les messages d'échec de liaison", "config.option.xtracr_realcamera.renderStuckObjects": "Afficher les Objets Coincés", "config.option.xtracr_realcamera.rerenderModel": "Réafficher le Modèle", - "config.option.xtracr_realcamera.disableWhenSneaking": "Désactiver la fonctionnalité principale en se faufilant", - "config.option.xtracr_realcamera.disableWhenSwimming": "Désactiver la fonctionnalité principale en nageant", - "config.option.xtracr_realcamera.swimOutTick": "Délai de sortie de l'état de nage (en ticks)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Images de rétention des résultats de liaison", "config.option.xtracr_realcamera.displacementSmoothFactor": "Facteur de lissage du déplacement", "config.option.xtracr_realcamera.rotationSmoothFactor": "Facteur de lissage de la rotation", + "config.option.xtracr_realcamera.activeConfigIndex": "Index de configuration actif", + "config.option.xtracr_realcamera.disableConfig": "Config Désactivée", + "config.option.xtracr_realcamera.disableWhenSneaking": "Désactiver la fonctionnalité principale en se faufilant", + "config.option.xtracr_realcamera.disableWhenCrawling": "Désactiver la fonctionnalité principale en rampant", + "config.option.xtracr_realcamera.disableWhenSwimming": "Désactiver la fonctionnalité principale en nageant", + "config.option.xtracr_realcamera.outTick": "Délai de sortie de l'état de nage (en ticks)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Désactiver la fonctionnalité principale en tenant...", "config.option.xtracr_realcamera.disableRenderItems": "Désactiver le rendu en tenant...", "config.tooltip.xtracr_realcamera.isClassic": "Le mode classique ne fait que des changements simples à la position et à la rotation de la caméra", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "Lors de l'appui sur la touche d'ajustement, ajuster le décalage ou la rotation de la caméra", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flèches, piqûres d'abeille et autres objets pouvant être coincés dans le corps du joueur", "config.tooltip.xtracr_realcamera.rerenderModel": "Afficher à nouveau le modèle au moment du rendu original pour éviter certains problèmes visuels causés par un rendu précoce", - "config.tooltip.xtracr_realcamera.swimOutTick": "Le délai d'activation de la fonction principale après la sortie de l'état de nage (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Pendant plusieurs images après l'échec de la liaison, continuer à utiliser le résultat de liaison réussi précédent", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Facteur de lissage du déplacement de la caméra, plus la valeur est élevée, plus le mouvement est fluide", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Facteur de lissage de la rotation de la caméra, plus la valeur est élevée, plus le mouvement est fluide", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Index de configuration actuellement lié, 0 signifie autoriser la liaison à toute configuration valide", + "config.tooltip.xtracr_realcamera.outTick": "Le délai d'activation de la fonction principale après la sortie de l'état de nage (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Trois méthodes de correspondance sont prises en charge :\n1. Correspondance avec joker `*` (par exemple, `minecraft:*sword`)\n2. Correspondance d'étiquette (commence par `#`, par exemple, `#minecraft:swords`)\n3. ID d'objet direct (par exemple, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Échec de la liaison, veuillez aller à l'écran %s et configurer manuellement (touche: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Configurations", "screen.widget.xtracr_realcamera.modelView_copy": "Copier", "screen.widget.xtracr_realcamera.modelView_paste": "Coller", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Config Actuelle", "screen.tooltip.xtracr_realcamera.modelView_import": "Importer la configuration depuis le presse-papiers", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importation %s réussie !", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Échec de l'importation : \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/ja_jp.json b/common/src/main/resources/assets/realcamera/lang/ja_jp.json index 0e430c04..83d42b51 100644 --- a/common/src/main/resources/assets/realcamera/lang/ja_jp.json +++ b/common/src/main/resources/assets/realcamera/lang/ja_jp.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "モデルビュー画面を開く", "key.xtracr_realcamera.togglePerspective": "オン/オフ", + "key.xtracr_realcamera.activeConfigIndexPREV": "前の設定に切り替え", + "key.xtracr_realcamera.activeConfigIndexNEXT": "次の設定に切り替え", + "key.xtracr_realcamera.activeConfigIndexRESET": "設定インデックスをリセット", "key.xtracr_realcamera.toggleAdjustMode": "調整モードを切り替え", "key.xtracr_realcamera.toggleCameraMode": "カメラモードを切り替え", "key.xtracr_realcamera.adjustUP": "上に調整", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "バインディング失敗メッセージを非表示", "config.option.xtracr_realcamera.renderStuckObjects": "体に刺さったオブジェクトをレンダリング", "config.option.xtracr_realcamera.rerenderModel": "モデルを再レンダリング", - "config.option.xtracr_realcamera.disableWhenSneaking": "スニーク時にメイン機能を無効化", - "config.option.xtracr_realcamera.disableWhenSwimming": "泳いでいる時にメイン機能を無効化", - "config.option.xtracr_realcamera.swimOutTick": "泳ぎ状態退出遅延(単位:TICK)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "バインディング結果保持フレーム数", "config.option.xtracr_realcamera.displacementSmoothFactor": "変位平滑化係数", "config.option.xtracr_realcamera.rotationSmoothFactor": "回転平滑化係数", + "config.option.xtracr_realcamera.activeConfigIndex": "現在の設定インデックス", + "config.option.xtracr_realcamera.disableConfig": "無効設定", + "config.option.xtracr_realcamera.disableWhenSneaking": "スニーク時にメイン機能を無効化", + "config.option.xtracr_realcamera.disableWhenCrawling": "這行時にメイン機能を無効化", + "config.option.xtracr_realcamera.disableWhenSwimming": "泳いでいる時にメイン機能を無効化", + "config.option.xtracr_realcamera.outTick": "無効状態退出遅延(単位:TICK)", "config.option.xtracr_realcamera.disableMainFeatureItems": "...を持っている時にメイン機能を無効化", "config.option.xtracr_realcamera.disableRenderItems": "...を持っている時にレンダリングを無効化", "config.tooltip.xtracr_realcamera.isClassic": "クラシックモードではカメラの位置と回転に簡単な変更のみを行います", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "現在の調整キーでカメラのオフセットまたは回転を調整", "config.tooltip.xtracr_realcamera.renderStuckObjects": "矢、蜂の針などプレイヤーの体に刺さるオブジェクト", "config.tooltip.xtracr_realcamera.rerenderModel": "元のレンダリングタイミングでモデルを再レンダリングし、早期レンダリングによる視覚的問題を回避", - "config.tooltip.xtracr_realcamera.swimOutTick": "プレイヤーが泳ぎ状態を停止した後、主機能を再開するまでの時間(1 tick = 0.05秒)", + "config.tooltip.xtracr_realcamera.outTick": "プレイヤーが特定の状態を停止した後、主機能を再開するまでの時間(1 tick = 0.05秒)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "バインディング失敗後の数フレーム間、前回成功したバインディング結果を継続使用", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "カメラ変位平滑化係数、値が大きいほどスムーズ", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "カメラ回転平滑化係数、値が大きいほどスムーズ", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "現在バインドされている設定のインデックス、0は有効な設定をバインド可能", "config.tooltip.xtracr_realcamera.disableRenderItems": "3つのマッチング方法をサポート:\n1. ワイルドカード`*`マッチング(例: `minecraft:*sword`)\n2. タグマッチング(`#`で始まる、例: `#minecraft:swords`)\n3. 直接アイテムID(例: `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: バインディングに失敗しました。%s画面で手動設定してください(キー: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "設定", "screen.widget.xtracr_realcamera.modelView_copy": "コピー", "screen.widget.xtracr_realcamera.modelView_paste": "貼り付け", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "現在の設定", "screen.tooltip.xtracr_realcamera.modelView_import": "クリップボードから設定をインポート", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%sのインポートに成功しました!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "インポートに失敗しました: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/ko_kr.json b/common/src/main/resources/assets/realcamera/lang/ko_kr.json index c629c5a3..a7b1587e 100644 --- a/common/src/main/resources/assets/realcamera/lang/ko_kr.json +++ b/common/src/main/resources/assets/realcamera/lang/ko_kr.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "모델 뷰 화면 열기", "key.xtracr_realcamera.togglePerspective": "활성화/비활성화", + "key.xtracr_realcamera.activeConfigIndexPREV": "이전 설정으로 전환", + "key.xtracr_realcamera.activeConfigIndexNEXT": "다음 설정으로 전환", + "key.xtracr_realcamera.activeConfigIndexRESET": "설정 인덱스 초기화", "key.xtracr_realcamera.toggleAdjustMode": "조정 모드 전환", "key.xtracr_realcamera.toggleCameraMode": "카메라 모드 전환", "key.xtracr_realcamera.adjustUP": "위로 조정", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "바인딩 실패 메시지 숨기기", "config.option.xtracr_realcamera.renderStuckObjects": "박힌 물체 렌더링", "config.option.xtracr_realcamera.rerenderModel": "모델 재렌더링", - "config.option.xtracr_realcamera.disableWhenSneaking": "숨어 있을 때 주요 기능 비활성화", - "config.option.xtracr_realcamera.disableWhenSwimming": "수영할 때 주요 기능 비활성화", - "config.option.xtracr_realcamera.swimOutTick": "수영 상태 종료 지연 (틱 단위)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "바인딩 결과 유지 프레임", "config.option.xtracr_realcamera.displacementSmoothFactor": "변위 평활화 계수", "config.option.xtracr_realcamera.rotationSmoothFactor": "회전 평활화 계수", + "config.option.xtracr_realcamera.activeConfigIndex": "현재 설정 인덱스", + "config.option.xtracr_realcamera.disableConfig": "비활성화 설정", + "config.option.xtracr_realcamera.disableWhenSneaking": "숨어 있을 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.disableWhenCrawling": "기어다닐 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.disableWhenSwimming": "수영할 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.outTick": "비활성화 상태 종료 지연 (틱 단위)", "config.option.xtracr_realcamera.disableMainFeatureItems": "...을(를) 들고 있을 때 주요 기능 비활성화", "config.option.xtracr_realcamera.disableRenderItems": "...을(를) 들고 있을 때 렌더링 비활성화", "config.tooltip.xtracr_realcamera.isClassic": "클래식 모드는 카메라의 위치와 회전에 간단한 변경만 적용합니다", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "조정 키 누를 때 카메라 오프셋 또는 회전 조정", "config.tooltip.xtracr_realcamera.renderStuckObjects": "화살, 벌 침 등 플레이어 몸에 박힐 수 있는 물체들", "config.tooltip.xtracr_realcamera.rerenderModel": "원본 렌더링 시간에 모델을 다시 렌더링하여 조기 렌더링으로 인한 시각적 문제 방지", - "config.tooltip.xtracr_realcamera.swimOutTick": "수영 상태 종료 후 주요 기능 재활성화까지의 시간 (1 틱 = 0.05초)", + "config.tooltip.xtracr_realcamera.outTick": "비활성화 상태 종료 후 주요 기능 재활성화까지의 시간 (1 틱 = 0.05초)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "바인딩 실패 후 몇 프레임 동안 이전 성공한 바인딩 결과 사용 유지", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "카메라 변위 평활화 계수, 값이 클수록 이동이 부드러워집니다", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "카메라 회전 평활화 계수, 값이 클수록 이동이 부드러워집니다", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "현재 바인딩된 설정의 인덱스, 0은 유효한 설정을 바인딩할 수 있음을 의미", "config.tooltip.xtracr_realcamera.disableRenderItems": "세 가지 매칭 방식 지원:\n1. 와일드카드 `*` 매칭 (예: `minecraft:*sword`)\n2. 태그 매칭 (`#`으로 시작, 예: `#minecraft:swords`)\n3. 직접 아이템 ID (예: `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: 바인딩 실패, %s 화면에서 수동으로 설정하세요 (키: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "설정", "screen.widget.xtracr_realcamera.modelView_copy": "복사", "screen.widget.xtracr_realcamera.modelView_paste": "붙여넣기", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "현재 설정", "screen.tooltip.xtracr_realcamera.modelView_import": "클립보드에서 설정 가져오기", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s 가져오기 성공!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "가져오기 실패: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/lzh.json b/common/src/main/resources/assets/realcamera/lang/lzh.json index a807ab4c..3481b108 100644 --- a/common/src/main/resources/assets/realcamera/lang/lzh.json +++ b/common/src/main/resources/assets/realcamera/lang/lzh.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "啟模型觀象之窗", "key.xtracr_realcamera.togglePerspective": "開/闔", + "key.xtracr_realcamera.activeConfigIndexPREV": "切上配", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切下配", + "key.xtracr_realcamera.activeConfigIndexRESET": "改配之引", "key.xtracr_realcamera.toggleAdjustMode": "易調校之法", "key.xtracr_realcamera.toggleCameraMode": "易鏡觀之道", "key.xtracr_realcamera.adjustUP": "上移", @@ -21,8 +24,8 @@ "config.tooltip.xtracr_realcamera.classicOffset": "鏡觀相對樞軸之移值", "config.tooltip.xtracr_realcamera.classicOffset_n": "註: 戯者之前、上、左分別為X、Y、Z軸", "config.tooltip.xtracr_realcamera.centerOffset": "樞軸相對首部之移值", - "config.tooltip.xtracr_realcamera.cameraRotation": "額外之鏡觀旋轉角度", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "註: 俯仰、偏航、翻滾乃以左、上、前為軸之旋轉", + "config.tooltip.xtracr_realcamera.cameraRotation": "額外之鏡觀轉角度", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "註: 俯仰、偏航、翻滾乃以左、上、前為軸之轉", "config.option.xtracr_realcamera.enabled": "啟其能", "config.option.xtracr_realcamera.isClassic": "古法", @@ -41,14 +44,17 @@ "config.option.xtracr_realcamera.legacyBindingMode": "古版系定之法", "config.option.xtracr_realcamera.adjustOffset": "調鏡觀移", "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱系定敗之訊", - "config.option.xtracr_realcamera.renderStuckObjects": "顯附身之物", + "config.option.xtracr_realcamera.renderStuckObjects": "示附身之物", "config.option.xtracr_realcamera.rerenderModel": "重顯其形", - "config.option.xtracr_realcamera.disableWhenSneaking": "潛伏時禁其能", - "config.option.xtracr_realcamera.disableWhenSwimming": "游水時禁其能", - "config.option.xtracr_realcamera.swimOutTick": "出游水之延(單位:tick)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "系定果存之幀數", "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑之係", "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑之係", + "config.option.xtracr_realcamera.activeConfigIndex": "現綁配之引", + "config.option.xtracr_realcamera.disableConfig": "禁配", + "config.option.xtracr_realcamera.disableWhenSneaking": "潛伏時禁其能", + "config.option.xtracr_realcamera.disableWhenCrawling": "爬攀時禁其能", + "config.option.xtracr_realcamera.disableWhenSwimming": "游水時禁其能", + "config.option.xtracr_realcamera.outTick": "出禁之延(單位:tick)", "config.option.xtracr_realcamera.disableMainFeatureItems": "持...時禁其能", "config.option.xtracr_realcamera.disableRenderItems": "持...時禁其顯", "config.tooltip.xtracr_realcamera.isClassic": "古法唯簡調鏡觀之位與旋", @@ -56,18 +62,19 @@ "config.tooltip.xtracr_realcamera.renderModel": "第一人稱顯戯者之形", "config.tooltip.xtracr_realcamera.adjustStep": "每步調校角度之百分一或長度", "config.tooltip.xtracr_realcamera.classicAdjustMode": "定當前按調校鍵時調何者", - "config.tooltip.xtracr_realcamera.scale": "控偏移量之大小", + "config.tooltip.xtracr_realcamera.scale": "控偏移大小", "config.tooltip.xtracr_realcamera.legacyBindingMode": "用古版(v0.5)系定之法,惟原模及原模所出之動可受\n啟之則可於%s窗'LEGACY_MODE'中設其性", "config.tooltip.xtracr_realcamera.adjustOffset": "當前按調校鍵時乃調鏡觀之偏移或旋轉", "config.tooltip.xtracr_realcamera.renderStuckObjects": "矢,蜂針等附身之物", "config.tooltip.xtracr_realcamera.rerenderModel": "於原顯時重顯其形,免早顯致視誤", - "config.tooltip.xtracr_realcamera.swimOutTick": "止游,即復其能所之延時(1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.outTick": "止禁,即復其能所之延時(1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "系定敗後數幀內,沿用前次成之果", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "鏡觀位移平滑之係,值愈大愈平", - "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "鏡觀旋轉平滑之係,值愈大愈平", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "鏡觀移滑係,值愈大愈平", + "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "鏡觀轉滑係,值愈大愈平", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "現配之引,零意奏許定諸配", "config.tooltip.xtracr_realcamera.disableRenderItems": "三法可配:\n1. 通配符`*`配(如`minecraft:*sword`)\n2. 標籤配以`#`始(如`#minecraft:swords`)\n3. 直物ID(如`minecraft:diamond_sword`)", - "message.xtracr_realcamera.bindingFailed": "[%s]: 系定敗,請往%s窗手設之(鍵:%s)", + "message.xtracr_realcamera.bindingFailed": "[%s]: 系定敗,往%s窗親設之(鍵:%s)", "screen.xtracr_realcamera.modelView_title": "模型觀象", "screen.widget.xtracr_realcamera.modelView_import": "入", @@ -97,7 +104,8 @@ "screen.widget.xtracr_realcamera.modelView_configs": "設", "screen.widget.xtracr_realcamera.modelView_copy": "抄", "screen.widget.xtracr_realcamera.modelView_paste": "貼", - "screen.tooltip.xtracr_realcamera.modelView_import": "自剪貼板入設", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "現綁配", + "screen.tooltip.xtracr_realcamera.modelView_import": "从剪貼板入設", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "入%s成!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "入敗:\n%s", "screen.tooltip.xtracr_realcamera.modelView_export": "出今設至剪貼板", diff --git a/common/src/main/resources/assets/realcamera/lang/pl_pl.json b/common/src/main/resources/assets/realcamera/lang/pl_pl.json index 15943bc2..29672052 100644 --- a/common/src/main/resources/assets/realcamera/lang/pl_pl.json +++ b/common/src/main/resources/assets/realcamera/lang/pl_pl.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Prawdziwa Kamera", "key.xtracr_realcamera.modelViewScreen": "Otwórz Ekran Podglądu Modelu", "key.xtracr_realcamera.togglePerspective": "Włącz/Wyłącz", + "key.xtracr_realcamera.activeConfigIndexPREV": "Przełącz na poprzednią konfigurację", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Przełącz na następną konfigurację", + "key.xtracr_realcamera.activeConfigIndexRESET": "Zresetuj indeks konfiguracji", "key.xtracr_realcamera.toggleAdjustMode": "Przełącz Tryb Dostosowania", "key.xtracr_realcamera.toggleCameraMode": "Przełącz Tryb Kamery", "key.xtracr_realcamera.adjustUP": "Dostosuj W GÓRĘ", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ukryj komunikaty o niepowodzeniu wiązania", "config.option.xtracr_realcamera.renderStuckObjects": "Wyświetl Zatkane Obiekty", "config.option.xtracr_realcamera.rerenderModel": "Ponownie Wyrenderuj Model", - "config.option.xtracr_realcamera.disableWhenSneaking": "Wyłącz główną funkcję podczas skradania", - "config.option.xtracr_realcamera.disableWhenSwimming": "Wyłącz główną funkcję podczas pływania", - "config.option.xtracr_realcamera.swimOutTick": "Opóźnienie wyjścia ze stanu pływania (w tickach)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Klatki przechowywania wyniku wiązania", "config.option.xtracr_realcamera.displacementSmoothFactor": "Współczynnik wygładzania przemieszczenia", "config.option.xtracr_realcamera.rotationSmoothFactor": "Współczynnik wygładzania obrotu", + "config.option.xtracr_realcamera.activeConfigIndex": "Aktywny Indeks Konfiguracji", + "config.option.xtracr_realcamera.disableConfig": "Wyłącz Konfigurację", + "config.option.xtracr_realcamera.disableWhenSneaking": "Wyłącz główną funkcję podczas skradania", + "config.option.xtracr_realcamera.disableWhenCrawling": "Wyłącz główną funkcję podczas czołgania", + "config.option.xtracr_realcamera.disableWhenSwimming": "Wyłącz główną funkcję podczas pływania", + "config.option.xtracr_realcamera.outTick": "Opóźnienie wyjścia ze stanu pływania (w tickach)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Wyłącz główną funkcję podczas trzymania...", "config.option.xtracr_realcamera.disableRenderItems": "Wyłącz renderowanie podczas trzymania...", "config.tooltip.xtracr_realcamera.isClassic": "Tryb klasyczny wprowadza tylko proste zmiany w pozycji i obrocie kamery", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "Po naciśnięciu klawisza dostosowania, reguluj przesunięcie lub obrót kamery", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Strzały, żądła pszczół i inne obiekty, które mogą utknąć w ciele gracza", "config.tooltip.xtracr_realcamera.rerenderModel": "Ponownie renderuj model w oryginalnym czasie renderowania, aby uniknąć problemów wizualnych spowodowanych wczesnym renderowaniem", - "config.tooltip.xtracr_realcamera.swimOutTick": "Opóźnienie włączenia głównej funkcji po wyjściu ze stanu pływania (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Przez kilka klatek po niepowodzeniu wiązania kontynuuj używanie poprzedniego udanego wyniku wiązania", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Współczynnik wygładzania przemieszczenia kamery, im wyższa wartość, tym płynniejszy ruch", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Współczynnik wygładzania obrotu kamery, im wyższa wartość, tym płynniejszy ruch", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Aktualnie powiązany indeks konfiguracji, 0 oznacza pozwolenie na powiązanie z dowolną prawidłową konfiguracją", + "config.tooltip.xtracr_realcamera.outTick": "Opóźnienie włączenia głównej funkcji po wyjściu ze stanu pływania (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Obsługiwane są trzy metody dopasowania:\n1. Dopasowanie wildcard `*` (np. `minecraft:*sword`)\n2. Dopasowanie tagów (zaczyna się od `#`, np. `#minecraft:swords`)\n3. Bezpośrednie ID przedmiotu (np. `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Błąd powiązania, przejdź do ekranu %s i skonfiguruj ręcznie (Klawisz: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Konfiguracje", "screen.widget.xtracr_realcamera.modelView_copy": "Kopiuj", "screen.widget.xtracr_realcamera.modelView_paste": "Wklej", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Bieżąca Konfiguracja", "screen.tooltip.xtracr_realcamera.modelView_import": "Importuj konfigurację ze schowka", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s powiódł się!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import nie powiódł się: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/pt_br.json b/common/src/main/resources/assets/realcamera/lang/pt_br.json index a8f696f2..dc1188e5 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_br.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_br.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Abrir Tela de Visualização do Modelo", "key.xtracr_realcamera.togglePerspective": "Ativar/Desativar", + "key.xtracr_realcamera.activeConfigIndexPREV": "Mudar para configuração anterior", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Mudar para próxima configuração", + "key.xtracr_realcamera.activeConfigIndexRESET": "Redefinir índice de configuração", "key.xtracr_realcamera.toggleAdjustMode": "Alternar Modo de Ajuste", "key.xtracr_realcamera.toggleCameraMode": "Alternar Modo de Câmera", "key.xtracr_realcamera.adjustUP": "Ajustar PARA CIMA", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensagens de falha de vinculação", "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Presos", "config.option.xtracr_realcamera.rerenderModel": "Renderizar Modelo Novamente", - "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", - "config.option.xtracr_realcamera.disableWhenSwimming": "Desativar função principal ao nadar", - "config.option.xtracr_realcamera.swimOutTick": "Atraso para sair do estado de natação (em ticks)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Quadros de retenção de resultado de vinculação", "config.option.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização de deslocamento", "config.option.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização de rotação", + "config.option.xtracr_realcamera.activeConfigIndex": "Índice de Configuração Ativa", + "config.option.xtracr_realcamera.disableConfig": "Desativar Configuração", + "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", + "config.option.xtracr_realcamera.disableWhenCrawling": "Desativar função principal ao rastejar", + "config.option.xtracr_realcamera.disableWhenSwimming": "Desativar função principal ao nadar", + "config.option.xtracr_realcamera.outTick": "Atraso na saída do estado de natação (em ticks)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Desativar função principal ao segurar...", "config.option.xtracr_realcamera.disableRenderItems": "Desativar renderização ao segurar...", "config.tooltip.xtracr_realcamera.isClassic": "O modo clássico apenas faz alterações simples na posição e rotação da câmera", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "Ao pressionar a tecla de ajuste, ajusta o deslocamento ou rotação da câmera", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flechas, ferrões de abelha e outros objetos que podem ficar presos no corpo do jogador", "config.tooltip.xtracr_realcamera.rerenderModel": "Renderizar o modelo novamente no momento original de renderização para evitar alguns problemas visuais causados pela renderização antecipada", - "config.tooltip.xtracr_realcamera.swimOutTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Por vários quadros após a falha de vinculação, continue usando o resultado de vinculação bem-sucedido anterior", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização do deslocamento da câmera, quanto maior o valor, mais suave o movimento", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização da rotação da câmera, quanto maior o valor, mais suave o movimento", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuração atualmente vinculada, 0 significa permitir vinculação a qualquer configuração válida", + "config.tooltip.xtracr_realcamera.outTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Três métodos de correspondência são suportados:\n1. Correspondência com curinga `*` (por exemplo, `minecraft:*sword`)\n2. Correspondência de tag (começa com `#`, por exemplo, `#minecraft:swords`)\n3. ID de item direto (por exemplo, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Vinculação falhou, por favor vá para a tela %s e configure manualmente (Tecla: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", "screen.widget.xtracr_realcamera.modelView_paste": "Colar", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/pt_pt.json b/common/src/main/resources/assets/realcamera/lang/pt_pt.json index 068d511b..49f8ba17 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_pt.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_pt.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Abrir Tela de Visualização de Modelo", "key.xtracr_realcamera.togglePerspective": "Ativar/Desativar", + "key.xtracr_realcamera.activeConfigIndexPREV": "Mudar para configuração anterior", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Mudar para próxima configuração", + "key.xtracr_realcamera.activeConfigIndexRESET": "Redefinir índice de configuração", "key.xtracr_realcamera.toggleAdjustMode": "Alternar Modo de Ajuste", "key.xtracr_realcamera.toggleCameraMode": "Alternar Modo de Câmera", "key.xtracr_realcamera.adjustUP": "Ajustar PARA CIMA", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensagens de falha de vinculação", "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Presos", "config.option.xtracr_realcamera.rerenderModel": "Renderizar Modelo Novamente", - "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", - "config.option.xtracr_realcamera.disableWhenSwimming": "Desativar função principal ao nadar", - "config.option.xtracr_realcamera.swimOutTick": "Atraso na saída do estado de natação (em ticks)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Quadros de retenção de resultado de vinculação", "config.option.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização de deslocamento", "config.option.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização de rotação", + "config.option.xtracr_realcamera.activeConfigIndex": "Índice de Configuração Ativa", + "config.option.xtracr_realcamera.disableConfig": "Desativar Configuração", + "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", + "config.option.xtracr_realcamera.disableWhenCrawling": "Desativar função principal ao rastejar", + "config.option.xtracr_realcamera.disableWhenSwimming": "Desativar função principal ao nadar", + "config.option.xtracr_realcamera.outTick": "Atraso na saída do estado de natação (em ticks)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Desativar função principal ao segurar...", "config.option.xtracr_realcamera.disableRenderItems": "Desativar renderização ao segurar...", "config.tooltip.xtracr_realcamera.isClassic": "O modo clássico apenas faz alterações simples na posição e rotação da câmera", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "Ao pressionar a tecla de ajuste, ajusta o deslocamento ou rotação da câmera", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flechas, ferrões de abelha e outros objetos que podem ficar presos no corpo do jogador", "config.tooltip.xtracr_realcamera.rerenderModel": "Renderizar o modelo novamente no momento original de renderização para evitar alguns problemas visuais causados pela renderização antecipada", - "config.tooltip.xtracr_realcamera.swimOutTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Por vários quadros após a falha de vinculação, continue usando o resultado de vinculação bem-sucedido anterior", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização do deslocamento da câmera, quanto maior o valor, mais suave o movimento", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização da rotação da câmera, quanto maior o valor, mais suave o movimento", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuração atualmente vinculada, 0 significa permitir vinculação a qualquer configuração válida", + "config.tooltip.xtracr_realcamera.outTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Três métodos de correspondência são suportados:\n1. Correspondência com curinga `*` (por exemplo, `minecraft:*sword`)\n2. Correspondência de tag (começa com `#`, por exemplo, `#minecraft:swords`)\n3. ID de item direto (por exemplo, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Vinculação falhou, por favor vá para a tela %s e configure manualmente (Tecla: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", "screen.widget.xtracr_realcamera.modelView_paste": "Colar", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/ru_ru.json b/common/src/main/resources/assets/realcamera/lang/ru_ru.json index 67d197f3..7b9505af 100644 --- a/common/src/main/resources/assets/realcamera/lang/ru_ru.json +++ b/common/src/main/resources/assets/realcamera/lang/ru_ru.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Открыть Экран Просмотра Модели", "key.xtracr_realcamera.togglePerspective": "Включить/Выключить", + "key.xtracr_realcamera.activeConfigIndexPREV": "Переключиться на предыдущую конфигурацию", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Переключиться на следующую конфигурацию", + "key.xtracr_realcamera.activeConfigIndexRESET": "Сбросить индекс конфигурации", "key.xtracr_realcamera.toggleAdjustMode": "Переключить Режим Настройки", "key.xtracr_realcamera.toggleCameraMode": "Переключить Режим Камеры", "key.xtracr_realcamera.adjustUP": "Настроить ВВЕРХ", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Скрывать сообщения о неудачной привязке", "config.option.xtracr_realcamera.renderStuckObjects": "Отображать Застрявшие Объекты", "config.option.xtracr_realcamera.rerenderModel": "Перерисовать Модель", - "config.option.xtracr_realcamera.disableWhenSneaking": "Отключить основную функцию при краже", - "config.option.xtracr_realcamera.disableWhenSwimming": "Отключить основную функцию при плавании", - "config.option.xtracr_realcamera.swimOutTick": "Задержка выхода из состояния плавания (в тиках)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадры сохранения результата привязки", "config.option.xtracr_realcamera.displacementSmoothFactor": "Коэффициент сглаживания смещения", "config.option.xtracr_realcamera.rotationSmoothFactor": "Коэффициент сглаживания вращения", + "config.option.xtracr_realcamera.activeConfigIndex": "Активный индекс конфигурации", + "config.option.xtracr_realcamera.disableConfig": "Отключить Конфигурацию", + "config.option.xtracr_realcamera.disableWhenSneaking": "Отключить основную функцию при краже", + "config.option.xtracr_realcamera.disableWhenCrawling": "Отключить основную функцию при ползании", + "config.option.xtracr_realcamera.disableWhenSwimming": "Отключить основную функцию при плавании", + "config.option.xtracr_realcamera.outTick": "Задержка выхода из состояния плавания (в тиках)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Отключить основную функцию при держании...", "config.option.xtracr_realcamera.disableRenderItems": "Отключить отображение при держании...", "config.tooltip.xtracr_realcamera.isClassic": "Классический режим вносит только простые изменения в положение и вращение камеры", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "При нажатии клавиши настройки, регулировать смещение или вращение камеры", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Стрелы, жала пчел и другие объекты, которые могут застрять в теле игрока", "config.tooltip.xtracr_realcamera.rerenderModel": "Перерисовывать модель в исходное время рендеринга, чтобы избежать визуальных проблем, вызванных ранним рендерингом", - "config.tooltip.xtracr_realcamera.swimOutTick": "Время перед включением основной функции после выхода из состояния плавания (1 тик = 0.05с)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "В течение нескольких кадров после неудачной привязки продолжать использовать предыдущий успешный результат привязки", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Коэффициент сглаживания смещения камеры, чем выше значение, тем плавнее движение", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Коэффициент сглаживания вращения камеры, чем выше значение, тем плавнее движение", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Текущий индекс привязанной конфигурации, 0 означает разрешение привязки к любой допустимой конфигурации", + "config.tooltip.xtracr_realcamera.outTick": "Время перед включением основной функции после выхода из состояния плавания (1 тик = 0.05с)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Поддерживаются три метода сопоставления:\n1. Сопоставление с подстановочным знаком `*` (например, `minecraft:*sword`)\n2. Сопоставление по тегам (начинается с `#`, например, `#minecraft:swords`)\n3. Прямой ID предмета (например, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Ошибка привязки, пожалуйста, перейдите на экран %s и настройте вручную (Клавиша: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Конфигурации", "screen.widget.xtracr_realcamera.modelView_copy": "Копировать", "screen.widget.xtracr_realcamera.modelView_paste": "Вставить", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Текущая Конфигурация", "screen.tooltip.xtracr_realcamera.modelView_import": "Импортировать конфигурацию из буфера обмена", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Импорт %s успешен!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Ошибка импорта: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/tr_tr.json b/common/src/main/resources/assets/realcamera/lang/tr_tr.json index 7a64a552..79eb9211 100644 --- a/common/src/main/resources/assets/realcamera/lang/tr_tr.json +++ b/common/src/main/resources/assets/realcamera/lang/tr_tr.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Model Görünüm Ekranını Aç", "key.xtracr_realcamera.togglePerspective": "Etkinleştir/Devre Dışı Bırak", + "key.xtracr_realcamera.activeConfigIndexPREV": "Önceki yapılandırmaya geç", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Sonraki yapılandırmaya geç", + "key.xtracr_realcamera.activeConfigIndexRESET": "Yapılandırma indeksini sıfırla", "key.xtracr_realcamera.toggleAdjustMode": "Ayarlama Modunu Değiştir", "key.xtracr_realcamera.toggleCameraMode": "Kamera Modunu Değiştir", "key.xtracr_realcamera.adjustUP": "YUKARI Ayarla", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Bağlama Başarısız Mesajını Gizle", "config.option.xtracr_realcamera.renderStuckObjects": "Sıkışmış Nesneleri Renderla", "config.option.xtracr_realcamera.rerenderModel": "Modeli Yeniden Renderla", - "config.option.xtracr_realcamera.disableWhenSneaking": "Eğilirken ana özelliği devre dışı bırak", - "config.option.xtracr_realcamera.disableWhenSwimming": "Yüzerken ana özelliği devre dışı bırak", - "config.option.xtracr_realcamera.swimOutTick": "Yüzme durumundan çıkma gecikmesi (tik cinsinden)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bağlama Sonucu Saklama Kareleri", "config.option.xtracr_realcamera.displacementSmoothFactor": "Yer Değiştirme Düzgünleştirme Faktörü", "config.option.xtracr_realcamera.rotationSmoothFactor": "Dönüş Düzgünleştirme Faktörü", + "config.option.xtracr_realcamera.activeConfigIndex": "Aktif Yapılandırma İndeksi", + "config.option.xtracr_realcamera.disableConfig": "Yapılandırmayı Devre Dışı Bırak", + "config.option.xtracr_realcamera.disableWhenSneaking": "Eğilirken ana özelliği devre dışı bırak", + "config.option.xtracr_realcamera.disableWhenCrawling": "Sürünürken ana özelliği devre dışı bırak", + "config.option.xtracr_realcamera.disableWhenSwimming": "Yüzerken ana özelliği devre dışı bırak", + "config.option.xtracr_realcamera.outTick": "Yüzme durumundan çıkma gecikmesi (tik cinsinden)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Tutarken ana özelliği devre dışı bırak...", "config.option.xtracr_realcamera.disableRenderItems": "Tutarken renderlamayı devre dışı bırak...", "config.tooltip.xtracr_realcamera.isClassic": "Klasik mod yalnızca kameranın konumuna ve dönüşüne basit değişiklikler yapar", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "Ayarlama tuşuna basıldığında, kameranın ofsetini veya dönüşünü ayarlar", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Oyuncunun vücuduna saplanabilen oklar, arı sokmaları ve diğer nesneler", "config.tooltip.xtracr_realcamera.rerenderModel": "Modeli orijinal render zamanında yeniden renderlayarak erken renderlamadan kaynaklanan görsel sorunları önler", - "config.tooltip.xtracr_realcamera.swimOutTick": "Yüzme durumundan çıktıktan sonra ana özelliği etkinleştirmeden önce geçen süre (1 tik = 0.05s)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Bağlama başarısızlığından sonraki birkaç kare boyunca önceki başarılı bağlama sonucunu kullanmaya devam edin", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Kamera yer değiştirme düzgünleştirme faktörü, değer ne kadar yüksekse hareket o kadar pürüzsüz olur", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Kamera dönüş düzgünleştirme faktörü, değer ne kadar yüksekse hareket o kadar pürüzsüz olur", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Şu anda bağlı yapılandırma indeksi, 0 herhangi bir geçerli yapılandırmaya bağlanmaya izin verir", + "config.tooltip.xtracr_realcamera.outTick": "Yüzme durumundan çıktıktan sonra ana özelliği etkinleştirmeden önce geçen süre (1 tik = 0.05s)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Üç eşleştirme yöntemi desteklenir:\n1. Joker karakter `*` eşleştirmesi (örneğin, `minecraft:*sword`)\n2. Etiket eşleştirmesi (`#` ile başlar, örneğin `#minecraft:swords`)\n3. Doğrudan öğe kimliği (örneğin, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Bağlama başarısız oldu, lütfen %s ekranına gidin ve manuel olarak yapılandırın (Tuş: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Yapılandırmalar", "screen.widget.xtracr_realcamera.modelView_copy": "Kopyala", "screen.widget.xtracr_realcamera.modelView_paste": "Yapıştır", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Mevcut Yapılandırma", "screen.tooltip.xtracr_realcamera.modelView_import": "Panodan yapılandırmayı içe aktar", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s içe aktarma başarılı!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "İçe aktarma başarısız: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/uk_ua.json b/common/src/main/resources/assets/realcamera/lang/uk_ua.json index d85e8c1d..764b0716 100644 --- a/common/src/main/resources/assets/realcamera/lang/uk_ua.json +++ b/common/src/main/resources/assets/realcamera/lang/uk_ua.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "Відкрити Екран Перегляду Моделі", "key.xtracr_realcamera.togglePerspective": "Увімкнути/Вимкнути", + "key.xtracr_realcamera.activeConfigIndexPREV": "Переключитися на попередню конфігурацію", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Переключитися на наступну конфігурацію", + "key.xtracr_realcamera.activeConfigIndexRESET": "Скинути індекс конфігурації", "key.xtracr_realcamera.toggleAdjustMode": "Переключити Режим Налаштування", "key.xtracr_realcamera.toggleCameraMode": "Переключити Режим Камери", "key.xtracr_realcamera.adjustUP": "Налаштувати ВГОРУ", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "Приховувати повідомлення про невдалу прив'язку", "config.option.xtracr_realcamera.renderStuckObjects": "Відображати Застряглі Об'єкти", "config.option.xtracr_realcamera.rerenderModel": "Перемалювати Модель", - "config.option.xtracr_realcamera.disableWhenSneaking": "Вимкнути основну функцію при крадіжці", - "config.option.xtracr_realcamera.disableWhenSwimming": "Вимкнути основну функцію при плаванні", - "config.option.xtracr_realcamera.swimOutTick": "Затримка виходу зі стану плавання (у тіках)", "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадри збереження результату прив'язки", "config.option.xtracr_realcamera.displacementSmoothFactor": "Коефіцієнт згладжування зміщення", "config.option.xtracr_realcamera.rotationSmoothFactor": "Коефіцієнт згладжування обертання", + "config.option.xtracr_realcamera.activeConfigIndex": "Активний індекс конфігурації", + "config.option.xtracr_realcamera.disableConfig": "Вимкнути Конфігурацію", + "config.option.xtracr_realcamera.disableWhenSneaking": "Вимкнути основну функцію при крадіжці", + "config.option.xtracr_realcamera.disableWhenCrawling": "Вимкнути основну функцію при повзанні", + "config.option.xtracr_realcamera.disableWhenSwimming": "Вимкнути основну функцію при плаванні", + "config.option.xtracr_realcamera.outTick": "Затримка виходу зі стану плавання (у тіках)", "config.option.xtracr_realcamera.disableMainFeatureItems": "Вимкнути основну функцію при триманні...", "config.option.xtracr_realcamera.disableRenderItems": "Вимкнути відображення при триманні...", "config.tooltip.xtracr_realcamera.isClassic": "Класичний режим вносить лише прості зміни в положення та обертання камери", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "При натисканні клавіші налаштування, регулювати зміщення або обертання камери", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Стріли, жала бджіл та інші об'єкти, які можуть застрягти в тілі гравця", "config.tooltip.xtracr_realcamera.rerenderModel": "Перемальовувати модель у вихідний час рендерингу, щоб уникнути візуальних проблем, викликаних раннім рендерингом", - "config.tooltip.xtracr_realcamera.swimOutTick": "Час перед ввімкненням основної функції після виходу зі стану плавання (1 тік = 0.05с)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Протягом кількох кадрів після невдалої прив'язки продовжувати використовувати попередній успішний результат прив'язки", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Коефіцієнт згладжування зміщення камери, чим вище значення, тим плавніший рух", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Коефіцієнт згладжування обертання камери, чим вище значення, тим плавніший рух", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Поточний індекс прив'язаної конфігурації, 0 означає дозвіл прив'язки до будь-якої допустимої конфігурації", + "config.tooltip.xtracr_realcamera.outTick": "Час перед ввімкненням основної функції після виходу зі стану плавання (1 тік = 0.05с)", "config.tooltip.xtracr_realcamera.disableRenderItems": "Підтримуються три методи співставлення:\n1. Співставлення з підстановковим знаком `*` (наприклад, `minecraft:*sword`)\n2. Співставлення за тегами (починається з `#`, наприклад, `#minecraft:swords`)\n3. Прямий ID предмета (наприклад, `minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: Помилка прив'язки, будь ласка, перейдіть на екран %s та налаштуйте вручну (Клавіша: %s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "Конфігурації", "screen.widget.xtracr_realcamera.modelView_copy": "Копіювати", "screen.widget.xtracr_realcamera.modelView_paste": "Вставити", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Поточна Конфігурація", "screen.tooltip.xtracr_realcamera.modelView_import": "Імпортувати конфігурацію з буфера обміну", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпорт %s успішний!", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Помилка імпорту: \n%s", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_hk.json b/common/src/main/resources/assets/realcamera/lang/zh_hk.json index 81052770..0b23af1c 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_hk.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_hk.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "打開模型視圖界面", "key.xtracr_realcamera.togglePerspective": "開啟/關閉", + "key.xtracr_realcamera.activeConfigIndexPREV": "切換到上一個配置", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切換到下一個配置", + "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", "key.xtracr_realcamera.toggleAdjustMode": "切換調整模式", "key.xtracr_realcamera.toggleCameraMode": "切換攝像頭模式", "key.xtracr_realcamera.adjustUP": "向上調整", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱藏綁定失敗消息", "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物體", "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", - "config.option.xtracr_realcamera.disableWhenSneaking": "潛行時禁用主要功能", - "config.option.xtracr_realcamera.disableWhenSwimming": "游泳時禁用主要功能", - "config.option.xtracr_realcamera.swimOutTick": "游泳狀態退出延遲(單位:tick)", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留幀數", - "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", - "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑系数", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留帧数", + "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑係數", + "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑係數", + "config.option.xtracr_realcamera.activeConfigIndex": "當前配置索引", + "config.option.xtracr_realcamera.disableConfig": "禁用配置", + "config.option.xtracr_realcamera.disableWhenSneaking": "潛行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...時禁用主要功能", "config.option.xtracr_realcamera.disableRenderItems": "在手持...時禁用渲染", "config.tooltip.xtracr_realcamera.isClassic": "經典模式只對攝像頭的位置和旋轉做簡單的修改", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "當前按下調整鍵時是調整攝像頭的偏移還是旋轉", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它會卡在玩家身體裡的物體", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染時機重新渲染模型,以避免一些因提前渲染導致的視覺問題", - "config.tooltip.xtracr_realcamera.swimOutTick": "玩家停止游泳狀態後重啟主要功能的時間(1 tick = 0.05秒)", + "config.tooltip.xtracr_realcamera.outTick": "玩家停止特定狀態後重啟主要功能的時間(1 tick = 0.05秒)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在綁定失敗的數帧内,沿用上个成功的綁定結果", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相機位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相機旋轉平滑系数,值越大越平滑", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "當前綁定的配置索引,0表示允許綁定任何有效配置", "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三種匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 標簽匹配`#`開頭(如`#minecraft:tools`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: 綁定失敗,請前往%s界面手動設置(鍵位:%s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "配置", "screen.widget.xtracr_realcamera.modelView_copy": "複製", "screen.widget.xtracr_realcamera.modelView_paste": "貼上", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_tw.json b/common/src/main/resources/assets/realcamera/lang/zh_tw.json index 81052770..0b23af1c 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_tw.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_tw.json @@ -2,6 +2,9 @@ "general.xtracr_realcamera.modName": "Real Camera", "key.xtracr_realcamera.modelViewScreen": "打開模型視圖界面", "key.xtracr_realcamera.togglePerspective": "開啟/關閉", + "key.xtracr_realcamera.activeConfigIndexPREV": "切換到上一個配置", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切換到下一個配置", + "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", "key.xtracr_realcamera.toggleAdjustMode": "切換調整模式", "key.xtracr_realcamera.toggleCameraMode": "切換攝像頭模式", "key.xtracr_realcamera.adjustUP": "向上調整", @@ -43,12 +46,15 @@ "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱藏綁定失敗消息", "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物體", "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", - "config.option.xtracr_realcamera.disableWhenSneaking": "潛行時禁用主要功能", - "config.option.xtracr_realcamera.disableWhenSwimming": "游泳時禁用主要功能", - "config.option.xtracr_realcamera.swimOutTick": "游泳狀態退出延遲(單位:tick)", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留幀數", - "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", - "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑系数", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留帧数", + "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑係數", + "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑係數", + "config.option.xtracr_realcamera.activeConfigIndex": "當前配置索引", + "config.option.xtracr_realcamera.disableConfig": "禁用配置", + "config.option.xtracr_realcamera.disableWhenSneaking": "潛行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...時禁用主要功能", "config.option.xtracr_realcamera.disableRenderItems": "在手持...時禁用渲染", "config.tooltip.xtracr_realcamera.isClassic": "經典模式只對攝像頭的位置和旋轉做簡單的修改", @@ -61,10 +67,11 @@ "config.tooltip.xtracr_realcamera.adjustOffset": "當前按下調整鍵時是調整攝像頭的偏移還是旋轉", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它會卡在玩家身體裡的物體", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染時機重新渲染模型,以避免一些因提前渲染導致的視覺問題", - "config.tooltip.xtracr_realcamera.swimOutTick": "玩家停止游泳狀態後重啟主要功能的時間(1 tick = 0.05秒)", + "config.tooltip.xtracr_realcamera.outTick": "玩家停止特定狀態後重啟主要功能的時間(1 tick = 0.05秒)", "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在綁定失敗的數帧内,沿用上个成功的綁定結果", "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相機位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相機旋轉平滑系数,值越大越平滑", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "當前綁定的配置索引,0表示允許綁定任何有效配置", "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三種匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 標簽匹配`#`開頭(如`#minecraft:tools`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", "message.xtracr_realcamera.bindingFailed": "[%s]: 綁定失敗,請前往%s界面手動設置(鍵位:%s)", @@ -97,6 +104,7 @@ "screen.widget.xtracr_realcamera.modelView_configs": "配置", "screen.widget.xtracr_realcamera.modelView_copy": "複製", "screen.widget.xtracr_realcamera.modelView_paste": "貼上", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", From e60f60ce8af1564c424d35310bcddce33d62c86a Mon Sep 17 00:00:00 2001 From: xTracr <57320980+xTracr@users.noreply.github.com> Date: Sun, 12 Apr 2026 22:24:06 +0800 Subject: [PATCH 09/33] Upgrade to 26.1.1 (#204) * Try to adapt to 26.1-snapshot environment * Update workflows to use Java 25 * Replace `deltaTick` with `partialTicks` * Upgrade to 26.1.1 * Reformat the code * Optimize `IterableVertexBuffer` and add `RoutingSubmitCollector` to fix shadow rendering * Add back commitSHA * Add solid feature rendering and refactor icon buttons * Fix DoubleSlider, raycast * Fix neoforge, improve build.gradle.kts --- .github/ISSUE_TEMPLATE/bug_report_cn.yml | 2 +- .github/workflows/build.yml | 8 +- .github/workflows/publish.yml | 6 +- .gitignore | 3 + README.md | 90 ++--- README_ZH.md | 90 ++--- build.gradle | 52 --- build.gradle.kts | 18 + common/build.gradle | 12 - common/build.gradle.kts | 53 +++ .../com/xtracr/realcamera/KeyMappings.java | 31 +- .../com/xtracr/realcamera/RealCameraCore.java | 116 +++--- .../com/xtracr/realcamera/api/BindResult.java | 29 +- .../xtracr/realcamera/api/RealCameraAPI.java | 4 +- .../compat/CompatibilityHelper.java | 18 +- .../realcamera/compat/DisableHelper.java | 21 +- .../realcamera/compat/LegacyBindingMode.java | 87 +---- .../xtracr/realcamera/compat/YSMCompat.java | 27 +- .../xtracr/realcamera/config/BindTarget.java | 13 +- .../realcamera/config/ConfigScreen.java | 59 +-- .../xtracr/realcamera/config/ModConfig.java | 2 +- .../realcamera/gui/CyclingTexturedButton.java | 71 ---- .../com/xtracr/realcamera/gui/GUIHelper.java | 90 +++-- .../xtracr/realcamera/gui/ModelAnalyser.java | 143 +++----- .../realcamera/gui/ModelViewScreen.java | 342 +++++++++--------- .../xtracr/realcamera/gui/TexturedButton.java | 52 --- .../gui/components/CycleIconButton.java | 73 ++++ .../gui/{ => components}/DoubleSlider.java | 11 +- .../gui/{ => components}/NumberField.java | 56 +-- .../gui/components/SimpleIconButton.java | 38 ++ .../xtracr/realcamera/mixin/MixinCamera.java | 83 +++-- .../mixin/MixinFishingHookRenderer.java | 11 +- .../realcamera/mixin/MixinGameRenderer.java | 55 +-- .../com/xtracr/realcamera/mixin/MixinGui.java | 16 +- .../xtracr/realcamera/mixin/MixinItem.java | 7 +- .../mixin/MixinItemInHandRenderer.java | 6 +- .../realcamera/mixin/MixinLevelRenderer.java | 49 ++- .../realcamera/mixin/MixinLocalPlayer.java | 43 ++- .../realcamera/mixin/MixinPlayerRenderer.java | 15 - .../mixin/MixinStuckInBodyLayer.java | 14 +- .../accessor/AvatarRendererAccessor.java | 16 + .../mixin/accessor/CameraAccessor.java | 12 - ...CustomFeatureRenderer$StorageAccessor.java | 19 + .../mixin/accessor/GameRendererAccessor.java | 14 - .../GuiGraphicsExtractorAccessor.java | 15 + .../ModelFeatureRenderer$StorageAccessor.java | 19 + ...elPartFeatureRenderer$StorageAccessor.java | 19 + .../accessor/PlayerRendererAccessor.java | 19 - .../BuiltIterableBuffer.java | 12 +- .../IterableVertexBuffer.java | 99 ++--- .../renderer/MultiVertexCatcher.java | 195 ++++++++++ .../renderer/RoutingSubmitCollector.java | 182 ++++++++++ .../renderer/gui/GuiCulledModelsRenderer.java | 58 +++ .../gui/GuiFlattenedModelsRenderer.java | 49 +++ .../renderer/state/BuiltModelRecord.java | 14 + .../{util => renderer/state}/VertexData.java | 2 +- .../gui/ColoredFloatLineRenderState.java | 63 ++++ .../gui/ColoredFloatQuadRenderState.java | 64 ++++ .../gui/ColoredFloatRectangleRenderState.java | 48 +++ .../state/gui/GuiCulledModelsRenderState.java | 34 ++ .../gui/GuiFlattenedModelsRenderState.java | 34 ++ .../realcamera/util/CameraTransform.java | 40 ++ .../xtracr/realcamera/util/CrosshairUtil.java | 13 +- .../com/xtracr/realcamera/util/MathUtil.java | 22 +- .../realcamera/util/MultiVertexCatcher.java | 96 ----- .../xtracr/realcamera/util/RaycastUtil.java | 45 +-- .../xtracr/realcamera/util/SmoothUtil.java | 25 -- .../main/resources/architectury.common.json | 3 - .../assets/realcamera/lang/be_by.json | 213 ++++++----- .../assets/realcamera/lang/en_us.json | 213 ++++++----- .../assets/realcamera/lang/es_es.json | 213 ++++++----- .../assets/realcamera/lang/fr_fr.json | 213 ++++++----- .../assets/realcamera/lang/ja_jp.json | 213 ++++++----- .../assets/realcamera/lang/ko_kr.json | 213 ++++++----- .../resources/assets/realcamera/lang/lzh.json | 213 ++++++----- .../assets/realcamera/lang/pl_pl.json | 213 ++++++----- .../assets/realcamera/lang/pt_br.json | 213 ++++++----- .../assets/realcamera/lang/pt_pt.json | 213 ++++++----- .../assets/realcamera/lang/ru_ru.json | 213 ++++++----- .../assets/realcamera/lang/tr_tr.json | 213 ++++++----- .../assets/realcamera/lang/uk_ua.json | 213 ++++++----- .../assets/realcamera/lang/zh_cn.json | 213 ++++++----- .../assets/realcamera/lang/zh_hk.json | 213 ++++++----- .../assets/realcamera/lang/zh_tw.json | 213 ++++++----- .../resources/realcamera-common.mixins.json | 11 +- .../main/resources/realcamera.accesswidener | 5 +- fabric/build.gradle | 72 ---- fabric/build.gradle.kts | 102 ++++++ .../com/xtracr/realcamera/EventHandler.java | 14 - .../xtracr/realcamera/RealCameraFabric.java | 18 +- fabric/src/main/resources/fabric.mod.json | 7 +- .../src/main/resources/realcamera.mixins.json | 2 +- gradle.properties | 19 +- gradle/wrapper/gradle-wrapper.jar | Bin 45633 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- neoforge/build.gradle | 69 ---- neoforge/build.gradle.kts | 99 +++++ neoforge/gradle.properties | 1 - .../com/xtracr/realcamera/EventHandler.java | 16 +- .../xtracr/realcamera/RealCameraNeoForge.java | 25 +- .../resources/META-INF/accesstransformer.cfg | 1 + .../resources/META-INF/neoforge.mods.toml | 14 +- .../src/main/resources/realcamera.mixins.json | 2 +- settings.gradle | 14 - settings.gradle.kts | 24 ++ 106 files changed, 3877 insertions(+), 3197 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts delete mode 100644 common/build.gradle create mode 100644 common/build.gradle.kts delete mode 100644 common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java create mode 100644 common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java rename common/src/main/java/com/xtracr/realcamera/gui/{ => components}/DoubleSlider.java (77%) rename common/src/main/java/com/xtracr/realcamera/gui/{ => components}/NumberField.java (67%) create mode 100644 common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java create mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/AvatarRendererAccessor.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/CameraAccessor.java create mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/CustomFeatureRenderer$StorageAccessor.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/GameRendererAccessor.java create mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/GuiGraphicsExtractorAccessor.java create mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelFeatureRenderer$StorageAccessor.java create mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelPartFeatureRenderer$StorageAccessor.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/PlayerRendererAccessor.java rename common/src/main/java/com/xtracr/realcamera/{util => renderer}/BuiltIterableBuffer.java (93%) rename common/src/main/java/com/xtracr/realcamera/{util => renderer}/IterableVertexBuffer.java (86%) create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/BuiltModelRecord.java rename common/src/main/java/com/xtracr/realcamera/{util => renderer/state}/VertexData.java (99%) create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatQuadRenderState.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatRectangleRenderState.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiCulledModelsRenderState.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiFlattenedModelsRenderState.java create mode 100644 common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/util/MultiVertexCatcher.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/util/SmoothUtil.java delete mode 100644 common/src/main/resources/architectury.common.json delete mode 100644 fabric/build.gradle create mode 100644 fabric/build.gradle.kts delete mode 100644 fabric/src/main/java/com/xtracr/realcamera/EventHandler.java delete mode 100644 neoforge/build.gradle create mode 100644 neoforge/build.gradle.kts delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml index 02018ff9..6e50b14e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_cn.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -73,7 +73,7 @@ body: attributes: label: 日志和崩溃报告 description: >- - 你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能 + 你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能
你可以日志上传到类似 https://paste.ubuntu.com/ 或者 https://mclo.gs/ 的网站并在此贴出链接
**请不要在此此处直接粘贴大段的日志文本!!** placeholder: '把日志文件往这丢或者使用外部链接' \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b790e02..7414c951 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,15 +19,15 @@ jobs: run: env - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: true - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: "temurin" - java-version: 21 + java-version: 25 - name: Make Gradle Wrapper Executable if: ${{ runner.os != 'Windows' }} @@ -37,7 +37,7 @@ jobs: run: ./gradlew clean build -PcommitSHA=${{ github.sha }} - name: Capture Build Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Artifacts path: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c1efbf9c..62670d51 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,15 +18,15 @@ jobs: run: env - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: true - name: Setup JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: "temurin" - java-version: 21 + java-version: 25 - name: Make Gradle Wrapper Executable if: ${{ runner.os != 'Windows' }} diff --git a/.gitignore b/.gitignore index 6b72fc32..36d81e47 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ hs_err_*.log replay_*.log *.hprof *.jfr + +# claude +CLAUDE.md \ No newline at end of file diff --git a/README.md b/README.md index ea1e7342..82d22a72 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### [中文](README_ZH.md) Make the camera more realistic in the first-person view. -Supported versions: 1.18.2-1.20.4 Forge, 1.18.2-1.21.8 Fabric, 1.21-1.21.8 NeoForge. +Supported versions: 1.18.2 - 1.20.4 Forge, 1.18.2 - 26.1 Fabric, 1.21 - 26.1 NeoForge. Download the mod from [Releases](https://github.com/xTracr/RealCamera/releases), [Modrinth](https://modrinth.com/mod/real-camera) or [CurseForge](https://curseforge.com/minecraft/mc-mods/real-camera) Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/build.yml) @@ -19,11 +19,11 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Theoretically, most mod models are supported, but need to be configured manually: * First, set the key binding for `Open Model View Screen`. - * ![gui_configs](https://cdn.modrinth.com/data/fYYSAh4R/images/4625282a5683cd38eba2947be1ca82e595e18bad.png) + * ![gui_configs](https://cdn.modrinth.com/data/fYYSAh4R/images/4625282a5683cd38eba2947be1ca82e595e18bad.png) * Open the model view screen and left click with left Alt held to select the corresponding face of the model, scroll with left Alt held to switch between the different layers of the model. * By clicking the `Selecting` button on the left, switch between the three to select the `Forward Vector`, `Upward Vector`, and `Target Plane`. * From the top right button, enter the `Preview` section, where you can see the relative relationship between the camera and the model and make certain adjustments (you can also adjust through key bindings). - * ![gui_preview](https://cdn.modrinth.com/data/fYYSAh4R/images/44c87a6f1750f8d1b03422120e6042d1098896cb.png) + * ![gui_preview](https://cdn.modrinth.com/data/fYYSAh4R/images/44c87a6f1750f8d1b03422120e6042d1098896cb.png) * Enter a name and save. #### Tips @@ -31,68 +31,68 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Configs can have their priority adjusted - higher priority configs appear higher in the right-side list * Disable depth in `Preview` section to hide models blocking the view * About `Disable` section (current version still rough, complex operations): - * When texture ID field is empty, use Left Alt+Left Click to select texture - * Model parts contained by blue boxes won't be rendered - * Left-click drag to select in texture view, other keys cancel selection - * Left Alt+Left Click quickly selects hovered parts - * In `All` mode, entire texture's model won't render (blue box containing the texture in left panel indicates this) - * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) + * When texture ID field is empty, use Left Alt+Left Click to select texture + * Model parts contained by blue boxes won't be rendered + * Left-click drag to select in texture view, other keys cancel selection + * Left Alt+Left Click quickly selects hovered parts + * In `All` mode, entire texture's model won't render (blue box containing the texture in left panel indicates this) + * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) ## Dependencies * Fabric: - * [Fabric API](https://modrinth.com/mod/fabric-api) + * [Fabric API](https://modrinth.com/mod/fabric-api) * Both: - * (Optional but recommended) [Cloth Config API](https://modrinth.com/mod/cloth-config) + * (Optional but recommended) [Cloth Config API](https://modrinth.com/mod/cloth-config) ## FAQ * A part of the model (e.g. hair) is always in the way, how to make it invisible? - * Increasing this value may help, or use `Disable` section - ![disable_depth](https://github.com/xTracr/RealCamera/assets/57320980/78c246e8-34aa-4979-89de-780ee907870b) + * Increasing this value may help, or use `Disable` section + ![disable_depth](https://github.com/xTracr/RealCamera/assets/57320980/78c246e8-34aa-4979-89de-780ee907870b) * What key to press can open Model View Screen? - * Set the key binding by yourself + * Set the key binding by yourself * Why can't i open the Config Screen? - * Please downlowd [Cloth Config API](https://modrinth.com/mod/cloth-config) + * Please downlowd [Cloth Config API](https://modrinth.com/mod/cloth-config) * Why does it show binding failed when use YSM models? - * Snapshot 0.6.15 "try" to fix problems, but it didn't fix completely - * If Minecraft version is 1.20.1, then bind upward vector to head left (or right) side, and set roll angle to 90 (or -90) in preview section + * Snapshot 0.6.15 "try" to fix problems, but it didn't fix completely + * If Minecraft version is 1.20.1, then bind upward vector to head left (or right) side, and set roll angle to 90 (or -90) in preview section * Why does the head of YSM model disappear when in the Model View Screen? - * You downloaded Better Combat, just put it away + * You downloaded Better Combat, just put it away ### Compatibility * Incompatible: - * OptiFine - * Armourer's Workshop (Mod version 0.6+) - * Armors based on GeckoLib - * Customizable Player Models - * Epic Fight (Mod version 0.6-) - * Timeless and Classics Zero,version 1.1.4+ + * OptiFine + * Armourer's Workshop (Mod version 0.6+) + * Armors based on GeckoLib + * Customizable Player Models + * Epic Fight (Mod version 0.6-) + * Timeless and Classics Zero,version 1.1.4+ * Compatible: - * most camera mods - * most player model mods - * Armourer's Workshop (Mod version 0.6-) - * Epic Fight (Mod version 0.6+) - * First-person Model - * Not Enough Animations - * ParCool! - * Pehkui - * Player Animation Lib - * Timeless and Classics Zero,version 1.0.3- - * Yes Steve Model (Not stably compatible) - * Superb Warfare + * most camera mods + * most player model mods + * Armourer's Workshop (Mod version 0.6-) + * Epic Fight (Mod version 0.6+) + * First-person Model + * Not Enough Animations + * ParCool! + * Pehkui + * Player Animation Lib + * Timeless and Classics Zero,version 1.0.3- + * Yes Steve Model (Not stably compatible) + * Superb Warfare * Model Mod Compatibility Requirements with `Real Camera` (Based on Official Mappings): * Vertex Data Acquisition - * `Real Camera` obtains vertex data by overriding the `MultiBufferSource multiBufferSource` parameter of the public method `EntityRenderDispatcher.render` - * The call timing is before the `Camera.setup` phase in the `GameRenderer.renderLevel` method - * *Therefore*, the mod needs to meet the following technical conditions: - * Use only the **provided** `multiBufferSource` parameter when rendering `Minecraft.getCameraEntity`, and avoid alternative approaches for obtaining or creating `MultiBufferSource` instances - * The overall rendering behavior remains unaffected when rendering the player model at the adjusted timing - * Ensure all vertex data ultimately passes through `VertexConsumer` gotten by `MultiBufferSource.getBuffer` + * `Real Camera` obtains vertex data by overriding the `MultiBufferSource multiBufferSource` parameter of the public method `EntityRenderDispatcher.render` + * The call timing is before the `Camera.setup` phase in the `GameRenderer.renderLevel` method + * *Therefore*, the mod needs to meet the following technical conditions: + * Use only the **provided** `multiBufferSource` parameter when rendering `Minecraft.getCameraEntity`, and avoid alternative approaches for obtaining or creating `MultiBufferSource` instances + * The overall rendering behavior remains unaffected when rendering the player model at the adjusted timing + * Ensure all vertex data ultimately passes through `VertexConsumer` gotten by `MultiBufferSource.getBuffer` * Render Times Compatibility - * `Real Camera` renders `Minecraft.getCameraEntity` by calling the public method `EntityRenderDispatcher.render` - * This is the second call to the `EntityRenderDispatcher.render` method in a frame (the first call is to solve the camera parameters). - * *Therefore*, the mod needs to meet the condition that the overall rendering behavior remains unaffected when rendering the player model **multiple times** in the same frame + * `Real Camera` renders `Minecraft.getCameraEntity` by calling the public method `EntityRenderDispatcher.render` + * This is the second call to the `EntityRenderDispatcher.render` method in a frame (the first call is to solve the camera parameters). + * *Therefore*, the mod needs to meet the condition that the overall rendering behavior remains unaffected when rendering the player model **multiple times** in the same frame diff --git a/README_ZH.md b/README_ZH.md index 1df074f4..6f2ae5d0 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -3,7 +3,7 @@ ### [English](README.md) 使第一人称视角下的摄像头更加真实。 -支持的版本: 1.18.2 - 1.20.4 Forge,1.18.2 - 1.21.8 Fabric,1.21 - 1.21.8 NeoForge +支持的版本: 1.18.2 - 1.20.4 Forge,1.18.2 - 26.1 Fabric,1.21 - 26.1 NeoForge 从[Releases](https://github.com/xTracr/RealCamera/releases)、[Modrinth](https://modrinth.com/mod/real-camera)或[CurseForge](https://curseforge.com/minecraft/mc-mods/real-camera)下载 快照版在[这里](https://github.com/xTracr/RealCamera/actions/workflows/build.yml) @@ -19,11 +19,11 @@ * 理论上支持大多数模组模型,但需要手动进行配置: * 首先设置`打开模型视图界面`的按键绑定 - * ![gui_configs](https://cdn.modrinth.com/data/fYYSAh4R/images/4625282a5683cd38eba2947be1ca82e595e18bad.png) + * ![gui_configs](https://cdn.modrinth.com/data/fYYSAh4R/images/4625282a5683cd38eba2947be1ca82e595e18bad.png) * 打开模型视图界面,左Alt+左键选择模型的对应的面,左Alt+滚轮可以在模型的不同层间切换 * 通过点击左侧的`选择`按钮,在三者间切换,选好`向前矢量`、`向上矢量`和`目标平面` * 从右上角的按钮进入`预览`界面,在这里可以看到摄像头与模型的相对关系,并进行一定的调整(也可以通过按键绑定调整) - * ![gui_preview](https://cdn.modrinth.com/data/fYYSAh4R/images/44c87a6f1750f8d1b03422120e6042d1098896cb.png) + * ![gui_preview](https://cdn.modrinth.com/data/fYYSAh4R/images/44c87a6f1750f8d1b03422120e6042d1098896cb.png) * 输入名称并保存 #### Tips @@ -31,67 +31,67 @@ * 可以更改配置的优先级,优先级越高的配置,在右侧排序越靠上 * 在`预览`界面可以更改禁用深度来禁用眼前的模型的渲染 * 关于`禁用`界面(当前版本尚不完善,操作较为繁琐): - * 在左侧材质id输入框为空时,可以使用Alt+左键选择材质 - * 被蓝框包含的部分不会被渲染。 - * 在左侧材质视图中鼠标左键框选,其它键取消选择 - * Alt+左键可快速选中被鼠标指针指向的部分 - * `全部`模式下,整个材质所对应的模型都不会被渲染(左侧会有一个包含整个材质的蓝框来表示这一点) - * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) + * 在左侧材质id输入框为空时,可以使用Alt+左键选择材质 + * 被蓝框包含的部分不会被渲染。 + * 在左侧材质视图中鼠标左键框选,其它键取消选择 + * Alt+左键可快速选中被鼠标指针指向的部分 + * `全部`模式下,整个材质所对应的模型都不会被渲染(左侧会有一个包含整个材质的蓝框来表示这一点) + * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) ## 依赖项目 * Fabric: - * [Fabric API](https://modrinth.com/mod/fabric-api) + * [Fabric API](https://modrinth.com/mod/fabric-api) * 所有平台: - * (可选但建议)[Cloth Config API](https://modrinth.com/mod/cloth-config) + * (可选但建议)[Cloth Config API](https://modrinth.com/mod/cloth-config) ## 常见问题 * 模型的一部分(如头发)始终挡在面前,怎样隐藏它? - * 增加这个值或许有所帮助,或者使用`禁用`功能 - ![disable_depth](https://github.com/xTracr/RealCamera/assets/57320980/78c246e8-34aa-4979-89de-780ee907870b) + * 增加这个值或许有所帮助,或者使用`禁用`功能 + ![disable_depth](https://github.com/xTracr/RealCamera/assets/57320980/78c246e8-34aa-4979-89de-780ee907870b) * 按什么键打开模组视图界面? - * 在按键绑定里自己设置 + * 在按键绑定里自己设置 * 为什么打不开配置界面(模组设置)? - * 没有安装[Cloth Config API](https://modrinth.com/mod/cloth-config) + * 没有安装[Cloth Config API](https://modrinth.com/mod/cloth-config) * 为什么ysm模型有时候会弹出绑定失败? - * 快照0.6.15“尝试”修复了ysm问题,但没有修复透彻 - * 如果Minecraft版本为1.20.1,那么需要将向上矢量绑定在头部的左面(或右面),并在预览界面中将翻滚角设置为90度(或-90度) + * 快照0.6.15“尝试”修复了ysm问题,但没有修复透彻 + * 如果Minecraft版本为1.20.1,那么需要将向上矢量绑定在头部的左面(或右面),并在预览界面中将翻滚角设置为90度(或-90度) * 为什么配置ysm时候,模型视图界面中ysm模型头部消失? - * 安装了Better Combat模组,去掉就可以了 + * 安装了Better Combat模组,去掉就可以了 ### 兼容性 * 不兼容: - * OptiFine - * Armourer's Workshop(时装工坊)(真实相机0.6版本以上) - * 基于GeckoLib的盔甲 - * Customizable Player Models(自定义玩家模型) - * Epic Fight(史诗战斗)(真实相机0.6版本以下) - * [TaCZ]永恒枪械工坊:零 1.1.4版本及以上 + * OptiFine + * Armourer's Workshop(时装工坊)(真实相机0.6版本以上) + * 基于GeckoLib的盔甲 + * Customizable Player Models(自定义玩家模型) + * Epic Fight(史诗战斗)(真实相机0.6版本以下) + * [TaCZ]永恒枪械工坊:零 1.1.4版本及以上 * 兼容: - * 大多数修改玩家镜头的模组 - * 多数模型模组 - * Armourer's Workshop(时装工坊)(真实相机0.6版本以下) - * Epic Fight(史诗战斗)(真实相机0.6版本以上) - * First-person Model(更真实的第一人称模型) - * Not Enough Animations(更多动画) - * Player Animation Lib - * Pehkui - * ParCool! - * [TaCZ]永恒枪械工坊:零 1.0.3版本及以下 - * Yes Steve Model(是,史蒂夫模型)(不能稳定兼容) - * Superb Warfare(卓越前线) + * 大多数修改玩家镜头的模组 + * 多数模型模组 + * Armourer's Workshop(时装工坊)(真实相机0.6版本以下) + * Epic Fight(史诗战斗)(真实相机0.6版本以上) + * First-person Model(更真实的第一人称模型) + * Not Enough Animations(更多动画) + * Player Animation Lib + * Pehkui + * ParCool! + * [TaCZ]永恒枪械工坊:零 1.0.3版本及以下 + * Yes Steve Model(是,史蒂夫模型)(不能稳定兼容) + * Superb Warfare(卓越前线) * 模型模组与`Real Camera`兼容的必要条件(基于官方映射): * 顶点数据获取 - * `Real Camera`通过替换公共方法`EntityRenderDispatcher.render`的`MultiBufferSource multiBufferSource`参数实现顶点数据获取 - * 调用时机为`GameRenderer.renderLevel`流程中的`Camera.setup`阶段之前 - * *因此*,模组需要满足以下技术条件: - * 渲染`Minecraft.getCameraEntity`时严格使用**传入的**`multiBufferSource`参数,没有通过其他途径获取或创建`MultiBufferSource`实例 - * 在调整后的时机渲染玩家模型,其整体表现不受影响 - * 所有顶点数据最终通过`MultiBufferSource.getBuffer`方法获取的`VertexConsumer`发送给GPU + * `Real Camera`通过替换公共方法`EntityRenderDispatcher.render`的`MultiBufferSource multiBufferSource`参数实现顶点数据获取 + * 调用时机为`GameRenderer.renderLevel`流程中的`Camera.setup`阶段之前 + * *因此*,模组需要满足以下技术条件: + * 渲染`Minecraft.getCameraEntity`时严格使用**传入的**`multiBufferSource`参数,没有通过其他途径获取或创建`MultiBufferSource`实例 + * 在调整后的时机渲染玩家模型,其整体表现不受影响 + * 所有顶点数据最终通过`MultiBufferSource.getBuffer`方法获取的`VertexConsumer`发送给GPU * 渲染次数兼容 - * `Real Camera`通过调用`EntityRenderDispatcher.render`公共方法进行`Minecraft.getCameraEntity`的渲染 - * 这是在一帧中第二次调用`EntityRenderDispatcher.render`方法(第一次是为了解算摄像机参数) - * *因此*,模组需要满足:同一帧内**多次**渲染玩家模型,其整体表现不受影响 + * `Real Camera`通过调用`EntityRenderDispatcher.render`公共方法进行`Minecraft.getCameraEntity`的渲染 + * 这是在一帧中第二次调用`EntityRenderDispatcher.render`方法(第一次是为了解算摄像机参数) + * *因此*,模组需要满足:同一帧内**多次**渲染玩家模型,其整体表现不受影响 diff --git a/build.gradle b/build.gradle deleted file mode 100644 index cd909ce2..00000000 --- a/build.gradle +++ /dev/null @@ -1,52 +0,0 @@ -plugins { - id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false -} - -architectury { - minecraft = rootProject.minecraft_version -} - -subprojects { - apply plugin: "dev.architectury.loom" - - loom { - silentMojangMappingsLicense() - accessWidenerPath = project(":common").file("src/main/resources/realcamera.accesswidener") - } - - dependencies { - minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" - mappings loom.officialMojangMappings() - } -} - -allprojects { - apply plugin: "java" - apply plugin: "architectury-plugin" - apply plugin: "maven-publish" - - base { - archivesName = rootProject.mod_id - } - - version = rootProject.mod_version + (findProperty("commitSHA") ? "-${(commitSHA as String).substring(0,7)}" : "") - group = rootProject.mod_group_id - - repositories { - maven { url "https://maven.shedaniel.me/" } - maven { url "https://maven.terraformersmc.com/releases/" } - maven { url "https://api.modrinth.com/maven" } - //maven { url "https://cursemaven.com" } - //maven { url "https://www.jitpack.io" } - } - - tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" - options.release = 21 - } - - java { - withSourcesJar() - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..f1fa2d86 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("java-library") + id("maven-publish") +} + +allprojects { + val commitSHA = findProperty("commitSHA")?.let { "-${it.toString().take(7)}" }.orEmpty() + group = property("mod_group_id") as String + version = "${property("mod_version")}$commitSHA" + + repositories { + mavenCentral() + maven("https://maven.shedaniel.me/") + maven("https://maven.terraformersmc.com/releases/") + maven("https://maven.fabricmc.net/") + maven("https://maven.neoforged.net/releases/") + } +} diff --git a/common/build.gradle b/common/build.gradle deleted file mode 100644 index f4d27d6a..00000000 --- a/common/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -architectury { - common(rootProject.enabled_platforms.split(",")) -} - -dependencies { - modCompileOnly "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" - - // Cloth Config - modCompileOnly("me.shedaniel.cloth:cloth-config:${rootProject.cloth_config_version}") { - exclude(group: "net.fabricmc.fabric-api") - } -} diff --git a/common/build.gradle.kts b/common/build.gradle.kts new file mode 100644 index 00000000..b282a12d --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,53 @@ +plugins { + id("net.fabricmc.fabric-loom") + id("maven-publish") +} + +val modId = project.property("mod_id") as String +val javaVersion = project.property("java_version") as String +val minecraftVersion = project.property("minecraft_version") as String +val fabricLoaderVersion = project.property("fabric_loader_version") as String + +val clothConfigVersion = project.property("cloth_config_version") as String + +base { + archivesName = "$modId-$minecraftVersion-fabric" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(javaVersion)) + } + withSourcesJar() +} + +tasks.withType { + options.encoding = "UTF-8" + options.release.set(javaVersion.toInt()) +} + +dependencies { + minecraft("com.mojang:minecraft:$minecraftVersion") + + // We depend on Fabric Loader here to use mixin and the Fabric @Environment annotations, + // compileOnly so it doesn't leak into neoforge's runtime classpath + compileOnly("net.fabricmc:fabric-loader:$fabricLoaderVersion") + + // Cloth Config + compileOnly("me.shedaniel.cloth:cloth-config:$clothConfigVersion") { + exclude(group = "net.fabricmc.fabric-api") + } +} + +loom { + accessWidenerPath.set(file("src/main/resources/realcamera.accesswidener")) +} + +publishing { + publications { + register("commonJar") { + artifactId = base.archivesName.get() + from(components["java"]) + } + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java index a951ab39..0fa37732 100644 --- a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java +++ b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java @@ -3,37 +3,38 @@ import com.mojang.blaze3d.platform.InputConstants; import com.xtracr.realcamera.config.ConfigFile; import com.xtracr.realcamera.gui.ModelViewScreen; -import com.xtracr.realcamera.util.LocUtil; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; +import net.minecraft.resources.Identifier; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; public final class KeyMappings { - private static final Map> KEY_MAPPINGS = new HashMap<>(); + public static final KeyMapping.Category GENERAL = new KeyMapping.Category(Identifier.fromNamespaceAndPath(RealCamera.FULL_ID, "general")); public static final KeyMapping MODEL_VIEW_SCREEN; + private static final Map> KEY_MAPPINGS = new HashMap<>(); static { MODEL_VIEW_SCREEN = createKeyMapping("modelViewScreen", client -> client.setScreen(new ModelViewScreen())); - createKeyMapping("togglePerspective", InputConstants.KEY_F6, client -> { + createKeyMapping("togglePerspective", InputConstants.KEY_F6, _ -> { boolean enabled = ConfigFile.config().enabled(); ConfigFile.load(); ConfigFile.config().setEnabled(!enabled); RealCameraCore.reset(); }); - createKeyMapping("toggleAdjustMode", client -> ConfigFile.config().cycleAdjustMode()); - createKeyMapping("toggleCameraMode", client -> ConfigFile.config().setClassic(!ConfigFile.config().isClassic())); - createKeyMapping("adjustFRONT", client -> ConfigFile.config().adjustOffsetX(1)); - createKeyMapping("adjustBACK", client -> ConfigFile.config().adjustOffsetX(-1)); - createKeyMapping("adjustUP", client -> ConfigFile.config().adjustOffsetY(1)); - createKeyMapping("adjustDOWN", client -> ConfigFile.config().adjustOffsetY(-1)); - createKeyMapping("adjustLEFT", client -> ConfigFile.config().adjustOffsetZ(1)); - createKeyMapping("adjustRIGHT", client -> ConfigFile.config().adjustOffsetZ(-1)); - createKeyMapping("activeConfigIndexNEXT", client -> ConfigFile.config().binding.activeConfigIndex += 1); - createKeyMapping("activeConfigIndexPREV", client -> ConfigFile.config().binding.activeConfigIndex -= 1); - createKeyMapping("activeConfigIndexRESET", client -> ConfigFile.config().binding.activeConfigIndex = 0); + createKeyMapping("toggleAdjustMode", _ -> ConfigFile.config().cycleAdjustMode()); + createKeyMapping("toggleCameraMode", _ -> ConfigFile.config().setClassic(!ConfigFile.config().isClassic())); + createKeyMapping("adjustFRONT", _ -> ConfigFile.config().adjustOffsetX(1)); + createKeyMapping("adjustBACK", _ -> ConfigFile.config().adjustOffsetX(-1)); + createKeyMapping("adjustUP", _ -> ConfigFile.config().adjustOffsetY(1)); + createKeyMapping("adjustDOWN", _ -> ConfigFile.config().adjustOffsetY(-1)); + createKeyMapping("adjustLEFT", _ -> ConfigFile.config().adjustOffsetZ(1)); + createKeyMapping("adjustRIGHT", _ -> ConfigFile.config().adjustOffsetZ(-1)); + createKeyMapping("activeConfigIndexNEXT", _ -> ConfigFile.config().binding.activeConfigIndex += 1); + createKeyMapping("activeConfigIndexPREV", _ -> ConfigFile.config().binding.activeConfigIndex -= 1); + createKeyMapping("activeConfigIndexRESET", _ -> ConfigFile.config().binding.activeConfigIndex = 0); } private static KeyMapping createKeyMapping(String id, Consumer whenPressed) { @@ -41,7 +42,7 @@ private static KeyMapping createKeyMapping(String id, Consumer whenPr } private static KeyMapping createKeyMapping(String id, int code, Consumer whenPressed) { - KeyMapping keyMapping = new KeyMapping("key." + RealCamera.FULL_ID + "." + id, code, LocUtil.KEY_MOD_NAME); + KeyMapping keyMapping = new KeyMapping("key." + RealCamera.FULL_ID + "." + id, code, GENERAL); KEY_MAPPINGS.put(keyMapping, whenPressed); return keyMapping; } diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index a860ecf3..18ad5f6e 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -1,25 +1,33 @@ package com.xtracr.realcamera; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import com.xtracr.realcamera.api.BindResult; import com.xtracr.realcamera.api.RealCameraAPI; import com.xtracr.realcamera.compat.DisableHelper; import com.xtracr.realcamera.config.BindTarget; import com.xtracr.realcamera.config.BindTarget.DisableConfig; import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.util.*; +import com.xtracr.realcamera.renderer.BuiltIterableBuffer; +import com.xtracr.realcamera.renderer.MultiVertexCatcher; +import com.xtracr.realcamera.renderer.RoutingSubmitCollector; +import com.xtracr.realcamera.renderer.state.VertexData; +import com.xtracr.realcamera.util.CameraTransform; +import com.xtracr.realcamera.util.LocUtil; +import com.xtracr.realcamera.util.MathUtil; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.util.Mth; +import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; +import org.joml.Matrix3f; import org.joml.Matrix4f; public class RealCameraCore { + private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); + private static final CameraTransform smoothedCamera = new CameraTransform(); private static BindResult lastResult = BindResult.EMPTY, newResult = BindResult.EMPTY; - private static Vec3 cameraPos = Vec3.ZERO, eulerAngle = Vec3.ZERO; private static boolean active = false, rendering = false; private static int failureFrames = 0; @@ -35,66 +43,47 @@ public static BindTarget currentTarget() { return lastResult.target; } - public static void initialize(Minecraft client) { + public static void initialize(Minecraft client, boolean renderLevel) { Entity entity = client.getCameraEntity(); - active = ConfigFile.config().enabled() && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); + active = renderLevel && ConfigFile.config().enabled() && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); rendering = ConfigFile.config().renderModel() && !DisableHelper.RENDER_MODEL.disabled(entity); } public static void reset() { - cameraPos = eulerAngle = Vec3.ZERO; + smoothedCamera.setPosition(Vec3.ZERO); + smoothedCamera.setRotation(new Matrix3f()); failureFrames = 0; } - public static float getPitch(float f) { - if (currentTarget().bindConfig().bindRotation()) return (float) eulerAngle.x(); - return f; - } - - public static float getYaw(float f) { - if (currentTarget().bindConfig().bindRotation()) return (float) -eulerAngle.y(); - return f; - } - - public static float getRoll(float f) { - if (ConfigFile.config().isClassic()) return f + ConfigFile.config().getClassicRoll(); - if (currentTarget().bindConfig().bindRotation()) return (float) eulerAngle.z(); - return f; - } - public static Vec3 getRawPos(Vec3 cameraPos, Vec3 entityPos) { - Vec3 rawPos = SmoothUtil.smoothPosition(lastResult.getPosition()).add(entityPos); + Vec3 rawPos = smoothedCamera.getPosition().add(entityPos); BindTarget.BindConfig bindConfig = currentTarget().bindConfig(); return new Vec3(bindConfig.bindX() ? rawPos.x() : cameraPos.x(), bindConfig.bindY() ? rawPos.y() : cameraPos.y(), bindConfig.bindZ() ? rawPos.z() : cameraPos.z()); } - public static Vec3 getCameraPos(Vec3 vec) { - BindTarget.BindConfig bindConfig = currentTarget().bindConfig(); - return new Vec3(bindConfig.bindX() ? cameraPos.x() : vec.x(), bindConfig.bindY() ? cameraPos.y() : vec.y(), bindConfig.bindZ() ? cameraPos.z() : vec.z()); - } - - public static void setCameraPos(Vec3 vec) { - cameraPos = vec; + public static Vec3 getEulerAngle(float pitch, float yaw, float roll) { + if (!currentTarget().bindConfig().bindRotation()) return new Vec3(pitch, yaw, roll); + double scale = Math.toDegrees(1); + return MathUtil.getEulerAngleYXZ(smoothedCamera.getRotation()).multiply(scale, -scale, scale); } - public static void computeCamera(Minecraft client, float deltaTick) { + public static void computeCamera(Minecraft client, float partialTicks) { Entity entity = client.getCameraEntity(); boolean invisible = entity.isInvisible(); entity.setInvisible(false); - newResult = RealCameraAPI.computeBindResult(client, deltaTick); + newResult = RealCameraAPI.computeBindResult(client, partialTicks); if (!newResult.available()) { EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); - MultiVertexCatcher catcher = MultiVertexCatcher.defaultImpl(); - dispatcher.render(entity, 0, 0, 0, Mth.lerp(deltaTick, entity.yRotO, entity.getYRot()), deltaTick, new PoseStack(), catcher, dispatcher.getPackedLightCoords(entity, deltaTick)); - catcher.endCatching(RealCameraCore::computeBindResult); + dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, new PoseStack(), vertexCatcher.initCollector()); + vertexCatcher.endCatching(RealCameraCore::computeBindResult); } entity.setInvisible(invisible); if (newResult.available()) { failureFrames = 0; - lastResult = newResult.computeCamera(); + lastResult = newResult.computeCamera(false); } else { failureFrames++; - Entity player = client.player; + Player player = client.player; int retentionFrames = ConfigFile.config().getBindResultRetentionFrames(); if (!ConfigFile.config().hideBindingFailureMessage() && failureFrames == retentionFrames + 1 && player != null) { player.sendSystemMessage(LocUtil.MESSAGE("bindingFailed", LocUtil.MOD_NAME(), LocUtil.MODEL_VIEW_TITLE(), KeyMappings.MODEL_VIEW_SCREEN.getTranslatedKeyMessage())); @@ -105,10 +94,11 @@ public static void computeCamera(Minecraft client, float deltaTick) { return; } } - eulerAngle = MathUtil.getEulerAngleYXZ(SmoothUtil.smoothRotation(lastResult.getRotation())).scale(Math.toDegrees(1)); + smoothedCamera.lerpPosition(lastResult.getPosition(), 1 - ConfigFile.config().getDisplacementSmoothFactor()); + smoothedCamera.slerpRotation(lastResult.getRotation(), 1 - ConfigFile.config().getRotationSmoothFactor()); } - public static void renderCameraEntity(Minecraft client, float deltaTick, MultiBufferSource bufferSource, Matrix4f modelView) { + public static void renderCameraEntity(Minecraft client, float partialTicks, SubmitNodeCollector submitNodeCollector, Matrix4f modelView) { Vec3 targetEulerAngle = MathUtil.getEulerAngleYXZ(lastResult.getRotation()); Matrix4f invertedCameraPose = new Matrix4f() .rotateZ((float) targetEulerAngle.z()) @@ -118,33 +108,33 @@ public static void renderCameraEntity(Minecraft client, float deltaTick, MultiBu .invert() .translate(Vec3.ZERO.subtract(lastResult.getPosition()).toVector3f()); PoseStack poseStack = new PoseStack(); - poseStack.mulPose(new Matrix4f(invertedCameraPose).mulLocal(modelView.invert(new Matrix4f()))); + poseStack.mulPose(modelView.invert(new Matrix4f())); + poseStack.mulPose(invertedCameraPose); Entity entity = client.getCameraEntity(); EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); - MultiVertexCatcher catcher = MultiVertexCatcher.defaultImpl(); - dispatcher.render(entity, 0, 0, 0, Mth.lerp(deltaTick, entity.yRotO, entity.getYRot()), deltaTick, poseStack, catcher, dispatcher.getPackedLightCoords(entity, deltaTick)); + SubmitNodeCollector collector = new RoutingSubmitCollector(submitNodeCollector, vertexCatcher.initCollector()); + dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, collector); final float m02 = modelView.m02(), m12 = modelView.m12(), m22 = modelView.m22(), m32 = modelView.m32(); final float depth = currentTarget().disablingDepth(); - catcher.endCatching(builtBuffer -> { + vertexCatcher.endCatching(builtBuffer -> { DisableConfig[] disableConfigs = currentTarget().filteredDisableConfigs(config -> builtBuffer.textureId().contains(config.textureId())); - for (DisableConfig config : disableConfigs) { - if (config.disableAll()) return; - } - VertexConsumer buffer = bufferSource.getBuffer(builtBuffer.renderType()); - if (!builtBuffer.renderType().canConsolidateConsecutiveGeometry()) { - for (VertexData vertex : builtBuffer.vertexBuffer()) vertex.render(buffer); - return; - } - builtBuffer.vertexBuffer().primitiveStream().forEach(primitive -> { - primitiveFor: - for (VertexData vertex : primitive) { - if (Math.fma(m02, vertex.x(), Math.fma(m12, vertex.y(), Math.fma(m22, vertex.z(), m32))) > -depth) continue; - for (DisableConfig config : disableConfigs) { - if (config.disable(vertex)) continue primitiveFor; - } - for (VertexData vertexData : primitive) vertexData.render(buffer); - break; + for (DisableConfig config : disableConfigs) if (config.disableAll()) return; + submitNodeCollector.submitCustomGeometry(poseStack, builtBuffer.renderType(), (_, buffer) -> { + if (!builtBuffer.renderType().canConsolidateConsecutiveGeometry()) { + for (VertexData vertex : builtBuffer.vertexBuffer()) vertex.render(buffer); + return; } + builtBuffer.vertexBuffer().primitiveStream().forEach(primitive -> { + primitiveFor: + for (VertexData vertex : primitive) { + if (Math.fma(m02, vertex.x(), Math.fma(m12, vertex.y(), Math.fma(m22, vertex.z(), m32))) > -depth) continue; + for (DisableConfig config : disableConfigs) { + if (config.disable(vertex)) continue primitiveFor; + } + for (VertexData vertexData : primitive) vertexData.render(buffer); + break; + } + }); }); }); } @@ -153,7 +143,7 @@ private static void computeBindResult(BuiltIterableBuffer builtBuffer) { if (newResult.available()) return; targetFor: for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = new BindResult(target, false); + BindResult result = new BindResult(target); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV[] uvs = {new VertexData.UV(config.posU(), config.posV()), new VertexData.UV(config.forwardU(), config.forwardV()), new VertexData.UV(config.upwardU(), config.upwardV())}; VertexData[][] primitives = builtBuffer.findPrimitivesInCache(uvs); diff --git a/common/src/main/java/com/xtracr/realcamera/api/BindResult.java b/common/src/main/java/com/xtracr/realcamera/api/BindResult.java index dd7bda3d..dd4051a2 100644 --- a/common/src/main/java/com/xtracr/realcamera/api/BindResult.java +++ b/common/src/main/java/com/xtracr/realcamera/api/BindResult.java @@ -2,22 +2,19 @@ import com.xtracr.realcamera.config.BindTarget; import com.xtracr.realcamera.config.ConfigFile; +import com.xtracr.realcamera.util.CameraTransform; import net.minecraft.world.phys.Vec3; -import org.joml.Matrix3f; import org.joml.Vector3f; import java.util.List; -public class BindResult { - public static final BindResult EMPTY = new BindResult(BindTarget.EMPTY, false); +public class BindResult extends CameraTransform { + public static final BindResult EMPTY = new BindResult(BindTarget.EMPTY); public final BindTarget target; - protected final Matrix3f rotation = new Matrix3f(); - protected final boolean mirrored; - private Vec3 position = Vec3.ZERO, forward = Vec3.ZERO, upward = Vec3.ZERO; + private Vec3 forward = Vec3.ZERO, upward = Vec3.ZERO; - public BindResult(BindTarget target, boolean mirrored) { + public BindResult(BindTarget target) { this.target = target; - this.mirrored = mirrored; } public static BindResult getOrCreate(String name) { @@ -30,7 +27,7 @@ public static BindResult getOrCreate(String name) { fixedTargets.add(blank); return blank; }); - return new BindResult(target, false); + return new BindResult(target); } public boolean available() { @@ -41,14 +38,6 @@ public boolean weakAvailable() { return !target.isEmpty() && (forward != Vec3.ZERO || upward != Vec3.ZERO || position != Vec3.ZERO) && Double.isFinite(position.lengthSqr()); } - public Vec3 getPosition() { - return position; - } - - public void setPosition(Vec3 vec) { - position = vec; - } - public Vec3 getForward() { return forward; } @@ -65,11 +54,7 @@ public void setUpward(Vec3 vec) { upward = vec.normalize(); } - public Matrix3f getRotation() { - return rotation; - } - - public BindResult computeCamera() { + public BindResult computeCamera(boolean mirrored) { if (!available()) return this; final int orientation = mirrored ? -1 : 1; upward = forward.cross(upward.cross(forward)).normalize(); diff --git a/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java b/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java index fb0c0ed4..c91225bb 100644 --- a/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java +++ b/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java @@ -22,9 +22,9 @@ public static void registerFunction(int priority, BiFunction PRIORITIES.get(b) - PRIORITIES.get(a)); } - public static BindResult computeBindResult(Minecraft client, float deltaTick) { + public static BindResult computeBindResult(Minecraft client, float partialTicks) { for (BiFunction function : FUNCTIONS) { - BindResult result = function.apply(client, deltaTick); + BindResult result = function.apply(client, partialTicks); if (result.available()) return result; } return BindResult.EMPTY; diff --git a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java index ecb8512f..5f481a36 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java @@ -1,10 +1,6 @@ package com.xtracr.realcamera.compat; import com.xtracr.realcamera.RealCamera; -import com.xtracr.realcamera.RealCameraCore; -import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.mixin.accessor.CameraAccessor; -import net.minecraft.client.Camera; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; @@ -26,7 +22,7 @@ public static void initialize(PlatformHelper platformHelper) { if (isModLoaded("freecam")) try { Class FC_Freecam = Class.forName("net.xolt.freecam.Freecam"); Method FC_Freecam_isEnabled = FC_Freecam.getDeclaredMethod("isEnabled"); - DisableHelper.MAIN_FEATURE.registerOr(player -> { + DisableHelper.MAIN_FEATURE.registerOr(_ -> { try { return (boolean) FC_Freecam_isEnabled.invoke(null); } catch (Exception ignored) { @@ -49,7 +45,7 @@ public static void initialize(PlatformHelper platformHelper) { Class SBW_ClientEventHandler = Class.forName("com.atsuishio.superbwarfare.event.ClientEventHandler"); SBW_ClientEventHandler_zoomTime = SBW_ClientEventHandler.getDeclaredField("zoomTime"); SBW_VehicleEntity = Class.forName("com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity"); - DisableHelper.MAIN_FEATURE.registerOrInBinding(player -> CompatibilityHelper.SBW_gunsIsZooming()); + DisableHelper.MAIN_FEATURE.registerOrInBinding(_ -> CompatibilityHelper.SBW_gunsIsZooming()); DisableHelper.MAIN_FEATURE.registerOrInBinding(CompatibilityHelper::SBW_isDrivingVehicle); } catch (Exception e) { RealCamera.LOGGER.warn("Compatibility with SuperbWarfare is outdated: [{}] {}", e.getClass().getName(), e.getMessage()); @@ -73,21 +69,15 @@ private static boolean SBW_isDrivingVehicle(Player player) { } } - public static void NEA_setDeltaTick(float deltaTick) { + public static void NEA_setDeltaTick(float partialTicks) { if (NEA_playerTransformer_setDeltaTick != null) try { Object INSTANCE = NEA_NEAnimationsLoader_INSTANCE.get(null); Object playerTransformer = NEA_NEAnimationsLoader_playerTransformer.get(INSTANCE); - NEA_playerTransformer_setDeltaTick.invoke(playerTransformer, deltaTick); + NEA_playerTransformer_setDeltaTick.invoke(playerTransformer, partialTicks); } catch (Exception ignored) { } } - public static void forceSetCameraPos(Camera camera) { - if (RealCameraCore.isActive() && !ConfigFile.config().isClassic()) { - ((CameraAccessor) camera).invokeSetPosition(RealCameraCore.getCameraPos(camera.getPosition())); - } - } - public static boolean isModLoaded(String modId) { return platformHelper.isModLoaded(modId); } diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index dd189ced..015ea304 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -3,7 +3,7 @@ import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.config.ConfigFile; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; @@ -15,19 +15,20 @@ import java.util.function.Predicate; public class DisableHelper { - private static final Predicate FALSE = player -> false; + public static final Entry MAIN_FEATURE, RENDER_MODEL, RENDER_HANDS; + private static final Predicate FALSE = _ -> false; private static final Map entries = new HashMap<>(); - public static final Entry MAIN_FEATURE = new Entry("mainFeature", player -> player.isSleeping() || player.isSpectator()); - public static final Entry RENDER_MODEL = new Entry("renderModel", FALSE, Player::isScoping); - public static final Entry RENDER_HANDS = new Entry("renderHands", player -> RealCameraCore.isRendering()); public static int exitTick = 0; static { + MAIN_FEATURE = new Entry("mainFeature", player -> player.isSleeping() || player.isSpectator()); + RENDER_MODEL = new Entry("renderModel", FALSE, Player::isScoping); + RENDER_HANDS = new Entry("renderHands", _ -> RealCameraCore.isRendering()); MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSneaking() && player.isCrouching()); MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSneaking() && player.isCrouching()); MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSwimming() && checkCondition(player, player.isSwimming(), ConfigFile.config().getBindingOutTick())); MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSwimming() && checkCondition(player, player.isSwimming(), ConfigFile.config().getClassicOutTick())); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenCrawling() && checkCondition(player, player.isVisuallyCrawling(), ConfigFile.config().getBindingOutTick())); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenCrawling() && checkCondition(player, player.isVisuallyCrawling(), ConfigFile.config().getBindingOutTick())); MAIN_FEATURE.registerOrInBinding(player -> { Item mainHand = player.getMainHandItem().getItem(); Item offHand = player.getOffhandItem().getItem(); @@ -69,10 +70,10 @@ public static void registerOr(String name, Predicate predicate) { public static boolean matchesItemPattern(Item item, String pattern) { if (pattern.startsWith("#")) { String tagId = pattern.substring(1); - TagKey itemTag = TagKey.create(BuiltInRegistries.ITEM.key(), ResourceLocation.parse(tagId)); - return BuiltInRegistries.ITEM.getTag(itemTag) - .map(tag -> tag.contains(BuiltInRegistries.ITEM.wrapAsHolder(item))) - .orElse(false); + TagKey itemTag = TagKey.create(BuiltInRegistries.ITEM.key(), Identifier.parse(tagId)); + return BuiltInRegistries.ITEM.get(itemTag) + .map(tag -> tag.contains(BuiltInRegistries.ITEM.wrapAsHolder(item))) + .orElse(false); } return simpleWildcardMatch(BuiltInRegistries.ITEM.getKey(item).toString(), pattern); } diff --git a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java index a0575ab8..e12c664f 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java @@ -4,15 +4,12 @@ import com.xtracr.realcamera.api.BindResult; import com.xtracr.realcamera.api.RealCameraAPI; import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.mixin.accessor.PlayerRendererAccessor; +import com.xtracr.realcamera.mixin.accessor.AvatarRendererAccessor; import net.minecraft.client.Minecraft; -import net.minecraft.client.model.PlayerModel; import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.renderer.entity.LivingEntityRenderer; -import net.minecraft.client.renderer.entity.player.PlayerRenderer; +import net.minecraft.client.renderer.entity.player.AvatarRenderer; +import net.minecraft.client.renderer.entity.state.AvatarRenderState; import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Pose; import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; @@ -23,79 +20,35 @@ public static void register() { RealCameraAPI.registerFunction(100, LegacyBindingMode::computeBindResult); } - private static BindResult computeBindResult(Minecraft client, float deltaTick) { + @SuppressWarnings("unchecked") + private static BindResult computeBindResult(Minecraft client, float partialTicks) { if (!ConfigFile.config().legacyBindingMode()) return BindResult.EMPTY; PoseStack poseStack = new PoseStack(); AbstractClientPlayer player = client.player; // WorldRenderer.render // EntityRenderDispatcher.render - PlayerRenderer playerRenderer = (PlayerRenderer) client.getEntityRenderDispatcher().getRenderer(player); - Vec3 renderOffset = playerRenderer.getRenderOffset(player, deltaTick); + AvatarRenderer playerRenderer = (AvatarRenderer) client.getEntityRenderDispatcher().getRenderer(player); + AvatarRenderState renderState = playerRenderer.createRenderState(player, partialTicks); + Vec3 renderOffset = playerRenderer.getRenderOffset(renderState); poseStack.translate(renderOffset.x(), renderOffset.y(), renderOffset.z()); - // PlayerEntityRenderer.render - ((PlayerRendererAccessor) playerRenderer).invokeSetModelProperties(player); // LivingEntityRenderer.render - PlayerModel playerModel = playerRenderer.getModel(); - playerModel.attackTime = player.getAttackAnim(deltaTick); - playerModel.riding = player.isPassenger(); - playerModel.young = player.isBaby(); - float h = Mth.rotLerp(deltaTick, player.yBodyRotO, player.yBodyRot); - float j = Mth.rotLerp(deltaTick, player.yHeadRotO, player.yHeadRot); - float k = j - h; - if (player.isPassenger() && player.getVehicle() instanceof LivingEntity livingEntity) { - h = Mth.rotLerp(deltaTick, livingEntity.yBodyRotO, livingEntity.yBodyRot); - k = j - h; - float l = Mth.wrapDegrees(k); - if (l < -85.0F) { - l = -85.0F; - } - if (l >= 85.0F) { - l = 85.0F; - } - h = j - l; - if (l * l > 2500.0F) { - h += l * 0.2F; - } - k = j - h; - } - float m = Mth.lerp(deltaTick, player.xRotO, player.getXRot()); - if (LivingEntityRenderer.isEntityUpsideDown(player)) { - m *= -1.0F; - k *= -1.0F; - } - k = Mth.wrapDegrees(k); - if (player.hasPose(Pose.SLEEPING)) { - Direction direction = player.getBedOrientation(); + if (renderState.hasPose(Pose.SLEEPING)) { + Direction direction = renderState.bedOrientation; if (direction != null) { - float n = player.getEyeHeight(Pose.STANDING) - 0.1F; - poseStack.translate((float)(-direction.getStepX()) * n, 0.0F, (float)(-direction.getStepZ()) * n); - } - } - float lx = player.getScale(); - poseStack.scale(lx, lx, lx); - float n = player.tickCount + deltaTick; - ((PlayerRendererAccessor) playerRenderer).invokeSetupRotations(player, poseStack, n, h, deltaTick, lx); - poseStack.scale(-1.0F, -1.0F, 1.0F); - ((PlayerRendererAccessor) playerRenderer).invokeScale(player, poseStack, deltaTick); - poseStack.translate(0.0F, -1.501F, 0.0F); - float o = 0.0F; - float p = 0.0F; - if (!player.isPassenger() && player.isAlive()) { - o = player.walkAnimation.speed(deltaTick); - p = player.walkAnimation.position(deltaTick); - if (player.isBaby()) { - p *= 3.0F; - } - - if (o > 1.0F) { - o = 1.0F; + float f = renderState.eyeHeight - 0.1f; + poseStack.translate((float) (-direction.getStepX()) * f, 0.0f, (float) (-direction.getStepZ()) * f); } } - playerModel.prepareMobModel(player, p, o, deltaTick); - playerModel.setupAnim(player, p, o, n, k, m); + float scale = renderState.scale; + poseStack.scale(scale, scale, scale); + ((AvatarRendererAccessor) playerRenderer).invokeSetupRotations(renderState, poseStack, renderState.bodyRot, scale); + poseStack.scale(-1.0f, -1.0f, 1.0f); + ((AvatarRendererAccessor) playerRenderer).invokeScale(renderState, poseStack); + poseStack.translate(0.0f, -1.501f, 0.0f); + playerRenderer.getModel().setupAnim(renderState); // AnimalModel.render // ModelPart.render - playerModel.head.translateAndRotate(poseStack); + playerRenderer.getModel().head.translateAndRotate(poseStack); Vector4f offset = poseStack.last().pose().transform(new Vector4f(0, -0.125f, -0.2f, 1.0f)); BindResult result = BindResult.getOrCreate("LEGACY_MODE"); diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index 4a9822dc..1a2d846c 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -5,12 +5,12 @@ import com.xtracr.realcamera.api.RealCameraAPI; import com.xtracr.realcamera.config.BindTarget; import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.util.BuiltIterableBuffer; -import com.xtracr.realcamera.util.MultiVertexCatcher; -import com.xtracr.realcamera.util.VertexData; +import com.xtracr.realcamera.renderer.BuiltIterableBuffer; +import com.xtracr.realcamera.renderer.MultiVertexCatcher; +import com.xtracr.realcamera.renderer.state.VertexData; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.util.Mth; +import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import org.joml.Matrix3f; @@ -20,12 +20,13 @@ import java.util.Map; public class YSMCompat { + private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final Map resultMap = new HashMap<>(); private static final TransformedVertexRecorder[] transformedRecorders = new TransformedVertexRecorder[4]; private static BindResult bindResult = BindResult.EMPTY; private static boolean allCached = false; - static { + static { final float pitch = 1.9106332f, yaw = 2.0943951f; transformedRecorders[0] = new TransformedVertexRecorder(); transformedRecorders[1] = new TransformedVertexRecorder().setRotation(pitch, 0); @@ -37,7 +38,7 @@ public static void register() { RealCameraAPI.registerFunction(-100, YSMCompat::computeBindResult); } - private static BindResult computeBindResult(Minecraft client, float deltaTick) { + private static BindResult computeBindResult(Minecraft client, float partialTicks) { resultMap.clear(); bindResult = BindResult.EMPTY; allCached = true; @@ -47,9 +48,8 @@ private static BindResult computeBindResult(Minecraft client, float deltaTick) { for (TransformedVertexRecorder transformedRecorder : transformedRecorders) { poseStack.pushPose(); poseStack.mulPose(transformedRecorder.matrix4f.invert(new Matrix4f())); - MultiVertexCatcher catcher = MultiVertexCatcher.defaultImpl(); - dispatcher.render(entity, 0, 0, 0, Mth.lerp(deltaTick, entity.yRotO, entity.getYRot()), deltaTick, poseStack, catcher, dispatcher.getPackedLightCoords(entity, deltaTick)); - catcher.endCatching(transformedRecorder::computeBindResultInCache); + dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); + vertexCatcher.endCatching(transformedRecorder::computeBindResultInCache); poseStack.popPose(); if (bindResult.available()) return bindResult; } @@ -57,9 +57,8 @@ private static BindResult computeBindResult(Minecraft client, float deltaTick) { for (TransformedVertexRecorder transformedRecorder : transformedRecorders) { poseStack.pushPose(); poseStack.mulPose(transformedRecorder.matrix4f.invert(new Matrix4f())); - MultiVertexCatcher catcher = MultiVertexCatcher.defaultImpl(); - dispatcher.render(entity, 0, 0, 0, Mth.lerp(deltaTick, entity.yRotO, entity.getYRot()), deltaTick, poseStack, catcher, dispatcher.getPackedLightCoords(entity, deltaTick)); - catcher.endCatching(transformedRecorder::computeBindResult); + dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); + vertexCatcher.endCatching(transformedRecorder::computeBindResult); poseStack.popPose(); if (bindResult.available()) return bindResult; } @@ -79,7 +78,7 @@ public TransformedVertexRecorder setRotation(float pitch, float yaw) { public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = resultMap.computeIfAbsent(target, k -> new BindResult(target, false)); + BindResult result = resultMap.computeIfAbsent(target, _ -> new BindResult(target)); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = new VertexData.UV(config.posU(), config.posV()); VertexData.UV forwardUV = new VertexData.UV(config.forwardU(), config.forwardV()); @@ -101,7 +100,7 @@ public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { public void computeBindResult(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = resultMap.computeIfAbsent(target, k -> new BindResult(target, false)); + BindResult result = resultMap.computeIfAbsent(target, _ -> new BindResult(target)); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = result.getPosition() == Vec3.ZERO ? new VertexData.UV(config.posU(), config.posV()) : null; VertexData.UV forwardUV = result.getForward() == Vec3.ZERO ? new VertexData.UV(config.forwardU(), config.forwardV()) : null; diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index 290bae3f..3f5dc027 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -4,7 +4,7 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; -import com.xtracr.realcamera.util.VertexData; +import com.xtracr.realcamera.renderer.state.VertexData; import it.unimi.dsi.fastutil.floats.Float2ObjectOpenHashMap; import it.unimi.dsi.fastutil.floats.FloatOpenHashSet; import net.minecraft.network.FriendlyByteBuf; @@ -24,7 +24,7 @@ public record BindTarget( DisableConfig[] disableConfigs) { public static final List defaultTargets; public static final BindTarget EMPTY = blank(null, null); - private static final short serialVersion = 703; + private static final short serialVersion = 703; // 0.7.3 static { defaultTargets = List.of( @@ -43,7 +43,8 @@ public static BindTarget blank(String name, String textureId) { public static BindTarget read(FriendlyByteBuf byteBuf) throws IllegalArgumentException { short version = byteBuf.readShort(); - if (version != serialVersion) throw new IllegalArgumentException("Invalid version: " + version + ", expected " + serialVersion); + if (version != serialVersion) + throw new IllegalArgumentException("Invalid version: " + version + ", expected " + serialVersion); String name = byteBuf.readUtf(); String textureId = byteBuf.readUtf(); int priority = byteBuf.readVarInt(); @@ -66,7 +67,7 @@ private static BindTarget vanillaTarget(String name, int priority, boolean shoul DisableConfig playerHead = new DisableConfig("player_head", textureId, false, new UVRectangle[]{new UVRectangle(0, 0, 1.0f, 0.25f)}); DisableConfig dragonHead = new DisableConfig("dragon_head", "minecraft:textures/entity/enderdragon/dragon.png", true, new UVRectangle[0]); DisableConfig[] disableConfigs = new DisableConfig[]{playerHead, dragonHead}; - return new BindTarget(name, textureId, priority, 0.1f, targetConfig, bindConfig, offsets, disableConfigs); + return new BindTarget(name, textureId, priority, 0.2f, targetConfig, bindConfig, offsets, disableConfigs); } public boolean isEmpty() { @@ -270,10 +271,10 @@ public boolean disable(VertexData vertex) { } for (UVRectangle rect : rectangles) { if (!rect.contains(u, v)) continue; - disableCacheMap.computeIfAbsent(u, k -> new FloatOpenHashSet()).add(v); + disableCacheMap.computeIfAbsent(u, _ -> new FloatOpenHashSet()).add(v); return true; } - disableCacheMap.computeIfAbsent(u, k -> new FloatOpenHashSet()).add(-v); + disableCacheMap.computeIfAbsent(u, _ -> new FloatOpenHashSet()).add(-v); return false; } diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 5c5a5859..1a56ded3 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -192,36 +192,37 @@ public static Screen create(Screen parent) { .setSaveConsumer(d -> config.binding.rotationSmoothFactor = d) .build()); SubCategoryBuilder disableConfig = entryBuilder.startSubCategory(LocUtil.CONFIG_OPTION("disableConfig")); - disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSneaking"), config.binding.disableWhenSneaking) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenSneaking = b) - .build()); - disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenCrawling"), config.binding.disableWhenCrawling) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenCrawling = b) - .build()); - disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSwimming"), config.binding.disableWhenSwimming) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenSwimming = b) - .build()); - disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("outTick"), config.binding.outTick) - .setDefaultValue(13) - .setMin(0) - .setMax(40) - .setTooltip(LocUtil.CONFIG_TOOLTIP("outTick")) - .setSaveConsumer(i -> config.binding.outTick = i) - .build()); - disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) - .setDefaultValue(List.of()) - .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) - .setSaveConsumer(l -> config.binding.disableMainFeatureItems = l) - .build()); - disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableRenderItems"), config.binding.disableRenderItems) - .setDefaultValue(ModConfig.Binding.defaultDisableRenderItems) - .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) - .setSaveConsumer(l -> config.binding.disableRenderItems = l) - .build()); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSneaking"), config.binding.disableWhenSneaking) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenSneaking = b) + .build()); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenCrawling"), config.binding.disableWhenCrawling) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenCrawling = b) + .build()); + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSwimming"), config.binding.disableWhenSwimming) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenSwimming = b) + .build()); + disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("outTick"), config.binding.outTick) + .setDefaultValue(13) + .setMin(0) + .setMax(40) + .setTooltip(LocUtil.CONFIG_TOOLTIP("outTick")) + .setSaveConsumer(i -> config.binding.outTick = i) + .build()); + disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) + .setDefaultValue(List.of()) + .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) + .setSaveConsumer(l -> config.binding.disableMainFeatureItems = l) + .build()); + disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableRenderItems"), config.binding.disableRenderItems) + .setDefaultValue(ModConfig.Binding.defaultDisableRenderItems) + .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) + .setSaveConsumer(l -> config.binding.disableRenderItems = l) + .build()); binding.addEntry(disableConfig.build()); + return builder.build(); } } \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index c6b2f490..50c64ae3 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -177,7 +177,7 @@ public boolean hideBindingFailureMessage() { } public boolean bindingDisableWhenCrawling() { - return binding.disableWhenCrawling; + return binding.disableWhenCrawling; } public boolean bindingDisableWhenSneaking() { diff --git a/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java b/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java deleted file mode 100644 index a10c17bf..00000000 --- a/common/src/main/java/com/xtracr/realcamera/gui/CyclingTexturedButton.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.xtracr.realcamera.gui; - -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.AbstractButton; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.CommonComponents; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.Nullable; - -import java.util.function.IntConsumer; - -public class CyclingTexturedButton extends AbstractButton { - protected final ResourceLocation texture; - protected final int textureWidth, textureHeight, u, v, vOffset, size; - @Nullable - private IntConsumer onValueChange; - private int value; - - public CyclingTexturedButton(int u, int v, int value, int size) { - this(0, 0, 16, 16, u, v, value, size); - } - - public CyclingTexturedButton(int x, int y, int width, int height, int u, int v, int value, int size) { - this(x, y, width, height, u, v, height, value, size, TexturedButton.ICON_TEXTURE, 256, 256); - } - - public CyclingTexturedButton(int x, int y, int width, int height, int u, int v, int vOffset, int value, int size, ResourceLocation texture, int textureWidth, int textureHeight) { - super(x, y, width, height, CommonComponents.EMPTY); - this.u = u; - this.v = v; - this.vOffset = vOffset; - this.size = size; - this.texture = texture; - this.textureWidth = textureWidth; - this.textureHeight = textureHeight; - setValue(value); - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = (value % size + size) % size; - } - - public CyclingTexturedButton setOnValueChange(IntConsumer onValueChange) { - this.onValueChange = onValueChange; - return this; - } - - @Override - public void onPress() { - if (Screen.hasShiftDown()) setValue(value - 1); - else setValue(value + 1); - if (onValueChange != null) onValueChange.accept(value); - } - - @Override - public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { - graphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0xFF646464); - graphics.blit(texture, getX(), getY(), u, v + value * vOffset, width, height, textureWidth, textureHeight); - if (isHoveredOrFocused()) graphics.renderOutline(getX(), getY(), getWidth(), getHeight(), 0xFFFFFFFF); - } - - @Override - protected void updateWidgetNarration(NarrationElementOutput builder) { - defaultButtonNarrationText(builder); - } -} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java index 8f7a8817..b31c9878 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java @@ -1,60 +1,76 @@ package com.xtracr.realcamera.gui; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.xtracr.realcamera.util.VertexData; -import net.minecraft.client.gui.GuiGraphics; +import com.xtracr.realcamera.mixin.accessor.GuiGraphicsExtractorAccessor; +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; +import com.xtracr.realcamera.renderer.state.VertexData; +import com.xtracr.realcamera.renderer.state.gui.*; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.navigation.ScreenRectangle; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.world.phys.Vec3; +import org.joml.Matrix3x2f; import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.jspecify.annotations.Nullable; + +import java.util.List; public class GUIHelper { - public static void enableScissor(GuiGraphics graphics, ScreenRectangle rectangle) { + @Nullable + public static ScreenRectangle getBounds(int x0, int y0, int x1, int y1, Matrix3x2f pose, @Nullable ScreenRectangle scissorArea) { + ScreenRectangle scissorArea2 = new ScreenRectangle(x0, y0, x1 - x0, y1 - y0).transformMaxBounds(pose); + return scissorArea != null ? scissorArea.intersection(scissorArea2) : scissorArea2; + } + + public static void enableScissor(GuiGraphicsExtractor graphics, ScreenRectangle rectangle) { graphics.enableScissor(rectangle.left(), rectangle.top(), rectangle.right(), rectangle.bottom()); } - public static void fill(GuiGraphics graphics, float x0, float y0, float x1, float y1, int argb) { + public static void fill(GuiGraphicsExtractor graphics, float x0, float y0, float x1, float y1, int argb) { fill(graphics, x0, y0, x1, y1, 0, argb); } - public static void fill(GuiGraphics graphics, float x0, float y0, float x1, float y1, float z, int argb) { - Matrix4f matrix4f = graphics.pose().last().pose(); - if (x0 < x1) { - float o = x0; - x0 = x1; - x1 = o; - } - if (y0 < y1) { - float o = y0; - y0 = y1; - y1 = o; - } - VertexConsumer buffer = graphics.bufferSource().getBuffer(RenderType.gui()); - buffer.addVertex(matrix4f, x0, y0, z).setColor(argb); - buffer.addVertex(matrix4f, x0, y1, z).setColor(argb); - buffer.addVertex(matrix4f, x1, y1, z).setColor(argb); - buffer.addVertex(matrix4f, x1, y0, z).setColor(argb); - graphics.flush(); - } - - public static void renderOutline(GuiGraphics graphics, float x, float y, float width, float height, int argb) { + public static void fill(GuiGraphicsExtractor graphics, float x0, float y0, float x1, float y1, float z, int argb) { + ((GuiGraphicsExtractorAccessor) graphics).getGuiRenderState().addGuiElement(new ColoredFloatRectangleRenderState( + RenderPipelines.GUI, TextureSetup.noTexture(), new Matrix3x2f(graphics.pose()), + x0, y0, x1, y1, z, argb, ((GuiGraphicsExtractorAccessor) graphics).getScissorStack().peek())); + } + + public static void outline(GuiGraphicsExtractor graphics, float x, float y, float width, float height, int argb) { fill(graphics, x, y, x + width, y + 1, argb); fill(graphics, x, y + height - 1, x + width, y + height, argb); fill(graphics, x, y + 1, x + 1, y + height - 1, argb); fill(graphics, x + width - 1, y + 1, x + width, y + height - 1, argb); } - public static void renderPolygon(GuiGraphics graphics, VertexData[] polygon, float z, int argb) { - VertexConsumer buffer = graphics.bufferSource().getBuffer(RenderType.gui()); - for (VertexData vertex : polygon) buffer.addVertex(vertex.x(), vertex.y(), z).setColor(argb); - if (polygon.length == 3) buffer.addVertex(polygon[2].x(), polygon[2].y(), z).setColor(argb); - graphics.flush(); + public static void polygon(GuiGraphicsExtractor graphics, VertexData[] polygon, float z, int argb) { + if (polygon.length < 3) return; + float x0 = polygon[0].x(), y0 = polygon[0].y(); + float x1 = polygon[1].x(), y1 = polygon[1].y(); + float x2 = polygon[2].x(), y2 = polygon[2].y(); + float x3 = polygon.length > 3 ? polygon[3].x() : x2, y3 = polygon.length > 3 ? polygon[3].y() : y2; + ((GuiGraphicsExtractorAccessor) graphics).getGuiRenderState().addGuiElement(new ColoredFloatQuadRenderState( + RenderPipelines.GUI, TextureSetup.noTexture(), new Matrix3x2f(graphics.pose()), + x0, y0, z, x1, y1, z, x2, y2, z, x3, y3, z, argb, ((GuiGraphicsExtractorAccessor) graphics).getScissorStack().peek())); + } + + public static void vector(GuiGraphicsExtractor graphics, Vec3 start, Vec3 vector, float z, int argb) { + ((GuiGraphicsExtractorAccessor) graphics).getGuiRenderState().addGuiElement(new ColoredFloatLineRenderState( + RenderPipelines.GUI, TextureSetup.noTexture(), new Matrix3x2f(graphics.pose()), + (float) start.x(), (float) start.y(), z, + (float) vector.x(), (float) vector.y(), 0, argb, ((GuiGraphicsExtractorAccessor) graphics).getScissorStack().peek())); + } + + public static void culledModels(GuiGraphicsExtractor graphics, List records, float scale, Matrix4f transform, int x0, int y0, int x1, int y1) { + ((GuiGraphicsExtractorAccessor) graphics).getGuiRenderState().addPicturesInPictureState( + new GuiCulledModelsRenderState(records, transform, x0, y0, x1, y1, scale, ((GuiGraphicsExtractorAccessor) graphics).getScissorStack().peek()) + ); } - public static void renderVector(GuiGraphics graphics, Vec3 start, Vec3 vector, float z, int argb) { - VertexConsumer buffer = graphics.bufferSource().getBuffer(RenderType.lines()); - buffer.addVertex((float) start.x, (float) start.y, z).setColor(argb).setNormal((float) vector.x, (float) vector.y, 0); - buffer.addVertex((float) (start.x + vector.x), (float) (start.y + vector.y), z).setColor(argb).setNormal((float) vector.x, (float) vector.y, 0); - graphics.flush(); + public static void flattenedModels(GuiGraphicsExtractor graphics, List records, Vector3f translation, int x0, int y0, int x1, int y1, float scale) { + ((GuiGraphicsExtractorAccessor) graphics).getGuiRenderState().addPicturesInPictureState( + new GuiFlattenedModelsRenderState(records, translation, x0, y0, x1, y1, scale, ((GuiGraphicsExtractorAccessor) graphics).getScissorStack().peek()) + ); } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 151d8bec..8d3b98f7 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -2,25 +2,27 @@ import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexFormat; import com.xtracr.realcamera.api.BindResult; import com.xtracr.realcamera.config.BindTarget; import com.xtracr.realcamera.config.BindTarget.DisableConfig; import com.xtracr.realcamera.config.BindTarget.TargetConfig; -import com.xtracr.realcamera.util.BuiltIterableBuffer; -import com.xtracr.realcamera.util.MultiVertexCatcher; -import com.xtracr.realcamera.util.VertexData; +import com.xtracr.realcamera.renderer.BuiltIterableBuffer; +import com.xtracr.realcamera.renderer.MultiVertexCatcher; +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; +import com.xtracr.realcamera.renderer.state.VertexData; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.rendertype.RenderTypes; +import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3f; +import org.jspecify.annotations.Nullable; import java.awt.*; import java.util.ArrayList; @@ -29,23 +31,27 @@ import java.util.Set; public class ModelAnalyser { - private static final Set UNFOCUSABLE_RENDER_TYPES = Set.of(RenderType.armorEntityGlint(), RenderType.glintTranslucent(), RenderType.glint(), RenderType.entityGlint(), RenderType.entityGlintDirect()); + private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); + private static final Set UNFOCUSABLE_RENDER_TYPES = Set.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; private static final int z1 = 210, z2 = z1 + 10; public final List focusedPolyhedron = new ArrayList<>(); public final PoseStack modelPose = new PoseStack(), texturePose = new PoseStack(); - private final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); + protected final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; private BindTarget target = BindTarget.EMPTY; @Nullable - private BuiltRecord focusedRecord, currentRecord; + private BuiltModelRecord focusedRecord, currentRecord; private double modelScale; private static boolean haveCommonVertex(VertexData[] p1, List primitives) { final float precision = 1e-5f; - for (VertexData[] p2 : primitives) for (VertexData v1 : p1) for (VertexData v2 : p2) - if (Math.abs(v1.x() - v2.x()) < precision && Math.abs(v1.y() - v2.y()) < precision && Math.abs(v1.z() - v2.z()) < precision) return true; + for (VertexData[] p2 : primitives) + for (VertexData v1 : p1) + for (VertexData v2 : p2) + if (Math.abs(v1.x() - v2.x()) < precision && Math.abs(v1.y() - v2.y()) < precision && Math.abs(v1.z() - v2.z()) < precision) + return true; return false; } @@ -79,15 +85,14 @@ public String getFocusedTextureId() { } public void applyDisableConfigs(String textureId, Set hiddenNames) { - for (BuiltRecord record : modelRecords) { - if (!record.textureId().contains(textureId)) continue; - textureRecords.add(record); + for (BuiltModelRecord record : modelRecords) { + if (record.containsTextureId(textureId)) textureRecords.add(record); } for (int i = 0; i < modelRecords.size(); i++) { - BuiltRecord record = modelRecords.get(i); + BuiltModelRecord record = modelRecords.get(i); List primitives = new ArrayList<>(); - DisableConfig[] disableConfigs = target.filteredDisableConfigs(config -> record.textureId().contains(config.textureId()) && hiddenNames.contains(config.name())); - boolean disableAll = !record.textureId().contains(textureId); + DisableConfig[] disableConfigs = target.filteredDisableConfigs(config -> record.containsTextureId(config.textureId()) && hiddenNames.contains(config.name())); + boolean disableAll = !record.containsTextureId(textureId); for (DisableConfig config : disableConfigs) { if (config.disableAll()) { disableAll = true; @@ -104,7 +109,7 @@ public void applyDisableConfigs(String textureId, Set hiddenNames) { break; } } - modelRecords.set(i, new BuiltRecord(record.renderType(), record.textureId(), record.vertices(), primitives.toArray(new VertexData[0][]))); + modelRecords.set(i, new BuiltModelRecord(record.renderType(), record.textureId(), record.vertices(), primitives.toArray(new VertexData[0][]))); } } @@ -112,7 +117,7 @@ public void computeFocusedOnTexture(int mouseX, int mouseY) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; Matrix4f positionMatrix = texturePose.last().pose(); Vector3f position = new Vector3f(); - for (BuiltRecord record : textureRecords) { + for (BuiltModelRecord record : textureRecords) { int length = record.renderType().mode().primitiveLength; int[] xs = new int[length], ys = new int[length]; for (VertexData[] primitive : record.primitives()) { @@ -134,7 +139,7 @@ public void computeFocusedOnTexture(int mouseX, int mouseY) { public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; List sortByZ = new ArrayList<>(); - for (BuiltRecord record : modelRecords) { + for (BuiltModelRecord record : modelRecords) { if (UNFOCUSABLE_RENDER_TYPES.contains(record.renderType())) continue; VertexData[][] primitives = record.primitives(); for (VertexData[] primitive : primitives) { @@ -147,14 +152,14 @@ public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { if (sortByZ.isEmpty()) return; sortByZ.sort(Comparator.comparingDouble(array -> -(float) array[2])); Object[] result = sortByZ.get(Math.min(sortByZ.size() - 1, layers)); - focusedRecord = (BuiltRecord) result[0]; + focusedRecord = (BuiltModelRecord) result[0]; focusedPolyhedron.add((VertexData[]) result[1]); } public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; List sortByZ = new ArrayList<>(); - for (BuiltRecord record : modelRecords) { + for (BuiltModelRecord record : modelRecords) { if (UNFOCUSABLE_RENDER_TYPES.contains(record.renderType())) continue; VertexData[][] primitives = record.primitives(); primitiveFor: @@ -171,7 +176,7 @@ public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { if (sortByZ.isEmpty()) return; sortByZ.sort(Comparator.comparingDouble(array -> -(float) array[2])); List polygons = new ArrayList<>(); - focusedRecord = (BuiltRecord) sortByZ.getFirst()[0]; + focusedRecord = (BuiltModelRecord) sortByZ.getFirst()[0]; while (!sortByZ.isEmpty()) { VertexData[] first = (VertexData[]) sortByZ.getFirst()[1]; focusedPolyhedron.add(first); @@ -182,7 +187,8 @@ public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { VertexData[] primitive = (VertexData[]) array[1]; primitiveFor: for (VertexData vertex : primitive) { - for (Polygon polygon : polygons) if (polygon.contains(vertex.x(), vertex.y())) continue primitiveFor; + for (Polygon polygon : polygons) + if (polygon.contains(vertex.x(), vertex.y())) continue primitiveFor; return false; } return true; @@ -229,34 +235,34 @@ public void computeFocusedPolyhedron() { resultIndexes.forEach(i -> focusedPolyhedron.add(primitives[i])); } - public void drawCameraDirections(GuiGraphics graphics) { + public void drawCameraDirections(GuiGraphicsExtractor graphics) { if (targetPrimitives[0] == null || targetPrimitives[1] == null || targetPrimitives[2] == null) return; Vec3 start = bindResult.getPosition(); Matrix3f normal = bindResult.getRotation(); if (normal.m00() == 0 && normal.m11() == 0 && normal.m22() == 0) return; - GUIHelper.renderVector(graphics, start, new Vec3(normal.m20(), normal.m21(), normal.m22()).scale(modelScale / 3), z2, forwardArgb); - GUIHelper.renderVector(graphics, start, new Vec3(normal.m10(), normal.m11(), normal.m12()).scale(modelScale / 6), z2, upwardArgb); - GUIHelper.renderVector(graphics, start, new Vec3(normal.m00(), normal.m01(), normal.m02()).scale(modelScale / 6), z2, leftArgb); + GUIHelper.vector(graphics, start, new Vec3(normal.m20(), normal.m21(), normal.m22()).scale(modelScale / 3), z2, forwardArgb); + GUIHelper.vector(graphics, start, new Vec3(normal.m10(), normal.m11(), normal.m12()).scale(modelScale / 6), z2, upwardArgb); + GUIHelper.vector(graphics, start, new Vec3(normal.m00(), normal.m01(), normal.m02()).scale(modelScale / 6), z2, leftArgb); } - public void drawBindTarget(GuiGraphics graphics) { + public void drawBindTarget(GuiGraphicsExtractor graphics) { if (currentRecord == null) return; TargetConfig config = target.targetConfig(); - if (targetPrimitives[0] != null) GUIHelper.renderPolygon(graphics, targetPrimitives[0], z1, planeArgb); - if (targetPrimitives[1] != null) GUIHelper.renderVector(graphics, VertexData.position(targetPrimitives[1], config.forwardU(), config.forwardV()), VertexData.normal(targetPrimitives[1]).scale(-modelScale / 2), z2, forwardArgb); - if (targetPrimitives[2] != null) GUIHelper.renderVector(graphics, VertexData.position(targetPrimitives[2], config.upwardU(), config.upwardV()), VertexData.normal(targetPrimitives[2]).scale(-modelScale / 2), z2, upwardArgb); + if (targetPrimitives[0] != null) GUIHelper.polygon(graphics, targetPrimitives[0], z1, planeArgb); + if (targetPrimitives[1] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[1], config.forwardU(), config.forwardV()), VertexData.normal(targetPrimitives[1]).scale(-modelScale / 2), z2, forwardArgb); + if (targetPrimitives[2] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[2], config.upwardU(), config.upwardV()), VertexData.normal(targetPrimitives[2]).scale(-modelScale / 2), z2, upwardArgb); } - public void drawFocusedInModelArea(GuiGraphics graphics) { + public void drawFocusedInModelArea(GuiGraphicsExtractor graphics) { if (focusedPolyhedron.isEmpty() || focusedRecord == null) return; VertexData[] focused = focusedPolyhedron.getFirst(); VertexData[] reversed = new VertexData[focused.length]; for (int i = 0; i < focused.length; i++) reversed[i] = focused[focused.length - 1 - i]; - GUIHelper.renderPolygon(graphics, reversed, z1, focusedArgb); - focusedPolyhedron.forEach(primitive -> GUIHelper.renderPolygon(graphics, primitive, z1, focusedArgb)); + GUIHelper.polygon(graphics, reversed, z1, focusedArgb); + focusedPolyhedron.forEach(primitive -> GUIHelper.polygon(graphics, primitive, z1, focusedArgb)); } - public void drawFocusedInTextureArea(GuiGraphics graphics) { + public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics) { Matrix4f positionMatrix = texturePose.last().pose(); int length = 0; VertexData[] transformed = new VertexData[0], reversed = new VertexData[0]; @@ -272,59 +278,16 @@ public void drawFocusedInTextureArea(GuiGraphics graphics) { position.set(vertex.u(), vertex.v(), 0).mulPosition(positionMatrix); transformed[i] = reversed[length - 1 - i] = VertexData.immutable(position.x(), position.y(), 0, vertex.argb(), vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); } - GUIHelper.renderPolygon(graphics, transformed, 0, focusedArgb); - GUIHelper.renderPolygon(graphics, reversed, 0, focusedArgb); + GUIHelper.polygon(graphics, transformed, 0, focusedArgb); + GUIHelper.polygon(graphics, reversed, 0, focusedArgb); } } - public void drawModel(GuiGraphics graphics, PoseStack poseStack) { - poseStack.pushPose(); - poseStack.mulPose(modelPose.last().pose().invert(new Matrix4f())); - float minEntityZ = 0f, maxEntityZ = 200f; - for (BuiltRecord record : modelRecords) { - for (VertexData vertex : record.vertices()) { - if (vertex.z() < minEntityZ) minEntityZ = vertex.z(); - if (vertex.z() > maxEntityZ) maxEntityZ = vertex.z(); - } - } - Matrix4f positionMatrix = new Matrix4f().mul(poseStack.last().pose()).scale(1, 1, 200 / (maxEntityZ - minEntityZ)).translate(0, 0, -minEntityZ); - Matrix3f normalMatrix = new Matrix3f(positionMatrix); - modelRecords.forEach(record -> { - VertexConsumer buffer = graphics.bufferSource().getBuffer(record.renderType()); - if (!record.renderType().canConsolidateConsecutiveGeometry()) { - for (VertexData vertex : record.vertices()) vertex.render(buffer, positionMatrix, normalMatrix); - return; - } - for (VertexData[] primitive : record.primitives()) { - for (VertexData vertex : primitive) vertex.render(buffer, positionMatrix, normalMatrix); - } - }); - poseStack.popPose(); - graphics.flush(); - } - - public void drawTexture(GuiGraphics graphics, PoseStack poseStack) { - Matrix4f positionMatrix = poseStack.last().pose(); - textureRecords.forEach(record -> { - VertexConsumer buffer = graphics.bufferSource().getBuffer(record.renderType()); - Vector3f position = new Vector3f(); - for (VertexData vertex : record.vertices()) { - position.set(vertex.u(), vertex.v(), 0).mulPosition(positionMatrix); - buffer.addVertex(position.x(), position.y(), 0, vertex.argb(), vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); - } - }); - graphics.flush(); - } - - public void updateModel(Minecraft client, Entity entity, float deltaTick, PoseStack poseStack) { - Lighting.setupForEntityInInventory(); + public void updateModel(Minecraft client, Entity entity, float partialTicks, PoseStack poseStack) { EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); - dispatcher.setRenderShadow(false); - MultiVertexCatcher catcher = MultiVertexCatcher.defaultImpl(); - dispatcher.render(entity, 0, 0, 0, 0, deltaTick, poseStack, catcher, 0xF000f0); - catcher.endCatching(this::computeBindResult); - dispatcher.setRenderShadow(true); - Lighting.setupFor3DItems(); + client.gameRenderer.getLighting().setupFor(Lighting.Entry.ENTITY_IN_UI); + dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); + vertexCatcher.endCatching(this::computeBindResult); } public void computeBindResult(BuiltIterableBuffer builtBuffer) { @@ -338,10 +301,10 @@ public void computeBindResult(BuiltIterableBuffer builtBuffer) { primitives[i][0] = vertices[startWithFirst ? 0 : k]; System.arraycopy(vertices, k + 1, primitives[i], 1, primitiveLength - 1); } - BuiltRecord record = new BuiltRecord(builtBuffer.renderType(), builtBuffer.textureId(), vertices, primitives); + BuiltModelRecord record = new BuiltModelRecord(builtBuffer.renderType(), builtBuffer.textureId(), vertices, primitives); modelRecords.add(record); if (!builtBuffer.textureId().contains(target.textureId()) || currentRecord != null) return; - BindResult result = new BindResult(target, true); + BindResult result = new BindResult(target); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV[] uvs = {new VertexData.UV(config.posU(), config.posV()), new VertexData.UV(config.forwardU(), config.forwardV()), new VertexData.UV(config.upwardU(), config.upwardV())}; targetPrimitives = builtBuffer.findPrimitivesInCache(uvs); @@ -359,9 +322,7 @@ public void computeBindResult(BuiltIterableBuffer builtBuffer) { if (targetPrimitives[2] != null) result.setUpward(VertexData.normal(targetPrimitives[2]).scale(-1)); if (result.weakAvailable()) { currentRecord = record; - bindResult = result.computeCamera(); + bindResult = result.computeCamera(true); } } - - private record BuiltRecord(RenderType renderType, String textureId, VertexData[] vertices, VertexData[][] primitives) { } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 0d49c730..83ebacfd 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.vertex.PoseStack; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.compat.CompatibilityHelper; import com.xtracr.realcamera.config.BindTarget; @@ -10,31 +11,37 @@ import com.xtracr.realcamera.config.ConfigFile; import com.xtracr.realcamera.config.ConfigScreen; import com.xtracr.realcamera.config.ModConfig; +import com.xtracr.realcamera.gui.components.CycleIconButton; +import com.xtracr.realcamera.gui.components.DoubleSlider; +import com.xtracr.realcamera.gui.components.NumberField; +import com.xtracr.realcamera.gui.components.SimpleIconButton; +import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.util.LocUtil; import com.xtracr.realcamera.util.MathUtil; -import com.xtracr.realcamera.util.VertexData; import io.netty.buffer.Unpooled; import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.*; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.layouts.FrameLayout; import net.minecraft.client.gui.layouts.GridLayout; import net.minecraft.client.gui.layouts.LayoutSettings; import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.client.gui.navigation.CommonInputs; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.phys.Vec2; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -69,12 +76,12 @@ public class ModelViewScreen extends Screen { private final List disableConfigs = new ArrayList<>(); private final List rectWidgets = new ArrayList<>(); private final Map> hiddenNameMap = new HashMap<>(); - private final CyclingTexturedButton showTextureButton = new CyclingTexturedButton(48, 16, 0, 2).setOnValueChange(i -> initWidgets(page)); - private final CyclingTexturedButton pauseButton = new CyclingTexturedButton(0, 16, 0, 2); - private final CyclingTexturedButton bindXButton = new CyclingTexturedButton(16, 16, 1, 2); - private final CyclingTexturedButton bindYButton = new CyclingTexturedButton(16, 16, 0, 2); - private final CyclingTexturedButton bindZButton = new CyclingTexturedButton(16, 16, 1, 2); - private final CyclingTexturedButton bindRotButton = new CyclingTexturedButton(16, 16, 1, 2); + private final CycleIconButton showTextureButton = new CycleIconButton(48, 16, 0, 2).setOnValueChange(_ -> initWidgets(page)); + private final CycleIconButton pauseButton = new CycleIconButton(0, 16, 0, 2); + private final CycleIconButton bindXButton = new CycleIconButton(16, 16, 1, 2); + private final CycleIconButton bindYButton = new CycleIconButton(16, 16, 0, 2); + private final CycleIconButton bindZButton = new CycleIconButton(16, 16, 1, 2); + private final CycleIconButton bindRotButton = new CycleIconButton(16, 16, 1, 2); private final DoubleSlider entityPitchSlider = createSlider("pitch", widgetWidth * 2 + 4, -90.0, 90.0); private final DoubleSlider entityYawSlider = createSlider("yaw", widgetWidth * 2 + 4, -60.0, 60.0); private final DoubleSlider offsetXSlider = createSlider("offsetX", widgetWidth * 2 - 18, ModConfig.MIN_OFFSET_D, ModConfig.MAX_OFFSET_D); @@ -84,57 +91,52 @@ public class ModelViewScreen extends Screen { private final DoubleSlider offsetYawSlider = createSlider("yaw", widgetWidth * 2 - 18, -180.0, 180.0); private final DoubleSlider offsetRollSlider = createSlider("roll", widgetWidth * 2 - 18, -180.0, 180.0); private final CycleButton selectingButton = createCyclingButtonBuilder(ImmutableSortedMap.of( - 0, LocUtil.MODEL_VIEW_WIDGET("forwardVector").withStyle(ChatFormatting.GREEN), - 1, LocUtil.MODEL_VIEW_WIDGET("upwardVector").withStyle(ChatFormatting.RED), - 2, LocUtil.MODEL_VIEW_WIDGET("position").withStyle(ChatFormatting.BLUE))) - .withInitialValue(0) - .withTooltip(i -> createTooltip("selecting", modifierKey.getDisplayName(), modifierKey.getDisplayName())) + 0, LocUtil.MODEL_VIEW_WIDGET("forwardVector").withStyle(ChatFormatting.GREEN), + 1, LocUtil.MODEL_VIEW_WIDGET("upwardVector").withStyle(ChatFormatting.RED), + 2, LocUtil.MODEL_VIEW_WIDGET("position").withStyle(ChatFormatting.BLUE)), 0) + .withTooltip(_ -> createTooltip("selecting", modifierKey.getDisplayName(), modifierKey.getDisplayName())) .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selecting")); private final CycleButton disableModeButton = createCyclingButtonBuilder(ImmutableMap.of( - 0, LocUtil.MODEL_VIEW_WIDGET("all").withStyle(ChatFormatting.GREEN), - 1, LocUtil.MODEL_VIEW_WIDGET("part").withStyle(ChatFormatting.BLUE))) - .withInitialValue(0) - .withTooltip(i -> createTooltip("disableMode", modifierKey.getDisplayName())) + 0, LocUtil.MODEL_VIEW_WIDGET("all").withStyle(ChatFormatting.GREEN), + 1, LocUtil.MODEL_VIEW_WIDGET("part").withStyle(ChatFormatting.BLUE)), 0) + .withTooltip(_ -> createTooltip("disableMode", modifierKey.getDisplayName())) .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("disableMode")); private final CycleButton selectionModeButton = createCyclingButtonBuilder(ImmutableSortedMap.of( - 0, LocUtil.MODEL_VIEW_WIDGET("single"), - 1, LocUtil.MODEL_VIEW_WIDGET("multiple"), - 2, LocUtil.MODEL_VIEW_WIDGET("range").withStyle(ChatFormatting.BLUE))) - .withInitialValue(0) - .withTooltip(i -> createTooltip("selectionMode", modifierKey.getDisplayName(), modifierKey.getDisplayName())) + 0, LocUtil.MODEL_VIEW_WIDGET("single"), + 1, LocUtil.MODEL_VIEW_WIDGET("multiple"), + 2, LocUtil.MODEL_VIEW_WIDGET("range").withStyle(ChatFormatting.BLUE)), 0) + .withTooltip(_ -> createTooltip("selectionMode", modifierKey.getDisplayName(), modifierKey.getDisplayName())) .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selectionMode")); private final CycleButton toggleSliderButton = createCyclingButtonBuilder(ImmutableMap.of( - 0, LocUtil.MODEL_VIEW_WIDGET("toggleSliderToField"), - 1, LocUtil.MODEL_VIEW_WIDGET("toggleFieldToSlider"))) - .withInitialValue(0) - .withTooltip(i -> createTooltip("toggleSlider")) + 0, LocUtil.MODEL_VIEW_WIDGET("toggleSliderToField"), + 1, LocUtil.MODEL_VIEW_WIDGET("toggleFieldToSlider")), 0) + .withTooltip(_ -> createTooltip("toggleSlider")) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, CommonComponents.EMPTY, (button, i) -> { + .create(0, 0, widgetWidth * 2 + 4, widgetHeight, CommonComponents.EMPTY, (_, i) -> { if (i == 1) { - offsetXField.setNumber((float) offsetXSlider.getValue()); - offsetYField.setNumber((float) offsetYSlider.getValue()); - offsetZField.setNumber((float) offsetZSlider.getValue()); - offsetPitchField.setNumber((float) offsetPitchSlider.getValue()); - offsetYawField.setNumber((float) offsetYawSlider.getValue()); - offsetRollField.setNumber((float) offsetRollSlider.getValue()); + offsetXField.setNumber((float) offsetXSlider.getDouble()); + offsetYField.setNumber((float) offsetYSlider.getDouble()); + offsetZField.setNumber((float) offsetZSlider.getDouble()); + offsetPitchField.setNumber((float) offsetPitchSlider.getDouble()); + offsetYawField.setNumber((float) offsetYawSlider.getDouble()); + offsetRollField.setNumber((float) offsetRollSlider.getDouble()); } else { - offsetXSlider.setValue(offsetXField.getNumber()); - offsetYSlider.setValue(offsetYField.getNumber()); - offsetZSlider.setValue(offsetZField.getNumber()); - offsetPitchSlider.setValue(offsetPitchField.getNumber()); - offsetYawSlider.setValue(offsetYawField.getNumber()); - offsetRollSlider.setValue(offsetRollField.getNumber()); + offsetXSlider.setDouble(offsetXField.getNumber()); + offsetYSlider.setDouble(offsetYField.getNumber()); + offsetZSlider.setDouble(offsetZField.getNumber()); + offsetPitchSlider.setDouble(offsetPitchField.getNumber()); + offsetYawSlider.setDouble(offsetYawField.getNumber()); + offsetRollSlider.setDouble(offsetRollField.getNumber()); } initWidgets(page); }); private final CycleButton toggleCategoryButton = createCyclingButtonBuilder(ImmutableSortedMap.of( - Category.CONFIGS, LocUtil.MODEL_VIEW_WIDGET(Category.CONFIGS.next().id), - Category.PREVIEW, LocUtil.MODEL_VIEW_WIDGET(Category.PREVIEW.next().id), - Category.DISABLE, LocUtil.MODEL_VIEW_WIDGET(Category.DISABLE.next().id))) - .withInitialValue(Category.CONFIGS) + Category.CONFIGS, LocUtil.MODEL_VIEW_WIDGET(Category.CONFIGS.next().id), + Category.PREVIEW, LocUtil.MODEL_VIEW_WIDGET(Category.PREVIEW.next().id), + Category.DISABLE, LocUtil.MODEL_VIEW_WIDGET(Category.DISABLE.next().id)), Category.CONFIGS) .withTooltip(category -> createTooltip(category.next().id)) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 - 18, widgetHeight, CommonComponents.EMPTY, (button, i) -> initWidgets(0)); + .create(0, 0, widgetWidth * 2 - 18, widgetHeight, CommonComponents.EMPTY, (_, _) -> initWidgets(0)); public ModelViewScreen() { super(LocUtil.MODEL_VIEW_TITLE()); @@ -165,12 +167,13 @@ private void initWidgets(int page) { clearWidgets(); initLeftWidgets(); if (textureViewArea != null) rectWidgets.forEach(this::addRenderableWidget); - if (toggleCategoryButton.getValue() == Category.DISABLE) addRenderableWidget(showTextureButton).setPosition(x + (xSize - middleWidth) / 2 + 4, y + 4); + if (toggleCategoryButton.getValue() == Category.DISABLE) + addRenderableWidget(showTextureButton).setPosition(x + (xSize - middleWidth) / 2 + 4, y + 4); addRenderableWidget(pauseButton).setPosition(x + (xSize + middleWidth) / 2 - 38, y + 4); - addRenderableWidget(new TexturedButton(x + (xSize + middleWidth) / 2 - 20, y + 4, 16, 16, 0, 0, button -> { + addRenderableWidget(new SimpleIconButton(x + (xSize + middleWidth) / 2 - 20, y + 4, 16, 16, 0, 0, _ -> { modelScale = textureScale = 80; - entityYawSlider.setValue(0); - entityPitchSlider.setValue(0); + entityYawSlider.setDouble(0); + entityPitchSlider.setDouble(0); modelX = modelY = textureX = textureY = 0; xRot = yRot = 0; layers = 0; @@ -239,19 +242,19 @@ private void initLeftWidgets() { else rows.addChild(offsetPitchField, fieldSettings); if (useSliderOffset) rows.addChild(offsetYawSlider, 2, grid.newCellSettings().padding(26, 2, 0, 0)); else rows.addChild(offsetYawField, 2, grid.newCellSettings().padding(29, 3, 1, 1)); - rows.addChild(new TexturedButton(0, 0, button -> { + rows.addChild(new SimpleIconButton(0, 0, _ -> { offsetXField.setNumber(0f); offsetYField.setNumber(0f); offsetZField.setNumber(0f); offsetPitchField.setNumber(0f); offsetYawField.setNumber(0f); offsetRollField.setNumber(0f); - offsetXSlider.setValue(0); - offsetYSlider.setValue(0); - offsetZSlider.setValue(0); - offsetPitchSlider.setValue(0); - offsetYawSlider.setValue(0); - offsetRollSlider.setValue(0); + offsetXSlider.setDouble(0); + offsetYSlider.setDouble(0); + offsetZSlider.setDouble(0); + offsetPitchSlider.setDouble(0); + offsetYawSlider.setDouble(0); + offsetRollSlider.setDouble(0); }), smallSettings); if (useSliderOffset) rows.addChild(offsetRollSlider, sliderSettings); else rows.addChild(offsetRollField, fieldSettings); @@ -275,7 +278,7 @@ else if (index > 0 && index <= rectWidgets.size()) { }).setTooltip(createTooltip("focusedRectangleNumber")); addRenderableWidget(new StringWidget(x + 4 + widgetWidth + 3, y + 4 + (widgetHeight + 2) * 3, 6, widgetHeight, LocUtil.literal("/"), font)); addRenderableWidget(rectWidgetsSizeWidget); - rows.addChild(new TexturedButton(48, 0, button -> deleteFocusedRectWidget()), grid.newCellSettings().padding(5 + widgetWidth - 18, 3, 1, 1)) + rows.addChild(new SimpleIconButton(48, 0, _ -> deleteFocusedRectWidget()), grid.newCellSettings().padding(5 + widgetWidth - 18, 3, 1, 1)) .setTooltip(createTooltip("deleteSelectedRectangle")); rows.addChild(new StringWidget(26, widgetHeight, LocUtil.literal("uMin:"), font)); rows.addChild(uMinField, offsetXSettings).setOnValueChange(f -> { @@ -322,20 +325,20 @@ private void initRightWidgets() { LayoutSettings smallSettings = grid.newCellSettings().padding(5, 3, 1, 1); GridLayout.RowHelper rows = grid.createRowHelper(4); rows.addChild(toggleCategoryButton, 3); - rows.addChild(new TexturedButton(80, 0, button -> { + rows.addChild(new SimpleIconButton(80, 0, _ -> { if (CompatibilityHelper.isModLoaded("cloth-config")) minecraft.setScreen(ConfigScreen.create(this)); }), smallSettings).setTooltip(createTooltip("toConfigScreen")); final int widgetsPerPage, size; if (toggleCategoryButton.getValue() == Category.DISABLE) { widgetsPerPage = 6; size = disableConfigs.size(); - rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("copy"), widgetWidth, button -> configsInClipBoard = List.copyOf(disableConfigs)), 2).setTooltip(createTooltip("copy")); - rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("paste"), widgetWidth, button -> { + rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("copy"), widgetWidth, _ -> configsInClipBoard = List.copyOf(disableConfigs)), 2).setTooltip(createTooltip("copy")); + rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("paste"), widgetWidth, _ -> { configsInClipBoard.stream().filter(config -> disableConfigs.stream().noneMatch(c -> c.name().equals(config.name()))).forEach(disableConfigs::add); initWidgets(0); }), 2).setTooltip(createTooltip("paste")); rows.addChild(disabledNameField, 3, smallSettings).setTooltip(createTooltip("disabledName")); - rows.addChild(new TexturedButton(64, 0, button -> { + rows.addChild(new SimpleIconButton(64, 0, button -> { String name = disabledNameField.getValue(), textureId = disabledIdField.getValue(); if (name.isBlank()) { button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyName").withStyle(ChatFormatting.RED))); @@ -358,14 +361,14 @@ private void initRightWidgets() { for (int i = page * widgetsPerPage; i < Math.min((page + 1) * widgetsPerPage, size); i++) { DisableConfig config = disableConfigs.get(i); String targetName = nameField.getValue(); - Set hiddenNames = hiddenNameMap.computeIfAbsent(targetName, k -> new HashSet<>()); - addRenderableWidget(new CyclingTexturedButton(32, 16, hiddenNames.contains(config.name()) ? 1 : 0, 2)) + Set hiddenNames = hiddenNameMap.computeIfAbsent(targetName, _ -> new HashSet<>()); + addRenderableWidget(new CycleIconButton(32, 16, hiddenNames.contains(config.name()) ? 1 : 0, 2)) .setOnValueChange(value -> { if (value == 0) hiddenNames.remove(config.name()); else hiddenNames.add(config.name()); }) .setPosition(x + (xSize + middleWidth) / 2 - 20, y + 5 + (widgetHeight + 2) * (3 + i % widgetsPerPage)); - rows.addChild(createButton(LocUtil.literal(config.name()), widgetWidth * 2 - 18, button -> { + rows.addChild(createButton(LocUtil.literal(config.name()), widgetWidth * 2 - 18, _ -> { disabledNameField.setValue(config.name()); disabledIdField.setValue(config.textureId()); disableModeButton.setValue(config.disableAll() ? 0 : 1); @@ -373,7 +376,7 @@ private void initRightWidgets() { for (UVRectangle rect : config.rectangles()) rectWidgets.add(createRectWidget(rect)); initWidgets(page); }), 3).setTooltip(Tooltip.create(LocUtil.literal(config.name()))); - rows.addChild(new TexturedButton(48, 0, button -> { + rows.addChild(new SimpleIconButton(48, 0, _ -> { disableConfigs.removeIf(disableConfig -> disableConfig.name().equals(config.name())); if (disabledNameField.getValue().equals(config.name())) rectWidgets.clear(); initWidgets(page * widgetsPerPage > size - 2 && size > 1 ? page - 1 : page); @@ -388,12 +391,13 @@ private void initRightWidgets() { for (int i = page * widgetsPerPage; i < Math.min((page + 1) * widgetsPerPage, size); i++) { BindTarget target = i < fixedTargetCount ? fixedTargetList.get(i) : targetList.get(i - fixedTargetCount); String name = target.name(); - Button configButton = createButton(LocUtil.literal(name), widgetWidth * 2 - 18, button -> loadBindTarget(target)); - if (name.equals(RealCameraCore.currentTarget().name())) configButton.setTooltip(Tooltip.create(LocUtil.literal(name + "\n").append(LocUtil.MODEL_VIEW_WIDGET("currentConfig")))); - else configButton.setTooltip(Tooltip.create(LocUtil.literal(name))); - rows.addChild(configButton, 3); + rows.addChild(createButton(LocUtil.literal(name), widgetWidth * 2 - 18, _ -> loadBindTarget(target)), 3) + .setTooltip(Tooltip.create(name.equals(RealCameraCore.currentTarget().name()) ? + LocUtil.literal(name + "\n").append(LocUtil.MODEL_VIEW_WIDGET("currentConfig")) : + LocUtil.literal(name)) + ); if (i < fixedTargetCount) continue; - rows.addChild(new TexturedButton(48, 0, button -> { + rows.addChild(new SimpleIconButton(48, 0, _ -> { targetList.remove(target); ConfigFile.save(); initWidgets(page * widgetsPerPage > size - 2 && size > 1 ? page - 1 : page); @@ -404,12 +408,13 @@ private void initRightWidgets() { FrameLayout.alignInRectangle(grid, x + (xSize + middleWidth) / 2 + 4, y + 2, x + xSize, y + ySize, 0, 0); grid.visitWidgets(this::addRenderableWidget); final int pages = (size - 1) / widgetsPerPage + 1; - addRenderableWidget(new TexturedButton(x + (xSize + middleWidth) / 2 + 8, y + ySize - 20, 16, 16, 16, 0, button -> initWidgets((page - 1 + pages) % pages))); - addRenderableWidget(new StringWidget(x + (xSize + middleWidth) / 2 + 30, y + ySize - 20, widgetWidth * 2 - 40, widgetHeight, LocUtil.literal((page + 1) + " / " + pages), font)); - addRenderableWidget(new TexturedButton(x + xSize - 21, y + ySize - 20, 16, 16, 32, 0, button -> initWidgets((page + 1) % pages))); + addRenderableWidget(new SimpleIconButton(x + (xSize + middleWidth) / 2 + 8, y + ySize - 20, 16, 16, 16, 0, _ -> initWidgets((page - 1 + pages) % pages))); + Component pageInfo = LocUtil.literal((page + 1) + " / " + pages); + addRenderableWidget(new StringWidget(x + (3 * xSize + middleWidth) / 4 + 2 - font.width(pageInfo) / 2, y + ySize - 20, font.width(pageInfo), widgetHeight, pageInfo, font)); + addRenderableWidget(new SimpleIconButton(x + xSize - 21, y + ySize - 20, 16, 16, 32, 0, _ -> initWidgets((page + 1) % pages))); } - public @NotNull UVRectangleWidget addRectWidget(@NotNull UVRectangleWidget rectWidget) { + public @NonNull UVRectangleWidget addRectWidget(@NonNull UVRectangleWidget rectWidget) { UVRectangleWidget foundRectWidget = rectWidgets.stream().filter(r -> r.contains(rectWidget)).findFirst().orElse(null); if (foundRectWidget == null) { rectWidgets.add(rectWidget); @@ -432,11 +437,11 @@ public boolean deleteFocusedRectWidget() { } @Override - public void render(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { - super.render(graphics, mouseX, mouseY, deltaTick); + public void extractRenderState(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { + super.extractRenderState(graphics, mouseX, mouseY, partialTicks); if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) { GUIHelper.enableScissor(graphics, modelViewArea); - graphics.fill(mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius, 400, 0x4F3333CC); + GUIHelper.fill(graphics, mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius, 400, 0x4F3333CC); graphics.disableScissor(); } if (textureViewArea != null) { @@ -444,14 +449,14 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick if (clickedX >= 0 && clickedY >= 0) graphics.fill(Math.min((int) clickedX, mouseX), Math.min((int) clickedY, mouseY), Math.max((int) clickedX, mouseX), Math.max((int) clickedY, mouseY), 0x4F3333CC); if (disableModeButton.getValue() == 0) - new UVRectangleWidget(0f, 0f, 1f, 1f).renderWidget(graphics, mouseX, mouseY, deltaTick); + new UVRectangleWidget(0f, 0f, 1f, 1f).extractWidgetRenderState(graphics, mouseX, mouseY, partialTicks); graphics.disableScissor(); } } @Override - public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { - super.renderBackground(graphics, mouseX, mouseY, deltaTick); + public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { + super.extractBackground(graphics, mouseX, mouseY, partialTicks); graphics.fill(x, y, x + (xSize - middleWidth) / 2 - 4, y + ySize, 0xFF444444); graphics.fill(x + (xSize - middleWidth) / 2, y, x + (xSize + middleWidth) / 2, y + ySize, 0xFF222222); graphics.fill(x + (xSize + middleWidth) / 2 + 4, y, x + xSize, y + ySize, 0xFF444444); @@ -461,7 +466,7 @@ public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float applyAnalyser(graphics, mouseX, mouseY); } - protected void applyAnalyser(GuiGraphics graphics, int mouseX, int mouseY) { + protected void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY) { String textureId = toggleCategoryButton.getValue() == Category.DISABLE ? disabledIdField.getValue() : ""; Set hiddenNames = hiddenNameMap.getOrDefault(nameField.getValue(), Set.of()); analyser.applyDisableConfigs(textureId, hiddenNames); @@ -473,34 +478,32 @@ protected void applyAnalyser(GuiGraphics graphics, int mouseX, int mouseY) { focusedPolyhedron = analyser.focusedPolyhedron.toArray(new VertexData[0][]); focusedTextureId = analyser.getFocusedTextureId(); GUIHelper.enableScissor(graphics, modelViewArea); - analyser.drawModel(graphics, analyser.modelPose); if (toggleCategoryButton.getValue() != Category.PREVIEW) analyser.drawFocusedInModelArea(graphics); if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics); else analyser.drawCameraDirections(graphics); graphics.disableScissor(); if (textureViewArea != null) { GUIHelper.enableScissor(graphics, textureViewArea); - analyser.drawTexture(graphics, analyser.texturePose); analyser.drawFocusedInTextureArea(graphics); graphics.disableScissor(); } } - protected void renderModelViewArea(GuiGraphics graphics, LivingEntity entity) { + protected void renderModelViewArea(GuiGraphicsExtractor graphics, LivingEntity entity) { int x1 = modelViewArea.left(), y1 = modelViewArea.top(), x2 = modelViewArea.right(), y2 = modelViewArea.bottom(); - Quaternionf quaternionf = new Quaternionf().rotateX((float) Math.PI / 6 + xRot).rotateY((float) Math.PI / 6 + yRot).rotateZ((float) Math.PI); + Quaternionf rotation = new Quaternionf().rotateX((float) Math.PI / 6 + xRot).rotateY((float) Math.PI / 6 + yRot).rotateZ((float) Math.PI); float entityBodyYaw = entity.yBodyRot; float entityYaw = entity.getYRot(); float entityPitch = entity.getXRot(); float entityPrevHeadYaw = entity.yHeadRotO; float entityHeadYaw = entity.yHeadRot; entity.yBodyRot = 180.0f; - entity.setYRot(180.0f + (float) entityYawSlider.getValue()); - entity.setXRot((float) entityPitchSlider.getValue()); + entity.setYRot(180.0f + (float) entityYawSlider.getDouble()); + entity.setXRot((float) entityPitchSlider.getDouble()); entity.yHeadRot = entity.getYRot(); entity.yHeadRotO = entity.getYRot(); Vector3f offset = new Vector3f((float) modelX, (float) modelY, 0); - renderEntityWithAnalyser(graphics, x1, y1, x2, y2, modelScale, offset, quaternionf, entity); + renderEntityWithAnalyser(graphics, x1, y1, x2, y2, modelScale, offset, rotation, entity); entity.yBodyRot = entityBodyYaw; entity.setYRot(entityYaw); entity.setXRot(entityPitch); @@ -508,26 +511,34 @@ protected void renderModelViewArea(GuiGraphics graphics, LivingEntity entity) { entity.yHeadRot = entityHeadYaw; } - protected void renderEntityWithAnalyser(GuiGraphics graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset, Quaternionf quaternionf, LivingEntity entity) { - analyser.modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - analyser.modelPose.scale(scale, scale, -scale); - analyser.modelPose.translate(offset.x(), offset.y(), offset.z()); - analyser.modelPose.mulPose(quaternionf); - analyser.modelPose.translate(0, -entity.getBbHeight() / 2.0f, 0); - analyser.updateModel(minecraft, entity, 1.0f, analyser.modelPose); + protected void renderEntityWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset, Quaternionf rotation, LivingEntity entity) { + PoseStack modelPose = analyser.modelPose; + modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + modelPose.scale(scale, scale, -scale); + modelPose.translate(offset.x(), offset.y(), offset.z()); + modelPose.mulPose(rotation); + modelPose.translate(0, -entity.getBbHeight() / 2.0f, 0); + analyser.updateModel(minecraft, entity, 1.0f, modelPose); + Matrix4f transform = new Matrix4f(); + transform.translate(offset.x(), offset.y(), offset.z()); + transform.rotate(rotation); + transform.translate(0, -entity.getBbHeight() / 2.0f, 0); + transform.mul(modelPose.last().pose().invert(new Matrix4f())); + GUIHelper.culledModels(graphics, analyser.modelRecords, scale, transform, x1, y1, x2, y2); } - protected void renderTextureViewArea(GuiGraphics graphics) { + protected void renderTextureViewArea(GuiGraphicsExtractor graphics) { if (textureViewArea == null) return; int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); renderTextureWithAnalyser(graphics, x1, y1, x2, y2, (float) (textureScale * textureViewArea.width()) / 80, offset); } - protected void renderTextureWithAnalyser(GuiGraphics graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset) { + protected void renderTextureWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset) { analyser.texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); analyser.texturePose.scale(scale, scale, -scale); analyser.texturePose.translate(offset.x(), offset.y(), offset.z()); + GUIHelper.flattenedModels(graphics, analyser.textureRecords, offset, x1, y1, x2, y2, scale); } protected void importBindTarget(Button button) { @@ -595,37 +606,38 @@ protected void loadBindTarget(BindTarget target) { bindZButton.setValue(target.bindConfig().bindZ() ? 0 : 1); bindRotButton.setValue(target.bindConfig().bindRotation() ? 0 : 1); scaleField.setNumber(target.offsets().getScale()); - offsetXSlider.setValue(target.offsets().getX()); + offsetXSlider.setDouble(target.offsets().getX()); offsetXField.setNumber(target.offsets().getX()); - offsetYSlider.setValue(target.offsets().getY()); + offsetYSlider.setDouble(target.offsets().getY()); offsetYField.setNumber(target.offsets().getY()); - offsetZSlider.setValue(target.offsets().getZ()); + offsetZSlider.setDouble(target.offsets().getZ()); offsetZField.setNumber(target.offsets().getZ()); - offsetPitchSlider.setValue(target.offsets().getPitch()); + offsetPitchSlider.setDouble(target.offsets().getPitch()); offsetPitchField.setNumber(target.offsets().getPitch()); - offsetYawSlider.setValue(target.offsets().getYaw()); + offsetYawSlider.setDouble(target.offsets().getYaw()); offsetYawField.setNumber(target.offsets().getYaw()); - offsetRollSlider.setValue(target.offsets().getRoll()); + offsetRollSlider.setDouble(target.offsets().getRoll()); offsetRollField.setNumber(target.offsets().getRoll()); disableConfigs.clear(); disableConfigs.addAll(List.of(target.disableConfigs())); } protected BindTarget genBindTarget() { - TargetConfig targetConfig = new TargetConfig( forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); - BindConfig bindConfig = new BindConfig( bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); + TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); + BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); OffsetConfig offsets = new OffsetConfig() .setScale(scaleField.getNumber()) - .setX(toggleSliderButton.getValue() == 0 ? (float) offsetXSlider.getValue() : offsetXField.getNumber()) - .setY(toggleSliderButton.getValue() == 0 ? (float) offsetYSlider.getValue() : offsetYField.getNumber()) - .setZ(toggleSliderButton.getValue() == 0 ? (float) offsetZSlider.getValue() : offsetZField.getNumber()) - .setPitch(toggleSliderButton.getValue() == 0 ? (float) offsetPitchSlider.getValue() : offsetPitchField.getNumber()) - .setYaw(toggleSliderButton.getValue() == 0 ? (float) offsetYawSlider.getValue() : offsetYawField.getNumber()) - .setRoll(toggleSliderButton.getValue() == 0 ? (float) offsetRollSlider.getValue() : offsetRollField.getNumber()); + .setX(toggleSliderButton.getValue() == 0 ? (float) offsetXSlider.getDouble() : offsetXField.getNumber()) + .setY(toggleSliderButton.getValue() == 0 ? (float) offsetYSlider.getDouble() : offsetYField.getNumber()) + .setZ(toggleSliderButton.getValue() == 0 ? (float) offsetZSlider.getDouble() : offsetZField.getNumber()) + .setPitch(toggleSliderButton.getValue() == 0 ? (float) offsetPitchSlider.getDouble() : offsetPitchField.getNumber()) + .setYaw(toggleSliderButton.getValue() == 0 ? (float) offsetYawSlider.getDouble() : offsetYawField.getNumber()) + .setRoll(toggleSliderButton.getValue() == 0 ? (float) offsetRollSlider.getDouble() : offsetRollField.getNumber()); DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toArray(UVRectangle[]::new)); DisableConfig[] disableConfigArray = disableConfigs.toArray(new DisableConfig[0]); for (int i = 0; i < disableConfigArray.length; i++) { - if (disableConfigArray[i].name().equals(currentDisableConfig.name())) disableConfigArray[i] = currentDisableConfig; + if (disableConfigArray[i].name().equals(currentDisableConfig.name())) + disableConfigArray[i] = currentDisableConfig; } return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, disableConfigArray); } @@ -642,8 +654,8 @@ protected Button createButton(Component message, int width, Button.OnPress onPre return Button.builder(message, onPress).size(width, widgetHeight).build(); } - protected CycleButton.Builder createCyclingButtonBuilder(Map messages) { - return new CycleButton.Builder(messages::get).withValues(messages.keySet()); + protected CycleButton.Builder createCyclingButtonBuilder(Map messages, T defaultValue) { + return new CycleButton.Builder<>(messages::get, () -> defaultValue).withValues(messages.keySet()); } protected DoubleSlider createSlider(String key, int width, double min, double max) { @@ -743,54 +755,54 @@ public boolean leftClickedWithModifier(double mouseX, double mouseY) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(@NonNull MouseButtonEvent event, boolean doubleClick) { double storedX = clickedX, storedY = clickedY; clickedX = clickedY = -1; - if (button == InputConstants.MOUSE_BUTTON_LEFT && toggleCategoryButton.getValue() != Category.PREVIEW) { - if (InputConstants.isKeyDown(minecraft.getWindow().getWindow(), modifierKey.getValue())) { - if (leftClickedWithModifier(mouseX, mouseY)) return true; - } else if (inTextureViewArea(mouseX, mouseY)) { - if (super.mouseClicked(mouseX, mouseY, button)) return true; + if (event.input() == InputConstants.MOUSE_BUTTON_LEFT && toggleCategoryButton.getValue() != Category.PREVIEW) { + if (InputConstants.isKeyDown(minecraft.getWindow(), modifierKey.getValue())) { + if (leftClickedWithModifier(event.x(), event.y())) return true; + } else if (inTextureViewArea(event.x(), event.y())) { + if (super.mouseClicked(event, doubleClick)) return true; if (storedX >= 0 && storedY >= 0) { - float xMin = (float) Math.min(storedX, mouseX), yMin = (float) Math.min(storedY, mouseY), xMax = (float) Math.max(storedX, mouseX), yMax = (float) Math.max(storedY, mouseY); + float xMin = (float) Math.min(storedX, event.x()), yMin = (float) Math.min(storedY, event.y()), xMax = (float) Math.max(storedX, event.x()), yMax = (float) Math.max(storedY, event.y()); setFocused(addRectWidget(new UVRectangleWidget(xMin, yMin, xMax, yMax, textureViewArea))); return true; } - clickedX = (int) mouseX; - clickedY = (int) mouseY; + clickedX = (int) event.x(); + clickedY = (int) event.y(); return true; } } - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(event, doubleClick); } @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (button == InputConstants.MOUSE_BUTTON_LEFT && !InputConstants.isKeyDown(minecraft.getWindow().getWindow(), modifierKey.getValue())) { - if (inModelViewArea(mouseX, mouseY)) { - xRot += (float) (Math.PI * deltaY / ySize); - yRot -= (float) (Math.PI * deltaX / middleWidth); + public boolean mouseDragged(@NonNull MouseButtonEvent event, double dx, double dy) { + if (event.input() == InputConstants.MOUSE_BUTTON_LEFT && !InputConstants.isKeyDown(minecraft.getWindow(), modifierKey.getValue())) { + if (inModelViewArea(event.x(), event.y())) { + xRot += (float) (Math.PI * dy / ySize); + yRot -= (float) (Math.PI * dx / middleWidth); return true; } - } else if (button == InputConstants.MOUSE_BUTTON_RIGHT) { - if (inModelViewArea(mouseX, mouseY)) { - modelX += deltaX / modelScale; - modelY += deltaY / modelScale; + } else if (event.input() == InputConstants.MOUSE_BUTTON_RIGHT) { + if (inModelViewArea(event.x(), event.y())) { + modelX += dx / modelScale; + modelY += dy / modelScale; return true; } - if (inTextureViewArea(mouseX, mouseY)) { - textureX += deltaX / textureScale; - textureY += deltaY / textureScale; + if (inTextureViewArea(event.x(), event.y())) { + textureX += dx / textureScale; + textureY += dy / textureScale; return true; } } - return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + return super.mouseDragged(event, dx, dy); } @Override public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { if (inModelViewArea(mouseX, mouseY)) { - if (InputConstants.isKeyDown(minecraft.getWindow().getWindow(), modifierKey.getValue())) { + if (InputConstants.isKeyDown(minecraft.getWindow(), modifierKey.getValue())) { if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2) selectionRadius = Mth.clamp(selectionRadius + (int) verticalAmount * 2, 2, 48); else layers = Math.max(0, layers + (int) verticalAmount); @@ -805,12 +817,12 @@ public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmou } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (CommonInputs.selected(keyCode)) { + public boolean keyPressed(@NonNull KeyEvent event) { + if (event.isSelection()) { GuiEventListener focused = getFocused(); if (focused != null && !focused.isFocused()) setFocused(focusedRectWidget); } - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(event); } @Override @@ -818,6 +830,18 @@ public boolean isPauseScreen() { return pauseButton.getValue() == 1; } + private enum Category { + CONFIGS, + PREVIEW, + DISABLE; + + public final String id = name().toLowerCase(); + + public Category next() { + return values()[(ordinal() + 1) % values().length]; + } + } + public class UVRectangleWidget extends AbstractWidget { protected float uMin, vMin, uMax, vMax; @@ -829,7 +853,7 @@ public UVRectangleWidget(float uMin, float vMin, float uMax, float vMax) { this.vMax = vMax; } - public UVRectangleWidget(float xMin, float yMin, float xMax, float yMax, @NotNull ScreenRectangle screenArea) { + public UVRectangleWidget(float xMin, float yMin, float xMax, float yMax, @NonNull ScreenRectangle screenArea) { super((int) xMin, (int) yMin, (int) (xMax - xMin), (int) (yMax - yMin), CommonComponents.EMPTY); Vec2 minUV = translateXYToUV(xMin, yMin, screenArea), maxUV = translateXYToUV(xMax, yMax, screenArea); this.uMin = minUV.x; @@ -872,14 +896,14 @@ private Vec2 translateUVToXY(float u, float v, ScreenRectangle screenArea) { private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); Vector3f vector3f = new Vector3f(x, y, 0) - .add(- (float) (x1 + x2) / 2.0f, - (float) (y1 + y2) / 2.0f, 0) + .add(-(float) (x1 + x2) / 2.0f, -(float) (y1 + y2) / 2.0f, 0) .mul((float) 80 / (textureScale * screenArea.width())) .add((float) -textureX + 0.5f, (float) -textureY + 0.5f, 0); return new Vec2(vector3f.x(), vector3f.y()); } @Override - protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { + protected void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { Vec2 minXY = translateUVToXY(uMin, vMin, textureViewArea), maxXY = translateUVToXY(uMax, vMax, textureViewArea); float x1 = minXY.x, y1 = minXY.y, x2 = maxXY.x, y2 = maxXY.y, width = x2 - x1, height = y2 - y1; setX((int) x1); @@ -889,21 +913,22 @@ protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float GUIHelper.enableScissor(graphics, textureViewArea); GUIHelper.fill(graphics, x1, y1, x2, y2, 0x4F3333CC); if (isHoveredOrFocused()) GUIHelper.fill(graphics, x1, y1, x2, y2, 0x2F3333CC); - if (isFocused() || this == focusedRectWidget) GUIHelper.renderOutline(graphics, x1, y1, width, height, 0xAAFFFFFF); + if (isFocused() || this == focusedRectWidget) + GUIHelper.outline(graphics, x1, y1, width, height, 0xAAFFFFFF); graphics.disableScissor(); } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + public boolean keyPressed(@NonNull KeyEvent event) { if (textureViewArea == null) return false; - if (keyCode == InputConstants.KEY_DELETE && deleteFocusedRectWidget()) return true; - if (CommonInputs.selected(keyCode) && uMin < uMax && vMin < vMax) { + if (event.input() == InputConstants.KEY_DELETE && deleteFocusedRectWidget()) return true; + if (event.isSelection() && uMin < uMax && vMin < vMax) { textureX = 0.5 * (1 - uMin - uMax); textureY = 0.5 * (1 - vMin - vMax); textureScale = (int) Mth.clamp(2560d / (textureViewArea.width() * Math.sqrt((uMax - uMin) * (vMax - vMin))), 16, 1024); return true; } - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(event); } @Override @@ -920,18 +945,7 @@ public void setFocused(boolean focused) { } @Override - protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { } - } - - private enum Category { - CONFIGS, - PREVIEW, - DISABLE; - - public final String id = name().toLowerCase(); - - public Category next() { - return values()[(ordinal() + 1) % values().length]; + protected void updateWidgetNarration(@NonNull NarrationElementOutput narrationElementOutput) { } } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java b/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java deleted file mode 100644 index ec0a6447..00000000 --- a/common/src/main/java/com/xtracr/realcamera/gui/TexturedButton.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.xtracr.realcamera.gui; - -import com.xtracr.realcamera.RealCamera; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.AbstractButton; -import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.network.chat.CommonComponents; -import net.minecraft.resources.ResourceLocation; - -import java.util.function.Consumer; - -public class TexturedButton extends AbstractButton { - public static final ResourceLocation ICON_TEXTURE = ResourceLocation.fromNamespaceAndPath(RealCamera.MODID, "textures/gui/icon.png"); - protected final ResourceLocation texture; - protected final int textureWidth, textureHeight, u, v; - private final Consumer onPress; - - public TexturedButton(int u, int v, Consumer onPress) { - this(0, 0, 16, 16, u, v, onPress); - } - - public TexturedButton(int x, int y, int width, int height, int u, int v, Consumer onPress) { - this(x, y, width, height, u, v, ICON_TEXTURE, 256, 256, onPress); - } - - public TexturedButton(int x, int y, int width, int height, int u, int v, ResourceLocation texture, int textureWidth, int textureHeight, Consumer onPress) { - super(x, y, width, height, CommonComponents.EMPTY); - this.textureWidth = textureWidth; - this.textureHeight = textureHeight; - this.onPress = onPress; - this.u = u; - this.v = v; - this.texture = texture; - } - - @Override - public void onPress() { - onPress.accept(this); - } - - @Override - public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { - graphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0xFF646464); - graphics.blit(texture, getX(), getY(), u, v, width, height, textureWidth, textureHeight); - if (isHoveredOrFocused()) graphics.renderOutline(getX(), getY(), getWidth(), getHeight(), 0xFFFFFFFF); - } - - @Override - protected void updateWidgetNarration(NarrationElementOutput builder) { - this.defaultButtonNarrationText(builder); - } -} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java b/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java new file mode 100644 index 00000000..d251f011 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java @@ -0,0 +1,73 @@ +package com.xtracr.realcamera.gui.components; + +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.input.InputWithModifiers; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.Identifier; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import java.util.function.IntConsumer; + +public class CycleIconButton extends AbstractButton { + protected final Identifier texture; + protected final int textureWidth, textureHeight, u, v, vOffset, size; + @Nullable + private IntConsumer onValueChange; + private int value; + + public CycleIconButton(int u, int v, int value, int size) { + this(0, 0, 16, 16, u, v, value, size); + } + + public CycleIconButton(int x, int y, int width, int height, int u, int v, int value, int size) { + this(x, y, width, height, u, v, height, value, size, SimpleIconButton.ICON_TEXTURE, 256, 256); + } + + public CycleIconButton(int x, int y, int width, int height, int u, int v, int vOffset, int value, int size, Identifier texture, int textureWidth, int textureHeight) { + super(x, y, width, height, CommonComponents.EMPTY); + this.u = u; + this.v = v; + this.vOffset = vOffset; + this.size = size; + this.texture = texture; + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + setValue(value); + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = (value % size + size) % size; + } + + public CycleIconButton setOnValueChange(IntConsumer onValueChange) { + this.onValueChange = onValueChange; + return this; + } + + @Override + public void onPress(@NonNull InputWithModifiers input) { + if (input.hasShiftDown()) setValue(value - 1); + else setValue(value + 1); + if (onValueChange != null) onValueChange.accept(value); + } + + @Override + public void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { + graphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0xFF646464); + graphics.blit(RenderPipelines.GUI_TEXTURED, texture, getX(), getY(), u, v + value * vOffset, width, height, textureWidth, textureHeight); + if (isHoveredOrFocused()) graphics.outline(getX(), getY(), getWidth(), getHeight(), 0xFFFFFFFF); + } + + @Override + protected void updateWidgetNarration(@NonNull NarrationElementOutput builder) { + defaultButtonNarrationText(builder); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/DoubleSlider.java b/common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java similarity index 77% rename from common/src/main/java/com/xtracr/realcamera/gui/DoubleSlider.java rename to common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java index 7089fcb9..fc319fd2 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/DoubleSlider.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java @@ -1,4 +1,4 @@ -package com.xtracr.realcamera.gui; +package com.xtracr.realcamera.gui.components; import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.network.chat.Component; @@ -17,18 +17,17 @@ public DoubleSlider(int width, int height, double value, double min, double max, this.max = max; } - public double getValue() { + public double getDouble() { return min + (max - min) * value; } - public void setValue(double value) { - this.value = Mth.clamp(0, (value - min) / (max - min), 1); - applyValue(); + public void setDouble(double value) { + setValue((value - min) / (max - min)); } @Override protected void updateMessage() { - setMessage(textFactory.apply(getValue())); + setMessage(textFactory.apply(getDouble())); } @Override diff --git a/common/src/main/java/com/xtracr/realcamera/gui/NumberField.java b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java similarity index 67% rename from common/src/main/java/com/xtracr/realcamera/gui/NumberField.java rename to common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java index 7a5534ee..f9dae213 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/NumberField.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java @@ -1,16 +1,17 @@ -package com.xtracr.realcamera.gui; +package com.xtracr.realcamera.gui.components; +import com.xtracr.realcamera.RealCamera; import com.xtracr.realcamera.util.LocUtil; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.client.gui.navigation.CommonInputs; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; import net.minecraft.network.chat.CommonComponents; -import net.minecraft.network.chat.Style; -import net.minecraft.util.FormattedCharSequence; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import java.util.function.Consumer; @@ -39,18 +40,18 @@ public static NumberField ofInt(Font font, int width, int height, int d public T getNumber() { try { return getNumberInternal(); + } catch (NumberFormatException e) { + return defaultValue; } catch (Exception e) { + RealCamera.LOGGER.warn("Unexpected error parsing number", e); return defaultValue; } } public void setNumber(T value) { - try { - if (value.compareTo(minimum) < 0) value = minimum; - else if (value.compareTo(maximum) > 0) value = maximum; - setValue(value.toString()); - } catch (Exception ignored) { - } + if (value.compareTo(minimum) < 0) value = minimum; + else if (value.compareTo(maximum) > 0) value = maximum; + setValue(value.toString()); } public NumberField setMax(T maximum) { @@ -64,23 +65,23 @@ public NumberField setMin(T minimum) { } public NumberField setOnValueChange(Consumer consumer) { - super.setResponder(str -> consumer.accept(getNumber())); + super.setResponder(_ -> consumer.accept(getNumber())); return this; } - abstract protected T getNumberInternal(); + abstract protected T getNumberInternal() throws NumberFormatException; protected void checkText() { super.setTooltip(tooltip); - setFormatter((string, firstCharacterIndex) -> FormattedCharSequence.forward(string, Style.EMPTY)); + setTextColor(EditBox.DEFAULT_TEXT_COLOR); if (getValue().isEmpty()) return; try { T value = getNumberInternal(); - if (value.compareTo(minimum) < 0) throw new Exception("< " + minimum); - if (value.compareTo(maximum) > 0) throw new Exception("> " + maximum); + if (value.compareTo(minimum) < 0) throw new RuntimeException("< " + minimum); + if (value.compareTo(maximum) > 0) throw new RuntimeException("> " + maximum); } catch (Exception e) { super.setTooltip(Tooltip.create(LocUtil.literal("Invalid number: " + e.getMessage()).withStyle(s -> s.withColor(ChatFormatting.RED)))); - setFormatter((string, firstCharacterIndex) -> FormattedCharSequence.forward(string, Style.EMPTY.withColor(ChatFormatting.RED))); + setTextColor(0xFFFF5555); } } @@ -91,24 +92,25 @@ public void setTooltip(Tooltip tooltip) { } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (CommonInputs.selected(keyCode)) { + public boolean keyPressed(@NonNull KeyEvent event) { + if (event.isSelection()) { setFocused(false); return true; } - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(event); } @Override - public boolean charTyped(char chr, int modifiers) { + public boolean charTyped(CharacterEvent event) { + char chr = (char) event.codepoint(); if (chr != '-' && chr != '.' && (chr < '0' || chr > '9')) return false; - return super.charTyped(chr, modifiers); + return super.charTyped(event); } @Override - public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { + public void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { checkText(); - super.renderWidget(graphics, mouseX, mouseY, deltaTick); + super.extractWidgetRenderState(graphics, mouseX, mouseY, partialTicks); } private static class FloatField extends NumberField { @@ -118,7 +120,7 @@ private static class FloatField extends NumberField { } @Override - protected Float getNumberInternal() { + protected Float getNumberInternal() throws NumberFormatException { return Float.parseFloat(getValue()); } } @@ -130,7 +132,7 @@ private static class IntField extends NumberField { } @Override - protected Integer getNumberInternal() { + protected Integer getNumberInternal() throws NumberFormatException { return Integer.parseInt(getValue()); } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java b/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java new file mode 100644 index 00000000..e3de55a2 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java @@ -0,0 +1,38 @@ +package com.xtracr.realcamera.gui.components; + +import com.xtracr.realcamera.RealCamera; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.Identifier; + +public class SimpleIconButton extends Button { + public static final Identifier ICON_TEXTURE = Identifier.fromNamespaceAndPath(RealCamera.MODID, "textures/gui/icon.png"); + protected final Identifier texture; + protected final int textureWidth, textureHeight, u, v; + + public SimpleIconButton(int u, int v, Button.OnPress onPress) { + this(0, 0, 16, 16, u, v, onPress); + } + + public SimpleIconButton(int x, int y, int width, int height, int u, int v, Button.OnPress onPress) { + this(x, y, width, height, u, v, ICON_TEXTURE, 256, 256, onPress); + } + + public SimpleIconButton(int x, int y, int width, int height, int u, int v, Identifier texture, int textureWidth, int textureHeight, Button.OnPress onPress) { + super(x, y, width, height, CommonComponents.EMPTY, onPress, DEFAULT_NARRATION); + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + this.u = u; + this.v = v; + this.texture = texture; + } + + @Override + public void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { + graphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0xFF646464); + graphics.blit(RenderPipelines.GUI_TEXTURED, texture, getX(), getY(), u, v, width, height, textureWidth, textureHeight); + if (isHoveredOrFocused()) graphics.outline(getX(), getY(), getWidth(), getHeight(), 0xFFFFFFFF); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java index 79f7a0f4..dae4e34b 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java @@ -3,17 +3,19 @@ import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.config.ConfigFile; import com.xtracr.realcamera.config.ModConfig; -import com.xtracr.realcamera.mixin.accessor.GameRendererAccessor; import net.minecraft.client.Camera; -import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import org.jspecify.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -23,21 +25,42 @@ @Mixin(Camera.class) public abstract class MixinCamera { + @Unique + private static final Vector3f FORWARDS = new Vector3f(0.0F, 0.0F, -1.0F); + @Unique + private static final Vector3f UP = new Vector3f(0.0F, 1.0F, 0.0F); + @Unique + private static final Vector3f LEFT = new Vector3f(-1.0F, 0.0F, 0.0F); + @Shadow + @Nullable + private Level level; @Shadow - private BlockGetter level; + @Nullable + private Entity entity; @Shadow private Vec3 position; @Shadow + @Final + private Vector3f forwards; + @Shadow + @Final + private Vector3f up; + @Shadow + @Final + private Vector3f left; + @Shadow private float xRot; @Shadow private float yRot; + @Shadow + @Final + private Quaternionf rotation; - @Inject(method = "setup", at = @At("RETURN")) - private void realcamera$setupCamera(BlockGetter area, Entity entity, boolean thirdPerson, boolean inverseView, float deltaTick, CallbackInfo ci) { + @Inject(method = "alignWithEntity", at = @At("RETURN")) + private void realcamera$setupCamera(float partialTicks, CallbackInfo ci) { if (!RealCameraCore.isActive()) return; ModConfig config = ConfigFile.config(); Vec3 startVec = position; - AABB box = entity.getBoundingBox(); if (config.isClassic()) { double scale = entity instanceof LivingEntity livingEntity ? livingEntity.getScale() : 1; Vec3 offset = new Vec3(config.getClassicX(), config.getClassicY(), -config.getClassicZ()).scale(scale); @@ -48,16 +71,28 @@ public abstract class MixinCamera { move((float) center.x(), (float) center.y(), (float) center.z()); setRotation(newYaw, newPitch); move((float) offset.x(), (float) offset.y(), (float) offset.z()); + realcamera$setRotation(newYaw, newPitch, ConfigFile.config().getClassicRoll()); } else { - Vec3 entityPos = entity.position().add(entity.position().subtract(entity.xOld, entity.yOld, entity.zOld).scale(entity.tickCount == 0 ? 0 : deltaTick - 1)); + Vec3 entityPos = entity.position().add(entity.position().subtract(entity.xOld, entity.yOld, entity.zOld).scale(entity.tickCount == 0 ? 0 : partialTicks - 1)); Vec3 rawPos = RealCameraCore.getRawPos(position, entityPos); + AABB box = entity.getBoundingBox(); double restrictedY = Mth.clamp(rawPos.y(), box.minY + 0.1D, box.maxY - 0.1D); startVec = new Vec3(position.x(), restrictedY, position.z()); setPosition(rawPos); - setRotation(RealCameraCore.getYaw(yRot), RealCameraCore.getPitch(xRot)); + Vec3 eulerAngle = RealCameraCore.getEulerAngle(xRot, yRot, 0); + realcamera$setRotation((float) eulerAngle.y(), (float) eulerAngle.x(), (float) eulerAngle.z()); } - realcamera$clipToSpace(startVec, entity, realcamera$getFov(deltaTick)); - RealCameraCore.setCameraPos(position); + realcamera$clipToSpace(startVec, entity, calculateFov(partialTicks)); + } + + @Unique + private void realcamera$setRotation(float yRot, float xRot, float roll) { + this.xRot = xRot; + this.yRot = yRot; + rotation.rotationYXZ((float) (Math.PI - Math.toRadians(yRot)), (float) -Math.toRadians(xRot), (float) -Math.toRadians(roll)); + FORWARDS.rotate(rotation, forwards); + UP.rotate(rotation, up); + LEFT.rotate(rotation, left); } @Unique @@ -65,25 +100,23 @@ public abstract class MixinCamera { Vec3 offset = position.subtract(startVec); final float depth = 0.05f + (float) (fov * (0.0001 + 0.000005 * fov)); for (int i = 0; i < 8; ++i) { - float f = depth * ((i & 1) * 2 - 1); - float g = depth * ((i >> 1 & 1) * 2 - 1); - float h = depth * ((i >> 2 & 1) * 2 - 1); - Vec3 start = startVec.add(f, g, h); - Vec3 end = startVec.add(offset).add(f, g, h); + float offsetX = depth * ((i & 1) * 2 - 1); + float offsetY = depth * ((i >> 1 & 1) * 2 - 1); + float offsetZ = depth * ((i >> 2 & 1) * 2 - 1); + Vec3 start = startVec.add(offsetX, offsetY, offsetZ); + Vec3 end = startVec.add(offset).add(offsetX, offsetY, offsetZ); HitResult hitResult = level.clip(new ClipContext(start, end, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, entity)); - double l = hitResult.getLocation().distanceTo(start); - if (hitResult.getType() == HitResult.Type.MISS || l >= offset.length()) continue; - offset = offset.scale(l / offset.length()); + if (hitResult.getType() == HitResult.Type.MISS) continue; + double sqDistance = hitResult.getLocation().distanceToSqr(start); + double sqOffsetL = offset.lengthSqr(); + if (sqDistance >= sqOffsetL) continue; + offset = offset.scale(Math.sqrt(sqDistance / sqOffsetL)); } setPosition(startVec.add(offset)); } - @Unique - private static float realcamera$getFov(float deltaTick) { - Minecraft client = Minecraft.getInstance(); - float fovModifier = Mth.lerp(deltaTick, ((GameRendererAccessor) client.gameRenderer).getOldFov(), ((GameRendererAccessor) client.gameRenderer).getFov()); - return client.options.fov().get() * fovModifier; - } + @Shadow + protected abstract float calculateFov(float partialTicks); @Shadow protected abstract void move(float x, float y, float z); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinFishingHookRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinFishingHookRenderer.java index 9237dc16..65dc9ab5 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinFishingHookRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinFishingHookRenderer.java @@ -1,18 +1,19 @@ package com.xtracr.realcamera.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.xtracr.realcamera.compat.DisableHelper; import net.minecraft.client.CameraType; import net.minecraft.client.renderer.entity.FishingHookRenderer; import net.minecraft.world.entity.player.Player; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(FishingHookRenderer.class) public abstract class MixinFishingHookRenderer { - @Redirect(method = "getPlayerHandPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/CameraType;isFirstPerson()Z")) - private boolean realcamera$redirectIsFirstPerson(CameraType cameraType, Player player) { - if (DisableHelper.RENDER_HANDS.disabled(player)) return false; - return cameraType.isFirstPerson(); + @WrapOperation(method = "getPlayerHandPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/CameraType;isFirstPerson()Z")) + private boolean realcamera$redirectIsFirstPerson(CameraType instance, Operation original, Player owner) { + if (DisableHelper.RENDER_HANDS.disabled(owner)) return false; + return original.call(instance); } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java index 6e5a1a85..feafd99b 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java @@ -1,69 +1,36 @@ package com.xtracr.realcamera.mixin; -import com.llamalad7.mixinextras.sugar.Local; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.compat.CompatibilityHelper; import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.util.CrosshairUtil; -import com.xtracr.realcamera.util.RaycastUtil; import net.minecraft.client.Camera; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.projectile.ProjectileUtil; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameRenderer.class) public abstract class MixinGameRenderer { @Shadow - @Final Minecraft minecraft; + @Final + private Minecraft minecraft; @Shadow - @Final private Camera mainCamera; + @Final + private Camera mainCamera; - @ModifyVariable(method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;", at = @At("STORE"), ordinal = 0) - private EntityHitResult realcamera$modifyEntityHitResult(EntityHitResult entityHitResult) { - CrosshairUtil.capturedEntityHitResult = entityHitResult; - if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - Vec3 startVec = RaycastUtil.getStartVec(); - Vec3 endVec = RaycastUtil.getEndVec(); - double sqDistance = (minecraft.hitResult != null ? minecraft.hitResult.getLocation().distanceToSqr(startVec) : endVec.distanceToSqr(startVec)); - Entity cameraEntity = minecraft.getCameraEntity(); - double interactionRange = Math.max(minecraft.player.blockInteractionRange(), minecraft.player.entityInteractionRange()); - AABB box = cameraEntity.getBoundingBox().expandTowards(cameraEntity.getViewVector(minecraft.getTimer().getGameTimeDeltaPartialTick(true)).scale(interactionRange)).inflate(1.0, 1.0, 1.0); - CrosshairUtil.capturedEntityHitResult = ProjectileUtil.getEntityHitResult(cameraEntity, startVec, endVec, box, entity -> !entity.isSpectator() && entity.isPickable(), sqDistance); - } - return CrosshairUtil.capturedEntityHitResult; - } - - @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setup(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/world/entity/Entity;ZZF)V")) - private void realcamera$atCameraSetup(DeltaTracker deltaTracker, CallbackInfo ci) { - final float deltaTick = deltaTracker.getGameTimeDeltaPartialTick(true); - CompatibilityHelper.NEA_setDeltaTick(deltaTick); - RealCameraCore.initialize(minecraft); + @Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;update(Lnet/minecraft/client/DeltaTracker;)V")) + private void realcamera$atCameraUpdate(DeltaTracker deltaTracker, boolean renderLevel, CallbackInfo ci) { + float partialTicks = deltaTracker.getGameTimeDeltaPartialTick(true); + CompatibilityHelper.NEA_setDeltaTick(partialTicks); + RealCameraCore.initialize(minecraft, renderLevel); if (RealCameraCore.isActive() && !ConfigFile.config().isClassic()) { - EntityRenderDispatcher dispatcher = minecraft.getEntityRenderDispatcher(); - dispatcher.prepare(minecraft.level, mainCamera, minecraft.crosshairPickEntity); - RealCameraCore.computeCamera(minecraft, deltaTick); - } - } - - @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;prepareCullFrustum(Lnet/minecraft/world/phys/Vec3;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V")) - private void realcamera$atPrepareCullFrustum(DeltaTracker deltaTracker, CallbackInfo ci, @Local(ordinal = 1) Matrix4f modelView) { - if (RealCameraCore.isActive()) { - modelView.rotateLocalZ(RealCameraCore.getRoll(0) * (float) (Math.PI / 180.0)); + minecraft.getEntityRenderDispatcher().prepare(mainCamera, minecraft.crosshairPickEntity); + RealCameraCore.computeCamera(minecraft, partialTicks); } - CompatibilityHelper.forceSetCameraPos(mainCamera); } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java index 3ad8d270..d5a25a84 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java @@ -5,7 +5,7 @@ import com.xtracr.realcamera.util.CrosshairUtil; import net.minecraft.client.DeltaTracker; import net.minecraft.client.gui.Gui; -import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.GuiGraphicsExtractor; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,18 +13,18 @@ @Mixin(Gui.class) public abstract class MixinGui { - @Inject(method = "renderCrosshair", at = @At("HEAD")) - private void realcamera$atRenderCrosshairHEAD(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo ci) { + @Inject(method = "extractCrosshair", at = @At("HEAD")) + private void realcamera$atRenderCrosshairHEAD(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - guiGraphics.pose().pushPose(); - CrosshairUtil.translateMatrices(guiGraphics.pose()); + graphics.pose().pushMatrix(); + CrosshairUtil.translateMatrices(graphics.pose()); } } - @Inject(method = "renderCrosshair", at = @At("RETURN")) - private void realcamera$atRenderCrosshairRETURN(GuiGraphics guiGraphics, DeltaTracker deltaTracker, CallbackInfo ci) { + @Inject(method = "extractCrosshair", at = @At("RETURN")) + private void realcamera$atRenderCrosshairRETURN(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - guiGraphics.pose().popPose(); + graphics.pose().popMatrix(); } } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java index a94ee2ae..2d99dcb1 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java @@ -1,5 +1,6 @@ package com.xtracr.realcamera.mixin; +import com.mojang.datafixers.util.Pair; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.config.ConfigFile; import com.xtracr.realcamera.util.RaycastUtil; @@ -8,6 +9,7 @@ import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -18,8 +20,9 @@ public abstract class MixinItem { @Inject(method = "getPlayerPOVHitResult", at = @At("HEAD"), cancellable = true) private static void realcamera$coverHitResult(Level level, Player player, ClipContext.Fluid fluid, CallbackInfoReturnable cir) { if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - RaycastUtil.update(player, 25.0d, 1.0f); - cir.setReturnValue(level.clip(RaycastUtil.getClipContext(ClipContext.Block.OUTLINE, fluid, player))); + double interactionRange = player.blockInteractionRange(); + Pair fromAndTo = RaycastUtil.getFromAndTo(player, interactionRange * interactionRange, 1.0f); + cir.setReturnValue(level.clip(new ClipContext(fromAndTo.getFirst(), fromAndTo.getSecond(), ClipContext.Block.OUTLINE, fluid, player))); } } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinItemInHandRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinItemInHandRenderer.java index f735ceeb..d83e0209 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinItemInHandRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinItemInHandRenderer.java @@ -4,7 +4,7 @@ import com.xtracr.realcamera.compat.DisableHelper; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.ItemInHandRenderer; -import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollector; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,7 +13,7 @@ @Mixin(ItemInHandRenderer.class) public abstract class MixinItemInHandRenderer { @Inject(method = "renderHandsWithItems", at = @At("HEAD"), cancellable = true) - private void realcamera$cancelRender(float f, PoseStack poseStack, MultiBufferSource.BufferSource bufferSource, LocalPlayer localPlayer, int i, CallbackInfo ci) { - if (DisableHelper.RENDER_HANDS.disabled(localPlayer)) ci.cancel(); + private void realcamera$cancelRender(float frameInterp, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, LocalPlayer player, int lightCoords, CallbackInfo ci) { + if (DisableHelper.RENDER_HANDS.disabled(player)) ci.cancel(); } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java index 215e8a0d..c293afb3 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java @@ -1,16 +1,25 @@ package com.xtracr.realcamera.mixin; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.resource.GraphicsResourceAllocator; import com.mojang.blaze3d.vertex.PoseStack; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.config.ConfigFile; -import net.minecraft.client.Camera; +import com.xtracr.realcamera.util.CrosshairUtil; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.chunk.ChunkSectionsToRender; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.client.renderer.state.level.CameraRenderState; +import net.minecraft.client.renderer.state.level.LevelRenderState; import net.minecraft.world.TickRateManager; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; +import org.joml.Matrix4fc; +import org.joml.Vector4f; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -21,24 +30,32 @@ @Mixin(LevelRenderer.class) public abstract class MixinLevelRenderer { @Shadow - @Final private Minecraft minecraft; + @Final + private Minecraft minecraft; @Shadow - @Final private RenderBuffers renderBuffers; + @Final + private EntityRenderDispatcher entityRenderDispatcher; - @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endLastBatch()V", ordinal = 0)) - private void realcamera$renderCameraEntity(DeltaTracker deltaTracker, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f modelView, Matrix4f projection, CallbackInfo ci) { + @Inject(method = "renderLevel", at = @At("HEAD")) + private void realcamera$atRenderLevelHead(GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker, boolean renderOutline, CameraRenderState cameraState, Matrix4fc modelViewMatrix, GpuBufferSlice terrainFog, Vector4f fogColor, boolean shouldRenderSky, ChunkSectionsToRender chunkSectionsToRender, CallbackInfo ci) { + if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + CrosshairUtil.update(minecraft, cameraState.pos, modelViewMatrix, cameraState.projectionMatrix); + } + } + + @Inject(method = "submitEntities", at = @At(value = "RETURN")) + private void realcamera$submitCameraEntity(PoseStack poseStack, LevelRenderState levelRenderState, SubmitNodeCollector output, CallbackInfo ci) { if (!RealCameraCore.isRendering()) return; - MultiBufferSource.BufferSource bufferSource = renderBuffers.bufferSource(); - Entity entity = camera.getEntity(); + Entity entity = minecraft.getCameraEntity(); TickRateManager tickManager = minecraft.level.tickRateManager(); - float deltaTick = deltaTracker.getGameTimeDeltaPartialTick(!tickManager.isEntityFrozen(entity)); - if (!ConfigFile.config().isClassic()) RealCameraCore.renderCameraEntity(minecraft, deltaTick, bufferSource, modelView); + float partialTicks = minecraft.getDeltaTracker().getGameTimeDeltaPartialTick(!tickManager.isEntityFrozen(entity)); + CameraRenderState cameraState = levelRenderState.cameraRenderState; + if (!ConfigFile.config().isClassic()) + RealCameraCore.renderCameraEntity(minecraft, partialTicks, output, cameraState.viewRotationMatrix); else { - Vec3 cameraPos = camera.getPosition(); - renderEntity(entity, cameraPos.x(), cameraPos.y(), cameraPos.z(), deltaTick, new PoseStack(), bufferSource); + Vec3 cameraPos = cameraState.pos; + EntityRenderState state = entityRenderDispatcher.extractEntity(entity, partialTicks); + entityRenderDispatcher.submit(state, cameraState, state.x - cameraPos.x, state.y - cameraPos.y, state.z - cameraPos.z, poseStack, output); } } - - @Shadow - protected abstract void renderEntity(Entity entity, double cameraX, double cameraY, double cameraZ, float deltaTick, PoseStack poseStack, MultiBufferSource bufferSource); } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java index ca966092..307d0788 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java @@ -1,40 +1,67 @@ package com.xtracr.realcamera.mixin; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.mojang.authlib.GameProfile; +import com.mojang.datafixers.util.Pair; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.compat.DisableHelper; import com.xtracr.realcamera.config.ConfigFile; +import com.xtracr.realcamera.util.CrosshairUtil; import com.xtracr.realcamera.util.RaycastUtil; +import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.function.Predicate; + @Mixin(LocalPlayer.class) public abstract class MixinLocalPlayer extends AbstractClientPlayer { public MixinLocalPlayer(ClientLevel world, GameProfile profile) { super(world, profile); } + @WrapOperation(method = "pick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;")) + private static @Nullable EntityHitResult realcamera$wrapGetEntityHitResult(Entity except, Vec3 from, Vec3 to, AABB box, Predicate matching, double maxValue, Operation original, Entity cameraEntity, double blockInteractionRange, double entityInteractionRange, float partialTicks) { + if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + double interactionRange = Math.max(blockInteractionRange, entityInteractionRange); + Pair fromAndTo = RaycastUtil.getFromAndTo(cameraEntity, interactionRange * interactionRange, partialTicks); + Vec3 newFrom = fromAndTo.getFirst(); + Vec3 newTo = fromAndTo.getSecond(); + Minecraft client = Minecraft.getInstance(); + double sqDistance = client.hitResult != null ? client.hitResult.getLocation().distanceToSqr(newFrom) : newTo.distanceToSqr(newFrom); + AABB newBox = cameraEntity.getBoundingBox().expandTowards(cameraEntity.getViewVector(partialTicks).scale(interactionRange)).inflate(1.0, 1.0, 1.0); + CrosshairUtil.capturedEntityHitResult = ProjectileUtil.getEntityHitResult(except, newFrom, newTo, newBox, matching, sqDistance); + return CrosshairUtil.capturedEntityHitResult; + } + return original.call(except, from, to, box, matching, maxValue); + } + @Inject(method = "getRopeHoldPosition", at = @At("HEAD"), cancellable = true) - private void realcamera$atGetRopePosHEAD(float deltaTick, CallbackInfoReturnable cir) { - if (DisableHelper.RENDER_HANDS.disabled(this)) cir.setReturnValue(super.getRopeHoldPosition(deltaTick)); + private void realcamera$atGetRopePosHEAD(float partialTickTime, CallbackInfoReturnable cir) { + if (DisableHelper.RENDER_HANDS.disabled(this)) cir.setReturnValue(super.getRopeHoldPosition(partialTickTime)); } @Override - public @NotNull HitResult pick(double maxDistance, float deltaTick, boolean includeFluids) { + public @NonNull HitResult pick(double maxDistance, float partialTicks, boolean includeFluids) { if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - RaycastUtil.update(this, maxDistance * maxDistance, deltaTick); - return level().clip(RaycastUtil.getClipContext(ClipContext.Block.OUTLINE, - includeFluids ? ClipContext.Fluid.ANY : ClipContext.Fluid.NONE, this)); + Pair fromAndTo = RaycastUtil.getFromAndTo(this, maxDistance * maxDistance, partialTicks); + return level().clip(new ClipContext(fromAndTo.getFirst(), fromAndTo.getSecond(), ClipContext.Block.OUTLINE, includeFluids ? ClipContext.Fluid.ANY : ClipContext.Fluid.NONE, this)); } - return super.pick(maxDistance, deltaTick, includeFluids); + return super.pick(maxDistance, partialTicks, includeFluids); } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java deleted file mode 100644 index 684b8f56..00000000 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xtracr.realcamera.mixin; - -import net.minecraft.client.renderer.entity.player.PlayerRenderer; -import net.minecraft.util.Mth; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(PlayerRenderer.class) -public abstract class MixinPlayerRenderer { - @Redirect(method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V", at = @At(value = "INVOKE", target = "Ljava/lang/Math;acos(D)D")) - private double realcamera$fixVanillaFallFlying(double n) { - return Math.acos(Mth.clamp(n, -1.0, 1.0)); - } -} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java index 61bd985f..c0cba4bd 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java @@ -3,20 +3,20 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.config.ConfigFile; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.entity.layers.StuckInBodyLayer; -import net.minecraft.world.entity.LivingEntity; +import net.minecraft.client.renderer.entity.state.AvatarRenderState; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(StuckInBodyLayer.class) -public abstract class MixinStuckInBodyLayer { - @Inject(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/entity/LivingEntity;FFFFFF)V", at = @At("HEAD"), cancellable = true) - private void realcamera$cancelRender(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T livingEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) { - if (livingEntity instanceof LocalPlayer && RealCameraCore.isRendering() && !ConfigFile.config().isClassic() && !ConfigFile.config().renderStuckObjects()) { +public abstract class MixinStuckInBodyLayer { + @Inject(method = "submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/renderer/entity/state/AvatarRenderState;FF)V", at = @At("HEAD"), cancellable = true) + private void realcamera$cancelRender(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, AvatarRenderState state, float yRot, float xRot, CallbackInfo ci) { + if (RealCameraCore.isRendering() && state.id == Minecraft.getInstance().getCameraEntity().getId() && !ConfigFile.config().isClassic() && !ConfigFile.config().renderStuckObjects()) { ci.cancel(); } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/AvatarRendererAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/AvatarRendererAccessor.java new file mode 100644 index 00000000..e59c811d --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/AvatarRendererAccessor.java @@ -0,0 +1,16 @@ +package com.xtracr.realcamera.mixin.accessor; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.entity.player.AvatarRenderer; +import net.minecraft.client.renderer.entity.state.AvatarRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(AvatarRenderer.class) +public interface AvatarRendererAccessor { + @Invoker + void invokeSetupRotations(AvatarRenderState renderState, PoseStack poseStack, float bodyRot, float entityScale); + + @Invoker + void invokeScale(AvatarRenderState renderState, PoseStack poseStack); +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/CameraAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/CameraAccessor.java deleted file mode 100644 index c536cc0e..00000000 --- a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/CameraAccessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.xtracr.realcamera.mixin.accessor; - -import net.minecraft.client.Camera; -import net.minecraft.world.phys.Vec3; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(Camera.class) -public interface CameraAccessor { - @Invoker - void invokeSetPosition(Vec3 position); -} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/CustomFeatureRenderer$StorageAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/CustomFeatureRenderer$StorageAccessor.java new file mode 100644 index 00000000..c428ad24 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/CustomFeatureRenderer$StorageAccessor.java @@ -0,0 +1,19 @@ +package com.xtracr.realcamera.mixin.accessor; + +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.feature.CustomFeatureRenderer; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.Map; + +@Mixin(CustomFeatureRenderer.Storage.class) +public interface CustomFeatureRenderer$StorageAccessor { + @Accessor + Map> getSolidCustomGeometrySubmits(); + + @Accessor + Map> getTranslucentCustomGeometrySubmits(); +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/GameRendererAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/GameRendererAccessor.java deleted file mode 100644 index 5f622e32..00000000 --- a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/GameRendererAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.xtracr.realcamera.mixin.accessor; - -import net.minecraft.client.renderer.GameRenderer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(GameRenderer.class) -public interface GameRendererAccessor { - @Accessor - float getFov(); - - @Accessor - float getOldFov(); -} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/GuiGraphicsExtractorAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/GuiGraphicsExtractorAccessor.java new file mode 100644 index 00000000..f1ac30ef --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/GuiGraphicsExtractorAccessor.java @@ -0,0 +1,15 @@ +package com.xtracr.realcamera.mixin.accessor; + +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.renderer.state.gui.GuiRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GuiGraphicsExtractor.class) +public interface GuiGraphicsExtractorAccessor { + @Accessor + GuiGraphicsExtractor.ScissorStack getScissorStack(); + + @Accessor + GuiRenderState getGuiRenderState(); +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelFeatureRenderer$StorageAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelFeatureRenderer$StorageAccessor.java new file mode 100644 index 00000000..938325c9 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelFeatureRenderer$StorageAccessor.java @@ -0,0 +1,19 @@ +package com.xtracr.realcamera.mixin.accessor; + +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.feature.ModelFeatureRenderer; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.Map; + +@Mixin(ModelFeatureRenderer.Storage.class) +public interface ModelFeatureRenderer$StorageAccessor { + @Accessor + Map>> getSolidModelSubmits(); + + @Accessor + List> getTranslucentModelSubmits(); +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelPartFeatureRenderer$StorageAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelPartFeatureRenderer$StorageAccessor.java new file mode 100644 index 00000000..77141613 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/ModelPartFeatureRenderer$StorageAccessor.java @@ -0,0 +1,19 @@ +package com.xtracr.realcamera.mixin.accessor; + +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.feature.ModelPartFeatureRenderer; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.Map; + +@Mixin(ModelPartFeatureRenderer.Storage.class) +public interface ModelPartFeatureRenderer$StorageAccessor { + @Accessor + Map> getSolidModelPartSubmits(); + + @Accessor + Map> getTranslucentModelPartSubmits(); +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/PlayerRendererAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/PlayerRendererAccessor.java deleted file mode 100644 index 4f3bb757..00000000 --- a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/PlayerRendererAccessor.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xtracr.realcamera.mixin.accessor; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.player.AbstractClientPlayer; -import net.minecraft.client.renderer.entity.player.PlayerRenderer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(PlayerRenderer.class) -public interface PlayerRendererAccessor { - @Invoker - void invokeSetModelProperties(AbstractClientPlayer abstractClientPlayer); - - @Invoker - void invokeSetupRotations(AbstractClientPlayer livingEntity, PoseStack poseStack, float f, float g, float deltaTick, float i); - - @Invoker - void invokeScale(AbstractClientPlayer livingEntity, PoseStack poseStack, float deltaTick); -} diff --git a/common/src/main/java/com/xtracr/realcamera/util/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java similarity index 93% rename from common/src/main/java/com/xtracr/realcamera/util/BuiltIterableBuffer.java rename to common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index 5f5e7f25..c3f0869b 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -1,10 +1,10 @@ -package com.xtracr.realcamera.util; - +package com.xtracr.realcamera.renderer; import com.mojang.blaze3d.vertex.MeshData; -import com.xtracr.realcamera.util.VertexData.UV; -import net.minecraft.client.renderer.RenderType; -import org.jetbrains.annotations.Nullable; +import com.xtracr.realcamera.renderer.state.VertexData; +import com.xtracr.realcamera.renderer.state.VertexData.UV; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.jspecify.annotations.Nullable; import java.awt.*; import java.util.HashMap; @@ -93,7 +93,7 @@ public boolean anyNotCached(UV[] uvs) { uvCache[j * 2] = primitive[j].u(); uvCache[j * 2 + 1] = primitive[j].v(); } - FIND_PRIMITIVE_CACHE.computeIfAbsent(renderType, k -> new HashMap<>()).put(uv, uvCache); + FIND_PRIMITIVE_CACHE.computeIfAbsent(renderType, _ -> new HashMap<>()).put(uv, uvCache); primitives[i] = VertexData.asImmutable(primitive); } return allFound; diff --git a/common/src/main/java/com/xtracr/realcamera/util/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java similarity index 86% rename from common/src/main/java/com/xtracr/realcamera/util/IterableVertexBuffer.java rename to common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index 8c67957b..d080fa59 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -1,13 +1,13 @@ -package com.xtracr.realcamera.util; +package com.xtracr.realcamera.renderer; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.MeshData; import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormatElement; -import com.xtracr.realcamera.util.VertexData.MutableVertex; -import net.minecraft.util.FastColor; +import com.xtracr.realcamera.renderer.state.VertexData; +import com.xtracr.realcamera.renderer.state.VertexData.MutableVertex; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NonNull; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -20,12 +20,13 @@ public class IterableVertexBuffer implements Iterable { private static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + private static final float NORMAL_SCALE = 1.0f / 127.0f; public final int vertexCount, vertexSize; private final MutableVertex reusableVertex = VertexData.mutable(); private final Iterable primitives; private final ByteBuffer buffer; private final int positionOffset, colorOffset, uvOffset, overlayOffset, lightOffset, normalOffset; - private final boolean hasPosition, hasColor, hasUV, hasOverlay, hasLight, hasNormal, fastFormat; + private final boolean hasPosition, hasColor, hasUV, hasOverlay, hasLight, hasNormal, fullFormat; public IterableVertexBuffer(MeshData meshData) { buffer = meshData.vertexBuffer(); @@ -45,9 +46,9 @@ public IterableVertexBuffer(MeshData meshData) { hasOverlay = overlayOffset != -1; hasLight = lightOffset != -1; hasNormal = normalOffset != -1; - fastFormat = format == DefaultVertexFormat.NEW_ENTITY; + fullFormat = vertexSize == DefaultVertexFormat.ENTITY.getVertexSize(); boolean isQuad = drawState.mode() == VertexFormat.Mode.QUADS; - primitives = fastFormat && isQuad ? new FastQuadReader() : new PrimitiveReader(drawState.mode()); + primitives = fullFormat && isQuad ? new FastQuadReader() : new PrimitiveReader(drawState.mode()); } public Iterable primitives() { @@ -63,13 +64,29 @@ public Stream primitiveStream() { } public VertexData readVertexAt(int index) { + Objects.checkIndex(index, vertexCount); return readVertexAt(index, reusableVertex); } - public MutableVertex readVertexAt(int index, MutableVertex mutable) { - Objects.checkIndex(index, vertexCount); + @Override + public @NonNull Iterator iterator() { + return new VertexIterator(); + } + + @Override + public Spliterator spliterator() { + return new VertexSpliterator(0, vertexCount); + } + + private int readColor(int offset) { + // net.minecraft.util.ARGB.fromABGR(abgr) + int abgr = IS_LITTLE_ENDIAN ? buffer.getInt(offset) : Integer.reverseBytes(buffer.getInt(offset)); + return (abgr & 0xFF00FF00) | (abgr & 0xFF0000) >> 16 | (abgr & 0xFF) << 16; + } + + private MutableVertex readVertexAt(int index, MutableVertex mutable) { int vertexOffset = index * vertexSize; - if (fastFormat) { + if (fullFormat) { mutable.x = buffer.getFloat(vertexOffset); mutable.y = buffer.getFloat(vertexOffset + 4); mutable.z = buffer.getFloat(vertexOffset + 8); @@ -78,9 +95,9 @@ public MutableVertex readVertexAt(int index, MutableVertex mutable) { mutable.v = buffer.getFloat(vertexOffset + 20); mutable.overlay = buffer.getInt(vertexOffset + 24); mutable.light = buffer.getInt(vertexOffset + 28); - mutable.normalX = buffer.get(vertexOffset + 32) / 127.0f; - mutable.normalY = buffer.get(vertexOffset + 33) / 127.0f; - mutable.normalZ = buffer.get(vertexOffset + 34) / 127.0f; + mutable.normalX = buffer.get(vertexOffset + 32) * NORMAL_SCALE; + mutable.normalY = buffer.get(vertexOffset + 33) * NORMAL_SCALE; + mutable.normalZ = buffer.get(vertexOffset + 34) * NORMAL_SCALE; return mutable; } if (hasPosition) { @@ -105,28 +122,13 @@ public MutableVertex readVertexAt(int index, MutableVertex mutable) { } if (hasNormal) { int offset = vertexOffset + normalOffset; - mutable.normalX = buffer.get(offset) / 127.0f; - mutable.normalY = buffer.get(offset + 1) / 127.0f; - mutable.normalZ = buffer.get(offset + 2) / 127.0f; + mutable.normalX = buffer.get(offset) * NORMAL_SCALE; + mutable.normalY = buffer.get(offset + 1) * NORMAL_SCALE; + mutable.normalZ = buffer.get(offset + 2) * NORMAL_SCALE; } return mutable; } - @Override - public @NotNull Iterator iterator() { - return new VertexIterator(); - } - - @Override - public Spliterator spliterator() { - return new VertexSpliterator(0, vertexCount); - } - - private int readColor(int offset) { - // ABGR2ARGB is the same as ARGB2ABGR - return FastColor.ABGR32.fromArgb32(IS_LITTLE_ENDIAN ? buffer.getInt(offset) : Integer.reverseBytes(buffer.getInt(offset))); - } - private class VertexPointer implements VertexData { protected int bytePointer = 0; @@ -150,7 +152,8 @@ public float z() { @Override public Vec3 position() { - if (hasPosition) return new Vec3(buffer.getFloat(bytePointer + positionOffset), buffer.getFloat(bytePointer + positionOffset + 4), buffer.getFloat(bytePointer + positionOffset + 8)); + if (hasPosition) + return new Vec3(buffer.getFloat(bytePointer + positionOffset), buffer.getFloat(bytePointer + positionOffset + 4), buffer.getFloat(bytePointer + positionOffset + 8)); return Vec3.ZERO; } @@ -174,7 +177,8 @@ public float v() { @Override public UV uv() { - if (hasUV) return new UV(buffer.getFloat(bytePointer + uvOffset), buffer.getFloat(bytePointer + uvOffset + 4)); + if (hasUV) + return new UV(buffer.getFloat(bytePointer + uvOffset), buffer.getFloat(bytePointer + uvOffset + 4)); return new UV(0, 0); } @@ -192,31 +196,32 @@ public int light() { @Override public float normalX() { - if (hasNormal) return buffer.get(bytePointer + normalOffset) / 127.0f; + if (hasNormal) return buffer.get(bytePointer + normalOffset) * NORMAL_SCALE; return 0; } @Override public float normalY() { - if (hasNormal) return buffer.get(bytePointer + normalOffset + 1) / 127.0f; + if (hasNormal) return buffer.get(bytePointer + normalOffset + 1) * NORMAL_SCALE; return 0; } @Override public float normalZ() { - if (hasNormal) return buffer.get(bytePointer + normalOffset + 2) / 127.0f; + if (hasNormal) return buffer.get(bytePointer + normalOffset + 2) * NORMAL_SCALE; return 0; } @Override public Vec3 normal() { - if (hasNormal) return new Vec3(buffer.get(bytePointer + normalOffset) / 127.0f, buffer.get(bytePointer + normalOffset + 1) / 127.0f, buffer.get(bytePointer + normalOffset + 2) / 127.0f); + if (hasNormal) + return new Vec3(buffer.get(bytePointer + normalOffset) * NORMAL_SCALE, buffer.get(bytePointer + normalOffset + 1) * NORMAL_SCALE, buffer.get(bytePointer + normalOffset + 2) * NORMAL_SCALE); return Vec3.ZERO; } @Override public VertexData asImmutable() { - if (fastFormat) { + if (fullFormat) { return new ImmutableVertex(buffer.getFloat(bytePointer), buffer.getFloat(bytePointer + 4), buffer.getFloat(bytePointer + 8), @@ -225,9 +230,9 @@ public VertexData asImmutable() { buffer.getFloat(bytePointer + 20), buffer.getInt(bytePointer + 24), buffer.getInt(bytePointer + 28), - buffer.get(bytePointer + 32) / 127.0f, - buffer.get(bytePointer + 33) / 127.0f, - buffer.get(bytePointer + 34) / 127.0f); + buffer.get(bytePointer + 32) * NORMAL_SCALE, + buffer.get(bytePointer + 33) * NORMAL_SCALE, + buffer.get(bytePointer + 34) * NORMAL_SCALE); } return VertexData.super.asImmutable(); } @@ -242,7 +247,7 @@ public boolean hasNext() { } @Override - public @NotNull VertexData next() { + public @NonNull VertexData next() { bytePointer += vertexSize; return this; } @@ -303,7 +308,7 @@ public PrimitiveReader(VertexFormat.Mode drawMode) { } @Override - public @NotNull Iterator iterator() { + public @NonNull Iterator iterator() { return new PrimitiveIterator(); } @@ -397,7 +402,7 @@ private class FastQuadReader implements Iterable { private final int quadCount = vertexCount / 4; @Override - public @NotNull Iterator iterator() { + public @NonNull Iterator iterator() { return new FastQuadIterator(); } @@ -418,9 +423,9 @@ private void fastReadQuadAt(int index, MutableVertex[] quad) { mutable.v = buffer.getFloat(vertexOffset + 20); mutable.overlay = buffer.getInt(vertexOffset + 24); mutable.light = buffer.getInt(vertexOffset + 28); - mutable.normalX = buffer.get(vertexOffset + 32) / 127.0f; - mutable.normalY = buffer.get(vertexOffset + 33) / 127.0f; - mutable.normalZ = buffer.get(vertexOffset + 34) / 127.0f; + mutable.normalX = buffer.get(vertexOffset + 32) * NORMAL_SCALE; + mutable.normalY = buffer.get(vertexOffset + 33) * NORMAL_SCALE; + mutable.normalZ = buffer.get(vertexOffset + 34) * NORMAL_SCALE; } } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java new file mode 100644 index 00000000..43ff4b47 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java @@ -0,0 +1,195 @@ +package com.xtracr.realcamera.renderer; + +import com.mojang.blaze3d.vertex.*; +import com.xtracr.realcamera.mixin.accessor.CustomFeatureRenderer$StorageAccessor; +import com.xtracr.realcamera.mixin.accessor.ModelFeatureRenderer$StorageAccessor; +import com.xtracr.realcamera.mixin.accessor.ModelPartFeatureRenderer$StorageAccessor; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMaps; +import net.minecraft.client.model.Model; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.SubmitNodeCollection; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.SubmitNodeStorage; +import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.jspecify.annotations.NonNull; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.SequencedMap; +import java.util.function.Consumer; + +public class MultiVertexCatcher { + private final SubmitNodeStorage storage = new SubmitNodeStorage(); + private final MeshCatcher meshCatcher = new MeshCatcher(); + + private MultiVertexCatcher() { } + + public static MultiVertexCatcher create() { + return new MultiVertexCatcher(); + } + + private static void renderModel(PoseStack poseStack, SubmitNodeStorage.ModelSubmit submit, VertexConsumer buffer) { + poseStack.pushPose(); + poseStack.last().set(submit.pose()); + Model model = submit.model(); + //noinspection resource + VertexConsumer wrappedBuffer = submit.sprite() == null ? buffer : submit.sprite().wrap(buffer); + model.setupAnim(submit.state()); + model.renderToBuffer(poseStack, wrappedBuffer, submit.lightCoords(), submit.overlayCoords(), submit.tintedColor()); + poseStack.popPose(); + } + + private static void renderModelParts(PoseStack poseStack, Map> modelPartSubmitsMap, MultiBufferSource.BufferSource bufferSource) { + poseStack.pushPose(); + for (Map.Entry> entry : modelPartSubmitsMap.entrySet()) { + RenderType renderType = entry.getKey(); + List modelPartSubmits = entry.getValue(); + VertexConsumer buffer = bufferSource.getBuffer(renderType); + + for (SubmitNodeStorage.ModelPartSubmit submit : modelPartSubmits) { + //noinspection resource + VertexConsumer wrappedBuffer = submit.sprite() == null ? buffer : submit.sprite().wrap(buffer); + poseStack.last().set(submit.pose()); + submit.modelPart().render(poseStack, wrappedBuffer, submit.lightCoords(), submit.overlayCoords(), submit.tintedColor()); + } + } + poseStack.popPose(); + } + + private static void renderCustomGeometry(Map> customGeometrySubmits, MultiBufferSource.BufferSource bufferSource) { + for (Map.Entry> entry : customGeometrySubmits.entrySet()) { + VertexConsumer buffer = bufferSource.getBuffer(entry.getKey()); + for (SubmitNodeStorage.CustomGeometrySubmit customGeometrySubmit : entry.getValue()) { + customGeometrySubmit.customGeometryRenderer().render(customGeometrySubmit.pose(), buffer); + } + } + } + + /** @see FeatureRenderDispatcher#renderSolidFeatures() */ + private void renderSolidFeatures() { + for (SubmitNodeCollection collection : storage.getSubmitsPerOrder().values()) { + PoseStack poseStack = new PoseStack(); + for (Map.Entry>> entry : ((ModelFeatureRenderer$StorageAccessor) collection.getModelSubmits()).getSolidModelSubmits().entrySet()) { + VertexConsumer buffer = meshCatcher.getBuffer(entry.getKey()); + for (SubmitNodeStorage.ModelSubmit submit : entry.getValue()) { + renderModel(poseStack, submit, buffer); + } + } + renderModelParts(poseStack, ((ModelPartFeatureRenderer$StorageAccessor) collection.getModelPartSubmits()).getSolidModelPartSubmits(), meshCatcher); + renderCustomGeometry(((CustomFeatureRenderer$StorageAccessor) collection.getCustomGeometrySubmits()).getSolidCustomGeometrySubmits(), meshCatcher); + } + } + + /** @see FeatureRenderDispatcher#renderTranslucentFeatures() */ + private void renderTranslucentFeatures() { + for (SubmitNodeCollection collection : storage.getSubmitsPerOrder().values()) { + PoseStack poseStack = new PoseStack(); + for (SubmitNodeStorage.TranslucentModelSubmit submit : ((ModelFeatureRenderer$StorageAccessor) collection.getModelSubmits()).getTranslucentModelSubmits()) { + renderModel(poseStack, submit.modelSubmit(), meshCatcher.getBuffer(submit.renderType())); + } + renderModelParts(poseStack, ((ModelPartFeatureRenderer$StorageAccessor) collection.getModelPartSubmits()).getTranslucentModelPartSubmits(), meshCatcher); + renderCustomGeometry(((CustomFeatureRenderer$StorageAccessor) collection.getCustomGeometrySubmits()).getTranslucentCustomGeometrySubmits(), meshCatcher); + } + } + + public SubmitNodeCollector initCollector() { + meshCatcher.initialize(); + return storage; + } + + public void endCatching(Consumer consumer) { + if (storage.getSubmitsPerOrder().isEmpty()) return; + renderSolidFeatures(); + renderTranslucentFeatures(); + storage.clear(); + meshCatcher.endCatching(consumer); + } + + static class MeshCatcher extends MultiBufferSource.BufferSource { + private final SequencedMap bufferPools = new Object2ObjectLinkedOpenHashMap<>(); + private final SequencedMap caughtMeshes = new Object2ObjectLinkedOpenHashMap<>(); + + protected MeshCatcher() { + super(new ByteBufferBuilder(0), Object2ObjectSortedMaps.emptyMap()); + } + + @Override + public @NonNull VertexConsumer getBuffer(@NonNull RenderType renderType) { + BufferBuilder bufferBuilder = startedBuilders.get(renderType); + if (bufferBuilder != null) { + endBatch(renderType, bufferBuilder); + } + ByteBufferBuilderPool bufferPool = bufferPools.computeIfAbsent(renderType, type -> new ByteBufferBuilderPool(type.bufferSize())); + bufferBuilder = new BufferBuilder(bufferPool.getBuffer(), renderType.mode(), renderType.format()); + startedBuilders.put(renderType, bufferBuilder); + return bufferBuilder; + } + + public void initialize() { + for (MeshData meshData : caughtMeshes.keySet()) { + meshData.close(); + } + caughtMeshes.clear(); + bufferPools.values().forEach(ByteBufferBuilderPool::release); + } + + public void endCatching(Consumer consumer) { + endBatch(); + for (Map.Entry entry : caughtMeshes.entrySet()) { + MeshData meshData = entry.getKey(); + consumer.accept(BuiltIterableBuffer.buildFrom(entry.getValue(), meshData)); + } + } + + @Override + public void endBatch() { + for (RenderType renderType : bufferPools.keySet()) { + endBatch(renderType); + } + } + + @Override + public void endBatch(@NonNull RenderType type) { + BufferBuilder builder = this.startedBuilders.remove(type); + if (builder != null) { + endBatch(type, builder); + } + } + + @Override + protected void endBatch(@NonNull RenderType renderType, BufferBuilder bufferBuilder) { + MeshData meshData = bufferBuilder.build(); + if (meshData != null) { + caughtMeshes.put(meshData, renderType); + } + } + + private static class ByteBufferBuilderPool { + private final int bufferSize; + private ByteBufferBuilder[] pool = new ByteBufferBuilder[0]; + private int next = 0; + + public ByteBufferBuilderPool(int bufferSize) { + this.bufferSize = bufferSize; + } + + public ByteBufferBuilder getBuffer() { + ByteBufferBuilder byteBufferBuilder; + if (next < pool.length) { + byteBufferBuilder = pool[next++]; + } else { + pool = Arrays.copyOf(pool, pool.length + 1); + pool[next++] = byteBufferBuilder = new ByteBufferBuilder(bufferSize); + } + return byteBufferBuilder; + } + + public void release() { + next = 0; + } + } + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java b/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java new file mode 100644 index 00000000..fcd8c0cf --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java @@ -0,0 +1,182 @@ +package com.xtracr.realcamera.renderer; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.Font; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.OrderedSubmitNodeCollector; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.block.MovingBlockRenderState; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.client.renderer.feature.ModelFeatureRenderer; +import net.minecraft.client.renderer.item.ItemStackRenderState; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.state.level.CameraRenderState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import java.util.List; + +public class RoutingSubmitCollector implements SubmitNodeCollector { + private final SubmitNodeCollector defaultCollector; + private final SubmitNodeCollector modelCollector; + + public RoutingSubmitCollector(SubmitNodeCollector defaultCollector, SubmitNodeCollector modelCollector) { + this.defaultCollector = defaultCollector; + this.modelCollector = modelCollector; + } + + @Override + public @NonNull OrderedSubmitNodeCollector order(int order) { + return new RoutingOrderedCollector(order); + } + + @Override + public void submitShadow(@NonNull PoseStack poseStack, float radius, @NonNull List pieces) { + defaultCollector.submitShadow(poseStack, radius, pieces); + } + + @Override + public void submitNameTag(@NonNull PoseStack poseStack, @Nullable Vec3 nameTagAttachment, int offset, @NonNull Component name, boolean seeThrough, int lightCoords, double distanceToCameraSq, @NonNull CameraRenderState camera) { + defaultCollector.submitNameTag(poseStack, nameTagAttachment, offset, name, seeThrough, lightCoords, distanceToCameraSq, camera); + } + + @Override + public void submitText(@NonNull PoseStack poseStack, float x, float y, @NonNull FormattedCharSequence string, boolean dropShadow, Font.@NonNull DisplayMode displayMode, int lightCoords, int color, int backgroundColor, int outlineColor) { + defaultCollector.submitText(poseStack, x, y, string, dropShadow, displayMode, lightCoords, color, backgroundColor, outlineColor); + } + + @Override + public void submitFlame(@NonNull PoseStack poseStack, @NonNull EntityRenderState renderState, @NonNull Quaternionf rotation) { + defaultCollector.submitFlame(poseStack, renderState, rotation); + } + + @Override + public void submitLeash(@NonNull PoseStack poseStack, EntityRenderState.@NonNull LeashState leashState) { + defaultCollector.submitLeash(poseStack, leashState); + } + + @Override + public void submitModel(@NonNull Model model, @NonNull S state, @NonNull PoseStack poseStack, @NonNull RenderType renderType, int lightCoords, int overlayCoords, int tintedColor, @Nullable TextureAtlasSprite sprite, int outlineColor, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) { + modelCollector.submitModel(model, state, poseStack, renderType, lightCoords, overlayCoords, tintedColor, sprite, outlineColor, crumblingOverlay); + } + + @Override + public void submitModelPart(@NonNull ModelPart modelPart, @NonNull PoseStack poseStack, @NonNull RenderType renderType, int lightCoords, int overlayCoords, @Nullable TextureAtlasSprite sprite, boolean sheeted, boolean hasFoil, int tintedColor, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay, int outlineColor) { + modelCollector.submitModelPart(modelPart, poseStack, renderType, lightCoords, overlayCoords, sprite, sheeted, hasFoil, tintedColor, crumblingOverlay, outlineColor); + } + + @Override + public void submitMovingBlock(@NonNull PoseStack poseStack, @NonNull MovingBlockRenderState movingBlockRenderState) { + defaultCollector.submitMovingBlock(poseStack, movingBlockRenderState); + } + + @Override + public void submitBlockModel(@NonNull PoseStack poseStack, @NonNull RenderType renderType, @NonNull List parts, int @NonNull [] tintLayers, int lightCoords, int overlayCoords, int outlineColor) { + defaultCollector.submitBlockModel(poseStack, renderType, parts, tintLayers, lightCoords, overlayCoords, outlineColor); + } + + @Override + public void submitBreakingBlockModel(@NonNull PoseStack poseStack, @NonNull BlockStateModel model, long seed, int progress) { + defaultCollector.submitBreakingBlockModel(poseStack, model, seed, progress); + } + + @Override + public void submitItem(@NonNull PoseStack poseStack, @NonNull ItemDisplayContext displayContext, int lightCoords, int overlayCoords, int outlineColor, int @NonNull [] tintLayers, @NonNull List quads, ItemStackRenderState.@NonNull FoilType foilType) { + defaultCollector.submitItem(poseStack, displayContext, lightCoords, overlayCoords, outlineColor, tintLayers, quads, foilType); + } + + @Override + public void submitCustomGeometry(@NonNull PoseStack poseStack, @NonNull RenderType renderType, @NonNull CustomGeometryRenderer customGeometryRenderer) { + modelCollector.submitCustomGeometry(poseStack, renderType, customGeometryRenderer); + } + + @Override + public void submitParticleGroup(@NonNull ParticleGroupRenderer particleGroupRenderer) { + defaultCollector.submitParticleGroup(particleGroupRenderer); + } + + private class RoutingOrderedCollector implements OrderedSubmitNodeCollector { + private final OrderedSubmitNodeCollector defaultDelegate; + private final OrderedSubmitNodeCollector modelDelegate; + + RoutingOrderedCollector(int order) { + this.defaultDelegate = defaultCollector.order(order); + this.modelDelegate = modelCollector.order(order); + } + + @Override + public void submitShadow(@NonNull PoseStack poseStack, float radius, @NonNull List pieces) { + defaultDelegate.submitShadow(poseStack, radius, pieces); + } + + @Override + public void submitNameTag(@NonNull PoseStack poseStack, @Nullable Vec3 nameTagAttachment, int offset, @NonNull Component name, boolean seeThrough, int lightCoords, double distanceToCameraSq, @NonNull CameraRenderState camera) { + defaultDelegate.submitNameTag(poseStack, nameTagAttachment, offset, name, seeThrough, lightCoords, distanceToCameraSq, camera); + } + + @Override + public void submitText(@NonNull PoseStack poseStack, float x, float y, @NonNull FormattedCharSequence string, boolean dropShadow, Font.@NonNull DisplayMode displayMode, int lightCoords, int color, int backgroundColor, int outlineColor) { + defaultDelegate.submitText(poseStack, x, y, string, dropShadow, displayMode, lightCoords, color, backgroundColor, outlineColor); + } + + @Override + public void submitFlame(@NonNull PoseStack poseStack, @NonNull EntityRenderState renderState, @NonNull Quaternionf rotation) { + defaultDelegate.submitFlame(poseStack, renderState, rotation); + } + + @Override + public void submitLeash(@NonNull PoseStack poseStack, EntityRenderState.@NonNull LeashState leashState) { + defaultDelegate.submitLeash(poseStack, leashState); + } + + @Override + public void submitModel(@NonNull Model model, @NonNull S state, @NonNull PoseStack poseStack, @NonNull RenderType renderType, int lightCoords, int overlayCoords, int tintedColor, @Nullable TextureAtlasSprite sprite, int outlineColor, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) { + modelDelegate.submitModel(model, state, poseStack, renderType, lightCoords, overlayCoords, tintedColor, sprite, outlineColor, crumblingOverlay); + } + + @Override + public void submitModelPart(@NonNull ModelPart modelPart, @NonNull PoseStack poseStack, @NonNull RenderType renderType, int lightCoords, int overlayCoords, @Nullable TextureAtlasSprite sprite, boolean sheeted, boolean hasFoil, int tintedColor, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay, int outlineColor) { + modelDelegate.submitModelPart(modelPart, poseStack, renderType, lightCoords, overlayCoords, sprite, sheeted, hasFoil, tintedColor, crumblingOverlay, outlineColor); + } + + @Override + public void submitMovingBlock(@NonNull PoseStack poseStack, @NonNull MovingBlockRenderState movingBlockRenderState) { + defaultDelegate.submitMovingBlock(poseStack, movingBlockRenderState); + } + + @Override + public void submitBlockModel(@NonNull PoseStack poseStack, @NonNull RenderType renderType, @NonNull List parts, int @NonNull [] tintLayers, int lightCoords, int overlayCoords, int outlineColor) { + defaultDelegate.submitBlockModel(poseStack, renderType, parts, tintLayers, lightCoords, overlayCoords, outlineColor); + } + + @Override + public void submitBreakingBlockModel(@NonNull PoseStack poseStack, @NonNull BlockStateModel model, long seed, int progress) { + defaultDelegate.submitBreakingBlockModel(poseStack, model, seed, progress); + } + + @Override + public void submitItem(@NonNull PoseStack poseStack, @NonNull ItemDisplayContext displayContext, int lightCoords, int overlayCoords, int outlineColor, int @NonNull [] tintLayers, @NonNull List quads, ItemStackRenderState.@NonNull FoilType foilType) { + defaultDelegate.submitItem(poseStack, displayContext, lightCoords, overlayCoords, outlineColor, tintLayers, quads, foilType); + } + + @Override + public void submitCustomGeometry(@NonNull PoseStack poseStack, @NonNull RenderType renderType, @NonNull CustomGeometryRenderer customGeometryRenderer) { + modelDelegate.submitCustomGeometry(poseStack, renderType, customGeometryRenderer); + } + + @Override + public void submitParticleGroup(@NonNull ParticleGroupRenderer particleGroupRenderer) { + defaultDelegate.submitParticleGroup(particleGroupRenderer); + } + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java new file mode 100644 index 00000000..25c39b35 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java @@ -0,0 +1,58 @@ +package com.xtracr.realcamera.renderer.gui; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; +import com.xtracr.realcamera.renderer.state.VertexData; +import com.xtracr.realcamera.renderer.state.gui.GuiCulledModelsRenderState; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.jspecify.annotations.NonNull; + +public class GuiCulledModelsRenderer extends PictureInPictureRenderer { + public GuiCulledModelsRenderer(MultiBufferSource.BufferSource bufferSource) { + super(bufferSource); + } + + @Override + public @NonNull Class getRenderStateClass() { + return GuiCulledModelsRenderState.class; + } + + @Override + protected void renderToTexture(@NonNull GuiCulledModelsRenderState renderState, @NonNull PoseStack poseStack) { + poseStack.mulPose(renderState.transform()); + + float minEntityZ = 0f, maxEntityZ = 200f; + for (BuiltModelRecord record : renderState.records()) { + for (VertexData vertex : record.vertices()) { + if (vertex.z() < minEntityZ) minEntityZ = vertex.z(); + if (vertex.z() > maxEntityZ) maxEntityZ = vertex.z(); + } + } + Matrix4f positionMatrix = poseStack.last().pose().scale(1, 1, 200 / (maxEntityZ - minEntityZ)).translate(0, 0, -minEntityZ); + Matrix3f normalMatrix = new Matrix3f(positionMatrix); + for (BuiltModelRecord record : renderState.records()) { + VertexConsumer buffer = bufferSource.getBuffer(record.renderType()); + if (!record.renderType().canConsolidateConsecutiveGeometry()) { + for (VertexData vertex : record.vertices()) vertex.render(buffer, positionMatrix, normalMatrix); + return; + } + for (VertexData[] primitive : record.primitives()) { + for (VertexData vertex : primitive) vertex.render(buffer, positionMatrix, normalMatrix); + } + } + } + + @Override + protected float getTranslateY(final int height, final int guiScale) { + return height / 2.0f; + } + + @Override + protected @NonNull String getTextureLabel() { + return "realcamera.culled_model"; + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java new file mode 100644 index 00000000..2513538e --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java @@ -0,0 +1,49 @@ +package com.xtracr.realcamera.renderer.gui; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; +import com.xtracr.realcamera.renderer.state.VertexData; +import com.xtracr.realcamera.renderer.state.gui.GuiFlattenedModelsRenderState; +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.jspecify.annotations.NonNull; + +public class GuiFlattenedModelsRenderer extends PictureInPictureRenderer { + public GuiFlattenedModelsRenderer(MultiBufferSource.BufferSource bufferSource) { + super(bufferSource); + } + + @Override + public @NonNull Class getRenderStateClass() { + return GuiFlattenedModelsRenderState.class; + } + + @Override + protected void renderToTexture(@NonNull GuiFlattenedModelsRenderState renderState, @NonNull PoseStack poseStack) { + Vector3f translation = renderState.translation(); + poseStack.translate(translation.x, translation.y, translation.z); + + Matrix4f positionMatrix = poseStack.last().pose(); + for (BuiltModelRecord record : renderState.records()) { + VertexConsumer buffer = bufferSource.getBuffer(record.renderType()); + Vector3f position = new Vector3f(); + for (VertexData vertex : record.vertices()) { + position.set(vertex.u(), vertex.v(), 0).mulPosition(positionMatrix); + buffer.addVertex(position.x(), position.y(), 0, vertex.argb(), vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); + } + } + } + + @Override + protected float getTranslateY(final int height, final int guiScale) { + return height / 2.0f; + } + + @Override + protected @NonNull String getTextureLabel() { + return "realcamera.texture"; + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/BuiltModelRecord.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/BuiltModelRecord.java new file mode 100644 index 00000000..14ed4d49 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/BuiltModelRecord.java @@ -0,0 +1,14 @@ +package com.xtracr.realcamera.renderer.state; + +import net.minecraft.client.renderer.rendertype.RenderType; + +public record BuiltModelRecord( + RenderType renderType, + String textureId, + VertexData[] vertices, + VertexData[][] primitives +) { + public boolean containsTextureId(String textureId) { + return this.textureId.contains(textureId); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/util/VertexData.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java similarity index 99% rename from common/src/main/java/com/xtracr/realcamera/util/VertexData.java rename to common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java index 36b4427d..63e97959 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/VertexData.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java @@ -1,4 +1,4 @@ -package com.xtracr.realcamera.util; +package com.xtracr.realcamera.renderer.state; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.world.phys.Vec3; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java new file mode 100644 index 00000000..565a5289 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java @@ -0,0 +1,63 @@ +package com.xtracr.realcamera.renderer.state.gui; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.gui.GUIHelper; +import com.xtracr.realcamera.util.MathUtil; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.state.gui.GuiElementRenderState; +import org.joml.Matrix3x2f; +import org.joml.Vector2f; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +public record ColoredFloatLineRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + float x, + float y, + float z, + float vectorX, + float vectorY, + float vectorZ, + int argb, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements GuiElementRenderState { + public ColoredFloatLineRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + float x, + float y, + float z, + float vectorX, + float vectorY, + float vectorZ, + int argb, + @Nullable ScreenRectangle scissorArea + ) { + this(pipeline, textureSetup, pose, x, y, z, vectorX, vectorY, vectorZ, argb, scissorArea, + GUIHelper.getBounds((int) MathUtil.floor(x, x + vectorX), (int) MathUtil.floor(y, y + vectorY), + (int) MathUtil.ceil(x, x + vectorX), (int) MathUtil.ceil(x, x + vectorX), pose, scissorArea)); + } + + @Override + public void buildVertices(@NonNull VertexConsumer vertexConsumer) { + Vector2f vec = pose.transformPosition(vectorX, vectorY, new Vector2f()); + if (pipeline.getVertexFormatMode().primitiveLength == 2) { + vertexConsumer.addVertexWith2DPose(pose, x, y).setColor(argb).setNormal(vec.x(), vec.y(), vectorZ); + vertexConsumer.addVertexWith2DPose(pose, x + vectorX, y + vectorY).setColor(argb).setNormal(vec.x(), vec.y(), vectorZ); + } else { + Vector2f start = pose.transformPosition(x, y, new Vector2f()); + Vector2f end = start.add(vec, new Vector2f()); + Vector2f normal = vec.normalize(new Vector2f()).mul(0.5f); + vertexConsumer.addVertex(start.x() - normal.y(), start.y() + normal.x(), z).setColor(argb); + vertexConsumer.addVertex(end.x() - normal.y(), end.y() + normal.x(), z + vectorZ).setColor(argb); + vertexConsumer.addVertex(end.x() + normal.y(), end.y() - normal.x(), z + vectorZ).setColor(argb); + vertexConsumer.addVertex(start.x() + normal.y(), start.y() - normal.x(), z).setColor(argb); + } + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatQuadRenderState.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatQuadRenderState.java new file mode 100644 index 00000000..ed4382ed --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatQuadRenderState.java @@ -0,0 +1,64 @@ +package com.xtracr.realcamera.renderer.state.gui; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.gui.GUIHelper; +import com.xtracr.realcamera.util.MathUtil; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.state.gui.GuiElementRenderState; +import org.joml.Matrix3x2f; +import org.jspecify.annotations.Nullable; + +public record ColoredFloatQuadRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + float x0, + float y0, + float z0, + float x1, + float y1, + float z1, + float x2, + float y2, + float z2, + float x3, + float y3, + float z3, + int argb, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements GuiElementRenderState { + public ColoredFloatQuadRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + float x0, + float y0, + float z0, + float x1, + float y1, + float z1, + float x2, + float y2, + float z2, + float x3, + float y3, + float z3, + int argb, + @Nullable ScreenRectangle scissorArea + ) { + this(pipeline, textureSetup, pose, x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3, argb, scissorArea, + GUIHelper.getBounds((int) MathUtil.floor(x0, x1, x2, x3), (int) MathUtil.floor(y0, y1, y2, y3), + (int) MathUtil.ceil(x0, x1, x2, x3), (int) MathUtil.ceil(y0, y1, y2, y3), pose, scissorArea)); + } + + @Override + public void buildVertices(VertexConsumer vertexConsumer) { + vertexConsumer.addVertexWith2DPose(pose, x0, y0).setColor(argb); + vertexConsumer.addVertexWith2DPose(pose, x1, y1).setColor(argb); + vertexConsumer.addVertexWith2DPose(pose, x2, y2).setColor(argb); + vertexConsumer.addVertexWith2DPose(pose, x3, y3).setColor(argb); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatRectangleRenderState.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatRectangleRenderState.java new file mode 100644 index 00000000..4ef2c7d7 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatRectangleRenderState.java @@ -0,0 +1,48 @@ +package com.xtracr.realcamera.renderer.state.gui; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.gui.GUIHelper; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.state.gui.GuiElementRenderState; +import org.joml.Matrix3x2f; +import org.jspecify.annotations.Nullable; + +public record ColoredFloatRectangleRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + float x0, + float y0, + float x1, + float y1, + float z, + int argb, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements GuiElementRenderState { + public ColoredFloatRectangleRenderState( + RenderPipeline pipeline, + TextureSetup textureSetup, + Matrix3x2f pose, + float x0, + float y0, + float x1, + float y1, + float z, + int argb, + @Nullable ScreenRectangle scissorArea + ) { + this(pipeline, textureSetup, pose, x0, y0, x1, y1, z, argb, scissorArea, + GUIHelper.getBounds((int) Math.floor(x0), (int) Math.floor(y0), (int) Math.ceil(x1), (int) Math.ceil(y1), pose, scissorArea)); + } + + @Override + public void buildVertices(VertexConsumer vertexConsumer) { + vertexConsumer.addVertexWith2DPose(pose, x0, y0).setColor(argb); + vertexConsumer.addVertexWith2DPose(pose, x0, y1).setColor(argb); + vertexConsumer.addVertexWith2DPose(pose, x1, y1).setColor(argb); + vertexConsumer.addVertexWith2DPose(pose, x1, y0).setColor(argb); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiCulledModelsRenderState.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiCulledModelsRenderState.java new file mode 100644 index 00000000..8aec1f5a --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiCulledModelsRenderState.java @@ -0,0 +1,34 @@ +package com.xtracr.realcamera.renderer.state.gui; + +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.renderer.state.gui.pip.PictureInPictureRenderState; +import org.joml.Matrix4f; +import org.jspecify.annotations.Nullable; + +import java.util.List; + +public record GuiCulledModelsRenderState( + List records, + Matrix4f transform, + int x0, + int y0, + int x1, + int y1, + float scale, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements PictureInPictureRenderState { + public GuiCulledModelsRenderState( + List records, + Matrix4f transform, + int x0, + int y0, + int x1, + int y1, + float scale, + @Nullable ScreenRectangle scissorArea + ) { + this(records, transform, x0, y0, x1, y1, scale, scissorArea, PictureInPictureRenderState.getBounds(x0, y0, x1, y1, scissorArea)); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiFlattenedModelsRenderState.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiFlattenedModelsRenderState.java new file mode 100644 index 00000000..009477c4 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/GuiFlattenedModelsRenderState.java @@ -0,0 +1,34 @@ +package com.xtracr.realcamera.renderer.state.gui; + +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.renderer.state.gui.pip.PictureInPictureRenderState; +import org.joml.Vector3f; +import org.jspecify.annotations.Nullable; + +import java.util.List; + +public record GuiFlattenedModelsRenderState( + List records, + Vector3f translation, + int x0, + int y0, + int x1, + int y1, + float scale, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements PictureInPictureRenderState { + public GuiFlattenedModelsRenderState( + List records, + Vector3f translation, + int x0, + int y0, + int x1, + int y1, + float scale, + @Nullable ScreenRectangle scissorArea + ) { + this(records, translation, x0, y0, x1, y1, scale, scissorArea, PictureInPictureRenderState.getBounds(x0, y0, x1, y1, scissorArea)); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java b/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java new file mode 100644 index 00000000..8009ce19 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java @@ -0,0 +1,40 @@ +package com.xtracr.realcamera.util; + +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix3f; +import org.joml.Matrix3fc; +import org.joml.Quaterniond; +import org.joml.Quaterniondc; + +public class CameraTransform { + protected final Matrix3f rotation = new Matrix3f(); + protected Vec3 position = Vec3.ZERO; + + public final Vec3 getPosition() { + return position; + } + + public final void setPosition(Vec3 vec) { + position = vec; + } + + public final Matrix3f getRotation() { + return rotation; + } + + public final void setRotation(Matrix3fc mat) { + rotation.set(mat); + } + + public final void lerpPosition(Vec3 vec, double a) { + position = position.lerp(vec, a); + } + + public final void slerpRotation(Matrix3fc mat, double alpha) { + slerpRotation(new Quaterniond().setFromNormalized(mat), alpha); + } + + public final void slerpRotation(Quaterniondc quat, double alpha) { + new Quaterniond().setFromNormalized(rotation).slerp(quat, alpha).get(rotation); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java b/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java index 7a322261..557c7dcb 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java @@ -1,29 +1,28 @@ package com.xtracr.realcamera.util; import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4f; +import org.joml.Matrix3x2fStack; +import org.joml.Matrix4fc; public class CrosshairUtil { public static EntityHitResult capturedEntityHitResult; public static Vec3 offset = Vec3.ZERO; - public static void translateMatrices(PoseStack poseStack) { - poseStack.translate(offset.x(), -offset.y(), 0.0d); + public static void translateMatrices(Matrix3x2fStack poseStack) { + poseStack.translate((float) offset.x, (float) -offset.y); } - public static void update(Minecraft client, Camera camera, Matrix4f... projectionMatrices) { + public static void update(Minecraft client, Vec3 cameraPos, Matrix4fc... projectionMatrices) { HitResult hitResult = client.hitResult; offset = Vec3.ZERO; if (client.crosshairPickEntity != null) hitResult = capturedEntityHitResult; if (hitResult == null) return; Window window = client.getWindow(); - offset = MathUtil.projectToVec2(hitResult.getLocation().subtract(camera.getPosition()), projectionMatrices) + offset = MathUtil.projectToVec2(hitResult.getLocation().subtract(cameraPos), projectionMatrices) .multiply(0.5 * window.getGuiScaledWidth(), 0.5 * window.getGuiScaledHeight(), 0.0d); } } diff --git a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java index 6b369f72..ab939a6a 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -2,7 +2,7 @@ import net.minecraft.world.phys.Vec3; import org.joml.Matrix3f; -import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Vector4f; public class MathUtil { @@ -10,6 +10,22 @@ public static double round(double d, int digits) { return Math.round(d * Math.pow(10, digits)) / Math.pow(10, digits); } + public static double floor(double... ds) { + double d = ds[0]; + for (int i = 1; i < ds.length; i++) { + d = Math.min(d, ds[i]); + } + return Math.floor(d); + } + + public static double ceil(double... ds) { + double d = ds[0]; + for (int i = 1; i < ds.length; i++) { + d = Math.max(d, ds[i]); + } + return Math.ceil(d); + } + public static Vec3 getEulerAngleYXZ(Matrix3f normal) { if (normal.m21 <= -1.0) return new Vec3(Math.PI / 2, Math.atan2(normal.m10, normal.m00), 0.0); else if (normal.m21 >= 1.0) return new Vec3(-Math.PI / 2, -Math.atan2(normal.m10, normal.m00), 0.0); @@ -24,9 +40,9 @@ public static Vec3 getIntersectionPoint(Vec3 planePoint, Vec3 planeNormal, Vec3 return linePoint.add(lineNormal.scale(distance)); } - public static Vec3 projectToVec2(Vec3 vec3, Matrix4f... projectionMatrices) { + public static Vec3 projectToVec2(Vec3 vec3, Matrix4fc... projectionMatrices) { Vector4f vector4f = new Vector4f((float) vec3.x(), (float) vec3.y(), (float) vec3.z(), 1.0f); - for (Matrix4f matrix4f : projectionMatrices) vector4f.mul(matrix4f); + for (Matrix4fc matrix4f : projectionMatrices) vector4f.mul(matrix4f); if (vector4f.w() == 0.0) return Vec3.ZERO; return new Vec3(vector4f.x(), vector4f.y(), 0).scale(1 / (double) vector4f.w()); } diff --git a/common/src/main/java/com/xtracr/realcamera/util/MultiVertexCatcher.java b/common/src/main/java/com/xtracr/realcamera/util/MultiVertexCatcher.java deleted file mode 100644 index 5e456621..00000000 --- a/common/src/main/java/com/xtracr/realcamera/util/MultiVertexCatcher.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.xtracr.realcamera.util; - -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.ByteBufferBuilder; -import com.mojang.blaze3d.vertex.MeshData; -import com.mojang.blaze3d.vertex.VertexConsumer; -import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMaps; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.SequencedMap; -import java.util.function.Consumer; - -public interface MultiVertexCatcher extends MultiBufferSource { - static MultiVertexCatcher defaultImpl() { - return MeshCatcher.INSTANCE; - } - - void endCatching(Consumer consumer); - - class MeshCatcher extends MultiBufferSource.BufferSource implements MultiVertexCatcher { - private static final MeshCatcher INSTANCE = new MeshCatcher(); - private final SequencedMap bufferPools = new Object2ObjectLinkedOpenHashMap<>(); - private final SequencedMap caughtMeshes = new Object2ObjectLinkedOpenHashMap<>(); - - protected MeshCatcher() { - super(new ByteBufferBuilder(0), Object2ObjectSortedMaps.emptyMap()); - } - - @Override - public @NotNull VertexConsumer getBuffer(RenderType renderType) { - BufferBuilder bufferBuilder = startedBuilders.get(renderType); - if (bufferBuilder != null) { - endBatch(renderType, bufferBuilder); - } - ByteBufferBuilderPool bufferPool = bufferPools.computeIfAbsent(renderType, type -> new ByteBufferBuilderPool(type.bufferSize())); - bufferBuilder = new BufferBuilder(bufferPool.getBuffer(), renderType.mode(), renderType.format()); - startedBuilders.put(renderType, bufferBuilder); - return bufferBuilder; - } - - @Override - public void endCatching(Consumer consumer) { - endBatch(); - caughtMeshes.forEach((meshData, renderType) -> { - consumer.accept(BuiltIterableBuffer.buildFrom(renderType, meshData)); - meshData.close(); - }); - caughtMeshes.clear(); - bufferPools.values().forEach(ByteBufferBuilderPool::release); - } - - @Override - public void endBatch() { - for(RenderType renderType : bufferPools.keySet()) { - endBatch(renderType); - } - } - - @Override - protected void endBatch(RenderType renderType, BufferBuilder bufferBuilder) { - MeshData meshData = bufferBuilder.build(); - if (meshData != null) { - caughtMeshes.put(meshData, renderType); - } - } - - private static class ByteBufferBuilderPool { - private final int bufferSize; - private ByteBufferBuilder[] pool = new ByteBufferBuilder[0]; - private int next = 0; - - public ByteBufferBuilderPool(int bufferSize) { - this.bufferSize = bufferSize; - } - - public ByteBufferBuilder getBuffer() { - ByteBufferBuilder byteBufferBuilder; - if (next < pool.length) { - byteBufferBuilder = pool[next++]; - } else { - pool = Arrays.copyOf(pool, pool.length + 1); - pool[next++] = byteBufferBuilder = new ByteBufferBuilder(bufferSize); - } - return byteBufferBuilder; - } - - public void release() { - next = 0; - } - } - } -} diff --git a/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java b/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java index ad853d6c..e2de0b92 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java @@ -1,44 +1,31 @@ package com.xtracr.realcamera.util; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.ClipContext.Block; -import net.minecraft.world.level.ClipContext.Fluid; import net.minecraft.world.phys.Vec3; public class RaycastUtil { - private static Vec3 startVec = Vec3.ZERO; - private static Vec3 endVec = Vec3.ZERO; - - public static Vec3 getStartVec() { - return startVec; - } - - public static Vec3 getEndVec() { - return endVec; - } - - public static ClipContext getClipContext(Block shapeType, Fluid fluidHandling, Entity entity) { - return new ClipContext(startVec, endVec, shapeType, fluidHandling, entity); - } - - public static void update(Entity entity, double sqDistance, float deltaTick) { + /** + * Updates raycast start and end points ensuring: + *
  • End point is on camera's viewing direction + *
  • Square distance from entity's eye to end point ≤ sqDistance + */ + public static Pair getFromAndTo(Entity entity, double sqDistance, float partialTicks) { Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera(); - Vec3 eyePos = entity.getEyePosition(deltaTick); - startVec = camera.getPosition(); - Vec3 direction = Vec3.directionFromRotation(camera.getXRot(), camera.getYRot()); - Vec3 offset = startVec.subtract(eyePos); + Vec3 eyePos = entity.getEyePosition(partialTicks); + Vec3 from = camera.position(); + Vec3 direction = Vec3.directionFromRotation(camera.xRot(), camera.yRot()); + Vec3 offset = from.subtract(eyePos); Vec3 footPoint = MathUtil.getIntersectionPoint(Vec3.ZERO, direction, offset, direction); if (footPoint.lengthSqr() > sqDistance) { - startVec = eyePos; - direction = entity.getViewVector(deltaTick); - endVec = startVec.add(direction.scale(Math.sqrt(sqDistance))); - return; + from = eyePos; + direction = entity.getViewVector(partialTicks); + return Pair.of(from, from.add(direction.scale(Math.sqrt(sqDistance)))); } else if (offset.lengthSqr() > sqDistance) { - startVec = startVec.add(direction.scale(offset.distanceTo(footPoint) - Math.sqrt(sqDistance - footPoint.lengthSqr()))); + from = from.add(direction.scale(offset.distanceTo(footPoint) - Math.sqrt(sqDistance - footPoint.lengthSqr()))); } - endVec = eyePos.add(footPoint.add(direction.scale(Math.sqrt(sqDistance - footPoint.lengthSqr())))); + return Pair.of(from, eyePos.add(footPoint.add(direction.scale(Math.sqrt(sqDistance - footPoint.lengthSqr()))))); } } diff --git a/common/src/main/java/com/xtracr/realcamera/util/SmoothUtil.java b/common/src/main/java/com/xtracr/realcamera/util/SmoothUtil.java deleted file mode 100644 index 63c7ec67..00000000 --- a/common/src/main/java/com/xtracr/realcamera/util/SmoothUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.xtracr.realcamera.util; - -import com.xtracr.realcamera.config.ConfigFile; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix3f; -import org.joml.Quaterniond; - -public class SmoothUtil { - private static final Quaterniond lastRotation = new Quaterniond(); - private static Vec3 lastPosition = Vec3.ZERO; - - public static Vec3 smoothPosition(Vec3 position) { - lastPosition = position.add(lastPosition.subtract(position).scale(ConfigFile.config().getDisplacementSmoothFactor())); - return lastPosition; - } - - public static Matrix3f smoothRotation(Matrix3f rotation) { - return smoothRotation(new Quaterniond().setFromNormalized(rotation)).get(new Matrix3f()); - } - - public static Quaterniond smoothRotation(Quaterniond rotation) { - lastRotation.slerp(rotation, 1 - ConfigFile.config().getRotationSmoothFactor()); - return lastRotation; - } -} diff --git a/common/src/main/resources/architectury.common.json b/common/src/main/resources/architectury.common.json deleted file mode 100644 index 6587691f..00000000 --- a/common/src/main/resources/architectury.common.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "accessWidener": "realcamera.accesswidener" -} \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/be_by.json b/common/src/main/resources/assets/realcamera/lang/be_by.json index 283e40c5..8024873c 100644 --- a/common/src/main/resources/assets/realcamera/lang/be_by.json +++ b/common/src/main/resources/assets/realcamera/lang/be_by.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Адкрыць экран прагляду мадэлі", - "key.xtracr_realcamera.togglePerspective": "Уключыць/Выключыць", - "key.xtracr_realcamera.activeConfigIndexPREV": "Пераключыцца на папярэднюю канфігурацыю", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Пераключыцца на наступную канфігурацыю", - "key.xtracr_realcamera.activeConfigIndexRESET": "Скінуць індэкс канфігурацыі", - "key.xtracr_realcamera.toggleAdjustMode": "Пераключыць рэжым налады", - "key.xtracr_realcamera.toggleCameraMode": "Пераключыць рэжым камеры", - "key.xtracr_realcamera.adjustUP": "Наладзіць УВЕРХ", - "key.xtracr_realcamera.adjustDOWN": "Наладзіць УНІЗ", - "key.xtracr_realcamera.adjustFRONT": "Наладзіць УПЕРАД", - "key.xtracr_realcamera.adjustBACK": "Наладзіць НАЗАД", - "key.xtracr_realcamera.adjustLEFT": "Наладзіць УЛЕВА", - "key.xtracr_realcamera.adjustRIGHT": "Наладзіць УПРАВА", - "modmenu.descriptionTranslation.realcamera": "Зрабіць камеру больш рэалістычнай у рэжыме ад першай асобы.", - - "config.category.xtracr_realcamera.general": "Асноўныя", "config.category.xtracr_realcamera.binding": "Рэжым прывязкі", - "config.category.xtracr_realcamera.classic": "Класічны рэжым", "config.category.xtracr_realcamera.cameraOffset": "Зрух камеры", - "config.category.xtracr_realcamera.centerOffset": "Зрух цэнтра кручэння", "config.category.xtracr_realcamera.cameraRotation": "Паварот камеры", - "config.tooltip.xtracr_realcamera.classicOffset": "Зрух камеры ад цэнтра кручэння", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Заўвага: пярэдняя, верхняя і левая бакі гульца адпавядаюць восям X, Y і Z", - "config.tooltip.xtracr_realcamera.centerOffset": "Зрух цэнтра кручэння ад галавы", - "config.tooltip.xtracr_realcamera.cameraRotation": "Дадатковы паварот камеры ў градусах", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Заўвага: тангаж, рысканне і крэн - гэта павароты вакол левай, верхняй і пярэдняй восей адпаведна", - - "config.option.xtracr_realcamera.enabled": "Мод уключаны", - "config.option.xtracr_realcamera.isClassic": "Класічны рэжым", - "config.option.xtracr_realcamera.dynamicCrosshair": "Дынамічны прыцэл", - "config.option.xtracr_realcamera.renderModel": "Адлюстроўваць мадэль гульца", + "config.category.xtracr_realcamera.centerOffset": "Зрух цэнтра кручэння", + "config.category.xtracr_realcamera.classic": "Класічны рэжым", + "config.category.xtracr_realcamera.general": "Асноўныя", + "config.option.xtracr_realcamera.activeConfigIndex": "Актыўны індэкс канфігурацыі", + "config.option.xtracr_realcamera.adjustOffset": "Наладзіць зрух камеры", "config.option.xtracr_realcamera.adjustStep": "Крок налады", - "config.option.xtracr_realcamera.classicAdjustMode": "Рэжым налады", - "config.option.xtracr_realcamera.scale": "Маштаб", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадры захавання выніку прывязкі", "config.option.xtracr_realcamera.cameraOffset": "Зрух камеры %s", "config.option.xtracr_realcamera.centerOffset": "Зрух цэнтра кручэння %s", - "config.option.xtracr_realcamera.pitch": "Тангаж", - "config.option.xtracr_realcamera.yaw": "Рысканне", - "config.option.xtracr_realcamera.roll": "Крэн", - "config.option.xtracr_realcamera.toModelViewScreen": "Для падрабязных налад перайдзіце на экран %s (неабходна прызначыць клавішу для адкрыцця)", - "config.option.xtracr_realcamera.screenModifierKey": "Клавіша-мадыфікатар для экрана %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Рэжым састарэлай прывязкі", - "config.option.xtracr_realcamera.adjustOffset": "Наладзіць зрух камеры", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Хаваць паведамленні пра няўдалую прывязку", - "config.option.xtracr_realcamera.renderStuckObjects": "Адлюстроўваць застряўшыя аб'екты", - "config.option.xtracr_realcamera.rerenderModel": "Перамаляваць мадэль", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадры захавання выніку прывязкі", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Каэфіцыент згладжвання зруху", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Каэфіцыент згладжвання павароту", - "config.option.xtracr_realcamera.activeConfigIndex": "Актыўны індэкс канфігурацыі", + "config.option.xtracr_realcamera.classicAdjustMode": "Рэжым налады", "config.option.xtracr_realcamera.disableConfig": "Адключыць Канфігурацыю", - "config.option.xtracr_realcamera.disableWhenSneaking": "Адключыць асноўную функцыю пры крадзяжы", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Адключыць асноўную функцыю пры трыманні...", + "config.option.xtracr_realcamera.disableRenderItems": "Адключыць адлюстраванне пры трыманні...", "config.option.xtracr_realcamera.disableWhenCrawling": "Адключыць асноўную функцыю пры поўзанні", + "config.option.xtracr_realcamera.disableWhenSneaking": "Адключыць асноўную функцыю пры крадзяжы", "config.option.xtracr_realcamera.disableWhenSwimming": "Адключыць асноўную функцыю пры плаванні", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Каэфіцыент згладжвання зруху", + "config.option.xtracr_realcamera.dynamicCrosshair": "Дынамічны прыцэл", + "config.option.xtracr_realcamera.enabled": "Мод уключаны", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Хаваць паведамленні пра няўдалую прывязку", + "config.option.xtracr_realcamera.isClassic": "Класічны рэжым", + "config.option.xtracr_realcamera.legacyBindingMode": "Рэжым састарэлай прывязкі", "config.option.xtracr_realcamera.outTick": "Затрымка выхаду з стану плавання (у тіках)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Адключыць асноўную функцыю пры трыманні...", - "config.option.xtracr_realcamera.disableRenderItems": "Адключыць адлюстраванне пры трыманні...", - "config.tooltip.xtracr_realcamera.isClassic": "Класічны рэжым уносіць толькі простыя змены ў становішча і паварот камеры", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Пры ўключэнні прыцэл будзе сачыць за поглядам гульца, забяспечваючы дакладнае трапленне\nРэкамендуецца ўключыць пры ўсталёўцы Jade, WTHIT ці падобных модаў", - "config.tooltip.xtracr_realcamera.renderModel": "Адлюстроўваць мадэль гульца ў рэжыме ад першай асобы", + "config.option.xtracr_realcamera.pitch": "Тангаж", + "config.option.xtracr_realcamera.renderModel": "Адлюстроўваць мадэль гульца", + "config.option.xtracr_realcamera.renderStuckObjects": "Адлюстроўваць застряўшыя аб'екты", + "config.option.xtracr_realcamera.rerenderModel": "Перамаляваць мадэль", + "config.option.xtracr_realcamera.roll": "Крэн", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Каэфіцыент згладжвання павароту", + "config.option.xtracr_realcamera.scale": "Маштаб", + "config.option.xtracr_realcamera.screenModifierKey": "Клавіша-мадыфікатар для экрана %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Для падрабязных налад перайдзіце на экран %s (неабходна прызначыць клавішу для адкрыцця)", + "config.option.xtracr_realcamera.yaw": "Рысканне", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Текущий индекс привязанной конфигурации, 0 означает разрешение привязки к любой допустимой конфигурации", + "config.tooltip.xtracr_realcamera.adjustOffset": "Пры націсканні клавішы налады, рэгуляваць зрух або паварот камеры", "config.tooltip.xtracr_realcamera.adjustStep": "Даўжыня або 1/100 вугла налады за крок", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "На працягу некалькіх кадраў пасля няўдалай прывязкі працягваць выкарыстоўваць папярэдні паспяховы вынік прывязкі", + "config.tooltip.xtracr_realcamera.cameraRotation": "Дадатковы паварот камеры ў градусах", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Заўвага: тангаж, рысканне і крэн - гэта павароты вакол левай, верхняй і пярэдняй восей адпаведна", + "config.tooltip.xtracr_realcamera.centerOffset": "Зрух цэнтра кручэння ад галавы", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Вызначае, што наладжваць пры націсканні клавішы налады", - "config.tooltip.xtracr_realcamera.scale": "Кантраляваць памер зрухаў", + "config.tooltip.xtracr_realcamera.classicOffset": "Зрух камеры ад цэнтра кручэння", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Заўвага: пярэдняя, верхняя і левая бакі гульца адпавядаюць восям X, Y і Z", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Падтрымліваюцца тры метады супадзення:\n1. Сімвал падстаноўкі `*` (напрыклад, `minecraft:*sword`)\n2. Супадзенне па тэгах (пачынаецца з `#`, напрыклад, `#minecraft:swords`)\n3. Прамы ID прадмета (напрыклад, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Каэфіцыент згладжвання зруху камеры, чым вышэй значэнне, тым больш плаўным будзе рух", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Пры ўключэнні прыцэл будзе сачыць за поглядам гульца, забяспечваючы дакладнае трапленне\nРэкамендуецца ўключыць пры ўсталёўцы Jade, WTHIT ці падобных модаў", + "config.tooltip.xtracr_realcamera.isClassic": "Класічны рэжым уносіць толькі простыя змены ў становішча і паварот камеры", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Выкарыстоўвае рэжым прывязкі састарэлай версіі (v0.5), падтрымліваюцца толькі стандартныя мадэлі і дзеянні на іх аснове\nПасля ўключэння ўласцівасціў выладывае дакладней прывязацца да мэтавай пазіцыі", - "config.tooltip.xtracr_realcamera.adjustOffset": "Пры націсканні клавішы налады, рэгуляваць зрух або паварот камеры", + "config.tooltip.xtracr_realcamera.outTick": "Затрымка ўключэння асноўнай функцыі пасля выхаду з стану плавання (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Адлюстроўваць мадэль гульца ў рэжыме ад першай асобы", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Стрэлы, джалы пчол і іншыя аб'екты, якія могуць застряць у целе гульца", "config.tooltip.xtracr_realcamera.rerenderModel": "Перамалёўваць мадэль у зыходны час рэндэрынгу, каб пазбегнуць візуальных праблем", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "На працягу некалькіх кадраў пасля няўдалай прывязкі працягваць выкарыстоўваць папярэдні паспяховы вынік прывязкі", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Каэфіцыент згладжвання зруху камеры, чым вышэй значэнне, тым больш плаўным будзе рух", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Каэфіцыент згладжвання павароту камеры, чым вышэй значэнне, тым больш плаўным будзе рух", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Текущий индекс привязанной конфигурации, 0 означает разрешение привязки к любой допустимой конфигурации", - "config.tooltip.xtracr_realcamera.outTick": "Затрымка ўключэння асноўнай функцыі пасля выхаду з стану плавання (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Падтрымліваюцца тры метады супадзення:\n1. Сімвал падстаноўкі `*` (напрыклад, `minecraft:*sword`)\n2. Супадзенне па тэгах (пачынаецца з `#`, напрыклад, `#minecraft:swords`)\n3. Прамы ID прадмета (напрыклад, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Кантраляваць памер зрухаў", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Пераключыцца на наступную канфігурацыю", + "key.xtracr_realcamera.activeConfigIndexPREV": "Пераключыцца на папярэднюю канфігурацыю", + "key.xtracr_realcamera.activeConfigIndexRESET": "Скінуць індэкс канфігурацыі", + "key.xtracr_realcamera.adjustBACK": "Наладзіць НАЗАД", + "key.xtracr_realcamera.adjustDOWN": "Наладзіць УНІЗ", + "key.xtracr_realcamera.adjustFRONT": "Наладзіць УПЕРАД", + "key.xtracr_realcamera.adjustLEFT": "Наладзіць УЛЕВА", + "key.xtracr_realcamera.adjustRIGHT": "Наладзіць УПРАВА", + "key.xtracr_realcamera.adjustUP": "Наладзіць УВЕРХ", + "key.xtracr_realcamera.modelViewScreen": "Адкрыць экран прагляду мадэлі", + "key.xtracr_realcamera.toggleAdjustMode": "Пераключыць рэжым налады", + "key.xtracr_realcamera.toggleCameraMode": "Пераключыць рэжым камеры", + "key.xtracr_realcamera.togglePerspective": "Уключыць/Выключыць", "message.xtracr_realcamera.bindingFailed": "[%s]: Памылка прывязкі, калі ласка, перайдзіце на экран %s і наладзьце ўручную (ключ: %s)", - - "screen.xtracr_realcamera.modelView_title": "Прагляд мадэлі", - "screen.widget.xtracr_realcamera.modelView_import": "Імпартаваць", + "modmenu.descriptionTranslation.realcamera": "Зрабіць камеру больш рэалістычнай у рэжыме ад першай асобы.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Калі адключана, адноснае становішча камеры да мадэлі не мяняецца, але адпаведныя атрыбуты камеры не будуць зменены гэтым модам", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Захаваныя канфігурацыі", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Капіяваць усе налады адключэння", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Выдаліць абраную прастакутную вобласць\n(Ці выкарыстайце клавішу Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскасці, адлеглась ад усіх вяршынь да экрана ў якіх меншая за гэта значэнне, не будуць адлюстроўвацца", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Налады адключэння\nГлабальныя налады адключэння знаходзяцца на экране канфігурацыі", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Часткі, уключаныя ў сінія рамкі, будуць адключаны\nЛевы клік для выбару, іншыя клавішы для скасавання выбару\n%s+Левы клік каб хутка выбраць частку, на якую наведзены паказальнік мышы", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Назва налады адключэння", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Назва не можа быць пустой!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "ID тэкстуры не можа быць пустым!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Экспартаваць бягучы канфіг у буфер абмену", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Экспарт не ўдаўся: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Экспарт паспяховы!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Нумар абранай прастакутнай вобласці\n(0 азначае адсутнасць выбару)\nНацісніце Прабел ці Enter каб знайсці бягучую абраную вобласць (Калі друкуеце, націсніце двойчы каб знайсці)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Імпартаваць канфіг з буфера абмену", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Імпарт не ўдаўся: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпарт %s паспяховы!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Уставіць усе налады адключэння з буфера абмену ў бягучы канфіг\n(Не перазапіша існуючыя налады з такой жа назвай)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "У рэжыме прадпрагляду вы можаце наладжваць зрух і паварот камеры", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Прыярытэт пры прывязцы, чым больш значэнне, тым вышэй прыярытэт і размяшчэнне справей у спісе", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Захаваць як\n(Калі існуе канфігурацыя з такой жа назвай, вы таксама можаце націснуць кнопку захавання злева)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Маштаб, які кіруе памерам зрухаў", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Левы клік каб атрымаць UV-каардынаты пад паказальнікам мышы\nТры наборы UV-каардынат ніжэй, зверху ўніз, гэта UV-каардынаты вектара наперад, вектара уверх і пункту прывязкі на мэтавай плоскасці\nЗаўвага: %s+Пракрутка каб пераключацца паміж рознымі слаямі мадэлі. Увод UV-каардынат уручную дазваляе дакладней прывязацца да мэтавай пазіцыі", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Вызначае рэжым хуткага выбару %s+Левы клік\n(%s+Пракрутка каб змяніць дыяпазон выбару ў рэжыме дыяпазону)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Назва канфігурацыі", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "ID тэкстуры выбранай мадэлі (не абавязковы поўны ID), можа быць скарочаны пры захаванні для лягчэйшага распазнання.\nНапрыклад, скараціць minecraft:textures/entity/player/slim/alex.png да minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Адкрыць глабальны экран канфігурацыі\n(Патрабуецца Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "Усё", + "screen.widget.xtracr_realcamera.modelView_configs": "Канфігурацыі", + "screen.widget.xtracr_realcamera.modelView_copy": "Капіяваць", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Бягучая Канфігурацыя", + "screen.widget.xtracr_realcamera.modelView_disable": "Адключыць", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Рэжым адключэння", "screen.widget.xtracr_realcamera.modelView_export": "Экспартаваць", - "screen.widget.xtracr_realcamera.modelView_selecting": "Выбар", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Вектар напрамку", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектар уверх", - "screen.widget.xtracr_realcamera.modelView_position": "Мэтавая плоскасць", - "screen.widget.xtracr_realcamera.modelView_save": "Захаваць", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Рэжым адключэння", - "screen.widget.xtracr_realcamera.modelView_all": "Усё", - "screen.widget.xtracr_realcamera.modelView_part": "Частка", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Рэжым выбару", - "screen.widget.xtracr_realcamera.modelView_single": "Адзіночны", + "screen.widget.xtracr_realcamera.modelView_import": "Імпартаваць", "screen.widget.xtracr_realcamera.modelView_multiple": "Множны", - "screen.widget.xtracr_realcamera.modelView_range": "Дыяпазон", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Пераключыць паўзунок у поле", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Пераключыць поле ў паўзунок", "screen.widget.xtracr_realcamera.modelView_offsetX": "Зрух X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Зрух Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Зрух Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Частка", + "screen.widget.xtracr_realcamera.modelView_paste": "Уставіць", "screen.widget.xtracr_realcamera.modelView_pitch": "Тангаж = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Рысканне = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Крэн = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Адключыць", + "screen.widget.xtracr_realcamera.modelView_position": "Мэтавая плоскасць", "screen.widget.xtracr_realcamera.modelView_preview": "Прадпрагляд", - "screen.widget.xtracr_realcamera.modelView_configs": "Канфігурацыі", - "screen.widget.xtracr_realcamera.modelView_copy": "Капіяваць", - "screen.widget.xtracr_realcamera.modelView_paste": "Уставіць", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Бягучая Канфігурацыя", - "screen.tooltip.xtracr_realcamera.modelView_import": "Імпартаваць канфіг з буфера абмену", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпарт %s паспяховы!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Імпарт не ўдаўся: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Экспартаваць бягучы канфіг у буфер абмену", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Экспарт паспяховы!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Экспарт не ўдаўся: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Левы клік каб атрымаць UV-каардынаты пад паказальнікам мышы\nТры наборы UV-каардынат ніжэй, зверху ўніз, гэта UV-каардынаты вектара наперад, вектара уверх і пункту прывязкі на мэтавай плоскасці\nЗаўвага: %s+Пракрутка каб пераключацца паміж рознымі слаямі мадэлі. Увод UV-каардынат уручную дазваляе дакладней прывязацца да мэтавай пазіцыі", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "ID тэкстуры выбранай мадэлі (не абавязковы поўны ID), можа быць скарочаны пры захаванні для лягчэйшага распазнання.\nНапрыклад, скараціць minecraft:textures/entity/player/slim/alex.png да minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Часткі, уключаныя ў сінія рамкі, будуць адключаны\nЛевы клік для выбару, іншыя клавішы для скасавання выбару\n%s+Левы клік каб хутка выбраць частку, на якую наведзены паказальнік мышы", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Вызначае рэжым хуткага выбару %s+Левы клік\n(%s+Пракрутка каб змяніць дыяпазон выбару ў рэжыме дыяпазону)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Нумар абранай прастакутнай вобласці\n(0 азначае адсутнасць выбару)\nНацісніце Прабел ці Enter каб знайсці бягучую абраную вобласць (Калі друкуеце, націсніце двойчы каб знайсці)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Выдаліць абраную прастакутную вобласць\n(Ці выкарыстайце клавішу Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Калі адключана, адноснае становішча камеры да мадэлі не мяняецца, але адпаведныя атрыбуты камеры не будуць зменены гэтым модам", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Маштаб, які кіруе памерам зрухаў", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскасці, адлеглась ад усіх вяршынь да экрана ў якіх меншая за гэта значэнне, не будуць адлюстроўвацца", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Прыярытэт пры прывязцы, чым больш значэнне, тым вышэй прыярытэт і размяшчэнне справей у спісе", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Назва канфігурацыі", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Налады адключэння\nГлабальныя налады адключэння знаходзяцца на экране канфігурацыі", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Захаваныя канфігурацыі", - "screen.tooltip.xtracr_realcamera.modelView_preview": "У рэжыме прадпрагляду вы можаце наладжваць зрух і паварот камеры", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Адкрыць глабальны экран канфігурацыі\n(Патрабуецца Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Капіяваць усе налады адключэння", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Уставіць усе налады адключэння з буфера абмену ў бягучы канфіг\n(Не перазапіша існуючыя налады з такой жа назвай)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Назва не можа быць пустой!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "ID тэкстуры не можа быць пустым!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Захаваць як\n(Калі існуе канфігурацыя з такой жа назвай, вы таксама можаце націснуць кнопку захавання злева)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Назва налады адключэння" + "screen.widget.xtracr_realcamera.modelView_range": "Дыяпазон", + "screen.widget.xtracr_realcamera.modelView_roll": "Крэн = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Захаваць", + "screen.widget.xtracr_realcamera.modelView_selecting": "Выбар", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Рэжым выбару", + "screen.widget.xtracr_realcamera.modelView_single": "Адзіночны", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Пераключыць поле ў паўзунок", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Пераключыць паўзунок у поле", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектар уверх", + "screen.widget.xtracr_realcamera.modelView_yaw": "Рысканне = %s", + "screen.xtracr_realcamera.modelView_title": "Прагляд мадэлі" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 1b9be4a3..0e7afd4e 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Open Model View Screen", - "key.xtracr_realcamera.togglePerspective": "Enable/Disable", - "key.xtracr_realcamera.activeConfigIndexPREV": "Switch to previous configuration", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Switch to next configuration", - "key.xtracr_realcamera.activeConfigIndexRESET": "Reset configuration index", - "key.xtracr_realcamera.toggleAdjustMode": "Toggle Adjust Mode", - "key.xtracr_realcamera.toggleCameraMode": "Toggle Camera Mode", - "key.xtracr_realcamera.adjustUP": "Adjust UP", - "key.xtracr_realcamera.adjustDOWN": "Adjust DOWN", - "key.xtracr_realcamera.adjustFRONT": "Adjust FRONT", - "key.xtracr_realcamera.adjustBACK": "Adjust BACK", - "key.xtracr_realcamera.adjustLEFT": "Adjust LEFT", - "key.xtracr_realcamera.adjustRIGHT": "Adjust RIGHT", - "modmenu.descriptionTranslation.realcamera": "Make the camera more realistic in the first-person view.", - - "config.category.xtracr_realcamera.general": "General", "config.category.xtracr_realcamera.binding": "Binding Mode", - "config.category.xtracr_realcamera.classic": "Classic Mode", "config.category.xtracr_realcamera.cameraOffset": "Camera Offset", - "config.category.xtracr_realcamera.centerOffset": "Rotation Center Offset", "config.category.xtracr_realcamera.cameraRotation": "Camera Rotation", - "config.tooltip.xtracr_realcamera.classicOffset": "Camera's offset from its rotation center", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Note: player's front, up and left are the X, Y and Z axes respectively", - "config.tooltip.xtracr_realcamera.centerOffset": "Rotation center's offset from head", - "config.tooltip.xtracr_realcamera.cameraRotation": "Additional camera rotation in degrees", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Note: Pitch, yaw and roll are rotations on the left, up and front axes respectively", - - "config.option.xtracr_realcamera.enabled": "Mod Enabled", - "config.option.xtracr_realcamera.isClassic": "Classic Mode", - "config.option.xtracr_realcamera.dynamicCrosshair": "Dynamic Crosshair", - "config.option.xtracr_realcamera.renderModel": "Render Player Model", + "config.category.xtracr_realcamera.centerOffset": "Rotation Center Offset", + "config.category.xtracr_realcamera.classic": "Classic Mode", + "config.category.xtracr_realcamera.general": "General", + "config.option.xtracr_realcamera.activeConfigIndex": "Active Configuration Index", + "config.option.xtracr_realcamera.adjustOffset": "Adjust Camera Offset", "config.option.xtracr_realcamera.adjustStep": "Adjust Step", - "config.option.xtracr_realcamera.classicAdjustMode": "Adjust Mode", - "config.option.xtracr_realcamera.scale": "Scale", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bind Result Retention Frames", "config.option.xtracr_realcamera.cameraOffset": "Camera %s Offset", "config.option.xtracr_realcamera.centerOffset": "Rotation Center %s Offset", - "config.option.xtracr_realcamera.pitch": "Pitch", - "config.option.xtracr_realcamera.yaw": "Yaw", - "config.option.xtracr_realcamera.roll": "Roll", - "config.option.xtracr_realcamera.toModelViewScreen": "For detailed settings, please go to the %s screen (key bind need to be set to open it)", - "config.option.xtracr_realcamera.screenModifierKey": "%s Screen Modifier Key", - "config.option.xtracr_realcamera.legacyBindingMode": "Legacy Binding Mode", - "config.option.xtracr_realcamera.adjustOffset": "Adjust Camera Offset", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Hide Binding Failure Message", - "config.option.xtracr_realcamera.renderStuckObjects": "Render Stuck Objects", - "config.option.xtracr_realcamera.rerenderModel": "Rerender Model", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bind Result Retention Frames", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Displacement Smooth Factor", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Rotation Smooth Factor", - "config.option.xtracr_realcamera.activeConfigIndex": "Active Configuration Index", + "config.option.xtracr_realcamera.classicAdjustMode": "Adjust Mode", "config.option.xtracr_realcamera.disableConfig": "Disable Config", - "config.option.xtracr_realcamera.disableWhenSneaking": "Disable main feature when sneaking", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Disable main feature when holding", + "config.option.xtracr_realcamera.disableRenderItems": "Disable rendering when holding", "config.option.xtracr_realcamera.disableWhenCrawling": "Disable main feature when crawling", + "config.option.xtracr_realcamera.disableWhenSneaking": "Disable main feature when sneaking", "config.option.xtracr_realcamera.disableWhenSwimming": "Disable main feature when swimming", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Displacement Smooth Factor", + "config.option.xtracr_realcamera.dynamicCrosshair": "Dynamic Crosshair", + "config.option.xtracr_realcamera.enabled": "Mod Enabled", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Hide Binding Failure Message", + "config.option.xtracr_realcamera.isClassic": "Classic Mode", + "config.option.xtracr_realcamera.legacyBindingMode": "Legacy Binding Mode", "config.option.xtracr_realcamera.outTick": "Restriction exit delay (in ticks)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Disable main feature when holding", - "config.option.xtracr_realcamera.disableRenderItems": "Disable rendering when holding", - "config.tooltip.xtracr_realcamera.isClassic": "Classic mode only makes simple changes to the position and rotation of camera", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "When enabled, the crosshair will follow the player's view, ensuring consistent hit result\nRecommended to enable when Jade, WTHIT or similar mods are installed", - "config.tooltip.xtracr_realcamera.renderModel": "Render player model in first-person perspective", + "config.option.xtracr_realcamera.pitch": "Pitch", + "config.option.xtracr_realcamera.renderModel": "Render Player Model", + "config.option.xtracr_realcamera.renderStuckObjects": "Render Stuck Objects", + "config.option.xtracr_realcamera.rerenderModel": "Rerender Model", + "config.option.xtracr_realcamera.roll": "Roll", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Rotation Smooth Factor", + "config.option.xtracr_realcamera.scale": "Scale", + "config.option.xtracr_realcamera.screenModifierKey": "%s Screen Modifier Key", + "config.option.xtracr_realcamera.toModelViewScreen": "For detailed settings, please go to the %s screen (key bind need to be set to open it)", + "config.option.xtracr_realcamera.yaw": "Yaw", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Currently bound configuration index, 0 means allowing binding to any valid configuration", + "config.tooltip.xtracr_realcamera.adjustOffset": "When pressing the adjustment key, adjust the offset or rotation of camera", "config.tooltip.xtracr_realcamera.adjustStep": "Length or 1/100 of the angle of the adjustment per step", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "For several frames after the binding failure, continue to use the previous successful binding result", + "config.tooltip.xtracr_realcamera.cameraRotation": "Additional camera rotation in degrees", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Note: Pitch, yaw and roll are rotations on the left, up and front axes respectively", + "config.tooltip.xtracr_realcamera.centerOffset": "Rotation center's offset from head", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Determine which to adjust when pressing the adjustment key", - "config.tooltip.xtracr_realcamera.scale": "Control the size of the offsets", + "config.tooltip.xtracr_realcamera.classicOffset": "Camera's offset from its rotation center", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Note: player's front, up and left are the X, Y and Z axes respectively", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Three matching methods are supported:\n1. Wildcard `*` matching (e.g., `minecraft:*sword`)\n2. Tag matching (starts with `#`, e.g., `#minecraft:swords`)\n3. Direct item ID (e.g., `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Smooth factor of camera displacement, the higher the value, the smoother the movement", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "When enabled, the crosshair will follow the player's view, ensuring consistent hit result\nRecommended to enable when Jade, WTHIT or similar mods are installed", + "config.tooltip.xtracr_realcamera.isClassic": "Classic mode only makes simple changes to the position and rotation of camera", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Using the binding mode of legacy version (v0.5), only vanilla model and actions based on vanilla model are supported\nIts properties can be set in 'LEGACY_MODE' of the %s screen when enabled", - "config.tooltip.xtracr_realcamera.adjustOffset": "When pressing the adjustment key, adjust the offset or rotation of camera", + "config.tooltip.xtracr_realcamera.outTick": "The time before re-enabling main feature after exiting restricted states (e.g., swimming, crawling) (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Render player model in first-person perspective", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Arrows, bee stings and other objects that can be stuck in the player's body", "config.tooltip.xtracr_realcamera.rerenderModel": "Render the model again at the original rendering time to avoid some visual problems caused by rendering early", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "For several frames after the binding failure, continue to use the previous successful binding result", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Smooth factor of camera displacement, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Smooth factor of camera rotation, the higher the value, the smoother the movement", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Currently bound configuration index, 0 means allowing binding to any valid configuration", - "config.tooltip.xtracr_realcamera.outTick": "The time before re-enabling main feature after exiting restricted states (e.g., swimming, crawling) (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Three matching methods are supported:\n1. Wildcard `*` matching (e.g., `minecraft:*sword`)\n2. Tag matching (starts with `#`, e.g., `#minecraft:swords`)\n3. Direct item ID (e.g., `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Control the size of the offsets", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Switch to next configuration", + "key.xtracr_realcamera.activeConfigIndexPREV": "Switch to previous configuration", + "key.xtracr_realcamera.activeConfigIndexRESET": "Reset configuration index", + "key.xtracr_realcamera.adjustBACK": "Adjust BACK", + "key.xtracr_realcamera.adjustDOWN": "Adjust DOWN", + "key.xtracr_realcamera.adjustFRONT": "Adjust FRONT", + "key.xtracr_realcamera.adjustLEFT": "Adjust LEFT", + "key.xtracr_realcamera.adjustRIGHT": "Adjust RIGHT", + "key.xtracr_realcamera.adjustUP": "Adjust UP", + "key.xtracr_realcamera.modelViewScreen": "Open Model View Screen", + "key.xtracr_realcamera.toggleAdjustMode": "Toggle Adjust Mode", + "key.xtracr_realcamera.toggleCameraMode": "Toggle Camera Mode", + "key.xtracr_realcamera.togglePerspective": "Enable/Disable", "message.xtracr_realcamera.bindingFailed": "[%s]: Binding failed, please go to the %s screen and configure manually (Key: %s)", - - "screen.xtracr_realcamera.modelView_title": "Model View", - "screen.widget.xtracr_realcamera.modelView_import": "Import", + "modmenu.descriptionTranslation.realcamera": "Make the camera more realistic in the first-person view.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "When disabled, the camera's relative relationship to the model will not change, but the camera's corresponding attributes will not be modified by this mod", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Saved Configs", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Copy all disabling settings", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Delete the selected rectangle\n(Or use the Delete key)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Planes where all vertex-to-screen distances are less than this value will not be rendered", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Disabling Settings\nGlobal disabling settings are in the config screen", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "The parts contained in the blue boxes will be disabled\nLeft Click to select, other keys to cancel selection\n%s+Left Click to quickly select the part pointed to by the mouse pointer", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Name of the disable setting", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Name cannot be empty!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Texture id cannot be empty!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Export the current config to the clipboard", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Export failed: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Export succeeded!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Focused Rectangle Number\n(0 means no selection)\nPress Space or Enter to locate the current focused rectangle (When typing, press twice to locate)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Import the config from the clipboard", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import failed: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s succeeded!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Paste all disabling settings in the clipboard to current config\n(Will not override existing setting with the same name)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "In the preview mode, you can adjust the camera's offset and rotation", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Priority when binding, the larger the value the higher the priority, and the higher the sorting on the right side", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Save as\n(When there is a setting with the same name, you can also press the save button on the left)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Scale, which controls the size of the offsets", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Left Click to get the UV coordinates at the mouse pointer\nThe three sets of UV coordinates below are, from top to bottom, the UV coordinates of the forward vector, the upward vector, and the binding point on the target plane\nNote: %s+Scroll to switch between the different layers of the model. Manually inputting UV coordinates allows you to bind more accurately to the target position", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Decide the mode of %s+Left Click quick selection\n(%s+Scroll to change the selection range in the range mode)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Name of the config", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "The texture id of the selected model (not necessary to be the full id), can be shortened when saving to make it easier to recognize.\nFor example, shorten minecraft:textures/entity/player/slim/alex.png to minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Open Global Config Screen\n(Cloth Config API required)", + "screen.widget.xtracr_realcamera.modelView_all": "All", + "screen.widget.xtracr_realcamera.modelView_configs": "Configs", + "screen.widget.xtracr_realcamera.modelView_copy": "Copy", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Current Config", + "screen.widget.xtracr_realcamera.modelView_disable": "Disable", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Disable Mode", "screen.widget.xtracr_realcamera.modelView_export": "Export", - "screen.widget.xtracr_realcamera.modelView_selecting": "Selecting", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Forward Vector", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Upward Vector", - "screen.widget.xtracr_realcamera.modelView_position": "Target Plane", - "screen.widget.xtracr_realcamera.modelView_save": "Save", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Disable Mode", - "screen.widget.xtracr_realcamera.modelView_all": "All", - "screen.widget.xtracr_realcamera.modelView_part": "Part", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Selection Mode", - "screen.widget.xtracr_realcamera.modelView_single": "Single", + "screen.widget.xtracr_realcamera.modelView_import": "Import", "screen.widget.xtracr_realcamera.modelView_multiple": "Multiple", - "screen.widget.xtracr_realcamera.modelView_range": "Range", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Toggle Slider to Field", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Toggle Field to Slider", "screen.widget.xtracr_realcamera.modelView_offsetX": "X Offset = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y Offset = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z Offset = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Part", + "screen.widget.xtracr_realcamera.modelView_paste": "Paste", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Disable", + "screen.widget.xtracr_realcamera.modelView_position": "Target Plane", "screen.widget.xtracr_realcamera.modelView_preview": "Preview", - "screen.widget.xtracr_realcamera.modelView_configs": "Configs", - "screen.widget.xtracr_realcamera.modelView_copy": "Copy", - "screen.widget.xtracr_realcamera.modelView_paste": "Paste", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Current Config", - "screen.tooltip.xtracr_realcamera.modelView_import": "Import the config from the clipboard", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s succeeded!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import failed: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Export the current config to the clipboard", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Export succeeded!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Export failed: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Left Click to get the UV coordinates at the mouse pointer\nThe three sets of UV coordinates below are, from top to bottom, the UV coordinates of the forward vector, the upward vector, and the binding point on the target plane\nNote: %s+Scroll to switch between the different layers of the model. Manually inputting UV coordinates allows you to bind more accurately to the target position", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "The texture id of the selected model (not necessary to be the full id), can be shortened when saving to make it easier to recognize.\nFor example, shorten minecraft:textures/entity/player/slim/alex.png to minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "The parts contained in the blue boxes will be disabled\nLeft Click to select, other keys to cancel selection\n%s+Left Click to quickly select the part pointed to by the mouse pointer", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Decide the mode of %s+Left Click quick selection\n(%s+Scroll to change the selection range in the range mode)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Focused Rectangle Number\n(0 means no selection)\nPress Space or Enter to locate the current focused rectangle (When typing, press twice to locate)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Delete the selected rectangle\n(Or use the Delete key)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "When disabled, the camera's relative relationship to the model will not change, but the camera's corresponding attributes will not be modified by this mod", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Scale, which controls the size of the offsets", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Planes where all vertex-to-screen distances are less than this value will not be rendered", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Priority when binding, the larger the value the higher the priority, and the higher the sorting on the right side", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Name of the config", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Disabling Settings\nGlobal disabling settings are in the config screen", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Saved Configs", - "screen.tooltip.xtracr_realcamera.modelView_preview": "In the preview mode, you can adjust the camera's offset and rotation", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Open Global Config Screen\n(Cloth Config API required)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copy all disabling settings", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Paste all disabling settings in the clipboard to current config\n(Will not override existing setting with the same name)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Name cannot be empty!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Texture id cannot be empty!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Save as\n(When there is a setting with the same name, you can also press the save button on the left)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Name of the disable setting" + "screen.widget.xtracr_realcamera.modelView_range": "Range", + "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Save", + "screen.widget.xtracr_realcamera.modelView_selecting": "Selecting", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Selection Mode", + "screen.widget.xtracr_realcamera.modelView_single": "Single", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Toggle Field to Slider", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Toggle Slider to Field", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Upward Vector", + "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", + "screen.xtracr_realcamera.modelView_title": "Model View" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/es_es.json b/common/src/main/resources/assets/realcamera/lang/es_es.json index 580e31fa..921cd865 100644 --- a/common/src/main/resources/assets/realcamera/lang/es_es.json +++ b/common/src/main/resources/assets/realcamera/lang/es_es.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Abrir Pantalla de Vista de Modelo", - "key.xtracr_realcamera.togglePerspective": "Activar/Desactivar", - "key.xtracr_realcamera.activeConfigIndexPREV": "Cambiar a la configuración anterior", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Cambiar a la siguiente configuración", - "key.xtracr_realcamera.activeConfigIndexRESET": "Restablecer índice de configuración", - "key.xtracr_realcamera.toggleAdjustMode": "Cambiar Modo de Ajuste", - "key.xtracr_realcamera.toggleCameraMode": "Cambiar Modo de Cámara", - "key.xtracr_realcamera.adjustUP": "Ajustar ARRIBA", - "key.xtracr_realcamera.adjustDOWN": "Ajustar ABAJO", - "key.xtracr_realcamera.adjustFRONT": "Ajustar ADELANTE", - "key.xtracr_realcamera.adjustBACK": "Ajustar ATRÁS", - "key.xtracr_realcamera.adjustLEFT": "Ajustar IZQUIERDA", - "key.xtracr_realcamera.adjustRIGHT": "Ajustar DERECHA", - "modmenu.descriptionTranslation.realcamera": "Hace que la cámara sea más realista en la vista en primera persona.", - - "config.category.xtracr_realcamera.general": "General", "config.category.xtracr_realcamera.binding": "Modo de Vinculación", - "config.category.xtracr_realcamera.classic": "Modo Clásico", "config.category.xtracr_realcamera.cameraOffset": "Desplazamiento de Cámara", - "config.category.xtracr_realcamera.centerOffset": "Desplazamiento del Centro de Rotación", "config.category.xtracr_realcamera.cameraRotation": "Rotación de Cámara", - "config.tooltip.xtracr_realcamera.classicOffset": "Desplazamiento de la cámara desde su centro de rotación", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Nota: el frente, arriba e izquierda del jugador son los ejes X, Y y Z respectivamente", - "config.tooltip.xtracr_realcamera.centerOffset": "Desplazamiento del centro de rotación desde la cabeza", - "config.tooltip.xtracr_realcamera.cameraRotation": "Rotación adicional de la cámara en grados", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Nota: Pitch, yaw y roll son rotaciones en los ejes izquierda, arriba y frente respectivamente", - - "config.option.xtracr_realcamera.enabled": "Mod Activado", - "config.option.xtracr_realcamera.isClassic": "Modo Clásico", - "config.option.xtracr_realcamera.dynamicCrosshair": "Mira Dinámica", - "config.option.xtracr_realcamera.renderModel": "Renderizar Modelo de Jugador", + "config.category.xtracr_realcamera.centerOffset": "Desplazamiento del Centro de Rotación", + "config.category.xtracr_realcamera.classic": "Modo Clásico", + "config.category.xtracr_realcamera.general": "General", + "config.option.xtracr_realcamera.activeConfigIndex": "Índice de configuración activa", + "config.option.xtracr_realcamera.adjustOffset": "Ajustar Desplazamiento de Cámara", "config.option.xtracr_realcamera.adjustStep": "Paso de Ajuste", - "config.option.xtracr_realcamera.classicAdjustMode": "Modo de Ajuste", - "config.option.xtracr_realcamera.scale": "Escala", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Marcos de retención de resultado de vinculación", "config.option.xtracr_realcamera.cameraOffset": "Desplazamiento de Cámara %s", "config.option.xtracr_realcamera.centerOffset": "Desplazamiento del Centro de Rotación %s", - "config.option.xtracr_realcamera.pitch": "Pitch", - "config.option.xtracr_realcamera.yaw": "Yaw", - "config.option.xtracr_realcamera.roll": "Roll", - "config.option.xtracr_realcamera.toModelViewScreen": "Para configuraciones detalladas, por favor vaya a la pantalla %s (se necesita configurar una tecla para abrirla)", - "config.option.xtracr_realcamera.screenModifierKey": "Tecla modificadora de pantalla %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Modo de Enlace Heredado", - "config.option.xtracr_realcamera.adjustOffset": "Ajustar Desplazamiento de Cámara", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensajes de fallo de vinculación", - "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Atascados", - "config.option.xtracr_realcamera.rerenderModel": "Re-renderizar Modelo", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Marcos de retención de resultado de vinculación", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Factor de suavizado de desplazamiento", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Factor de suavizado de rotación", - "config.option.xtracr_realcamera.activeConfigIndex": "Índice de configuración activa", + "config.option.xtracr_realcamera.classicAdjustMode": "Modo de Ajuste", "config.option.xtracr_realcamera.disableConfig": "Configuración Desactivada", - "config.option.xtracr_realcamera.disableWhenSneaking": "Desactivar función principal al agacharse", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Desactivar función principal al sostener...", + "config.option.xtracr_realcamera.disableRenderItems": "Desactivar renderizado al sostener...", "config.option.xtracr_realcamera.disableWhenCrawling": "Desactivar función principal al gatear", + "config.option.xtracr_realcamera.disableWhenSneaking": "Desactivar función principal al agacharse", "config.option.xtracr_realcamera.disableWhenSwimming": "Desactivar función principal al nadar", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Factor de suavizado de desplazamiento", + "config.option.xtracr_realcamera.dynamicCrosshair": "Mira Dinámica", + "config.option.xtracr_realcamera.enabled": "Mod Activado", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensajes de fallo de vinculación", + "config.option.xtracr_realcamera.isClassic": "Modo Clásico", + "config.option.xtracr_realcamera.legacyBindingMode": "Modo de Enlace Heredado", "config.option.xtracr_realcamera.outTick": "Retraso al salir del estado de natación (en ticks)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Desactivar función principal al sostener...", - "config.option.xtracr_realcamera.disableRenderItems": "Desactivar renderizado al sostener...", - "config.tooltip.xtracr_realcamera.isClassic": "El modo clásico solo hace cambios simples a la posición y rotación de la cámara", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Cuando está activado, la mira seguirá la vista del jugador, asegurando resultados de impacto consistentes\nRecomendado activar cuando están instalados mods como Jade, WTHIT o similares", - "config.tooltip.xtracr_realcamera.renderModel": "Renderizar modelo del jugador en perspectiva en primera persona", + "config.option.xtracr_realcamera.pitch": "Pitch", + "config.option.xtracr_realcamera.renderModel": "Renderizar Modelo de Jugador", + "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Atascados", + "config.option.xtracr_realcamera.rerenderModel": "Re-renderizar Modelo", + "config.option.xtracr_realcamera.roll": "Roll", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Factor de suavizado de rotación", + "config.option.xtracr_realcamera.scale": "Escala", + "config.option.xtracr_realcamera.screenModifierKey": "Tecla modificadora de pantalla %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Para configuraciones detalladas, por favor vaya a la pantalla %s (se necesita configurar una tecla para abrirla)", + "config.option.xtracr_realcamera.yaw": "Yaw", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuración actualmente vinculada, 0 significa permitir la vinculación a cualquier configuración válida", + "config.tooltip.xtracr_realcamera.adjustOffset": "Al presionar la tecla de ajuste, ajusta el desplazamiento o rotación de la cámara", "config.tooltip.xtracr_realcamera.adjustStep": "Longitud o 1/100 del ángulo del ajuste por paso", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Durante varios fotogramas después del fallo de vinculación, continuar utilizando el resultado de vinculación exitoso anterior", + "config.tooltip.xtracr_realcamera.cameraRotation": "Rotación adicional de la cámara en grados", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Nota: Pitch, yaw y roll son rotaciones en los ejes izquierda, arriba y frente respectivamente", + "config.tooltip.xtracr_realcamera.centerOffset": "Desplazamiento del centro de rotación desde la cabeza", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Determina qué ajustar al presionar la tecla de ajuste", - "config.tooltip.xtracr_realcamera.scale": "Controla el tamaño de los desplazamientos", + "config.tooltip.xtracr_realcamera.classicOffset": "Desplazamiento de la cámara desde su centro de rotación", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Nota: el frente, arriba e izquierda del jugador son los ejes X, Y y Z respectivamente", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Se admiten tres métodos de coincidencia:\n1. Coincidencia con comodín `*` (por ejemplo, `minecraft:*sword`)\n2. Coincidencia de etiquetas (comienza con `#`, por ejemplo, `#minecraft:swords`)\n3. ID de objeto directo (por ejemplo, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Factor de suavizado del desplazamiento de la cámara, cuanto mayor sea el valor, más suave será el movimiento", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Cuando está activado, la mira seguirá la vista del jugador, asegurando resultados de impacto consistentes\nRecomendado activar cuando están instalados mods como Jade, WTHIT o similares", + "config.tooltip.xtracr_realcamera.isClassic": "El modo clásico solo hace cambios simples a la posición y rotación de la cámara", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Usando el modo de enlace de la versión heredada (v0.5), solo se admiten modelos vanilla y acciones basadas en modelos vanilla\nSus propiedades se pueden configurar en 'LEGACY_MODE' de la pantalla %s cuando está habilitado", - "config.tooltip.xtracr_realcamera.adjustOffset": "Al presionar la tecla de ajuste, ajusta el desplazamiento o rotación de la cámara", + "config.tooltip.xtracr_realcamera.outTick": "Tiempo antes de activar la función principal después de salir del estado de natación (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Renderizar modelo del jugador en perspectiva en primera persona", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flechas, picaduras de abeja y otros objetos que pueden quedar atascados en el cuerpo del jugador", "config.tooltip.xtracr_realcamera.rerenderModel": "Renderizar el modelo nuevamente en el momento original de renderizado para evitar problemas visuales causados por renderizado temprano", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Durante varios fotogramas después del fallo de vinculación, continuar utilizando el resultado de vinculación exitoso anterior", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Factor de suavizado del desplazamiento de la cámara, cuanto mayor sea el valor, más suave será el movimiento", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Factor de suavizado de la rotación de la cámara, cuanto mayor sea el valor, más suave será el movimiento", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuración actualmente vinculada, 0 significa permitir la vinculación a cualquier configuración válida", - "config.tooltip.xtracr_realcamera.outTick": "Tiempo antes de activar la función principal después de salir del estado de natación (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Se admiten tres métodos de coincidencia:\n1. Coincidencia con comodín `*` (por ejemplo, `minecraft:*sword`)\n2. Coincidencia de etiquetas (comienza con `#`, por ejemplo, `#minecraft:swords`)\n3. ID de objeto directo (por ejemplo, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Controla el tamaño de los desplazamientos", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Cambiar a la siguiente configuración", + "key.xtracr_realcamera.activeConfigIndexPREV": "Cambiar a la configuración anterior", + "key.xtracr_realcamera.activeConfigIndexRESET": "Restablecer índice de configuración", + "key.xtracr_realcamera.adjustBACK": "Ajustar ATRÁS", + "key.xtracr_realcamera.adjustDOWN": "Ajustar ABAJO", + "key.xtracr_realcamera.adjustFRONT": "Ajustar ADELANTE", + "key.xtracr_realcamera.adjustLEFT": "Ajustar IZQUIERDA", + "key.xtracr_realcamera.adjustRIGHT": "Ajustar DERECHA", + "key.xtracr_realcamera.adjustUP": "Ajustar ARRIBA", + "key.xtracr_realcamera.modelViewScreen": "Abrir Pantalla de Vista de Modelo", + "key.xtracr_realcamera.toggleAdjustMode": "Cambiar Modo de Ajuste", + "key.xtracr_realcamera.toggleCameraMode": "Cambiar Modo de Cámara", + "key.xtracr_realcamera.togglePerspective": "Activar/Desactivar", "message.xtracr_realcamera.bindingFailed": "[%s]: Vinculación fallida, por favor vaya a la pantalla %s y configure manualmente (tecla: %s)", - - "screen.xtracr_realcamera.modelView_title": "Vista de Modelo", - "screen.widget.xtracr_realcamera.modelView_import": "Importar", + "modmenu.descriptionTranslation.realcamera": "Hace que la cámara sea más realista en la vista en primera persona.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Cuando está desactivado, la relación relativa de la cámara con el modelo no cambiará, pero los atributos correspondientes de la cámara no serán modificados por este mod", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Configuraciones Guardadas", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas las configuraciones de desactivación", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Eliminar el rectángulo seleccionado\n(O usar la tecla Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Los planos donde todas las distancias de vértice a pantalla son menores que este valor no se renderizarán", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Configuraciones de Desactivación\nLas configuraciones globales de desactivación están en la pantalla de configuración", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Las partes contenidas en los cuadros azules serán desactivadas\nClic izquierdo para seleccionar, otras teclas para cancelar la selección\n%s+Clic izquierdo para seleccionar rápidamente la parte señalada por el puntero del ratón", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nombre de la configuración de desactivación", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "¡El nombre no puede estar vacío!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "¡El ID de textura no puede estar vacío!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Exportar la configuración actual al portapapeles", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Exportación fallida: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "¡Exportación exitosa!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Número de Rectángulo Enfocado\n(0 significa sin selección)\nPresione Espacio o Enter para localizar el rectángulo enfocado actual (Al escribir, presione dos veces para localizar)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Importar la configuración desde el portapapeles", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Importación fallida: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "¡Importación %s exitosa!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Pegar todas las configuraciones de desactivación del portapapeles a la configuración actual\n(No sobrescribirá la configuración existente con el mismo nombre)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "En el modo de vista previa, puedes ajustar el desplazamiento y rotación de la cámara", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridad al vincular, cuanto mayor sea el valor, mayor será la prioridad y más alto será el orden en el lado derecho", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Guardar como\n(Cuando existe una configuración con el mismo nombre, también puede usar el botón guardar a la izquierda)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla el tamaño de los desplazamientos", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clic izquierdo para obtener las coordenadas UV en el puntero del ratón\nLos tres conjuntos de coordenadas UV a continuación son, de arriba a abajo, las coordenadas UV del vector adelante, el vector arriba y el punto de vinculación en el plano objetivo\nNota: %s+Desplazarse para cambiar entre las diferentes capas del modelo. Ingresar manualmente las coordenadas UV permite vincular con mayor precisión a la posición objetivo", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina el modo de selección rápida %s+Clic izquierdo\n(%s+Desplazarse para cambiar el rango de selección en el modo de rango)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nombre de la configuración", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "El ID de textura del modelo seleccionado (no es necesario que sea el ID completo), se puede acortar al guardar para que sea más fácil de reconocer.\nPor ejemplo, acortar minecraft:textures/entity/player/slim/alex.png a minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir la Pantalla de Configuración Global\n(Requiere Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "Todo", + "screen.widget.xtracr_realcamera.modelView_configs": "Configuraciones", + "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuración Actual", + "screen.widget.xtracr_realcamera.modelView_disable": "Desactivar", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo Desactivado", "screen.widget.xtracr_realcamera.modelView_export": "Exportar", - "screen.widget.xtracr_realcamera.modelView_selecting": "Seleccionando", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Vector Adelante", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vector Arriba", - "screen.widget.xtracr_realcamera.modelView_position": "Plano Objetivo", - "screen.widget.xtracr_realcamera.modelView_save": "Guardar", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo Desactivado", - "screen.widget.xtracr_realcamera.modelView_all": "Todo", - "screen.widget.xtracr_realcamera.modelView_part": "Parte", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Modo de Selección", - "screen.widget.xtracr_realcamera.modelView_single": "Único", + "screen.widget.xtracr_realcamera.modelView_import": "Importar", "screen.widget.xtracr_realcamera.modelView_multiple": "Múltiple", - "screen.widget.xtracr_realcamera.modelView_range": "Rango", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Cambiar de Deslizador a Campo", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Cambiar de Campo a Deslizador", "screen.widget.xtracr_realcamera.modelView_offsetX": "Desplazamiento X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Desplazamiento Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Desplazamiento Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Parte", + "screen.widget.xtracr_realcamera.modelView_paste": "Pegar", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Desactivar", + "screen.widget.xtracr_realcamera.modelView_position": "Plano Objetivo", "screen.widget.xtracr_realcamera.modelView_preview": "Vista Previa", - "screen.widget.xtracr_realcamera.modelView_configs": "Configuraciones", - "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", - "screen.widget.xtracr_realcamera.modelView_paste": "Pegar", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuración Actual", - "screen.tooltip.xtracr_realcamera.modelView_import": "Importar la configuración desde el portapapeles", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "¡Importación %s exitosa!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Importación fallida: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Exportar la configuración actual al portapapeles", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "¡Exportación exitosa!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Exportación fallida: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clic izquierdo para obtener las coordenadas UV en el puntero del ratón\nLos tres conjuntos de coordenadas UV a continuación son, de arriba a abajo, las coordenadas UV del vector adelante, el vector arriba y el punto de vinculación en el plano objetivo\nNota: %s+Desplazarse para cambiar entre las diferentes capas del modelo. Ingresar manualmente las coordenadas UV permite vincular con mayor precisión a la posición objetivo", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "El ID de textura del modelo seleccionado (no es necesario que sea el ID completo), se puede acortar al guardar para que sea más fácil de reconocer.\nPor ejemplo, acortar minecraft:textures/entity/player/slim/alex.png a minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Las partes contenidas en los cuadros azules serán desactivadas\nClic izquierdo para seleccionar, otras teclas para cancelar la selección\n%s+Clic izquierdo para seleccionar rápidamente la parte señalada por el puntero del ratón", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina el modo de selección rápida %s+Clic izquierdo\n(%s+Desplazarse para cambiar el rango de selección en el modo de rango)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Número de Rectángulo Enfocado\n(0 significa sin selección)\nPresione Espacio o Enter para localizar el rectángulo enfocado actual (Al escribir, presione dos veces para localizar)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Eliminar el rectángulo seleccionado\n(O usar la tecla Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Cuando está desactivado, la relación relativa de la cámara con el modelo no cambiará, pero los atributos correspondientes de la cámara no serán modificados por este mod", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla el tamaño de los desplazamientos", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Los planos donde todas las distancias de vértice a pantalla son menores que este valor no se renderizarán", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridad al vincular, cuanto mayor sea el valor, mayor será la prioridad y más alto será el orden en el lado derecho", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nombre de la configuración", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Configuraciones de Desactivación\nLas configuraciones globales de desactivación están en la pantalla de configuración", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Configuraciones Guardadas", - "screen.tooltip.xtracr_realcamera.modelView_preview": "En el modo de vista previa, puedes ajustar el desplazamiento y rotación de la cámara", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir la Pantalla de Configuración Global\n(Requiere Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas las configuraciones de desactivación", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Pegar todas las configuraciones de desactivación del portapapeles a la configuración actual\n(No sobrescribirá la configuración existente con el mismo nombre)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "¡El nombre no puede estar vacío!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "¡El ID de textura no puede estar vacío!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Guardar como\n(Cuando existe una configuración con el mismo nombre, también puede usar el botón guardar a la izquierda)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nombre de la configuración de desactivación" + "screen.widget.xtracr_realcamera.modelView_range": "Rango", + "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Guardar", + "screen.widget.xtracr_realcamera.modelView_selecting": "Seleccionando", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Modo de Selección", + "screen.widget.xtracr_realcamera.modelView_single": "Único", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Cambiar de Campo a Deslizador", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Cambiar de Deslizador a Campo", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vector Arriba", + "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", + "screen.xtracr_realcamera.modelView_title": "Vista de Modelo" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/fr_fr.json b/common/src/main/resources/assets/realcamera/lang/fr_fr.json index 581ef6b6..69dd50bf 100644 --- a/common/src/main/resources/assets/realcamera/lang/fr_fr.json +++ b/common/src/main/resources/assets/realcamera/lang/fr_fr.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Ouvrir l'écran de visualisation du modèle", - "key.xtracr_realcamera.togglePerspective": "Activer/Désactiver", - "key.xtracr_realcamera.activeConfigIndexPREV": "Passer à la configuration précédente", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Passer à la configuration suivante", - "key.xtracr_realcamera.activeConfigIndexRESET": "Réinitialiser l'index de configuration", - "key.xtracr_realcamera.toggleAdjustMode": "Basculer le mode d'ajustement", - "key.xtracr_realcamera.toggleCameraMode": "Basculer le mode caméra", - "key.xtracr_realcamera.adjustUP": "Ajuster vers le HAUT", - "key.xtracr_realcamera.adjustDOWN": "Ajuster vers le BAS", - "key.xtracr_realcamera.adjustFRONT": "Ajuster vers l'AVANT", - "key.xtracr_realcamera.adjustBACK": "Ajuster vers l'ARRIÈRE", - "key.xtracr_realcamera.adjustLEFT": "Ajuster vers la GAUCHE", - "key.xtracr_realcamera.adjustRIGHT": "Ajuster vers la DROITE", - "modmenu.descriptionTranslation.realcamera": "Rendre la caméra plus réaliste en vue à la première personne.", - - "config.category.xtracr_realcamera.general": "Général", "config.category.xtracr_realcamera.binding": "Mode Liaison", - "config.category.xtracr_realcamera.classic": "Mode Classique", "config.category.xtracr_realcamera.cameraOffset": "Décalage Caméra", - "config.category.xtracr_realcamera.centerOffset": "Décalage Centre Rotation", "config.category.xtracr_realcamera.cameraRotation": "Rotation Caméra", - "config.tooltip.xtracr_realcamera.classicOffset": "Décalage de la caméra par rapport à son centre de rotation", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Note : l'avant, le haut et la gauche du joueur sont respectivement les axes X, Y et Z", - "config.tooltip.xtracr_realcamera.centerOffset": "Décalage du centre de rotation par rapport à la tête", - "config.tooltip.xtracr_realcamera.cameraRotation": "Rotation supplémentaire de la caméra en degrés", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Note : Pitch, yaw et roll sont des rotations sur les axes gauche, haut et avant respectivement", - - "config.option.xtracr_realcamera.enabled": "Mod Activé", - "config.option.xtracr_realcamera.isClassic": "Mode Classique", - "config.option.xtracr_realcamera.dynamicCrosshair": "Réticule Dynamique", - "config.option.xtracr_realcamera.renderModel": "Afficher le Modèle du Joueur", + "config.category.xtracr_realcamera.centerOffset": "Décalage Centre Rotation", + "config.category.xtracr_realcamera.classic": "Mode Classique", + "config.category.xtracr_realcamera.general": "Général", + "config.option.xtracr_realcamera.activeConfigIndex": "Index de configuration actif", + "config.option.xtracr_realcamera.adjustOffset": "Ajuster le Décalage Caméra", "config.option.xtracr_realcamera.adjustStep": "Pas d'Ajustement", - "config.option.xtracr_realcamera.classicAdjustMode": "Mode d'Ajustement", - "config.option.xtracr_realcamera.scale": "Échelle", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Images de rétention des résultats de liaison", "config.option.xtracr_realcamera.cameraOffset": "Décalage Caméra %s", "config.option.xtracr_realcamera.centerOffset": "Décalage Centre Rotation %s", - "config.option.xtracr_realcamera.pitch": "Pitch", - "config.option.xtracr_realcamera.yaw": "Yaw", - "config.option.xtracr_realcamera.roll": "Roll", - "config.option.xtracr_realcamera.toModelViewScreen": "Pour les paramètres détaillés, veuillez aller à l'écran %s (un raccourci clavier doit être défini pour l'ouvrir)", - "config.option.xtracr_realcamera.screenModifierKey": "Touche modifi d'écran %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Mode de Liaison Hérité", - "config.option.xtracr_realcamera.adjustOffset": "Ajuster le Décalage Caméra", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Masquer les messages d'échec de liaison", - "config.option.xtracr_realcamera.renderStuckObjects": "Afficher les Objets Coincés", - "config.option.xtracr_realcamera.rerenderModel": "Réafficher le Modèle", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Images de rétention des résultats de liaison", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Facteur de lissage du déplacement", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Facteur de lissage de la rotation", - "config.option.xtracr_realcamera.activeConfigIndex": "Index de configuration actif", + "config.option.xtracr_realcamera.classicAdjustMode": "Mode d'Ajustement", "config.option.xtracr_realcamera.disableConfig": "Config Désactivée", - "config.option.xtracr_realcamera.disableWhenSneaking": "Désactiver la fonctionnalité principale en se faufilant", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Désactiver la fonctionnalité principale en tenant...", + "config.option.xtracr_realcamera.disableRenderItems": "Désactiver le rendu en tenant...", "config.option.xtracr_realcamera.disableWhenCrawling": "Désactiver la fonctionnalité principale en rampant", + "config.option.xtracr_realcamera.disableWhenSneaking": "Désactiver la fonctionnalité principale en se faufilant", "config.option.xtracr_realcamera.disableWhenSwimming": "Désactiver la fonctionnalité principale en nageant", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Facteur de lissage du déplacement", + "config.option.xtracr_realcamera.dynamicCrosshair": "Réticule Dynamique", + "config.option.xtracr_realcamera.enabled": "Mod Activé", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Masquer les messages d'échec de liaison", + "config.option.xtracr_realcamera.isClassic": "Mode Classique", + "config.option.xtracr_realcamera.legacyBindingMode": "Mode de Liaison Hérité", "config.option.xtracr_realcamera.outTick": "Délai de sortie de l'état de nage (en ticks)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Désactiver la fonctionnalité principale en tenant...", - "config.option.xtracr_realcamera.disableRenderItems": "Désactiver le rendu en tenant...", - "config.tooltip.xtracr_realcamera.isClassic": "Le mode classique ne fait que des changements simples à la position et à la rotation de la caméra", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Lorsqu'il est activé, le réticule suivra la vue du joueur, garantissant un résultat de frappe cohérent\nRecommandé d'activer lorsque Jade, WTHIT ou des mods similaires sont installés", - "config.tooltip.xtracr_realcamera.renderModel": "Afficher le modèle du joueur en vue à la première personne", + "config.option.xtracr_realcamera.pitch": "Pitch", + "config.option.xtracr_realcamera.renderModel": "Afficher le Modèle du Joueur", + "config.option.xtracr_realcamera.renderStuckObjects": "Afficher les Objets Coincés", + "config.option.xtracr_realcamera.rerenderModel": "Réafficher le Modèle", + "config.option.xtracr_realcamera.roll": "Roll", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Facteur de lissage de la rotation", + "config.option.xtracr_realcamera.scale": "Échelle", + "config.option.xtracr_realcamera.screenModifierKey": "Touche modifi d'écran %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Pour les paramètres détaillés, veuillez aller à l'écran %s (un raccourci clavier doit être défini pour l'ouvrir)", + "config.option.xtracr_realcamera.yaw": "Yaw", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Index de configuration actuellement lié, 0 signifie autoriser la liaison à toute configuration valide", + "config.tooltip.xtracr_realcamera.adjustOffset": "Lors de l'appui sur la touche d'ajustement, ajuster le décalage ou la rotation de la caméra", "config.tooltip.xtracr_realcamera.adjustStep": "Longueur ou 1/100 de l'angle de l'ajustement par étape", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Pendant plusieurs images après l'échec de la liaison, continuer à utiliser le résultat de liaison réussi précédent", + "config.tooltip.xtracr_realcamera.cameraRotation": "Rotation supplémentaire de la caméra en degrés", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Note : Pitch, yaw et roll sont des rotations sur les axes gauche, haut et avant respectivement", + "config.tooltip.xtracr_realcamera.centerOffset": "Décalage du centre de rotation par rapport à la tête", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Détermine quoi ajuster lors de l'appui sur la touche d'ajustement", - "config.tooltip.xtracr_realcamera.scale": "Contrôler la taille des décalages", + "config.tooltip.xtracr_realcamera.classicOffset": "Décalage de la caméra par rapport à son centre de rotation", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Note : l'avant, le haut et la gauche du joueur sont respectivement les axes X, Y et Z", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Trois méthodes de correspondance sont prises en charge :\n1. Correspondance avec joker `*` (par exemple, `minecraft:*sword`)\n2. Correspondance d'étiquette (commence par `#`, par exemple, `#minecraft:swords`)\n3. ID d'objet direct (par exemple, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Facteur de lissage du déplacement de la caméra, plus la valeur est élevée, plus le mouvement est fluide", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Lorsqu'il est activé, le réticule suivra la vue du joueur, garantissant un résultat de frappe cohérent\nRecommandé d'activer lorsque Jade, WTHIT ou des mods similaires sont installés", + "config.tooltip.xtracr_realcamera.isClassic": "Le mode classique ne fait que des changements simples à la position et à la rotation de la caméra", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Utilisation du mode de liaison de la version héritée (v0.5), seuls les modèles vanilla et les actions basées sur des modèles vanilla sont pris en charge\nSes propriétés peuvent être définies dans 'LEGACY_MODE' de l'écran %s lorsqu'il est activé", - "config.tooltip.xtracr_realcamera.adjustOffset": "Lors de l'appui sur la touche d'ajustement, ajuster le décalage ou la rotation de la caméra", + "config.tooltip.xtracr_realcamera.outTick": "Le délai d'activation de la fonction principale après la sortie de l'état de nage (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Afficher le modèle du joueur en vue à la première personne", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flèches, piqûres d'abeille et autres objets pouvant être coincés dans le corps du joueur", "config.tooltip.xtracr_realcamera.rerenderModel": "Afficher à nouveau le modèle au moment du rendu original pour éviter certains problèmes visuels causés par un rendu précoce", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Pendant plusieurs images après l'échec de la liaison, continuer à utiliser le résultat de liaison réussi précédent", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Facteur de lissage du déplacement de la caméra, plus la valeur est élevée, plus le mouvement est fluide", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Facteur de lissage de la rotation de la caméra, plus la valeur est élevée, plus le mouvement est fluide", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Index de configuration actuellement lié, 0 signifie autoriser la liaison à toute configuration valide", - "config.tooltip.xtracr_realcamera.outTick": "Le délai d'activation de la fonction principale après la sortie de l'état de nage (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Trois méthodes de correspondance sont prises en charge :\n1. Correspondance avec joker `*` (par exemple, `minecraft:*sword`)\n2. Correspondance d'étiquette (commence par `#`, par exemple, `#minecraft:swords`)\n3. ID d'objet direct (par exemple, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Contrôler la taille des décalages", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Passer à la configuration suivante", + "key.xtracr_realcamera.activeConfigIndexPREV": "Passer à la configuration précédente", + "key.xtracr_realcamera.activeConfigIndexRESET": "Réinitialiser l'index de configuration", + "key.xtracr_realcamera.adjustBACK": "Ajuster vers l'ARRIÈRE", + "key.xtracr_realcamera.adjustDOWN": "Ajuster vers le BAS", + "key.xtracr_realcamera.adjustFRONT": "Ajuster vers l'AVANT", + "key.xtracr_realcamera.adjustLEFT": "Ajuster vers la GAUCHE", + "key.xtracr_realcamera.adjustRIGHT": "Ajuster vers la DROITE", + "key.xtracr_realcamera.adjustUP": "Ajuster vers le HAUT", + "key.xtracr_realcamera.modelViewScreen": "Ouvrir l'écran de visualisation du modèle", + "key.xtracr_realcamera.toggleAdjustMode": "Basculer le mode d'ajustement", + "key.xtracr_realcamera.toggleCameraMode": "Basculer le mode caméra", + "key.xtracr_realcamera.togglePerspective": "Activer/Désactiver", "message.xtracr_realcamera.bindingFailed": "[%s]: Échec de la liaison, veuillez aller à l'écran %s et configurer manuellement (touche: %s)", - - "screen.xtracr_realcamera.modelView_title": "Vue Modèle", - "screen.widget.xtracr_realcamera.modelView_import": "Importer", + "modmenu.descriptionTranslation.realcamera": "Rendre la caméra plus réaliste en vue à la première personne.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Lorsqu'il est désactivé, la relation relative de la caméra avec le modèle ne changera pas, mais les attributs correspondants de la caméra ne seront pas modifiés par ce mod", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurations enregistrées", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Copier tous les paramètres de désactivation", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Supprimer le rectangle sélectionné\n(Ou utiliser la touche Suppr)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Les plans où toutes les distances vertex-à-écran sont inférieures à cette valeur ne seront pas rendus", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Paramètres de désactivation\nLes paramètres de désactivation globaux se trouvent dans l'écran de configuration", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Les parties contenues dans les cadres bleus seront désactivées\nClic gauche pour sélectionner, autres touches pour annuler la sélection\n%s+Clic gauche pour sélectionner rapidement la partie pointée par le curseur de la souris", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nom du paramètre de désactivation", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Le nom ne peut pas être vide !", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "L'identifiant de texture ne peut pas être vide !", + "screen.tooltip.xtracr_realcamera.modelView_export": "Exporter la configuration actuelle vers le presse-papiers", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Échec de l'exportation : \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Exportation réussie !", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Numéro du rectangle focalisé\n(0 signifie aucune sélection)\nAppuyez sur Espace ou Entrée pour localiser le rectangle focalisé actuel (Lors de la frappe, appuyez deux fois pour localiser)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Importer la configuration depuis le presse-papiers", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Échec de l'importation : \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importation %s réussie !", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Coller tous les paramètres de désactivation du presse-papiers dans la configuration actuelle\n(Ne remplacera pas les paramètres existants portant le même nom)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "En mode aperçu, vous pouvez ajuster le décalage et la rotation de la caméra", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorité lors de la liaison, plus la valeur est grande, plus la priorité est élevée et plus le tri est haut sur le côté droit", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Enregistrer sous\n(Lorsqu'il existe une configuration avec le même nom, vous pouvez également utiliser le bouton enregistrer à gauche)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Échelle, qui contrôle la taille des décalages", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clic gauche pour obtenir les coordonnées UV au niveau du pointeur de la souris\nLes trois ensembles de coordonnées UV ci-dessous sont, de haut en bas, les coordonnées UV du vecteur avant, du vecteur haut et du point de liaison sur le plan cible\nNote : %s+Défilement pour basculer entre les différentes couches du modèle. La saisie manuelle des coordonnées UV permet de se lier plus précisément à la position cible", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Détermine le mode de sélection rapide %s+Clic gauche\n(%s+Défilement pour changer la plage de sélection en mode plage)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nom de la configuration", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "L'identifiant de texture du modèle sélectionné (pas nécessairement l'identifiant complet), peut être raccourci lors de l'enregistrement pour faciliter la reconnaissance.\nPar exemple, raccourcissez minecraft:textures/entity/player/slim/alex.png en minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Ouvrir l'écran de configuration globale\n(API Cloth Config requise)", + "screen.widget.xtracr_realcamera.modelView_all": "Tout", + "screen.widget.xtracr_realcamera.modelView_configs": "Configurations", + "screen.widget.xtracr_realcamera.modelView_copy": "Copier", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Config Actuelle", + "screen.widget.xtracr_realcamera.modelView_disable": "Désactiver", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Mode Désactivé", "screen.widget.xtracr_realcamera.modelView_export": "Exporter", - "screen.widget.xtracr_realcamera.modelView_selecting": "Sélection", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Vecteur Avant", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vecteur Haut", - "screen.widget.xtracr_realcamera.modelView_position": "Plan Cible", - "screen.widget.xtracr_realcamera.modelView_save": "Enregistrer", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Mode Désactivé", - "screen.widget.xtracr_realcamera.modelView_all": "Tout", - "screen.widget.xtracr_realcamera.modelView_part": "Partie", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Mode de Sélection", - "screen.widget.xtracr_realcamera.modelView_single": "Unique", + "screen.widget.xtracr_realcamera.modelView_import": "Importer", "screen.widget.xtracr_realcamera.modelView_multiple": "Multiple", - "screen.widget.xtracr_realcamera.modelView_range": "Plage", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Basculer du curseur au champ", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Basculer du champ au curseur", "screen.widget.xtracr_realcamera.modelView_offsetX": "Décalage X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Décalage Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Décalage Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Partie", + "screen.widget.xtracr_realcamera.modelView_paste": "Coller", "screen.widget.xtracr_realcamera.modelView_pitch": "Tangage = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Lacet = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Roulis = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Désactiver", + "screen.widget.xtracr_realcamera.modelView_position": "Plan Cible", "screen.widget.xtracr_realcamera.modelView_preview": "Aperçu", - "screen.widget.xtracr_realcamera.modelView_configs": "Configurations", - "screen.widget.xtracr_realcamera.modelView_copy": "Copier", - "screen.widget.xtracr_realcamera.modelView_paste": "Coller", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Config Actuelle", - "screen.tooltip.xtracr_realcamera.modelView_import": "Importer la configuration depuis le presse-papiers", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importation %s réussie !", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Échec de l'importation : \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Exporter la configuration actuelle vers le presse-papiers", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Exportation réussie !", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Échec de l'exportation : \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clic gauche pour obtenir les coordonnées UV au niveau du pointeur de la souris\nLes trois ensembles de coordonnées UV ci-dessous sont, de haut en bas, les coordonnées UV du vecteur avant, du vecteur haut et du point de liaison sur le plan cible\nNote : %s+Défilement pour basculer entre les différentes couches du modèle. La saisie manuelle des coordonnées UV permet de se lier plus précisément à la position cible", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "L'identifiant de texture du modèle sélectionné (pas nécessairement l'identifiant complet), peut être raccourci lors de l'enregistrement pour faciliter la reconnaissance.\nPar exemple, raccourcissez minecraft:textures/entity/player/slim/alex.png en minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Les parties contenues dans les cadres bleus seront désactivées\nClic gauche pour sélectionner, autres touches pour annuler la sélection\n%s+Clic gauche pour sélectionner rapidement la partie pointée par le curseur de la souris", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Détermine le mode de sélection rapide %s+Clic gauche\n(%s+Défilement pour changer la plage de sélection en mode plage)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Numéro du rectangle focalisé\n(0 signifie aucune sélection)\nAppuyez sur Espace ou Entrée pour localiser le rectangle focalisé actuel (Lors de la frappe, appuyez deux fois pour localiser)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Supprimer le rectangle sélectionné\n(Ou utiliser la touche Suppr)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Lorsqu'il est désactivé, la relation relative de la caméra avec le modèle ne changera pas, mais les attributs correspondants de la caméra ne seront pas modifiés par ce mod", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Échelle, qui contrôle la taille des décalages", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Les plans où toutes les distances vertex-à-écran sont inférieures à cette valeur ne seront pas rendus", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorité lors de la liaison, plus la valeur est grande, plus la priorité est élevée et plus le tri est haut sur le côté droit", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nom de la configuration", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Paramètres de désactivation\nLes paramètres de désactivation globaux se trouvent dans l'écran de configuration", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurations enregistrées", - "screen.tooltip.xtracr_realcamera.modelView_preview": "En mode aperçu, vous pouvez ajuster le décalage et la rotation de la caméra", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Ouvrir l'écran de configuration globale\n(API Cloth Config requise)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copier tous les paramètres de désactivation", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Coller tous les paramètres de désactivation du presse-papiers dans la configuration actuelle\n(Ne remplacera pas les paramètres existants portant le même nom)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Le nom ne peut pas être vide !", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "L'identifiant de texture ne peut pas être vide !", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Enregistrer sous\n(Lorsqu'il existe une configuration avec le même nom, vous pouvez également utiliser le bouton enregistrer à gauche)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nom du paramètre de désactivation" + "screen.widget.xtracr_realcamera.modelView_range": "Plage", + "screen.widget.xtracr_realcamera.modelView_roll": "Roulis = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Enregistrer", + "screen.widget.xtracr_realcamera.modelView_selecting": "Sélection", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Mode de Sélection", + "screen.widget.xtracr_realcamera.modelView_single": "Unique", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Basculer du champ au curseur", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Basculer du curseur au champ", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vecteur Haut", + "screen.widget.xtracr_realcamera.modelView_yaw": "Lacet = %s", + "screen.xtracr_realcamera.modelView_title": "Vue Modèle" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/ja_jp.json b/common/src/main/resources/assets/realcamera/lang/ja_jp.json index 83d42b51..7b167d1d 100644 --- a/common/src/main/resources/assets/realcamera/lang/ja_jp.json +++ b/common/src/main/resources/assets/realcamera/lang/ja_jp.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "モデルビュー画面を開く", - "key.xtracr_realcamera.togglePerspective": "オン/オフ", - "key.xtracr_realcamera.activeConfigIndexPREV": "前の設定に切り替え", - "key.xtracr_realcamera.activeConfigIndexNEXT": "次の設定に切り替え", - "key.xtracr_realcamera.activeConfigIndexRESET": "設定インデックスをリセット", - "key.xtracr_realcamera.toggleAdjustMode": "調整モードを切り替え", - "key.xtracr_realcamera.toggleCameraMode": "カメラモードを切り替え", - "key.xtracr_realcamera.adjustUP": "上に調整", - "key.xtracr_realcamera.adjustDOWN": "下に調整", - "key.xtracr_realcamera.adjustFRONT": "前に調整", - "key.xtracr_realcamera.adjustBACK": "後ろに調整", - "key.xtracr_realcamera.adjustLEFT": "左に調整", - "key.xtracr_realcamera.adjustRIGHT": "右に調整", - "modmenu.descriptionTranslation.realcamera": "一人称視点のカメラをよりリアルにします。", - - "config.category.xtracr_realcamera.general": "一般", "config.category.xtracr_realcamera.binding": "バインディングモード", - "config.category.xtracr_realcamera.classic": "クラシックモード", "config.category.xtracr_realcamera.cameraOffset": "カメラオフセット", - "config.category.xtracr_realcamera.centerOffset": "回転中心オフセット", "config.category.xtracr_realcamera.cameraRotation": "カメラ回転", - "config.tooltip.xtracr_realcamera.classicOffset": "カメラの回転中心に対するオフセット値", - "config.tooltip.xtracr_realcamera.classicOffset_n": "注: プレイヤーの前方、上方、左方がそれぞれX、Y、Z軸", - "config.tooltip.xtracr_realcamera.centerOffset": "回転中心の頭部に対するオフセット値", - "config.tooltip.xtracr_realcamera.cameraRotation": "追加のカメラ回転角度", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "注: ピッチ、ヨー、ロールはそれぞれ左方、上方、前方を軸とした回転", - - "config.option.xtracr_realcamera.enabled": "機能を有効にする", - "config.option.xtracr_realcamera.isClassic": "クラシックモード", - "config.option.xtracr_realcamera.dynamicCrosshair": "動的クロスヘア", - "config.option.xtracr_realcamera.renderModel": "プレイヤーモデルをレンダリング", + "config.category.xtracr_realcamera.centerOffset": "回転中心オフセット", + "config.category.xtracr_realcamera.classic": "クラシックモード", + "config.category.xtracr_realcamera.general": "一般", + "config.option.xtracr_realcamera.activeConfigIndex": "現在の設定インデックス", + "config.option.xtracr_realcamera.adjustOffset": "カメラオフセットを調整", "config.option.xtracr_realcamera.adjustStep": "調整ステップ", - "config.option.xtracr_realcamera.classicAdjustMode": "調整モード", - "config.option.xtracr_realcamera.scale": "スケール", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "バインディング結果保持フレーム数", "config.option.xtracr_realcamera.cameraOffset": "カメラ%sオフセット", "config.option.xtracr_realcamera.centerOffset": "回転中心%sオフセット", - "config.option.xtracr_realcamera.pitch": "ピッチ角", - "config.option.xtracr_realcamera.yaw": "ヨー角", - "config.option.xtracr_realcamera.roll": "ロール角", - "config.option.xtracr_realcamera.toModelViewScreen": "詳細設定は%s画面で行ってください(開くにはホットキーを設定する必要があります)", - "config.option.xtracr_realcamera.screenModifierKey": "%s画面修飾キー", - "config.option.xtracr_realcamera.legacyBindingMode": "旧バインディングモード", - "config.option.xtracr_realcamera.adjustOffset": "カメラオフセットを調整", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "バインディング失敗メッセージを非表示", - "config.option.xtracr_realcamera.renderStuckObjects": "体に刺さったオブジェクトをレンダリング", - "config.option.xtracr_realcamera.rerenderModel": "モデルを再レンダリング", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "バインディング結果保持フレーム数", - "config.option.xtracr_realcamera.displacementSmoothFactor": "変位平滑化係数", - "config.option.xtracr_realcamera.rotationSmoothFactor": "回転平滑化係数", - "config.option.xtracr_realcamera.activeConfigIndex": "現在の設定インデックス", + "config.option.xtracr_realcamera.classicAdjustMode": "調整モード", "config.option.xtracr_realcamera.disableConfig": "無効設定", - "config.option.xtracr_realcamera.disableWhenSneaking": "スニーク時にメイン機能を無効化", + "config.option.xtracr_realcamera.disableMainFeatureItems": "...を持っている時にメイン機能を無効化", + "config.option.xtracr_realcamera.disableRenderItems": "...を持っている時にレンダリングを無効化", "config.option.xtracr_realcamera.disableWhenCrawling": "這行時にメイン機能を無効化", + "config.option.xtracr_realcamera.disableWhenSneaking": "スニーク時にメイン機能を無効化", "config.option.xtracr_realcamera.disableWhenSwimming": "泳いでいる時にメイン機能を無効化", + "config.option.xtracr_realcamera.displacementSmoothFactor": "変位平滑化係数", + "config.option.xtracr_realcamera.dynamicCrosshair": "動的クロスヘア", + "config.option.xtracr_realcamera.enabled": "機能を有効にする", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "バインディング失敗メッセージを非表示", + "config.option.xtracr_realcamera.isClassic": "クラシックモード", + "config.option.xtracr_realcamera.legacyBindingMode": "旧バインディングモード", "config.option.xtracr_realcamera.outTick": "無効状態退出遅延(単位:TICK)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "...を持っている時にメイン機能を無効化", - "config.option.xtracr_realcamera.disableRenderItems": "...を持っている時にレンダリングを無効化", - "config.tooltip.xtracr_realcamera.isClassic": "クラシックモードではカメラの位置と回転に簡単な変更のみを行います", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "有効時、クロスヘアはプレイヤーの視線に合わせて移動し、命中結果に影響を与えません\nJade、WTHITなどの類似MODがインストールされている場合に推奨", - "config.tooltip.xtracr_realcamera.renderModel": "一人称視点でプレイヤーモデルをレンダリング", + "config.option.xtracr_realcamera.pitch": "ピッチ角", + "config.option.xtracr_realcamera.renderModel": "プレイヤーモデルをレンダリング", + "config.option.xtracr_realcamera.renderStuckObjects": "体に刺さったオブジェクトをレンダリング", + "config.option.xtracr_realcamera.rerenderModel": "モデルを再レンダリング", + "config.option.xtracr_realcamera.roll": "ロール角", + "config.option.xtracr_realcamera.rotationSmoothFactor": "回転平滑化係数", + "config.option.xtracr_realcamera.scale": "スケール", + "config.option.xtracr_realcamera.screenModifierKey": "%s画面修飾キー", + "config.option.xtracr_realcamera.toModelViewScreen": "詳細設定は%s画面で行ってください(開くにはホットキーを設定する必要があります)", + "config.option.xtracr_realcamera.yaw": "ヨー角", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "現在バインドされている設定のインデックス、0は有効な設定をバインド可能", + "config.tooltip.xtracr_realcamera.adjustOffset": "現在の調整キーでカメラのオフセットまたは回転を調整", "config.tooltip.xtracr_realcamera.adjustStep": "各調整ステップの角度の1/100または長さ", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "バインディング失敗後の数フレーム間、前回成功したバインディング結果を継続使用", + "config.tooltip.xtracr_realcamera.cameraRotation": "追加のカメラ回転角度", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "注: ピッチ、ヨー、ロールはそれぞれ左方、上方、前方を軸とした回転", + "config.tooltip.xtracr_realcamera.centerOffset": "回転中心の頭部に対するオフセット値", "config.tooltip.xtracr_realcamera.classicAdjustMode": "現在の調整キーで何を調整するかを決定", - "config.tooltip.xtracr_realcamera.scale": "オフセット量のサイズを制御", + "config.tooltip.xtracr_realcamera.classicOffset": "カメラの回転中心に対するオフセット値", + "config.tooltip.xtracr_realcamera.classicOffset_n": "注: プレイヤーの前方、上方、左方がそれぞれX、Y、Z軸", + "config.tooltip.xtracr_realcamera.disableRenderItems": "3つのマッチング方法をサポート:\n1. ワイルドカード`*`マッチング(例: `minecraft:*sword`)\n2. タグマッチング(`#`で始まる、例: `#minecraft:swords`)\n3. 直接アイテムID(例: `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "カメラ変位平滑化係数、値が大きいほどスムーズ", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "有効時、クロスヘアはプレイヤーの視線に合わせて移動し、命中結果に影響を与えません\nJade、WTHITなどの類似MODがインストールされている場合に推奨", + "config.tooltip.xtracr_realcamera.isClassic": "クラシックモードではカメラの位置と回転に簡単な変更のみを行います", "config.tooltip.xtracr_realcamera.legacyBindingMode": "旧バージョン(v0.5)のバインディングモードを使用します。バニラモデルとバニラモデルベースのアクションのみサポート\n有効にすると、%sインターフェースの'LEGACY_MODE'でプロパティを設定できます", - "config.tooltip.xtracr_realcamera.adjustOffset": "現在の調整キーでカメラのオフセットまたは回転を調整", + "config.tooltip.xtracr_realcamera.outTick": "プレイヤーが特定の状態を停止した後、主機能を再開するまでの時間(1 tick = 0.05秒)", + "config.tooltip.xtracr_realcamera.renderModel": "一人称視点でプレイヤーモデルをレンダリング", "config.tooltip.xtracr_realcamera.renderStuckObjects": "矢、蜂の針などプレイヤーの体に刺さるオブジェクト", "config.tooltip.xtracr_realcamera.rerenderModel": "元のレンダリングタイミングでモデルを再レンダリングし、早期レンダリングによる視覚的問題を回避", - "config.tooltip.xtracr_realcamera.outTick": "プレイヤーが特定の状態を停止した後、主機能を再開するまでの時間(1 tick = 0.05秒)", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "バインディング失敗後の数フレーム間、前回成功したバインディング結果を継続使用", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "カメラ変位平滑化係数、値が大きいほどスムーズ", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "カメラ回転平滑化係数、値が大きいほどスムーズ", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "現在バインドされている設定のインデックス、0は有効な設定をバインド可能", - "config.tooltip.xtracr_realcamera.disableRenderItems": "3つのマッチング方法をサポート:\n1. ワイルドカード`*`マッチング(例: `minecraft:*sword`)\n2. タグマッチング(`#`で始まる、例: `#minecraft:swords`)\n3. 直接アイテムID(例: `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "オフセット量のサイズを制御", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "次の設定に切り替え", + "key.xtracr_realcamera.activeConfigIndexPREV": "前の設定に切り替え", + "key.xtracr_realcamera.activeConfigIndexRESET": "設定インデックスをリセット", + "key.xtracr_realcamera.adjustBACK": "後ろに調整", + "key.xtracr_realcamera.adjustDOWN": "下に調整", + "key.xtracr_realcamera.adjustFRONT": "前に調整", + "key.xtracr_realcamera.adjustLEFT": "左に調整", + "key.xtracr_realcamera.adjustRIGHT": "右に調整", + "key.xtracr_realcamera.adjustUP": "上に調整", + "key.xtracr_realcamera.modelViewScreen": "モデルビュー画面を開く", + "key.xtracr_realcamera.toggleAdjustMode": "調整モードを切り替え", + "key.xtracr_realcamera.toggleCameraMode": "カメラモードを切り替え", + "key.xtracr_realcamera.togglePerspective": "オン/オフ", "message.xtracr_realcamera.bindingFailed": "[%s]: バインディングに失敗しました。%s画面で手動設定してください(キー: %s)", - - "screen.xtracr_realcamera.modelView_title": "モデルビュー", - "screen.widget.xtracr_realcamera.modelView_import": "インポート", + "modmenu.descriptionTranslation.realcamera": "一人称視点のカメラをよりリアルにします。", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "無効時、カメラとモデルの相対的な位置関係は変化しませんが、カメラの対応する属性はこのMODによって変更されません", + "screen.tooltip.xtracr_realcamera.modelView_configs": "保存済み設定", + "screen.tooltip.xtracr_realcamera.modelView_copy": "全ての無効設定をコピー", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "選択された矩形を削除\n(またはDeleteキーを使用)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "全ての頂点から画面までの距離がこの値より小さい面はレンダリングされません", + "screen.tooltip.xtracr_realcamera.modelView_disable": "無効設定\nグローバル無効設定は設定画面にあります", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "青い枠で囲まれた部分は無効になります\n左側のマテリアルビューでマウスの左ボタンで選択、他のボタンで選択解除\n%s+左クリックでマウスポインタが指す部分を素早く選択できます", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "無効設定の名前", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名前は空にできません!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "テクスチャIDは空にできません!", + "screen.tooltip.xtracr_realcamera.modelView_export": "現在の設定をクリップボードにエクスポート", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "エクスポートに失敗しました: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "エクスポートに成功しました!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "選択された矩形の番号\n(0は未選択)\nスペースまたはエンターで現在選択されている矩形を位置特定(入力中は2回押すと位置特定)", + "screen.tooltip.xtracr_realcamera.modelView_import": "クリップボードから設定をインポート", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "インポートに失敗しました: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%sのインポートに成功しました!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "クリップボードの全ての無効設定を現在の設定に貼り付け\n(同名設定は上書きされません)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "プレビューモードでカメラの様々なオフセットを調整できます", + "screen.tooltip.xtracr_realcamera.modelView_priority": "バインディング時の優先度、値が大きいほど優先度が高く右側のソートで上位に表示", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "名前を付けて保存\n(同名設定がある場合も左の保存ボタンを使用できます)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "スケール、オフセットのサイズを制御", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左クリックでマウスポインタ位置のUV座標を取得\n下の3組のUV座標は上から順に前方ベクトル、上方ベクトル、ターゲット平面上のバインディング点のUV座標\n注: %s+スクロールでモデルの異なるレイヤー間を切り替えられます。手動でUV座標を入力するとターゲット位置に正確にバインドできます", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+左クリッククイック選択のモードを決定\n(%s+スクロールで範囲モードの選択範囲を変更)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "設定名", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "選択されたモデルのテクスチャID(完全なIDでなくても認識可能)、保存時に一部を短縮してプログラム認識を容易にできます\n例: minecraft:textures/entity/player/slim/alex.pngをminecraft:textures/entity/player/に短縮", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "グローバル設定画面を開く\n(Cloth Config APIが必要)", + "screen.widget.xtracr_realcamera.modelView_all": "全て", + "screen.widget.xtracr_realcamera.modelView_configs": "設定", + "screen.widget.xtracr_realcamera.modelView_copy": "コピー", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "現在の設定", + "screen.widget.xtracr_realcamera.modelView_disable": "無効", + "screen.widget.xtracr_realcamera.modelView_disableMode": "無効モード", "screen.widget.xtracr_realcamera.modelView_export": "エクスポート", - "screen.widget.xtracr_realcamera.modelView_selecting": "選択", "screen.widget.xtracr_realcamera.modelView_forwardVector": "前方ベクトル", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "上方ベクトル", - "screen.widget.xtracr_realcamera.modelView_position": "ターゲット平面", - "screen.widget.xtracr_realcamera.modelView_save": "保存", - "screen.widget.xtracr_realcamera.modelView_disableMode": "無効モード", - "screen.widget.xtracr_realcamera.modelView_all": "全て", - "screen.widget.xtracr_realcamera.modelView_part": "一部", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "選択モード", - "screen.widget.xtracr_realcamera.modelView_single": "単一選択", + "screen.widget.xtracr_realcamera.modelView_import": "インポート", "screen.widget.xtracr_realcamera.modelView_multiple": "複数選択", - "screen.widget.xtracr_realcamera.modelView_range": "範囲", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "スライダーから入力欄へ切り替え", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "入力欄からスライダーへ切り替え", "screen.widget.xtracr_realcamera.modelView_offsetX": "Xオフセット = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Yオフセット = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Zオフセット = %s", + "screen.widget.xtracr_realcamera.modelView_part": "一部", + "screen.widget.xtracr_realcamera.modelView_paste": "貼り付け", "screen.widget.xtracr_realcamera.modelView_pitch": "ピッチ = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "ヨー = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "ロール = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "無効", + "screen.widget.xtracr_realcamera.modelView_position": "ターゲット平面", "screen.widget.xtracr_realcamera.modelView_preview": "プレビュー", - "screen.widget.xtracr_realcamera.modelView_configs": "設定", - "screen.widget.xtracr_realcamera.modelView_copy": "コピー", - "screen.widget.xtracr_realcamera.modelView_paste": "貼り付け", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "現在の設定", - "screen.tooltip.xtracr_realcamera.modelView_import": "クリップボードから設定をインポート", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%sのインポートに成功しました!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "インポートに失敗しました: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "現在の設定をクリップボードにエクスポート", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "エクスポートに成功しました!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "エクスポートに失敗しました: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左クリックでマウスポインタ位置のUV座標を取得\n下の3組のUV座標は上から順に前方ベクトル、上方ベクトル、ターゲット平面上のバインディング点のUV座標\n注: %s+スクロールでモデルの異なるレイヤー間を切り替えられます。手動でUV座標を入力するとターゲット位置に正確にバインドできます", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "選択されたモデルのテクスチャID(完全なIDでなくても認識可能)、保存時に一部を短縮してプログラム認識を容易にできます\n例: minecraft:textures/entity/player/slim/alex.pngをminecraft:textures/entity/player/に短縮", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "青い枠で囲まれた部分は無効になります\n左側のマテリアルビューでマウスの左ボタンで選択、他のボタンで選択解除\n%s+左クリックでマウスポインタが指す部分を素早く選択できます", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+左クリッククイック選択のモードを決定\n(%s+スクロールで範囲モードの選択範囲を変更)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "選択された矩形の番号\n(0は未選択)\nスペースまたはエンターで現在選択されている矩形を位置特定(入力中は2回押すと位置特定)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "選択された矩形を削除\n(またはDeleteキーを使用)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "無効時、カメラとモデルの相対的な位置関係は変化しませんが、カメラの対応する属性はこのMODによって変更されません", - "screen.tooltip.xtracr_realcamera.modelView_scale": "スケール、オフセットのサイズを制御", - "screen.tooltip.xtracr_realcamera.modelView_depth": "全ての頂点から画面までの距離がこの値より小さい面はレンダリングされません", - "screen.tooltip.xtracr_realcamera.modelView_priority": "バインディング時の優先度、値が大きいほど優先度が高く右側のソートで上位に表示", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "設定名", - "screen.tooltip.xtracr_realcamera.modelView_disable": "無効設定\nグローバル無効設定は設定画面にあります", - "screen.tooltip.xtracr_realcamera.modelView_configs": "保存済み設定", - "screen.tooltip.xtracr_realcamera.modelView_preview": "プレビューモードでカメラの様々なオフセットを調整できます", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "グローバル設定画面を開く\n(Cloth Config APIが必要)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "全ての無効設定をコピー", - "screen.tooltip.xtracr_realcamera.modelView_paste": "クリップボードの全ての無効設定を現在の設定に貼り付け\n(同名設定は上書きされません)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名前は空にできません!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "テクスチャIDは空にできません!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "名前を付けて保存\n(同名設定がある場合も左の保存ボタンを使用できます)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "無効設定の名前" + "screen.widget.xtracr_realcamera.modelView_range": "範囲", + "screen.widget.xtracr_realcamera.modelView_roll": "ロール = %s", + "screen.widget.xtracr_realcamera.modelView_save": "保存", + "screen.widget.xtracr_realcamera.modelView_selecting": "選択", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "選択モード", + "screen.widget.xtracr_realcamera.modelView_single": "単一選択", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "入力欄からスライダーへ切り替え", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "スライダーから入力欄へ切り替え", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "上方ベクトル", + "screen.widget.xtracr_realcamera.modelView_yaw": "ヨー = %s", + "screen.xtracr_realcamera.modelView_title": "モデルビュー" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/ko_kr.json b/common/src/main/resources/assets/realcamera/lang/ko_kr.json index a7b1587e..5936f653 100644 --- a/common/src/main/resources/assets/realcamera/lang/ko_kr.json +++ b/common/src/main/resources/assets/realcamera/lang/ko_kr.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "모델 뷰 화면 열기", - "key.xtracr_realcamera.togglePerspective": "활성화/비활성화", - "key.xtracr_realcamera.activeConfigIndexPREV": "이전 설정으로 전환", - "key.xtracr_realcamera.activeConfigIndexNEXT": "다음 설정으로 전환", - "key.xtracr_realcamera.activeConfigIndexRESET": "설정 인덱스 초기화", - "key.xtracr_realcamera.toggleAdjustMode": "조정 모드 전환", - "key.xtracr_realcamera.toggleCameraMode": "카메라 모드 전환", - "key.xtracr_realcamera.adjustUP": "위로 조정", - "key.xtracr_realcamera.adjustDOWN": "아래로 조정", - "key.xtracr_realcamera.adjustFRONT": "앞으로 조정", - "key.xtracr_realcamera.adjustBACK": "뒤로 조정", - "key.xtracr_realcamera.adjustLEFT": "왼쪽으로 조정", - "key.xtracr_realcamera.adjustRIGHT": "오른쪽으로 조정", - "modmenu.descriptionTranslation.realcamera": "1인칭 시점에서 카메라를 더 현실적으로 만듭니다", - - "config.category.xtracr_realcamera.general": "일반", "config.category.xtracr_realcamera.binding": "바인딩 모드", - "config.category.xtracr_realcamera.classic": "클래식 모드", "config.category.xtracr_realcamera.cameraOffset": "카메라 오프셋", - "config.category.xtracr_realcamera.centerOffset": "회전 중심 오프셋", "config.category.xtracr_realcamera.cameraRotation": "카메라 회전", - "config.tooltip.xtracr_realcamera.classicOffset": "회전 중심으로부터의 카메라 오프셋", - "config.tooltip.xtracr_realcamera.classicOffset_n": "참고: 플레이어의 전방, 상단, 좌측이 각각 X, Y, Z 축입니다", - "config.tooltip.xtracr_realcamera.centerOffset": "머리로부터의 회전 중심 오프셋", - "config.tooltip.xtracr_realcamera.cameraRotation": "추가 카메라 회전 각도", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "참고: 피치, 요, 롤은 각각 좌측, 상단, 전방 축을 기준으로 한 회전입니다", - - "config.option.xtracr_realcamera.enabled": "모드 활성화", - "config.option.xtracr_realcamera.isClassic": "클래식 모드", - "config.option.xtracr_realcamera.dynamicCrosshair": "동적 크로스헤어", - "config.option.xtracr_realcamera.renderModel": "플레이어 모델 렌더링", + "config.category.xtracr_realcamera.centerOffset": "회전 중심 오프셋", + "config.category.xtracr_realcamera.classic": "클래식 모드", + "config.category.xtracr_realcamera.general": "일반", + "config.option.xtracr_realcamera.activeConfigIndex": "현재 설정 인덱스", + "config.option.xtracr_realcamera.adjustOffset": "카메라 오프셋 조정", "config.option.xtracr_realcamera.adjustStep": "조정 단계", - "config.option.xtracr_realcamera.classicAdjustMode": "조정 모드", - "config.option.xtracr_realcamera.scale": "크기 조절", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "바인딩 결과 유지 프레임", "config.option.xtracr_realcamera.cameraOffset": "카메라 %s 오프셋", "config.option.xtracr_realcamera.centerOffset": "회전 중심 %s 오프셋", - "config.option.xtracr_realcamera.pitch": "피치", - "config.option.xtracr_realcamera.yaw": "요", - "config.option.xtracr_realcamera.roll": "롤", - "config.option.xtracr_realcamera.toModelViewScreen": "자세한 설정은 %s 화면에서 확인하세요 (열기 위한 키 설정 필요)", - "config.option.xtracr_realcamera.screenModifierKey": "%s 화면 수정 키", - "config.option.xtracr_realcamera.legacyBindingMode": "레거시 바인딩 모드", - "config.option.xtracr_realcamera.adjustOffset": "카메라 오프셋 조정", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "바인딩 실패 메시지 숨기기", - "config.option.xtracr_realcamera.renderStuckObjects": "박힌 물체 렌더링", - "config.option.xtracr_realcamera.rerenderModel": "모델 재렌더링", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "바인딩 결과 유지 프레임", - "config.option.xtracr_realcamera.displacementSmoothFactor": "변위 평활화 계수", - "config.option.xtracr_realcamera.rotationSmoothFactor": "회전 평활화 계수", - "config.option.xtracr_realcamera.activeConfigIndex": "현재 설정 인덱스", + "config.option.xtracr_realcamera.classicAdjustMode": "조정 모드", "config.option.xtracr_realcamera.disableConfig": "비활성화 설정", - "config.option.xtracr_realcamera.disableWhenSneaking": "숨어 있을 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.disableMainFeatureItems": "...을(를) 들고 있을 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.disableRenderItems": "...을(를) 들고 있을 때 렌더링 비활성화", "config.option.xtracr_realcamera.disableWhenCrawling": "기어다닐 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.disableWhenSneaking": "숨어 있을 때 주요 기능 비활성화", "config.option.xtracr_realcamera.disableWhenSwimming": "수영할 때 주요 기능 비활성화", + "config.option.xtracr_realcamera.displacementSmoothFactor": "변위 평활화 계수", + "config.option.xtracr_realcamera.dynamicCrosshair": "동적 크로스헤어", + "config.option.xtracr_realcamera.enabled": "모드 활성화", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "바인딩 실패 메시지 숨기기", + "config.option.xtracr_realcamera.isClassic": "클래식 모드", + "config.option.xtracr_realcamera.legacyBindingMode": "레거시 바인딩 모드", "config.option.xtracr_realcamera.outTick": "비활성화 상태 종료 지연 (틱 단위)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "...을(를) 들고 있을 때 주요 기능 비활성화", - "config.option.xtracr_realcamera.disableRenderItems": "...을(를) 들고 있을 때 렌더링 비활성화", - "config.tooltip.xtracr_realcamera.isClassic": "클래식 모드는 카메라의 위치와 회전에 간단한 변경만 적용합니다", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "활성화 시 크로스헤어가 플레이어의 시선을 따라가며 일관된 명중 결과를 보장합니다\nJade, WTHIT 또는 유사 모드 설치 시 활성화 권장", - "config.tooltip.xtracr_realcamera.renderModel": "1인칭 시점에서 플레이어 모델 렌더링", + "config.option.xtracr_realcamera.pitch": "피치", + "config.option.xtracr_realcamera.renderModel": "플레이어 모델 렌더링", + "config.option.xtracr_realcamera.renderStuckObjects": "박힌 물체 렌더링", + "config.option.xtracr_realcamera.rerenderModel": "모델 재렌더링", + "config.option.xtracr_realcamera.roll": "롤", + "config.option.xtracr_realcamera.rotationSmoothFactor": "회전 평활화 계수", + "config.option.xtracr_realcamera.scale": "크기 조절", + "config.option.xtracr_realcamera.screenModifierKey": "%s 화면 수정 키", + "config.option.xtracr_realcamera.toModelViewScreen": "자세한 설정은 %s 화면에서 확인하세요 (열기 위한 키 설정 필요)", + "config.option.xtracr_realcamera.yaw": "요", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "현재 바인딩된 설정의 인덱스, 0은 유효한 설정을 바인딩할 수 있음을 의미", + "config.tooltip.xtracr_realcamera.adjustOffset": "조정 키 누를 때 카메라 오프셋 또는 회전 조정", "config.tooltip.xtracr_realcamera.adjustStep": "단계별 조정 길이 또는 각도의 1/100", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "바인딩 실패 후 몇 프레임 동안 이전 성공한 바인딩 결과 사용 유지", + "config.tooltip.xtracr_realcamera.cameraRotation": "추가 카메라 회전 각도", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "참고: 피치, 요, 롤은 각각 좌측, 상단, 전방 축을 기준으로 한 회전입니다", + "config.tooltip.xtracr_realcamera.centerOffset": "머리로부터의 회전 중심 오프셋", "config.tooltip.xtracr_realcamera.classicAdjustMode": "조정 키 누를 때 조정할 대상을 결정합니다", - "config.tooltip.xtracr_realcamera.scale": "오프셋 크기를 제어합니다", + "config.tooltip.xtracr_realcamera.classicOffset": "회전 중심으로부터의 카메라 오프셋", + "config.tooltip.xtracr_realcamera.classicOffset_n": "참고: 플레이어의 전방, 상단, 좌측이 각각 X, Y, Z 축입니다", + "config.tooltip.xtracr_realcamera.disableRenderItems": "세 가지 매칭 방식 지원:\n1. 와일드카드 `*` 매칭 (예: `minecraft:*sword`)\n2. 태그 매칭 (`#`으로 시작, 예: `#minecraft:swords`)\n3. 직접 아이템 ID (예: `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "카메라 변위 평활화 계수, 값이 클수록 이동이 부드러워집니다", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "활성화 시 크로스헤어가 플레이어의 시선을 따라가며 일관된 명중 결과를 보장합니다\nJade, WTHIT 또는 유사 모드 설치 시 활성화 권장", + "config.tooltip.xtracr_realcamera.isClassic": "클래식 모드는 카메라의 위치와 회전에 간단한 변경만 적용합니다", "config.tooltip.xtracr_realcamera.legacyBindingMode": "이전 버전(v0.5)의 바인딩 모드 사용, 기본 모델 및 기본 모델 기반 작업만 지원합니다\n활성화 시 %s 화면의 'LEGACY_MODE'에서 속성 설정 가능", - "config.tooltip.xtracr_realcamera.adjustOffset": "조정 키 누를 때 카메라 오프셋 또는 회전 조정", + "config.tooltip.xtracr_realcamera.outTick": "비활성화 상태 종료 후 주요 기능 재활성화까지의 시간 (1 틱 = 0.05초)", + "config.tooltip.xtracr_realcamera.renderModel": "1인칭 시점에서 플레이어 모델 렌더링", "config.tooltip.xtracr_realcamera.renderStuckObjects": "화살, 벌 침 등 플레이어 몸에 박힐 수 있는 물체들", "config.tooltip.xtracr_realcamera.rerenderModel": "원본 렌더링 시간에 모델을 다시 렌더링하여 조기 렌더링으로 인한 시각적 문제 방지", - "config.tooltip.xtracr_realcamera.outTick": "비활성화 상태 종료 후 주요 기능 재활성화까지의 시간 (1 틱 = 0.05초)", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "바인딩 실패 후 몇 프레임 동안 이전 성공한 바인딩 결과 사용 유지", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "카메라 변위 평활화 계수, 값이 클수록 이동이 부드러워집니다", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "카메라 회전 평활화 계수, 값이 클수록 이동이 부드러워집니다", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "현재 바인딩된 설정의 인덱스, 0은 유효한 설정을 바인딩할 수 있음을 의미", - "config.tooltip.xtracr_realcamera.disableRenderItems": "세 가지 매칭 방식 지원:\n1. 와일드카드 `*` 매칭 (예: `minecraft:*sword`)\n2. 태그 매칭 (`#`으로 시작, 예: `#minecraft:swords`)\n3. 직접 아이템 ID (예: `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "오프셋 크기를 제어합니다", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "다음 설정으로 전환", + "key.xtracr_realcamera.activeConfigIndexPREV": "이전 설정으로 전환", + "key.xtracr_realcamera.activeConfigIndexRESET": "설정 인덱스 초기화", + "key.xtracr_realcamera.adjustBACK": "뒤로 조정", + "key.xtracr_realcamera.adjustDOWN": "아래로 조정", + "key.xtracr_realcamera.adjustFRONT": "앞으로 조정", + "key.xtracr_realcamera.adjustLEFT": "왼쪽으로 조정", + "key.xtracr_realcamera.adjustRIGHT": "오른쪽으로 조정", + "key.xtracr_realcamera.adjustUP": "위로 조정", + "key.xtracr_realcamera.modelViewScreen": "모델 뷰 화면 열기", + "key.xtracr_realcamera.toggleAdjustMode": "조정 모드 전환", + "key.xtracr_realcamera.toggleCameraMode": "카메라 모드 전환", + "key.xtracr_realcamera.togglePerspective": "활성화/비활성화", "message.xtracr_realcamera.bindingFailed": "[%s]: 바인딩 실패, %s 화면에서 수동으로 설정하세요 (키: %s)", - - "screen.xtracr_realcamera.modelView_title": "모델 뷰", - "screen.widget.xtracr_realcamera.modelView_import": "가져오기", + "modmenu.descriptionTranslation.realcamera": "1인칭 시점에서 카메라를 더 현실적으로 만듭니다", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "비활성화 시 카메라와 모델의 상대적 관계는 변하지 않지만, 카메라의 해당 속성은 이 모드에서 수정되지 않습니다", + "screen.tooltip.xtracr_realcamera.modelView_configs": "저장된 설정", + "screen.tooltip.xtracr_realcamera.modelView_copy": "모든 비활성화 설정 복사", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "선택된 사각형 삭제\n(또는 Delete 키 사용)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "모든 정점-화면 거리가 이 값보다 작은 면은 렌더링되지 않습니다", + "screen.tooltip.xtracr_realcamera.modelView_disable": "비활성화 설정\n전역 비활성화 설정은 설정 화면에 있습니다", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "파란색 상자 안의 부분이 비활성화됩니다\n왼쪽 텍스처 뷰에서 왼쪽 클릭으로 선택, 다른 키로 선택 취소\n%s+왼쪽 클릭으로 마우스 포인터가 가리키는 부분 빠르게 선택", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "비활성화 설정 이름", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "이름은 비울 수 없습니다!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "텍스처 ID는 비울 수 없습니다!", + "screen.tooltip.xtracr_realcamera.modelView_export": "현재 설정을 클립보드로 내보내기", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "내보내기 실패: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "내보내기 성공!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "선택된 사각형 번호\n(0은 미선택)\n스페이스 또는 엔터로 현재 선택된 사각형 위치 확인 (입력 중일 때 두 번 누르면 위치 확인)", + "screen.tooltip.xtracr_realcamera.modelView_import": "클립보드에서 설정 가져오기", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "가져오기 실패: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s 가져오기 성공!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "클립보드의 모든 비활성화 설정을 현재 설정에 붙여넣기\n(동일 이름 설정 덮어쓰지 않음)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "미리보기 모드에서 카메라의 다양한 오프셋 조정 가능", + "screen.tooltip.xtracr_realcamera.modelView_priority": "바인딩 시 우선순위, 값이 클수록 우선순위가 높으며 오른쪽 정렬에서 위쪽에 표시", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "다른 이름으로 저장\n(동일 이름 설정이 있을 때 왼쪽 저장 버튼도 사용 가능)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "크기 조절, 오프셋 크기 제어", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+왼쪽 클릭으로 마우스 포인터 위치의 UV 좌표 얻기\n아래 세 가지 UV 좌표는 위에서부터 전방 벡터, 상향 벡터, 대상 평면의 바인딩 지점 UV 좌표입니다\n참고: %s+스크롤로 모델의 다른 레이어 간 전환, 수동 UV 좌표 입력으로 대상 위치에 더 정확하게 바인딩 가능", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+왼쪽 클릭 빠른 선택 모드 결정\n(%s+스크롤로 범위 모드에서 선택 범위 변경)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "설정 이름", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "선택된 모델의 텍스처 ID (전체 ID일 필요 없음), 저장 시 일부 생략하여 프로그램 인식 용이하게 함\n예: minecraft:textures/entity/player/slim/alex.png → minecraft:textures/entity/player/", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "전역 설정 화면 열기\n(Cloth Config API 필요)", + "screen.widget.xtracr_realcamera.modelView_all": "전체", + "screen.widget.xtracr_realcamera.modelView_configs": "설정", + "screen.widget.xtracr_realcamera.modelView_copy": "복사", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "현재 설정", + "screen.widget.xtracr_realcamera.modelView_disable": "비활성화", + "screen.widget.xtracr_realcamera.modelView_disableMode": "비활성화 모드", "screen.widget.xtracr_realcamera.modelView_export": "내보내기", - "screen.widget.xtracr_realcamera.modelView_selecting": "선택", "screen.widget.xtracr_realcamera.modelView_forwardVector": "전방 벡터", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "상향 벡터", - "screen.widget.xtracr_realcamera.modelView_position": "대상 평면", - "screen.widget.xtracr_realcamera.modelView_save": "저장", - "screen.widget.xtracr_realcamera.modelView_disableMode": "비활성화 모드", - "screen.widget.xtracr_realcamera.modelView_all": "전체", - "screen.widget.xtracr_realcamera.modelView_part": "부분", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "선택 모드", - "screen.widget.xtracr_realcamera.modelView_single": "단일", + "screen.widget.xtracr_realcamera.modelView_import": "가져오기", "screen.widget.xtracr_realcamera.modelView_multiple": "다중", - "screen.widget.xtracr_realcamera.modelView_range": "범위", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "슬라이더에서 필드로 전환", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "필드에서 슬라이더로 전환", "screen.widget.xtracr_realcamera.modelView_offsetX": "X 오프셋 = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y 오프셋 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z 오프셋 = %s", + "screen.widget.xtracr_realcamera.modelView_part": "부분", + "screen.widget.xtracr_realcamera.modelView_paste": "붙여넣기", "screen.widget.xtracr_realcamera.modelView_pitch": "피치 = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "요 = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "롤 = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "비활성화", + "screen.widget.xtracr_realcamera.modelView_position": "대상 평면", "screen.widget.xtracr_realcamera.modelView_preview": "미리보기", - "screen.widget.xtracr_realcamera.modelView_configs": "설정", - "screen.widget.xtracr_realcamera.modelView_copy": "복사", - "screen.widget.xtracr_realcamera.modelView_paste": "붙여넣기", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "현재 설정", - "screen.tooltip.xtracr_realcamera.modelView_import": "클립보드에서 설정 가져오기", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s 가져오기 성공!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "가져오기 실패: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "현재 설정을 클립보드로 내보내기", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "내보내기 성공!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "내보내기 실패: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+왼쪽 클릭으로 마우스 포인터 위치의 UV 좌표 얻기\n아래 세 가지 UV 좌표는 위에서부터 전방 벡터, 상향 벡터, 대상 평면의 바인딩 지점 UV 좌표입니다\n참고: %s+스크롤로 모델의 다른 레이어 간 전환, 수동 UV 좌표 입력으로 대상 위치에 더 정확하게 바인딩 가능", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "선택된 모델의 텍스처 ID (전체 ID일 필요 없음), 저장 시 일부 생략하여 프로그램 인식 용이하게 함\n예: minecraft:textures/entity/player/slim/alex.png → minecraft:textures/entity/player/", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "파란색 상자 안의 부분이 비활성화됩니다\n왼쪽 텍스처 뷰에서 왼쪽 클릭으로 선택, 다른 키로 선택 취소\n%s+왼쪽 클릭으로 마우스 포인터가 가리키는 부분 빠르게 선택", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+왼쪽 클릭 빠른 선택 모드 결정\n(%s+스크롤로 범위 모드에서 선택 범위 변경)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "선택된 사각형 번호\n(0은 미선택)\n스페이스 또는 엔터로 현재 선택된 사각형 위치 확인 (입력 중일 때 두 번 누르면 위치 확인)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "선택된 사각형 삭제\n(또는 Delete 키 사용)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "비활성화 시 카메라와 모델의 상대적 관계는 변하지 않지만, 카메라의 해당 속성은 이 모드에서 수정되지 않습니다", - "screen.tooltip.xtracr_realcamera.modelView_scale": "크기 조절, 오프셋 크기 제어", - "screen.tooltip.xtracr_realcamera.modelView_depth": "모든 정점-화면 거리가 이 값보다 작은 면은 렌더링되지 않습니다", - "screen.tooltip.xtracr_realcamera.modelView_priority": "바인딩 시 우선순위, 값이 클수록 우선순위가 높으며 오른쪽 정렬에서 위쪽에 표시", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "설정 이름", - "screen.tooltip.xtracr_realcamera.modelView_disable": "비활성화 설정\n전역 비활성화 설정은 설정 화면에 있습니다", - "screen.tooltip.xtracr_realcamera.modelView_configs": "저장된 설정", - "screen.tooltip.xtracr_realcamera.modelView_preview": "미리보기 모드에서 카메라의 다양한 오프셋 조정 가능", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "전역 설정 화면 열기\n(Cloth Config API 필요)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "모든 비활성화 설정 복사", - "screen.tooltip.xtracr_realcamera.modelView_paste": "클립보드의 모든 비활성화 설정을 현재 설정에 붙여넣기\n(동일 이름 설정 덮어쓰지 않음)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "이름은 비울 수 없습니다!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "텍스처 ID는 비울 수 없습니다!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "다른 이름으로 저장\n(동일 이름 설정이 있을 때 왼쪽 저장 버튼도 사용 가능)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "비활성화 설정 이름" + "screen.widget.xtracr_realcamera.modelView_range": "범위", + "screen.widget.xtracr_realcamera.modelView_roll": "롤 = %s", + "screen.widget.xtracr_realcamera.modelView_save": "저장", + "screen.widget.xtracr_realcamera.modelView_selecting": "선택", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "선택 모드", + "screen.widget.xtracr_realcamera.modelView_single": "단일", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "필드에서 슬라이더로 전환", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "슬라이더에서 필드로 전환", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "상향 벡터", + "screen.widget.xtracr_realcamera.modelView_yaw": "요 = %s", + "screen.xtracr_realcamera.modelView_title": "모델 뷰" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/lzh.json b/common/src/main/resources/assets/realcamera/lang/lzh.json index 3481b108..88c8885b 100644 --- a/common/src/main/resources/assets/realcamera/lang/lzh.json +++ b/common/src/main/resources/assets/realcamera/lang/lzh.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "啟模型觀象之窗", - "key.xtracr_realcamera.togglePerspective": "開/闔", - "key.xtracr_realcamera.activeConfigIndexPREV": "切上配", - "key.xtracr_realcamera.activeConfigIndexNEXT": "切下配", - "key.xtracr_realcamera.activeConfigIndexRESET": "改配之引", - "key.xtracr_realcamera.toggleAdjustMode": "易調校之法", - "key.xtracr_realcamera.toggleCameraMode": "易鏡觀之道", - "key.xtracr_realcamera.adjustUP": "上移", - "key.xtracr_realcamera.adjustDOWN": "下移", - "key.xtracr_realcamera.adjustFRONT": "前移", - "key.xtracr_realcamera.adjustBACK": "後移", - "key.xtracr_realcamera.adjustLEFT": "左移", - "key.xtracr_realcamera.adjustRIGHT": "右移", - "modmenu.descriptionTranslation.realcamera": "使第一人稱之鏡觀愈真。", - - "config.category.xtracr_realcamera.general": "總則", "config.category.xtracr_realcamera.binding": "系定之法", - "config.category.xtracr_realcamera.classic": "古法", "config.category.xtracr_realcamera.cameraOffset": "鏡觀偏移", - "config.category.xtracr_realcamera.centerOffset": "樞軸偏移", "config.category.xtracr_realcamera.cameraRotation": "鏡觀旋轉", - "config.tooltip.xtracr_realcamera.classicOffset": "鏡觀相對樞軸之移值", - "config.tooltip.xtracr_realcamera.classicOffset_n": "註: 戯者之前、上、左分別為X、Y、Z軸", - "config.tooltip.xtracr_realcamera.centerOffset": "樞軸相對首部之移值", - "config.tooltip.xtracr_realcamera.cameraRotation": "額外之鏡觀轉角度", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "註: 俯仰、偏航、翻滾乃以左、上、前為軸之轉", - - "config.option.xtracr_realcamera.enabled": "啟其能", - "config.option.xtracr_realcamera.isClassic": "古法", - "config.option.xtracr_realcamera.dynamicCrosshair": "動準星", - "config.option.xtracr_realcamera.renderModel": "顯戯者之形", + "config.category.xtracr_realcamera.centerOffset": "樞軸偏移", + "config.category.xtracr_realcamera.classic": "古法", + "config.category.xtracr_realcamera.general": "總則", + "config.option.xtracr_realcamera.activeConfigIndex": "現綁配之引", + "config.option.xtracr_realcamera.adjustOffset": "調鏡觀移", "config.option.xtracr_realcamera.adjustStep": "調校之步", - "config.option.xtracr_realcamera.classicAdjustMode": "調校之法", - "config.option.xtracr_realcamera.scale": "縮放之度", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "系定果存之幀數", "config.option.xtracr_realcamera.cameraOffset": "鏡觀%s移", "config.option.xtracr_realcamera.centerOffset": "樞軸%s移", - "config.option.xtracr_realcamera.pitch": "俯仰", - "config.option.xtracr_realcamera.yaw": "偏航", - "config.option.xtracr_realcamera.roll": "翻滾", - "config.option.xtracr_realcamera.toModelViewScreen": "詳設請往%s窗(需設捷鍵以啟之)", - "config.option.xtracr_realcamera.screenModifierKey": "%s窗修飾鍵", - "config.option.xtracr_realcamera.legacyBindingMode": "古版系定之法", - "config.option.xtracr_realcamera.adjustOffset": "調鏡觀移", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱系定敗之訊", - "config.option.xtracr_realcamera.renderStuckObjects": "示附身之物", - "config.option.xtracr_realcamera.rerenderModel": "重顯其形", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "系定果存之幀數", - "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑之係", - "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑之係", - "config.option.xtracr_realcamera.activeConfigIndex": "現綁配之引", + "config.option.xtracr_realcamera.classicAdjustMode": "調校之法", "config.option.xtracr_realcamera.disableConfig": "禁配", - "config.option.xtracr_realcamera.disableWhenSneaking": "潛伏時禁其能", + "config.option.xtracr_realcamera.disableMainFeatureItems": "持...時禁其能", + "config.option.xtracr_realcamera.disableRenderItems": "持...時禁其顯", "config.option.xtracr_realcamera.disableWhenCrawling": "爬攀時禁其能", + "config.option.xtracr_realcamera.disableWhenSneaking": "潛伏時禁其能", "config.option.xtracr_realcamera.disableWhenSwimming": "游水時禁其能", + "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑之係", + "config.option.xtracr_realcamera.dynamicCrosshair": "動準星", + "config.option.xtracr_realcamera.enabled": "啟其能", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱系定敗之訊", + "config.option.xtracr_realcamera.isClassic": "古法", + "config.option.xtracr_realcamera.legacyBindingMode": "古版系定之法", "config.option.xtracr_realcamera.outTick": "出禁之延(單位:tick)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "持...時禁其能", - "config.option.xtracr_realcamera.disableRenderItems": "持...時禁其顯", - "config.tooltip.xtracr_realcamera.isClassic": "古法唯簡調鏡觀之位與旋", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "啟時,準星隨視線而動,保中無誤\n若裝Jade、WTHIT等類模組,宜啟之", - "config.tooltip.xtracr_realcamera.renderModel": "第一人稱顯戯者之形", + "config.option.xtracr_realcamera.pitch": "俯仰", + "config.option.xtracr_realcamera.renderModel": "顯戯者之形", + "config.option.xtracr_realcamera.renderStuckObjects": "示附身之物", + "config.option.xtracr_realcamera.rerenderModel": "重顯其形", + "config.option.xtracr_realcamera.roll": "翻滾", + "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑之係", + "config.option.xtracr_realcamera.scale": "縮放之度", + "config.option.xtracr_realcamera.screenModifierKey": "%s窗修飾鍵", + "config.option.xtracr_realcamera.toModelViewScreen": "詳設請往%s窗(需設捷鍵以啟之)", + "config.option.xtracr_realcamera.yaw": "偏航", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "現配之引,零意奏許定諸配", + "config.tooltip.xtracr_realcamera.adjustOffset": "當前按調校鍵時乃調鏡觀之偏移或旋轉", "config.tooltip.xtracr_realcamera.adjustStep": "每步調校角度之百分一或長度", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "系定敗後數幀內,沿用前次成之果", + "config.tooltip.xtracr_realcamera.cameraRotation": "額外之鏡觀轉角度", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "註: 俯仰、偏航、翻滾乃以左、上、前為軸之轉", + "config.tooltip.xtracr_realcamera.centerOffset": "樞軸相對首部之移值", "config.tooltip.xtracr_realcamera.classicAdjustMode": "定當前按調校鍵時調何者", - "config.tooltip.xtracr_realcamera.scale": "控偏移大小", + "config.tooltip.xtracr_realcamera.classicOffset": "鏡觀相對樞軸之移值", + "config.tooltip.xtracr_realcamera.classicOffset_n": "註: 戯者之前、上、左分別為X、Y、Z軸", + "config.tooltip.xtracr_realcamera.disableRenderItems": "三法可配:\n1. 通配符`*`配(如`minecraft:*sword`)\n2. 標籤配以`#`始(如`#minecraft:swords`)\n3. 直物ID(如`minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "鏡觀移滑係,值愈大愈平", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "啟時,準星隨視線而動,保中無誤\n若裝Jade、WTHIT等類模組,宜啟之", + "config.tooltip.xtracr_realcamera.isClassic": "古法唯簡調鏡觀之位與旋", "config.tooltip.xtracr_realcamera.legacyBindingMode": "用古版(v0.5)系定之法,惟原模及原模所出之動可受\n啟之則可於%s窗'LEGACY_MODE'中設其性", - "config.tooltip.xtracr_realcamera.adjustOffset": "當前按調校鍵時乃調鏡觀之偏移或旋轉", + "config.tooltip.xtracr_realcamera.outTick": "止禁,即復其能所之延時(1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "第一人稱顯戯者之形", "config.tooltip.xtracr_realcamera.renderStuckObjects": "矢,蜂針等附身之物", "config.tooltip.xtracr_realcamera.rerenderModel": "於原顯時重顯其形,免早顯致視誤", - "config.tooltip.xtracr_realcamera.outTick": "止禁,即復其能所之延時(1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "系定敗後數幀內,沿用前次成之果", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "鏡觀移滑係,值愈大愈平", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "鏡觀轉滑係,值愈大愈平", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "現配之引,零意奏許定諸配", - "config.tooltip.xtracr_realcamera.disableRenderItems": "三法可配:\n1. 通配符`*`配(如`minecraft:*sword`)\n2. 標籤配以`#`始(如`#minecraft:swords`)\n3. 直物ID(如`minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "控偏移大小", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切下配", + "key.xtracr_realcamera.activeConfigIndexPREV": "切上配", + "key.xtracr_realcamera.activeConfigIndexRESET": "改配之引", + "key.xtracr_realcamera.adjustBACK": "後移", + "key.xtracr_realcamera.adjustDOWN": "下移", + "key.xtracr_realcamera.adjustFRONT": "前移", + "key.xtracr_realcamera.adjustLEFT": "左移", + "key.xtracr_realcamera.adjustRIGHT": "右移", + "key.xtracr_realcamera.adjustUP": "上移", + "key.xtracr_realcamera.modelViewScreen": "啟模型觀象之窗", + "key.xtracr_realcamera.toggleAdjustMode": "易調校之法", + "key.xtracr_realcamera.toggleCameraMode": "易鏡觀之道", + "key.xtracr_realcamera.togglePerspective": "開/闔", "message.xtracr_realcamera.bindingFailed": "[%s]: 系定敗,往%s窗親設之(鍵:%s)", - - "screen.xtracr_realcamera.modelView_title": "模型觀象", - "screen.widget.xtracr_realcamera.modelView_import": "入", + "modmenu.descriptionTranslation.realcamera": "使第一人稱之鏡觀愈真。", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "禁時,鏡觀與模型之相對不變,然鏡觀之對應性不為本模所改", + "screen.tooltip.xtracr_realcamera.modelView_configs": "已存之設", + "screen.tooltip.xtracr_realcamera.modelView_copy": "抄諸禁設", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "去擇之矩\n(或用Delete鍵)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "諸頂點至屏距皆小於此值之面不顯", + "screen.tooltip.xtracr_realcamera.modelView_disable": "禁設\n全禁設在設屏中", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "藍框含之部將禁\n可於左材視以左鍵框擇,他鍵廢擇\n%s+左鍵可速擇光標指之部", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁設之名", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名不可空!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材id不可空!", + "screen.tooltip.xtracr_realcamera.modelView_export": "出今設至剪貼板", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "出敗:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "出成!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "擇矩之號\n(0示未擇)\n可以空格或回車定位今擇之矩(當輸時,按兩次即可定位)", + "screen.tooltip.xtracr_realcamera.modelView_import": "从剪貼板入設", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "入敗:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "入%s成!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "貼剪貼板諸禁設至今設\n(不蓋同名設)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "於覽式可調鏡觀諸偏移", + "screen.tooltip.xtracr_realcamera.modelView_priority": "系定之先級,值愈大愈先,且右列愈前", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "存為\n(當有同名設時,亦可用左存鈕)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放之度,控偏移量之大小", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左鍵可取光標處UV座標\n下三組UV座標自上而下為前向矢、上向矢與的平面上系點之UV座標\n註:%s鍵+滾輪可易模型之層,手輸UV座標可精系的位", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "定%s+左鍵速擇之法\n(%s鍵+滾輪可易域擇之範)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "設之名", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "所選模型紋理之id(非全id亦可識),存時可短之以便程序識\n如將minecraft:textures/entity/player/slim/alex.png短為minecraft:textures/entity/player/", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "啟全設屏\n(需裝Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "全", + "screen.widget.xtracr_realcamera.modelView_configs": "設", + "screen.widget.xtracr_realcamera.modelView_copy": "抄", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "現綁配", + "screen.widget.xtracr_realcamera.modelView_disable": "禁", + "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用之法", "screen.widget.xtracr_realcamera.modelView_export": "出", - "screen.widget.xtracr_realcamera.modelView_selecting": "擇", "screen.widget.xtracr_realcamera.modelView_forwardVector": "前向矢", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "上向矢", - "screen.widget.xtracr_realcamera.modelView_position": "的平面", - "screen.widget.xtracr_realcamera.modelView_save": "存", - "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用之法", - "screen.widget.xtracr_realcamera.modelView_all": "全", - "screen.widget.xtracr_realcamera.modelView_part": "塊", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "擇法", - "screen.widget.xtracr_realcamera.modelView_single": "單擇", + "screen.widget.xtracr_realcamera.modelView_import": "入", "screen.widget.xtracr_realcamera.modelView_multiple": "多擇", - "screen.widget.xtracr_realcamera.modelView_range": "域", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "滑塊向框", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "框向滑塊", "screen.widget.xtracr_realcamera.modelView_offsetX": "X移 = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y移 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z移 = %s", + "screen.widget.xtracr_realcamera.modelView_part": "塊", + "screen.widget.xtracr_realcamera.modelView_paste": "貼", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰 = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "偏航 = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "翻滾 = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "禁", + "screen.widget.xtracr_realcamera.modelView_position": "的平面", "screen.widget.xtracr_realcamera.modelView_preview": "覽", - "screen.widget.xtracr_realcamera.modelView_configs": "設", - "screen.widget.xtracr_realcamera.modelView_copy": "抄", - "screen.widget.xtracr_realcamera.modelView_paste": "貼", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "現綁配", - "screen.tooltip.xtracr_realcamera.modelView_import": "从剪貼板入設", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "入%s成!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "入敗:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "出今設至剪貼板", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "出成!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "出敗:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左鍵可取光標處UV座標\n下三組UV座標自上而下為前向矢、上向矢與的平面上系點之UV座標\n註:%s鍵+滾輪可易模型之層,手輸UV座標可精系的位", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "所選模型紋理之id(非全id亦可識),存時可短之以便程序識\n如將minecraft:textures/entity/player/slim/alex.png短為minecraft:textures/entity/player/", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "藍框含之部將禁\n可於左材視以左鍵框擇,他鍵廢擇\n%s+左鍵可速擇光標指之部", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "定%s+左鍵速擇之法\n(%s鍵+滾輪可易域擇之範)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "擇矩之號\n(0示未擇)\n可以空格或回車定位今擇之矩(當輸時,按兩次即可定位)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "去擇之矩\n(或用Delete鍵)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "禁時,鏡觀與模型之相對不變,然鏡觀之對應性不為本模所改", - "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放之度,控偏移量之大小", - "screen.tooltip.xtracr_realcamera.modelView_depth": "諸頂點至屏距皆小於此值之面不顯", - "screen.tooltip.xtracr_realcamera.modelView_priority": "系定之先級,值愈大愈先,且右列愈前", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "設之名", - "screen.tooltip.xtracr_realcamera.modelView_disable": "禁設\n全禁設在設屏中", - "screen.tooltip.xtracr_realcamera.modelView_configs": "已存之設", - "screen.tooltip.xtracr_realcamera.modelView_preview": "於覽式可調鏡觀諸偏移", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "啟全設屏\n(需裝Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "抄諸禁設", - "screen.tooltip.xtracr_realcamera.modelView_paste": "貼剪貼板諸禁設至今設\n(不蓋同名設)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名不可空!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材id不可空!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "存為\n(當有同名設時,亦可用左存鈕)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁設之名" + "screen.widget.xtracr_realcamera.modelView_range": "域", + "screen.widget.xtracr_realcamera.modelView_roll": "翻滾 = %s", + "screen.widget.xtracr_realcamera.modelView_save": "存", + "screen.widget.xtracr_realcamera.modelView_selecting": "擇", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "擇法", + "screen.widget.xtracr_realcamera.modelView_single": "單擇", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "框向滑塊", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "滑塊向框", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "上向矢", + "screen.widget.xtracr_realcamera.modelView_yaw": "偏航 = %s", + "screen.xtracr_realcamera.modelView_title": "模型觀象" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/pl_pl.json b/common/src/main/resources/assets/realcamera/lang/pl_pl.json index 29672052..3a70311c 100644 --- a/common/src/main/resources/assets/realcamera/lang/pl_pl.json +++ b/common/src/main/resources/assets/realcamera/lang/pl_pl.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Prawdziwa Kamera", - "key.xtracr_realcamera.modelViewScreen": "Otwórz Ekran Podglądu Modelu", - "key.xtracr_realcamera.togglePerspective": "Włącz/Wyłącz", - "key.xtracr_realcamera.activeConfigIndexPREV": "Przełącz na poprzednią konfigurację", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Przełącz na następną konfigurację", - "key.xtracr_realcamera.activeConfigIndexRESET": "Zresetuj indeks konfiguracji", - "key.xtracr_realcamera.toggleAdjustMode": "Przełącz Tryb Dostosowania", - "key.xtracr_realcamera.toggleCameraMode": "Przełącz Tryb Kamery", - "key.xtracr_realcamera.adjustUP": "Dostosuj W GÓRĘ", - "key.xtracr_realcamera.adjustDOWN": "Dostosuj W DÓŁ", - "key.xtracr_realcamera.adjustFRONT": "Dostosuj DO PRZODU", - "key.xtracr_realcamera.adjustBACK": "Dostosuj DO TYŁU", - "key.xtracr_realcamera.adjustLEFT": "Dostosuj W LEWO", - "key.xtracr_realcamera.adjustRIGHT": "Dostosuj W PRAWO", - "modmenu.descriptionTranslation.realcamera": "Uczynienie kamery bardziej realistyczną w trybie pierwszoosobowym.", - - "config.category.xtracr_realcamera.general": "Ogólne", "config.category.xtracr_realcamera.binding": "Tryb Powiązania", - "config.category.xtracr_realcamera.classic": "Tryb Klasyczny", "config.category.xtracr_realcamera.cameraOffset": "Przesunięcie Kamery", - "config.category.xtracr_realcamera.centerOffset": "Przesunięcie Centrum Obrótu", "config.category.xtracr_realcamera.cameraRotation": "Obrót Kamery", - "config.tooltip.xtracr_realcamera.classicOffset": "Przesunięcie kamery względem centrum obrotu", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Uwaga: przód, góra i lewa strona gracza odpowiadają osiom X, Y i Z", - "config.tooltip.xtracr_realcamera.centerOffset": "Przesunięcie centrum obrotu względem głowy", - "config.tooltip.xtracr_realcamera.cameraRotation": "Dodatkowy obrót kamery w stopniach", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Uwaga: pochylenie, odchylenie i przechylenie to obroty wokół lewej, górnej i przedniej osi odpowiednio", - - "config.option.xtracr_realcamera.enabled": "Mod Włączony", - "config.option.xtracr_realcamera.isClassic": "Tryb Klasyczny", - "config.option.xtracr_realcamera.dynamicCrosshair": "Dynamiczny Celownik", - "config.option.xtracr_realcamera.renderModel": "Wyświetl Model Gracza", + "config.category.xtracr_realcamera.centerOffset": "Przesunięcie Centrum Obrótu", + "config.category.xtracr_realcamera.classic": "Tryb Klasyczny", + "config.category.xtracr_realcamera.general": "Ogólne", + "config.option.xtracr_realcamera.activeConfigIndex": "Aktywny Indeks Konfiguracji", + "config.option.xtracr_realcamera.adjustOffset": "Dostosuj Przesunięcie Kamery", "config.option.xtracr_realcamera.adjustStep": "Krok Dostosowania", - "config.option.xtracr_realcamera.classicAdjustMode": "Tryb Dostosowania", - "config.option.xtracr_realcamera.scale": "Skala", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Klatki przechowywania wyniku wiązania", "config.option.xtracr_realcamera.cameraOffset": "Przesunięcie Kamery %s", "config.option.xtracr_realcamera.centerOffset": "Przesunięcie Centrum Obrótu %s", - "config.option.xtracr_realcamera.pitch": "Pochylenie", - "config.option.xtracr_realcamera.yaw": "Odchylenie", - "config.option.xtracr_realcamera.roll": "Przechylenie", - "config.option.xtracr_realcamera.toModelViewScreen": "Aby uzyskać szczegółowe ustawienia, przejdź do ekranu %s (wymagane przypisanie klawisza otwierającego)", - "config.option.xtracr_realcamera.screenModifierKey": "Klawisz modyfikatora ekranu %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Tryb Przestarzałego Wiązania", - "config.option.xtracr_realcamera.adjustOffset": "Dostosuj Przesunięcie Kamery", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ukryj komunikaty o niepowodzeniu wiązania", - "config.option.xtracr_realcamera.renderStuckObjects": "Wyświetl Zatkane Obiekty", - "config.option.xtracr_realcamera.rerenderModel": "Ponownie Wyrenderuj Model", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Klatki przechowywania wyniku wiązania", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Współczynnik wygładzania przemieszczenia", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Współczynnik wygładzania obrotu", - "config.option.xtracr_realcamera.activeConfigIndex": "Aktywny Indeks Konfiguracji", + "config.option.xtracr_realcamera.classicAdjustMode": "Tryb Dostosowania", "config.option.xtracr_realcamera.disableConfig": "Wyłącz Konfigurację", - "config.option.xtracr_realcamera.disableWhenSneaking": "Wyłącz główną funkcję podczas skradania", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Wyłącz główną funkcję podczas trzymania...", + "config.option.xtracr_realcamera.disableRenderItems": "Wyłącz renderowanie podczas trzymania...", "config.option.xtracr_realcamera.disableWhenCrawling": "Wyłącz główną funkcję podczas czołgania", + "config.option.xtracr_realcamera.disableWhenSneaking": "Wyłącz główną funkcję podczas skradania", "config.option.xtracr_realcamera.disableWhenSwimming": "Wyłącz główną funkcję podczas pływania", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Współczynnik wygładzania przemieszczenia", + "config.option.xtracr_realcamera.dynamicCrosshair": "Dynamiczny Celownik", + "config.option.xtracr_realcamera.enabled": "Mod Włączony", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ukryj komunikaty o niepowodzeniu wiązania", + "config.option.xtracr_realcamera.isClassic": "Tryb Klasyczny", + "config.option.xtracr_realcamera.legacyBindingMode": "Tryb Przestarzałego Wiązania", "config.option.xtracr_realcamera.outTick": "Opóźnienie wyjścia ze stanu pływania (w tickach)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Wyłącz główną funkcję podczas trzymania...", - "config.option.xtracr_realcamera.disableRenderItems": "Wyłącz renderowanie podczas trzymania...", - "config.tooltip.xtracr_realcamera.isClassic": "Tryb klasyczny wprowadza tylko proste zmiany w pozycji i obrocie kamery", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Po włączeniu celownik będzie podążał za wzrokiem gracza, zapewniając precyzyjne trafienie\nZaleca się włączenie przy instalacji modów takich jak Jade, WTHIT lub podobnych", - "config.tooltip.xtracr_realcamera.renderModel": "Wyświetl model gracza w trybie pierwszoosobowym", + "config.option.xtracr_realcamera.pitch": "Pochylenie", + "config.option.xtracr_realcamera.renderModel": "Wyświetl Model Gracza", + "config.option.xtracr_realcamera.renderStuckObjects": "Wyświetl Zatkane Obiekty", + "config.option.xtracr_realcamera.rerenderModel": "Ponownie Wyrenderuj Model", + "config.option.xtracr_realcamera.roll": "Przechylenie", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Współczynnik wygładzania obrotu", + "config.option.xtracr_realcamera.scale": "Skala", + "config.option.xtracr_realcamera.screenModifierKey": "Klawisz modyfikatora ekranu %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Aby uzyskać szczegółowe ustawienia, przejdź do ekranu %s (wymagane przypisanie klawisza otwierającego)", + "config.option.xtracr_realcamera.yaw": "Odchylenie", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Aktualnie powiązany indeks konfiguracji, 0 oznacza pozwolenie na powiązanie z dowolną prawidłową konfiguracją", + "config.tooltip.xtracr_realcamera.adjustOffset": "Po naciśnięciu klawisza dostosowania, reguluj przesunięcie lub obrót kamery", "config.tooltip.xtracr_realcamera.adjustStep": "Długość lub 1/100 kąta dostosowania na krok", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Przez kilka klatek po niepowodzeniu wiązania kontynuuj używanie poprzedniego udanego wyniku wiązania", + "config.tooltip.xtracr_realcamera.cameraRotation": "Dodatkowy obrót kamery w stopniach", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Uwaga: pochylenie, odchylenie i przechylenie to obroty wokół lewej, górnej i przedniej osi odpowiednio", + "config.tooltip.xtracr_realcamera.centerOffset": "Przesunięcie centrum obrotu względem głowy", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Określa, co dostosować po naciśnięciu klawisza dostosowania", - "config.tooltip.xtracr_realcamera.scale": "Kontroluj rozmiar przesunięć", + "config.tooltip.xtracr_realcamera.classicOffset": "Przesunięcie kamery względem centrum obrotu", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Uwaga: przód, góra i lewa strona gracza odpowiadają osiom X, Y i Z", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Obsługiwane są trzy metody dopasowania:\n1. Dopasowanie wildcard `*` (np. `minecraft:*sword`)\n2. Dopasowanie tagów (zaczyna się od `#`, np. `#minecraft:swords`)\n3. Bezpośrednie ID przedmiotu (np. `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Współczynnik wygładzania przemieszczenia kamery, im wyższa wartość, tym płynniejszy ruch", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Po włączeniu celownik będzie podążał za wzrokiem gracza, zapewniając precyzyjne trafienie\nZaleca się włączenie przy instalacji modów takich jak Jade, WTHIT lub podobnych", + "config.tooltip.xtracr_realcamera.isClassic": "Tryb klasyczny wprowadza tylko proste zmiany w pozycji i obrocie kamery", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Używa trybu przestarzałego wiązania (v0.5), obsługuje tylko standardowe modele i działania na nich bazujące\nPo włączeniu właściwości można ustawić w 'LEGACY_MODE' ekranu %s", - "config.tooltip.xtracr_realcamera.adjustOffset": "Po naciśnięciu klawisza dostosowania, reguluj przesunięcie lub obrót kamery", + "config.tooltip.xtracr_realcamera.outTick": "Opóźnienie włączenia głównej funkcji po wyjściu ze stanu pływania (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Wyświetl model gracza w trybie pierwszoosobowym", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Strzały, żądła pszczół i inne obiekty, które mogą utknąć w ciele gracza", "config.tooltip.xtracr_realcamera.rerenderModel": "Ponownie renderuj model w oryginalnym czasie renderowania, aby uniknąć problemów wizualnych spowodowanych wczesnym renderowaniem", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Przez kilka klatek po niepowodzeniu wiązania kontynuuj używanie poprzedniego udanego wyniku wiązania", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Współczynnik wygładzania przemieszczenia kamery, im wyższa wartość, tym płynniejszy ruch", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Współczynnik wygładzania obrotu kamery, im wyższa wartość, tym płynniejszy ruch", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Aktualnie powiązany indeks konfiguracji, 0 oznacza pozwolenie na powiązanie z dowolną prawidłową konfiguracją", - "config.tooltip.xtracr_realcamera.outTick": "Opóźnienie włączenia głównej funkcji po wyjściu ze stanu pływania (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Obsługiwane są trzy metody dopasowania:\n1. Dopasowanie wildcard `*` (np. `minecraft:*sword`)\n2. Dopasowanie tagów (zaczyna się od `#`, np. `#minecraft:swords`)\n3. Bezpośrednie ID przedmiotu (np. `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Kontroluj rozmiar przesunięć", + "general.xtracr_realcamera.modName": "Prawdziwa Kamera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Przełącz na następną konfigurację", + "key.xtracr_realcamera.activeConfigIndexPREV": "Przełącz na poprzednią konfigurację", + "key.xtracr_realcamera.activeConfigIndexRESET": "Zresetuj indeks konfiguracji", + "key.xtracr_realcamera.adjustBACK": "Dostosuj DO TYŁU", + "key.xtracr_realcamera.adjustDOWN": "Dostosuj W DÓŁ", + "key.xtracr_realcamera.adjustFRONT": "Dostosuj DO PRZODU", + "key.xtracr_realcamera.adjustLEFT": "Dostosuj W LEWO", + "key.xtracr_realcamera.adjustRIGHT": "Dostosuj W PRAWO", + "key.xtracr_realcamera.adjustUP": "Dostosuj W GÓRĘ", + "key.xtracr_realcamera.modelViewScreen": "Otwórz Ekran Podglądu Modelu", + "key.xtracr_realcamera.toggleAdjustMode": "Przełącz Tryb Dostosowania", + "key.xtracr_realcamera.toggleCameraMode": "Przełącz Tryb Kamery", + "key.xtracr_realcamera.togglePerspective": "Włącz/Wyłącz", "message.xtracr_realcamera.bindingFailed": "[%s]: Błąd powiązania, przejdź do ekranu %s i skonfiguruj ręcznie (Klawisz: %s)", - - "screen.xtracr_realcamera.modelView_title": "Widok modelu", - "screen.widget.xtracr_realcamera.modelView_import": "Importuj", + "modmenu.descriptionTranslation.realcamera": "Uczynienie kamery bardziej realistyczną w trybie pierwszoosobowym.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Po wyłączeniu względna pozycja kamery względem modelu nie ulegnie zmianie, ale odpowiednie atrybuty kamery nie będą modyfikowane przez ten mod", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Zapisane konfiguracje", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Skopiuj wszystkie ustawienia wyłączenia", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Usuń zaznaczony prostokąt\n(Lub użyj klawisza Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Płaszczyzny, w których wszystkie odległości od wierzchołka do ekranu są mniejsze niż ta wartość, nie będą renderowane", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Ustawienia wyłączenia\nGlobalne ustawienia wyłączenia znajdują się na ekranie konfiguracji", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Części zawarte w niebieskich ramkach zostaną wyłączone\nLewy przycisk myszy do wyboru, inne klawisze do anulowania wyboru\n%s+LKliknij, aby szybko wybrać część wskazaną przez kursor myszy", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nazwa ustawienia wyłączenia", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Nazwa nie może być pusta!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Identyfikator tekstury nie może być pusty!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Eksportuj bieżącą konfigurację do schowka", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Eksport nie powiódł się: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Eksport powiódł się!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Numer zaznaczonego prostokąta\n(0 oznacza brak wyboru)\nNaciśnij Spację lub Enter, aby zlokalizować bieżący zaznaczony prostokąt (Podczas pisania naciśnij dwukrotnie, aby zlokalizować)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Importuj konfigurację ze schowka", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import nie powiódł się: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s powiódł się!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Wklej wszystkie ustawienia wyłączenia ze schowka do bieżącej konfiguracji\n(Nie nadpisze istniejących ustawień o tej samej nazwie)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "W trybie podglądu możesz dostosować przesunięcie i obrót kamery", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorytet powiązania: im większa wartość, tym wyższy priorytet i wyższe sortowanie po prawej stronie", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Zapisz jako\n(Gdy istnieje konfiguracja o tej samej nazwie, możesz również użyć przycisku zapisu po lewej stronie)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Skala, która kontroluje rozmiar przesunięć", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+LKliknij, aby uzyskać współrzędne UV w miejscu wskaźnika myszy\nTrzy zestawy współrzędnych UV poniżej, od góry do dołu, to współrzędne UV wektora do przodu, wektora w górę i punktu wiązania na płaszczyźnie docelowej\nUwaga: %s+Przewiń, aby przełączać się między różnymi warstwami modelu. Ręczne wprowadzanie współrzędnych UV pozwala dokładniej powiązać z pozycją docelową", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Określa tryb szybkiego wyboru %s+LKliknięcia\n(%s+Przewiń, aby zmienić zakres wyboru w trybie zakresu)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nazwa konfiguracji", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "Identyfikator tekstury wybranego modelu (niekoniecznie pełny identyfikator), może zostać skrócony podczas zapisywania dla łatwiejszego rozpoznania.\nNa przykład skróć minecraft:textures/entity/player/slim/alex.png do minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Otwórz globalny ekran konfiguracji\n(Wymagane Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "Wszystko", + "screen.widget.xtracr_realcamera.modelView_configs": "Konfiguracje", + "screen.widget.xtracr_realcamera.modelView_copy": "Kopiuj", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Bieżąca Konfiguracja", + "screen.widget.xtracr_realcamera.modelView_disable": "Wyłącz", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Tryb wyłączenia", "screen.widget.xtracr_realcamera.modelView_export": "Eksportuj", - "screen.widget.xtracr_realcamera.modelView_selecting": "Wybór", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Wektor do przodu", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Wektor w górę", - "screen.widget.xtracr_realcamera.modelView_position": "Płaszczyzna docelowa", - "screen.widget.xtracr_realcamera.modelView_save": "Zapisz", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Tryb wyłączenia", - "screen.widget.xtracr_realcamera.modelView_all": "Wszystko", - "screen.widget.xtracr_realcamera.modelView_part": "Część", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Tryb wyboru", - "screen.widget.xtracr_realcamera.modelView_single": "Pojedynczy", + "screen.widget.xtracr_realcamera.modelView_import": "Importuj", "screen.widget.xtracr_realcamera.modelView_multiple": "Wielokrotny", - "screen.widget.xtracr_realcamera.modelView_range": "Zakres", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Przełącz suwak na pole", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Przełącz pole na suwak", "screen.widget.xtracr_realcamera.modelView_offsetX": "Przesunięcie X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Przesunięcie Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Przesunięcie Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Część", + "screen.widget.xtracr_realcamera.modelView_paste": "Wklej", "screen.widget.xtracr_realcamera.modelView_pitch": "Pochylenie = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Odchylenie = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Przechylenie = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Wyłącz", + "screen.widget.xtracr_realcamera.modelView_position": "Płaszczyzna docelowa", "screen.widget.xtracr_realcamera.modelView_preview": "Podgląd", - "screen.widget.xtracr_realcamera.modelView_configs": "Konfiguracje", - "screen.widget.xtracr_realcamera.modelView_copy": "Kopiuj", - "screen.widget.xtracr_realcamera.modelView_paste": "Wklej", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Bieżąca Konfiguracja", - "screen.tooltip.xtracr_realcamera.modelView_import": "Importuj konfigurację ze schowka", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s powiódł się!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import nie powiódł się: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Eksportuj bieżącą konfigurację do schowka", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Eksport powiódł się!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Eksport nie powiódł się: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+LKliknij, aby uzyskać współrzędne UV w miejscu wskaźnika myszy\nTrzy zestawy współrzędnych UV poniżej, od góry do dołu, to współrzędne UV wektora do przodu, wektora w górę i punktu wiązania na płaszczyźnie docelowej\nUwaga: %s+Przewiń, aby przełączać się między różnymi warstwami modelu. Ręczne wprowadzanie współrzędnych UV pozwala dokładniej powiązać z pozycją docelową", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "Identyfikator tekstury wybranego modelu (niekoniecznie pełny identyfikator), może zostać skrócony podczas zapisywania dla łatwiejszego rozpoznania.\nNa przykład skróć minecraft:textures/entity/player/slim/alex.png do minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Części zawarte w niebieskich ramkach zostaną wyłączone\nLewy przycisk myszy do wyboru, inne klawisze do anulowania wyboru\n%s+LKliknij, aby szybko wybrać część wskazaną przez kursor myszy", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Określa tryb szybkiego wyboru %s+LKliknięcia\n(%s+Przewiń, aby zmienić zakres wyboru w trybie zakresu)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Numer zaznaczonego prostokąta\n(0 oznacza brak wyboru)\nNaciśnij Spację lub Enter, aby zlokalizować bieżący zaznaczony prostokąt (Podczas pisania naciśnij dwukrotnie, aby zlokalizować)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Usuń zaznaczony prostokąt\n(Lub użyj klawisza Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Po wyłączeniu względna pozycja kamery względem modelu nie ulegnie zmianie, ale odpowiednie atrybuty kamery nie będą modyfikowane przez ten mod", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Skala, która kontroluje rozmiar przesunięć", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Płaszczyzny, w których wszystkie odległości od wierzchołka do ekranu są mniejsze niż ta wartość, nie będą renderowane", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorytet powiązania: im większa wartość, tym wyższy priorytet i wyższe sortowanie po prawej stronie", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nazwa konfiguracji", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Ustawienia wyłączenia\nGlobalne ustawienia wyłączenia znajdują się na ekranie konfiguracji", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Zapisane konfiguracje", - "screen.tooltip.xtracr_realcamera.modelView_preview": "W trybie podglądu możesz dostosować przesunięcie i obrót kamery", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Otwórz globalny ekran konfiguracji\n(Wymagane Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Skopiuj wszystkie ustawienia wyłączenia", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Wklej wszystkie ustawienia wyłączenia ze schowka do bieżącej konfiguracji\n(Nie nadpisze istniejących ustawień o tej samej nazwie)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Nazwa nie może być pusta!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Identyfikator tekstury nie może być pusty!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Zapisz jako\n(Gdy istnieje konfiguracja o tej samej nazwie, możesz również użyć przycisku zapisu po lewej stronie)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nazwa ustawienia wyłączenia" + "screen.widget.xtracr_realcamera.modelView_range": "Zakres", + "screen.widget.xtracr_realcamera.modelView_roll": "Przechylenie = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Zapisz", + "screen.widget.xtracr_realcamera.modelView_selecting": "Wybór", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Tryb wyboru", + "screen.widget.xtracr_realcamera.modelView_single": "Pojedynczy", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Przełącz pole na suwak", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Przełącz suwak na pole", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Wektor w górę", + "screen.widget.xtracr_realcamera.modelView_yaw": "Odchylenie = %s", + "screen.xtracr_realcamera.modelView_title": "Widok modelu" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/pt_br.json b/common/src/main/resources/assets/realcamera/lang/pt_br.json index dc1188e5..ae0d7381 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_br.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_br.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Abrir Tela de Visualização do Modelo", - "key.xtracr_realcamera.togglePerspective": "Ativar/Desativar", - "key.xtracr_realcamera.activeConfigIndexPREV": "Mudar para configuração anterior", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Mudar para próxima configuração", - "key.xtracr_realcamera.activeConfigIndexRESET": "Redefinir índice de configuração", - "key.xtracr_realcamera.toggleAdjustMode": "Alternar Modo de Ajuste", - "key.xtracr_realcamera.toggleCameraMode": "Alternar Modo de Câmera", - "key.xtracr_realcamera.adjustUP": "Ajustar PARA CIMA", - "key.xtracr_realcamera.adjustDOWN": "Ajustar PARA BAIXO", - "key.xtracr_realcamera.adjustFRONT": "Ajustar FRENTE", - "key.xtracr_realcamera.adjustBACK": "Ajustar TRÁS", - "key.xtracr_realcamera.adjustLEFT": "Ajustar ESQUERDA", - "key.xtracr_realcamera.adjustRIGHT": "Ajustar DIREITA", - "modmenu.descriptionTranslation.realcamera": "Torna a câmera mais realista na visão em primeira pessoa.", - - "config.category.xtracr_realcamera.general": "Geral", "config.category.xtracr_realcamera.binding": "Modo de Vinculação", - "config.category.xtracr_realcamera.classic": "Modo Clássico", "config.category.xtracr_realcamera.cameraOffset": "Deslocamento da Câmera", - "config.category.xtracr_realcamera.centerOffset": "Deslocamento do Centro de Rotação", "config.category.xtracr_realcamera.cameraRotation": "Rotação da Câmera", - "config.tooltip.xtracr_realcamera.classicOffset": "Deslocamento da câmera em relação ao seu centro de rotação", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Nota: a frente, cima e esquerda do jogador são os eixos X, Y e Z respectivamente", - "config.tooltip.xtracr_realcamera.centerOffset": "Deslocamento do centro de rotação em relação à cabeça", - "config.tooltip.xtracr_realcamera.cameraRotation": "Rotação adicional da câmera em graus", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Nota: Pitch, yaw e roll são rotações nos eixos esquerda, cima e frente respectivamente", - - "config.option.xtracr_realcamera.enabled": "Mod Ativado", - "config.option.xtracr_realcamera.isClassic": "Modo Clássico", - "config.option.xtracr_realcamera.dynamicCrosshair": "Mira Dinâmica", - "config.option.xtracr_realcamera.renderModel": "Renderizar Modelo do Jogador", + "config.category.xtracr_realcamera.centerOffset": "Deslocamento do Centro de Rotação", + "config.category.xtracr_realcamera.classic": "Modo Clássico", + "config.category.xtracr_realcamera.general": "Geral", + "config.option.xtracr_realcamera.activeConfigIndex": "Índice de Configuração Ativa", + "config.option.xtracr_realcamera.adjustOffset": "Ajustar Deslocamento da Câmera", "config.option.xtracr_realcamera.adjustStep": "Passo de Ajuste", - "config.option.xtracr_realcamera.classicAdjustMode": "Modo de Ajuste", - "config.option.xtracr_realcamera.scale": "Escala", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Quadros de retenção de resultado de vinculação", "config.option.xtracr_realcamera.cameraOffset": "Deslocamento %s da Câmera", "config.option.xtracr_realcamera.centerOffset": "Deslocamento %s do Centro de Rotação", - "config.option.xtracr_realcamera.pitch": "Pitch", - "config.option.xtracr_realcamera.yaw": "Yaw", - "config.option.xtracr_realcamera.roll": "Roll", - "config.option.xtracr_realcamera.toModelViewScreen": "Para configurações detalhadas, vá para a tela %s (é necessário definir uma tecla para abri-la)", - "config.option.xtracr_realcamera.screenModifierKey": "Tecla modificadora de tela %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Modo de Vinculação Legado", - "config.option.xtracr_realcamera.adjustOffset": "Ajustar Deslocamento da Câmera", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensagens de falha de vinculação", - "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Presos", - "config.option.xtracr_realcamera.rerenderModel": "Renderizar Modelo Novamente", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Quadros de retenção de resultado de vinculação", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização de deslocamento", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização de rotação", - "config.option.xtracr_realcamera.activeConfigIndex": "Índice de Configuração Ativa", + "config.option.xtracr_realcamera.classicAdjustMode": "Modo de Ajuste", "config.option.xtracr_realcamera.disableConfig": "Desativar Configuração", - "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Desativar função principal ao segurar...", + "config.option.xtracr_realcamera.disableRenderItems": "Desativar renderização ao segurar...", "config.option.xtracr_realcamera.disableWhenCrawling": "Desativar função principal ao rastejar", + "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", "config.option.xtracr_realcamera.disableWhenSwimming": "Desativar função principal ao nadar", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização de deslocamento", + "config.option.xtracr_realcamera.dynamicCrosshair": "Mira Dinâmica", + "config.option.xtracr_realcamera.enabled": "Mod Ativado", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensagens de falha de vinculação", + "config.option.xtracr_realcamera.isClassic": "Modo Clássico", + "config.option.xtracr_realcamera.legacyBindingMode": "Modo de Vinculação Legado", "config.option.xtracr_realcamera.outTick": "Atraso na saída do estado de natação (em ticks)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Desativar função principal ao segurar...", - "config.option.xtracr_realcamera.disableRenderItems": "Desativar renderização ao segurar...", - "config.tooltip.xtracr_realcamera.isClassic": "O modo clássico apenas faz alterações simples na posição e rotação da câmera", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Quando ativado, a mira seguirá a visão do jogador, garantindo um resultado de acerto consistente\nRecomendado ativar quando mods como Jade, WTHIT ou similares estiverem instalados", - "config.tooltip.xtracr_realcamera.renderModel": "Renderizar modelo do jogador em perspectiva de primeira pessoa", + "config.option.xtracr_realcamera.pitch": "Pitch", + "config.option.xtracr_realcamera.renderModel": "Renderizar Modelo do Jogador", + "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Presos", + "config.option.xtracr_realcamera.rerenderModel": "Renderizar Modelo Novamente", + "config.option.xtracr_realcamera.roll": "Roll", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização de rotação", + "config.option.xtracr_realcamera.scale": "Escala", + "config.option.xtracr_realcamera.screenModifierKey": "Tecla modificadora de tela %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Para configurações detalhadas, vá para a tela %s (é necessário definir uma tecla para abri-la)", + "config.option.xtracr_realcamera.yaw": "Yaw", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuração atualmente vinculada, 0 significa permitir vinculação a qualquer configuração válida", + "config.tooltip.xtracr_realcamera.adjustOffset": "Ao pressionar a tecla de ajuste, ajusta o deslocamento ou rotação da câmera", "config.tooltip.xtracr_realcamera.adjustStep": "Comprimento ou 1/100 do ângulo do ajuste por passo", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Por vários quadros após a falha de vinculação, continue usando o resultado de vinculação bem-sucedido anterior", + "config.tooltip.xtracr_realcamera.cameraRotation": "Rotação adicional da câmera em graus", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Nota: Pitch, yaw e roll são rotações nos eixos esquerda, cima e frente respectivamente", + "config.tooltip.xtracr_realcamera.centerOffset": "Deslocamento do centro de rotação em relação à cabeça", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Determina o que ajustar ao pressionar a tecla de ajuste", - "config.tooltip.xtracr_realcamera.scale": "Controla o tamanho dos deslocamentos", + "config.tooltip.xtracr_realcamera.classicOffset": "Deslocamento da câmera em relação ao seu centro de rotação", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Nota: a frente, cima e esquerda do jogador são os eixos X, Y e Z respectivamente", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Três métodos de correspondência são suportados:\n1. Correspondência com curinga `*` (por exemplo, `minecraft:*sword`)\n2. Correspondência de tag (começa com `#`, por exemplo, `#minecraft:swords`)\n3. ID de item direto (por exemplo, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização do deslocamento da câmera, quanto maior o valor, mais suave o movimento", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Quando ativado, a mira seguirá a visão do jogador, garantindo um resultado de acerto consistente\nRecomendado ativar quando mods como Jade, WTHIT ou similares estiverem instalados", + "config.tooltip.xtracr_realcamera.isClassic": "O modo clássico apenas faz alterações simples na posição e rotação da câmera", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Usando o modo de vinculação da versão legada (v0.5), apenas modelos vanilla e ações baseadas em modelos vanilla são suportados\nSuas propriedades podem ser definidas em 'LEGACY_MODE' da tela %s quando ativado", - "config.tooltip.xtracr_realcamera.adjustOffset": "Ao pressionar a tecla de ajuste, ajusta o deslocamento ou rotação da câmera", + "config.tooltip.xtracr_realcamera.outTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Renderizar modelo do jogador em perspectiva de primeira pessoa", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flechas, ferrões de abelha e outros objetos que podem ficar presos no corpo do jogador", "config.tooltip.xtracr_realcamera.rerenderModel": "Renderizar o modelo novamente no momento original de renderização para evitar alguns problemas visuais causados pela renderização antecipada", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Por vários quadros após a falha de vinculação, continue usando o resultado de vinculação bem-sucedido anterior", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização do deslocamento da câmera, quanto maior o valor, mais suave o movimento", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização da rotação da câmera, quanto maior o valor, mais suave o movimento", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuração atualmente vinculada, 0 significa permitir vinculação a qualquer configuração válida", - "config.tooltip.xtracr_realcamera.outTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Três métodos de correspondência são suportados:\n1. Correspondência com curinga `*` (por exemplo, `minecraft:*sword`)\n2. Correspondência de tag (começa com `#`, por exemplo, `#minecraft:swords`)\n3. ID de item direto (por exemplo, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Controla o tamanho dos deslocamentos", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Mudar para próxima configuração", + "key.xtracr_realcamera.activeConfigIndexPREV": "Mudar para configuração anterior", + "key.xtracr_realcamera.activeConfigIndexRESET": "Redefinir índice de configuração", + "key.xtracr_realcamera.adjustBACK": "Ajustar TRÁS", + "key.xtracr_realcamera.adjustDOWN": "Ajustar PARA BAIXO", + "key.xtracr_realcamera.adjustFRONT": "Ajustar FRENTE", + "key.xtracr_realcamera.adjustLEFT": "Ajustar ESQUERDA", + "key.xtracr_realcamera.adjustRIGHT": "Ajustar DIREITA", + "key.xtracr_realcamera.adjustUP": "Ajustar PARA CIMA", + "key.xtracr_realcamera.modelViewScreen": "Abrir Tela de Visualização do Modelo", + "key.xtracr_realcamera.toggleAdjustMode": "Alternar Modo de Ajuste", + "key.xtracr_realcamera.toggleCameraMode": "Alternar Modo de Câmera", + "key.xtracr_realcamera.togglePerspective": "Ativar/Desativar", "message.xtracr_realcamera.bindingFailed": "[%s]: Vinculação falhou, por favor vá para a tela %s e configure manualmente (Tecla: %s)", - - "screen.xtracr_realcamera.modelView_title": "Visualização de Modelo", - "screen.widget.xtracr_realcamera.modelView_import": "Importar", + "modmenu.descriptionTranslation.realcamera": "Torna a câmera mais realista na visão em primeira pessoa.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Quando desativado, a relação relativa da câmera com o modelo não mudará, mas os atributos correspondentes da câmera não serão modificados por este mod", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurações Salvas", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas as configurações de desativação", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Excluir o retângulo selecionado\n(Ou use a tecla Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Planos onde todas as distâncias vértice-para-tela são menores que este valor não serão renderizados", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Configurações de Desativação\nConfigurações globais de desativação estão na tela de configuração", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "As partes contidas nas caixas azuis serão desativadas\nClique esquerdo para selecionar, outras teclas para cancelar a seleção\n%s+Clique Esquerdo para selecionar rapidamente a parte apontada pelo cursor do mouse", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nome da configuração de desativação", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "O nome não pode estar vazio!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "O ID da textura não pode estar vazio!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Exportar configuração atual para a área de transferência", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Falha na exportação: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Exportação bem-sucedida!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Número do Retângulo Focado\n(0 significa nenhuma seleção)\nPressione Espaço ou Enter para localizar o retângulo focado atual (Ao digitar, pressione duas vezes para localizar)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Colar todas as configurações de desativação da área de transferência para a configuração atual\n(Não substituirá configurações existentes com o mesmo nome)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla o tamanho dos deslocamentos", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clique Esquerdo para obter as coordenadas UV no ponteiro do mouse\nOs três conjuntos de coordenadas UV abaixo são, de cima para baixo, as coordenadas UV do vetor de frente, do vetor para cima e do ponto de vinculação no plano alvo\nNota: %s+Rolar para alternar entre as diferentes camadas do modelo. Inserir manualmente as coordenadas UV permite vincular com mais precisão à posição alvo", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina o modo de seleção rápida %s+Clique Esquerdo\n(%s+Rolar para alterar o intervalo de seleção no modo de intervalo)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nome da configuração", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "O ID da textura do modelo selecionado (não precisa ser o ID completo), pode ser encurtado ao salvar para facilitar o reconhecimento.\nPor exemplo, encurte minecraft:textures/entity/player/slim/alex.png para minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir a Tela de Configuração Global\n(Cloth Config API necessário)", + "screen.widget.xtracr_realcamera.modelView_all": "Todos", + "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", + "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", + "screen.widget.xtracr_realcamera.modelView_disable": "Desativar", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo de Desativação", "screen.widget.xtracr_realcamera.modelView_export": "Exportar", - "screen.widget.xtracr_realcamera.modelView_selecting": "Selecionando", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Vetor de Frente", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vetor para Cima", - "screen.widget.xtracr_realcamera.modelView_position": "Plano Alvo", - "screen.widget.xtracr_realcamera.modelView_save": "Salvar", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo de Desativação", - "screen.widget.xtracr_realcamera.modelView_all": "Todos", - "screen.widget.xtracr_realcamera.modelView_part": "Parte", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Modo de Seleção", - "screen.widget.xtracr_realcamera.modelView_single": "Único", + "screen.widget.xtracr_realcamera.modelView_import": "Importar", "screen.widget.xtracr_realcamera.modelView_multiple": "Múltiplo", - "screen.widget.xtracr_realcamera.modelView_range": "Intervalo", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Alternar Controle Deslizante para Campo", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Alternar Campo para Controle Deslizante", "screen.widget.xtracr_realcamera.modelView_offsetX": "Deslocamento X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Deslocamento Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Deslocamento Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Parte", + "screen.widget.xtracr_realcamera.modelView_paste": "Colar", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Desativar", + "screen.widget.xtracr_realcamera.modelView_position": "Plano Alvo", "screen.widget.xtracr_realcamera.modelView_preview": "Pré-visualização", - "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", - "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", - "screen.widget.xtracr_realcamera.modelView_paste": "Colar", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", - "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Exportar configuração atual para a área de transferência", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Exportação bem-sucedida!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Falha na exportação: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clique Esquerdo para obter as coordenadas UV no ponteiro do mouse\nOs três conjuntos de coordenadas UV abaixo são, de cima para baixo, as coordenadas UV do vetor de frente, do vetor para cima e do ponto de vinculação no plano alvo\nNota: %s+Rolar para alternar entre as diferentes camadas do modelo. Inserir manualmente as coordenadas UV permite vincular com mais precisão à posição alvo", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "O ID da textura do modelo selecionado (não precisa ser o ID completo), pode ser encurtado ao salvar para facilitar o reconhecimento.\nPor exemplo, encurte minecraft:textures/entity/player/slim/alex.png para minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "As partes contidas nas caixas azuis serão desativadas\nClique esquerdo para selecionar, outras teclas para cancelar a seleção\n%s+Clique Esquerdo para selecionar rapidamente a parte apontada pelo cursor do mouse", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina o modo de seleção rápida %s+Clique Esquerdo\n(%s+Rolar para alterar o intervalo de seleção no modo de intervalo)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Número do Retângulo Focado\n(0 significa nenhuma seleção)\nPressione Espaço ou Enter para localizar o retângulo focado atual (Ao digitar, pressione duas vezes para localizar)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Excluir o retângulo selecionado\n(Ou use a tecla Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Quando desativado, a relação relativa da câmera com o modelo não mudará, mas os atributos correspondentes da câmera não serão modificados por este mod", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla o tamanho dos deslocamentos", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Planos onde todas as distâncias vértice-para-tela são menores que este valor não serão renderizados", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nome da configuração", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Configurações de Desativação\nConfigurações globais de desativação estão na tela de configuração", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurações Salvas", - "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir a Tela de Configuração Global\n(Cloth Config API necessário)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas as configurações de desativação", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Colar todas as configurações de desativação da área de transferência para a configuração atual\n(Não substituirá configurações existentes com o mesmo nome)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "O nome não pode estar vazio!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "O ID da textura não pode estar vazio!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nome da configuração de desativação" + "screen.widget.xtracr_realcamera.modelView_range": "Intervalo", + "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Salvar", + "screen.widget.xtracr_realcamera.modelView_selecting": "Selecionando", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Modo de Seleção", + "screen.widget.xtracr_realcamera.modelView_single": "Único", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Alternar Campo para Controle Deslizante", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Alternar Controle Deslizante para Campo", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vetor para Cima", + "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", + "screen.xtracr_realcamera.modelView_title": "Visualização de Modelo" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/pt_pt.json b/common/src/main/resources/assets/realcamera/lang/pt_pt.json index 49f8ba17..b672d933 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_pt.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_pt.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Abrir Tela de Visualização de Modelo", - "key.xtracr_realcamera.togglePerspective": "Ativar/Desativar", - "key.xtracr_realcamera.activeConfigIndexPREV": "Mudar para configuração anterior", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Mudar para próxima configuração", - "key.xtracr_realcamera.activeConfigIndexRESET": "Redefinir índice de configuração", - "key.xtracr_realcamera.toggleAdjustMode": "Alternar Modo de Ajuste", - "key.xtracr_realcamera.toggleCameraMode": "Alternar Modo de Câmera", - "key.xtracr_realcamera.adjustUP": "Ajustar PARA CIMA", - "key.xtracr_realcamera.adjustDOWN": "Ajustar PARA BAIXO", - "key.xtracr_realcamera.adjustFRONT": "Ajustar FRENTE", - "key.xtracr_realcamera.adjustBACK": "Ajustar TRÁS", - "key.xtracr_realcamera.adjustLEFT": "Ajustar ESQUERDA", - "key.xtracr_realcamera.adjustRIGHT": "Ajustar DIREITA", - "modmenu.descriptionTranslation.realcamera": "Torne a câmera mais realista na visão em primeira pessoa.", - - "config.category.xtracr_realcamera.general": "Geral", "config.category.xtracr_realcamera.binding": "Modo de Vinculação", - "config.category.xtracr_realcamera.classic": "Modo Clássico", "config.category.xtracr_realcamera.cameraOffset": "Deslocamento da Câmera", - "config.category.xtracr_realcamera.centerOffset": "Deslocamento do Centro de Rotação", "config.category.xtracr_realcamera.cameraRotation": "Rotação da Câmera", - "config.tooltip.xtracr_realcamera.classicOffset": "Deslocamento da câmera em relação ao seu centro de rotação", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Nota: a frente, cima e esquerda do jogador são os eixos X, Y and Z respectivamente", - "config.tooltip.xtracr_realcamera.centerOffset": "Deslocamento do centro de rotação em relação à cabeça", - "config.tooltip.xtracr_realcamera.cameraRotation": "Rotação adicional da câmera em graus", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Nota: Pitch, yaw e roll são rotações nos eixos esquerda, cima e frente respectivamente", - - "config.option.xtracr_realcamera.enabled": "Mod Ativado", - "config.option.xtracr_realcamera.isClassic": "Modo Clássico", - "config.option.xtracr_realcamera.dynamicCrosshair": "Mira Dinâmica", - "config.option.xtracr_realcamera.renderModel": "Renderizar Modelo do Jogador", + "config.category.xtracr_realcamera.centerOffset": "Deslocamento do Centro de Rotação", + "config.category.xtracr_realcamera.classic": "Modo Clássico", + "config.category.xtracr_realcamera.general": "Geral", + "config.option.xtracr_realcamera.activeConfigIndex": "Índice de Configuração Ativa", + "config.option.xtracr_realcamera.adjustOffset": "Ajustar Deslocamento da Câmera", "config.option.xtracr_realcamera.adjustStep": "Passo de Ajuste", - "config.option.xtracr_realcamera.classicAdjustMode": "Modo de Ajuste", - "config.option.xtracr_realcamera.scale": "Escala", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Quadros de retenção de resultado de vinculação", "config.option.xtracr_realcamera.cameraOffset": "Deslocamento %s da Câmera", "config.option.xtracr_realcamera.centerOffset": "Deslocamento %s do Centro de Rotação", - "config.option.xtracr_realcamera.pitch": "Pitch", - "config.option.xtracr_realcamera.yaw": "Yaw", - "config.option.xtracr_realcamera.roll": "Roll", - "config.option.xtracr_realcamera.toModelViewScreen": "Para configurações detalhadas, vá para a tela %s (é necessário definir uma tecla para abri-la)", - "config.option.xtracr_realcamera.screenModifierKey": "Tecla modificadora de tela %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Modo de Vinculação Legado", - "config.option.xtracr_realcamera.adjustOffset": "Ajustar Deslocamento da Câmera", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensagens de falha de vinculação", - "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Presos", - "config.option.xtracr_realcamera.rerenderModel": "Renderizar Modelo Novamente", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Quadros de retenção de resultado de vinculação", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização de deslocamento", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização de rotação", - "config.option.xtracr_realcamera.activeConfigIndex": "Índice de Configuração Ativa", + "config.option.xtracr_realcamera.classicAdjustMode": "Modo de Ajuste", "config.option.xtracr_realcamera.disableConfig": "Desativar Configuração", - "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Desativar função principal ao segurar...", + "config.option.xtracr_realcamera.disableRenderItems": "Desativar renderização ao segurar...", "config.option.xtracr_realcamera.disableWhenCrawling": "Desativar função principal ao rastejar", + "config.option.xtracr_realcamera.disableWhenSneaking": "Desativar função principal ao agachar", "config.option.xtracr_realcamera.disableWhenSwimming": "Desativar função principal ao nadar", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização de deslocamento", + "config.option.xtracr_realcamera.dynamicCrosshair": "Mira Dinâmica", + "config.option.xtracr_realcamera.enabled": "Mod Ativado", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Ocultar mensagens de falha de vinculação", + "config.option.xtracr_realcamera.isClassic": "Modo Clássico", + "config.option.xtracr_realcamera.legacyBindingMode": "Modo de Vinculação Legado", "config.option.xtracr_realcamera.outTick": "Atraso na saída do estado de natação (em ticks)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Desativar função principal ao segurar...", - "config.option.xtracr_realcamera.disableRenderItems": "Desativar renderização ao segurar...", - "config.tooltip.xtracr_realcamera.isClassic": "O modo clássico apenas faz alterações simples na posição e rotação da câmera", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Quando ativado, a mira seguirá a visão do jogador, garantindo um resultado de acerto consistente\nRecomendado ativar quando mods como Jade, WTHIT ou similares estiverem instalados", - "config.tooltip.xtracr_realcamera.renderModel": "Renderizar modelo do jogador em perspectiva de primeira pessoa", + "config.option.xtracr_realcamera.pitch": "Pitch", + "config.option.xtracr_realcamera.renderModel": "Renderizar Modelo do Jogador", + "config.option.xtracr_realcamera.renderStuckObjects": "Renderizar Objetos Presos", + "config.option.xtracr_realcamera.rerenderModel": "Renderizar Modelo Novamente", + "config.option.xtracr_realcamera.roll": "Roll", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização de rotação", + "config.option.xtracr_realcamera.scale": "Escala", + "config.option.xtracr_realcamera.screenModifierKey": "Tecla modificadora de tela %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Para configurações detalhadas, vá para a tela %s (é necessário definir uma tecla para abri-la)", + "config.option.xtracr_realcamera.yaw": "Yaw", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuração atualmente vinculada, 0 significa permitir vinculação a qualquer configuração válida", + "config.tooltip.xtracr_realcamera.adjustOffset": "Ao pressionar a tecla de ajuste, ajusta o deslocamento ou rotação da câmera", "config.tooltip.xtracr_realcamera.adjustStep": "Comprimento ou 1/100 do ângulo do ajuste por passo", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Por vários quadros após a falha de vinculação, continue usando o resultado de vinculação bem-sucedido anterior", + "config.tooltip.xtracr_realcamera.cameraRotation": "Rotação adicional da câmera em graus", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Nota: Pitch, yaw e roll são rotações nos eixos esquerda, cima e frente respectivamente", + "config.tooltip.xtracr_realcamera.centerOffset": "Deslocamento do centro de rotação em relação à cabeça", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Determina o que ajustar ao pressionar a tecla de ajuste", - "config.tooltip.xtracr_realcamera.scale": "Controla o tamanho dos deslocamentos", + "config.tooltip.xtracr_realcamera.classicOffset": "Deslocamento da câmera em relação ao seu centro de rotação", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Nota: a frente, cima e esquerda do jogador são os eixos X, Y and Z respectivamente", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Três métodos de correspondência são suportados:\n1. Correspondência com curinga `*` (por exemplo, `minecraft:*sword`)\n2. Correspondência de tag (começa com `#`, por exemplo, `#minecraft:swords`)\n3. ID de item direto (por exemplo, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização do deslocamento da câmera, quanto maior o valor, mais suave o movimento", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Quando ativado, a mira seguirá a visão do jogador, garantindo um resultado de acerto consistente\nRecomendado ativar quando mods como Jade, WTHIT ou similares estiverem instalados", + "config.tooltip.xtracr_realcamera.isClassic": "O modo clássico apenas faz alterações simples na posição e rotação da câmera", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Usando o modo de vinculação da versão legada (v0.5), apenas modelos vanilla e ações baseadas em modelos vanilla são suportados\nSuas propriedades podem ser definidas em 'LEGACY_MODE' da tela %s quando ativado", - "config.tooltip.xtracr_realcamera.adjustOffset": "Ao pressionar a tecla de ajuste, ajusta o deslocamento ou rotação da câmera", + "config.tooltip.xtracr_realcamera.outTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Renderizar modelo do jogador em perspectiva de primeira pessoa", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Flechas, ferrões de abelha e outros objetos que podem ficar presos no corpo do jogador", "config.tooltip.xtracr_realcamera.rerenderModel": "Renderizar o modelo novamente no momento original de renderização para evitar alguns problemas visuais causados pela renderização antecipada", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Por vários quadros após a falha de vinculação, continue usando o resultado de vinculação bem-sucedido anterior", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Fator de suavização do deslocamento da câmera, quanto maior o valor, mais suave o movimento", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Fator de suavização da rotação da câmera, quanto maior o valor, mais suave o movimento", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Índice de configuração atualmente vinculada, 0 significa permitir vinculação a qualquer configuração válida", - "config.tooltip.xtracr_realcamera.outTick": "O tempo antes de habilitar o recurso principal após sair do estado de natação (1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Três métodos de correspondência são suportados:\n1. Correspondência com curinga `*` (por exemplo, `minecraft:*sword`)\n2. Correspondência de tag (começa com `#`, por exemplo, `#minecraft:swords`)\n3. ID de item direto (por exemplo, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Controla o tamanho dos deslocamentos", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Mudar para próxima configuração", + "key.xtracr_realcamera.activeConfigIndexPREV": "Mudar para configuração anterior", + "key.xtracr_realcamera.activeConfigIndexRESET": "Redefinir índice de configuração", + "key.xtracr_realcamera.adjustBACK": "Ajustar TRÁS", + "key.xtracr_realcamera.adjustDOWN": "Ajustar PARA BAIXO", + "key.xtracr_realcamera.adjustFRONT": "Ajustar FRENTE", + "key.xtracr_realcamera.adjustLEFT": "Ajustar ESQUERDA", + "key.xtracr_realcamera.adjustRIGHT": "Ajustar DIREITA", + "key.xtracr_realcamera.adjustUP": "Ajustar PARA CIMA", + "key.xtracr_realcamera.modelViewScreen": "Abrir Tela de Visualização de Modelo", + "key.xtracr_realcamera.toggleAdjustMode": "Alternar Modo de Ajuste", + "key.xtracr_realcamera.toggleCameraMode": "Alternar Modo de Câmera", + "key.xtracr_realcamera.togglePerspective": "Ativar/Desativar", "message.xtracr_realcamera.bindingFailed": "[%s]: Vinculação falhou, por favor vá para a tela %s e configure manualmente (Tecla: %s)", - - "screen.xtracr_realcamera.modelView_title": "Visualização de Modelo", - "screen.widget.xtracr_realcamera.modelView_import": "Importar", + "modmenu.descriptionTranslation.realcamera": "Torne a câmera mais realista na visão em primeira pessoa.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Quando desativado, a relação relativa da câmera com o modelo não mudará, mas os atributos correspondentes da câmera não serão modificados por este mod", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurações Salvas", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas as configurações de desativação", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Excluir o retângulo selecionado\n(Ou use a tecla Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Planos onde todas as distâncias vértice-para-tela são menores que este valor não serão renderizados", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Configurações de Desativação\nConfigurações globais de desativação estão na tela de configuração", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "As partes contidas nas caixas azuis serão desativadas\nClique esquerdo para selecionar, outras teclas para cancelar a seleção\n%s+Clique Esquerdo para selecionar rapidamente a parte apontada pelo ponteiro do mouse", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nome da configuração de desativação", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "O nome não pode estar vazio!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "O ID da textura não pode estar vazio!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Exportar configuração atual para a área de transferência", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Falha na exportação: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Exportação bem-sucedida!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Número do Retângulo Focado\n(0 significa nenhuma seleção)\nPressione Espaço ou Enter para localizar o retângulo focado atual (Ao digitar, pressione duas vezes para localizar)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Colar todas as configurações de desativação da área de transferência para a configuração atual\n(Não substituirá configurações existentes com o mesmo nome)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla o tamanho dos deslocamentos", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clique Esquerdo para obter as coordenadas UV no ponteiro do mouse\nOs três conjuntos de coordenadas UV abaixo são, de cima para baixo, as coordenadas UV do vetor de frente, do vetor para cima e do ponto de vinculação no plano alvo\nNota: %s+Rolar para alternar entre as diferentes camadas do modelo. Inserir manualmente as coordenadas UV permite vincular com mais precisão à posição alvo", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina o modo de seleção rápida %s+Clique Esquerdo\n(%s+Rolar para alterar o intervalo de seleção no modo de intervalo)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nome da configuração", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "O ID da textura do modelo selecionado (não precisa ser o ID completo), pode ser encurtado ao salvar para facilitar o reconhecimento.\nPor exemplo, encurte minecraft:textures/entity/player/slim/alex.png para minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir a Tela de Configuração Global\n(Cloth Config API necessário)", + "screen.widget.xtracr_realcamera.modelView_all": "Todos", + "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", + "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", + "screen.widget.xtracr_realcamera.modelView_disable": "Desativar", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo de Desativação", "screen.widget.xtracr_realcamera.modelView_export": "Exportar", - "screen.widget.xtracr_realcamera.modelView_selecting": "Selecionando", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Vetor de Frente", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vetor para Cima", - "screen.widget.xtracr_realcamera.modelView_position": "Plano Alvo", - "screen.widget.xtracr_realcamera.modelView_save": "Salvar", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo de Desativação", - "screen.widget.xtracr_realcamera.modelView_all": "Todos", - "screen.widget.xtracr_realcamera.modelView_part": "Parte", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Modo de Seleção", - "screen.widget.xtracr_realcamera.modelView_single": "Único", + "screen.widget.xtracr_realcamera.modelView_import": "Importar", "screen.widget.xtracr_realcamera.modelView_multiple": "Múltiplo", - "screen.widget.xtracr_realcamera.modelView_range": "Intervalo", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Alternar Deslizante para Campo", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Alternar Campo para Deslizante", "screen.widget.xtracr_realcamera.modelView_offsetX": "Deslocamento X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Deslocamento Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Deslocamento Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Parte", + "screen.widget.xtracr_realcamera.modelView_paste": "Colar", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Desativar", + "screen.widget.xtracr_realcamera.modelView_position": "Plano Alvo", "screen.widget.xtracr_realcamera.modelView_preview": "Pré-visualização", - "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", - "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", - "screen.widget.xtracr_realcamera.modelView_paste": "Colar", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", - "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Exportar configuração atual para a área de transferência", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Exportação bem-sucedida!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Falha na exportação: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clique Esquerdo para obter as coordenadas UV no ponteiro do mouse\nOs três conjuntos de coordenadas UV abaixo são, de cima para baixo, as coordenadas UV do vetor de frente, do vetor para cima e do ponto de vinculação no plano alvo\nNota: %s+Rolar para alternar entre as diferentes camadas do modelo. Inserir manualmente as coordenadas UV permite vincular com mais precisão à posição alvo", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "O ID da textura do modelo selecionado (não precisa ser o ID completo), pode ser encurtado ao salvar para facilitar o reconhecimento.\nPor exemplo, encurte minecraft:textures/entity/player/slim/alex.png para minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "As partes contidas nas caixas azuis serão desativadas\nClique esquerdo para selecionar, outras teclas para cancelar a seleção\n%s+Clique Esquerdo para selecionar rapidamente a parte apontada pelo ponteiro do mouse", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina o modo de seleção rápida %s+Clique Esquerdo\n(%s+Rolar para alterar o intervalo de seleção no modo de intervalo)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Número do Retângulo Focado\n(0 significa nenhuma seleção)\nPressione Espaço ou Enter para localizar o retângulo focado atual (Ao digitar, pressione duas vezes para localizar)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Excluir o retângulo selecionado\n(Ou use a tecla Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Quando desativado, a relação relativa da câmera com o modelo não mudará, mas os atributos correspondentes da câmera não serão modificados por este mod", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla o tamanho dos deslocamentos", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Planos onde todas as distâncias vértice-para-tela são menores que este valor não serão renderizados", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Nome da configuração", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Configurações de Desativação\nConfigurações globais de desativação estão na tela de configuração", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurações Salvas", - "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir a Tela de Configuração Global\n(Cloth Config API necessário)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas as configurações de desativação", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Colar todas as configurações de desativação da área de transferência para a configuração atual\n(Não substituirá configurações existentes com o mesmo nome)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "O nome não pode estar vazio!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "O ID da textura não pode estar vazio!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Nome da configuração de desativação" + "screen.widget.xtracr_realcamera.modelView_range": "Intervalo", + "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Salvar", + "screen.widget.xtracr_realcamera.modelView_selecting": "Selecionando", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Modo de Seleção", + "screen.widget.xtracr_realcamera.modelView_single": "Único", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Alternar Campo para Deslizante", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Alternar Deslizante para Campo", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vetor para Cima", + "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", + "screen.xtracr_realcamera.modelView_title": "Visualização de Modelo" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/ru_ru.json b/common/src/main/resources/assets/realcamera/lang/ru_ru.json index 7b9505af..fb449b6a 100644 --- a/common/src/main/resources/assets/realcamera/lang/ru_ru.json +++ b/common/src/main/resources/assets/realcamera/lang/ru_ru.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Открыть Экран Просмотра Модели", - "key.xtracr_realcamera.togglePerspective": "Включить/Выключить", - "key.xtracr_realcamera.activeConfigIndexPREV": "Переключиться на предыдущую конфигурацию", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Переключиться на следующую конфигурацию", - "key.xtracr_realcamera.activeConfigIndexRESET": "Сбросить индекс конфигурации", - "key.xtracr_realcamera.toggleAdjustMode": "Переключить Режим Настройки", - "key.xtracr_realcamera.toggleCameraMode": "Переключить Режим Камеры", - "key.xtracr_realcamera.adjustUP": "Настроить ВВЕРХ", - "key.xtracr_realcamera.adjustDOWN": "Настроить ВНИЗ", - "key.xtracr_realcamera.adjustFRONT": "Настроить ВПЕРЕД", - "key.xtracr_realcamera.adjustBACK": "Настроить НАЗАД", - "key.xtracr_realcamera.adjustLEFT": "Настроить ВЛЕВО", - "key.xtracr_realcamera.adjustRIGHT": "Настроить ВПРАВО", - "modmenu.descriptionTranslation.realcamera": "Сделать камеру более реалистичной в режиме от первого лица.", - - "config.category.xtracr_realcamera.general": "Основные", "config.category.xtracr_realcamera.binding": "Режим Привязки", - "config.category.xtracr_realcamera.classic": "Классический Режим", "config.category.xtracr_realcamera.cameraOffset": "Смещение Камеры", - "config.category.xtracr_realcamera.centerOffset": "Смещение Центра Вращения", "config.category.xtracr_realcamera.cameraRotation": "Вращение Камеря", - "config.tooltip.xtracr_realcamera.classicOffset": "Смещение камеры от центра вращения", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Примечание: передняя, верхняя и левая стороны игрока соответствуют осям X, Y и Z", - "config.tooltip.xtracr_realcamera.centerOffset": "Смещение центра вращения от головы", - "config.tooltip.xtracr_realcamera.cameraRotation": "Дополнительное вращение камеры в градусах", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Примечание: тангаж, рыскание и крен - это вращения вокруг левой, верхней и передней осей соответственно", - - "config.option.xtracr_realcamera.enabled": "Мод Включен", - "config.option.xtracr_realcamera.isClassic": "Классический Режим", - "config.option.xtracr_realcamera.dynamicCrosshair": "Динамический Прицел", - "config.option.xtracr_realcamera.renderModel": "Отображать Модель Игрока", + "config.category.xtracr_realcamera.centerOffset": "Смещение Центра Вращения", + "config.category.xtracr_realcamera.classic": "Классический Режим", + "config.category.xtracr_realcamera.general": "Основные", + "config.option.xtracr_realcamera.activeConfigIndex": "Активный индекс конфигурации", + "config.option.xtracr_realcamera.adjustOffset": "Настроить Смещение Камеры", "config.option.xtracr_realcamera.adjustStep": "Шаг Настройки", - "config.option.xtracr_realcamera.classicAdjustMode": "Режим Настройки", - "config.option.xtracr_realcamera.scale": "Масштаб", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадры сохранения результата привязки", "config.option.xtracr_realcamera.cameraOffset": "Смещение Камеры %s", "config.option.xtracr_realcamera.centerOffset": "Смещение Центра Вращения %s", - "config.option.xtracr_realcamera.pitch": "Тангаж", - "config.option.xtracr_realcamera.yaw": "Рыскание", - "config.option.xtracr_realcamera.roll": "Крен", - "config.option.xtracr_realcamera.toModelViewScreen": "Для подробных настроек перейдите на экран %s (необходимо назначить клавишу для открытия)", - "config.option.xtracr_realcamera.screenModifierKey": "Клавиша-модификатор экрана %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Режим Устаревшей Привязки", - "config.option.xtracr_realcamera.adjustOffset": "Настроить Смещение Камеры", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Скрывать сообщения о неудачной привязке", - "config.option.xtracr_realcamera.renderStuckObjects": "Отображать Застрявшие Объекты", - "config.option.xtracr_realcamera.rerenderModel": "Перерисовать Модель", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадры сохранения результата привязки", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Коэффициент сглаживания смещения", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Коэффициент сглаживания вращения", - "config.option.xtracr_realcamera.activeConfigIndex": "Активный индекс конфигурации", + "config.option.xtracr_realcamera.classicAdjustMode": "Режим Настройки", "config.option.xtracr_realcamera.disableConfig": "Отключить Конфигурацию", - "config.option.xtracr_realcamera.disableWhenSneaking": "Отключить основную функцию при краже", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Отключить основную функцию при держании...", + "config.option.xtracr_realcamera.disableRenderItems": "Отключить отображение при держании...", "config.option.xtracr_realcamera.disableWhenCrawling": "Отключить основную функцию при ползании", + "config.option.xtracr_realcamera.disableWhenSneaking": "Отключить основную функцию при краже", "config.option.xtracr_realcamera.disableWhenSwimming": "Отключить основную функцию при плавании", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Коэффициент сглаживания смещения", + "config.option.xtracr_realcamera.dynamicCrosshair": "Динамический Прицел", + "config.option.xtracr_realcamera.enabled": "Мод Включен", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Скрывать сообщения о неудачной привязке", + "config.option.xtracr_realcamera.isClassic": "Классический Режим", + "config.option.xtracr_realcamera.legacyBindingMode": "Режим Устаревшей Привязки", "config.option.xtracr_realcamera.outTick": "Задержка выхода из состояния плавания (в тиках)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Отключить основную функцию при держании...", - "config.option.xtracr_realcamera.disableRenderItems": "Отключить отображение при держании...", - "config.tooltip.xtracr_realcamera.isClassic": "Классический режим вносит только простые изменения в положение и вращение камеры", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "При включении прицел будет следовать за взглядом игрока, обеспечивая точное попадание\nРекомендуется включить при установке Jade, WTHIT или подобных модов", - "config.tooltip.xtracr_realcamera.renderModel": "Отображать модель игрока в режиме от первого лица", + "config.option.xtracr_realcamera.pitch": "Тангаж", + "config.option.xtracr_realcamera.renderModel": "Отображать Модель Игрока", + "config.option.xtracr_realcamera.renderStuckObjects": "Отображать Застрявшие Объекты", + "config.option.xtracr_realcamera.rerenderModel": "Перерисовать Модель", + "config.option.xtracr_realcamera.roll": "Крен", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Коэффициент сглаживания вращения", + "config.option.xtracr_realcamera.scale": "Масштаб", + "config.option.xtracr_realcamera.screenModifierKey": "Клавиша-модификатор экрана %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Для подробных настроек перейдите на экран %s (необходимо назначить клавишу для открытия)", + "config.option.xtracr_realcamera.yaw": "Рыскание", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Текущий индекс привязанной конфигурации, 0 означает разрешение привязки к любой допустимой конфигурации", + "config.tooltip.xtracr_realcamera.adjustOffset": "При нажатии клавиши настройки, регулировать смещение или вращение камеры", "config.tooltip.xtracr_realcamera.adjustStep": "Длина или 1/100 угла настройки за шаг", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "В течение нескольких кадров после неудачной привязки продолжать использовать предыдущий успешный результат привязки", + "config.tooltip.xtracr_realcamera.cameraRotation": "Дополнительное вращение камеры в градусах", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Примечание: тангаж, рыскание и крен - это вращения вокруг левой, верхней и передней осей соответственно", + "config.tooltip.xtracr_realcamera.centerOffset": "Смещение центра вращения от головы", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Определяет, что настраивать при нажатии клавиши настройки", - "config.tooltip.xtracr_realcamera.scale": "Контролировать размер смещений", + "config.tooltip.xtracr_realcamera.classicOffset": "Смещение камеры от центра вращения", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Примечание: передняя, верхняя и левая стороны игрока соответствуют осям X, Y и Z", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Поддерживаются три метода сопоставления:\n1. Сопоставление с подстановочным знаком `*` (например, `minecraft:*sword`)\n2. Сопоставление по тегам (начинается с `#`, например, `#minecraft:swords`)\n3. Прямой ID предмета (например, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Коэффициент сглаживания смещения камеры, чем выше значение, тем плавнее движение", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "При включении прицел будет следовать за взглядом игрока, обеспечивая точное попадание\nРекомендуется включить при установке Jade, WTHIT или подобных модов", + "config.tooltip.xtracr_realcamera.isClassic": "Классический режим вносит только простые изменения в положение и вращение камеры", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Использует режим привязки устаревшей версии (v0.5), поддерживаются только стандартные модели и действия на их основе\nПосле включения свойства можно настроить в 'LEGACY_MODE' экрана %s", - "config.tooltip.xtracr_realcamera.adjustOffset": "При нажатии клавиши настройки, регулировать смещение или вращение камеры", + "config.tooltip.xtracr_realcamera.outTick": "Время перед включением основной функции после выхода из состояния плавания (1 тик = 0.05с)", + "config.tooltip.xtracr_realcamera.renderModel": "Отображать модель игрока в режиме от первого лица", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Стрелы, жала пчел и другие объекты, которые могут застрять в теле игрока", "config.tooltip.xtracr_realcamera.rerenderModel": "Перерисовывать модель в исходное время рендеринга, чтобы избежать визуальных проблем, вызванных ранним рендерингом", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "В течение нескольких кадров после неудачной привязки продолжать использовать предыдущий успешный результат привязки", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Коэффициент сглаживания смещения камеры, чем выше значение, тем плавнее движение", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Коэффициент сглаживания вращения камеры, чем выше значение, тем плавнее движение", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Текущий индекс привязанной конфигурации, 0 означает разрешение привязки к любой допустимой конфигурации", - "config.tooltip.xtracr_realcamera.outTick": "Время перед включением основной функции после выхода из состояния плавания (1 тик = 0.05с)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Поддерживаются три метода сопоставления:\n1. Сопоставление с подстановочным знаком `*` (например, `minecraft:*sword`)\n2. Сопоставление по тегам (начинается с `#`, например, `#minecraft:swords`)\n3. Прямой ID предмета (например, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Контролировать размер смещений", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Переключиться на следующую конфигурацию", + "key.xtracr_realcamera.activeConfigIndexPREV": "Переключиться на предыдущую конфигурацию", + "key.xtracr_realcamera.activeConfigIndexRESET": "Сбросить индекс конфигурации", + "key.xtracr_realcamera.adjustBACK": "Настроить НАЗАД", + "key.xtracr_realcamera.adjustDOWN": "Настроить ВНИЗ", + "key.xtracr_realcamera.adjustFRONT": "Настроить ВПЕРЕД", + "key.xtracr_realcamera.adjustLEFT": "Настроить ВЛЕВО", + "key.xtracr_realcamera.adjustRIGHT": "Настроить ВПРАВО", + "key.xtracr_realcamera.adjustUP": "Настроить ВВЕРХ", + "key.xtracr_realcamera.modelViewScreen": "Открыть Экран Просмотра Модели", + "key.xtracr_realcamera.toggleAdjustMode": "Переключить Режим Настройки", + "key.xtracr_realcamera.toggleCameraMode": "Переключить Режим Камеры", + "key.xtracr_realcamera.togglePerspective": "Включить/Выключить", "message.xtracr_realcamera.bindingFailed": "[%s]: Ошибка привязки, пожалуйста, перейдите на экран %s и настройте вручную (Клавиша: %s)", - - "screen.xtracr_realcamera.modelView_title": "Просмотр Модели", - "screen.widget.xtracr_realcamera.modelView_import": "Импорт", + "modmenu.descriptionTranslation.realcamera": "Сделать камеру более реалистичной в режиме от первого лица.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "При отключении относительное положение камеры к модели не изменится, но соответствующие атрибуты камеры не будут изменены этим модом", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Сохраненные конфигурации", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Копировать все настройки отключения", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Удалить выбранный прямоугольник\n(Или используйте клавишу Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскости, где все расстояния от вершины до экрана меньше этого значения, не будут отображаться", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Настройки отключения\nГлобальные настройки отключения находятся на экране конфигурации", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Части, содержащиеся в синих рамках, будут отключены\nЛевый клик для выбора, другие клавиши для отмены выбора\n%s+Левый клик для быстрого выбора части, на которую указывает курсор мыши", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Имя настройки отключения", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Имя не может быть пустым!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Идентификатор текстуры не может быть пустым!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Экспортировать текущую конфигурацию в буфер обмена", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Ошибка экспорта: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Экспорт успешен!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Номер выделенного прямоугольника\n(0 означает отсутствие выбора)\nНажмите Пробел или Enter чтобы найти текущий выделенный прямоугольник (При вводе нажмите дважды чтобы найти)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Импортировать конфигурацию из буфера обмена", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Ошибка импорта: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Импорт %s успешен!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Вставить все настройки отключения из буфера обмена в текущую конфигурацию\n(Не перезапишет существующие настройки с тем же именем)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "В режиме предпросмотра вы можете настроить смещение и вращение камеры", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Приоритет при привязке: чем больше значение, тем выше приоритет и выше сортировка на правой стороне", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Сохранить как\n(При наличии настройки с тем же именем вы также можете использовать кнопку сохранения слева)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Масштаб, который контролирует размер смещений", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Левый клик чтобы получить UV-координаты в месте указателя мыши\nТри набора UV-координат ниже, сверху вниз, это UV-координаты вектора направления, вектора вверх и точки привязки на целевой плоскости\nПримечание: %s+Прокрутка для переключения между различными слоями модели. Ручной ввод UV-координат позволяет более точно привязаться к целевой позиции", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Определяет режим быстрого выбора %s+Левый клик\n(%s+Прокрутка для изменения диапазона выбора в режиме диапазона)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Имя конфигурации", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "Идентификатор текстуры выбранной модели (не обязательно полный идентификатор), может быть сокращен при сохранении для удобства распознавания.\nНапример, сократите minecraft:textures/entity/player/slim/alex.png до minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Открыть глобальный экран конфигурации\n(Требуется Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "Все", + "screen.widget.xtracr_realcamera.modelView_configs": "Конфигурации", + "screen.widget.xtracr_realcamera.modelView_copy": "Копировать", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Текущая Конфигурация", + "screen.widget.xtracr_realcamera.modelView_disable": "Отключить", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Режим отключения", "screen.widget.xtracr_realcamera.modelView_export": "Экспорт", - "screen.widget.xtracr_realcamera.modelView_selecting": "Выбор", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Вектор направления", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектор вверх", - "screen.widget.xtracr_realcamera.modelView_position": "Целевая плоскость", - "screen.widget.xtracr_realcamera.modelView_save": "Сохранить", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Режим отключения", - "screen.widget.xtracr_realcamera.modelView_all": "Все", - "screen.widget.xtracr_realcamera.modelView_part": "Часть", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Режим выбора", - "screen.widget.xtracr_realcamera.modelView_single": "Одиночный", + "screen.widget.xtracr_realcamera.modelView_import": "Импорт", "screen.widget.xtracr_realcamera.modelView_multiple": "Множественный", - "screen.widget.xtracr_realcamera.modelView_range": "Диапазон", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Переключить ползунок в поле", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Переключить поле в ползунок", "screen.widget.xtracr_realcamera.modelView_offsetX": "Смещение X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Смещение Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Смещение Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Часть", + "screen.widget.xtracr_realcamera.modelView_paste": "Вставить", "screen.widget.xtracr_realcamera.modelView_pitch": "Тангаж = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Рыскание = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Крен = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Отключить", + "screen.widget.xtracr_realcamera.modelView_position": "Целевая плоскость", "screen.widget.xtracr_realcamera.modelView_preview": "Предпросмотр", - "screen.widget.xtracr_realcamera.modelView_configs": "Конфигурации", - "screen.widget.xtracr_realcamera.modelView_copy": "Копировать", - "screen.widget.xtracr_realcamera.modelView_paste": "Вставить", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Текущая Конфигурация", - "screen.tooltip.xtracr_realcamera.modelView_import": "Импортировать конфигурацию из буфера обмена", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Импорт %s успешен!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Ошибка импорта: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Экспортировать текущую конфигурацию в буфер обмена", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Экспорт успешен!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Ошибка экспорта: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Левый клик чтобы получить UV-координаты в месте указателя мыши\nТри набора UV-координат ниже, сверху вниз, это UV-координаты вектора направления, вектора вверх и точки привязки на целевой плоскости\nПримечание: %s+Прокрутка для переключения между различными слоями модели. Ручной ввод UV-координат позволяет более точно привязаться к целевой позиции", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "Идентификатор текстуры выбранной модели (не обязательно полный идентификатор), может быть сокращен при сохранении для удобства распознавания.\nНапример, сократите minecraft:textures/entity/player/slim/alex.png до minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Части, содержащиеся в синих рамках, будут отключены\nЛевый клик для выбора, другие клавиши для отмены выбора\n%s+Левый клик для быстрого выбора части, на которую указывает курсор мыши", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Определяет режим быстрого выбора %s+Левый клик\n(%s+Прокрутка для изменения диапазона выбора в режиме диапазона)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Номер выделенного прямоугольника\n(0 означает отсутствие выбора)\nНажмите Пробел или Enter чтобы найти текущий выделенный прямоугольник (При вводе нажмите дважды чтобы найти)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Удалить выбранный прямоугольник\n(Или используйте клавишу Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "При отключении относительное положение камеры к модели не изменится, но соответствующие атрибуты камеры не будут изменены этим модом", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Масштаб, который контролирует размер смещений", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскости, где все расстояния от вершины до экрана меньше этого значения, не будут отображаться", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Приоритет при привязке: чем больше значение, тем выше приоритет и выше сортировка на правой стороне", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Имя конфигурации", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Настройки отключения\nГлобальные настройки отключения находятся на экране конфигурации", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Сохраненные конфигурации", - "screen.tooltip.xtracr_realcamera.modelView_preview": "В режиме предпросмотра вы можете настроить смещение и вращение камеры", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Открыть глобальный экран конфигурации\n(Требуется Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Копировать все настройки отключения", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Вставить все настройки отключения из буфера обмена в текущую конфигурацию\n(Не перезапишет существующие настройки с тем же именем)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Имя не может быть пустым!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Идентификатор текстуры не может быть пустым!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Сохранить как\n(При наличии настройки с тем же именем вы также можете использовать кнопку сохранения слева)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Имя настройки отключения" + "screen.widget.xtracr_realcamera.modelView_range": "Диапазон", + "screen.widget.xtracr_realcamera.modelView_roll": "Крен = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Сохранить", + "screen.widget.xtracr_realcamera.modelView_selecting": "Выбор", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Режим выбора", + "screen.widget.xtracr_realcamera.modelView_single": "Одиночный", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Переключить поле в ползунок", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Переключить ползунок в поле", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектор вверх", + "screen.widget.xtracr_realcamera.modelView_yaw": "Рыскание = %s", + "screen.xtracr_realcamera.modelView_title": "Просмотр Модели" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/tr_tr.json b/common/src/main/resources/assets/realcamera/lang/tr_tr.json index 79eb9211..4fec1c17 100644 --- a/common/src/main/resources/assets/realcamera/lang/tr_tr.json +++ b/common/src/main/resources/assets/realcamera/lang/tr_tr.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Model Görünüm Ekranını Aç", - "key.xtracr_realcamera.togglePerspective": "Etkinleştir/Devre Dışı Bırak", - "key.xtracr_realcamera.activeConfigIndexPREV": "Önceki yapılandırmaya geç", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Sonraki yapılandırmaya geç", - "key.xtracr_realcamera.activeConfigIndexRESET": "Yapılandırma indeksini sıfırla", - "key.xtracr_realcamera.toggleAdjustMode": "Ayarlama Modunu Değiştir", - "key.xtracr_realcamera.toggleCameraMode": "Kamera Modunu Değiştir", - "key.xtracr_realcamera.adjustUP": "YUKARI Ayarla", - "key.xtracr_realcamera.adjustDOWN": "AŞAĞI Ayarla", - "key.xtracr_realcamera.adjustFRONT": "ÖNE Ayarla", - "key.xtracr_realcamera.adjustBACK": "ARKAYA Ayarla", - "key.xtracr_realcamera.adjustLEFT": "SOLA Ayarla", - "key.xtracr_realcamera.adjustRIGHT": "SAĞA Ayarla", - "modmenu.descriptionTranslation.realcamera": "Birinci şahıs görünümünde kamerayı daha gerçekçi hale getirir.", - - "config.category.xtracr_realcamera.general": "Genel", "config.category.xtracr_realcamera.binding": "Bağlama Modu", - "config.category.xtracr_realcamera.classic": "Klasik Mod", "config.category.xtracr_realcamera.cameraOffset": "Kamera Ofseti", - "config.category.xtracr_realcamera.centerOffset": "Dönüş Merkezi Ofseti", "config.category.xtracr_realcamera.cameraRotation": "Kamera Dönüşü", - "config.tooltip.xtracr_realcamera.classicOffset": "Kameranın dönüş merkezinden ofseti", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Not: oyuncunun ön, üst ve sol tarafı sırasıyla X, Y ve Z eksenleridir", - "config.tooltip.xtracr_realcamera.centerOffset": "Dönüş merkezinin baştan ofseti", - "config.tooltip.xtracr_realcamera.cameraRotation": "Derece cinsinden ek kamera dönüşü", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Not: Pitch, yaw ve roll sırasıyla sol, üst ve ön eksenlerdeki dönüşlerdir", - - "config.option.xtracr_realcamera.enabled": "Mod Etkin", - "config.option.xtracr_realcamera.isClassic": "Klasik Mod", - "config.option.xtracr_realcamera.dynamicCrosshair": "Dinamik Nişangah", - "config.option.xtracr_realcamera.renderModel": "Oyuncu Modelini Renderla", + "config.category.xtracr_realcamera.centerOffset": "Dönüş Merkezi Ofseti", + "config.category.xtracr_realcamera.classic": "Klasik Mod", + "config.category.xtracr_realcamera.general": "Genel", + "config.option.xtracr_realcamera.activeConfigIndex": "Aktif Yapılandırma İndeksi", + "config.option.xtracr_realcamera.adjustOffset": "Kamera Ofsetini Ayarla", "config.option.xtracr_realcamera.adjustStep": "Ayarlama Adımı", - "config.option.xtracr_realcamera.classicAdjustMode": "Ayarlama Modu", - "config.option.xtracr_realcamera.scale": "Ölçek", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bağlama Sonucu Saklama Kareleri", "config.option.xtracr_realcamera.cameraOffset": "Kamera %s Ofseti", "config.option.xtracr_realcamera.centerOffset": "Dönüş Merkezi %s Ofseti", - "config.option.xtracr_realcamera.pitch": "Pitch", - "config.option.xtracr_realcamera.yaw": "Yaw", - "config.option.xtracr_realcamera.roll": "Roll", - "config.option.xtracr_realcamera.toModelViewScreen": "Detaylı ayarlar için lütfen %s ekranına gidin (açmak için tuş ataması yapılmalıdır)", - "config.option.xtracr_realcamera.screenModifierKey": "%s Ekranı Değiştirici Tuşu", - "config.option.xtracr_realcamera.legacyBindingMode": "Eski Bağlama Modu", - "config.option.xtracr_realcamera.adjustOffset": "Kamera Ofsetini Ayarla", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Bağlama Başarısız Mesajını Gizle", - "config.option.xtracr_realcamera.renderStuckObjects": "Sıkışmış Nesneleri Renderla", - "config.option.xtracr_realcamera.rerenderModel": "Modeli Yeniden Renderla", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Bağlama Sonucu Saklama Kareleri", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Yer Değiştirme Düzgünleştirme Faktörü", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Dönüş Düzgünleştirme Faktörü", - "config.option.xtracr_realcamera.activeConfigIndex": "Aktif Yapılandırma İndeksi", + "config.option.xtracr_realcamera.classicAdjustMode": "Ayarlama Modu", "config.option.xtracr_realcamera.disableConfig": "Yapılandırmayı Devre Dışı Bırak", - "config.option.xtracr_realcamera.disableWhenSneaking": "Eğilirken ana özelliği devre dışı bırak", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Tutarken ana özelliği devre dışı bırak...", + "config.option.xtracr_realcamera.disableRenderItems": "Tutarken renderlamayı devre dışı bırak...", "config.option.xtracr_realcamera.disableWhenCrawling": "Sürünürken ana özelliği devre dışı bırak", + "config.option.xtracr_realcamera.disableWhenSneaking": "Eğilirken ana özelliği devre dışı bırak", "config.option.xtracr_realcamera.disableWhenSwimming": "Yüzerken ana özelliği devre dışı bırak", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Yer Değiştirme Düzgünleştirme Faktörü", + "config.option.xtracr_realcamera.dynamicCrosshair": "Dinamik Nişangah", + "config.option.xtracr_realcamera.enabled": "Mod Etkin", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Bağlama Başarısız Mesajını Gizle", + "config.option.xtracr_realcamera.isClassic": "Klasik Mod", + "config.option.xtracr_realcamera.legacyBindingMode": "Eski Bağlama Modu", "config.option.xtracr_realcamera.outTick": "Yüzme durumundan çıkma gecikmesi (tik cinsinden)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Tutarken ana özelliği devre dışı bırak...", - "config.option.xtracr_realcamera.disableRenderItems": "Tutarken renderlamayı devre dışı bırak...", - "config.tooltip.xtracr_realcamera.isClassic": "Klasik mod yalnızca kameranın konumuna ve dönüşüne basit değişiklikler yapar", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Etkinleştirildiğinde, nişangah oyuncunun görüşünü takip ederek tutarlı vuruş sonuçları sağlar\nJade, WTHIT veya benzeri modlar yüklüyken etkinleştirilmesi önerilir", - "config.tooltip.xtracr_realcamera.renderModel": "Birinci şahıs perspektifinde oyuncu modelini renderla", + "config.option.xtracr_realcamera.pitch": "Pitch", + "config.option.xtracr_realcamera.renderModel": "Oyuncu Modelini Renderla", + "config.option.xtracr_realcamera.renderStuckObjects": "Sıkışmış Nesneleri Renderla", + "config.option.xtracr_realcamera.rerenderModel": "Modeli Yeniden Renderla", + "config.option.xtracr_realcamera.roll": "Roll", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Dönüş Düzgünleştirme Faktörü", + "config.option.xtracr_realcamera.scale": "Ölçek", + "config.option.xtracr_realcamera.screenModifierKey": "%s Ekranı Değiştirici Tuşu", + "config.option.xtracr_realcamera.toModelViewScreen": "Detaylı ayarlar için lütfen %s ekranına gidin (açmak için tuş ataması yapılmalıdır)", + "config.option.xtracr_realcamera.yaw": "Yaw", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Şu anda bağlı yapılandırma indeksi, 0 herhangi bir geçerli yapılandırmaya bağlanmaya izin verir", + "config.tooltip.xtracr_realcamera.adjustOffset": "Ayarlama tuşuna basıldığında, kameranın ofsetini veya dönüşünü ayarlar", "config.tooltip.xtracr_realcamera.adjustStep": "Ayarlama başına adım uzunluğu veya açının 1/100'ü", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Bağlama başarısızlığından sonraki birkaç kare boyunca önceki başarılı bağlama sonucunu kullanmaya devam edin", + "config.tooltip.xtracr_realcamera.cameraRotation": "Derece cinsinden ek kamera dönüşü", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Not: Pitch, yaw ve roll sırasıyla sol, üst ve ön eksenlerdeki dönüşlerdir", + "config.tooltip.xtracr_realcamera.centerOffset": "Dönüş merkezinin baştan ofseti", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Ayarlama tuşuna basıldığında neyin ayarlanacağını belirler", - "config.tooltip.xtracr_realcamera.scale": "Ofsetlerin boyutunu kontrol eder", + "config.tooltip.xtracr_realcamera.classicOffset": "Kameranın dönüş merkezinden ofseti", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Not: oyuncunun ön, üst ve sol tarafı sırasıyla X, Y ve Z eksenleridir", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Üç eşleştirme yöntemi desteklenir:\n1. Joker karakter `*` eşleştirmesi (örneğin, `minecraft:*sword`)\n2. Etiket eşleştirmesi (`#` ile başlar, örneğin `#minecraft:swords`)\n3. Doğrudan öğe kimliği (örneğin, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Kamera yer değiştirme düzgünleştirme faktörü, değer ne kadar yüksekse hareket o kadar pürüzsüz olur", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "Etkinleştirildiğinde, nişangah oyuncunun görüşünü takip ederek tutarlı vuruş sonuçları sağlar\nJade, WTHIT veya benzeri modlar yüklüyken etkinleştirilmesi önerilir", + "config.tooltip.xtracr_realcamera.isClassic": "Klasik mod yalnızca kameranın konumuna ve dönüşüne basit değişiklikler yapar", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Eski sürümün (v0.5) bağlama modu kullanılarak, yalnızca vanilla model ve vanilla model temelli eylemler desteklenir\nÖzellikleri, etkinleştirildiğinde %s ekranının 'LEGACY_MODE' bölümünde ayarlanabilir", - "config.tooltip.xtracr_realcamera.adjustOffset": "Ayarlama tuşuna basıldığında, kameranın ofsetini veya dönüşünü ayarlar", + "config.tooltip.xtracr_realcamera.outTick": "Yüzme durumundan çıktıktan sonra ana özelliği etkinleştirmeden önce geçen süre (1 tik = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "Birinci şahıs perspektifinde oyuncu modelini renderla", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Oyuncunun vücuduna saplanabilen oklar, arı sokmaları ve diğer nesneler", "config.tooltip.xtracr_realcamera.rerenderModel": "Modeli orijinal render zamanında yeniden renderlayarak erken renderlamadan kaynaklanan görsel sorunları önler", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Bağlama başarısızlığından sonraki birkaç kare boyunca önceki başarılı bağlama sonucunu kullanmaya devam edin", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Kamera yer değiştirme düzgünleştirme faktörü, değer ne kadar yüksekse hareket o kadar pürüzsüz olur", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Kamera dönüş düzgünleştirme faktörü, değer ne kadar yüksekse hareket o kadar pürüzsüz olur", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Şu anda bağlı yapılandırma indeksi, 0 herhangi bir geçerli yapılandırmaya bağlanmaya izin verir", - "config.tooltip.xtracr_realcamera.outTick": "Yüzme durumundan çıktıktan sonra ana özelliği etkinleştirmeden önce geçen süre (1 tik = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Üç eşleştirme yöntemi desteklenir:\n1. Joker karakter `*` eşleştirmesi (örneğin, `minecraft:*sword`)\n2. Etiket eşleştirmesi (`#` ile başlar, örneğin `#minecraft:swords`)\n3. Doğrudan öğe kimliği (örneğin, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Ofsetlerin boyutunu kontrol eder", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Sonraki yapılandırmaya geç", + "key.xtracr_realcamera.activeConfigIndexPREV": "Önceki yapılandırmaya geç", + "key.xtracr_realcamera.activeConfigIndexRESET": "Yapılandırma indeksini sıfırla", + "key.xtracr_realcamera.adjustBACK": "ARKAYA Ayarla", + "key.xtracr_realcamera.adjustDOWN": "AŞAĞI Ayarla", + "key.xtracr_realcamera.adjustFRONT": "ÖNE Ayarla", + "key.xtracr_realcamera.adjustLEFT": "SOLA Ayarla", + "key.xtracr_realcamera.adjustRIGHT": "SAĞA Ayarla", + "key.xtracr_realcamera.adjustUP": "YUKARI Ayarla", + "key.xtracr_realcamera.modelViewScreen": "Model Görünüm Ekranını Aç", + "key.xtracr_realcamera.toggleAdjustMode": "Ayarlama Modunu Değiştir", + "key.xtracr_realcamera.toggleCameraMode": "Kamera Modunu Değiştir", + "key.xtracr_realcamera.togglePerspective": "Etkinleştir/Devre Dışı Bırak", "message.xtracr_realcamera.bindingFailed": "[%s]: Bağlama başarısız oldu, lütfen %s ekranına gidin ve manuel olarak yapılandırın (Tuş: %s)", - - "screen.xtracr_realcamera.modelView_title": "Model Görünümü", - "screen.widget.xtracr_realcamera.modelView_import": "İçe Aktar", + "modmenu.descriptionTranslation.realcamera": "Birinci şahıs görünümünde kamerayı daha gerçekçi hale getirir.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Devre dışı bırakıldığında, kameranın modele göre göreceli ilişkisi değişmeyecek, ancak kameranın ilgili özellikleri bu mod tarafından değiştirilmeyecektir", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Kayıtlı Yapılandırmalar", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Tüm devre dışı bırakma ayarlarını kopyala", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Seçili dikdörtgeni sil\n(Veya Sil tuşunu kullanın)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Tüm köşe-ekran mesafelerinin bu değerden küçük olduğu düzlemler render edilmeyecektir", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Devre Dışı Bırakma Ayarları\nGenel devre dışı bırakma ayarları ayarlar ekranındadır", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Mavi kutuların içindeki parçalar devre dışı bırakılacak\nSol tıkla seçin, diğer tuşlarla seçimi iptal edin\n%s+Sol Tık ile fare işaretçisinin gösterdiği parçayı hızlıca seçin", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Devre dışı bırakma ayarının adı", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "İsim boş olamaz!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Doku kimliği boş olamaz!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Mevcut yapılandırmayı panoya dışa aktar", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Dışa aktarma başarısız: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Dışa aktarma başarılı!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Odaklanan Dikdörtgen Numarası\n(0 seçim olmadığı anlamına gelir)\nMevcut odaklanan dikdörtgeni bulmak için Boşluk veya Enter'a basın (Yazarken, bulmak için iki kez basın)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Panodan yapılandırmayı içe aktar", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "İçe aktarma başarısız: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s içe aktarma başarılı!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Panodaki tüm devre dışı bırakma ayarlarını mevcut yapılandırmaya yapıştır\n(Aynı isimdeki mevcut ayarların üzerine yazılmaz)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "Önizleme modunda kameranın çeşitli ofsetlerini ayarlayabilirsiniz", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Bağlama önceliği, değer ne kadar büyükse öncelik o kadar yüksektir ve sağ taraftaki sıralama da o kadar yukarıdadır", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Farklı Kaydet\n(Aynı isimde bir ayar olduğunda, soldaki kaydet düğmesini de kullanabilirsiniz)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Ölçek, ofsetlerin boyutunu kontrol eder", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Sol Tık ile fare işaretçisindeki UV koordinatlarını alın\nAşağıdaki üç UV koordinat seti, yukarıdan aşağıya doğru, ileri vektör, yukarı vektör ve hedef düzlemdeki bağlama noktasının UV koordinatlarıdır\nNot: %s+Kaydırma ile modelin farklı katmanları arasında geçiş yapabilirsiniz. UV koordinatlarını manuel olarak girerek hedef konuma daha hassas bir şekilde bağlanabilirsiniz", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+Sol Tık hızlı seçim modunu belirler\n(%s+Kaydırma ile aralık modundaki seçim aralığını değiştirin)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Yapılandırmanın adı", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "Seçilen modelin doku kimliği (tam kimlik olması gerekmez), kaydederken tanınmasını kolaylaştırmak için kısaltılabilir.\nÖrneğin, minecraft:textures/entity/player/slim/alex.png dosyasını minecraft:textures/entity/player/ olarak kısaltabilirsiniz.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Genel Yapılandırma Ekranını Aç\n(Cloth Config API gerekli)", + "screen.widget.xtracr_realcamera.modelView_all": "Tümü", + "screen.widget.xtracr_realcamera.modelView_configs": "Yapılandırmalar", + "screen.widget.xtracr_realcamera.modelView_copy": "Kopyala", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Mevcut Yapılandırma", + "screen.widget.xtracr_realcamera.modelView_disable": "Devre Dışı Bırak", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Devre Dışı Bırakma Modu", "screen.widget.xtracr_realcamera.modelView_export": "Dışa Aktar", - "screen.widget.xtracr_realcamera.modelView_selecting": "Seçim", "screen.widget.xtracr_realcamera.modelView_forwardVector": "İleri Vektörü", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Yukarı Vektörü", - "screen.widget.xtracr_realcamera.modelView_position": "Hedef Düzlem", - "screen.widget.xtracr_realcamera.modelView_save": "Kaydet", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Devre Dışı Bırakma Modu", - "screen.widget.xtracr_realcamera.modelView_all": "Tümü", - "screen.widget.xtracr_realcamera.modelView_part": "Parça", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Seçim Modu", - "screen.widget.xtracr_realcamera.modelView_single": "Tekli", + "screen.widget.xtracr_realcamera.modelView_import": "İçe Aktar", "screen.widget.xtracr_realcamera.modelView_multiple": "Çoklu", - "screen.widget.xtracr_realcamera.modelView_range": "Aralık", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Kaydırıcıdan Alana Geç", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Alandan Kaydırıcıya Geç", "screen.widget.xtracr_realcamera.modelView_offsetX": "X Ofseti = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y Ofseti = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z Ofseti = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Parça", + "screen.widget.xtracr_realcamera.modelView_paste": "Yapıştır", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Devre Dışı Bırak", + "screen.widget.xtracr_realcamera.modelView_position": "Hedef Düzlem", "screen.widget.xtracr_realcamera.modelView_preview": "Önizleme", - "screen.widget.xtracr_realcamera.modelView_configs": "Yapılandırmalar", - "screen.widget.xtracr_realcamera.modelView_copy": "Kopyala", - "screen.widget.xtracr_realcamera.modelView_paste": "Yapıştır", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Mevcut Yapılandırma", - "screen.tooltip.xtracr_realcamera.modelView_import": "Panodan yapılandırmayı içe aktar", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s içe aktarma başarılı!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "İçe aktarma başarısız: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Mevcut yapılandırmayı panoya dışa aktar", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Dışa aktarma başarılı!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Dışa aktarma başarısız: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Sol Tık ile fare işaretçisindeki UV koordinatlarını alın\nAşağıdaki üç UV koordinat seti, yukarıdan aşağıya doğru, ileri vektör, yukarı vektör ve hedef düzlemdeki bağlama noktasının UV koordinatlarıdır\nNot: %s+Kaydırma ile modelin farklı katmanları arasında geçiş yapabilirsiniz. UV koordinatlarını manuel olarak girerek hedef konuma daha hassas bir şekilde bağlanabilirsiniz", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "Seçilen modelin doku kimliği (tam kimlik olması gerekmez), kaydederken tanınmasını kolaylaştırmak için kısaltılabilir.\nÖrneğin, minecraft:textures/entity/player/slim/alex.png dosyasını minecraft:textures/entity/player/ olarak kısaltabilirsiniz.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Mavi kutuların içindeki parçalar devre dışı bırakılacak\nSol tıkla seçin, diğer tuşlarla seçimi iptal edin\n%s+Sol Tık ile fare işaretçisinin gösterdiği parçayı hızlıca seçin", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+Sol Tık hızlı seçim modunu belirler\n(%s+Kaydırma ile aralık modundaki seçim aralığını değiştirin)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Odaklanan Dikdörtgen Numarası\n(0 seçim olmadığı anlamına gelir)\nMevcut odaklanan dikdörtgeni bulmak için Boşluk veya Enter'a basın (Yazarken, bulmak için iki kez basın)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Seçili dikdörtgeni sil\n(Veya Sil tuşunu kullanın)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Devre dışı bırakıldığında, kameranın modele göre göreceli ilişkisi değişmeyecek, ancak kameranın ilgili özellikleri bu mod tarafından değiştirilmeyecektir", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Ölçek, ofsetlerin boyutunu kontrol eder", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Tüm köşe-ekran mesafelerinin bu değerden küçük olduğu düzlemler render edilmeyecektir", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Bağlama önceliği, değer ne kadar büyükse öncelik o kadar yüksektir ve sağ taraftaki sıralama da o kadar yukarıdadır", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Yapılandırmanın adı", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Devre Dışı Bırakma Ayarları\nGenel devre dışı bırakma ayarları ayarlar ekranındadır", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Kayıtlı Yapılandırmalar", - "screen.tooltip.xtracr_realcamera.modelView_preview": "Önizleme modunda kameranın çeşitli ofsetlerini ayarlayabilirsiniz", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Genel Yapılandırma Ekranını Aç\n(Cloth Config API gerekli)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Tüm devre dışı bırakma ayarlarını kopyala", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Panodaki tüm devre dışı bırakma ayarlarını mevcut yapılandırmaya yapıştır\n(Aynı isimdeki mevcut ayarların üzerine yazılmaz)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "İsim boş olamaz!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Doku kimliği boş olamaz!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Farklı Kaydet\n(Aynı isimde bir ayar olduğunda, soldaki kaydet düğmesini de kullanabilirsiniz)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Devre dışı bırakma ayarının adı" + "screen.widget.xtracr_realcamera.modelView_range": "Aralık", + "screen.widget.xtracr_realcamera.modelView_roll": "Roll = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Kaydet", + "screen.widget.xtracr_realcamera.modelView_selecting": "Seçim", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Seçim Modu", + "screen.widget.xtracr_realcamera.modelView_single": "Tekli", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Alandan Kaydırıcıya Geç", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Kaydırıcıdan Alana Geç", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Yukarı Vektörü", + "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", + "screen.xtracr_realcamera.modelView_title": "Model Görünümü" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/uk_ua.json b/common/src/main/resources/assets/realcamera/lang/uk_ua.json index 764b0716..aa48b777 100644 --- a/common/src/main/resources/assets/realcamera/lang/uk_ua.json +++ b/common/src/main/resources/assets/realcamera/lang/uk_ua.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "Відкрити Екран Перегляду Моделі", - "key.xtracr_realcamera.togglePerspective": "Увімкнути/Вимкнути", - "key.xtracr_realcamera.activeConfigIndexPREV": "Переключитися на попередню конфігурацію", - "key.xtracr_realcamera.activeConfigIndexNEXT": "Переключитися на наступну конфігурацію", - "key.xtracr_realcamera.activeConfigIndexRESET": "Скинути індекс конфігурації", - "key.xtracr_realcamera.toggleAdjustMode": "Переключити Режим Налаштування", - "key.xtracr_realcamera.toggleCameraMode": "Переключити Режим Камери", - "key.xtracr_realcamera.adjustUP": "Налаштувати ВГОРУ", - "key.xtracr_realcamera.adjustDOWN": "Налаштувати ВНИЗ", - "key.xtracr_realcamera.adjustFRONT": "Налаштувати ВПЕРЕД", - "key.xtracr_realcamera.adjustBACK": "Налаштувати НАЗАД", - "key.xtracr_realcamera.adjustLEFT": "Налаштувати ВЛІВО", - "key.xtracr_realcamera.adjustRIGHT": "Налаштувати ВПРАВО", - "modmenu.descriptionTranslation.realcamera": "Зробити камеру більш реалістичною в режимі від першої особи.", - - "config.category.xtracr_realcamera.general": "Основні", "config.category.xtracr_realcamera.binding": "Режим Прив'язки", - "config.category.xtracr_realcamera.classic": "Класичний Режим", "config.category.xtracr_realcamera.cameraOffset": "Зміщення Камери", - "config.category.xtracr_realcamera.centerOffset": "Зміщення Центру Обертання", "config.category.xtracr_realcamera.cameraRotation": "Обертання Камери", - "config.tooltip.xtracr_realcamera.classicOffset": "Зміщення камери від центру обертання", - "config.tooltip.xtracr_realcamera.classicOffset_n": "Примітка: передня, верхня та ліва сторони гравця відповідають осям X, Y та Z", - "config.tooltip.xtracr_realcamera.centerOffset": "Зміщення центру обертання від голови", - "config.tooltip.xtracr_realcamera.cameraRotation": "Додаткове обертання камери в градусах", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "Примітка: тангаж, рискання та крен - це обертання навколо лівої, верхньої та передньої осей відповідно", - - "config.option.xtracr_realcamera.enabled": "Мод Увімкнено", - "config.option.xtracr_realcamera.isClassic": "Класичний Режим", - "config.option.xtracr_realcamera.dynamicCrosshair": "Динамічний Приціл", - "config.option.xtracr_realcamera.renderModel": "Відображати Модель Гравця", + "config.category.xtracr_realcamera.centerOffset": "Зміщення Центру Обертання", + "config.category.xtracr_realcamera.classic": "Класичний Режим", + "config.category.xtracr_realcamera.general": "Основні", + "config.option.xtracr_realcamera.activeConfigIndex": "Активний індекс конфігурації", + "config.option.xtracr_realcamera.adjustOffset": "Налаштувати Зміщення Камери", "config.option.xtracr_realcamera.adjustStep": "Крок Налаштування", - "config.option.xtracr_realcamera.classicAdjustMode": "Режим Налаштування", - "config.option.xtracr_realcamera.scale": "Масштаб", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадри збереження результату прив'язки", "config.option.xtracr_realcamera.cameraOffset": "Зміщення Камери %s", "config.option.xtracr_realcamera.centerOffset": "Зміщення Центру Обертання %s", - "config.option.xtracr_realcamera.pitch": "Тангаж", - "config.option.xtracr_realcamera.yaw": "Рискання", - "config.option.xtracr_realcamera.roll": "Крен", - "config.option.xtracr_realcamera.toModelViewScreen": "Для детальних налаштувань перейдіть на екран %s (необхідно призначити клавішу для відкриття)", - "config.option.xtracr_realcamera.screenModifierKey": "Клавіша-модифікатор екрану %s", - "config.option.xtracr_realcamera.legacyBindingMode": "Режим Застарілої Прив'язки", - "config.option.xtracr_realcamera.adjustOffset": "Налаштувати Зміщення Камери", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "Приховувати повідомлення про невдалу прив'язку", - "config.option.xtracr_realcamera.renderStuckObjects": "Відображати Застряглі Об'єкти", - "config.option.xtracr_realcamera.rerenderModel": "Перемалювати Модель", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "Кадри збереження результату прив'язки", - "config.option.xtracr_realcamera.displacementSmoothFactor": "Коефіцієнт згладжування зміщення", - "config.option.xtracr_realcamera.rotationSmoothFactor": "Коефіцієнт згладжування обертання", - "config.option.xtracr_realcamera.activeConfigIndex": "Активний індекс конфігурації", + "config.option.xtracr_realcamera.classicAdjustMode": "Режим Налаштування", "config.option.xtracr_realcamera.disableConfig": "Вимкнути Конфігурацію", - "config.option.xtracr_realcamera.disableWhenSneaking": "Вимкнути основну функцію при крадіжці", + "config.option.xtracr_realcamera.disableMainFeatureItems": "Вимкнути основну функцію при триманні...", + "config.option.xtracr_realcamera.disableRenderItems": "Вимкнути відображення при триманні...", "config.option.xtracr_realcamera.disableWhenCrawling": "Вимкнути основну функцію при повзанні", + "config.option.xtracr_realcamera.disableWhenSneaking": "Вимкнути основну функцію при крадіжці", "config.option.xtracr_realcamera.disableWhenSwimming": "Вимкнути основну функцію при плаванні", + "config.option.xtracr_realcamera.displacementSmoothFactor": "Коефіцієнт згладжування зміщення", + "config.option.xtracr_realcamera.dynamicCrosshair": "Динамічний Приціл", + "config.option.xtracr_realcamera.enabled": "Мод Увімкнено", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "Приховувати повідомлення про невдалу прив'язку", + "config.option.xtracr_realcamera.isClassic": "Класичний Режим", + "config.option.xtracr_realcamera.legacyBindingMode": "Режим Застарілої Прив'язки", "config.option.xtracr_realcamera.outTick": "Затримка виходу зі стану плавання (у тіках)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "Вимкнути основну функцію при триманні...", - "config.option.xtracr_realcamera.disableRenderItems": "Вимкнути відображення при триманні...", - "config.tooltip.xtracr_realcamera.isClassic": "Класичний режим вносить лише прості зміни в положення та обертання камери", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "При ввімкненні приціл слідуватиме за поглядом гравця, забезпечуючи точне попадання\nРекомендується ввімкнути при встановленні Jade, WTHIT або подібних модів", - "config.tooltip.xtracr_realcamera.renderModel": "Відображати модель гравця в режимі від першої особи", + "config.option.xtracr_realcamera.pitch": "Тангаж", + "config.option.xtracr_realcamera.renderModel": "Відображати Модель Гравця", + "config.option.xtracr_realcamera.renderStuckObjects": "Відображати Застряглі Об'єкти", + "config.option.xtracr_realcamera.rerenderModel": "Перемалювати Модель", + "config.option.xtracr_realcamera.roll": "Крен", + "config.option.xtracr_realcamera.rotationSmoothFactor": "Коефіцієнт згладжування обертання", + "config.option.xtracr_realcamera.scale": "Масштаб", + "config.option.xtracr_realcamera.screenModifierKey": "Клавіша-модифікатор екрану %s", + "config.option.xtracr_realcamera.toModelViewScreen": "Для детальних налаштувань перейдіть на екран %s (необхідно призначити клавішу для відкриття)", + "config.option.xtracr_realcamera.yaw": "Рискання", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "Поточний індекс прив'язаної конфігурації, 0 означає дозвіл прив'язки до будь-якої допустимої конфігурації", + "config.tooltip.xtracr_realcamera.adjustOffset": "При натисканні клавіші налаштування, регулювати зміщення або обертання камери", "config.tooltip.xtracr_realcamera.adjustStep": "Довжина або 1/100 кута налаштування за крок", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Протягом кількох кадрів після невдалої прив'язки продовжувати використовувати попередній успішний результат прив'язки", + "config.tooltip.xtracr_realcamera.cameraRotation": "Додаткове обертання камери в градусах", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "Примітка: тангаж, рискання та крен - це обертання навколо лівої, верхньої та передньої осей відповідно", + "config.tooltip.xtracr_realcamera.centerOffset": "Зміщення центру обертання від голови", "config.tooltip.xtracr_realcamera.classicAdjustMode": "Визначає, що налаштовувати при натисканні клавіші налаштування", - "config.tooltip.xtracr_realcamera.scale": "Контролювати розмір зміщень", + "config.tooltip.xtracr_realcamera.classicOffset": "Зміщення камери від центру обертання", + "config.tooltip.xtracr_realcamera.classicOffset_n": "Примітка: передня, верхня та ліва сторони гравця відповідають осям X, Y та Z", + "config.tooltip.xtracr_realcamera.disableRenderItems": "Підтримуються три методи співставлення:\n1. Співставлення з підстановковим знаком `*` (наприклад, `minecraft:*sword`)\n2. Співставлення за тегами (починається з `#`, наприклад, `#minecraft:swords`)\n3. Прямий ID предмета (наприклад, `minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Коефіцієнт згладжування зміщення камери, чим вище значення, тим плавніший рух", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "При ввімкненні приціл слідуватиме за поглядом гравця, забезпечуючи точне попадання\nРекомендується ввімкнути при встановленні Jade, WTHIT або подібних модів", + "config.tooltip.xtracr_realcamera.isClassic": "Класичний режим вносить лише прості зміни в положення та обертання камери", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Використовує режим прив'язки застарілої версії (v0.5), підтримуються лише стандартні моделі та дії на їх основі\nПісля ввімкнення властивості можна налаштувати в 'LEGACY_MODE' екрані %s", - "config.tooltip.xtracr_realcamera.adjustOffset": "При натисканні клавіші налаштування, регулювати зміщення або обертання камери", + "config.tooltip.xtracr_realcamera.outTick": "Час перед ввімкненням основної функції після виходу зі стану плавання (1 тік = 0.05с)", + "config.tooltip.xtracr_realcamera.renderModel": "Відображати модель гравця в режимі від першої особи", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Стріли, жала бджіл та інші об'єкти, які можуть застрягти в тілі гравця", "config.tooltip.xtracr_realcamera.rerenderModel": "Перемальовувати модель у вихідний час рендерингу, щоб уникнути візуальних проблем, викликаних раннім рендерингом", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "Протягом кількох кадрів після невдалої прив'язки продовжувати використовувати попередній успішний результат прив'язки", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "Коефіцієнт згладжування зміщення камери, чим вище значення, тим плавніший рух", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Коефіцієнт згладжування обертання камери, чим вище значення, тим плавніший рух", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "Поточний індекс прив'язаної конфігурації, 0 означає дозвіл прив'язки до будь-якої допустимої конфігурації", - "config.tooltip.xtracr_realcamera.outTick": "Час перед ввімкненням основної функції після виходу зі стану плавання (1 тік = 0.05с)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "Підтримуються три методи співставлення:\n1. Співставлення з підстановковим знаком `*` (наприклад, `minecraft:*sword`)\n2. Співставлення за тегами (починається з `#`, наприклад, `#minecraft:swords`)\n3. Прямий ID предмета (наприклад, `minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "Контролювати розмір зміщень", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "Переключитися на наступну конфігурацію", + "key.xtracr_realcamera.activeConfigIndexPREV": "Переключитися на попередню конфігурацію", + "key.xtracr_realcamera.activeConfigIndexRESET": "Скинути індекс конфігурації", + "key.xtracr_realcamera.adjustBACK": "Налаштувати НАЗАД", + "key.xtracr_realcamera.adjustDOWN": "Налаштувати ВНИЗ", + "key.xtracr_realcamera.adjustFRONT": "Налаштувати ВПЕРЕД", + "key.xtracr_realcamera.adjustLEFT": "Налаштувати ВЛІВО", + "key.xtracr_realcamera.adjustRIGHT": "Налаштувати ВПРАВО", + "key.xtracr_realcamera.adjustUP": "Налаштувати ВГОРУ", + "key.xtracr_realcamera.modelViewScreen": "Відкрити Екран Перегляду Моделі", + "key.xtracr_realcamera.toggleAdjustMode": "Переключити Режим Налаштування", + "key.xtracr_realcamera.toggleCameraMode": "Переключити Режим Камери", + "key.xtracr_realcamera.togglePerspective": "Увімкнути/Вимкнути", "message.xtracr_realcamera.bindingFailed": "[%s]: Помилка прив'язки, будь ласка, перейдіть на екран %s та налаштуйте вручну (Клавіша: %s)", - - "screen.xtracr_realcamera.modelView_title": "Перегляд Моделі", - "screen.widget.xtracr_realcamera.modelView_import": "Імпорт", + "modmenu.descriptionTranslation.realcamera": "Зробити камеру більш реалістичною в режимі від першої особи.", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "При вимкненні відносне положення камери до моделі не зміниться, але відповідні атрибути камери не будуть змінені цим модом", + "screen.tooltip.xtracr_realcamera.modelView_configs": "Збережені конфігурації", + "screen.tooltip.xtracr_realcamera.modelView_copy": "Копіювати всі налаштування вимкнення", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Видалити вибраний прямокутник\n(Або використовуйте клавішу Delete)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "Площини, де всі відстані від вершини до екрану менші за це значення, не будуть відображатися", + "screen.tooltip.xtracr_realcamera.modelView_disable": "Налаштування вимкнення\nГлобальні налаштування вимкнення знаходяться на екрані конфігурації", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Частини, що містяться в синіх рамках, будуть вимкнені\nЛівий клік для вибору, інші клавіші для скасування вибору\n%s+Лівий клік для швидкого вибору частини, на яку вказує курсор миші", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Ім'я налаштування вимкнення", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Ім'я не може бути порожнім!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Ідентифікатор текстури не може бути порожнім!", + "screen.tooltip.xtracr_realcamera.modelView_export": "Експортувати поточну конфігурацію в буфер обміну", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Помилка експорту: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Експорт успішний!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Номер виділеного прямокутника\n(0 означає відсутність вибору)\nНатисніть Пробіл або Enter щоб знайти поточний виділений прямокутник (При вводі натисніть двічі щоб знайти)", + "screen.tooltip.xtracr_realcamera.modelView_import": "Імпортувати конфігурацію з буфера обміну", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Помилка імпорту: \n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпорт %s успішний!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "Вставити всі налаштування вимкнення з буфера обміну в поточну конфігурацію\n(Не перезапише існуючі налаштування з тим же ім'ям)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "У режимі попереднього перегляду ви можете налаштувати зміщення та обертання камери", + "screen.tooltip.xtracr_realcamera.modelView_priority": "Пріоритет при прив'язці: чим більше значення, тим вищий пріоритет і вище сортування на правій стороні", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Зберегти як\n(При наявності налаштування з тим же ім'ям ви також можете використовувати кнопку збереження зліва)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "Масштаб, який контролює розмір зміщень", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Лівий клік щоб отримати UV-координати в місці вказівника миші\nТри набори UV-координат нижче, зверху вниз, це UV-координати вектора напрямку, вектора вгору та точки прив'язки на цільовій площині\nПримітка: %s+Прокрутка для перемикання між різними шарами моделі. Ручний ввід UV-координат дозволяє точніше прив'язатися до цільової позиції", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Визначає режим швидкого вибору %s+Лівий клік\n(%s+Прокрутка для зміни діапазону вибору в режимі діапазону)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "Ім'я конфігурації", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "Ідентифікатор текстури обраної моделі (не обов'язково повний ідентифікатор), може бути скорочений при збереженні для зручності розпізнавання.\nНаприклад, скоротити minecraft:textures/entity/player/slim/alex.png до minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Відкрити глобальний екран конфігурації\n(Потрібен Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "Усе", + "screen.widget.xtracr_realcamera.modelView_configs": "Конфігурації", + "screen.widget.xtracr_realcamera.modelView_copy": "Копіювати", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "Поточна Конфігурація", + "screen.widget.xtracr_realcamera.modelView_disable": "Вимкнути", + "screen.widget.xtracr_realcamera.modelView_disableMode": "Режим вимкнення", "screen.widget.xtracr_realcamera.modelView_export": "Експорт", - "screen.widget.xtracr_realcamera.modelView_selecting": "Вибір", "screen.widget.xtracr_realcamera.modelView_forwardVector": "Вектор напрямку", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектор вгору", - "screen.widget.xtracr_realcamera.modelView_position": "Цільова площина", - "screen.widget.xtracr_realcamera.modelView_save": "Зберегти", - "screen.widget.xtracr_realcamera.modelView_disableMode": "Режим вимкнення", - "screen.widget.xtracr_realcamera.modelView_all": "Усе", - "screen.widget.xtracr_realcamera.modelView_part": "Частина", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "Режим вибору", - "screen.widget.xtracr_realcamera.modelView_single": "Одиночний", + "screen.widget.xtracr_realcamera.modelView_import": "Імпорт", "screen.widget.xtracr_realcamera.modelView_multiple": "Множинний", - "screen.widget.xtracr_realcamera.modelView_range": "Діапазон", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Переключити повзунок у поле", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Переключити поле у повзунок", "screen.widget.xtracr_realcamera.modelView_offsetX": "Зміщення X = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Зміщення Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Зміщення Z = %s", + "screen.widget.xtracr_realcamera.modelView_part": "Частина", + "screen.widget.xtracr_realcamera.modelView_paste": "Вставити", "screen.widget.xtracr_realcamera.modelView_pitch": "Тангаж = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "Рискання = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "Крен = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "Вимкнути", + "screen.widget.xtracr_realcamera.modelView_position": "Цільова площина", "screen.widget.xtracr_realcamera.modelView_preview": "Попередній перегляд", - "screen.widget.xtracr_realcamera.modelView_configs": "Конфігурації", - "screen.widget.xtracr_realcamera.modelView_copy": "Копіювати", - "screen.widget.xtracr_realcamera.modelView_paste": "Вставити", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "Поточна Конфігурація", - "screen.tooltip.xtracr_realcamera.modelView_import": "Імпортувати конфігурацію з буфера обміну", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпорт %s успішний!", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Помилка імпорту: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_export": "Експортувати поточну конфігурацію в буфер обміну", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "Експорт успішний!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "Помилка експорту: \n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Лівий клік щоб отримати UV-координати в місці вказівника миші\nТри набори UV-координат нижче, зверху вниз, це UV-координати вектора напрямку, вектора вгору та точки прив'язки на цільовій площині\nПримітка: %s+Прокрутка для перемикання між різними шарами моделі. Ручний ввід UV-координат дозволяє точніше прив'язатися до цільової позиції", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "Ідентифікатор текстури обраної моделі (не обов'язково повний ідентифікатор), може бути скорочений при збереженні для зручності розпізнавання.\nНаприклад, скоротити minecraft:textures/entity/player/slim/alex.png до minecraft:textures/entity/player/.", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "Частини, що містяться в синіх рамках, будуть вимкнені\nЛівий клік для вибору, інші клавіші для скасування вибору\n%s+Лівий клік для швидкого вибору частини, на яку вказує курсор миші", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Визначає режим швидкого вибору %s+Лівий клік\n(%s+Прокрутка для зміни діапазону вибору в режимі діапазону)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "Номер виділеного прямокутника\n(0 означає відсутність вибору)\nНатисніть Пробіл або Enter щоб знайти поточний виділений прямокутник (При вводі натисніть двічі щоб знайти)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Видалити вибраний прямокутник\n(Або використовуйте клавішу Delete)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "При вимкненні відносне положення камери до моделі не зміниться, але відповідні атрибути камери не будуть змінені цим модом", - "screen.tooltip.xtracr_realcamera.modelView_scale": "Масштаб, який контролює розмір зміщень", - "screen.tooltip.xtracr_realcamera.modelView_depth": "Площини, де всі відстані від вершини до екрану менші за це значення, не будуть відображатися", - "screen.tooltip.xtracr_realcamera.modelView_priority": "Пріоритет при прив'язці: чим більше значення, тим вищий пріоритет і вище сортування на правій стороні", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "Ім'я конфігурації", - "screen.tooltip.xtracr_realcamera.modelView_disable": "Налаштування вимкнення\nГлобальні налаштування вимкнення знаходяться на екрані конфігурації", - "screen.tooltip.xtracr_realcamera.modelView_configs": "Збережені конфігурації", - "screen.tooltip.xtracr_realcamera.modelView_preview": "У режимі попереднього перегляду ви можете налаштувати зміщення та обертання камери", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Відкрити глобальний екран конфігурації\n(Потрібен Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Копіювати всі налаштування вимкнення", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Вставити всі налаштування вимкнення з буфера обміну в поточну конфігурацію\n(Не перезапише існуючі налаштування з тим же ім'ям)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "Ім'я не може бути порожнім!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "Ідентифікатор текстури не може бути порожнім!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Зберегти як\n(При наявності налаштування з тим же ім'ям ви також можете використовувати кнопку збереження зліва)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "Ім'я налаштування вимкнення" + "screen.widget.xtracr_realcamera.modelView_range": "Діапазон", + "screen.widget.xtracr_realcamera.modelView_roll": "Крен = %s", + "screen.widget.xtracr_realcamera.modelView_save": "Зберегти", + "screen.widget.xtracr_realcamera.modelView_selecting": "Вибір", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "Режим вибору", + "screen.widget.xtracr_realcamera.modelView_single": "Одиночний", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "Переключити поле у повзунок", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "Переключити повзунок у поле", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектор вгору", + "screen.widget.xtracr_realcamera.modelView_yaw": "Рискання = %s", + "screen.xtracr_realcamera.modelView_title": "Перегляд Моделі" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index d81515cb..4ce465b3 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "打开模型视图界面", - "key.xtracr_realcamera.togglePerspective": "开启/关闭", - "key.xtracr_realcamera.activeConfigIndexPREV": "切换到上一个配置", - "key.xtracr_realcamera.activeConfigIndexNEXT": "切换到下一个配置", - "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", - "key.xtracr_realcamera.toggleAdjustMode": "切换调整模式", - "key.xtracr_realcamera.toggleCameraMode": "切换摄像头模式", - "key.xtracr_realcamera.adjustUP": "向上调整", - "key.xtracr_realcamera.adjustDOWN": "向下调整", - "key.xtracr_realcamera.adjustFRONT": "向前调整", - "key.xtracr_realcamera.adjustBACK": "向后调整", - "key.xtracr_realcamera.adjustLEFT": "向左调整", - "key.xtracr_realcamera.adjustRIGHT": "向右调整", - "modmenu.descriptionTranslation.realcamera": "使第一人称视角下的摄像头更加真实。", - - "config.category.xtracr_realcamera.general": "通用", "config.category.xtracr_realcamera.binding": "绑定模式", - "config.category.xtracr_realcamera.classic": "经典模式", "config.category.xtracr_realcamera.cameraOffset": "摄像头偏移", - "config.category.xtracr_realcamera.centerOffset": "旋转中心偏移", "config.category.xtracr_realcamera.cameraRotation": "摄像头旋转", - "config.tooltip.xtracr_realcamera.classicOffset": "摄像头相对旋转中心的偏移值", - "config.tooltip.xtracr_realcamera.classicOffset_n": "注:玩家的的前方、上方和左方分别为X、Y和Z轴", - "config.tooltip.xtracr_realcamera.centerOffset": "旋转中心相对头部的偏移值", - "config.tooltip.xtracr_realcamera.cameraRotation": "额外的摄像头旋转角度", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "注:俯仰、偏航和翻滚分别是以左方、上方和前方为轴的旋转", - - "config.option.xtracr_realcamera.enabled": "开启功能", - "config.option.xtracr_realcamera.isClassic": "经典模式", - "config.option.xtracr_realcamera.dynamicCrosshair": "动态十字准心", - "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", + "config.category.xtracr_realcamera.centerOffset": "旋转中心偏移", + "config.category.xtracr_realcamera.classic": "经典模式", + "config.category.xtracr_realcamera.general": "通用", + "config.option.xtracr_realcamera.activeConfigIndex": "当前配置索引", + "config.option.xtracr_realcamera.adjustOffset": "调整摄像头偏移", "config.option.xtracr_realcamera.adjustStep": "调整步长", - "config.option.xtracr_realcamera.classicAdjustMode": "调整模式", - "config.option.xtracr_realcamera.scale": "缩放比例", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "绑定结果保留帧数", "config.option.xtracr_realcamera.cameraOffset": "摄像头%s偏移", "config.option.xtracr_realcamera.centerOffset": "旋转中心%s偏移", - "config.option.xtracr_realcamera.pitch": "俯仰角", - "config.option.xtracr_realcamera.yaw": "偏航角", - "config.option.xtracr_realcamera.roll": "翻滚角", - "config.option.xtracr_realcamera.toModelViewScreen": "详细设置请前往%s界面(需设置快捷键来打开它)", - "config.option.xtracr_realcamera.screenModifierKey": "%s界面修饰键", - "config.option.xtracr_realcamera.legacyBindingMode": "旧绑定模式", - "config.option.xtracr_realcamera.adjustOffset": "调整摄像头偏移", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "隐藏绑定失败消息", - "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物体", - "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "绑定结果保留帧数", - "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", - "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", - "config.option.xtracr_realcamera.activeConfigIndex": "当前配置索引", + "config.option.xtracr_realcamera.classicAdjustMode": "调整模式", "config.option.xtracr_realcamera.disableConfig": "禁用配置", - "config.option.xtracr_realcamera.disableWhenSneaking": "潜行时禁用主要功能", + "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...时禁用主要功能", + "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用渲染", "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSneaking": "潜行时禁用主要功能", "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", + "config.option.xtracr_realcamera.dynamicCrosshair": "动态十字准心", + "config.option.xtracr_realcamera.enabled": "开启功能", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "隐藏绑定失败消息", + "config.option.xtracr_realcamera.isClassic": "经典模式", + "config.option.xtracr_realcamera.legacyBindingMode": "旧绑定模式", "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...时禁用主要功能", - "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用渲染", - "config.tooltip.xtracr_realcamera.isClassic": "经典模式只对摄像头的位置和旋转做简单的修改", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在开启状态下,十字准心会随着玩家的视线移动,确保命中结果不受影响\n在安装了Jade、WTHIT或类似模组时建议启用", - "config.tooltip.xtracr_realcamera.renderModel": "在第一人称视角下渲染玩家模型", + "config.option.xtracr_realcamera.pitch": "俯仰角", + "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", + "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物体", + "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", + "config.option.xtracr_realcamera.roll": "翻滚角", + "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", + "config.option.xtracr_realcamera.scale": "缩放比例", + "config.option.xtracr_realcamera.screenModifierKey": "%s界面修饰键", + "config.option.xtracr_realcamera.toModelViewScreen": "详细设置请前往%s界面(需设置快捷键来打开它)", + "config.option.xtracr_realcamera.yaw": "偏航角", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "当前绑定的配置索引,0表示允许绑定任何有效配置", + "config.tooltip.xtracr_realcamera.adjustOffset": "当前按下调整键时是调整摄像头的偏移还是旋转", "config.tooltip.xtracr_realcamera.adjustStep": "每步调整的角度的1/100或长度", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在绑定失败后的数帧内,沿用上个成功的绑定结果", + "config.tooltip.xtracr_realcamera.cameraRotation": "额外的摄像头旋转角度", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "注:俯仰、偏航和翻滚分别是以左方、上方和前方为轴的旋转", + "config.tooltip.xtracr_realcamera.centerOffset": "旋转中心相对头部的偏移值", "config.tooltip.xtracr_realcamera.classicAdjustMode": "决定当前按下调整键时调整哪一个", - "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", + "config.tooltip.xtracr_realcamera.classicOffset": "摄像头相对旋转中心的偏移值", + "config.tooltip.xtracr_realcamera.classicOffset_n": "注:玩家的的前方、上方和左方分别为X、Y和Z轴", + "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三种匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 标签匹配以`#`开头(如`#minecraft:swords`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相机位移平滑系数,值越大越平滑", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在开启状态下,十字准心会随着玩家的视线移动,确保命中结果不受影响\n在安装了Jade、WTHIT或类似模组时建议启用", + "config.tooltip.xtracr_realcamera.isClassic": "经典模式只对摄像头的位置和旋转做简单的修改", "config.tooltip.xtracr_realcamera.legacyBindingMode": "使用旧版本(v0.5)的绑定模式,仅支持原版模型和基于原版模型的动作\n开启后可在%s界面的'LEGACY_MODE'中设置属性", - "config.tooltip.xtracr_realcamera.adjustOffset": "当前按下调整键时是调整摄像头的偏移还是旋转", + "config.tooltip.xtracr_realcamera.outTick": "玩家停止某些状态(如游泳、爬行)后重启主要功能的时间(1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.renderModel": "在第一人称视角下渲染玩家模型", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它会卡在玩家身体里的物体", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染时机重新渲染模型,以避免一些因提前渲染导致的视觉问题", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在绑定失败后的数帧内,沿用上个成功的绑定结果", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相机位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相机旋转平滑系数,值越大越平滑", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "当前绑定的配置索引,0表示允许绑定任何有效配置", - "config.tooltip.xtracr_realcamera.outTick": "玩家停止某些状态(如游泳、爬行)后重启主要功能的时间(1 tick = 0.05s)", - "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三种匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 标签匹配以`#`开头(如`#minecraft:swords`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切换到下一个配置", + "key.xtracr_realcamera.activeConfigIndexPREV": "切换到上一个配置", + "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", + "key.xtracr_realcamera.adjustBACK": "向后调整", + "key.xtracr_realcamera.adjustDOWN": "向下调整", + "key.xtracr_realcamera.adjustFRONT": "向前调整", + "key.xtracr_realcamera.adjustLEFT": "向左调整", + "key.xtracr_realcamera.adjustRIGHT": "向右调整", + "key.xtracr_realcamera.adjustUP": "向上调整", + "key.xtracr_realcamera.modelViewScreen": "打开模型视图界面", + "key.xtracr_realcamera.toggleAdjustMode": "切换调整模式", + "key.xtracr_realcamera.toggleCameraMode": "切换摄像头模式", + "key.xtracr_realcamera.togglePerspective": "开启/关闭", "message.xtracr_realcamera.bindingFailed": "[%s]: 绑定失败,请前往%s界面手动设置(键位:%s)", - - "screen.xtracr_realcamera.modelView_title": "模型视图", - "screen.widget.xtracr_realcamera.modelView_import": "导入", + "modmenu.descriptionTranslation.realcamera": "使第一人称视角下的摄像头更加真实。", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "当禁用时,摄像头与模型的相对关系不会变化,但摄像头的对应属性不会被本模组修改", + "screen.tooltip.xtracr_realcamera.modelView_configs": "已保存的配置", + "screen.tooltip.xtracr_realcamera.modelView_copy": "复制所有禁用设置", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "删除选中的矩形\n(或使用Delete键)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "全部顶点到屏幕距离均小于该值的面不会被渲染", + "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用设置\n全局禁用设置在配置屏幕中", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "被蓝框包含的部分会被禁用\n可在左侧材质视图中鼠标左键框选,其它键取消选择\n%s+左键可快速选择被鼠标指针指向的部分", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁用设置的名称", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名称不能为空!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材质id不能为空!", + "screen.tooltip.xtracr_realcamera.modelView_export": "导出当前配置到剪贴板", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "导出失败:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "导出成功!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "选中的矩形编号\n(0表示不选中)\n可通过空格或回车键定位到当前选中的矩形(当正在输入时,按两次即可定位)", + "screen.tooltip.xtracr_realcamera.modelView_import": "从剪贴板导入配置", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "导入失败:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "导入%s成功!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "粘贴剪贴板中的所有禁用设置到当前配置\n(不会覆盖同名设置)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "在预览模式可以调整相机的各个偏移量", + "screen.tooltip.xtracr_realcamera.modelView_priority": "绑定时的优先级,值越大优先级越高,并且在右侧排序越靠上", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "保存为\n(当存在同名设置时,也可使用左侧保存按钮)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "缩放比例,控制偏移量的大小", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左键可获取鼠标指针处的UV坐标\n下方三组UV坐标由上到下依次为向前矢量、向上矢量和目标平面上绑定点的UV坐标\n注:%s键+滚轮可在模型的不同层间切换,手动输入UV坐标可以更加精确地绑定到目标位置", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "决定%s+左键快速选择的模式\n(%s键+滚轮可改变范围模式下的选择范围)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "配置的名称", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "被选中的模型的纹理的id(不是完整的id也可以识别),保存时可以缩短一部分以便于程序识别\n比如将minecraft:textures/entity/player/slim/alex.png缩短为minecraft:textures/entity/player/", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打开全局配置屏幕\n(需要安装Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "全部", + "screen.widget.xtracr_realcamera.modelView_configs": "配置", + "screen.widget.xtracr_realcamera.modelView_copy": "复制", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "当前配置", + "screen.widget.xtracr_realcamera.modelView_disable": "禁用", + "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", "screen.widget.xtracr_realcamera.modelView_export": "导出", - "screen.widget.xtracr_realcamera.modelView_selecting": "选择", "screen.widget.xtracr_realcamera.modelView_forwardVector": "向前矢量", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上矢量", - "screen.widget.xtracr_realcamera.modelView_position": "目标平面", - "screen.widget.xtracr_realcamera.modelView_save": "保存", - "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", - "screen.widget.xtracr_realcamera.modelView_all": "全部", - "screen.widget.xtracr_realcamera.modelView_part": "部分", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "选择模式", - "screen.widget.xtracr_realcamera.modelView_single": "单选", + "screen.widget.xtracr_realcamera.modelView_import": "导入", "screen.widget.xtracr_realcamera.modelView_multiple": "多选", - "screen.widget.xtracr_realcamera.modelView_range": "范围", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "切换滑块到输入框", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "切换输入框到滑块", "screen.widget.xtracr_realcamera.modelView_offsetX": "X偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z偏移量 = %s", + "screen.widget.xtracr_realcamera.modelView_part": "部分", + "screen.widget.xtracr_realcamera.modelView_paste": "粘贴", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰角 = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "翻滚角 = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "禁用", + "screen.widget.xtracr_realcamera.modelView_position": "目标平面", "screen.widget.xtracr_realcamera.modelView_preview": "预览", - "screen.widget.xtracr_realcamera.modelView_configs": "配置", - "screen.widget.xtracr_realcamera.modelView_copy": "复制", - "screen.widget.xtracr_realcamera.modelView_paste": "粘贴", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "当前配置", - "screen.tooltip.xtracr_realcamera.modelView_import": "从剪贴板导入配置", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "导入失败:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "导入%s成功!", - "screen.tooltip.xtracr_realcamera.modelView_export": "导出当前配置到剪贴板", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "导出成功!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "导出失败:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左键可获取鼠标指针处的UV坐标\n下方三组UV坐标由上到下依次为向前矢量、向上矢量和目标平面上绑定点的UV坐标\n注:%s键+滚轮可在模型的不同层间切换,手动输入UV坐标可以更加精确地绑定到目标位置", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "被选中的模型的纹理的id(不是完整的id也可以识别),保存时可以缩短一部分以便于程序识别\n比如将minecraft:textures/entity/player/slim/alex.png缩短为minecraft:textures/entity/player/", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "被蓝框包含的部分会被禁用\n可在左侧材质视图中鼠标左键框选,其它键取消选择\n%s+左键可快速选择被鼠标指针指向的部分", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "决定%s+左键快速选择的模式\n(%s键+滚轮可改变范围模式下的选择范围)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "选中的矩形编号\n(0表示不选中)\n可通过空格或回车键定位到当前选中的矩形(当正在输入时,按两次即可定位)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "删除选中的矩形\n(或使用Delete键)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "当禁用时,摄像头与模型的相对关系不会变化,但摄像头的对应属性不会被本模组修改", - "screen.tooltip.xtracr_realcamera.modelView_scale": "缩放比例,控制偏移量的大小", - "screen.tooltip.xtracr_realcamera.modelView_depth": "全部顶点到屏幕距离均小于该值的面不会被渲染", - "screen.tooltip.xtracr_realcamera.modelView_priority": "绑定时的优先级,值越大优先级越高,并且在右侧排序越靠上", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "配置的名称", - "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用设置\n全局禁用设置在配置屏幕中", - "screen.tooltip.xtracr_realcamera.modelView_configs": "已保存的配置", - "screen.tooltip.xtracr_realcamera.modelView_preview": "在预览模式可以调整相机的各个偏移量", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打开全局配置屏幕\n(需要安装Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "复制所有禁用设置", - "screen.tooltip.xtracr_realcamera.modelView_paste": "粘贴剪贴板中的所有禁用设置到当前配置\n(不会覆盖同名设置)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名称不能为空!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材质id不能为空!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "保存为\n(当存在同名设置时,也可使用左侧保存按钮)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁用设置的名称" + "screen.widget.xtracr_realcamera.modelView_range": "范围", + "screen.widget.xtracr_realcamera.modelView_roll": "翻滚角 = %s", + "screen.widget.xtracr_realcamera.modelView_save": "保存", + "screen.widget.xtracr_realcamera.modelView_selecting": "选择", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "选择模式", + "screen.widget.xtracr_realcamera.modelView_single": "单选", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "切换输入框到滑块", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "切换滑块到输入框", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上矢量", + "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", + "screen.xtracr_realcamera.modelView_title": "模型视图" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/zh_hk.json b/common/src/main/resources/assets/realcamera/lang/zh_hk.json index 0b23af1c..96053fb9 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_hk.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_hk.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "打開模型視圖界面", - "key.xtracr_realcamera.togglePerspective": "開啟/關閉", - "key.xtracr_realcamera.activeConfigIndexPREV": "切換到上一個配置", - "key.xtracr_realcamera.activeConfigIndexNEXT": "切換到下一個配置", - "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", - "key.xtracr_realcamera.toggleAdjustMode": "切換調整模式", - "key.xtracr_realcamera.toggleCameraMode": "切換攝像頭模式", - "key.xtracr_realcamera.adjustUP": "向上調整", - "key.xtracr_realcamera.adjustDOWN": "向下調整", - "key.xtracr_realcamera.adjustFRONT": "向前調整", - "key.xtracr_realcamera.adjustBACK": "向後調整", - "key.xtracr_realcamera.adjustLEFT": "向左調整", - "key.xtracr_realcamera.adjustRIGHT": "向右調整", - "modmenu.descriptionTranslation.realcamera": "使第一人稱視角下的攝像頭更加真實。", - - "config.category.xtracr_realcamera.general": "通用", "config.category.xtracr_realcamera.binding": "綁定模式", - "config.category.xtracr_realcamera.classic": "經典模式", "config.category.xtracr_realcamera.cameraOffset": "攝像頭偏移", - "config.category.xtracr_realcamera.centerOffset": "旋轉中心偏移", "config.category.xtracr_realcamera.cameraRotation": "攝像頭旋轉", - "config.tooltip.xtracr_realcamera.classicOffset": "攝像頭相對旋轉中心的偏移值", - "config.tooltip.xtracr_realcamera.classicOffset_n": "注: 玩家的前方、上方和左方分別為X、Y和Z軸", - "config.tooltip.xtracr_realcamera.centerOffset": "旋轉中心相對頭部的偏移值", - "config.tooltip.xtracr_realcamera.cameraRotation": "額外的攝像頭旋轉角度", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "注:俯仰、偏航和翻滾分別是以左方、上方和前方為軸的旋轉", - - "config.option.xtracr_realcamera.enabled": "開啟功能", - "config.option.xtracr_realcamera.isClassic": "經典模式", - "config.option.xtracr_realcamera.dynamicCrosshair": "動態十字準心", - "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", + "config.category.xtracr_realcamera.centerOffset": "旋轉中心偏移", + "config.category.xtracr_realcamera.classic": "經典模式", + "config.category.xtracr_realcamera.general": "通用", + "config.option.xtracr_realcamera.activeConfigIndex": "當前配置索引", + "config.option.xtracr_realcamera.adjustOffset": "調整攝像頭偏移", "config.option.xtracr_realcamera.adjustStep": "調整步長", - "config.option.xtracr_realcamera.classicAdjustMode": "調整模式", - "config.option.xtracr_realcamera.scale": "縮放比例", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留帧数", "config.option.xtracr_realcamera.cameraOffset": "攝像頭%s偏移", "config.option.xtracr_realcamera.centerOffset": "旋轉中心%s偏移", - "config.option.xtracr_realcamera.pitch": "俯仰角", - "config.option.xtracr_realcamera.yaw": "偏航角", - "config.option.xtracr_realcamera.roll": "翻滾角", - "config.option.xtracr_realcamera.toModelViewScreen": "詳細設置請前往%s界面(需設置快捷鍵來打開它)", - "config.option.xtracr_realcamera.screenModifierKey": "%s界面修飾鍵", - "config.option.xtracr_realcamera.legacyBindingMode": "舊綁定模式", - "config.option.xtracr_realcamera.adjustOffset": "調整攝像頭偏移", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱藏綁定失敗消息", - "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物體", - "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留帧数", - "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑係數", - "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑係數", - "config.option.xtracr_realcamera.activeConfigIndex": "當前配置索引", + "config.option.xtracr_realcamera.classicAdjustMode": "調整模式", "config.option.xtracr_realcamera.disableConfig": "禁用配置", - "config.option.xtracr_realcamera.disableWhenSneaking": "潛行时禁用主要功能", + "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...時禁用主要功能", + "config.option.xtracr_realcamera.disableRenderItems": "在手持...時禁用渲染", "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSneaking": "潛行时禁用主要功能", "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑係數", + "config.option.xtracr_realcamera.dynamicCrosshair": "動態十字準心", + "config.option.xtracr_realcamera.enabled": "開啟功能", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱藏綁定失敗消息", + "config.option.xtracr_realcamera.isClassic": "經典模式", + "config.option.xtracr_realcamera.legacyBindingMode": "舊綁定模式", "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...時禁用主要功能", - "config.option.xtracr_realcamera.disableRenderItems": "在手持...時禁用渲染", - "config.tooltip.xtracr_realcamera.isClassic": "經典模式只對攝像頭的位置和旋轉做簡單的修改", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在開啟狀態下,十字準心會隨著玩家的視線移動,確保命中結果不受影響\n在安裝了Jade、WTHIT或類似模組時建議啟用", - "config.tooltip.xtracr_realcamera.renderModel": "在第一人稱視角下渲染玩家模型", + "config.option.xtracr_realcamera.pitch": "俯仰角", + "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", + "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物體", + "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", + "config.option.xtracr_realcamera.roll": "翻滾角", + "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑係數", + "config.option.xtracr_realcamera.scale": "縮放比例", + "config.option.xtracr_realcamera.screenModifierKey": "%s界面修飾鍵", + "config.option.xtracr_realcamera.toModelViewScreen": "詳細設置請前往%s界面(需設置快捷鍵來打開它)", + "config.option.xtracr_realcamera.yaw": "偏航角", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "當前綁定的配置索引,0表示允許綁定任何有效配置", + "config.tooltip.xtracr_realcamera.adjustOffset": "當前按下調整鍵時是調整攝像頭的偏移還是旋轉", "config.tooltip.xtracr_realcamera.adjustStep": "每步調整的角度1/100或長度", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在綁定失敗的數帧内,沿用上个成功的綁定結果", + "config.tooltip.xtracr_realcamera.cameraRotation": "額外的攝像頭旋轉角度", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "注:俯仰、偏航和翻滾分別是以左方、上方和前方為軸的旋轉", + "config.tooltip.xtracr_realcamera.centerOffset": "旋轉中心相對頭部的偏移值", "config.tooltip.xtracr_realcamera.classicAdjustMode": "決定當前按下調整鍵時調整哪一個", - "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", + "config.tooltip.xtracr_realcamera.classicOffset": "攝像頭相對旋轉中心的偏移值", + "config.tooltip.xtracr_realcamera.classicOffset_n": "注: 玩家的前方、上方和左方分別為X、Y和Z軸", + "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三種匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 標簽匹配`#`開頭(如`#minecraft:tools`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相機位移平滑系数,值越大越平滑", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在開啟狀態下,十字準心會隨著玩家的視線移動,確保命中結果不受影響\n在安裝了Jade、WTHIT或類似模組時建議啟用", + "config.tooltip.xtracr_realcamera.isClassic": "經典模式只對攝像頭的位置和旋轉做簡單的修改", "config.tooltip.xtracr_realcamera.legacyBindingMode": "使用舊版本(v0.5)的綁定模式,僅支援原版模型和基於原版模型的動作\n開啟後可在%s界面的'LEGACY_MODE'中設置屬性", - "config.tooltip.xtracr_realcamera.adjustOffset": "當前按下調整鍵時是調整攝像頭的偏移還是旋轉", + "config.tooltip.xtracr_realcamera.outTick": "玩家停止特定狀態後重啟主要功能的時間(1 tick = 0.05秒)", + "config.tooltip.xtracr_realcamera.renderModel": "在第一人稱視角下渲染玩家模型", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它會卡在玩家身體裡的物體", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染時機重新渲染模型,以避免一些因提前渲染導致的視覺問題", - "config.tooltip.xtracr_realcamera.outTick": "玩家停止特定狀態後重啟主要功能的時間(1 tick = 0.05秒)", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在綁定失敗的數帧内,沿用上个成功的綁定結果", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相機位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相機旋轉平滑系数,值越大越平滑", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "當前綁定的配置索引,0表示允許綁定任何有效配置", - "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三種匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 標簽匹配`#`開頭(如`#minecraft:tools`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切換到下一個配置", + "key.xtracr_realcamera.activeConfigIndexPREV": "切換到上一個配置", + "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", + "key.xtracr_realcamera.adjustBACK": "向後調整", + "key.xtracr_realcamera.adjustDOWN": "向下調整", + "key.xtracr_realcamera.adjustFRONT": "向前調整", + "key.xtracr_realcamera.adjustLEFT": "向左調整", + "key.xtracr_realcamera.adjustRIGHT": "向右調整", + "key.xtracr_realcamera.adjustUP": "向上調整", + "key.xtracr_realcamera.modelViewScreen": "打開模型視圖界面", + "key.xtracr_realcamera.toggleAdjustMode": "切換調整模式", + "key.xtracr_realcamera.toggleCameraMode": "切換攝像頭模式", + "key.xtracr_realcamera.togglePerspective": "開啟/關閉", "message.xtracr_realcamera.bindingFailed": "[%s]: 綁定失敗,請前往%s界面手動設置(鍵位:%s)", - - "screen.xtracr_realcamera.modelView_title": "模型視圖", - "screen.widget.xtracr_realcamera.modelView_import": "導入", + "modmenu.descriptionTranslation.realcamera": "使第一人稱視角下的攝像頭更加真實。", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "當禁用時,攝像頭與模型的相對關係不會變化,但攝像頭的對應屬性不會被本模組修改", + "screen.tooltip.xtracr_realcamera.modelView_configs": "已儲存的配置", + "screen.tooltip.xtracr_realcamera.modelView_copy": "複製所有禁用設置", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "刪除選中的矩形\n(或使用Delete鍵)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "全部頂點到屏幕距離均小於該值的面不會被渲染", + "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用設置\n全局禁用設置在配置屏幕中", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "被藍框包含的部分會被禁用\n可在左側材質視圖中鼠標左鍵框選,其它鍵取消選擇\n左Alt+左鍵可快速選擇被鼠標指針指向的部分", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁用設置的名稱", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名稱不能為空!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材質id不能為空!", + "screen.tooltip.xtracr_realcamera.modelView_export": "導出當前配置到剪貼簿", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "導出失敗:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "導出成功!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "選中的矩形編號\n(0表示不選中)\n可通過空格或回車鍵定位到當前選中的矩形(當正在輸入時,按兩次即可定位)", + "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "貼上剪貼簿中的所有禁用設置到當前配置\n(不會覆蓋同名設置)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", + "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放比例,控制偏移量的大小", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "左Alt+左鍵可獲取鼠標指針處的UV座標\n下方三組UV座標由上到下依次為向前向量、向上向量和目標平面上綁定點的UV座標\n註:左Alt鍵+滾輪可在模型的不同層間切換,手動輸入UV座標可以更加精確地綁定到目標位置", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "決定左Alt+左鍵快速選擇的模式\n(左Alt鍵+滾輪可改變範圍模式下的選擇範圍)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "配置的名稱", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "被選中的模型的紋理的id(不是完整的id也可以識別),儲存時可以縮短一部分以便於程序識別\n比如將minecraft:textures/entity/player/slim/alex.png縮短為minecraft:textures/entity/player/", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打開全局配置屏幕\n(需要安裝Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "全部", + "screen.widget.xtracr_realcamera.modelView_configs": "配置", + "screen.widget.xtracr_realcamera.modelView_copy": "複製", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", + "screen.widget.xtracr_realcamera.modelView_disable": "禁用", + "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", "screen.widget.xtracr_realcamera.modelView_export": "導出", - "screen.widget.xtracr_realcamera.modelView_selecting": "選擇", "screen.widget.xtracr_realcamera.modelView_forwardVector": "向前向量", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上向量", - "screen.widget.xtracr_realcamera.modelView_position": "目標平面", - "screen.widget.xtracr_realcamera.modelView_save": "儲存", - "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", - "screen.widget.xtracr_realcamera.modelView_all": "全部", - "screen.widget.xtracr_realcamera.modelView_part": "部分", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "選擇模式", - "screen.widget.xtracr_realcamera.modelView_single": "單選", + "screen.widget.xtracr_realcamera.modelView_import": "導入", "screen.widget.xtracr_realcamera.modelView_multiple": "多選", - "screen.widget.xtracr_realcamera.modelView_range": "範圍", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "切換滑塊到輸入框", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "切換輸入框到滑塊", "screen.widget.xtracr_realcamera.modelView_offsetX": "X偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z偏移量 = %s", + "screen.widget.xtracr_realcamera.modelView_part": "部分", + "screen.widget.xtracr_realcamera.modelView_paste": "貼上", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰角 = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "翻滾角 = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "禁用", + "screen.widget.xtracr_realcamera.modelView_position": "目標平面", "screen.widget.xtracr_realcamera.modelView_preview": "預覽", - "screen.widget.xtracr_realcamera.modelView_configs": "配置", - "screen.widget.xtracr_realcamera.modelView_copy": "複製", - "screen.widget.xtracr_realcamera.modelView_paste": "貼上", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", - "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", - "screen.tooltip.xtracr_realcamera.modelView_export": "導出當前配置到剪貼簿", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "導出成功!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "導出失敗:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "左Alt+左鍵可獲取鼠標指針處的UV座標\n下方三組UV座標由上到下依次為向前向量、向上向量和目標平面上綁定點的UV座標\n註:左Alt鍵+滾輪可在模型的不同層間切換,手動輸入UV座標可以更加精確地綁定到目標位置", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "被選中的模型的紋理的id(不是完整的id也可以識別),儲存時可以縮短一部分以便於程序識別\n比如將minecraft:textures/entity/player/slim/alex.png縮短為minecraft:textures/entity/player/", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "被藍框包含的部分會被禁用\n可在左側材質視圖中鼠標左鍵框選,其它鍵取消選擇\n左Alt+左鍵可快速選擇被鼠標指針指向的部分", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "決定左Alt+左鍵快速選擇的模式\n(左Alt鍵+滾輪可改變範圍模式下的選擇範圍)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "選中的矩形編號\n(0表示不選中)\n可通過空格或回車鍵定位到當前選中的矩形(當正在輸入時,按兩次即可定位)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "刪除選中的矩形\n(或使用Delete鍵)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "當禁用時,攝像頭與模型的相對關係不會變化,但攝像頭的對應屬性不會被本模組修改", - "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放比例,控制偏移量的大小", - "screen.tooltip.xtracr_realcamera.modelView_depth": "全部頂點到屏幕距離均小於該值的面不會被渲染", - "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "配置的名稱", - "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用設置\n全局禁用設置在配置屏幕中", - "screen.tooltip.xtracr_realcamera.modelView_configs": "已儲存的配置", - "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打開全局配置屏幕\n(需要安裝Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "複製所有禁用設置", - "screen.tooltip.xtracr_realcamera.modelView_paste": "貼上剪貼簿中的所有禁用設置到當前配置\n(不會覆蓋同名設置)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名稱不能為空!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材質id不能為空!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁用設置的名稱" + "screen.widget.xtracr_realcamera.modelView_range": "範圍", + "screen.widget.xtracr_realcamera.modelView_roll": "翻滾角 = %s", + "screen.widget.xtracr_realcamera.modelView_save": "儲存", + "screen.widget.xtracr_realcamera.modelView_selecting": "選擇", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "選擇模式", + "screen.widget.xtracr_realcamera.modelView_single": "單選", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "切換輸入框到滑塊", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "切換滑塊到輸入框", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上向量", + "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", + "screen.xtracr_realcamera.modelView_title": "模型視圖" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/zh_tw.json b/common/src/main/resources/assets/realcamera/lang/zh_tw.json index 0b23af1c..96053fb9 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_tw.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_tw.json @@ -1,135 +1,132 @@ { - "general.xtracr_realcamera.modName": "Real Camera", - "key.xtracr_realcamera.modelViewScreen": "打開模型視圖界面", - "key.xtracr_realcamera.togglePerspective": "開啟/關閉", - "key.xtracr_realcamera.activeConfigIndexPREV": "切換到上一個配置", - "key.xtracr_realcamera.activeConfigIndexNEXT": "切換到下一個配置", - "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", - "key.xtracr_realcamera.toggleAdjustMode": "切換調整模式", - "key.xtracr_realcamera.toggleCameraMode": "切換攝像頭模式", - "key.xtracr_realcamera.adjustUP": "向上調整", - "key.xtracr_realcamera.adjustDOWN": "向下調整", - "key.xtracr_realcamera.adjustFRONT": "向前調整", - "key.xtracr_realcamera.adjustBACK": "向後調整", - "key.xtracr_realcamera.adjustLEFT": "向左調整", - "key.xtracr_realcamera.adjustRIGHT": "向右調整", - "modmenu.descriptionTranslation.realcamera": "使第一人稱視角下的攝像頭更加真實。", - - "config.category.xtracr_realcamera.general": "通用", "config.category.xtracr_realcamera.binding": "綁定模式", - "config.category.xtracr_realcamera.classic": "經典模式", "config.category.xtracr_realcamera.cameraOffset": "攝像頭偏移", - "config.category.xtracr_realcamera.centerOffset": "旋轉中心偏移", "config.category.xtracr_realcamera.cameraRotation": "攝像頭旋轉", - "config.tooltip.xtracr_realcamera.classicOffset": "攝像頭相對旋轉中心的偏移值", - "config.tooltip.xtracr_realcamera.classicOffset_n": "注: 玩家的前方、上方和左方分別為X、Y和Z軸", - "config.tooltip.xtracr_realcamera.centerOffset": "旋轉中心相對頭部的偏移值", - "config.tooltip.xtracr_realcamera.cameraRotation": "額外的攝像頭旋轉角度", - "config.tooltip.xtracr_realcamera.cameraRotation_n": "注:俯仰、偏航和翻滾分別是以左方、上方和前方為軸的旋轉", - - "config.option.xtracr_realcamera.enabled": "開啟功能", - "config.option.xtracr_realcamera.isClassic": "經典模式", - "config.option.xtracr_realcamera.dynamicCrosshair": "動態十字準心", - "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", + "config.category.xtracr_realcamera.centerOffset": "旋轉中心偏移", + "config.category.xtracr_realcamera.classic": "經典模式", + "config.category.xtracr_realcamera.general": "通用", + "config.option.xtracr_realcamera.activeConfigIndex": "當前配置索引", + "config.option.xtracr_realcamera.adjustOffset": "調整攝像頭偏移", "config.option.xtracr_realcamera.adjustStep": "調整步長", - "config.option.xtracr_realcamera.classicAdjustMode": "調整模式", - "config.option.xtracr_realcamera.scale": "縮放比例", + "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留帧数", "config.option.xtracr_realcamera.cameraOffset": "攝像頭%s偏移", "config.option.xtracr_realcamera.centerOffset": "旋轉中心%s偏移", - "config.option.xtracr_realcamera.pitch": "俯仰角", - "config.option.xtracr_realcamera.yaw": "偏航角", - "config.option.xtracr_realcamera.roll": "翻滾角", - "config.option.xtracr_realcamera.toModelViewScreen": "詳細設置請前往%s界面(需設置快捷鍵來打開它)", - "config.option.xtracr_realcamera.screenModifierKey": "%s界面修飾鍵", - "config.option.xtracr_realcamera.legacyBindingMode": "舊綁定模式", - "config.option.xtracr_realcamera.adjustOffset": "調整攝像頭偏移", - "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱藏綁定失敗消息", - "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物體", - "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", - "config.option.xtracr_realcamera.bindResultRetentionFrames": "綁定結果保留帧数", - "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑係數", - "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑係數", - "config.option.xtracr_realcamera.activeConfigIndex": "當前配置索引", + "config.option.xtracr_realcamera.classicAdjustMode": "調整模式", "config.option.xtracr_realcamera.disableConfig": "禁用配置", - "config.option.xtracr_realcamera.disableWhenSneaking": "潛行时禁用主要功能", + "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...時禁用主要功能", + "config.option.xtracr_realcamera.disableRenderItems": "在手持...時禁用渲染", "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSneaking": "潛行时禁用主要功能", "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑係數", + "config.option.xtracr_realcamera.dynamicCrosshair": "動態十字準心", + "config.option.xtracr_realcamera.enabled": "開啟功能", + "config.option.xtracr_realcamera.hideBindingFailureMessage": "隱藏綁定失敗消息", + "config.option.xtracr_realcamera.isClassic": "經典模式", + "config.option.xtracr_realcamera.legacyBindingMode": "舊綁定模式", "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", - "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...時禁用主要功能", - "config.option.xtracr_realcamera.disableRenderItems": "在手持...時禁用渲染", - "config.tooltip.xtracr_realcamera.isClassic": "經典模式只對攝像頭的位置和旋轉做簡單的修改", - "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在開啟狀態下,十字準心會隨著玩家的視線移動,確保命中結果不受影響\n在安裝了Jade、WTHIT或類似模組時建議啟用", - "config.tooltip.xtracr_realcamera.renderModel": "在第一人稱視角下渲染玩家模型", + "config.option.xtracr_realcamera.pitch": "俯仰角", + "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", + "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物體", + "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", + "config.option.xtracr_realcamera.roll": "翻滾角", + "config.option.xtracr_realcamera.rotationSmoothFactor": "旋轉平滑係數", + "config.option.xtracr_realcamera.scale": "縮放比例", + "config.option.xtracr_realcamera.screenModifierKey": "%s界面修飾鍵", + "config.option.xtracr_realcamera.toModelViewScreen": "詳細設置請前往%s界面(需設置快捷鍵來打開它)", + "config.option.xtracr_realcamera.yaw": "偏航角", + "config.tooltip.xtracr_realcamera.activeConfigIndex": "當前綁定的配置索引,0表示允許綁定任何有效配置", + "config.tooltip.xtracr_realcamera.adjustOffset": "當前按下調整鍵時是調整攝像頭的偏移還是旋轉", "config.tooltip.xtracr_realcamera.adjustStep": "每步調整的角度1/100或長度", + "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在綁定失敗的數帧内,沿用上个成功的綁定結果", + "config.tooltip.xtracr_realcamera.cameraRotation": "額外的攝像頭旋轉角度", + "config.tooltip.xtracr_realcamera.cameraRotation_n": "注:俯仰、偏航和翻滾分別是以左方、上方和前方為軸的旋轉", + "config.tooltip.xtracr_realcamera.centerOffset": "旋轉中心相對頭部的偏移值", "config.tooltip.xtracr_realcamera.classicAdjustMode": "決定當前按下調整鍵時調整哪一個", - "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", + "config.tooltip.xtracr_realcamera.classicOffset": "攝像頭相對旋轉中心的偏移值", + "config.tooltip.xtracr_realcamera.classicOffset_n": "注: 玩家的前方、上方和左方分別為X、Y和Z軸", + "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三種匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 標簽匹配`#`開頭(如`#minecraft:tools`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", + "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相機位移平滑系数,值越大越平滑", + "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在開啟狀態下,十字準心會隨著玩家的視線移動,確保命中結果不受影響\n在安裝了Jade、WTHIT或類似模組時建議啟用", + "config.tooltip.xtracr_realcamera.isClassic": "經典模式只對攝像頭的位置和旋轉做簡單的修改", "config.tooltip.xtracr_realcamera.legacyBindingMode": "使用舊版本(v0.5)的綁定模式,僅支援原版模型和基於原版模型的動作\n開啟後可在%s界面的'LEGACY_MODE'中設置屬性", - "config.tooltip.xtracr_realcamera.adjustOffset": "當前按下調整鍵時是調整攝像頭的偏移還是旋轉", + "config.tooltip.xtracr_realcamera.outTick": "玩家停止特定狀態後重啟主要功能的時間(1 tick = 0.05秒)", + "config.tooltip.xtracr_realcamera.renderModel": "在第一人稱視角下渲染玩家模型", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它會卡在玩家身體裡的物體", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染時機重新渲染模型,以避免一些因提前渲染導致的視覺問題", - "config.tooltip.xtracr_realcamera.outTick": "玩家停止特定狀態後重啟主要功能的時間(1 tick = 0.05秒)", - "config.tooltip.xtracr_realcamera.bindResultRetentionFrames": "在綁定失敗的數帧内,沿用上个成功的綁定結果", - "config.tooltip.xtracr_realcamera.displacementSmoothFactor": "相機位移平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相機旋轉平滑系数,值越大越平滑", - "config.tooltip.xtracr_realcamera.activeConfigIndex": "當前綁定的配置索引,0表示允許綁定任何有效配置", - "config.tooltip.xtracr_realcamera.disableRenderItems": "支持三種匹配方式:\n1. 通配符`*`匹配(如`minecraft:*sword`)\n2. 標簽匹配`#`開頭(如`#minecraft:tools`)\n3. 直接物品ID(如`minecraft:diamond_sword`)", - + "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", + "general.xtracr_realcamera.modName": "Real Camera", + "key.category.xtracr_realcamera.general": "Real Camera", + "key.xtracr_realcamera.activeConfigIndexNEXT": "切換到下一個配置", + "key.xtracr_realcamera.activeConfigIndexPREV": "切換到上一個配置", + "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", + "key.xtracr_realcamera.adjustBACK": "向後調整", + "key.xtracr_realcamera.adjustDOWN": "向下調整", + "key.xtracr_realcamera.adjustFRONT": "向前調整", + "key.xtracr_realcamera.adjustLEFT": "向左調整", + "key.xtracr_realcamera.adjustRIGHT": "向右調整", + "key.xtracr_realcamera.adjustUP": "向上調整", + "key.xtracr_realcamera.modelViewScreen": "打開模型視圖界面", + "key.xtracr_realcamera.toggleAdjustMode": "切換調整模式", + "key.xtracr_realcamera.toggleCameraMode": "切換攝像頭模式", + "key.xtracr_realcamera.togglePerspective": "開啟/關閉", "message.xtracr_realcamera.bindingFailed": "[%s]: 綁定失敗,請前往%s界面手動設置(鍵位:%s)", - - "screen.xtracr_realcamera.modelView_title": "模型視圖", - "screen.widget.xtracr_realcamera.modelView_import": "導入", + "modmenu.descriptionTranslation.realcamera": "使第一人稱視角下的攝像頭更加真實。", + "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "當禁用時,攝像頭與模型的相對關係不會變化,但攝像頭的對應屬性不會被本模組修改", + "screen.tooltip.xtracr_realcamera.modelView_configs": "已儲存的配置", + "screen.tooltip.xtracr_realcamera.modelView_copy": "複製所有禁用設置", + "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "刪除選中的矩形\n(或使用Delete鍵)", + "screen.tooltip.xtracr_realcamera.modelView_depth": "全部頂點到屏幕距離均小於該值的面不會被渲染", + "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用設置\n全局禁用設置在配置屏幕中", + "screen.tooltip.xtracr_realcamera.modelView_disableMode": "被藍框包含的部分會被禁用\n可在左側材質視圖中鼠標左鍵框選,其它鍵取消選擇\n左Alt+左鍵可快速選擇被鼠標指針指向的部分", + "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁用設置的名稱", + "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名稱不能為空!", + "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材質id不能為空!", + "screen.tooltip.xtracr_realcamera.modelView_export": "導出當前配置到剪貼簿", + "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "導出失敗:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "導出成功!", + "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "選中的矩形編號\n(0表示不選中)\n可通過空格或回車鍵定位到當前選中的矩形(當正在輸入時,按兩次即可定位)", + "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", + "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", + "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", + "screen.tooltip.xtracr_realcamera.modelView_paste": "貼上剪貼簿中的所有禁用設置到當前配置\n(不會覆蓋同名設置)", + "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", + "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", + "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放比例,控制偏移量的大小", + "screen.tooltip.xtracr_realcamera.modelView_selecting": "左Alt+左鍵可獲取鼠標指針處的UV座標\n下方三組UV座標由上到下依次為向前向量、向上向量和目標平面上綁定點的UV座標\n註:左Alt鍵+滾輪可在模型的不同層間切換,手動輸入UV座標可以更加精確地綁定到目標位置", + "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "決定左Alt+左鍵快速選擇的模式\n(左Alt鍵+滾輪可改變範圍模式下的選擇範圍)", + "screen.tooltip.xtracr_realcamera.modelView_targetName": "配置的名稱", + "screen.tooltip.xtracr_realcamera.modelView_textureId": "被選中的模型的紋理的id(不是完整的id也可以識別),儲存時可以縮短一部分以便於程序識別\n比如將minecraft:textures/entity/player/slim/alex.png縮短為minecraft:textures/entity/player/", + "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打開全局配置屏幕\n(需要安裝Cloth Config API)", + "screen.widget.xtracr_realcamera.modelView_all": "全部", + "screen.widget.xtracr_realcamera.modelView_configs": "配置", + "screen.widget.xtracr_realcamera.modelView_copy": "複製", + "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", + "screen.widget.xtracr_realcamera.modelView_disable": "禁用", + "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", "screen.widget.xtracr_realcamera.modelView_export": "導出", - "screen.widget.xtracr_realcamera.modelView_selecting": "選擇", "screen.widget.xtracr_realcamera.modelView_forwardVector": "向前向量", - "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上向量", - "screen.widget.xtracr_realcamera.modelView_position": "目標平面", - "screen.widget.xtracr_realcamera.modelView_save": "儲存", - "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", - "screen.widget.xtracr_realcamera.modelView_all": "全部", - "screen.widget.xtracr_realcamera.modelView_part": "部分", - "screen.widget.xtracr_realcamera.modelView_selectionMode": "選擇模式", - "screen.widget.xtracr_realcamera.modelView_single": "單選", + "screen.widget.xtracr_realcamera.modelView_import": "導入", "screen.widget.xtracr_realcamera.modelView_multiple": "多選", - "screen.widget.xtracr_realcamera.modelView_range": "範圍", - "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "切換滑塊到輸入框", - "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "切換輸入框到滑塊", "screen.widget.xtracr_realcamera.modelView_offsetX": "X偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetY": "Y偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z偏移量 = %s", + "screen.widget.xtracr_realcamera.modelView_part": "部分", + "screen.widget.xtracr_realcamera.modelView_paste": "貼上", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰角 = %s", - "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", - "screen.widget.xtracr_realcamera.modelView_roll": "翻滾角 = %s", - "screen.widget.xtracr_realcamera.modelView_disable": "禁用", + "screen.widget.xtracr_realcamera.modelView_position": "目標平面", "screen.widget.xtracr_realcamera.modelView_preview": "預覽", - "screen.widget.xtracr_realcamera.modelView_configs": "配置", - "screen.widget.xtracr_realcamera.modelView_copy": "複製", - "screen.widget.xtracr_realcamera.modelView_paste": "貼上", - "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", - "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", - "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", - "screen.tooltip.xtracr_realcamera.modelView_export": "導出當前配置到剪貼簿", - "screen.tooltip.xtracr_realcamera.modelView_exportSucceeded": "導出成功!", - "screen.tooltip.xtracr_realcamera.modelView_exportFailed": "導出失敗:\n%s", - "screen.tooltip.xtracr_realcamera.modelView_selecting": "左Alt+左鍵可獲取鼠標指針處的UV座標\n下方三組UV座標由上到下依次為向前向量、向上向量和目標平面上綁定點的UV座標\n註:左Alt鍵+滾輪可在模型的不同層間切換,手動輸入UV座標可以更加精確地綁定到目標位置", - "screen.tooltip.xtracr_realcamera.modelView_textureId": "被選中的模型的紋理的id(不是完整的id也可以識別),儲存時可以縮短一部分以便於程序識別\n比如將minecraft:textures/entity/player/slim/alex.png縮短為minecraft:textures/entity/player/", - "screen.tooltip.xtracr_realcamera.modelView_disableMode": "被藍框包含的部分會被禁用\n可在左側材質視圖中鼠標左鍵框選,其它鍵取消選擇\n左Alt+左鍵可快速選擇被鼠標指針指向的部分", - "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "決定左Alt+左鍵快速選擇的模式\n(左Alt鍵+滾輪可改變範圍模式下的選擇範圍)", - "screen.tooltip.xtracr_realcamera.modelView_focusedRectangleNumber": "選中的矩形編號\n(0表示不選中)\n可通過空格或回車鍵定位到當前選中的矩形(當正在輸入時,按兩次即可定位)", - "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "刪除選中的矩形\n(或使用Delete鍵)", - "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "當禁用時,攝像頭與模型的相對關係不會變化,但攝像頭的對應屬性不會被本模組修改", - "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放比例,控制偏移量的大小", - "screen.tooltip.xtracr_realcamera.modelView_depth": "全部頂點到屏幕距離均小於該值的面不會被渲染", - "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", - "screen.tooltip.xtracr_realcamera.modelView_targetName": "配置的名稱", - "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用設置\n全局禁用設置在配置屏幕中", - "screen.tooltip.xtracr_realcamera.modelView_configs": "已儲存的配置", - "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", - "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打開全局配置屏幕\n(需要安裝Cloth Config API)", - "screen.tooltip.xtracr_realcamera.modelView_copy": "複製所有禁用設置", - "screen.tooltip.xtracr_realcamera.modelView_paste": "貼上剪貼簿中的所有禁用設置到當前配置\n(不會覆蓋同名設置)", - "screen.tooltip.xtracr_realcamera.modelView_emptyName": "名稱不能為空!", - "screen.tooltip.xtracr_realcamera.modelView_emptyTextureId": "材質id不能為空!", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", - "screen.tooltip.xtracr_realcamera.modelView_disabledName": "禁用設置的名稱" + "screen.widget.xtracr_realcamera.modelView_range": "範圍", + "screen.widget.xtracr_realcamera.modelView_roll": "翻滾角 = %s", + "screen.widget.xtracr_realcamera.modelView_save": "儲存", + "screen.widget.xtracr_realcamera.modelView_selecting": "選擇", + "screen.widget.xtracr_realcamera.modelView_selectionMode": "選擇模式", + "screen.widget.xtracr_realcamera.modelView_single": "單選", + "screen.widget.xtracr_realcamera.modelView_toggleFieldToSlider": "切換輸入框到滑塊", + "screen.widget.xtracr_realcamera.modelView_toggleSliderToField": "切換滑塊到輸入框", + "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上向量", + "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", + "screen.xtracr_realcamera.modelView_title": "模型視圖" } \ No newline at end of file diff --git a/common/src/main/resources/realcamera-common.mixins.json b/common/src/main/resources/realcamera-common.mixins.json index 21830b03..1f026f74 100644 --- a/common/src/main/resources/realcamera-common.mixins.json +++ b/common/src/main/resources/realcamera-common.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8.5", "package": "com.xtracr.realcamera.mixin", - "compatibilityLevel": "JAVA_21", + "compatibilityLevel": "JAVA_25", "mixins": [ ], "client": [ @@ -14,11 +14,12 @@ "MixinItemInHandRenderer", "MixinLevelRenderer", "MixinLocalPlayer", - "MixinPlayerRenderer", "MixinStuckInBodyLayer", - "accessor.CameraAccessor", - "accessor.GameRendererAccessor", - "accessor.PlayerRendererAccessor" + "accessor.AvatarRendererAccessor", + "accessor.CustomFeatureRenderer$StorageAccessor", + "accessor.GuiGraphicsExtractorAccessor", + "accessor.ModelFeatureRenderer$StorageAccessor", + "accessor.ModelPartFeatureRenderer$StorageAccessor" ], "server": [ ], diff --git a/common/src/main/resources/realcamera.accesswidener b/common/src/main/resources/realcamera.accesswidener index 246b8795..869e8c7c 100644 --- a/common/src/main/resources/realcamera.accesswidener +++ b/common/src/main/resources/realcamera.accesswidener @@ -1,2 +1,3 @@ -accessWidener v2 named -extendable method net/minecraft/client/renderer/MultiBufferSource$BufferSource endBatch (Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/BufferBuilder;)V \ No newline at end of file +accessWidener v2 official +accessible class net/minecraft/client/gui/GuiGraphicsExtractor$ScissorStack +extendable method net/minecraft/client/renderer/MultiBufferSource$BufferSource endBatch (Lnet/minecraft/client/renderer/rendertype/RenderType;Lcom/mojang/blaze3d/vertex/BufferBuilder;)V \ No newline at end of file diff --git a/fabric/build.gradle b/fabric/build.gradle deleted file mode 100644 index d3fa27df..00000000 --- a/fabric/build.gradle +++ /dev/null @@ -1,72 +0,0 @@ -plugins { - id "com.gradleup.shadow" version "9.3.0" -} - -base { - archivesName = rootProject.mod_id + "-" + rootProject.minecraft_version + "-fabric" -} - -architectury { - platformSetupLoomIde() - fabric() -} - -configurations { - common - shadowCommon - compileClasspath.extendsFrom common - runtimeClasspath.extendsFrom common - developmentFabric.extendsFrom common -} - -dependencies { - modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" - - // Cloth Config - modRuntimeOnly "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_config_version}" - // Modmenu - modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { - exclude(group: "net.fabricmc.fabric-api") - } - -// modImplementation "org.antlr:antlr4-runtime:4.13.1" -// modImplementation "io.github.douira:glsl-transformer:2.0.1" -// modImplementation "org.anarres:jcpp:1.4.14" -// modImplementation "maven.modrinth:iris:1.8.8+1.21.1-fabric" -// modImplementation "maven.modrinth:sodium:mc1.21.1-0.6.13-fabric" - - common(project(path: ":common", configuration: "namedElements")) { transitive false } - shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false } -} - -processResources { - inputs.property "version", project.version - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -shadowJar { - exclude "architectury.common.json" - configurations = [project.configurations.shadowCommon] - archiveClassifier = "dev-shadow" -} - -remapJar { - injectAccessWidener = true - inputFile.set shadowJar.archiveFile - dependsOn shadowJar -} - -sourcesJar { - def commonSources = project(":common").sourcesJar - dependsOn commonSources - from commonSources.archiveFile.map { zipTree(it) } -} - -components.java { - withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { - skip() - } -} diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts new file mode 100644 index 00000000..8adb3df2 --- /dev/null +++ b/fabric/build.gradle.kts @@ -0,0 +1,102 @@ +plugins { + id("net.fabricmc.fabric-loom") + id("maven-publish") +} + +val modId = project.property("mod_id") as String +val javaVersion = project.property("java_version") as String +val minecraftVersion = project.property("minecraft_version") as String +val fabricLoaderVersion = project.property("fabric_loader_version") as String +val fabricApiVersion = project.property("fabric_api_version") as String + +val clothConfigVersion = project.property("cloth_config_version") as String +val modMenuVersion = project.property("modmenu_version") as String + +base { + archivesName = "$modId-$minecraftVersion-fabric" +} + +val commonProject = project(":common") + +project.evaluationDependsOn(commonProject.path) + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(javaVersion)) + } + withSourcesJar() +} + +tasks.withType { + options.encoding = "UTF-8" + options.release.set(javaVersion.toInt()) +} + +dependencies { + minecraft("com.mojang:minecraft:$minecraftVersion") + + implementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") + implementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") + + // Cloth Config + runtimeOnly("me.shedaniel.cloth:cloth-config-fabric:$clothConfigVersion") + // Modmenu + implementation("com.terraformersmc:modmenu:$modMenuVersion") { + exclude(group = "net.fabricmc.fabric-api") + } + + implementation(commonProject) +} + +loom { + accessWidenerPath.set(project(":common").file("src/main/resources/realcamera.accesswidener")) + + mods { + create(modId) { + sourceSet(sourceSets.main.get()) + } + } +} + +sourceSets { + named("main") { + resources { + srcDir(commonProject.sourceSets.main.get().resources) + } + } +} + +tasks.processResources { + inputs.property("version", project.version) + filesMatching("fabric.mod.json") { + expand("version" to project.version) + } +} + +tasks.jar { + from(sourceSets.main.get().output) + from(commonProject.sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +val sourcesJarTask = tasks.named("sourcesJar") { + from(sourceSets.main.get().allSource) + from(commonProject.sourceSets.main.get().allSource) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + archiveClassifier.set("sources") +} + +artifacts { + archives(tasks.jar) + archives(sourcesJarTask) +} + +publishing { + publications { + register("fabricJar") { + artifactId = base.archivesName.get() + artifact(tasks.jar) + artifact(sourcesJarTask) + } + } +} diff --git a/fabric/src/main/java/com/xtracr/realcamera/EventHandler.java b/fabric/src/main/java/com/xtracr/realcamera/EventHandler.java deleted file mode 100644 index 9bed039d..00000000 --- a/fabric/src/main/java/com/xtracr/realcamera/EventHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.xtracr.realcamera; - -import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.util.CrosshairUtil; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import net.minecraft.client.Minecraft; - -public class EventHandler { - public static void onWorldRenderStart(WorldRenderContext context) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - CrosshairUtil.update(Minecraft.getInstance(), context.camera(), context.positionMatrix(), context.projectionMatrix()); - } - } -} diff --git a/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java b/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java index 9ffd9155..1b621dde 100644 --- a/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java +++ b/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java @@ -1,22 +1,32 @@ package com.xtracr.realcamera; +import com.xtracr.realcamera.renderer.gui.GuiCulledModelsRenderer; +import com.xtracr.realcamera.renderer.gui.GuiFlattenedModelsRenderer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper; +import net.fabricmc.fabric.api.client.rendering.v1.PictureInPictureRendererRegistry; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.KeyMapping; @Environment(EnvType.CLIENT) public class RealCameraFabric implements ClientModInitializer, RealCamera { @Override public void onInitializeClient() { initialize(); - KeyMappings.register(KeyBindingHelper::registerKeyBinding); + + KeyMapping.Category.register(KeyMappings.GENERAL.id()); + KeyMappings.register(KeyMappingHelper::registerKeyMapping); + registerPictureInPictureRenderers(); ClientTickEvents.END_CLIENT_TICK.register(KeyMappings::handle); - WorldRenderEvents.START.register(EventHandler::onWorldRenderStart); + } + + private void registerPictureInPictureRenderers() { + PictureInPictureRendererRegistry.register(ctx -> new GuiCulledModelsRenderer(ctx.bufferSource())); + PictureInPictureRendererRegistry.register(ctx -> new GuiFlattenedModelsRenderer(ctx.bufferSource())); } @Override diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 39d04c4d..f4fd8a17 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -27,11 +27,12 @@ "realcamera.mixins.json", "realcamera-common.mixins.json" ], + "accessWidener": "realcamera.accesswidener", "depends": { - "fabricloader": "*", + "fabricloader": ">=0.18.4", "fabric-api": "*", - "minecraft": "1.21.1", - "java": ">=21" + "minecraft": "~26.1", + "java": ">=25" }, "recommends": { "modmenu": "*", diff --git a/fabric/src/main/resources/realcamera.mixins.json b/fabric/src/main/resources/realcamera.mixins.json index 16ce00cc..6e60890b 100644 --- a/fabric/src/main/resources/realcamera.mixins.json +++ b/fabric/src/main/resources/realcamera.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8.5", "package": "com.xtracr.realcamera.mixin", - "compatibilityLevel": "JAVA_21", + "compatibilityLevel": "JAVA_25", "mixins": [ ], "client": [ diff --git a/gradle.properties b/gradle.properties index 8adf3338..e08ad7e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,20 @@ # Done to increase the memory available to gradle. org.gradle.jvmargs=-Xmx4G -XX:+UseG1GC org.gradle.parallel=true -org.gradle.caching=true +org.gradle.configuration-cache=false ## Environment Properties -minecraft_version=1.21.1 +java_version=25 +minecraft_version=26.1.1 enabled_platforms=fabric,neoforge -fabric_loader_version=0.18.4 -neoforge_version=21.1.217 +loom_version=1.16-SNAPSHOT +fabric_loader_version=0.19.0 +neoforge_version=26.1.1.14-beta +moddev_version=2.0.141 ## Mod Properties mod_id=realcamera -mod_version=0.7.5-beta +mod_version=0.7.6-beta mod_group_id=com.xtracr.realcamera ## Dependencies -fabric_api_version=0.116.7+1.21.1 -cloth_config_version=15.0.140 -modmenu_version=11.0.3 +fabric_api_version=0.145.4+26.1.1 +cloth_config_version=26.1.154 +modmenu_version=18.0.0-alpha.8 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f8e1ee3125fe0768e9a76ee977ac089eb657005e..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch delta 39855 zcmXVXQ+QqP+jNu0*|BzP+qP}nwz(VIw(T}nV>Y(!G&aBf{_l6P4%W3!)^%g%nVF~W z0DSlpyulU;B=emaId5fcNe2nefbXcJWnFxsLk*?mq_P~dt9;cOC)+IDtQE$DaIp27 z%^+y8c5kTI5+gig#&1UYvO zan`mxLcb8HDf+ntw5C{uuKC^$86)hQm1?k;%Q0Gz?Ttaps1n@B#zSDf1eYFXJr}E4 zDz3R9AoHiXGh4~h>6%D`grmRGOQl0Z_r07G$X3@hKg1sVF>sUbuA^qDPq67(0I6$l zC6X=7=r0E9Ww1l72~tjyX%@9Y;-CV<8QJ7q3HWecsBjSai>o9H4YTtqCq@GH?VA%= za$^c@ay=bVvVIvx@-Z?NlDI=Nc@HupnRpC2atvd6G6D(%sFyDddy5c{kFiJDMsE`> zttcZ zXj<4Z+B`&Foi4P04nY=Xq`__c5`Ki7VI0fy$Rf&H{({!=truvb z-g#KDmuL(J3X@)+h3^<(S4CHwr>a?rg=%erBd+EAFeVSd4)b^sV9eN0_}yn?KX*Q2`K+{-;|%Y1;P3tBAW(xe7hr#WQ@VhNecl*bO18YCi?j=?HRVnP*# zlg9RskU;4p4+}&*Ewi^m9mej*U7scxZwvB5Pj^BlK<=V9J_uL+J2HW1MIUU3cCX%;gwwze1fWVc?G{-%G{PI}eSaE88C>k{r+$ z_9=-4Z8l?x5BLvJqkk1Yh?!>bw z7{b8F<6I@>u4W!*X6EL8d>oH3etSwZeRgxY{`uTj;ZjXpVqb%!F{#B;)9ctl5WgXm z6<`GalXe%D0M2E}+e*jXn7u!Z5C>Gvei>>qX2nxBon5vbcT>>O|2H)}M19CKp!U$) z4CZ{JOIDW{UlXoS?=-<(u_D1GvAfOBvE6FTWcry4Zn(e^lHNShvW^n?M~E9z(s>;X za>5nPoaF@@^Qdke z`gZL&pQ5)Ec}&Z!;)gW~eFm?e2A>b`>F&LxxqZ*G0p#Ay3N6{LCiL-o$JH2T3Ex-S z8`VRl`*e&t$XdGp*+JbjB?57Rdv9cyfA~CucCnA3Flu&jM0L92(G67(N)ji<0c)n?f-9Ia$+0s`Fhk}i`6>$Yp)6g`?dst$p-QCJg3p7b?jed`PM}Y_f)MvrwMfw8rji0)pBcj0XZL zt+OD!-0O0SC5@K>x-iQPwjp&e%f;O=j4`qC7)@1L%K08a%%kMxr)PUv#&BU>`%5nD z>6-G1^YWye=USMp)prM{44(YEh?5cIBjhdTFQpcxpk@Z*J|+}f-*S|bT!TXgce@%{#Sr2kk0!WYZHL!#GfYYcLo!ybkt7P?zeHN2pZGSU7I04y|i z2Yxn*+Xt0H*ihojh+pWjoWrsUxuBH2GcOAct_m$mwu?|!lfRC5r__n1)L+KDP@(yF z7AU6(5HWUZYzQfUU!g6X^Um@h#F)rs;~s(4GuZb*w@X>g2_WdcOBKg@Z?Bu?lvLPF z;TN_$8Msx+huNWMy#__i6>?YrE^`O zv$>4i?(2-O!>aU}PxPwQJi#f@xFI#!Ot#x1DcEcQV{8GNk$oxh9dkdnhi>Mk1jX37 z>g@pWmhfT|jy^4j8r@uO4|Sjrze}u$aRN9}|Ax))+KKL!wQK$kSarF7q){AvQy|X+ zr7{O^15tmmU0d_aX7$KH{}rf*_|-|t)U(+{(~p31Kg*YV!anHp7IY)=wbuLZ`DA{UI^!dIpy)NPbi6^08JN(ogkm3kkGvGM$0Y&)}B>WLlcw0LS zR1BXPb-k}A)h{b={8N07Gu5p#;>B%tLx45m`d6nCMDoEIpgoWpf1UxWeW$}A+ErcO ze^NKkAK6kr8m=qD_VXGeJTXCpT9o()t{Xx!fscP;8V4R3#)lb`R0+DcZ(fDBjy@S8 zJVs05hv0uRhQgFArtqJ<{C! zJF#%rAcfH8H)m96u)01aZiggco(N{rSUy(pWHyf{a_Lq#a`|iqg$*``^Ab7_ueGBp ztZv6IA>UQP1P=KVUkTJvBCPrBOxK<}`m5HwyY%?&H_{)bT1wYvskD~5`ABgmH_nL) z5bHspn^_|+V5Pg(rZpNk9o+*jIrJ1TigS{FjJ_@2mQesM8 zBv55Ulyu}_@CNOmSr`7cSbLtV4||?8ydC4TBoVWpV@_IyGUV?J=4tJuWVS9TEHjE< zA!-!(*N@cZ{XOOZbT|bqkDuh$=dh|xgYw0o(sh~Adp8mpc}ur-l*iA!CicwBX{jCV z@gLQlBB6?XiR_`WqxMP#+63OcsahCKVpqzF3I+OoVL9NCeP6^`$;6)SewkV#gRF^E zs3lUNq-xdK+oN)AK90g89>xv-_K{Y$ohSCs28V@Qe$5G~`H|6kLoJ&!844MXAQSz#T zGcbezwFz~h;ILR1jD-f+>_Zzt+IbnzwJ|%H5`9R0gm#!LAD-1DB;kFZc@!;L3mP1) zc%QAa9knp&dTN#p`?I+DI^vKr8a5J8jnVw=Zh|?P8XK!ra3gCu8y{7sj+0iOKW$+( z*Z4;Eg|g=#_(f|3q}{fB(tU_0ACkT#>c=+FK~Y5K-`Hbzz8DVdIS)pmdm>Xf?QA5D z8df|UfxzT|u-9a`tV;%MslLhy=frsBV|;?cg31$(nb}Ol2({r{ICK$U#zHPgXt;$U zCPWHCf}S_wswYBvGf;0I3K8E4kzI2S-BctkWy()bk7Qdh6=u|i0U>@L7JF=-)gJ$_r)av2Byo%Wf_8&)SJt5~gmZ~jb#>HFU5GlA4H1Mn2{#2Q!Vc^lRvuh-? z@r56MWb|87|HPc?x9f5V|C>W0IdrUL+|ri9ZZ~UL`t}T%y@ss(xO*mvXK8WLvg9V8 zvU!3E3Ar=(6YqFZe^dqu5aIMNSjT!P_YIq){H*rUPLm>;wPulgKoE!Pq@O3F@%|Vi zc&F%5k9FKx&l!um$(gy1!u#p|?0`{c;%V&To75hC4h^U9Xd%D6qo!|zLdisJ=R9qC zAz8ybfYEZP^XKYOB-UF);rR6aS^Zs0#5;Df;Z<))5gS$j;?N5;d(E0tJAD4k{UMdy z@Y5wd=~Y%Q+0T)xLS{{agY{3`q7y&Xh+!=aK4aSN$9?l;?Bp5*!8EMidRkyQOmV&bSG&_-OiU0 zmB+5g3ttOk0mBk&yndnf#x`3t|E~5$>>m@uZbwY$EigWLXlE+MFOt%UXFROnTztM{ju!NFCI97J+TV>O%Bcmm z1j>B10jTgG9oqw6lJd%$%oKzlsI*ILZ6S|i$opuu-7~tx#q*Tk)j$9IsL%Za@5Qrp zls&@A8Zoj)^BHsIW9UDGmoy;X=tS1?Yl|~{K}aB}5Qz4ZQRW6)@2u3#a2`PM?`L=Y z^}0hDZ*b2M5+9pK0R|nhS1HCT1J~Vg*nauH^`~D!b%oqWKOe&#O$OXAs1rL+MJ`UY$1Qp+YpTNG9TqN;PDpV^{7-Gf<8}EdVuAv&T z4MlPWU6Njyh}1ERkCVs`oo|4B^?&~g%QKB)T|cmk&%`^vW1t%UB$d#x`+` zYvh&J=q2~C#B|Yd9Gp1t3*F?N-13XXxWQE3FmjwSqWz4tfBxbAOzg2^y3ojQp6c(1 zopWcG>Wi5Ah4mi}mwj#^8A5;i#)I_jo04pDa|$r|l~@(zZYMsBj_9_r8O4Es3qzIaQz?G(+*U;rq%r&CP$j zk^j5r>stdLcz2+$FM61_c5;%RnBHEU)w8L};?-cp+56ym?%Gc_K@hoar?4QtlaK9> zzVT(KKH~yN!?O)Hs%ohbA>I=}xzx5^=UUw(vQogjbLFO=j$`(d6lEMO@GQV+`QnFeT}5V{s_qkiyll0!%(ORh zl+kA9%oZkwqVa6;Tj&9v8Fb20Rv`pfYnkSbmYqNAS4l$43=vK8e z)==0n3G{S5Q+@-LR&S(#R4EQxBqJ}+hDc= zIq+}a(vurf@c;2VRS>wWEXugNkeXg}OOvdy!y!otDjV4fDiP|tXj$jL&xTI&U%DYc zZ{++wLYp?Stmkh6DK~VGhiPt{nVT<&=aT-4f7fF^qLv1Tm zt9nYy)VmKZv^kz?ld8GNMUfdo>Dwqr+a~$tw=rMqG(Gs-Z9viMc~aHBWk=WilW=Uq zQTrRfe4@HP2Ct5(_SxSYvuy{OFzT$^MWiO!VK=eninT&4p(UYyWf4CvDk2yG5*Jmp z&-R+l;lm=6*jURB!suB#?9Gp4;|BCiBU94a??Ym+9)ogR3ER4aH2g2&A)5iGRa47+ zXV^FoU+7Tor=YN2?#(t5)=8x+M_mKI6U4__Cotb(7kW_Iu6z+sx6kuICl!empcwH9 zXoD6FhAb`%0cWDjMueBK2Gqd|&_Y+MxTi%hJ&~gOd+nds*luf~@v);*;H%K~Up&*C8F5m? zdrmqo(e?;A_f^v(cUx_}kW-KeXfyNvbVH}f3%h}E4r}3sfy-kKX*1q9kt=K?b<5{L z69*rI$ur&YuxO=GPAFpvJ!~El31H3l?QCez(bd(}8e?@clvadO#Z%JnVJwlQMkGNC z3oEpZ1=X7s>_CbJQ@?v>`>L7il6aF(xF$eIFk|+?3}ZJ{O-|V>FN_Cz!~Fz&v|8L= zMn;>^1WC`pE>6v>TUsH?z5G-~cZtQa7xt`=qd=|@rUQx;kYoO#CMIUObu4-y|LdbH z3zG@W!J$HFg_v8&?jQ8%2$Kionep!Plha|p*HKrg)i3vY4h_Jzu&yn4ydJ)ekixiS ziG(_M?j2@ci=WNs5x4mOPHr=I1w=(Y^h54* zM__W((O%*I>vQoi_u=GSN@q~koRF-bLU#=pS%mp1G_tUIrFfN4RDlgLw8O8?4Ix?hsWrY;IR z2p&OZ=rxeiiRmhZ$)SjMB;-d3)FQHUakF7#8A-0Xha4-|g+H4xQ?x-Drr0u9jo6OH z9nF*NWnc9HYScp^_@>WcqH~!GViIRDtFYJ;Am(jDQ0o?wY8C|69T7xRxVSm$D+vay zmu?2#IG`-5NNmiie$;j0^ha(_QKOkgoXqy!w$aIqGW;2M+LTjJqDZc|0G6&mxr>fN>^JPL$ry>Pf!|Y##OZ)xbP#)f4 zBCgh{$sXVWp3t6~fLz1g%V2z7>~{Yq&pN*T(|gi7It*?D4gYv7Mx)tmJPmKTBcQ2x zR~%IQsUliPe%2Kh9=|zyOzdL*_4C@ftbswsSUvW!#Vr~mycae1-417`hY?EIgau{% zw2^nzH2<_Vd(Ux!$N%c|pk;Ym^iQ$&2mjx}GY^eCd5a7xS&#+@QbZF*=bvA4sMM8( z*Mh{*S6Z91H&wIieI|-jBpSv6^kke~Ht4U^|8aOTIRKpyUaO-~MN)iz1Eu(Q!rv6L zC(BLcv_Ea|T3$X88uoy-#ZwG~7Z+pwZPiJ~4ew`dcAs2X#>v|44E%dN`pCceATQj7 z9`_IVCJ2z+iz#D30}WSUYp(*HBC|8#vYy@r>y5*~mpGiu1S&Ol`NvmJ_~8)^BM+T! z=y~S8B2w$WBJg3bRp|HDCw(Vd9HIgr8K8#~uAcp^Bg$Jyfo_I6^s+AVDD(r3y4gMF zF4G$%rN??;683H@sw_MsRn>{+9`yKW7bQts~Uf)9M+ucLpmHi}uG4Dha&` zglR=23S+e#uS}yE*7iwoXV}=L2~w@g5#b&FgX~EgRuLd}7*qEp4U&=Jv|=P`zDHvX z$q*4ZhxkdxuX9R9_wm0DYVx;|PY$3n1#QdX3L}qL#!9ngWog*w`*Hh8$xIbDEf(yF zmIfiK#XRq}bV(WB^0?5PfHSRlDvJ>=l&Z!7WyY@p9r7?D>_yn(Ob?)d~HB z@LIh0@8qQO`8Ygt2NAw+w!y+fmVwz^k6MOo@yEj8pto!k6Dg)|#*1=%QM6rx1!&6x zOI<>~KL45e(f<@EIN%<$%-OcolK12ZE#pjbUicL&Iv2Shrg0YXOY|r9)1II0-#49! zcmz_7WZsV{R^gDgpE0Hpg6p zLWK%J1J^l4T>x^hQu|8t9?}9OM^Mhx0N{^C0RRJR{^4WT8Zv6CzSIjFwb(9T#WNYX zLC^8)*xkkRxpp}7N7bz3*%ZZs{K{&;6OUrAX8IZ`ljVKj>~w8_JkQ+QPU~paY`sjt zc?M|^i)95kn-Z3Z1@?~5lGCkwf7ty{r}8^%nI|Qn&d==V9+xp zMht8cFctx*3>X~TxHL!$-Rzv)q_>ITir5x3VuDL3IddD#2Z-b6cipHr<=ajNN} z33YW~L!TCat{d$|HYdfhaS0;`xjdNwXPRE9b}BUkrEezXbjSn%X?Q#naPl+YyV6JT zmZ{}GAWanHn>pOB*uO)Z2JFai`iv5}e6e~^aAiNg^N6xMvHh+qBs^x7BCRG4?lCA~ zDiI!NU%{Q73Eo=4H9heZyAKJM9j|;7kyr>|_$|FFgjyPp$u{@{jt`{qsgKk{ha! zK(Xq&nrNE9%@GL7K`rtEHcay@8`!`E8Uy66p@>v)SkwiHrh6t=DG3TzXN&$)4MIKt zOC5nTQ$s)dYDgVT`~0^#!rATFIY)~&jG$_5TGnGf%Y6TyU%w~bZ>AX?!E%Pd2cjtz zhu;W>%G+6J0qk3ZnihMT&OQcHC?M{ux{SQ{X zR&mcR9T{~m_R@Ad%d%;ghYRk09slz;OPdY_sLnsCl-4vcNft21))J95uKhnx>3%*v z+&|uzsxf1M@W4%Bu>NF~Mx19c0L|uUN@X!M-4iw3=yTa=F&rvL2ib<{b+u4~KmcgM zYwoF{S68QO^CNFi#u!m3cv-!0NAfH?Ro}GyniCnX1{Cj`k}IcJ9b-L_FZd?_COBj z?I%H4Hx`?yD+4nGYHlkj*Ncdcrv%#$ljsS!{w5_?gZF%m z!jwz|GoD6ht+vQy4X>e7o9eIb{Y!~!u(f`!pkkDe#_3W!ODoxp&i9Azv*H+s1)6wD zPKnCOx3MW?0W+&jaSB*MW~qPYsa!#5&s;J4ClN#;Ac^Hng`^Rz z^j$rZp9Jfd+&i>#9apMy1G`zqNYUb9qPn@atR}tcB%uVF8*D>t82w{kWO1OZ5QA}{ z_1!en?b)1Ljym`Bh;zVHSY^RfA`s(J$z2Q3t=qWD(h9d{EDwyTARVjt9ZAL=AE22O z$dgqcNT#>JH5|9|6L&@y)Ygx@&F3JsEFO7|U9DCPGk~q96havnQVmGfb^w-#Hj<`lg>6G_A^||9fm#IqdO0 zO&-U7j=pbETpNQmMUy7*R&COKPPu>5v!(Ps>n!x);iO?=iw6S&b64 z6Mo;`#h7dY-;ZF}9(^o-@KN0`WsHf!DPCnz?}}@^Q&qT4&d{hTF~RWCim!>zIEyD% z0_-SGy4{bfaWS5b7trXLmQS&8_J# zuV3l~k5850Gfr*e4yu56V0NR?{Q~N%0nrC(Qr%5ID$Dfjv;2>4y^lMDpF=zK2~h)q zS`Enfa&<;lAZ*g#_P>rj8sqKPD5HjE>o7L-hd-8gWT|4^J^;D9+;L>qYUa=Q<*o-> zRlcxOx#`s)caUP;RUaOIz0m8w)mK}z+=)Eqhht^0FHZX?WtG5$SW|=z=2#@1lEdam zX}lZDtoX&$=r23RcgF_sx(EdQ&$&N931&Qp_?A4tp#ehEME^vDRRDr#QAO#<#E>Mw zQx^f-SHOpg$c$oBB~HzgxM9C1XS!MR&n>EJYJQ1-eDB%QL2uHw_dgTW{1PI3V||?| zdpih{PG00da(%p5O?S-y_?v6^`T8mOO;g#(>+$}y`#HTYCTVjw3?~QH!nIF|$rdvz ztBxznS_}kVHZJYxoJ-459^x>aTF)F4s7<3jb^Uky;){K=zJ*p@( ziIjYAq?j0`qJW!g5LOi*N5nB$L(ssw(r2BPqyTIJSf)w#oj zP6fxqdQCOK!MPtuK<~tVc9Tm+5bPz!c-yJ8;UI>!$30zt0VVC7Q5GW#@wMg>(eg!6 zaz>dTvOC0cr)hom3DO8Hy>n+4%0YcPRlO$>{5VW@J~dm$qlToAMqW;vtOavWICK=FM}eLd0Vg2=S4QczL=CJ?V^s1qt)3{ z^#g@&K6l8J6F@0SL}#9Ne5eU7%7Z&HB=)fZb3J62gacVrA5gMW=q`I* z8gs4!!QLyF#h4Mj4r|3bX4De>k>$o4kncPW&&YV+`|t@XBv82gm`M-gPhqr^bd%aO zB{*uCbj{2h+HZos9-eo{3OuabF(vGY(?!t@m+9_)`!KVTIO|)#l0=ppfXnD_pC1nh zG)rHF$o+fDX!@?xw7P-68S0u`htuJsU&!l%_<@(-t9uog;^y9lcVT z-^flLT2Gg>RHlspER4Wd&@DsSgqCn=5Gp1nQ#gCzD#dRsTRFW?)4qsqYSd(oJlsDm zyG-Cq)w#@R0*!O+1g6ceaSxnESsq?fy)Tge>0zih+FZ*2be5X`l7V>1d1y$D~I7;+xKS=+Z&)%gi_afbFY*`uF!MPr+|1(YgRtP6xn~ zVKjQ107Z?78BtL>$xVcVrft|5|3C`}RlSo+>JmoPNi*SR|7M5*%4>#heMe#-DyKe5 z{K9x7O+7gvvax<yX zO`Msay)K9u!qsDQc1U^v9RRydT|SP;m_=f)mFGm~P$p9%lY3-v7&AbQ$T<&6%5g$( z`lpN@?em$tROj%hx6!#N_PK~m9x%k2g~jFLj4?Od0f^JnLm;sC)Zv;)v-~g8@5m;C zJM%F4!31elkxi5UPh!nS@+=TVom1fr;IzRfBAzfbJUk5m<0zg26NKQZ^|TR$3Gpj%+e%x^!&>+;M34 zpLIZCEQTh6$*sL;82@rLE=D@+6gh9;5z%e{(I<-3hGLnT^1SHOEgCNbd58g@bsUvPdlTXL$5 z@x|^}3+h=Y zD7YC6%Fcb9_$^T0!_B48;KUF+FT(FaXn5>#DX36ILjY`xqFFiDBSK!_SmrL(O?Fm) zS?kzzCLGd1nZFbJAc7b%(@VS%l{Mbk4ASdy(x4OVWhvBiO8rzBXA8oZNFMaPg5l(G zZ2VJ?wyuhhB`iA+<-_RX8(GV!$2b0XZ=g}uofT2E1_ea}&eP}kG&uhh;qgs1?AEYb ztfHk+$QIMzuly(zK`PpL`c}V4#U-lPByKqwI6E&(B^w{b7X}JyBl9O!MBzJ2IafFK zj^@e&jODIx=4S2Mr2VzlOE#@@maGTvi;$XHs{F#Qm543YUSLW=iS|mhD<7}4gVt%f z3B|N_RIkUW8`a|xRwFljNN|`!fNtLBKEqs>A5Wm6$kQWDuA{7iv+{OR!Oi!$$a3l$ zL#``ijcC1@>H;-y|IpSwc8POTDxIEVfVWIPix~Iy`u+WC@4LwTMGZf34x9b$h^|AU z`$Vf>Nc^F$0Pzx9n0gbX9!9>3Yq@pvJb2;K%m|eCUjXAMeK(72wts~IJzC0l->ni_L7>30Pyie> z+2m3F%{2(p+y3(s)WsfJ>zVy~xF@f#^c?{Ak{7+Z$0qh&;(K~Iv&2UA%i~qy!LL9q z2D_)Na9)I~!u%A*6Fl*e4iK^`in;u_w~#QF|2!;PEDxPit~!Tov|K9-v$nzF;aO>uxJKI=PD~q{aV;&M#GRBDEuA- z>b3{M5jFrI3HKMw>fd1RMNod1fnWdpSZEk11UoAd$Zy{?VE(s8r6iG(gcU%g8~!%M z9hgN3%F#51a0+TLQRCj-d0gu?%W2DT704gR0Y6+7VG!}Sua$dOX!d#uEIhY-?=0Bf z?v`7xz9HTy?aWV3W}k)=rP&B`z{Y)NhkyK@Y8lG$bFLlX7a#GkEDISvGj}?JnyU)D zrX>Scp7g$zAk`dGvUmk=_U)P`PIJQsPkjjWnYHcLmzoHOHa zIdnWynX$;k&OS~^?+!`5tT71yh(VYx~xfvO);gDtt4N^6DwPN$)Vx^F!=aowY`#m)1nh6D$3@aH2GmOk z8uAaEKI!Q+ZS~bR{(biCTdew~E1Ej`*Cxd&h4l|VB^pBY7^!*r zxd^|-7By>oW(xa+CZi}Fj_ho=^+|^nyC{4pgAd$6%W_8l3Pgy6+1<*i=d0(EeXZ%u z67;p5glXSt{^R$lmt5EB&zmd8-(XzO(Yv6&kGJKpD~af+j{aB`H?pd<;>Zdc4cn}` zl`LzrYKzF^jXfUCvmC_q6dx7+y)&6^lB?6CT(zS(#gaeY^53V2XaSBEcw3Rm|5-y1*9-pGTOvGp4J&cW_? zeh{J}LhXc3Ln8%&J?mC84G6F6bb|W-R;NiDuiFCd91nWPon06?0qW>f?3)HLh#upV zZJHFjFu`UwS#=eIr->^EX3zuQw)&L?U!CkmLceFRtBW6_DloOxAG)|QO8K3p*liE< z3f%9LiN@PoO!BH>pW%niH-4<)_Z537{>V2uS@-3cow-MC{g*do)0t#C5C_E+wtf$; z6&Vcx5GgdH%bTPClXBIbBG;tQ6;MU{#iMq`YQF0-(&nK=5wdvM|8gI7;#y)Japhuk zV`Ren%CC|Emc^C!J~Zop8l0VI?m0w*1N*Fy1p0x8HCbU*E53Gy*{rK^`=)&#lx7o- zoF_DY3q7Dc1Cwf;d{s2hNvJPV=N zqTi-ErOD>=Jf}klJj*etUmThg4O%+SbVkArZpnR`j_BuqRR|+X=Rx?=A2{1E58{1? z=WOVO%4P|kl^t|^v{n4Y3krwLHuA@(HqFMg;<<|0Y$9YSTN$FqG$|iD1wy2qz<$s5 zObPb#B#Y;@tvdf%ZQ2>%h8P-@S(?7UE_oy*7Z%DQ6RwofK7sWL%=SYm#{_KzG~6lQmG2!E7}NzM@QV>cBZLUg;=(N#N5jhBQ^CqBu1{DElH8IDfj-^2 zjdM%JV_7)iglUPD4IwI2ERrSL%k4G8^~<|GDf&u$#$-qe2GJT%@5P@Ogwu`W4j|!Z> zV5k)CB;8$leZtn+bLE5#!dS015VVcKJu6^Bm<_n52x2?-VfEx`LwgRg?lR&#moUBY zcEuc6CiNv!fO=?Rz8XHtg`(SDv)jmt-Zopalq~ZDu_QKJZkf~KI#|WLlmg&+#FPwOU2#vD$+-0wu9tWF{$#;`_J=KHi zflSV8t-rpqeNH)Ekdlk3at~qZrCu@rX3i7nJAFVaA^h8nGOz;4>k!|*o&6t(L5k{v z>K{t2(ibaMl=g#xXlO8DQDyP-fB$+I@pNY9J`Rl{-DqB`p-TI)-$+(^R#ph3ac1Uj zupV#tPUpV7{++k{7LN?$x3Rrl_Zw-AWs7tkb}6V0cOi)DuceG^xeD6jJR-A$bn>4_ zBwrS!eS#t1mx6p~Tm4GcDoAbAM{~?75Xs2?W7S2CfN@=I{z>QeTI^9@7QbHNOfhVd zYPtTC1iPtbV0}HGUS&8w4isS-F~sjeR&uw>yW6lQGh0*c}b~sQSBqc(9}RmuL>VUZW7!^y#pRRNDT*L z5f}IOp}gk(rWS!{m|oMbk1FDwFKk~bcsYJ`iFQly)HA_*NB`#xdQ&J@a7#27`8?bF zSO$&sud=s{k(VI9-IBTKB|bWrK*L)LiN>?4=jNuVkvT0_<(;W71bj}n_87Q27`cuV z`|FLW@|f4Quye@MFd^&QdQGDi-P31C`|*odJKH^D#eUJ7Mn<_i)V85n*A%8cU#E~v z4cogd;;Gn%Ye;y>il)mYi8i;0YSIn93Vb|U$2$<>9&fbvQDZzfJxfmCAku&6w_J|e zw)PL!M*a`|)Wiiq6Aoy?$Th_A?*CZ22x=Px-o@y-Is^o5B-f8YY8Y5qJmmC8J74~( z%L^L|JH!Y-nC;$B_(ZOM#v8iKIv5ygy0yEzy8Gmx`26jj?_MFkaQO@j21o*fq;to1 zzn;04_S>+|t7_zh`_wq7t79NN^_aZVc0>G%C~KxaYVL19HyLo#-EC9JNoRv}d<5}v zRJ=YUdYsR-gws(X-vkQ}lyq9!8~;qL=*@8RGIl}`-V;7TOAp^Yn|_xmnveU5CbZ|oSE zMWgSfLxZ&iDvF#@(h_7}3Mq%9&ArUV%xYT|3rPb=+13U3e@v}zzb5|@;#8pKX$dO)u|GT`BASQ?s5C)0t3<`Wid)XE@!b4yN~m%BPuxy)^IB=fBtG2y7v-N?rb|%xuuFPpp%xRANBcCi zxn!PmkLsa@dt{sN-@{Lbiw=koeggqf)!o%NO0gX;jzUqC5cKHlwY}9LomEuP{c~j| zsM^DkKfz=4(&xh@vr-YAW~^RTaI5hc$~%Eye}jekMkjW@FSS)c#O&T zP%5NY%{X5YH1$B2tEtUXWlW?PqyW-7$8{2;4Er7mAy(}g))<`y@NCJH(V=COFGmWu zgOgV?e=VkycCJ)D;REVu!f(tl>-YQ5WK0!Y$c(tk4grdC3H4wovWaRN;JM0D(Fjsi6dMU4>}#h zvR7*rTuKcVHz{I0=86tM(BGKT@u@C6LAT{Jc#mM9o1tJJnCFxcg{HPP2qe_}0;s|c z+|b50D}t^vOo#|WqV52ahW7gL-J_?`{^zm));HJARrvS62N%aS{uPB`=5s#I=vZ!e zeaf*AB;E70_Zq-qDMHtC9>R^3Y#>F}y_&<|M;r_)M6#HsbS1hs8Mk+`%C#78QuYN{ zB?*O9m)I}9xsY$FrH{w)PS*>FWvhsYr5;RoOrS(R6^fgncW8+d=$12zjyikr`#;@J=-M4akKoO0&f;1*fF zgX3KF!vDm>HkAxZ*?-qqP$BK3Xw?~$>u^6#3P=s-wn`{eUW)_y`C?8eFSc=f40EeWJUtRK86je|meu zSSfvD!SA>r<_cE>`7Dz;4+zoWLT4A2`j$1aU`*>T~@V zkT*M(Bb-WV*^4zB6L~J?!c5|sDq#0P&oMhegr?~3W#tbyzOrZ-*i`XgfJqgBePu2X z8KDmQsNKS4UvGrSy}-tRGI4V$6w!+&wzrdSW`C35!;m&%l1n6cF|R7DA$S#$NHmUs z+Tzg~SWSowbOkh0Xj8QbfqoVkSjEJ;Ut#6LvRYMj8qYbwif+0QhFe?I)}Y5QUFeiI zR;Ex%;gdC214h0`Ngv9x^gp+8=6>gqAK3v3_FVsQQfkQ*$>~5{jNLD{ul36 z5k>MD2=0{M_3oHixYrZf2An;CG4cex;~zi)Yflhos$!RDI!?XQK_321j>WB6bTvlH zJC=ijMDGtFnVd|HvvDxp=0D?l;<;`S@5V&%DbGqq6eB>v%0R!4ATj*YEjs=)t}n=T zj`v=x-7Uo!GF@R!9U;}fcxh|KC{nDKLUGVZCq{Q9koYZOz4{?YLpNu%gC{ zC(?#cL>k&rlLwmVMa(E8O5~U4)-V%2{yAom?J`%{b1FIol-+Z4w1ts)`z}p0Gb;aH zwlp=}_gGoOBeZ?3r{cXt$W{u1e0cA+{$z9BO?P=C34)%wzb!>z2Cmot4p{H7J$qX? zAOOiLF19XFzMW^ECrfaoPgQuV&5&x7mL@vdV9PhNDIiv9ka1U#KWV+xsBf>;ThP_E z3veQjRkcg$oN<*q)@JGWGAw7E%iMmv$b|uHm11+GRpz1RI?6Jw{eNt9XIVQl-Yz%i zZ2n|OntNO_JPt;_9*OPBT;M2W&FVE7zyn1fX4udai$7)BFqCJ`%EtKn3@fR^@qsUD zR{1VkNi0Gar9bLdlG{TXfH@8WfirUBp7O;76Pb3!PE%}9a+5zh=F)0URd#|-A!K;# z+QiN^@31??9COJS)OAGPr~V%Rl0a?0a)yF-TC)V^bvZWX?Q|yEt>(CBuCCep40BIU zI;$CZe_KFw2%M5Mbb7^(Pf^g+P^RI;L|bDSdy8rfy2@*&Fck#plJnDg+P+X=Rzu_V z0On(XAGKI0Fn>DT3QiU9X}WC=#WfmO(@?${S#1Fk?ZkP5h48Vt~ ze=1aBLjVEHkzbbxwEZ7YSFlN7*-YlRDBI%4W^@GL$85Q4X8?0CPkwa^EFt3i(*t=^ zqxStn>+|*?5tmLnRVaWey!I`J3Bh3WCBHdw{?{KRU!of<+OqxfhtBS z&gzwAsJ6@a^;Muj?+TZ~{Yfn+ z-K-!Zu;_$>ZFxo@tCh{`OrlLHt8pr18=;(PT3U#De8>reXFgWXplR$=`!ZV5e<0Hj z11xBB2W>mol9NI2wKUU*{Dd0fl&pP>!hkG2tENeuY13o~SI@?NT*Hbh^;_i|Tqn>n z6WS*OP}ZMUur4)Bs@?86Ug^gTcoi$#xML@YzJ}MBrP;+CVg$-yJ7KA#@O5~-AFst5 zSZ38!YGN7)G){tiIn~u}=sHi&e}&XEq4v9OVIhAD{cUPj<z@DOvY;`Ik^O)sjO<;EKq-fo!0jnd$eemn(a%e-I}fTt4W@U74{b9LiPkh;F0nj zigJ_~G*VksoiVXibQ#8;d~RlZPY~=G%4sid(%o`q*~Y1}?P?|y=fy^_f4v*G`tdH@ zHqVRO1u6-r3=i2d1utcEe_nSY72Q<)pqlsMeL*&6?oghY0e$>6A=|kFrn}bD)O@(|tI=Hlr*-9D~z3?_yoeM0dDL z+f6Mck;(Q?!6yhS-ldyae;AAE1$zI7Dt8i>OndEq5})$pPJCKm^$Xg;&C<_GnS-VB zH~oGJ?jlf&u5e4mVaB4!*s59<`?Qn~1@>o?x7mNarmOc|qA! zl;`BsSpu8kaf2a-$zT{p`rNsd} zBGZ30t*GhE3ja?s>=@S5q!;$HayBpVaNJyv5wg0P_IQBLtA=!wuXH8 z#w5`R5&4$1``g^mmY`#Koi5nl#rLWhxbG998#L9_%uo@cKNP4tX}h7|$JDz)`oo8x z2xLPO>uAVeZyi$ge^6Stv?N=OP;%Tk@?J|7Z-NkoLYti(Lgg9R658s#hNPG!lPHuQ zKX$yuhoAAf;-e#gpUYD|hF>r`(gMRwU+oy+!!OxK6i?*ClL0*79`rZ#x??xFzbo~S z4qD08)~-?T2i_(O-9|mhhm|QoQeIZvRV#|Kbl{)xXFvXkf4>MUcfpW0qRBydZ`<@T zE1znn+FhD?{1n~R+p}pm+t)>1Q`Q&PQS0CFbQS)Ff4Gg$h9O(NOvc->X+#=#vf2C> zo{?~QR^Zf=S*+kVONr(XJ>w1d!iJq2rmY3fW6Y1|_+&!(gvRxKj1+Gg+2Y63*<42J z$Y%4lY(3nLe_vEgsvRfqz$H?J$1i4yO8($X`9tRfd8Td54$T@bcmYu*i_9_MFCEWO zwBEAhBg)V>nkJh85nw^+D3;QYCV8!)UOr!P+>T9E@DPIm0`i4dc3hEMSQws@r#U1^0HR$6V&e`DFFPw*k< z?KjMLTVNy3^7G;2VcoemX z&S9KVz|s+%F3{C9f<}Sca2`J*0{0`DNOX_jEP(>n#zt_SV6pXy?gN<9>`-KPha=4e zT(slB*n{DNR4YUie_P-gLl6}TY8Ad;@f^Ymf1(Q7#%PPj<&xq*m|9g#g88_(Xy6$% zSQ@w@oY=K%80(vkpuPDBHjZL*qO)ljF9{z(*U}@16>!-h$iFIVL%b+`3n}TAi$>9# zkQxfOyi;@)u(P{>-4_4r9;3&QTbN;8o#a*!MX~ ze`fQcoTV3QoH2+6&bSbD&bS!MoH2ycopB}3az@t$0f;e@^oT-UjeG?bO^h=Ff@4$o zFg6DFj^Nq~`nATPu6L+os2Rl#3CS78tB>N1@|+cpS}!V=Jc~J^ncsd?U`IIfipbF_NgO+&zrD3%IwswSX@~_))+YV^UA6 zClY*+d)!Z$bIqYTPwW6f)cKV}thiOHM?~aSV^4}!&w;VWBM-rIh$}7+esy;Ne_y{H zYa_J2y;E+~75wHfzH=BqI0k?4M_dji_|sNTxT%h@yf^r`yK@0gM1sHSbe1iaVv*g! zU%PVdg02GyM-Jn+$8fQn4*s5#NAXw5x(oj-;NJxyiYuE(#Vmq9+%zn_1)=a9%?07( zP!O{Zjfy#mS}|`}1n(P**vGioI4OUyAWm+RWf7^|Fh&i^r)HcK23T*w>`5(E)~;Cv!$C$;1WfSU+` zTPb}PtHYyAiYEw{r-%sb$BaDR(T973m7e=KnD$a8l( zZTv{SqJq~@^I9*xoy9Y{wo9t@!&Z-s5?`5#bA2M9B)4G&NY z0012p002-+0|XQR2nYxOlf9G>ldM=of4luav7(^(#i~#ewi}~jgTw@-z(WnBwI)6_ zx4YBr(*4Ta-5O%#hxjjy2^vlO0sbiCv}latgD>~aoS8FoX72s={qt7<53nro?)bP_ zdt-E^J)qDrHVnIGtQmF`#GWrxFAB{da)@z7KFNeQ*q4cE_sJe4S&$eTJ?SU3e`dt4 z8OYf5Ml~LG*QK-mh;vo#7r&SJJ_AW#n)leH(Dgzh<%KSzLsAL%V!T$pU#*!A4UM-t zgg~JcWy+=<&nJPENV%4)q~nwITFE#jW$ljLc0y_|3aAl9gDloCDKL8|htl$8=vw>T zL$Xs1(*g_I^_{JD<3(q;xwYM>e|Orgdb6{)|GX|xZv1An(vh;q0{W)yd!d&;5y(|m zUkc3so%A&Ge20{VlEC!lIJbmzC>Ah-^8)#drB(Z^O~-{lRJD$hlmZPG1&S`E2P)!u z(j$T8%2_3=XQ2`<;c@|UnCHf$WrU7^`Cr_hnz_UkTpbBr1uUcU}rClPE!Tu zD*tSL6Sqdpr4n@H^O(YIfyrn5*u48GX#BwhSLfK+(osN>@4M`+V1g}R@e5{NeZ*|J z{0R#uxK_Tw#|exNxbq$u({g-HAol}MO9u$8t7l5t0RRB90+X?n9Fr;!50mY!2$TO> z5q~5>V{~b6ZZ2bNVRLg;R0RM500000HIBhf!!Qhn9SU^p#4|)3KrE{eFsj|SuoFT8 z3C?cnw%O9OO4@>i*n{vW9C!d83gLqA!SesvzwNK@k52%&fT@7@?e;!>l^N;{xm+%# zF62z=rf!YJ&NNQdO-{@`S;9cvtS~5Dk$>KVz7BF(pba#WZK-N(l^J(jW(&+0S3K*} ze}BlbbRv2U>*-* z7(=jS0taIS5$7FljvGEf6ZEXd{ouF|NYJ^cXBg8 zNC+@2GD47SlL#te5HVp5BmoIahef=Zxk*N5iL(UaLe*-mt=nsDD{A|!wM}d7W^oct z743rB+EriezP#>>-B+vTeb2dfl9^-z`rbc}Pr|+ToZs(ve%tvi=j2PTJ@y0ANYqG267fJR5jHWNG^3`GGBMd}qynK{ zGju4GiKP}dbsN!?S--fiClE9G0uf2$ysni-c;)$kO|Ht}cW0te45WIEz;b+=@t#QB zG?S5d4@UdVWD09xd{x6a4XXlSvw!h59%3fFGm%M#f6R@MsL527NcJ@LB#m&?Y&@Ja z`ufad<0kdF$NFkFB5{qJOl6lF{YGQdi1##Z>$=Fvox8brY2`h-PeadnMFBV~p%$w+#jaU#rWFL`O2PNg)R z>5Nmue`-|5Gz|-_gR(4%nHEf1Vtf|F%c(-AnKX-O?o?13&1NbE*|tPT854@h5sjPa z#$7wwKxi)cbeco+n7sKj8ZBUQr4ze$v`#{61=<<3NT-G5FGOqAXfaa>*6f6j#3073 z9BRI{y;Ma@by`Aa!7AM_u7|1%tY*P!RLkTxf3L{E$CxUs+a{WIbHr{#1mQ~Bh1jaGuCbi(q;F}(mp zjsSZVT~JErQxmu;;$|9MnDYiT+>ub8w%+XCn8?J#8;)%+spg67)gJ3G7w^1O7y}KizBkf4A&z_g9+@ zJq`ZA`q+S+T@xGVH=-G{2HWA?SRrhtLdl4&pYmdE@Lsx0@_8&5wbkm)$)quWh&=V!-e&R?QdRshMtvhUxL5J zjDao_D<#w0Y!5G*Jwg0A`if3Z(N~#7AmE{|GX+j7NOL#Xwd0XS-;^8R_3Hcuot~%v zf{cN{zDw5}sPoW^fA~ONLMfH<(sv{`b@W{%g;b_1WxID}b!*W${eAj@g#IC7ZX#YF z?cUcJ{7);YMKI5DSoX*C6REQQW?J#a@iqDxqM6OEv~qJ25}sZCI(RAM;urKwoqkTg z0=4S3sTy0KYZ_`j^c$!&5)Ye4wspg2puAQu{f=Iey86BJf92Mx)cHpV@+Y(;iFmUe z#+h1*dCnW<_Am5T$?e~eAQZQfS;gx=5WT997i1!bJFSnT0efgdl{kH#t0mc z2(RS20mV;q4%03xU(;z+rq0q(0@X+)p4w^-c+q5`e14Dx)0~N-v}7XDFfuQrrQ(2x z-8#EuY2%g^e^opT%%b8?L1wj=OIQa9E=BxEC#*>?PeTcVL9|KJQ5_&G=G5!uGWsGk z!!woEp~k)_iaak@DDyIUA9oa;WV%;HgH|uk<~gtu&xMSMct^sn3%oo}YWOLhkKM26 zA&c5s@nd{e z2`}Ykx!$G_K;s&nYh{4tH6E^?B9KW3=LV^lMkey`a%ihBGqDP^Bju@U-CQ{3bNF28 zH0L3GS`y|LoP0jhlIp@%Vv53$W%BdG&-zi=7rJm29k_pyp`Q%l6R5u`04bR*?;=isa2Oa9~qLF0B=)v0p^Rj7G+8>(#X;O&Us1#D`(!)oPH*dJq6@5B;EmK9#! z$-7G6iMz4cavR>uZ<4$H0S?M2nA#BQlZ)-ce=g%%MoZ#MMXtpDx)j?80|zH%mpo|< z34vB*QC@+7vZu$0s<1ZR>M-KOe2Y~-lD9vWiKZji$bPH9YVdHk&ZZ12i)^TH!c6&P zOV?}kn|>ocV1WV>oy@W+JIh@#%x2i7Es;2sfu;^27_Q&2v3Xb9&V!qFG_P;laBx@W ze})|gH*ag-;N=(!SdMbsIw8qveu6yTf8HS@ zelw%1SzJU4`|x0cIx9d*<99)18MK!b4L1{YXo>wEo$uuLVogg5rlQ9j_EPI?e@P81 zyz?=>y9DUyaOM|5T8~~dnlQo|zpuEb7Ne>$nx5%#GkrLbJhU?sGZQj6Gt$`y`2G^U zkI~l50k8d#Vsg-{tDZvEVr>t9h(E0J`x$M|it1ugTW+$t2yUyTypKxs2g?YNX-?FL zb%l+p!h@x%vzcxyN_&FwRu?;de>w$Ar%?CmV#XiK0=vEZasGr(F8<^UH=_+(Jicxu z-k&&RHnu5A+Re1lZG^zvfW{9aFvP|On4ZfI3^pDxdJ|zQGo`Amz*8jEO@%0r0seQB z){>{jt(iQ#&WJ`kBeLk^l8 zpJzI7%8hqQot=&sdnIJ^6O4}78;-~>u`6TsebXl#;qx>6tPC&ciMi3k&%xoNMk?KE zHAi0ls#P?84b#xoH&8L8e~fN(R}xA1j44ji$4EcVFUUZFW_DUS(cHPNwKZ4mzo-tc z`P;|=?d#9;@ON`3rDGQu?Pe-v^qA`-J*F&izi(w|Wt6zQ7+F4bhAvJ6{QQuAr1KB> z$4stWJ2wVac^Dn42V`3Y(lUz9E=F@-iM7-A)hxdjh1DYG1V=UjyWokv@ejNR0`$ z#uS`zSYv4L=9x!Af6+`T(ywmYnnNL|u-%A5izso{Ch#Q)LgYm}`yun9g38 z$V9^`4uz5?Jj&mv4#fT89JIQ&kZQGJmq(y)^~8;MLKX+A)!pJ13&k0z2E`&5$$v9i zE_M*V@MNz4hqiVgMI>UDA=D+3K%cpA>_#ipYsBMbG^Mn<&ic^AS-Ja`Ng!?DM-$ad zB6-*&YIU(xf3|J9RF(zCbY^wljao7KP+mYZ09Bw9)zZlUNmNFYsqo}Hkd})Tx>zR8 zVOsrva6?VVc2%AJt&1j7<|XoAJvuPH`LVj1$X&yT^TjG%tP~d%^lUqOVYRR(RwELm zqNdp=H}@6^zD8W6iwnitT(e$yv7?D*K!)I%Ua^jzf0f?09$K(3*1cjQZP!JO*d&YN zNS8;nqA)Gu!7YhI8k^ndlQ~cwl%eLr#@VWiHW@WaqKE}jcKB~i;ZBMhF{zcbOceVj z+*^tcu}wPY_S`X$eGROfz75$&>Tid5$G^0Cv1}(#+wiv$9na= z8F^wpe`#-7Q{ZK<*r$u2*zYC7db?E0vaj&wdJ1f7Ghe2QPGKPXARoxhWf^Va>9945 z1w$e%Er-ojnUc5g@T?>00(R$BPraV#5xo*!CPrAS!9FO68ku;g*Gx88rHizeM;wwC z0;U~dmY$~D%*C9Th)X>rJmj(N1g$!c>EhE|e^^=s@<}GmZh1RlSBjvW6e*obMY`bZ zun;6NM^1G+dY(D}MTa<6&C)za@f#WhSD#v`NZG);9| zWp|f3ZThz~@5pO9^E01)p)1~u;A{6$^2*C2u9JUFQRG}V?_g5A1zA_zz|`o6Phg?2 zfB&!%Ndrhlu;J!C?GUMBD8ad*Pi;Qe!``(xI?F%0QD;Rg+87g;WX-1YRvot?TX9nA{w5+@) zOO3~XK+v~Eleuy^Lx5>%2M`;Jsr$=aK(D^uN!L5$E&hp*0 z!?bsZ_MO-&$7_e^vJ-?#g{D)G4$yq6qH0=8Lfk3;WQm-k_!Jtg(P#;=Mr%g_e`tL- z6OED%Tsei;*+2lq0r74{O)?MH#e56ib@{gnmS~y}Lh3}$hidC`JcsbxUEW)Md6wcs zbVZiZ)=%3A^#}Lw?--&Z&PV8K*W*+d3_8k>b~?+i?aa~*<#mtH+jFD0VDvUQx+gbs z2S(m0M}p;d0!2bl(Wwe;;gej?e?az;XIWmOe2=pB|#)Ba{s`xdJ}t5Iy=R zonUHm``nMx(@e+sS)WV3f0^k?kZ#hl^tEIB5uaB64P}a%BlJ9QCF-{ZN1wy^x3l!U zW8?#x1_S=cryb1FPqXyvCfDHTLzw@qns1QvWoxqZhm{hr5}<#!Kr3C&f6LU{kFxZ4 ziF6o9|5QkRiR2sy^=a;Lu^MfV zBrUv;@m3bFX*ZQfs1gNrqt7+MuAr~vU8Q7r)Al9|7*v6f38Z8^D-%FrANuy)4=Kn9G@(*z2Gqffw6R~N7= zi4VSJOwE}Mu~wpFd4YUC$LEx6EgGQ*gB?TcFTW$pOOA7Omg`_Vmt||(B;RtDc2{s9 z%V!5yYWEU!gU=ONUb$y*^m%+#YCgB4Qj>zXotH^7yAN8kk4Vq1f2-hCL%e#Jo10v6 z$zb51&o#vBv%IN-TeI9|t#FdO`1HAl`I0?8XR!Pz#=zH}uY!<1*(5X^zjWz8qN&fil9tAekd<1}nH{hp0)Lb%fs^e{2ub9_I(J)-ZqM;1GYT z-si4+j7Nw*l@~1QJ1h9{T(m?qQ!$Zmrv;;QKWSDBR6qS1-LKJ88hxJV6)khH?Jw;&wCc&%l9HmV~fPS6>8b!b?nTiI>`SqkvHE;b$pgB_jAtYM>XP%1F zQ7R?(*fd#_e{y(!-mpdwstM41l^P{?|D=UdCEPhm+oe8qnKLFKa3|5304&AOt5jo6 zT+E{s%2zbsAX!y;=OUS3)VoSICuunn4T@a+zXVeaU^R+=Slf2K^A$}U}9Be<%Uk-L4?W%1%ER)r~BMZ z+8|9E3tn1%5LAZwTUq{2lc$2eH_Sg#8?}NFMt_;*-;VH02(r$V*lK^O^kB>UwX7=3 zf46tx5dQ=FPp$4fXzj!%O-3xwaef(u5KL5>f7E@>rV`XDK8(B~N5maIS5ry7j0loc zy`*%UN5_cC$StXO=+qk3GFjEGW1 z3gCGHwe>?{dRADqRB)?IBWXLmND--9k`S}TurVEM&x$#B({d~9Osmg|d5ST=3?ve_ zfA(O7Sdbs1WHjM+?id#SS>nuCg;;W-h%HhWDL{=Sf577U5z!WG9}?~Oz9iUwlFI6zaNb9Hy<sdh|b{tt$^5>6?@tdH5UdEG>653tN^=R!=k%3D=x1P(X8mhY$;-D`I^oO zaRr7mV-+dm>#99jadf;;ZFAHD?Akgz_Dy=fOWW|jY;wEX{f06=S z*VfyL8pHDGu!)s7fcTDa&@q6LDF9T>Tp@0+9TM+6fdJn}{f>8tTWNr9QqNoI9{J=K z`G?{HB#W2$uj=_Szbc=CMTvTr2(PHYbGn$Rp0mXw^;{xq)U!owav-paP2v&--zj#> zr-L1(>N(9(rk>@FD)n6ESSz1)e~S7k%^gMM?a}yz44!-+D)d~qmHFaj(qExjEYnJH z7!~kerMQQNRCbz<%rOO=0#PA(HKKPO5RHN0#lvnpiA*L%`A`z%X4yt4k_%+U0+lt0 z^`ca!4|`&k%!hJ96H7I*43nCuapq<(M%0%W%kaAt#6-&|M#eB|au`d;e=t1A7i7`0 z;bqG*f&TdNyJQPw@%4&g_FvQ~^Q(J|hy=F?&6K^4J(?#$9XT;QHX&`H1SA_sDa$W$ zCl1LjOWdl`UOz3Qc}RPUkoKy;@GEB2C497Ec3A?>vy?cIVkh3f9` zzjzOxUSb}GZ$8AI=7;_VP)i30OlKHPf*1e*?J|?GlpK@CaY%p1U}XdtjE+I26kIoI z*r47fx9uHCZb@#o;R6*B5Jh>2Ivy&%hKh>VrG@ekahsrmC=VZ~C?YDNh^UB2{hu$% znwGZE-!DD)eBb%b`#a}+550cZy#S6;?Fu(seDTIL@2>B)Vi(w{czvWk)>q$DA9Is~ zPQvmWHx*90ahreZX**$C8Jn8}Rwf)9uwxfwvdK(+q|ZuZ?56s`{&3P73_HSOb#JQ` zZ#|Z@={3dkec42U3z-2cd=ybT)$gQiJMEXDEy7YnqR4UK5Vn+w0$JLMa5g z+-y2#Z*UT}!eTew-_oD9;t9KDN7@=3w9_r^sf=eO5=(!NGEk;4cbm1{YDrkB{+6?P zx7jhzK!w5~dNu1giI$j~ie=MjJLR>s@tD<{unm|zxZO%DO}H^Dajr9%mo~dYA9LIm z!H-v{5}LS^@zy(Og_Cm@Qui2Qde8!Jz>ds8cAT>*>FP8kToVjv=iJmKtGT zslu#&+dJEmK<1-0w|KB8mr!Z)5Rh$4%luu7yIP2-#03rwt5Fg-U<6~wV3U6&AHRw=>_o# ztgXUzxSo|Yr58Sh!)4*qbZ)}!@3$%F;HfTPhu);L8*pPKqj3|hUN5=Fpw`8Ub*9e5 zXQT%8NX`13LTFk}20l;EP-GBa6!I_NOAJFkn{^|dHz_Z~SG#emWWraNYNdb47{u44 zm2AUpYyh6SuB)xRy;wiLAtlVkH|al)6Hebn>)joxglomy3bTsB>M3s7TPd~Q!X2W` zx0%q{)VrL)4w)0COXve;@ZcWgUhA&poK%msXJr#VE)eCneRXOQaqZs<8H1s zXY}PWaW9dy&4Rt1)uw*>wo`w+OhJ4H_Y0Tr(i=ssPRaK5*=akz(YAE!`yQiK+-pw_ zW($?6xV^8~HVX!okQn&>6k*dn>7f7~#19n8H*eYyUSr}%3XS80B|N6>YL5i4A3v6o zcHmfErNaJC0@#b6^1_fyyn{nz5RZ$?_TmYOjV0U+SAHgQ#a{fpcw>LHm=cfwa>B-@ zfwa3LKMMYePHA(qiFjSg_3HYha@Fxp4b-ucG3S57OEX2L7gNo^ZyBkK)n{)`vyd)n zm{j8?N9h^-K7ilh*-5iRv1rUVOFSnx?~e+q*~Fje4mv60rXp1GFVgpHuh5=?_^Y_* z*Z3P%b2H5;PB|w2&ar<%QZDUMe~&fvh_^J%Q1U9edqaiz-RNUQ>F%{nkCdX^f za#Aem2bWsWHejW@>&Z< z6=SL@7P4bkuQt^z8ZXV)O1UYA`s$mj=I9|x&6NtiWt#L>)d3YyHRQ=jCGAPKC^fYp z{P>`%Rr7^%0WaDcwha{$7g&zBLHY$JzV@IxSS=2yMT(>KY^qjr(|C_dX5-Q;7*vO< zIyrRMgw95$Ny~rp#Q4JlYN?*imt~fvOmzgCN1xtRIAMx}*)nYsPh?EV4Qe@gt47|E z@iXlyZl<$?o*f^*tg5MGgla#lWTRQMTQgz!;8kW>Fw{|O5QT?cerfVxpI@aSN2_B3 zYL((JUg;FY2i37GAY3K$#_@8HvAsHbrya|BQY`9tbCQ2fMjoyiDG$7QDk5UZ*t0wB z9eV6mC+G=AomlJvTKdLp%5#!-i7h7u)XCCF4=L6XJ6>1X`s(_~jS@J%&#!Yb)TfRw zODA5(cB1#1O|_nZYU6X8N_2UA(VuAzZW2v7%t)c^%qDy7v|izZt(=n~ZASUrdGcrj z2!jR42b+I}e6DH8=N$ka>1%KhpXD2fHS&A~;gZJa)~%tkJ(#~@4;D7c&wli*_^)VPOu-N3kN>*fWeKjjqh$nCe#k%i*|T zoG^q%Ih?!;t5@XEwhPTXGoQaj(Hu66pd)(b5Z-?t?c9fo-TpZ%?m#!0Y{|jOA>Q2> zjcz41DHe7PVR594$0FrJSQ3p?H03bRJ%nV$@VA;3t(9TT-K;ftAYwU%PIf~1ok-#u6zqhr@-x{n9)>eHUhlb4B;Hqe3mR7nd z6bOIu>m%Kl2G#Ddr$d2=88Yw0H46EUPb%!f(ekxRv28CSKk9$8I3yJ4ss8LRZlRfZ zU*z!R5q!0K_t=BfuVM&a&*AoP$QZ$pC^kYfcH^1u+RBPs@JPtmkB6ExRWxE~c7`}O zhkL}k_Z2xl5HUx!)Q}kpgbSev=P6f~P%?iGbjT?7Mz_j|{n1f8NDYVa!|I2J@#ruf z%i+n0nZqwaX2jTyPH|XeNEYsEiWV(0da9qMMI-n_4u7hC{(xDbwpM;d9baqS@OpPK1^8R6ncZHJ2&zi9qmeQRaP>YOm&W`K(yi>To{dp%6p>z8Wrp+t5LJN%3CXPYF=$cPuH+ID5n-O zZE|YKE@Z?Jo#KXw5#myP^}{{%*`pzYju=%-NjI#P(Vb6{U>_Pn6*cO}h*@?IjA*3N zA2Pb=?#i56!C*esxf^r&TO^ED@?(E~cto}46peq8m>Cur-iO0NWkolY_tdE4CuK%c zm$x*ot!)o1q@|}-ujcU_p|5T$+Ed-bQScPl&UU&!Y!p)q# z1>VMSTHp{zRDs{cehnYO!y5jA1Cc-(VFdn>Lx#Xt*_H{}a0437VjmMIoko9Py*f_A z6V*lylWI^sji=Ow>Ix07R99(uwYpKmo79MgcdJJ=d{jNAo(0qs>gO7NRy{A!ca`sY z|7_KwVL*j_H~BuNae;#0;`@@u1qyzvZ;!?W3O?c+)wn>x@AciUae;zA;M=Ehfr3Bi z`<2E83jVb3IgJYx`~}}j8W(>k_{+XmG%ir^|N1L5E|9pt+P^?>4T;02PGi}<9CiQ0 zIR=&)=zJBk$2j)|43z7I)AfH>|KDbCxKY3utN648tl_9Ij4{^uX=w~xN~+f}*T7{; zEgoa9sG6Q1iA1JD zn}O;ntYmhp|U(hYHWe&ZD!HpUKJ#y(vj7V>3ZA+y;;E>3BZz_`C=rVMT<3EdqxXt{Ma zNaIXtnX5GM;xr`I4QY~=c(X077qlt3v7OkuJ1wa#)qmYA@?x2Js_@usZpmdSi8cwc&--b?=8D1S%J4#{_h!Gzl!ECh{XA zLrwmzky%E@KTd2ewVwaZ2gSw8=oc8jmR;#^M%BR( zhKDhLnu7{PifU4z|A1c!HEzoMGksh!#Z|3fI13I3qr6UYH;WPnP+h*ddcpY0GbZZK zn0f+wXsKsW`UFr*2MCl3!<1?P008F!002-+1CyM9UVntf4hk>F3E)_HVCR8IO1PG; z?MozGp?ej_yasF7I@s3Hvb9N9V06rEWnHs@9GXI4>wvP+u6uW5bQ|p+EnPddZi5ZH z|99?{Eju!FU4HrL-0z(4eCIpg_x~Qpue|rg=ZNS-;!Z)Q@4kC*>mAL*TKbrt&on2R z(<99t&3|b#S1_`gZJ7CZ&dlhTFX~xcvve$uX;wTvrl*ftrJU8A7}2tp-qBnbjpwvN z++Z17hP$;)cMo`rTPyoVO4%$XtT8RV38bDMHS)S%H1eaEJ+2omoQ3(VotJfPjc4@Z z&36Sz2nr3ErD9sY*2wCDE;5UwU86-UlhwP%i<9_)5PwxWu61R#{AkzS;al~zt&m@k zKWmPT>P11TlQs4y<>EF$fs8qx&zf3B(8aYFceu-7y+}Wi&Xz3WxYVmRoz^XDx0cuB zDOXl+HuAP!%xl@M5ioXT&Ga!`xNGNv+acV4g^@Sxs|0LD!+%lG2%m*~N#slyvQo&8XSd{yv-6yJH{2lzls@+kIKhvII4@ zwO7fKliR{{39V%-sDi@P$12nehv+8^%eJJ!Zhs2XdTI?(3tc(~ZjMe0wFzpHvnAWe zcJ-OrEKmq!TM9)51@&CPo=8HPpoWSbl9T74MhC@16r)bCW--Gm;N1GQ_QP|n5vGl_ ziM7})Xz9E)1%XYCv!Z*8MNOWmPAlkHmDg> zx7568t7$WDYertx@)KZlbTV|SQ{8!@07B2GwyBO7`HZTc(9(8xLftgOH_;iOo$$|y zSE&$~qU3OmyIjZ>rt9eX5VcdkpnnZNBCHe|5Y*E4fiRUZwmU>g+9Swo8Mo^a zN&R8kM>nvc1`+BD8p^eg1v8jx?#H##ejJGqVBhw)Uucmq9i&67%8lU58p8p)i4g&P z+iMtOyJ^}`Q!DI-Vneo8M5n*o>xbGhV47o;4biOxjaOD{*PkzxY>3dc zoI)lihq=l-c)Kk`1wt`eba=Z$c7G)wfM?G3;{YVS5c9sa!`m5>Cukx><8(Wss#M5m zHgs38)Zfoy@1(m}qq{5OeG;XMZC4=jmf1 z`Z@XqZUE42*kfV(INiWO{s~Mmmh!mxnzp_Rce{!}$S=|_u`Zt!6kphd3+z0_J5Qtd z*k(o7*VQQMal=bdWS7DTe5Yo z>tXseme4|zVv+wKbQr*H8@$(Ou-!g_@AzEvi<8YHl3EVDdP3yE;-db4UYrv43Q78nk4$*vS{$ zQGJ;M#cV=twJ__-QIn=)B4>Igk5(Gngv>py`QEe*hg40g?!rOCGHi9swhLCG%T1A; zoGsl(dA3FF;*8~FBdPk#0(-|Cfv*glP;EXW_WlvaTEh$|wPe9OnwrKXaouXx4%O0i z=@iwlEw=V?0{}!0{C{=ysk2xcEahz@r=x?@3%pOE&&{j!bL!P^hUiK9JlYTkeCQTx zWSW~0)LGfgG|hAvUcW6IlU;|4&~0%^MB0$!W?;3EDHS|LJhB- z-DXkWnbmWUipczZZg0L!FCq`+^%J(cFh90uD(lPi6=r`073l)4cS6kxh5is4Bck`9 zP=@KN9LcZJ*N|}*?8iCg_ZKyOHEB*W!kO{wXkIOCL}mn*CFs&0DQ7{+KcPPj(I3;F z@yX}|{kdc49)EDxzjRX0H;^YQPS{==8R0~*w`5mUlD`(Ts@hF+SN|qNud`nwv!1PH za549{A$pDe4&9|JoinR~y4sSpO;@?h+`5MQyg}b$*M1vbsdb=2{|LB^qwK=q|IAhG zpXfXM^AX;Kq7{-*#RdjDvApI*|0)KsG31P}jirlFN=-)V_BZ9mf z{Q>$9K>|VfUogUgk2;0k;r`1U4b%T{1pYU@i|R3mY{F?OK+{kRws9MUFkZ)i%DrL{ zrqKf9k*wS4v4!F%uiIS*2K#0FEQXYQ$f|kUc~>uMYoFJc3BOR_c@bdu1B<@S0{Xmw zr~}4!RDY%7fLM%X=zZRzidYJCGb|4j(H33OHcy+mWLVUThLBh$8s`<<1zY#3f-9O} za>~y_T1AIfd{J3HV+IYt4!i7 zCZXCIadAkj7MIN3mQ(~@jZ09(xF+VE=N?k;ynp?(Ymn3|T0&x-SdW~F7guiyRRP)A zsYkQ@bHykN$wAbJOT`8@7oMFBz-qdbMay=;(u=*LkQf$GAOy=XAcSY*aylU5m1J~* zP(^e>l%?B)XhhJq?Q^R)o<$3`&GV{<*d#WG#71!$tOEJtX7Sj5R35X094Y$4VvFbw zLVu?oTps7RN6&D0+ql&fmx~0;z|(z+R7T6V9AR;#vvgIZyzw2bM;V@Xk87MZY0&k0 zADkW*+tC1uUeU*WUyZJ@8caJGOxMD2Dq>58aE1)th;MOFubnx0$VBq3s6U$&1m1=# z+ZIeuVmDs_@2h2_(gZf#l60C>v5$4!D1UC4^Y;aG**XW)5P}!)1rA+jYJS~uW`VH- z;$TSZ7l*LHu(*3J7E1+mIAM`OQpd_oKH`7Nh;S16hEW8F#m{*?f5D%z=12AV9r}n? z%Gwor-@NTO|7LNN-F(a3zbpM;1u0?}<+;-Q;jw9#tiCZ^RF{vIUAq`88KH+nT7Qfn zx6ZV8)!v$yUHh%u-`h0B!XBV`JutyRN%uUw3LLH0JQ=9UW}`wsUuU=aE_Lz2BxSf z`ZTSKJx!60r)l*W>H8q9p^KeO;$>{{W2}os%e3xLnKqoJ&{^sln53&?Wx6ai@Dlka zr+*MVM?Id2$emde^<@_|yQ2Q+FlMW*2oX76zs z1hXp+d+Vjs)XQ{>Ltlfhw`uJ(e6t8MNqFQAC=i9i{n)qVNPqYuUUu0Xsc!$n z)DVyOJWc*G{lp~PO`mA;FM4I2by!qQ`^T4(kS>X(K^m5B$)&p_rKC%`S&$SYS30Bw zq#Fc5Vd*Y`2kDS5NhyB|uh-+t``dr^x@NxjJ+X7nnKL_ce?o6=eMMK;C;GSp2(J!$ zZkc_*PVCwL?0WC_R(MsVZD8B>a=-S(lqGlwr+vu-@1Q2e@^X?UvS+dgC+h?O&*Z>V zD6Zh_-Bz`hI&(71#Hz%10)?>FMB&6k-#qDsnfOYJUI-PH-9=2~w96QjS#Yy)Sc!cY zhN$9>r>rXRDjN9xsKv6|jH)R9K+GU_v>bzokVR#JCGi(FJ$l%Fmep~`N-Tl(#ZpBh zGYD(zwxlcZwSk09f2uphE{D|8&F%!lTKO#X{2br8%vKM>=p3r}v&dDGcCYwFai3s`(y_msnl+JJPj;yal|CLA zFNciOsByZvey!yp`8mYKdcq>dm6}c}%2Qj(%!`eN*D76F=)zh_805peO7ZicIEW6} zhcsvv;qB=OCsE~??Xc$;nX9ch3Ucw@Ep+LL`d-w! z#F87{FN15)Bu(?tM9dj9DaF^aXM?p;mL_Y>ee}!9nCg6S{K&zw$fPPUw26mNp=$Kk ziO!BJxu6<+gm7YsOBLB98x;hrueiU}JOI!0TG@ojz#C&V7o%F{_WDLNkjg;GlWa(y zG2Y^FUL%`lK}A_n3f20{DYw`K#cEyqSZ)Kes2wt}_+%_otgDv!^sitvQxSzluO8RV z6qe{#bVvX>ptXhVQA=xkwrN!n$I3x`?-`Ax)o>K~z{;WRY-64ixT?=ZD)YUOkQF8;zwtdK4@+Cg`%Jdm)(VE(DV z=cRAG9wS`1kN2H^h;AZeB?z8&Da%C*Pis?|V}^ePO8HAKX#IF(Hd=wd*u8~#S--YIQy6ah) zGEHzi)s=bLZEIKNQ8U4zO(Bxcp*uBB>jgd&iE5cwu-Oj~wGk;PqM2^Ro^^P8JWXv& zmoo3S(Mzj4!fE{xzTYW($x|Fl9wI>fd>-vsT%PhB7pH&*!7ldCYtFj`l2``!ax6Rm zV3_)TtqPdP0kOZs$%QW>^h+_nb0uJ7s)%wl(^oIU;(Hn%8d~te980!Mr4i<7=Ddqy z@%9=wFpRAH4Hf*nE$wN@5hlA-T~gMr)mhf@=MClI!A294Hbgxb2JC2TtahBdzB?vh zdFq?Tw;7!jZJ3+?z>kFWPwA`QP_}}rP;gM#`MrxtAy{U+5!D1GJ1ukAU5VQn>9ByI zL`pAv@C(j`{Fxm0{)6rY6{(q}S(Y1&={h4C!~s49F+xfCPx74Xi~1b49xlag6aWi( z-Bv+RXCWMSNy-WG;92r8+^j_0zoH#w&9;q_kfefb!Y{4nA!99w=63?wf}HneE6M@# zp@tg}K0_uFQ+Z%#awN$Nw)F3Sf%-gD%z#f>*Zk7X9AC1eFz6JRuC-&$wlHHE+U!Qvs^J!Kw^>1gP^xwXzKBn z>i*0#P8e>f^5(?Pi(dxTP=qHP*E{ffs}rF@s$XGg3_llkY#Yom3BA@@6V*;T7l!Rs z>`v)Uhn7B(rqJZ*eb-og^eLudcmgsdOhQ=DPV3Q#>;0%4A4B&ZbmCFb~Gz)rqxI%A0O2EANfw|;9SZni7725lF7I?MHVFV%h7 zlCC>8;W}s_TE!?S7;}JqfQp31igJ2(&>*9)E;X0fZ56ys@kXp@Qmr6&qV7EtvrT}o<2|il6GU;R!&zgQb9#lGxOf}>V zjlJNO-1rze*}<;G$jHMR8(tIHO88jqxd=qHgG+W*Yj}3aIk15@JXmQ|AX^6m!znMHI0&F?XDjrh}pDrJtWd|uv{ zhU!nMM0$uWAJxu$!P+S3C+0=r9q}j}c#Pn8lkq-i_{MJMABaFIM)4`?1V>%&L@+U{ z1A4K^(UTlhtOgzQXO1&#Z9^431{RLM&ywe-0_wq7#R2zcr0JqQ4nbLyogv*hBvMjk zj<%sM91<}2B^dOSTbKIQ=t)xt-?|0YOjew=Q;j{_v@p3MoUPHlTFN-MeFO>N><$Q5 zLhSsYZ_n*^w*Eckc<<(Fk<$dBDbgdH5r>k^Dln3$sp09MxdUxsl6haMm5$^5Qnpjt z#}XYvdaqELCRTaopn#e6p|E-)z5-~X%1O~*^oW~ zO#CLIY+*Gyvt$n~G&z9*dgCXtO4ah&q%ELi1)?tB-6C9)kn~!AIf6!aX;3G7Q6`7T zXPd~AaG0Z^;Fd@%m{aXZMP1tRQ)UVj3e5RZ|EwY`r{sypVLG`!7{U-z)ugbL@9tt6 zj^5mv(bh=z^NLETeF<6l2V1hfvEQMX30AF$Nx52HUgLIgadXksuQ`a!fYzJ#7pnT< zk_jLApGyiz%WFG2Lvcw}yKzw8aGWi@A2Yh0ebWkA9eKrvom`01bT#;^=6yaUbnAT*nD!0LVB9VO{Y0Ms8m@63h zpzmu4$l=ZIMuypGJT1$8Y_ zq~63HK_tF2o^px})31!fUdNGk>_02&mTK||3K02$@r*{eh0;sZOaGju6MCVc+*e?D zq20x6MY8bf=5IN&JU9^BPwkj&fk0j z1(*;t0GUx1_nBW8D-rd~#vfv|SqOetXS*ycdJcwKm^mAz`}#~w$K=gX@S;mk#99cA z#YBPfUHRoH>d!Yo26=eRWKvru`=HeFC=7%wC-6Qq6r=_DJ@y+(U;W4)L@%RriwDDJ zr?oUB{6fBVeUPyMw|se?Y+TMLYDaGg=u?&3P-lIl%xtVUv>WE9!Y0kxek z4B4w0*8dctF`(a^^4DGS%fN9XS_>U^SXNk5o5Y#Z?_P2yoXM4$0>+jox^O8qx1~w2 zhjEVF4xK{e#>qD^r)^Q{SxGcTD@O-cIgKjwk(6`!!Kx5ek2qY^!a%_wAqsx@fMxqzdY-1zSiQCmCs(FGYJYJbNH5o_M9-{? zr}hQkha_$t6@I#JYuZUu5KWAcYVF=pO)JuR*{Ssb51lUbS}83z!I$Y}Hg8Fzo~}BC zkUp&lJO1aNuzws%I?2X+0Jw?S9JRM&z20pQw>kVo`ceUZ-mzdzs}Z;89-I z>yck?Eq;L(s%9Hfs8iCn)!M<#Y7n@|K>dzzg8Q9R)(%>zry)y>{ubnBZkR=L?+8m2 z6x_T2McF6%ph@dI+<*uXwx{(ABg>?JZAS<3_FQpjxKqrKyn|@OV|BM&)6#dIR>BkQ zEpKtjyW*~fS^Pb67TGwolM3c^b1|Ax3N;`a2pJ}M2veEskDj}n+CS?H3>5MD>3ZGISP9QJvyKdnVD@yAyk6K2p`5=fk%WeQ+opL*xF+_$s0MG05sxZY7%Ph__7z zDwoBGMJ{OYwG7#j&Bxo@{~GF-rKIh@Kw#p2#Ng~d*2R;35gN_uw@Sc~ecH)re4QZh zY-@$JYCBjhz_Y{t@B)LfYrpA&z!mEdh~=l#nWA%j1fwvmLLR!f28}DX;s0Ppn0l`IK{Ov`;xRt&RFXpt$Mr zeh#RddPOK3hI1=-OS>Qdqw=n@B%b-%}Cj065N<-x>F zUnJL*{H83Xpf*8|zI@|x6pLY0Mc1)!_{8US9S%rFCUJx%Pd4R`Exg)P0XqBI8oQr* z1@X}v>rzH|{8N}7{b|E3^3$6vtF>UA59n@sv6a*b_Cny*IrTc=P^>GA-h_AYTXji3 zYxZ(}0_+*+5k!-d%(hKmLr7Xi!1YZgjkR_*3D25TF!>wf{U%#+wI}TJ@k^GejcSxh z1SOENb$r8!v!gnO+&9WZm|48+VHubLXTri@B@F^3=j5$>9*h+K>O)frc1|+YjBIwBm0UIB^46#ohIQYz+ zGbj&mjKt{K!!*_r5&<%&cVVgM4y1`>C*|hJXI>NF)uqUTr81*3J-e6{F$Z>tb0NYj zn#yF2_#zFb>dNSB=lMviBtOzWchgE&)$1BgIuhwdvy|l`^XT-GZ(;s=^#pcpR8CZl z`*r?xp;eh>D!YvUj0t1zx=Ai}{3a@L87A@~dJwfC z?3pM?3;}LxB@m2SQxO zgYyCX!n%y-ku=oXOL%qVqm1PE{>D_Q(;a8kh|^#gZx5Y1!VJFD;BDv!>Fo4<8#!nb zhdQ)Hoh$Rg>pon9uua42AN|V?<*Ua@4oJ`XCok8=j5B zX=ul>bGW>fK6RjL*ikz<1F30FNGZR}u<|;X+{wF@^u->za>3*T$^3@wI8yPSaQQ@D zMt%PpcjZFJ$u*}v@8(-4HAc&pa*Y4t<4L@$l51||r3+%E#`AJ7C3)|VUgFNtXBA&d z*+g^~I=%;fe&f~eQLK}2NGWY$@U1KPM#6~yU=^00s8UF`Ot&4FHVbjRIz)$Mo%+h( zgq(kjT;~bLy7Bea){PbwE!2Z8;{|^GXg`B#3w<8r~Wx$&^JN=f<$N|x7 z#%8Y;FMlM7Us&3hzASpL-sOGF{^-+0N)`n}sQ`Mc&NE*JddFQ%F~ybr@s;dR0{Rb1 znp54+$bHDwW~&_D{v+s4CU9=tG4}49yFmL(kr=7((`Ug?ELOdL^$RJozmB;eju?w6 z9~KPi$#TJw&D7|UgjkD)t`1+|-$W-!ioQ1-eHGLB2t5X0OgA+Y_S+PpnuPfn9NyZ= zUbTd;T5vgQG3N4_vi7JV2D)J*>JxTi1wHd0cZqq_UXiegH~1cxU%ZgnS0o8@UzUK( zX7_D&Psb=T`Fj&EHJNbN=gtxR1Xgyog>fc))l*-oqQnIoZpewHh^1I;WhHJ+yUQwq zeK76~ujDf@H}AMs?i!O()SMiOn}Y}*h73W>er#@OVZprQENz*(yUXTDGP*z2JgWqO z;5m$5)jNG}_vy4&HTK!_j#XI$}x{vgK1Ty~w zCHPQ+ymYB718x8C62+`6Y%dndQm6-PE&g5H5Y1DtdD%EXZ;h}R!oez!}zc5 z0{tWC?_w6<9rB$PZfgaPY5cHR*US&Z;w(h>O}HnG!#B$e!;QEf)GU(iUxO|-vip9x z<3uNx5F=)B+-Hq)aNPU&155>sqrsU%4}64k{qgY#PL!r1zatoiz`H>6{|Seo+a*#c z_b5InS1A!+bfBn_F#tl zPP>b|4plEFMvPLuPdBYVgIddR{-@{u4L=P4@IG*&qWQ1*rkor2-?8#&9thiX{sR=F{s{4q;NjSyCWUmszXx{!0G0<{ku3j+ zsqY$ta=#4@s!>UV_#*(GK>_{Yf_vY}|K61KuwF>faG^Z#@1i6CK>eVIvA1vm@ctLM zTSdCNVh!K}i0XleFZ;e8Jc<7q(s#=zbnqd4w-4;$aQu;TFWjhN1O9zo0suH3c(cm8 z7s*uf0{>2Z|F=VL3hzb#dBb8uzQ5BfRTCqsm;6b8icJTg11w>|=grl3H!-h&^t zHi!WEAIwPEKYox9u-)#}QKF~Bj2MZT7>8$b3GH>dhbddNXSk=vV|gKM_kkiH346j= z5X1{uN6EIQ-~D{MI)C>Y{RzxO1&daW!*Ytsc+@TpGk|dO(D4@fR79y zn-U8@z&j*K;<(wB{T-l}T`>~LH@D3S5$q4>2FUB@ygyA#n}kETAZMY7mNbYwtWg`M zp8UKd5jf3yOr#nl2U!0wnMpS6xUy;QTBMdzfA zcs;s;Sir&)2rmkcaiqyks-D64I(371l(}?u8r<2je7DHL$f#$Cy^jeU?r33cD%UVI@7cgH*OxPl)h*W3s|6@2a&5SV4E;IFHUGHSj6Zwz9;E1Nu5Y22Q|6@#{RxIi zHEO{@YvAjro!*Ux|1(|;th~>`a3Os4_y?PtZ&| zKEwyuXzy+9$4&0##UUhlPI4xaMT}2xbmSZN;B5-iqL^FSKD}iw&nJ~!9ij>edEG~| zHU@{2ZU$gvl7tcdVN70ytX>nCOtma;qZGc_qfd(FNFuHbiVb1oDFUb@B2ru6}}sVPLX-b zGlddBBS$p!63Wg%nN8#%Q;x9wNuX;4fCUXHG8vo@{#S3FW0ICJAb(VAzz>O+J)=045*2v<+(oi@o>uf(4af|fyvmV1ad64)h-U?CJS z9-~ti6ZaDnQ&XRx_xqRuW(QaT`1qZ404D1V9;7)Ab@&Q<|W zsH-k@h;xz1Qi>w+A&HOI>8$c) zN2%Q+`GTR}ljy7W@~QXHNT2T3S*Gp#G&^vrg(dz`n_y%ot3z~&X_Dw|k)u{4Scc!g zw7ICB$J{aIia8z^5Xg5qIq%Q^-hBh-5)8BC7)4CJB@tOeU2+PG9qJ0$T$mhrjI@!y z?Jvg_PbRzCvBzs>9%fpE%k~0bmC`sYWTZdX`az-IT2NmxgNwT&hy3L5p-_A!(HDHn<(pgx7{;IK)pPkK6Z(;kM(@F zUH5VnT>$b3dEk;-f))%}G5D{K;K5s>fuyBYv$D6CY*icxQu#rlDOiiYuuh~0I*iqK1V@;OEt06zzy6Q zw7Y7GPn`B6&I``#ufg3q5rc3epOQ;hxd+<4z``vL?Vl2|2)DGwX=G}u%tTZ(_(F&U zM%!bfcw>9xWstajP}u_?Zf;40n^&2I^XEGsAyjB3|x2Vx=gXS z8t8Uuflui-*h5c{ZQ5RRt~qnAP|7#(i7Z`1BXv&VUh$6E`Fq8uw%g5|b{6Zgj&Xri zv@HR3M1RowZEcMaR|rogpn>)u{9oZud>e8wEFKJ@b%wUaVshKBF@-kEBBtq?FC%O+S=Q(V=S17GWm)I==r)qHww)phUS^k`7d-=v z6VJKuTCPREC#YA%ScgyynO?j|7IWrl$2Ta(gcERVm6uPlg5x6zn2wPfI)5M@m-lco z<(^+Y0EKZ}vo8)V!VKqyEz44FyD->2P9tb_6BBFOUK@QE2nAu8E%kt7{PDBbvjAXc z`0xFz=FJo3{`Nz>unsJud=rkC-c|hR#9RmLgG7SO@0l5Hx9Q`0u(UHqj3==TQv}d8w*!iM>z>%4l}k zrK}BY@^~0DwjzJO{)1e04#@pj5$su_@te9}ur*W>?w-iJ&wjq^Sa$im8~qCan+XyFuhHxBEq+|x2`9)w zDif`x$07v41B0Dt(>P=|*(+7atjNJmo0vkcpa^2m<;esX_E6<1PQlj2-R6;Z4ZZ0S z7v_=s=V#~UHa2`SJKSyb{n<>?$+-5t52%_+*v$(=YGW3#%0PYYmQfE&Lnbj*2_e7X z1T+xD0s%c^D^9oJMlj%r+E1GEzpE%^XVExgitPckX$vY5RP0$xb`mR)KFUj~<%0Bq z7SunhuVByxz$edPFca1bf7SEd1<=;fSVnFYWmo=c50cXYhY9);VWSnf8he4M3lFy- zQ6iE|V37z?n`sef_;F13M{08dN}@OR1l&*AVXOtXx?r{b=DOghJ33=j2=^QkRN;o} z>f;B{SbnxOxmrM^zFEvFC!AA^x%4kx$urbJ?pD1}R@6>4t9&egXlLIDE{91nssTEy zjx74&yq6|b1VF%N9MY5;!8VO83aJ+-pEV4#NF_L_%X+H??%Jz(WV*u>v#I717=Z(H)DgnyNb~X&gm9v>1j=^(M;Ag0V6L>_ z^#+-bwoK#N_Vr8UtzOUwZd^?HMmn=4YfWMJuLxU-_UwH=xZ#IqDMZ$;z{3d&<%n(W zKilAeBK;*!ebb5naiRV!@_TA7FKPy7=Ch8;0y;MIO&A^?mG23%?el@YP(M}LP$dED zON9wY5j~}5kj|T!%w@dsb{jnjB2x)N&Y7mNBZ&)X*ZX33AEF5Xm4|aTR0N;|zD640 zYx(WipW!$LQFOfXuAkYz`cUMF%v!%|<5N8?ltWyt@Al^XDim)xczQt0j41}MNa>{C3APVz<{DDWk_i*$s4c6 zF~UAMWpj`LPsq0eK$@r~1jIjybN`N1je>F4X|*}5NxyUxJ3szGQHTOM;$#DW)Cvz| z3s5oUY)U56Un~05YuRy)N^E%ItaWywze{LVix<^}t05uNdt9m_X9l?F>=hs0K`nrOOj`^G>Z4f1A&QV-})J9S5 z1SW#UG1%3$Zp+609!EA4_0BXBCBrql!zg3tw!p??8vilL8)B;AC?FtbSC)LMXZlnk zGGsBiJ#)ceul&GAMQHH1o!MOfg(m#+AE)=l^toH(R~x~t1gbGD!L5%Ww9R6E!087> z_v60Ndu&~^*j&0P*LJeUEU)Ku#WyMGhhq?DhTKUe-?84|`4Me$#DQ<5Laiy}Bl7Fc z2F-Z|BM1+@^qX2e2O&K~o3T2Gj&Dm;G?27#r zCQ^5QEQ49=g3Ml*4SoSVxw{4AzJQ%J0+=E|TKlzVZ)ak}Tn9%QYlfd8`S7ArfB=YcLaUaDVa%DoB_tLf zudLRLz4ZQ^c?a82SG|9AHTosMqEV++ljbA{ow9}^@T!UD&^{5-_tr)yJMXbF1DnG0 zG%df^;SxjJt%8OA$o|ZFkkMB3strBp+_-$s_eHR9=HT(9u(PFY$a|~q)$sPyDxeY4 z;4k#l{vbPQR0oVci>j+gky2-TBUdlAa>TyeCmy2I_Umev6)#bMD1RvXZor#{d23oZ z*&I+}jvUvR{DGa^*tPb@D;l12pf6$NN_(3x@n@?f&{%dPkZRDvsV;TS55E34%=CUM zqT?Y&SD!;Ar|8-;NxkPQMwd#E5n}%{kNK_N=M&#$dn8~8Z{&=yD^zZ|wnp;G{H}Gp z?FMAoPya653uoQ0+gY^pv*AI>Omu0eu?S$w-o+nxKAt(Nm|dSOiTDsY>Jx0KPod(# zHQw;BEXh?;%ht>w%xRBvnknEWB)K?b7Ykfm^h_FC`@JY3g>CE* zThA+}-XrF20pYCeFhqOco4m>0zvY{Se#@bxYvC|u%=;OE{}S)^g6zJFx=_ntll;>c zJM+;t*&8AG6Z5|*Y-3h5WB~c?8xP{QZ;CQM!9b8=7@&7z6+p6`*bo}>_6*EgXVR&z zYtSsz?0{(ya&Ur!$EKc!l|yP1DYLkLcy}*i`iboO&VNEnLB?W+PRJ7EbH(qMeVm!? zay4zR4fs~tZ}?K%{gr-Qm*66$CF1qM?an^R+rrVTJ_>lQG z@CGwyRp?h@Mkm#yL{}sFogx*MMJe7WKNB?RWc-sc03GOkFL@=@BLY(~(Cr|@>)Yd~ zAsF$?DZ@w?puM4<5SktuM2!v_F=Yz00(OjVH-QO#II@nqs5^A+`gEK*TB$Ynl{Qrj z;zNi5u+U--@5tm)uMNV3w1Qgr3bP?-juc1s=%$!uz3v!avyksde`Hr`HtyG>=@!1; zkO}z!Vxg=A?9aZCKOA+@Q|saf$#s>S2r%^+@d)@=&Py*rqk(%EACG)5E$ z-RQ)a9TZvjF2W{;|4hcu?GM$=R~h||-N5y0CVx-uIE0!|yhm?qk9KE+ZOF*=!{F8) zcTE?8F)?*1S}t?oQu~a2w-B9%>kI{J_!SSOT9^cD0rC3_>s-xJ4rErxflm5;8e|-K zp?V5?_fwZ%1ES@LdRBKp`A3Ev8!K`pUw}Xen$p|Phz3+B>Q0`K=)pS^$q$JCO3Ya7 zXSwV@ZI$}}+NzyQ1%Q!~;!Mr?UC9aD&MMVeWlT(x+)}a@i74?cOt!iIPi;GSy-vu# zHCs+Ep>+#c`pY+gq+46qu_7rC&}!DT?=f#G_x<1LID>B#bv-w)2d4ZVN|P>r23+87 z;)@;&h2@x+Kj-(dwOrZSHIYJOjG(VzSgxEk<~>5Yu2XC^vH+{QDYS`afqAR%zgWj{ zK%o8o{rQ39Q`)brL^I@_D`>raop_2`DQbh`cc2HngalhmiqEZQ5{=M-@^m5zhk6 z#5PYm?I5Fas+c5VuU-`DO%|0XvGpT)qtK+K7S~WbUH%)FDc_wtl+~LSN;EL+MD{EP zPc|mD(=TecGr$;qAWNsCoOw!K?>hTt?<~y)@2>At=IQS(zWxkNJMYVzTMy)rSu|mO zZLFX=Gs5s(dN}Y|C>-QFIea)f4#6o{8ddLPAhYYB`qK-sg4PDJGHy12q5k$6PTICN z#)dRPe1o)m9Syuww60a+en;GqaMS1^FGpL$^^e%GG~iv0{WcxlKoHS-=~vYoIvi6& zIH|&2G@EpjBVQ^^MF@jeaq^htXq<-Zaz@OrK@bvwNqk-bj8Lx%@EaqVy_-3EH>GPF z52_H{EmOA9i@muAjZ%CeQ-w{&c*W|a?a}4jleW2wixvO)j1N6OHJp>En^$%`LJ?Px zDin^m1Awh7F)+vpC@$g|h2c>)7OVNLonjUbMsdp*4c%clW6i-^FQP;Xc|;@03b&ay zdWMSGD~mOsiweUqr)FXKD7TuJh3O1BrWf+4$)-Rm6SO@R}~1`Ksi103jc{JhS|oL7AIK|YuF{7-+7FO*fqo0&sPQi@VHGyfKn!` zPpXu|$Cb$|c1#UKIhM4|%75e?YMNqhd_$I=9*N3Mp|g^U41HX9gcw}4EJn3aIY|}l zuxD~L%T~5yEBP`ezWh$)1v8W8u?O)auAE0ccn-H5(LejyJlo=E`8o&j+f3jx+?Blp zW7~EIG~#h7$@Kzk$yOj{u@nVaGl`miqPS#-c*F)#1grhKBXD=)AmUcOL>Gte<_};+ z!Sg7pNTOukzIj`z`buC)!G$`4iS>$5C7cEWMhO-jwf&df3FBUS7-g8AU|;C7A1YSx z8P%j)cut5Y#HH%6P^A|cGgJ|jw^gDe`s3&+?J~sUCzA{R7rc0iPUWuzq5X75Pomby z;N1fp5uHGm;Ja4EzAg(z%cddrl@LG`jcV>#?#lZdjz-?W)}v}dT+`2vIzrcpozm4a z!POx__{>?jvivzdAv0`W+o$Et=t`ZQRRHgjNkdMnR{I>3#&}#Q3&_$+Ymk6GySIrI z`(PC8kvvDT&@IVQ)?=(^W5Kn%&@wC@Ic4iJz~WinfvdGCaU03L^59tB{D#WTE^_DdAQ2j!rWgLcRuKn0EH05@el z2NWSR{-4Q3Eh|5&EGyKT7k`)$lOV3(5Zdmk*u}83zZe6}G@CYSCK&vfp8zL>H)^01 ziu9MC?@DKzp+ksFAla$R*5?ggi>qfsgRbwE`9n9m2M1#3RZF`=36AY+#pVwU<>sET z4y$|(d>S4d)kOL*I{&7iSq@|yU>0*oiOKPYUH$OoFID#K1^laX^~zaW4xE@UG+G_Z z*UmsYROE+N|D4!9c6tpct5%A-VPOc>s2BB1p{gQ}!MY~~_@VgKXNWl@1$rH(lWey0 z;sZUM1^D%H2cOvf%_{_I{$my-XS?Y*?=3`9J#bdI`>^-l%XU}kkDXI_048B@Y9LuE zg^2(0^C6X46!GC83K)S_HM)SgCZpVt9LwR)MEYbzRb6q8pWqs*h0MHBGQTwvu=Dst zcpk*D;b4pI8W2$0vWFJCwYxoM*jdP+TH%5<)K@GtGv~Bl8zaf-EFAGUu_C{=1hF;U zH6+2CKS2cDJMIv)Eg}?-fbEi2qVtkac}0_3dh`m-D6*?^%^u^BC2XwDiV3EAIn>_x zO+>4cY^N{sYtbBDOuzlBo>M4n){z7wm`ST3ByK4x%vUVdXm3@k?c8~m#D;)Y>2|-^ z))>}8H2jH>W)#&>Ab9b2Bv{dVrfDpy!m9o zQw66}noBJ*bwK{FaO#74c_Oj7g5>D_#O{BD2@>jvs~8IuKxYD&l;3AU8Xit+Qlv_{ zMoqOuq_+-lS{DgKheVQ;L?>$7>zR})F6*tMrK}1;;)8PNg|MljjM|AUuh4QCZ(!_S;X75!!yz8gG2EmPRI<8Z zRL&D4$7Hy@fz>O3bDH7isf7K+-|7*pN%Ml)m3-}a@9k}TNvVj!;mvKd{KybtHesm?PdP>hO+>K$FWupQ2MaqSgAC)?`^9jR!{q{UyJl}hCB zAw5y!N0ua|@aB#Jr(S-kpikKtwq2&jL}l|>b!9BO`8(^9u;w1(-MI`Of>j&e=5fo~ zVI#pG0wAH@@TTmXE1W(cz>gd3mBB?YAdn8&NR=d=oG-o5_-0NiaSkH}Yl^-4K14df zr`c(IxSGJ(A@6QXmRdDo=r%xG%K_I=ZCsL$Nkm+LD(n z;JzZ!%HbM656tu*e&WJQEi`^4mRxPLnxv~#nsjP}g=s%SxHR}~V))wucd-6^M*7Xf z4c8ERuBNWDc82E(8s^TOf9QT{Y`%WI?tJtn`ygvVzEdnrFs1Sc_2_wIDGVAhqf%=} zX%I@qM$y%V>jy0I`}eqo`J{9qi{q`i1vic(6^ zM-^ls;Y=utaPuxtXqE5c)Oev%(I@uY1?_hc`X$3)tq$@518fnwdhgzL3Rt_&{yIY6 zU9b<73e76#c#W|lMJw4i(&KA9Cy__ysOBEhQ4eMrM#jZ`BI)fSY+(wqL>}m8t$5%?A`Wu`#9kI}*;_(0nN-#J8-2tO3x|K$XDq9|GeX&?GNq!!XN`h7OE}X&`w)Csl_blT^f=oip-~ROe`S z^5~bS()aY?a-|}2nhi%GU(|;}&%(8sXEc-u~DblP#g}o3est+ zB?H4o*aqyw@>RJMBu!0kp+=G#35vM*8(Wj*WQ>{(g;`LrsHpUVxPdFbA*;F5vztVv z=!z&?_MyhH^6^Vrf02tSL}cy=8N_E`V3rG@KEhB$2iU7`yFR2j(VJ! z4p{fVR?CAAez?EWR=^`&LntyH2XRNJu>Sa&0l-W{l!&kkmc$I25EvxxY=8+|o{Otn z&d$t|Ts;prE%A_}EP9hUG<*H7Z||=B`upf%O2&3 zENw~^e3@H#Mdnu&yds`Cd1i=dWWGH_ucyM_rOAhybnhCm&o)%{pw@1Uuu5i-g`i@p zSpivOaf}T8X#=kOO`R@18oylybAJQ-+4~95$KfQJc@HfH;wwa9_^Vs2BCTjb=D(!y zzSyAsk^-Ch>4&?DxDWAlaT$=8hhNBK!QFrZrH*0c{l+Kjv6CsSYDmvEeTt&^QbQkd zWTRSeZHaJ;v%dIbyYENL?qHak0s1}UK)}nA6KNZRwC=QKk+vAt)J-A@pA(s``R^&` zekT01it>vndXI*6e3oW2ds|I356hGByS5aTF1H}cM=uoL}5Ukq`K0=VF>dvS&#*pd#(U4ZKc zMc6R*+TA*bRfAMBm`19Z+JusR8Q7Q#`?8b-^z!yv%H4T6CdZ#~Sc{=QFDz>3@QIP@ zCh2m@jg(IqL+b~9k|{bbe9;+HiGmSX6}rRXcPNmqVl{qXleu~Xg*J6z(jLYkQK2;U`g6EVxyK2KVoE(>i_ z8e62P@4KV3%x55*U1kpdy`B`%&)lq%STt(a_h9ZhoB?SmI+>Bpo}Tq^^b5eIr7QNp z9*ZWS;l%ces_h@}7j}13&KCE{YvstYA4VR6usZ-RrdxOqJW=2Ux^3n%SSuROnrPj6 zIpaPMmQuUBUt_cywKKRk)iMHH<7SpsHx9g@lNQSp_z)-AHsnG(!Y8)R`TfcFa(a0L zBe+|bCKkfDSJ;*76^66|>o34AjK4X|&v;xwjV{)sv+q)E!wNrE{ zSKnt~SCb8KgL#?XUGE{`&1}wY@Q@z`w47{8dKkCQ)5Uo6^ykwQBf#&AG{6cCE1S>X zm-5rhQDXGMg&#K)*4(*QlF0-uvb=buJWm1uE1m+{I>6DOlPB~*r%hiyO!KQytqpSF z7OVFp)0~iim1ZvIVJU>me2<;V)i z+)_bE`dxhTx^gr{Fuj7(h9!?JrWD)w{*QZC!dali8jY$quB01ZQY7#3i5SctU@Tuw zmU~rbMXvWv9Dwf!SSU=qy@;%)*pb9- znmES9Zr<;q`Ld9`VEfW@k!L2)B6b5X30yr2P>*#gseXsRvM|8VV)OT%!83NKoywJ0 z!1F3Gl5i&UrS*S{5xvh5(#TBpW)7yo`vXLOX0nO z4DIO{^}8G`ssRlvzo1G>8+93wsK^dYCYB8k!LiqCw-;}>P*UAG-Ds%4Atc?h@o0=q z%fcLYWLVDe$0g8+7R55Vro7qe1z2sd) z=w9a5n$&q;T`qsr{KG~`^YOu=)baAJB2TAZG^^P|3FL?Mbc=BK1SxL8+r_Y)NfPI&{G!kxlxl2mk=+Om2h=4RF{KB3%@E^!JE>5Ns6MhKGR~o!T0RFI<{oF$)&eA#3jsEY1yB zMkf$4c9~In3tCx;EMFkrT@9g;OH|||fGVWcQ&nuaZ+@&MkJK0NZ~-=s9ykb@8lrX- zP-Zye1*$#i_zL{~Chwxu&#I7mTFfdAjllf!L+3oKMOtF-U;K!y-9I2{Ys)cI`O2}J zHSw;bfbnLOwS_LYWoLukSO+LZGDx2X|cVZdTTqcvfhTS90lR&Zm~ z%P*wf7;rHmM{bJd)02ZE|2O` zM>bUEWA$s+F9BCBOJIOw$f6~>mAnV{G-aHMq>)lKb2rhUJBFp;tj?^SD9Zx@4Pvmf zWi2aV9+h;kC05kGbqNU+f(v8aNkhu6>Escz1p?1{2i+R(Otdo{sidbiX+xiboBW}n z!Crx{2@B*}fs3CDjIc!?s3r#{2CIAVKP70?2J3#AnP}V>2l8N?InE%Ryn{SyRfkz{ z;8m3>j1cGpS5^EOwPo=>O?tySsZqM^_;@Fl6pg?dn(Zky-+S&ZU%@7;I2#NCt=jrr zAd>$V=gMb#epLJ?y(<4dKA3}w2)b-$2Dqu%xXg>A@#AJlG9MMCJR}H*5|JU-sU|9B zLe{k9@lDJ(;8PiJ+-YN+7`ZP)V*}sg-Vh&b!VrOhc^^}8#@^&W=r~o@6piC8pR3k( zi|r1-SHu8tT@x%@yUl7rrzOuD#X>uaQD~m2N>o!R#>m##KMg6Sc0w&^bvx3EfZB02 z`jg0=yfex%t+N}=2(1##C6uiSG4SEOzKx9ylEbmLzi;w_vCxWo`n*y(B=7~QP}oJp zdFR43XJVe48P8{pO`0Cr>4tF0>PxACEm(s=c`2hah~y5#eR0b4reh}EBE(-5%bUE3 z$9#PD2YVrGisma{0W~gyM^-1>08JmFA9jXGdF7rG2kgsU!X3jU8S7T`Sy9^AuXu0a zm-yzneTJge?5C%4z`2KsPMY!+m0tS`GsCWk54MmwUF%1me^MOM!&+Poqidw1tFZhp z#SpeQ-}JyToOygvxPFrB zg2GDE1qc#WyT?`_aAE0^(#OOI>~ty>eQ6z&y@6qof1xLopX|WRyctfjB~)bx^<9(7 zABch-(^uzIPZ?T0CPs#_=C6%|hU|hd^ctg~B|}Vcgb_*>leQuw5UaL-Wd$a-c4f;; zO_+0RB2*njt$5cJDb%qt0hbHoPISTq2JuFM$YuI|c;Wi?c0Vn!JIbWk%_PR;S?yeS zIf0XAGcik{a-+`kQ-zzP6)Ug68TTv;tV>gt-ESqu;fEYF;x*HbaF3bpy z;sdLCW|_55;sh{`Z@m32&;}oCZ|B>y?sk)EyWbad1IrEglf1ylweOQB^YEZ-V2qXExMB- zVmMi-l$ko_BaHRWQ$OaKMSof^}gcKyewq= z%&qYP>afZ(24(_0*)sd5L^N|;AhAl^xLZ#E8xFsDRmOW&&c6WP4knAhUXpD&eZoA4 znXA~83*!)F7$PF&ZM6FAFg#S?mX|)a7-Iu*AZVjV>g-@bG2c#VN*XkgCM{c?Vw=nd zsF6K_sXdA8$P?n#tsztF7@N(PJr*k+M9{2Q0=HBxDQejFQ{hFh^U)O5ZQT<8359 z2K2|2pBGRK3SMeIcD+WsohYK38=)aiZrC2Rf=k2pJ#*^6ZwFmZ-N14<;0R&*g)~1D z=y=<_{M@~vy@K%-|GNnvY=;rrGF*eLhY_Orck(;ZcN4g#boDC1|GsJRnV2{e^e##a zGL+T#5ri(y$AJGcyNDmKwfsZEo2^7Pn`tS{X#YBLTn_$P)%MPytEa&FJiw zdldB`pQB8l>sD5SZofCUTnL4o{n=UjkIv`)_CO^u*d&0l;RZ$fiou*gYMLt*bCHs}RZRPclZe7W8p8vN3g#E2q< zE$p;nQ~mM@oJE3zm}~6Lw1LbtY6O@cQIO75Kk4_WJm&>+XLx=iYeG{Nx+n)q99Go< zevu35ch)`XY&Cdo$23Btf#9Fq4LHFz1Wh2t0@EyL)Sp^^mAxZ=bircYi%l2_?HG$T zjk;Xc&mP{bZM$MdwPb>7GS%Kz(}T?zZe+G(sa5sRuOvk#gZIF z4A&@ZgOAk(EEWdoH>RXKz+f_bJAd4($&E8w>J&Se>7XL|;2_+^`5C38_VCB*=LS%3 zb*fA>YOf3ONl|AON^fjVx;O$;H9eP&k9e({7@W7~_Fe2nmw`d6{``_R? zpHuPy#mE{0_#IG%ko;r>rm#fzLda$a(A*F1sfR+PkiaEXg(Nlef3blcUpl5Xx2!zu zBB@@9-yv{t;;CM~zf%po{P;nZjz5|4yw$P!@wtD_`AuX)q0Tjl9{0J5dGL{fF>XS$X32;#njMJR!siAX2OLB2N4%~ zF5dk(FP06vW08a>HO|4BvWlGn-DY}hmbz2$S@21fcEi$T`-_@w_^{8)-^f}0B!xkS zRRWYb{~TK$srOb%7mPU9L1r=>sB8FqL)F*T_mr8EbYxopu(+D(7G7IcYfw-utC5`& zncQp%AYnt}$icGdQweR9f0l!l+ps1PmVqc_*AUtjI(~5Y7(LCw->+?(lzOh}>vbC; zD+x_5ahCeJ(F4d=2VMe<^<+pcs6@fR^Snblr@mx$TB15B-0Ny;KXtdz>}(~uLNo4C zISZw=xv!;`Q_2hN@%(!)6@I~Q_Ab@j{%g#5h2ouAPZoH-mC)rt(;L+Ppf`6>Hxv7h zR1o~P&xH~}1jQLafv(k{K>hNP0OG>lff-?u1Uy-lL8=jDa-LQE8cwb2w!gbXYKL>U zkn*}a--fdj(vcdK*Hsc;DBpj|H(b*x&cPtH&vjh$-A{B7PEX8Zc7Gxm63D>m z&(@FYZPD_MV&C7pxVTtE;Hny2I}BIL{94&PRAEEUzVs9Zi?u*q!xWONgQ}Uz&aO(K zpXKz&1N(RF;g9!w@6SFAFr9D(op&dNmPY6M^`od_>w$w;^>mdrL~P@UT7R()bnVk0|p0*X$G?-i(&@~MQIz}hof+R zaqNYe3rpZ%fahPoIK41RC?@C+^qeJ4a}T@ZPh-boY=IP=Vu;nKs!y@R)q^9I@PkK8 za}8y~fN_PX^LZwc-jLYNOBI%r;Sx?Q3wZ)iQ9{&ojF`(13=Q$V0JwgKHP>Vbd~^va z)zs~z1@BJH<%Hp3oLFP&z1Wg{Q0l$OmzC2$4qwhSmHX6+82)d&j<2Hl5U#8xf#%jC6Ew7q0S@;}L*z61=mf8knw=A30E+u!zQy-SN-wcwL zyPyou_64Ddlh;`|a@UP(%GrX%t)6#D$oT^ww&S0FmuY$iM#GS25qQaWz9jY-ovk3# zxTLS(9?W0Lc_+X9&mz^Pc1e)=M?Fyf-_*8HmIH{v&_Ls{%S&w~>Gp{pW%>f^uZ}2@t z6xds~wiCtrr%@Za$nxrhOOxcC2ArG1vwvD0TID--%)wWSYQdkuxbHWjGQ5ncJ&S@$ z5CM$;E+;;`nK2n}j5pS%n7O!^n3zO0)7GL4XjVC}JNV)Z@~Rx2Q%FM^GV!!DLLW*o zR#hS@B2@Wk)gPCQm>}Gy=%rLPnr(aI9nBchKzue)2k8fc`SGLeSLr70eCxcVo2lm} zlPza&1I{=E}l0F(EHF$)w9?3rJva z<=h36S5GKn)%#6uCq^@x7d6gH`>ltjWJ}%vh z)SrNl<0B0nydb39J~?wwh)vxh0(#tZ%^qi_e&rGAMD|NrVgfp$_e;)`A!1F}Kg3pF zmthV1!P{9PB3u!NmYfQ!%)1Eqv6gOoby>pRamM2sHstgEs^HPCuq-|{0j#;rbj5C2 z)73|i`sEZ;qRz7HT}pW; zG2eif@%Roqnx8=ejT>`y*mEOtENuzXR{AV~(i@kQ8^O2bvfbF@8j?%Kvh>!Nf$}zmzYxpm1Tvi za0DGqLnJIsDHRRP)!(2<@QC9rPLOrt1>75{Oz&lF&azd5ec^(*+BIxEvg zm&J5SO2s(<@?pW=zW7|{TqXE%@{yW0mGe)Vjix!9MG^O{UG`yHzm>D3M}8S`_Sz+y zv%KGVZnm4Ji=P1Mj;-(?D-26s#7W1oJIJ z6pC9;tKI^on1AfkuCj<3RC!DuvI?+KT;Z>nGFQm$=vu@%wyKV;W_>~Jq$!>4(<4q5 zJIbm69xQozEefwexe4W&1%>7b}uC!dCLWjjRapYXsn#-E4*mY|`T<9g>NJFP^l(HGhwMnM%sq1Yv2{M=p zpi8P-sX$=rbpN>GG*UW$jUjfh@W}aYL3IP*?T%<_KGk8yLun`OJ>>fe&UvzCVoJWizR)8!(u%+ z!2m5EIQ@LjNd%Q8`TRY}0DVk7eAZ-{cly0!S2+5hz1cqVjV?Gm{&+Kt4<=-u@s%#% zrH&z-NFK@H9DD5(v6OaYr1nAc$dhUvuZO}F47rD|&c*`i-YNg(%$zF=Nzl?1hJ*65 zz{Cdj3W<11a+C&bfc!_k{{spfo?ra)I&ecNI}wFytGlS+qK0J@sj?9Lfq9}xlDyRW zkV;iY?ES4SMis@Q{;)-ejDPEppk^8Hhrc0VlGicxx0jifxJOu!XL7UlGm@iK;5t}d z(y%P+1nH5u&h)_vkr14>Z=Xt+6Gvuj*!*pGgjW~mz)^cCl=>SPvw7Rw32+u|8kUoG zgeB8kwKwI57|}58k(_jX43FA=!;!YOelvb`0s*=gaHKA7k<(O%^zBzlD%>By&)Q$$ zcAxR*MB|*-1@jZjh^^wP1M6vNPa){Ob|R|xJ8jm11=kily`A&i@#O(XGrB` z%h$}~ld|(;Vx>&?_>nIz+NV(fS_3c=d05tXO)Fg`r@wQ?-<`heZ#tczNLP6B>Ity+ zw^SRN&XY`TWB0`DrI(@$QwZ^ClONSbnMq~$IiqgTt8U1?ZmsxVgkB@VI-m<4dzO*e zUNb>f5pA6p&HcrCXKA6iBFcD420s(S!cgmn+QcLr$ok%}D+0G{r_){pC@HW2EnUwP zuN`%D>C1U*XIxoN=JRUK%S|%jXXnoq78Q5U-sCV4i<1)Dfm};diqkD|e}dOh6hDqt zONDbo;LFm=+WihMdw~*p5nPf5CnQ}^xn|iHMc4Xp+CcBo_svJ~ohQoOv6rTBq8jI@ zPP9BcTlu^z>?Ab${PK7UZ@=A-wl_V`L5)sspSh}Y2vtLJLIk6H^dzyX{JBU!D;#W zpq&r!nkf$#9uA|2e44eU={fbX?W15VXTy#8U%3215`(P>%$Y3r0NwH8rVkYED4G14 z1)fsRXrrkoH<&K%#L8lW-eqbMAh+#hF@=X5`h&gTRQ@x(FKfW?E&W*3XIIQD2D*Z` z#(W#I#zSmW#j6`{4;#HT#5vpvXU8eh_l9(L>@ct1AIU#U|%&8Xm)U9h)|) zp+Eh9RT*U`wPjl@0kDhhiEg&Qw> z;ofw9MSKai(yfN~k4nW`&NgbCOwZr~b`CDPI|r}9l1KoOH3U6xNjs~e3i!U7BJ1Mt zC#r<#jX|zJTUL(@IO*=3PrQALfRkPnCv4}UH%#kydl`hYQdE@_=+gqmGxF04`3G0$ z!dT_lh1FS2fJ{AXxbX|75@#OJG(gn!2P`OSpQ|;T9MTCwL}Olv&Y}h0=7e6ygb`TE)Dk z9FAD3a9Ya@G96!nRI0b1*_0TM&n=~p6Jev%J+|Ji;9I}Qgf9kF9 zFeMOjZAQO8pgEoThXY*dz#|eLCPkr}b-4mR3uhDu%(5yg!Y?<)E;@3<1JwLHo^)My&k$o5-`sXu=+^28HzbmuoU{0xvjZG zV&OHZ0TR>TLbXyPqogpmXQKDIEX+d4hHM;SSA)Qr8=($wgx5xSWgjv(C^ys=4r;D_ z&kw&A{Y;lwRh=mA62iP2`8kgO&vD5`Ew-gyde4gH?>>?0i*sBC<-QrJuS{!+{E7Y& zY4(r!!v6=JKw-Z_n0~Yg+?b5+9LKwgxMe|W5x0fON4I|zaeL2Rs7*z@zbASazWwxd zS?B{hi}>*E2$HV$&_|2-Wa!hKLcS}se;l6;kzWrcldZncL=m44eX-^N94O*&t3UK* zL4UP2;%+(aC%=gC zQL5i_Xnc~Yt{9)jGje0SVF@1jPk22Gd#-pPI|=bh~uFa(B0e82KUo z3uA&t6Muj|$~av#M)ARyduPtfnK?7}e*6CUD}V-81l}DVcbaeX18I#Yu=Ney8tCh~ z75b6u$;1r)~4aYAF8@XaYB9`7X?ZVCC^pJ^CU+CE7h|~*3Lp@T*Bod z7O=>TC(8(I0pq{8KQ(iSE4Vrly3CWBwbRvVxXxc*5}u|CEL8v5{3dQqn77N&P$*yq zcLb)N@?-PvXOQO)Cb&AsGD|}dCBE;mw~8sYfaNckd-W0XmC7e9o#0yK1|KKTKj7|r zAfx5@oI>sgP)i30R7hKD*Z}|lvI3IFyhE+`0C3743gU zIxDIxB38U78Z**SD-noW9VXV3X3R8FCN{f`R3OrAMvkO1@l-{y(}<WZGOK-}mFL?w+?t5&XDxel<&wR!x`Oe}_lRJRdWflo8h6-}6CGMebZ>QOV9!dX~f zTXRLt+CYbSwBijKF_YeAWs(tdQ#5~OGA*)_UA0|Fqa$Y49!nZMJ!Z0Yv;5p^f3+CV zgi21Psn;7vjoO%z=&Ie`e!UqK#<9;dqjG;}WWOyfm{`Ab57U&9)rOdnN~xqX zm35iv9Z4$LP)Qz^)XtcWxw6q6^KFw?cWcZNV{7Ws6VNwb+e zqjyxA%j8O1yLUE^Lu&@wd|IH>Jn|Q!HLFy?RDv_x;3IK}F+GnuTH794M2mG=NSDJZ zoiMIOl?7I_;Z$12$}2--&ANW+J`Yt>K&L9Ifvs##qE@Y-S-ZnXcf*Lw znH*pU{!>{fL|&%R@L+8vU7^zoTE*lYzpv72u#~oJj~vzuK*S2L*V4LDT0=o_Q^d_w zx+?Dta=F!#p4Mn~Zn83oj;3VNN~*Lmuhbk_m9Ak@g(HFk57pbcYXE;ES49)i^u{r| z8Fpz8HPI%W>S(iVlO0CVOr$;3EC|%mR-0(65jQ;)ve#Nb^gzw^Mskrx+u=PmJxL3Z zm5!Pzja~!3l4eiL5D}S7L8WVpoLhvGVjj>&yM)|&f5*GSv_`$ttpybLKAakp9YOwPe%kd zv5U%JL#u?7JVvrB6Nd_R_4dFSr-jDkFOck^8%oHcB$&TJBN%_obwegl}3$@ z!^ElHRN9OOgrPNhEz@L4CXNkE=nmrNSH2;etE zyGBaz!nC+RyZL`C5GrID1m8k$)#(J?I$oF32|7k;RHe5=c_S3I7^!ZEtI|7A5^Src z>U(Wg;V7X($QGjq$Gwx@C7k5l;|O6}rT>BeQXz1uS(T%?ZLnf7yApuN9rRwEPSTxB zzRKb-w$I+B)9rLh6td7bu5%#o*XcI8hiUbz1;e6xv(tY{+Tq-mY0vGe^g*W0l^1bZ z8+-j&h;hoz@$+GwK13hMXH;ps=CqkK+C_5vD3cZyUui2Tq#CWD=G;2e^Ktq_DSeFk zn5th@D*MrvHqxN~srCneL{a~@ta8H4y4%Ib6<^)o4ffJP591zuH>%dso0T$hA|%PTK|mqIR{ zrf=%>6nzWSDz8p0&FOPP%`%O?4V6X{9p>@vs0>ahuh~Q2rSAz{eP8%;^F-?Wp#b?2 zI$SGJmrLVJ^~F5rKjrqv^qk=Ke^4MKw}M&8>raur7NIVPat?QDjHX2Vb$ICKc8U81 zQgwe0BXCe4{3_pEN`C6{n7JHxKJ@h-#jh&?bW12Zul=@6G z)*LEq@#q$xqf*e$bWv2WID-H0Yrr${P+Ms}}LsvfG zw7na7U<>-*kYydo^r(zMWL9I-rn=psU57UBtZNK49opU2wDZuG?JZ3nZbE-+$Bn#c zxN)u#jdP7`oOz2qpyoWI7p{3pDF8~}%G*S2gg|!enHsmk#vp4Zj(T{94T#xgTJHQ& zBMrAPEvzh@;U*Y8csB+N-osQ`L@^_-El6xZ7{!q2_*(n^z>faWLBC+knM=p`p@;YJ zex1X70L@^L^FmfvmpI@$QFMRy+58>W`4AgoU_OorgbPMQx~pR()`}t|a(5<8$IVDa zv_sqpuNP@%Nl|@_%}(~2QJuT^dYlQz?~J0l7UZKbM>R;8OwzCu62~}R0(A5cbBZ7} zVi1d2Mu*Bh#htMjRh7{}PR4+L%t{{F6^)ygNE+Pi;WTGTIK`NIW`cj$qmW{}RjMi{ zkhNIP&&Rn}=NlLk)5^+XQrk9KUj(<=R^ICc`Wu*L7eQ`Lq|z8kReodP1T*Y#M!H)R z;A0VdaUv)xg7_+54pz+A=1N|>Y6l+kJKPDYvLPjH(vO!^Lf zuTU_?sYz+8uC1ZDIoBfaUGf5jF+w?78n4v&{qVrTOSBd|t&es!C(@=&5T5~3hvYzH3Q6uk{;a_H9Cj+3 zB^lW3^EyAkr$zU4PP}DB3x!-Tb+q~FjTCCu!y=!j_z~D*$Ik6rn;Ld${Dm=)@}7zx zvmws{^0m<(8~cBY_S%>1H5=|L_S#nw3Fh%gER%{Jl{db1kqA`SVkDqNg!P8ez88gn z$%GNJZ{}iFnX*a@30M70rgW z6~3YKd49_F3VDTt`cW`|=I(X)oBS=ERDK3Vt%*gBX#9U2STla417p00zh~!t%pavu zboohi5>^uJ#}Dmw3>~vaDDKQ8(#Vse+K3-xMryD!u@2c9M3N>v&fg>N+WZ}PYW_|u z=@)AE3j_Ey#<(#BT-UXytXL*(+LryPyj0|$>HM7NJG6w6utZjt4fa+K|B`qjQzs7$-{GG@1QwP+&6P478+m@6!p^U*|-te_-q}xa&%vegArNRDC`S*DN$AN^v zu*!eH0G>Ri@gH@5UKDg)Xxj#3x~y{4wQw=|(EeZeuLAWYIB`1JD~O78G!dTI2h!j9 zA3DFl7(UkjKm1tbm(j?`JBNmtl`>x=uJdBOBiVlgr^^j7+R1kI0uSl@ib4hR$gXaf zwL?`Dq>@z3Gj9wi-j!v3x9r@09$4QWr?oLRw_}x zP*6nl*+v_CCuOhVz-3C6uv|3+Nr|75;8}mi(*^9#uAKNhrADb0=*!{Cuvks5SB@E( zM5G)2y50HDhBhOIf8{DfF;f!$2p0k7zN|-4+D8rU-%k;|Po< znKV1aooKC10kqdCL7hsK^#wN;g;1)p0ZB5NIBFe10$NvOkev8xxnL+$u2!zmm5qN2 zh9p-+#F|HGfZxMdjZ94=sWT>ib~EK2xvf2aUYq`{bvymhM1Fa6>GUsIoLW+&DVUes z$gwEsV|Xp1pCY{G=Okr|(v0Ro*@|M2>xad?y{3f3FN{Slr$*hbD6QxMl_1$q{f5j?{Sd;!58lsu}b~Xls{wtxS}b$3v$ayfL|g-I=95{S?m90sAjBNY{lA9BAz)!+C~G*P~Pw4m-SE zZBB2rElY84)fr0VS2I{WCRX?6S9-DXI9%mtIY_sM1E=Xd zS$bbT-Q79b6y_?*ur-cK_<4$^-?HA@4h_~Sm+ z`-l*erVY{;fGbeX_6?oK`WLhGl~d#cnhNDS=~EA7>3o)+3A*}*?#KRjlBsc1-03@@HHPkE(Be!)mpjcQ?snxd*O`FRjxS?3rWj0DQZxY zWVHgaHZvE30P$%-5a=5^3p<&G%w7^;phvpjpm+SFWN>oT67<;%jWwR>oqpjXBVv%F+)-_SEYDT+^Zlxsp7)paJYJq=Z5>ayPuDoW~*h8Zvc3p`ZOPdB?kC)hx&i{#zDR*+=9p(egJ;tT&-pKp>hp8ote5Q%l*>5RD2G= zxy0%8*F%4{n*~*2KkYORf)G?I^MLMi1xxziCRlk?tSEO>1xo@x%~v8Q1q7kf{P-{} zIHx2AoeF9tr}@j_pq{5z;&X+BlzN`n<<-8Ds!@c_6%xw5x`%0==C2R(`EbYwNqx?0 zsPyS9e_LkZaEpkO1G(^#^0i75-yO!rcDOamKe&IJRs@7SX%ZgK%9P?Cd34Q>!0yewg%X z$I6yIa&b%bIcghJW`_@i05K=4%x`f%O7p^w>b3!8QC7LUUs*b!1aR_-GUbY_vIe`Q z;gG|-p{-0=i{-1ZpkiTJ8{?~fZ&qpgoKSz8T;ArW0@&td1Ijj`v2na}>)E`DVVg3g zMcU?fS!G9=vQrqjq(I}#0(oT(qxtkhWy&r)E0!sHMqq~lN+tl~Koeay?`0~*_Yn0BbHF#LoPzcxq!99-q`yqlS?HoTjO6kaN@&iPq)LA$4U0Pt zPJ&27ZWIR>08w6Nb(*VD()_33`&M!YJxQdwHf269zs0}YM!9V!xuNp&D!<@V`NjNh zJvwCp%P)xkJrBQ9N`}Z?fb*h_^L!phBbP)Gv~mcJ{OS2+8g<5=5ifmNI4*SBMoNBn zrsQBWnoY6{W*J!@7N-ifQc8bDHiY#`Y53o;*XZMyNKn4^0(m4cak5}yq0NNcj3`k& zYiOICBGzGl2SnRPPBI~L6ng0e#v8%$dtmZ=aR?e$`V=VM57Rz~czl|s&@(iZb(+Rr z@+zO9GUXAPuAHTEc!?G|9kj@)(qiWny4>ldCC*B!bXL<+=PFv}TtijPI;wVFO9AIWs&PiB z)_H=KJ3mG%oPD&?`5;~4{1L5kzC>3#|3#}^Olw?=Xss(i>s-qz=xV0*uI+S{D^43+ zM`@$0m#%i*Mc23l72{kx3QHGU@$rc)ly*HC}D$om)y2@B)KKI z*@h2P#Ni9&;cJKw@G(?Wz%H#+hKSn)6+}S=QSpHsXpc=2b_fEIc_SPbmKOE z*VA^wwlX$1`>jkk)^Eoy&t#LC`be*p$k z1Q#;>R(J(bJJsi;Y&-3w`nbBoPG=~K>uZ`%YF-nL+dJytWBV?4?>-1&Q+M^0fJ0>xtI}h7RNqN41!s~Z3 zicNH>hvdorx3-gGQqw~k9M3SthbD^ZTxAOfh8uX#ZP^IxGL zW?-g#9Ua6h%$BcX6#NZxt_H^jV4zN+jIO8uj%rxiF)@a;E?8=WfyD|l`fTq4O9GjX z*6iZJqNPEcfD;2)f(C_oV=TLWJjuDUvQ8pyrwud)uuQ}oWY=jW?TH%X$;m8?W?|Ms zPm2#yafNWhk%UK{Er=qE6<8_KPNMP6?&T&{E0~^}rwZa^5wHwv6po)Xg5#uU*F{7j z$xA20jHIL7^p)DNmjrP-*2?Y~RM*J}mmt>Vm(Eg{MPt`(%eaZGXJ24{dHq4G&s%r4 z!h)$&!oWGakX9^aXPA-8nUj4D(`L|XSuxGw#Rb?Vg@(Rs#~T7T7jINJ@pT?Da2~bI z6Q1iP>45VkAv&zs&(~SD_6I6Ws^Z%E*5P^ zqIew(Rm4DQyhpYA1_tQg_Gqnty^A_zg4mI_b|m^YZ{S8|6q|FWy~_*Y!&qB|oA41<)|6iO z7><{PkJGscx3ABppra?dfE{|1(r(5lDjAJiX!Ux@JqEQdUaT{9CO#!Ks7GqnXB0wH zax!omJwuT}d``$ei_bF*`E1sWbk2ml5MS-Z?UD&!WU7^aCSwp^mR7PIcd!9??z*nF z_V!}^{Hl~N7hj|QI8HddSFU$=rV_3dZ!63y3acl%Wv{2y-i5nGo3AsWv#B>b106Ca zOqI}w&EUa($jQMWmesLIn6@4s9{2ln;50v;&%c3 z2G2~GC5lC3+F9Zca`XPEpqfqmneL#IGHxnDCI2FQ&-M!KDTu#{dwz+(Q8hQyoZ^&Y z;_n=P8zkk@F7@|VLr-{J!we<=11|>H2me{D`S~&?H-hf_w}NkT*Wr#>vd5GE!ON9+ z3IC;N&+Tw`viI;sF($f{dQ#Ea*Yfl(T=(@DkMof%W{jbL)T_ADpGl74il6>a@i zy34*IYo}tmswlrI<9St1|7>$og&>;BP?$e|c8V^M0jD@2s!GYKe!gN%RmDPf^6J&5 znnB~G`C2JAp zJWq^2KA;xs>3m6MNy=0wuzB?AU4_#oNti8DCh>U2l-!_}lDBH)Eg3u0p5kUYJK)*z zvCFEON=B&m^Gi0GMY}cQh7Vq4mIXttV1p<;^zus+2mAag6*)<*3aFKe!+51r6dzP4 zvw(1w%p1qbLB{s#>|J&&>q)VwZyo`C1cO-w0G*UTb-sS7+9kG}5m0AJBR!^AOYC@EY3r-&B{xdo_&&GJ$xxpgaW&1F{X&)AZ_hDhEd>%kD-unQY0y$|2s}7>#ZvH7VwI4q{=X zjK?D7gIE-eR5az#-#v(A#PGM86|I$F&E2du_aM*|4wdDQ4VCAx>t<99Q^y{ujFuNIAjcCP!t=c8GG^D?%K+VTk%N9IE06qG*vWWXm*A;IEQ=1yZ042J`gcS zwA7Fp3WN)x2vGJ2|?rbWZ}eGY%Be)h0g#eK7<`Z;a!^M|)o#3*YuYb$+kindmM zN}XD3-u!BJF$MTrsF~eak_f6wwxf|U32^lb!}!;P5uM_O zh!Nsaef7gV^x2~!gN_(ci%B=6me8F)CBZ>7geq#(i4n8xUKr6xr9WhJ(cP6fwT!`h zs&g-9^S3}4E$7F7-0-k!%_$oHJTWsYFnkclh02Orp9GCwYFPdpg6&W zo#8u2)R|Ga4MS?(ee#`;ZH;QvXa7{A&MpL(`&fw^_+Gde_u!M9yanFDaa!OYM^u5| z#vu(K!owOq$$?0qj4%TK$RR`E%WTVpY`6gpXRwb6lujdmuwI>_;pu9lhDkM`p2kz^ z3iTch->0tA@Ot$L4R2Ay8h%qfs^O#RG4%|fexjbx_%rHRfxhc}AMwvrEgA+?*msNX zGa45t_^rOrYh0kKT%h2?z7dTJ6nww$evJzh`~lxVjSCd~LEkSlE>Q5NeSgrn zK*68$y`XV_fr7v2dr9L01^=(VLgNC7`>Xx)1lN!_eCiyQ-D^?zKU`#BiGj|SF>{o2 zU%)`QUN~3(clH1628SC3jIxSPNx&M83d0y>jh~Xnz%`_L6|)WOR%+oWdqvgM{757+ z{nPO?v|8qLBsXc2Q>NGa5(D>);@T;RToO^Cr$$kKHZ_fb1DfiWV%RiPPic+Lm|mk% zHqF(PbzWd7!9`yRFJ@y zZnTVTl$CCX%kvvA;kZ$D=rZ={0wG6A`R>f8(%}t7z4`WDAU?($ISzD_ZVUG>qaUy4 zFtD3WbT?A5FR;bGf`D3wDzzR#)rT1>iJ88&nC07q*}h9L#}`AjuMai8t8kRR3$^~s zFxMZ)Jimka{scn)0WHU`#}5Dh0Z>Z^2viNf;I(rwi8)* zwnz0VB6B$;+Eo2#Y9HMA*)?7md|3nvAMn3 z@S4vEapw`FQ{U&Sgr z5LjCMYw#alyAmj@u3b5BFjYbkWd~yzAIAtP4oaBFt672JLw+SxxGD0_3~|L2SCyRM zEI1rY@;cAmA_^QpdHwqO1=AaS%vAfBdj;c<4TDCUn3XG1K zt*mP{kV8`lY#mTG+I8=4jBcadqor%d)@`tX_W#bkvSr7HZp$w}o%@~ho$q|-`~KhK z_|^Bn_&gC^F76U^`ks3Rx82!1tfi0X`Al=7IX%+c(VRRsa|I)-*@l^q=gf?b`J$fH zHA~0hm}bS(V|x0SRmxe-i4iSp=^f35(RfZP#0@Fq^2;}G-h2gki`%M`?TsB4ZJn2O zZi{F1W8C2`gY_c)L^@ltjN?+To^)Ebtle5(lc!u&yV=OwdNHqM zyGFp+l{M4HaN(|<3vP#S|CL7Gu&);Mk+u)e_X9PYZ*iYykM&rVo*T|$d;5PuL7uku zgJD`i%R;13y`b&?54{y?4AF9`4^x;H2gye(!W5t&f2|5ri0b(3BDhnNyVh^qxKYsP zyccvGx;-hKX_#Gnm`h354%v*F?d>11dA&RKF-+OFqq^Of)htU;V_SQTEIGM7OqbAF zwt^}sTzjlS&2Wf*!mw;h8ti}OFs-N75Vg>yv*70Fq)?lnCOKQOjciw+nau))K(?h& zR8UaQ73_&5qzP)M>LEFK4r+8zJVY_-1Zx&EtOCxhZ)-n1+ZtioNSj!T&4QNBSyK?$ z)Hox$r&!eFnF?(UQ8#C7r&CO;{8D8 zlG%zYbgdx8uy*q8!qiKxb<{(Bf^NNDdPmKGsb~zB*b?f7R%?TrF?CDLo3@%Z^R{N> zRV_aOHb*Bzw>s6GCki0+jB1_2z`Ux#KA{s;YWm(LIZ+Y+CCJfGRAg?C`o$+c`f4(T_UMJO#A3YHq;Strd|f)^AeiBO$tl(bYcNCV4H#`NHO`GY^b!<&!i)yFPy$D}20GPjmiLTwqX-I=R zj8UD#!9a+?+!8JMH2l43o-8>&(xs;5v^s6kPg(k%! z|3SvRk(PhWn`(~C7a{712B>7#wdPy%DfCzK^5nD$bxb?1tHZjUS8Xka*hiunH|(*_ z)_k9tA2EtK)gIGq{OIb2+RZ~_8X{$=l-r;diY7MN6Dq=Wg3ofYN!-mQo$flanaaI} zYFLQwBBw6YgbZ&{wIWn=;}`~$$GO|pk)oMH8nAzhC5zLbCA-B=zSxf1%N!_X6Kbo4 zSyzslG#wK;)6;ph+Sn#!?rF{Uq-{8)W?FR@4jPtWt7EoZuo7KvitOZU={CwUEpiuU zEGHXD)u$KOJLU*{W#EKb^C7YKk2uyEWusD^E^wT~MB zAaZ};uc1$!!P;OcZyPxs9h_d^eF}YUPNkn!uYMy$PtoVmhB)9uw=hqpxfwy7mCa1k zbcZq<*uO=;&9HnL8DpMxh00<20-Xt=H$02nQOe(86a=lEx2DeIw^=O~c68lr6r5)5 zOCfrWv!0^oZLW`kBD1=zo%vEuFG{yVx$}SY0`tE(OI{6&Lcfbp!)s@^S=4uC^&F%k zGJlWTn=jK#$U}MkgzYZOjqT~m`U-u8*P--cJ_J5Zs20Nln=c46>;;;QzK^d0{BDDOhi z3P~t(ipYlPi*$|=`u*A}y0<2f{sn(8fj+Z@Fy$si?oAyJw|BK#3^%z7p;WQPX3KWBF+(sdc*D;`SpIC%xw7_^I>vno< zq4>$`cGrQyei=WDA!Q%3YTkC<)yvx2=QL)*FBEuQ1law+qOY@nJ})5ZfU$oaHK{lt z7NZ&ZfVZe3mIB=j%L7HUMVGYA(PlOo7WJYbB$kQBIR$sY*1e|SiYAy`tPr$*NG~Eb z)S_;eig_gU8}{$t2g)iSwIctT86D;ntE!JZ_jEsJ2F291^R= zC9}6B6@gdd5)?76iFxO_htz*NXaCF^BsGhckXR?yBPZa+)vH-Xx~GKFfE4W%rI{wW zYMF(EA#}v0VguU@Z_fq*HeJf1Z#!V=#hy_}42vjWg5?-s!n1KX9T4$qM!G<#BDx^T z((OTXBk0}sxg{KLqXm2CIVD7F5}QL}qqq#Ff&6i^cx*q)k6A*Z6#ai;u|;eRLZ@z2 z6`bQ9J-gvC|P($&=($9K2^wRp}wu625)LD%(t@O)VG zq6-u~qK})ud0NL>MD1imT?fOd2rw1G88>(+zRi)ncKYNY6B)Rw{!C^Ncp$E9TQEn7 z-FyW+vX+fX6WDM|(&>Lx#Xil{%-h+sS#IDVa}xy8qs1<($NgCVhB z9Kr^};ugACEEUk^ghdLO9V<8ci2p4k!bxZzMiC_zzv=b-1%Jz$8`|r4=p$MwYgg%g zbGGCBTf|Xz^R2W0xb(jjq=;eE=xPUu7pGma`o?fkUA|m)?P7nhWP~0PX)%HXJKf`r zYnE!v+`2O$#-I)%@F^gUA-5Lg>vX>v7CCN1S_C4mzBa$f_A(&Ql{C0bb3(NpKdWs4 z0TX$0R(n7Iw9yZajp=uiQ|-iYph%1Z>kLZx2iHm;+pQJ$GY?>!H1hhMQf^o;${DIh z2~yxH5558v#8-bk|6NUvVOoq)fe)9^QW9bU)CTZ-F|LlLj!aR*Ia;0?n4+fWGqf`H z3`IJgq19)k?}N04E_ODFSFpv8u`U)Z)4D@t+HjgeXQ^volCFuB>9W+o%jBP|{2+Rc zx>Lz1+V=d_o~_;{@5PVP#nC43=2XI0rtPOF6pP^FnnQmly<)QRW^5q(EbS0Uow@i|7Sv!F)?9m5eqV zo}wdA_7t_nEKq=G>8ikr775IbMyIlss?25zQ zdTE7vm~L_CYw`6Ct*yW}i!hUfNA83IQ8?U>jr%Y=24TnHt&c(MBbc28-&UlmWvU;lAbCw=T zC9wHn7`!gxUAD1IpE?BbnELdglRhBg>m4lT(bS$YJ$?!*#ZqN@0%&_Osjyd4M-pC7 zbjW`j8}fAw`Qt+kzaH^AE_x~j2mR)Gsl|C%pouPm$q5K;$oH)$~cfCV_3Z(mM7E20h0iiQv(si)A2!Ri329rU*;G+iI3kG2(Q;td-yP*BwnUJJWGEjgY3^w(NebmUmlvQd~K2rcf^0s z(d*3lMv6f+Mc<70rs(g=^!EvGy>||@K21xj(E9FVJ5nf3kA#Kolpvb-tra z-#f!U=aJ1qxJs`y+HyIrBvp>h)GEg|+A7B@=xRCcq+N1M(q1_Z(h)fxp`$Q3k%q9~ zag0nkmgqq_@^7yM&8Ot(Kq$*NSi*my`DN+W=h&y0IXU3DX$<+Mmlb-AqZmxh44&!P z*A*HEgoxgyRTbRID+OR)%6OOjJF4IaL0$&nco1Vf{d3i8bUQY1KEE;6ah85?CbcJ; zdYU2}hOwg!|29QGMED@U8vX-69q#u#_(7bN>3x?qeiV&0^9s-O(s>+4fP{Y^xx>K@ za?EuKsCwZQKIeGv!_pBX-sy;@WY!&sl||4w9$BC)LJ-&}!j4#plqU|kr*`1fB{=o0 zSY8$@s|u~&!`?=b5kW>%qlhHDBH^eUX0c@}koUfJq5(PM2pN#nU3ktmzJx}Wp z4W^hBNjZKNKq=DQlIDMr>AUG(`W|Q=zYY2%eNNImGW~ffOPWWfU!+$g%_Gxa!7tN1 zGW|n5ftlu!>G#AUN%II=c!Zy6IWoOOESEHoOs^K}B+Vn!-D10>d1QJ}9FR1ROy49% zB+Vn!w~MXT+ zU$qPF28c+?C7Cf=YP zyAiqSCYb*r@}L-udAW&VcaZ0Q08mQ@2>VvU$r2F&0Mj6o0Yw~>Po6G+?M@Rx6o%h{ z!a^yOLO~EvTov2GvQQgSsWCAmCM5ME)?nn{bUSPp_KW?%7$X}$Ko-;W!-+q1h3ZR5FhU257XXQ6)og4eYZKxZnv8%4AhUfT}%_GZm zHOFfR(gR@&9tv7)@=!B>n!?x*V<%KMcDWsj71cL2hx?k<@+g&x#o}Fx4a%qdZfx5m zgiWrk)30z%%M~K9T$9v85rmYB^z!QM)w0$Qhw9rQFotB!ivvSEv~0mJ>jkE62E1Vl z{Z+tyUj%y9GffdFNHC1=@k6fL+%@$l^*v!k3I-XnXX*nY+y<|I+d{z*!@xmoiHL#i zFbv+aTr0ZIkjU-iw;B3#`Rx=^7)wGyI)x-ghB1H)t=OK)FqNyG`PL%2kBa2Z)lhpK zM#51rMT{3yo~brsdHPd|kBAc7sibfTGsBq1EW>1%00naliZ2D*O<@7qB<692O6INY zFsz-gWwXhHnmCAmg=>gPzS?c`6$bqx;q+F6IZ&BlO zn?0Rp{;YK|C`f~4>gpz)LWa>=L&Tb4AYyDO{aS@ zK=Twv>8sJ-H2P=&$->Le7@zxuiT99C29wBkVwO5F>B2{4OdKQm0hgCga8(8}thOzG zV2qeWTo!i^4k+`%bB!NJFRTAW>454mUdvcaWd~Otu|HrNjKf337jV zd?)J6qrc^m?_I^*30D4F1zjL=k<0zR0Z>Z^2n8NkS(DzNSAWk+12GWBC-$$kihTkl zr&hXMtUat%1Q9$5ibC(x>~uG6HoGL-dJy{{zJ({jgAd?CiBr*o6PS zx`6t*wz|9!aL~Q^3FtiBY(4w$dJ_SaZg0|tCbU}6fGZsV)hqr2bfCs|Q-V(uwz==J z>#$Z>Ye#R;e*Fz>z!p@#0Z>Z^2+FyCTa#X*Z-1siF@%Izikd<%wnzmVpb{*mUhrgc zk_=2{#<@UQYFB;mN3;+6*w;RVwyb3zeDmGk;BWB7xX*A&fVebkO=ix%eEV{~y?_7v z<*xuHu)*-;;lriOcd-K3)`eM&O~$lREE&_Rs;wK`(=9VqwTgn|jxYpw1t}}sO=%UO zt$(|I)s0P-xZ#Rq%r2*@+)n8M#>B+<`1lpFbu#<@CEqYe;8u9*5*>wE)=eQC-7J%I zLpUzQB6())@>nKS6dSQ0LSPJP&hi~i+|~`j5VxFiy6o_xA<~-;w{791?>ZK}JYBfb zW|o_zbQE+jbg%IZo;J8yPA?YLgyt#eWPdnQ7G7@4^+dJd$#5Z_4Xkx5En%icc8|WN z8|is&PccNA^$JvmPTk#2t35t)KY|FlRD^Mop|9aPZ5akdrrKNu-3%d7wY@DuWH=o^ z8YF@qoKbNay$rn#RU=OYXDRGe-PFD7LD+i{oWp>Mew=6MZ_aSew0$qg#a2#uN6RG01Whq?9a1SsQ>%1OINY-whO>u!=l0|Ta0%mKyo<{WJ;(J5 z-eXXRtqbCT7r_VU3gdlbs9KW*)PLfA)Fz4$<|L-1-BrrKv#0~a(4)4yQnI~{8!8lh z$Pji9I5if+twZeFHCONv(b@I5*w=w`B*GkdxQ4OpZhXhD-~`|9=T}4=a)g zpEI2DP1*!{N#_Ma1OpI_AL0M;dAN@+ZpA%htU#^(6tas z|8j@HY*kbU=yWS`Pnm?7`hSo9AIgG?Uxy(fs`8H*mS_6&mMuesvAcw_MV8W7W3oi9 ziENpWj%!z$%099iyBb-`Si&uF?J0YW51Pt*-f z?t_9)#D3i4QJS`XID|J=Z?~qFn{gR&Zx;z-zX`^Mx>V&g#8(Nt7AWrXR(&qn=_tCm zW%CL`e1VP=Q768Qkwat&P2`P_9!h+w(g!OUIO1U~M|^xaC%yeL`Mmz&G;M-X*6zi5 zZ0fdLfSdUd^4sd9+y2mrfg2A@I?}YkUES^691(Z;`+uJ)T`7NGA`d!1yMfWfgwudb zo*LfbND6`92gMxc&UjEnLTRg_MfmI;A;mKJ)x8lGM)eP>N`9sM?uJ{> z&mgzitn|yx`0vo$(q5q5s$UZI&-;I1SMRxtyW65tp1}(8tv%z6PGN>EE;P3Kjya*8 zASq5!83is;ywukrgUKn~R!Z;gSpk+8?C{1XNr-n|NWfN`lyu`8&f$XJ%i`X*2=;WO zlz?kAu~T)#Df+JGM5s?-m~twrEP7oY5~)@CcsO44R!ROnEfbaLO0V7rUHu;qkp|O} z!mf?5IY>$2MzM?UILXjYJFLqvd!8vW&<+)E`w8Fp zee;OL;%b1pTzE%Mvk4<%nQXZgZO6+%S+tBg@O&Fl8ixf&`u zQFKj!%TaThV-zqd5a7SQrV}qxiFepZYGaXe+tr^W2z^m(Vgqg!NU+VTX0#VWy`_VF zef`&g=LN==>Qi^GIfTA|Q|rDGCC*MvCN``x^HYN-0hy-hc(b~%3dJ|aEgxmCpwycp z^vlpPyU>RrQK*G?VKUb4MhQ%5 zXCm3GTFS{<7*gdkZY@h_7E<<8Z>LFCdZjc2N+zGYoKI$vMCF?l#okQ#xN_$wS99#v z8!^-V+~d^F&di;$A4^|Gx0Y_#?@4Gm`>rZIyzhEjnJU;Y3PQl`oP$FDzU# zuG6!IJvvp0GEJl4LdEZbrKbWPqlq)vz+^b`8}VC70vcU62|FurX5pagio^ynX_iA0 zbuD&IPbTT~^u4a5uF;nyeNU|BqkYDx0~li!v74~jML>Th5|8q%Z5_(_Q{CGTD{9H8 zBVlShfuuw@>gQokdbl{@!ZavZaVhiu2}K2S%p!oErQLA3Q9=$WX!d5EAozgZS5gbk zV_LT4Y%^x(`8*8ajfSa{ywL~K?gWP!FmZpuhX8W_B)UNlGC6IsVOt|0q2zO+r;fBF z+D>{h>pWJ&voot$+z)MbvCEwbk-MGgTOriViDb8O=&^dqA{K%6clmgaBQl=y7%Bo@8e27%Ju1GBeYXhOXSsY`HVgSUay# zG8lvJyk0dpUHYLm#I!tZD<{>tk7ocVIC2*7)~E30oXQ01+l zzXdxgN=%7=>EiPF&*D52k1c!&DL7Ywr|uOV+kX7b^+%Q;)C6%a<3#Jf<`_1hv;9`B zh{En$H#|*L^s1$TOZZQHjNOFZrf8U(g@6pRx*isrP zy_|eO{DggI*Gc9U&X3Ko+!nUD=+Xli=g?%|*?X$inGFl=2M%Z&fRliTH#-9jkY7wunG zyv6@rUYC?g+Rk*dUVb}I+&ve+YyCqtd^o>os9s#G;oKD#7p#!=_=OZfsp}Konq#f#8MU{C z1~(IP*bh9JiA9;=5_riBdm$v9fLhiR;?f)i$p@U%JCPdfx7h+tvj9Q0Ho?l2qL# zv(ei<+-qPv%Y#E=w8Y2*jJafn^{YlQd*2F@KyRF zPs*?!h#X_=AJ4Yi`*2(=vM#F_=_Z>@@$a->c+1)Jq;a#)wSAVNIHsQi82u??PCgtkN24ROwM_^k{t*{FSynmaH z>e4;gzUE`F*0owjwqZlB`@NEVu2F`np=^ZMR|e^_3Jc;s;h0ok(ZS*4goLS$wD=(J ztOl*APN}CVgvyUVf~O)=V76|e({5zxH+j>(k%B9}{29GkQyFuzHVCz=Q)@*`x;lAj zsb9~?;+{o4vlqa;EO0cNv+9SN;-j0q@`~G6H+Z#`RejW*PH_?+Av^L6qV+;h$%rW9 zq@8@H1aArLa4fNJRNj9uxe{$)AITdh!%(LzB!D;Z$JK>SV z4sE+oO=_!W6kKf8^T^&pW$@jiwwDm)1H;}KDwY?3xg33ZzBYGF zuRddZI3A!d7hn`(A{G+giW};dw3sdJhftgMiaFLU8`J{^Wrffka|w4~v+N4v%`O9M zJaD<(27%GMp=k&Hs#Sv%qSFx2@#xnp@+eSRaRS&ZmqJi3uPRx9c9;MdC9O^e8Sv2{ zrwT>*|7T5W&_Qg#^9ozUeo*l5BI6=75&cR<=w8SwfUo3ZcqB%9Z(Iya?X2fS{EG4f zo2p7D{z>9L@DLy;DL{kwLK{Uv&<$)d{W)!)`~^R$5=Z=s2?SvUI@M@t8hE%Gh1g4V zy8#02U=L~1L1{8H$hTSru^)Z}fgtIiaCs0C1!k&+;QP@dze62>P>nWXKRN>fk){*L zM+3q&qQIjXark~%!0#t#5ByVOhM>9BgH=07u*v7>M25A1@ftXAm3&Tc&+Gg>2(^RI zSvqK58v+PpL;#ao6~r&sZIF_sqtq}!cq1>+X7caV*>@5C{X1p!Y2d$B-LkZ+v+u16 zfhf|ct{VMs9@bQ-=lMC2TTKy=w45J@^EIB>g>4_qW224KxX>>>~m N2q(zEpY4qk{{xkq;s5{u diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 23449a2b..c61a118f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index adff685a..739907df 100644 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/neoforge/build.gradle b/neoforge/build.gradle deleted file mode 100644 index 1a5e1213..00000000 --- a/neoforge/build.gradle +++ /dev/null @@ -1,69 +0,0 @@ -plugins { - id "com.gradleup.shadow" version "9.3.0" -} - -base { - archivesName = rootProject.mod_id + "-" + rootProject.minecraft_version + "-neoforge" -} - -architectury { - platformSetupLoomIde() - neoForge() -} - -repositories { - maven { url "https://maven.neoforged.net/releases" } -} - -loom { - neoForge {} -} - -configurations { - common - shadowCommon - compileClasspath.extendsFrom common - runtimeClasspath.extendsFrom common - developmentNeoForge.extendsFrom common -} - -dependencies { - neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}" - - // Cloth Config - modRuntimeOnly "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_config_version}" - - common(project(path: ":common", configuration: "namedElements")) { transitive false } - shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive false } -} - -processResources { - inputs.property "version", project.version - filesMatching("META-INF/neoforge.mods.toml") { - expand "version": project.version - } -} - -shadowJar { - exclude "fabric.mod.json" - exclude "architectury.common.json" - configurations = [project.configurations.shadowCommon] - setArchiveClassifier "dev-shadow" -} - -remapJar { - inputFile.set shadowJar.archiveFile - dependsOn shadowJar -} - -sourcesJar { - def commonSources = project(":common").sourcesJar - dependsOn commonSources - from commonSources.archiveFile.map { zipTree(it) } -} - -components.java { - withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { - skip() - } -} diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts new file mode 100644 index 00000000..e550da50 --- /dev/null +++ b/neoforge/build.gradle.kts @@ -0,0 +1,99 @@ +plugins { + id("java-library") + id("net.neoforged.moddev") + id("maven-publish") +} + +val modId = project.property("mod_id") as String +val javaVersion = project.property("java_version") as String +val minecraftVersion = project.property("minecraft_version") as String +val neoforgeVersion = project.property("neoforge_version") as String + +val clothConfigVersion = project.property("cloth_config_version") as String + +base { + archivesName = "$modId-$minecraftVersion-neoforge" +} + +val commonProject = project(":common") + +project.evaluationDependsOn(commonProject.path) + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(javaVersion)) + } + withSourcesJar() +} + +tasks.withType { + options.encoding = "UTF-8" + options.release.set(javaVersion.toInt()) +} + +dependencies { + // Cloth Config + runtimeOnly("me.shedaniel.cloth:cloth-config-neoforge:$clothConfigVersion") + + implementation(commonProject) +} + +neoForge { + version = neoforgeVersion + + runs { + register("neoforgeClient") { + client() + systemProperty("forge.logging.console.level", "debug") + gameDirectory.set(file("run/client")) + } + register("neoforgeServer") { + server() + systemProperty("forge.logging.console.level", "debug") + gameDirectory.set(file("run/server")) + programArguments.addAll("nogui") + } + } + + mods { + create(modId) { + sourceSet(sourceSets.main.get()) + sourceSet(commonProject.sourceSets.main.get()) + } + } +} + +tasks.processResources { + inputs.property("version", project.version) + filesMatching("META-INF/neoforge.mods.toml") { + expand("version" to project.version) + } +} + +tasks.jar { + from(sourceSets.main.get().output) + from(commonProject.sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +val sourcesJarTask = tasks.named("sourcesJar") { + from(sourceSets.main.get().allSource) + from(commonProject.sourceSets.main.get().allSource) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + archiveClassifier.set("sources") +} + +artifacts { + archives(tasks.jar) + archives(sourcesJarTask) +} + +publishing { + publications { + register("neoforgeJar") { + artifactId = base.archivesName.get() + artifact(tasks.jar) + artifact(sourcesJarTask) + } + } +} diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties index 7da18ea6..e69de29b 100644 --- a/neoforge/gradle.properties +++ b/neoforge/gradle.properties @@ -1 +0,0 @@ -loom.platform=neoforge diff --git a/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java b/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java index eea429fe..c6aecff5 100644 --- a/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java +++ b/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java @@ -1,21 +1,15 @@ package com.xtracr.realcamera; -import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.util.CrosshairUtil; import net.minecraft.client.Minecraft; import net.neoforged.neoforge.client.event.ClientTickEvent; -import net.neoforged.neoforge.client.event.RenderLevelStageEvent; +import net.neoforged.neoforge.common.NeoForge; public class EventHandler { - public static void onClientTick(ClientTickEvent.Post event) { - KeyMappings.handle(Minecraft.getInstance()); + public static void addListeners() { + NeoForge.EVENT_BUS.addListener(EventHandler::onClientTick); } - public static void onRenderLevelStage(RenderLevelStageEvent event) { - if (RenderLevelStageEvent.Stage.AFTER_SKY.equals(event.getStage())) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - CrosshairUtil.update(Minecraft.getInstance(), event.getCamera(), event.getModelViewMatrix(), event.getProjectionMatrix()); - } - } + public static void onClientTick(ClientTickEvent.Post event) { + KeyMappings.handle(Minecraft.getInstance()); } } diff --git a/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java b/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java index be986d01..4348ff19 100644 --- a/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java +++ b/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java @@ -1,18 +1,23 @@ package com.xtracr.realcamera; import com.xtracr.realcamera.config.ConfigScreen; +import com.xtracr.realcamera.renderer.gui.GuiCulledModelsRenderer; +import com.xtracr.realcamera.renderer.gui.GuiFlattenedModelsRenderer; +import com.xtracr.realcamera.renderer.state.gui.GuiCulledModelsRenderState; +import com.xtracr.realcamera.renderer.state.gui.GuiFlattenedModelsRenderState; +import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.ModContainer; import net.neoforged.fml.ModList; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; +import net.neoforged.neoforge.client.event.RegisterPictureInPictureRenderersEvent; import net.neoforged.neoforge.client.gui.IConfigScreenFactory; -import net.neoforged.neoforge.common.NeoForge; import java.util.Map; -@Mod(RealCamera.MODID) +@Mod(value = RealCamera.MODID, dist = Dist.CLIENT) public class RealCameraNeoForge implements RealCamera { private final ModContainer modContainer; private final Map modIdMap = Map.of("cloth-config", "cloth_config"); @@ -21,23 +26,29 @@ public RealCameraNeoForge(IEventBus modEventBus, ModContainer modContainer) { this.modContainer = modContainer; modEventBus.addListener(this::clientSetup); modEventBus.addListener(this::onKeyRegister); + modEventBus.addListener(this::onPictureInPictureRenderersRegister); } - public void clientSetup(FMLClientSetupEvent event) { + private void clientSetup(FMLClientSetupEvent event) { initialize(); - NeoForge.EVENT_BUS.addListener(EventHandler::onClientTick); - NeoForge.EVENT_BUS.addListener(EventHandler::onRenderLevelStage); + EventHandler.addListeners(); if (isModLoaded("cloth-config")) { - modContainer.registerExtensionPoint(IConfigScreenFactory.class, (container, modListScreen) -> ConfigScreen.create(modListScreen)); + modContainer.registerExtensionPoint(IConfigScreenFactory.class, (_, modListScreen) -> ConfigScreen.create(modListScreen)); } } - public void onKeyRegister(RegisterKeyMappingsEvent event) { + private void onKeyRegister(RegisterKeyMappingsEvent event) { + event.registerCategory(KeyMappings.GENERAL); KeyMappings.register(event::register); } + private void onPictureInPictureRenderersRegister(RegisterPictureInPictureRenderersEvent event) { + event.register(GuiCulledModelsRenderState.class, GuiCulledModelsRenderer::new); + event.register(GuiFlattenedModelsRenderState.class, GuiFlattenedModelsRenderer::new); + } + @Override public boolean isModLoaded(String modId) { return ModList.get().isLoaded(modIdMap.getOrDefault(modId, modId)); diff --git a/neoforge/src/main/resources/META-INF/accesstransformer.cfg b/neoforge/src/main/resources/META-INF/accesstransformer.cfg index 3e6e0b95..3e09a5a6 100644 --- a/neoforge/src/main/resources/META-INF/accesstransformer.cfg +++ b/neoforge/src/main/resources/META-INF/accesstransformer.cfg @@ -1 +1,2 @@ +public net.minecraft.client.gui.GuiGraphicsExtractor$ScissorStack protected net.minecraft.client.renderer.MultiBufferSource$BufferSource endBatch(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/BufferBuilder;)V \ No newline at end of file diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index d164d6af..811bf035 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -24,28 +24,28 @@ Make the camera more realistic in the first-person view. [[dependencies.realcamera]] modId = "neoforge" -type= "required" -versionRange = "[21,)" +type = "required" +versionRange = "[26,)" ordering = "NONE" side = "BOTH" [[dependencies.realcamera]] modId = "minecraft" type = "required" -versionRange = "[1.21.1,1.21.2)" +versionRange = "[26,27)" ordering = "NONE" side = "BOTH" [[dependencies.realcamera]] modId = "cloth_config" type = "optional" -versionRange = "[15.0,)" +versionRange = "[21.0,)" ordering = "NONE" side = "CLIENT" [dependencies.realcamera.mc-publish] - ignore = false - modrinth = "cloth-config" - curseforge = "cloth-config" +ignore = false +modrinth = "cloth-config" +curseforge = "cloth-config" [[mixins]] config = "realcamera-common.mixins.json" diff --git a/neoforge/src/main/resources/realcamera.mixins.json b/neoforge/src/main/resources/realcamera.mixins.json index 16ce00cc..6e60890b 100644 --- a/neoforge/src/main/resources/realcamera.mixins.json +++ b/neoforge/src/main/resources/realcamera.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8.5", "package": "com.xtracr.realcamera.mixin", - "compatibilityLevel": "JAVA_21", + "compatibilityLevel": "JAVA_25", "mixins": [ ], "client": [ diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index c460dcc6..00000000 --- a/settings.gradle +++ /dev/null @@ -1,14 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - maven { url "https://maven.fabricmc.net/" } - maven { url "https://maven.architectury.dev/" } - maven { url "https://maven.neoforged.net/releases" } - } -} - -include("common") -include("fabric") -include("neoforge") - -rootProject.name = "RealCamera" diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..6c49b8d6 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + maven { + name = "NeoForge" + url = uri("https://maven.neoforged.net/releases") + } + gradlePluginPortal() + } + + plugins { + id("net.fabricmc.fabric-loom") version providers.gradleProperty("loom_version") + id("net.neoforged.moddev") version providers.gradleProperty("moddev_version") + } +} + +rootProject.name = "RealCamera" + +include("common") +include("fabric") +include("neoforge") From c1021874bebe1fb5302a04ab521c7763f7fafde1 Mon Sep 17 00:00:00 2001 From: xTracr Date: Sun, 19 Apr 2026 14:16:54 +0800 Subject: [PATCH 10/33] Delete `copy`, `paste` button and fix textureId lookup --- .../realcamera/gui/ModelViewScreen.java | 16 +++----- .../mixin/accessor/RenderTypeAccessor.java | 12 ++++++ .../renderer/BuiltIterableBuffer.java | 39 +++++++++++++++---- .../assets/realcamera/lang/be_by.json | 4 -- .../assets/realcamera/lang/en_us.json | 4 -- .../assets/realcamera/lang/es_es.json | 4 -- .../assets/realcamera/lang/fr_fr.json | 4 -- .../assets/realcamera/lang/ja_jp.json | 4 -- .../assets/realcamera/lang/ko_kr.json | 4 -- .../resources/assets/realcamera/lang/lzh.json | 4 -- .../assets/realcamera/lang/pl_pl.json | 4 -- .../assets/realcamera/lang/pt_br.json | 4 -- .../assets/realcamera/lang/pt_pt.json | 4 -- .../assets/realcamera/lang/ru_ru.json | 4 -- .../assets/realcamera/lang/tr_tr.json | 4 -- .../assets/realcamera/lang/uk_ua.json | 4 -- .../assets/realcamera/lang/zh_cn.json | 4 -- .../assets/realcamera/lang/zh_hk.json | 4 -- .../assets/realcamera/lang/zh_tw.json | 4 -- .../resources/realcamera-common.mixins.json | 3 +- .../main/resources/realcamera.accesswidener | 1 + .../resources/META-INF/accesstransformer.cfg | 1 + 22 files changed, 52 insertions(+), 84 deletions(-) create mode 100644 common/src/main/java/com/xtracr/realcamera/mixin/accessor/RenderTypeAccessor.java diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 83ebacfd..bc58e4dd 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -64,7 +64,6 @@ public class ModelViewScreen extends Screen { @Nullable private ScreenRectangle textureViewArea; private VertexData[][] focusedPolyhedron = new VertexData[0][]; - private List configsInClipBoard = new ArrayList<>(); @Nullable private UVRectangleWidget focusedRectWidget; private StringWidget rectWidgetsSizeWidget; @@ -182,7 +181,7 @@ private void initWidgets(int page) { } private void initLeftWidgets() { - rectWidgetsSizeWidget = new StringWidget(x + 4 + widgetWidth + 5, y + 4 + (widgetHeight + 2) * 3, widgetWidth - 22, widgetHeight, LocUtil.literal(String.valueOf(rectWidgets.size())), font); + rectWidgetsSizeWidget = new StringWidget(x + 4 + widgetWidth + 5 + font.width("/"), y + 4 + (widgetHeight + 2) * 3, widgetWidth - 22, widgetHeight, LocUtil.literal(String.valueOf(rectWidgets.size())), font); forwardUField = createFloatField(widgetWidth, 0, forwardUField); forwardVField = createFloatField(widgetWidth, 0, forwardVField); upwardUField = createFloatField(widgetWidth, 0, upwardUField); @@ -330,13 +329,8 @@ private void initRightWidgets() { }), smallSettings).setTooltip(createTooltip("toConfigScreen")); final int widgetsPerPage, size; if (toggleCategoryButton.getValue() == Category.DISABLE) { - widgetsPerPage = 6; + widgetsPerPage = 7; size = disableConfigs.size(); - rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("copy"), widgetWidth, _ -> configsInClipBoard = List.copyOf(disableConfigs)), 2).setTooltip(createTooltip("copy")); - rows.addChild(createButton(LocUtil.MODEL_VIEW_WIDGET("paste"), widgetWidth, _ -> { - configsInClipBoard.stream().filter(config -> disableConfigs.stream().noneMatch(c -> c.name().equals(config.name()))).forEach(disableConfigs::add); - initWidgets(0); - }), 2).setTooltip(createTooltip("paste")); rows.addChild(disabledNameField, 3, smallSettings).setTooltip(createTooltip("disabledName")); rows.addChild(new SimpleIconButton(64, 0, button -> { String name = disabledNameField.getValue(), textureId = disabledIdField.getValue(); @@ -367,7 +361,7 @@ private void initRightWidgets() { if (value == 0) hiddenNames.remove(config.name()); else hiddenNames.add(config.name()); }) - .setPosition(x + (xSize + middleWidth) / 2 - 20, y + 5 + (widgetHeight + 2) * (3 + i % widgetsPerPage)); + .setPosition(x + (xSize + middleWidth) / 2 - 20, y + 5 + (widgetHeight + 2) * (2 + i % widgetsPerPage)); rows.addChild(createButton(LocUtil.literal(config.name()), widgetWidth * 2 - 18, _ -> { disabledNameField.setValue(config.name()); disabledIdField.setValue(config.textureId()); @@ -409,8 +403,8 @@ private void initRightWidgets() { grid.visitWidgets(this::addRenderableWidget); final int pages = (size - 1) / widgetsPerPage + 1; addRenderableWidget(new SimpleIconButton(x + (xSize + middleWidth) / 2 + 8, y + ySize - 20, 16, 16, 16, 0, _ -> initWidgets((page - 1 + pages) % pages))); - Component pageInfo = LocUtil.literal((page + 1) + " / " + pages); - addRenderableWidget(new StringWidget(x + (3 * xSize + middleWidth) / 4 + 2 - font.width(pageInfo) / 2, y + ySize - 20, font.width(pageInfo), widgetHeight, pageInfo, font)); + Component pageInfoText = LocUtil.literal((page + 1) + " / " + pages); + addRenderableWidget(new StringWidget(x + (3 * xSize + middleWidth) / 4 + 2 - font.width(pageInfoText) / 2, y + ySize - 20, font.width(pageInfoText), widgetHeight, pageInfoText, font)); addRenderableWidget(new SimpleIconButton(x + xSize - 21, y + ySize - 20, 16, 16, 32, 0, _ -> initWidgets((page + 1) % pages))); } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/accessor/RenderTypeAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/RenderTypeAccessor.java new file mode 100644 index 00000000..4366b6dd --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/accessor/RenderTypeAccessor.java @@ -0,0 +1,12 @@ +package com.xtracr.realcamera.mixin.accessor; + +import net.minecraft.client.renderer.rendertype.RenderSetup; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(RenderType.class) +public interface RenderTypeAccessor { + @Accessor + RenderSetup getState(); +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index c3f0869b..611914be 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -1,31 +1,54 @@ package com.xtracr.realcamera.renderer; import com.mojang.blaze3d.vertex.MeshData; +import com.xtracr.realcamera.RealCamera; +import com.xtracr.realcamera.mixin.accessor.RenderTypeAccessor; import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.renderer.state.VertexData.UV; +import net.minecraft.client.renderer.rendertype.RenderSetup; import net.minecraft.client.renderer.rendertype.RenderType; import org.jspecify.annotations.Nullable; import java.awt.*; +import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public record BuiltIterableBuffer(RenderType renderType, String textureId, IterableVertexBuffer vertexBuffer) { - private static final Pattern TEXTURE_ID_PATTERN = Pattern.compile("texture\\[Optional\\[(.*?)]"); + @Nullable + private static final Field TEXTURES_FIELD; private static final Map TEXTURE_ID_CACHE = new HashMap<>(); private static final Map> FIND_PRIMITIVE_CACHE = new HashMap<>(); + static { + Field texturesField = null; + try { + texturesField = RenderSetup.class.getDeclaredField("textures"); + texturesField.setAccessible(true); + } catch (NoSuchFieldException e) { + RealCamera.LOGGER.error("Failed to find textures field in RenderSetup", e); + } + TEXTURES_FIELD = texturesField; + } + public static BuiltIterableBuffer buildFrom(RenderType renderType, MeshData meshData) { - String textureId = TEXTURE_ID_CACHE.computeIfAbsent(renderType, rt -> { - String renderTypeName = rt.toString(); - Matcher matcher = TEXTURE_ID_PATTERN.matcher(renderTypeName); - return matcher.find() ? matcher.group(1) : renderTypeName; - }); + String textureId = TEXTURE_ID_CACHE.computeIfAbsent(renderType, BuiltIterableBuffer::getTextureId); return new BuiltIterableBuffer(renderType, textureId, new IterableVertexBuffer(meshData)); } + @SuppressWarnings("unchecked") + private static String getTextureId(RenderType renderType) { + if (TEXTURES_FIELD == null) return renderType.toString(); + RenderSetup renderSetup = ((RenderTypeAccessor) renderType).getState(); + try { + Map textureBindings = (Map) TEXTURES_FIELD.get(renderSetup); + RenderSetup.TextureBinding sampler0 = textureBindings.get("Sampler0"); + if (sampler0 != null) return sampler0.location().toString(); + } catch (IllegalAccessException | IllegalArgumentException | ClassCastException _) { + } + return renderType.toString(); + } + public boolean anyNotCached(UV[] uvs) { Map cache = FIND_PRIMITIVE_CACHE.get(renderType); if (cache == null) return true; diff --git a/common/src/main/resources/assets/realcamera/lang/be_by.json b/common/src/main/resources/assets/realcamera/lang/be_by.json index 8024873c..7c8ee0ce 100644 --- a/common/src/main/resources/assets/realcamera/lang/be_by.json +++ b/common/src/main/resources/assets/realcamera/lang/be_by.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Зрабіць камеру больш рэалістычнай у рэжыме ад першай асобы.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Калі адключана, адноснае становішча камеры да мадэлі не мяняецца, але адпаведныя атрыбуты камеры не будуць зменены гэтым модам", "screen.tooltip.xtracr_realcamera.modelView_configs": "Захаваныя канфігурацыі", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Капіяваць усе налады адключэння", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Выдаліць абраную прастакутную вобласць\n(Ці выкарыстайце клавішу Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскасці, адлеглась ад усіх вяршынь да экрана ў якіх меншая за гэта значэнне, не будуць адлюстроўвацца", "screen.tooltip.xtracr_realcamera.modelView_disable": "Налады адключэння\nГлабальныя налады адключэння знаходзяцца на экране канфігурацыі", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Імпартаваць канфіг з буфера абмену", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Імпарт не ўдаўся: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпарт %s паспяховы!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Уставіць усе налады адключэння з буфера абмену ў бягучы канфіг\n(Не перазапіша існуючыя налады з такой жа назвай)", "screen.tooltip.xtracr_realcamera.modelView_preview": "У рэжыме прадпрагляду вы можаце наладжваць зрух і паварот камеры", "screen.tooltip.xtracr_realcamera.modelView_priority": "Прыярытэт пры прывязцы, чым больш значэнне, тым вышэй прыярытэт і размяшчэнне справей у спісе", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Захаваць як\n(Калі існуе канфігурацыя з такой жа назвай, вы таксама можаце націснуць кнопку захавання злева)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Адкрыць глабальны экран канфігурацыі\n(Патрабуецца Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "Усё", "screen.widget.xtracr_realcamera.modelView_configs": "Канфігурацыі", - "screen.widget.xtracr_realcamera.modelView_copy": "Капіяваць", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Бягучая Канфігурацыя", "screen.widget.xtracr_realcamera.modelView_disable": "Адключыць", "screen.widget.xtracr_realcamera.modelView_disableMode": "Рэжым адключэння", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Зрух Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Зрух Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Частка", - "screen.widget.xtracr_realcamera.modelView_paste": "Уставіць", "screen.widget.xtracr_realcamera.modelView_pitch": "Тангаж = %s", "screen.widget.xtracr_realcamera.modelView_position": "Мэтавая плоскасць", "screen.widget.xtracr_realcamera.modelView_preview": "Прадпрагляд", diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 0e7afd4e..73f7e51a 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Make the camera more realistic in the first-person view.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "When disabled, the camera's relative relationship to the model will not change, but the camera's corresponding attributes will not be modified by this mod", "screen.tooltip.xtracr_realcamera.modelView_configs": "Saved Configs", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copy all disabling settings", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Delete the selected rectangle\n(Or use the Delete key)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Planes where all vertex-to-screen distances are less than this value will not be rendered", "screen.tooltip.xtracr_realcamera.modelView_disable": "Disabling Settings\nGlobal disabling settings are in the config screen", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Import the config from the clipboard", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import failed: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s succeeded!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Paste all disabling settings in the clipboard to current config\n(Will not override existing setting with the same name)", "screen.tooltip.xtracr_realcamera.modelView_preview": "In the preview mode, you can adjust the camera's offset and rotation", "screen.tooltip.xtracr_realcamera.modelView_priority": "Priority when binding, the larger the value the higher the priority, and the higher the sorting on the right side", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Save as\n(When there is a setting with the same name, you can also press the save button on the left)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Open Global Config Screen\n(Cloth Config API required)", "screen.widget.xtracr_realcamera.modelView_all": "All", "screen.widget.xtracr_realcamera.modelView_configs": "Configs", - "screen.widget.xtracr_realcamera.modelView_copy": "Copy", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Current Config", "screen.widget.xtracr_realcamera.modelView_disable": "Disable", "screen.widget.xtracr_realcamera.modelView_disableMode": "Disable Mode", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y Offset = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z Offset = %s", "screen.widget.xtracr_realcamera.modelView_part": "Part", - "screen.widget.xtracr_realcamera.modelView_paste": "Paste", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", "screen.widget.xtracr_realcamera.modelView_position": "Target Plane", "screen.widget.xtracr_realcamera.modelView_preview": "Preview", diff --git a/common/src/main/resources/assets/realcamera/lang/es_es.json b/common/src/main/resources/assets/realcamera/lang/es_es.json index 921cd865..5139d5df 100644 --- a/common/src/main/resources/assets/realcamera/lang/es_es.json +++ b/common/src/main/resources/assets/realcamera/lang/es_es.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Hace que la cámara sea más realista en la vista en primera persona.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Cuando está desactivado, la relación relativa de la cámara con el modelo no cambiará, pero los atributos correspondientes de la cámara no serán modificados por este mod", "screen.tooltip.xtracr_realcamera.modelView_configs": "Configuraciones Guardadas", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas las configuraciones de desactivación", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Eliminar el rectángulo seleccionado\n(O usar la tecla Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Los planos donde todas las distancias de vértice a pantalla son menores que este valor no se renderizarán", "screen.tooltip.xtracr_realcamera.modelView_disable": "Configuraciones de Desactivación\nLas configuraciones globales de desactivación están en la pantalla de configuración", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Importar la configuración desde el portapapeles", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Importación fallida: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "¡Importación %s exitosa!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Pegar todas las configuraciones de desactivación del portapapeles a la configuración actual\n(No sobrescribirá la configuración existente con el mismo nombre)", "screen.tooltip.xtracr_realcamera.modelView_preview": "En el modo de vista previa, puedes ajustar el desplazamiento y rotación de la cámara", "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridad al vincular, cuanto mayor sea el valor, mayor será la prioridad y más alto será el orden en el lado derecho", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Guardar como\n(Cuando existe una configuración con el mismo nombre, también puede usar el botón guardar a la izquierda)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir la Pantalla de Configuración Global\n(Requiere Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "Todo", "screen.widget.xtracr_realcamera.modelView_configs": "Configuraciones", - "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuración Actual", "screen.widget.xtracr_realcamera.modelView_disable": "Desactivar", "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo Desactivado", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Desplazamiento Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Desplazamiento Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Parte", - "screen.widget.xtracr_realcamera.modelView_paste": "Pegar", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", "screen.widget.xtracr_realcamera.modelView_position": "Plano Objetivo", "screen.widget.xtracr_realcamera.modelView_preview": "Vista Previa", diff --git a/common/src/main/resources/assets/realcamera/lang/fr_fr.json b/common/src/main/resources/assets/realcamera/lang/fr_fr.json index 69dd50bf..a174e7ea 100644 --- a/common/src/main/resources/assets/realcamera/lang/fr_fr.json +++ b/common/src/main/resources/assets/realcamera/lang/fr_fr.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Rendre la caméra plus réaliste en vue à la première personne.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Lorsqu'il est désactivé, la relation relative de la caméra avec le modèle ne changera pas, mais les attributs correspondants de la caméra ne seront pas modifiés par ce mod", "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurations enregistrées", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copier tous les paramètres de désactivation", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Supprimer le rectangle sélectionné\n(Ou utiliser la touche Suppr)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Les plans où toutes les distances vertex-à-écran sont inférieures à cette valeur ne seront pas rendus", "screen.tooltip.xtracr_realcamera.modelView_disable": "Paramètres de désactivation\nLes paramètres de désactivation globaux se trouvent dans l'écran de configuration", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Importer la configuration depuis le presse-papiers", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Échec de l'importation : \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importation %s réussie !", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Coller tous les paramètres de désactivation du presse-papiers dans la configuration actuelle\n(Ne remplacera pas les paramètres existants portant le même nom)", "screen.tooltip.xtracr_realcamera.modelView_preview": "En mode aperçu, vous pouvez ajuster le décalage et la rotation de la caméra", "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorité lors de la liaison, plus la valeur est grande, plus la priorité est élevée et plus le tri est haut sur le côté droit", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Enregistrer sous\n(Lorsqu'il existe une configuration avec le même nom, vous pouvez également utiliser le bouton enregistrer à gauche)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Ouvrir l'écran de configuration globale\n(API Cloth Config requise)", "screen.widget.xtracr_realcamera.modelView_all": "Tout", "screen.widget.xtracr_realcamera.modelView_configs": "Configurations", - "screen.widget.xtracr_realcamera.modelView_copy": "Copier", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Config Actuelle", "screen.widget.xtracr_realcamera.modelView_disable": "Désactiver", "screen.widget.xtracr_realcamera.modelView_disableMode": "Mode Désactivé", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Décalage Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Décalage Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Partie", - "screen.widget.xtracr_realcamera.modelView_paste": "Coller", "screen.widget.xtracr_realcamera.modelView_pitch": "Tangage = %s", "screen.widget.xtracr_realcamera.modelView_position": "Plan Cible", "screen.widget.xtracr_realcamera.modelView_preview": "Aperçu", diff --git a/common/src/main/resources/assets/realcamera/lang/ja_jp.json b/common/src/main/resources/assets/realcamera/lang/ja_jp.json index 7b167d1d..0858a1fb 100644 --- a/common/src/main/resources/assets/realcamera/lang/ja_jp.json +++ b/common/src/main/resources/assets/realcamera/lang/ja_jp.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "一人称視点のカメラをよりリアルにします。", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "無効時、カメラとモデルの相対的な位置関係は変化しませんが、カメラの対応する属性はこのMODによって変更されません", "screen.tooltip.xtracr_realcamera.modelView_configs": "保存済み設定", - "screen.tooltip.xtracr_realcamera.modelView_copy": "全ての無効設定をコピー", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "選択された矩形を削除\n(またはDeleteキーを使用)", "screen.tooltip.xtracr_realcamera.modelView_depth": "全ての頂点から画面までの距離がこの値より小さい面はレンダリングされません", "screen.tooltip.xtracr_realcamera.modelView_disable": "無効設定\nグローバル無効設定は設定画面にあります", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "クリップボードから設定をインポート", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "インポートに失敗しました: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%sのインポートに成功しました!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "クリップボードの全ての無効設定を現在の設定に貼り付け\n(同名設定は上書きされません)", "screen.tooltip.xtracr_realcamera.modelView_preview": "プレビューモードでカメラの様々なオフセットを調整できます", "screen.tooltip.xtracr_realcamera.modelView_priority": "バインディング時の優先度、値が大きいほど優先度が高く右側のソートで上位に表示", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "名前を付けて保存\n(同名設定がある場合も左の保存ボタンを使用できます)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "グローバル設定画面を開く\n(Cloth Config APIが必要)", "screen.widget.xtracr_realcamera.modelView_all": "全て", "screen.widget.xtracr_realcamera.modelView_configs": "設定", - "screen.widget.xtracr_realcamera.modelView_copy": "コピー", "screen.widget.xtracr_realcamera.modelView_currentConfig": "現在の設定", "screen.widget.xtracr_realcamera.modelView_disable": "無効", "screen.widget.xtracr_realcamera.modelView_disableMode": "無効モード", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Yオフセット = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Zオフセット = %s", "screen.widget.xtracr_realcamera.modelView_part": "一部", - "screen.widget.xtracr_realcamera.modelView_paste": "貼り付け", "screen.widget.xtracr_realcamera.modelView_pitch": "ピッチ = %s", "screen.widget.xtracr_realcamera.modelView_position": "ターゲット平面", "screen.widget.xtracr_realcamera.modelView_preview": "プレビュー", diff --git a/common/src/main/resources/assets/realcamera/lang/ko_kr.json b/common/src/main/resources/assets/realcamera/lang/ko_kr.json index 5936f653..af9931ee 100644 --- a/common/src/main/resources/assets/realcamera/lang/ko_kr.json +++ b/common/src/main/resources/assets/realcamera/lang/ko_kr.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "1인칭 시점에서 카메라를 더 현실적으로 만듭니다", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "비활성화 시 카메라와 모델의 상대적 관계는 변하지 않지만, 카메라의 해당 속성은 이 모드에서 수정되지 않습니다", "screen.tooltip.xtracr_realcamera.modelView_configs": "저장된 설정", - "screen.tooltip.xtracr_realcamera.modelView_copy": "모든 비활성화 설정 복사", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "선택된 사각형 삭제\n(또는 Delete 키 사용)", "screen.tooltip.xtracr_realcamera.modelView_depth": "모든 정점-화면 거리가 이 값보다 작은 면은 렌더링되지 않습니다", "screen.tooltip.xtracr_realcamera.modelView_disable": "비활성화 설정\n전역 비활성화 설정은 설정 화면에 있습니다", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "클립보드에서 설정 가져오기", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "가져오기 실패: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s 가져오기 성공!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "클립보드의 모든 비활성화 설정을 현재 설정에 붙여넣기\n(동일 이름 설정 덮어쓰지 않음)", "screen.tooltip.xtracr_realcamera.modelView_preview": "미리보기 모드에서 카메라의 다양한 오프셋 조정 가능", "screen.tooltip.xtracr_realcamera.modelView_priority": "바인딩 시 우선순위, 값이 클수록 우선순위가 높으며 오른쪽 정렬에서 위쪽에 표시", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "다른 이름으로 저장\n(동일 이름 설정이 있을 때 왼쪽 저장 버튼도 사용 가능)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "전역 설정 화면 열기\n(Cloth Config API 필요)", "screen.widget.xtracr_realcamera.modelView_all": "전체", "screen.widget.xtracr_realcamera.modelView_configs": "설정", - "screen.widget.xtracr_realcamera.modelView_copy": "복사", "screen.widget.xtracr_realcamera.modelView_currentConfig": "현재 설정", "screen.widget.xtracr_realcamera.modelView_disable": "비활성화", "screen.widget.xtracr_realcamera.modelView_disableMode": "비활성화 모드", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y 오프셋 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z 오프셋 = %s", "screen.widget.xtracr_realcamera.modelView_part": "부분", - "screen.widget.xtracr_realcamera.modelView_paste": "붙여넣기", "screen.widget.xtracr_realcamera.modelView_pitch": "피치 = %s", "screen.widget.xtracr_realcamera.modelView_position": "대상 평면", "screen.widget.xtracr_realcamera.modelView_preview": "미리보기", diff --git a/common/src/main/resources/assets/realcamera/lang/lzh.json b/common/src/main/resources/assets/realcamera/lang/lzh.json index 88c8885b..a0ed305b 100644 --- a/common/src/main/resources/assets/realcamera/lang/lzh.json +++ b/common/src/main/resources/assets/realcamera/lang/lzh.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "使第一人稱之鏡觀愈真。", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "禁時,鏡觀與模型之相對不變,然鏡觀之對應性不為本模所改", "screen.tooltip.xtracr_realcamera.modelView_configs": "已存之設", - "screen.tooltip.xtracr_realcamera.modelView_copy": "抄諸禁設", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "去擇之矩\n(或用Delete鍵)", "screen.tooltip.xtracr_realcamera.modelView_depth": "諸頂點至屏距皆小於此值之面不顯", "screen.tooltip.xtracr_realcamera.modelView_disable": "禁設\n全禁設在設屏中", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "从剪貼板入設", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "入敗:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "入%s成!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "貼剪貼板諸禁設至今設\n(不蓋同名設)", "screen.tooltip.xtracr_realcamera.modelView_preview": "於覽式可調鏡觀諸偏移", "screen.tooltip.xtracr_realcamera.modelView_priority": "系定之先級,值愈大愈先,且右列愈前", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "存為\n(當有同名設時,亦可用左存鈕)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "啟全設屏\n(需裝Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "全", "screen.widget.xtracr_realcamera.modelView_configs": "設", - "screen.widget.xtracr_realcamera.modelView_copy": "抄", "screen.widget.xtracr_realcamera.modelView_currentConfig": "現綁配", "screen.widget.xtracr_realcamera.modelView_disable": "禁", "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用之法", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y移 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z移 = %s", "screen.widget.xtracr_realcamera.modelView_part": "塊", - "screen.widget.xtracr_realcamera.modelView_paste": "貼", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰 = %s", "screen.widget.xtracr_realcamera.modelView_position": "的平面", "screen.widget.xtracr_realcamera.modelView_preview": "覽", diff --git a/common/src/main/resources/assets/realcamera/lang/pl_pl.json b/common/src/main/resources/assets/realcamera/lang/pl_pl.json index 3a70311c..0b75ce8a 100644 --- a/common/src/main/resources/assets/realcamera/lang/pl_pl.json +++ b/common/src/main/resources/assets/realcamera/lang/pl_pl.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Uczynienie kamery bardziej realistyczną w trybie pierwszoosobowym.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Po wyłączeniu względna pozycja kamery względem modelu nie ulegnie zmianie, ale odpowiednie atrybuty kamery nie będą modyfikowane przez ten mod", "screen.tooltip.xtracr_realcamera.modelView_configs": "Zapisane konfiguracje", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Skopiuj wszystkie ustawienia wyłączenia", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Usuń zaznaczony prostokąt\n(Lub użyj klawisza Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Płaszczyzny, w których wszystkie odległości od wierzchołka do ekranu są mniejsze niż ta wartość, nie będą renderowane", "screen.tooltip.xtracr_realcamera.modelView_disable": "Ustawienia wyłączenia\nGlobalne ustawienia wyłączenia znajdują się na ekranie konfiguracji", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Importuj konfigurację ze schowka", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Import nie powiódł się: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s powiódł się!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Wklej wszystkie ustawienia wyłączenia ze schowka do bieżącej konfiguracji\n(Nie nadpisze istniejących ustawień o tej samej nazwie)", "screen.tooltip.xtracr_realcamera.modelView_preview": "W trybie podglądu możesz dostosować przesunięcie i obrót kamery", "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorytet powiązania: im większa wartość, tym wyższy priorytet i wyższe sortowanie po prawej stronie", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Zapisz jako\n(Gdy istnieje konfiguracja o tej samej nazwie, możesz również użyć przycisku zapisu po lewej stronie)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Otwórz globalny ekran konfiguracji\n(Wymagane Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "Wszystko", "screen.widget.xtracr_realcamera.modelView_configs": "Konfiguracje", - "screen.widget.xtracr_realcamera.modelView_copy": "Kopiuj", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Bieżąca Konfiguracja", "screen.widget.xtracr_realcamera.modelView_disable": "Wyłącz", "screen.widget.xtracr_realcamera.modelView_disableMode": "Tryb wyłączenia", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Przesunięcie Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Przesunięcie Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Część", - "screen.widget.xtracr_realcamera.modelView_paste": "Wklej", "screen.widget.xtracr_realcamera.modelView_pitch": "Pochylenie = %s", "screen.widget.xtracr_realcamera.modelView_position": "Płaszczyzna docelowa", "screen.widget.xtracr_realcamera.modelView_preview": "Podgląd", diff --git a/common/src/main/resources/assets/realcamera/lang/pt_br.json b/common/src/main/resources/assets/realcamera/lang/pt_br.json index ae0d7381..8b604596 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_br.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_br.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Torna a câmera mais realista na visão em primeira pessoa.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Quando desativado, a relação relativa da câmera com o modelo não mudará, mas os atributos correspondentes da câmera não serão modificados por este mod", "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurações Salvas", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas as configurações de desativação", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Excluir o retângulo selecionado\n(Ou use a tecla Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Planos onde todas as distâncias vértice-para-tela são menores que este valor não serão renderizados", "screen.tooltip.xtracr_realcamera.modelView_disable": "Configurações de Desativação\nConfigurações globais de desativação estão na tela de configuração", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Colar todas as configurações de desativação da área de transferência para a configuração atual\n(Não substituirá configurações existentes com o mesmo nome)", "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir a Tela de Configuração Global\n(Cloth Config API necessário)", "screen.widget.xtracr_realcamera.modelView_all": "Todos", "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", - "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", "screen.widget.xtracr_realcamera.modelView_disable": "Desativar", "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo de Desativação", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Deslocamento Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Deslocamento Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Parte", - "screen.widget.xtracr_realcamera.modelView_paste": "Colar", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", "screen.widget.xtracr_realcamera.modelView_position": "Plano Alvo", "screen.widget.xtracr_realcamera.modelView_preview": "Pré-visualização", diff --git a/common/src/main/resources/assets/realcamera/lang/pt_pt.json b/common/src/main/resources/assets/realcamera/lang/pt_pt.json index b672d933..ccbb4f41 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_pt.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_pt.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Torne a câmera mais realista na visão em primeira pessoa.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Quando desativado, a relação relativa da câmera com o modelo não mudará, mas os atributos correspondentes da câmera não serão modificados por este mod", "screen.tooltip.xtracr_realcamera.modelView_configs": "Configurações Salvas", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Copiar todas as configurações de desativação", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Excluir o retângulo selecionado\n(Ou use a tecla Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Planos onde todas as distâncias vértice-para-tela são menores que este valor não serão renderizados", "screen.tooltip.xtracr_realcamera.modelView_disable": "Configurações de Desativação\nConfigurações globais de desativação estão na tela de configuração", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Importar configuração da área de transferência", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Falha na importação: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Colar todas as configurações de desativação da área de transferência para a configuração atual\n(Não substituirá configurações existentes com o mesmo nome)", "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Abrir a Tela de Configuração Global\n(Cloth Config API necessário)", "screen.widget.xtracr_realcamera.modelView_all": "Todos", "screen.widget.xtracr_realcamera.modelView_configs": "Configurações", - "screen.widget.xtracr_realcamera.modelView_copy": "Copiar", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Configuração Atual", "screen.widget.xtracr_realcamera.modelView_disable": "Desativar", "screen.widget.xtracr_realcamera.modelView_disableMode": "Modo de Desativação", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Deslocamento Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Deslocamento Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Parte", - "screen.widget.xtracr_realcamera.modelView_paste": "Colar", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", "screen.widget.xtracr_realcamera.modelView_position": "Plano Alvo", "screen.widget.xtracr_realcamera.modelView_preview": "Pré-visualização", diff --git a/common/src/main/resources/assets/realcamera/lang/ru_ru.json b/common/src/main/resources/assets/realcamera/lang/ru_ru.json index fb449b6a..eb8eec98 100644 --- a/common/src/main/resources/assets/realcamera/lang/ru_ru.json +++ b/common/src/main/resources/assets/realcamera/lang/ru_ru.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Сделать камеру более реалистичной в режиме от первого лица.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "При отключении относительное положение камеры к модели не изменится, но соответствующие атрибуты камеры не будут изменены этим модом", "screen.tooltip.xtracr_realcamera.modelView_configs": "Сохраненные конфигурации", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Копировать все настройки отключения", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Удалить выбранный прямоугольник\n(Или используйте клавишу Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Плоскости, где все расстояния от вершины до экрана меньше этого значения, не будут отображаться", "screen.tooltip.xtracr_realcamera.modelView_disable": "Настройки отключения\nГлобальные настройки отключения находятся на экране конфигурации", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Импортировать конфигурацию из буфера обмена", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Ошибка импорта: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Импорт %s успешен!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Вставить все настройки отключения из буфера обмена в текущую конфигурацию\n(Не перезапишет существующие настройки с тем же именем)", "screen.tooltip.xtracr_realcamera.modelView_preview": "В режиме предпросмотра вы можете настроить смещение и вращение камеры", "screen.tooltip.xtracr_realcamera.modelView_priority": "Приоритет при привязке: чем больше значение, тем выше приоритет и выше сортировка на правой стороне", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Сохранить как\n(При наличии настройки с тем же именем вы также можете использовать кнопку сохранения слева)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Открыть глобальный экран конфигурации\n(Требуется Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "Все", "screen.widget.xtracr_realcamera.modelView_configs": "Конфигурации", - "screen.widget.xtracr_realcamera.modelView_copy": "Копировать", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Текущая Конфигурация", "screen.widget.xtracr_realcamera.modelView_disable": "Отключить", "screen.widget.xtracr_realcamera.modelView_disableMode": "Режим отключения", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Смещение Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Смещение Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Часть", - "screen.widget.xtracr_realcamera.modelView_paste": "Вставить", "screen.widget.xtracr_realcamera.modelView_pitch": "Тангаж = %s", "screen.widget.xtracr_realcamera.modelView_position": "Целевая плоскость", "screen.widget.xtracr_realcamera.modelView_preview": "Предпросмотр", diff --git a/common/src/main/resources/assets/realcamera/lang/tr_tr.json b/common/src/main/resources/assets/realcamera/lang/tr_tr.json index 4fec1c17..2dd336f2 100644 --- a/common/src/main/resources/assets/realcamera/lang/tr_tr.json +++ b/common/src/main/resources/assets/realcamera/lang/tr_tr.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Birinci şahıs görünümünde kamerayı daha gerçekçi hale getirir.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "Devre dışı bırakıldığında, kameranın modele göre göreceli ilişkisi değişmeyecek, ancak kameranın ilgili özellikleri bu mod tarafından değiştirilmeyecektir", "screen.tooltip.xtracr_realcamera.modelView_configs": "Kayıtlı Yapılandırmalar", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Tüm devre dışı bırakma ayarlarını kopyala", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Seçili dikdörtgeni sil\n(Veya Sil tuşunu kullanın)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Tüm köşe-ekran mesafelerinin bu değerden küçük olduğu düzlemler render edilmeyecektir", "screen.tooltip.xtracr_realcamera.modelView_disable": "Devre Dışı Bırakma Ayarları\nGenel devre dışı bırakma ayarları ayarlar ekranındadır", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Panodan yapılandırmayı içe aktar", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "İçe aktarma başarısız: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s içe aktarma başarılı!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Panodaki tüm devre dışı bırakma ayarlarını mevcut yapılandırmaya yapıştır\n(Aynı isimdeki mevcut ayarların üzerine yazılmaz)", "screen.tooltip.xtracr_realcamera.modelView_preview": "Önizleme modunda kameranın çeşitli ofsetlerini ayarlayabilirsiniz", "screen.tooltip.xtracr_realcamera.modelView_priority": "Bağlama önceliği, değer ne kadar büyükse öncelik o kadar yüksektir ve sağ taraftaki sıralama da o kadar yukarıdadır", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Farklı Kaydet\n(Aynı isimde bir ayar olduğunda, soldaki kaydet düğmesini de kullanabilirsiniz)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Genel Yapılandırma Ekranını Aç\n(Cloth Config API gerekli)", "screen.widget.xtracr_realcamera.modelView_all": "Tümü", "screen.widget.xtracr_realcamera.modelView_configs": "Yapılandırmalar", - "screen.widget.xtracr_realcamera.modelView_copy": "Kopyala", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Mevcut Yapılandırma", "screen.widget.xtracr_realcamera.modelView_disable": "Devre Dışı Bırak", "screen.widget.xtracr_realcamera.modelView_disableMode": "Devre Dışı Bırakma Modu", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y Ofseti = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z Ofseti = %s", "screen.widget.xtracr_realcamera.modelView_part": "Parça", - "screen.widget.xtracr_realcamera.modelView_paste": "Yapıştır", "screen.widget.xtracr_realcamera.modelView_pitch": "Pitch = %s", "screen.widget.xtracr_realcamera.modelView_position": "Hedef Düzlem", "screen.widget.xtracr_realcamera.modelView_preview": "Önizleme", diff --git a/common/src/main/resources/assets/realcamera/lang/uk_ua.json b/common/src/main/resources/assets/realcamera/lang/uk_ua.json index aa48b777..27307c1b 100644 --- a/common/src/main/resources/assets/realcamera/lang/uk_ua.json +++ b/common/src/main/resources/assets/realcamera/lang/uk_ua.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "Зробити камеру більш реалістичною в режимі від першої особи.", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "При вимкненні відносне положення камери до моделі не зміниться, але відповідні атрибути камери не будуть змінені цим модом", "screen.tooltip.xtracr_realcamera.modelView_configs": "Збережені конфігурації", - "screen.tooltip.xtracr_realcamera.modelView_copy": "Копіювати всі налаштування вимкнення", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "Видалити вибраний прямокутник\n(Або використовуйте клавішу Delete)", "screen.tooltip.xtracr_realcamera.modelView_depth": "Площини, де всі відстані від вершини до екрану менші за це значення, не будуть відображатися", "screen.tooltip.xtracr_realcamera.modelView_disable": "Налаштування вимкнення\nГлобальні налаштування вимкнення знаходяться на екрані конфігурації", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "Імпортувати конфігурацію з буфера обміну", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "Помилка імпорту: \n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпорт %s успішний!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "Вставити всі налаштування вимкнення з буфера обміну в поточну конфігурацію\n(Не перезапише існуючі налаштування з тим же ім'ям)", "screen.tooltip.xtracr_realcamera.modelView_preview": "У режимі попереднього перегляду ви можете налаштувати зміщення та обертання камери", "screen.tooltip.xtracr_realcamera.modelView_priority": "Пріоритет при прив'язці: чим більше значення, тим вищий пріоритет і вище сортування на правій стороні", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Зберегти як\n(При наявності налаштування з тим же ім'ям ви також можете використовувати кнопку збереження зліва)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "Відкрити глобальний екран конфігурації\n(Потрібен Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "Усе", "screen.widget.xtracr_realcamera.modelView_configs": "Конфігурації", - "screen.widget.xtracr_realcamera.modelView_copy": "Копіювати", "screen.widget.xtracr_realcamera.modelView_currentConfig": "Поточна Конфігурація", "screen.widget.xtracr_realcamera.modelView_disable": "Вимкнути", "screen.widget.xtracr_realcamera.modelView_disableMode": "Режим вимкнення", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Зміщення Y = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Зміщення Z = %s", "screen.widget.xtracr_realcamera.modelView_part": "Частина", - "screen.widget.xtracr_realcamera.modelView_paste": "Вставити", "screen.widget.xtracr_realcamera.modelView_pitch": "Тангаж = %s", "screen.widget.xtracr_realcamera.modelView_position": "Цільова площина", "screen.widget.xtracr_realcamera.modelView_preview": "Попередній перегляд", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 4ce465b3..3ffd60e7 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "使第一人称视角下的摄像头更加真实。", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "当禁用时,摄像头与模型的相对关系不会变化,但摄像头的对应属性不会被本模组修改", "screen.tooltip.xtracr_realcamera.modelView_configs": "已保存的配置", - "screen.tooltip.xtracr_realcamera.modelView_copy": "复制所有禁用设置", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "删除选中的矩形\n(或使用Delete键)", "screen.tooltip.xtracr_realcamera.modelView_depth": "全部顶点到屏幕距离均小于该值的面不会被渲染", "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用设置\n全局禁用设置在配置屏幕中", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "从剪贴板导入配置", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "导入失败:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "导入%s成功!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "粘贴剪贴板中的所有禁用设置到当前配置\n(不会覆盖同名设置)", "screen.tooltip.xtracr_realcamera.modelView_preview": "在预览模式可以调整相机的各个偏移量", "screen.tooltip.xtracr_realcamera.modelView_priority": "绑定时的优先级,值越大优先级越高,并且在右侧排序越靠上", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "保存为\n(当存在同名设置时,也可使用左侧保存按钮)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打开全局配置屏幕\n(需要安装Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "全部", "screen.widget.xtracr_realcamera.modelView_configs": "配置", - "screen.widget.xtracr_realcamera.modelView_copy": "复制", "screen.widget.xtracr_realcamera.modelView_currentConfig": "当前配置", "screen.widget.xtracr_realcamera.modelView_disable": "禁用", "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_part": "部分", - "screen.widget.xtracr_realcamera.modelView_paste": "粘贴", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰角 = %s", "screen.widget.xtracr_realcamera.modelView_position": "目标平面", "screen.widget.xtracr_realcamera.modelView_preview": "预览", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_hk.json b/common/src/main/resources/assets/realcamera/lang/zh_hk.json index 96053fb9..c75986e5 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_hk.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_hk.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "使第一人稱視角下的攝像頭更加真實。", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "當禁用時,攝像頭與模型的相對關係不會變化,但攝像頭的對應屬性不會被本模組修改", "screen.tooltip.xtracr_realcamera.modelView_configs": "已儲存的配置", - "screen.tooltip.xtracr_realcamera.modelView_copy": "複製所有禁用設置", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "刪除選中的矩形\n(或使用Delete鍵)", "screen.tooltip.xtracr_realcamera.modelView_depth": "全部頂點到屏幕距離均小於該值的面不會被渲染", "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用設置\n全局禁用設置在配置屏幕中", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "貼上剪貼簿中的所有禁用設置到當前配置\n(不會覆蓋同名設置)", "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打開全局配置屏幕\n(需要安裝Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "全部", "screen.widget.xtracr_realcamera.modelView_configs": "配置", - "screen.widget.xtracr_realcamera.modelView_copy": "複製", "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", "screen.widget.xtracr_realcamera.modelView_disable": "禁用", "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_part": "部分", - "screen.widget.xtracr_realcamera.modelView_paste": "貼上", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰角 = %s", "screen.widget.xtracr_realcamera.modelView_position": "目標平面", "screen.widget.xtracr_realcamera.modelView_preview": "預覽", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_tw.json b/common/src/main/resources/assets/realcamera/lang/zh_tw.json index 96053fb9..c75986e5 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_tw.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_tw.json @@ -75,7 +75,6 @@ "modmenu.descriptionTranslation.realcamera": "使第一人稱視角下的攝像頭更加真實。", "screen.tooltip.xtracr_realcamera.modelView_bindButtons": "當禁用時,攝像頭與模型的相對關係不會變化,但攝像頭的對應屬性不會被本模組修改", "screen.tooltip.xtracr_realcamera.modelView_configs": "已儲存的配置", - "screen.tooltip.xtracr_realcamera.modelView_copy": "複製所有禁用設置", "screen.tooltip.xtracr_realcamera.modelView_deleteSelectedRectangle": "刪除選中的矩形\n(或使用Delete鍵)", "screen.tooltip.xtracr_realcamera.modelView_depth": "全部頂點到屏幕距離均小於該值的面不會被渲染", "screen.tooltip.xtracr_realcamera.modelView_disable": "禁用設置\n全局禁用設置在配置屏幕中", @@ -90,7 +89,6 @@ "screen.tooltip.xtracr_realcamera.modelView_import": "從剪貼簿導入配置", "screen.tooltip.xtracr_realcamera.modelView_importFailed": "導入失敗:\n%s", "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", - "screen.tooltip.xtracr_realcamera.modelView_paste": "貼上剪貼簿中的所有禁用設置到當前配置\n(不會覆蓋同名設置)", "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", @@ -102,7 +100,6 @@ "screen.tooltip.xtracr_realcamera.modelView_toConfigScreen": "打開全局配置屏幕\n(需要安裝Cloth Config API)", "screen.widget.xtracr_realcamera.modelView_all": "全部", "screen.widget.xtracr_realcamera.modelView_configs": "配置", - "screen.widget.xtracr_realcamera.modelView_copy": "複製", "screen.widget.xtracr_realcamera.modelView_currentConfig": "當前配置", "screen.widget.xtracr_realcamera.modelView_disable": "禁用", "screen.widget.xtracr_realcamera.modelView_disableMode": "禁用模式", @@ -114,7 +111,6 @@ "screen.widget.xtracr_realcamera.modelView_offsetY": "Y偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_offsetZ": "Z偏移量 = %s", "screen.widget.xtracr_realcamera.modelView_part": "部分", - "screen.widget.xtracr_realcamera.modelView_paste": "貼上", "screen.widget.xtracr_realcamera.modelView_pitch": "俯仰角 = %s", "screen.widget.xtracr_realcamera.modelView_position": "目標平面", "screen.widget.xtracr_realcamera.modelView_preview": "預覽", diff --git a/common/src/main/resources/realcamera-common.mixins.json b/common/src/main/resources/realcamera-common.mixins.json index 1f026f74..fea92b3d 100644 --- a/common/src/main/resources/realcamera-common.mixins.json +++ b/common/src/main/resources/realcamera-common.mixins.json @@ -19,7 +19,8 @@ "accessor.CustomFeatureRenderer$StorageAccessor", "accessor.GuiGraphicsExtractorAccessor", "accessor.ModelFeatureRenderer$StorageAccessor", - "accessor.ModelPartFeatureRenderer$StorageAccessor" + "accessor.ModelPartFeatureRenderer$StorageAccessor", + "accessor.RenderTypeAccessor" ], "server": [ ], diff --git a/common/src/main/resources/realcamera.accesswidener b/common/src/main/resources/realcamera.accesswidener index 869e8c7c..8b9c3f07 100644 --- a/common/src/main/resources/realcamera.accesswidener +++ b/common/src/main/resources/realcamera.accesswidener @@ -1,3 +1,4 @@ accessWidener v2 official accessible class net/minecraft/client/gui/GuiGraphicsExtractor$ScissorStack +accessible class net/minecraft/client/renderer/rendertype/RenderSetup$TextureBinding extendable method net/minecraft/client/renderer/MultiBufferSource$BufferSource endBatch (Lnet/minecraft/client/renderer/rendertype/RenderType;Lcom/mojang/blaze3d/vertex/BufferBuilder;)V \ No newline at end of file diff --git a/neoforge/src/main/resources/META-INF/accesstransformer.cfg b/neoforge/src/main/resources/META-INF/accesstransformer.cfg index 3e09a5a6..9b411f49 100644 --- a/neoforge/src/main/resources/META-INF/accesstransformer.cfg +++ b/neoforge/src/main/resources/META-INF/accesstransformer.cfg @@ -1,2 +1,3 @@ public net.minecraft.client.gui.GuiGraphicsExtractor$ScissorStack +public net.minecraft.client.renderer.rendertype.RenderSetup$TextureBinding protected net.minecraft.client.renderer.MultiBufferSource$BufferSource endBatch(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/BufferBuilder;)V \ No newline at end of file From d811c45f0c59a703862c4c8b494fd3769f90c926 Mon Sep 17 00:00:00 2001 From: xTracr Date: Sat, 9 May 2026 14:08:10 +0800 Subject: [PATCH 11/33] Replace `Float2ObjectOpenHashMap` with `LongOpenHashSet` --- .../realcamera/compat/DisableHelper.java | 4 +++- .../xtracr/realcamera/compat/YSMCompat.java | 4 ++-- .../xtracr/realcamera/config/BindTarget.java | 18 +++++++----------- gradle.properties | 10 +++++----- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 015ea304..70c6140a 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -13,9 +13,11 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; +import java.util.regex.Pattern; public class DisableHelper { public static final Entry MAIN_FEATURE, RENDER_MODEL, RENDER_HANDS; + private static final Pattern MULTI_STAR = Pattern.compile("\\*+"); private static final Predicate FALSE = _ -> false; private static final Map entries = new HashMap<>(); public static int exitTick = 0; @@ -81,7 +83,7 @@ public static boolean matchesItemPattern(Item item, String pattern) { public static boolean simpleWildcardMatch(String text, String pattern) { if (pattern.isEmpty()) return text.isEmpty(); if (pattern.equals(text)) return true; - String[] parts = pattern.split("\\*+"); + String[] parts = MULTI_STAR.split(pattern); if (parts.length == 0) return true; int currentIndex = 0; if (!pattern.startsWith("*")) { diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index 1a2d846c..e00e6bf9 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -78,7 +78,7 @@ public TransformedVertexRecorder setRotation(float pitch, float yaw) { public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = resultMap.computeIfAbsent(target, _ -> new BindResult(target)); + BindResult result = resultMap.computeIfAbsent(target, BindResult::new); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = new VertexData.UV(config.posU(), config.posV()); VertexData.UV forwardUV = new VertexData.UV(config.forwardU(), config.forwardV()); @@ -100,7 +100,7 @@ public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { public void computeBindResult(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = resultMap.computeIfAbsent(target, _ -> new BindResult(target)); + BindResult result = resultMap.computeIfAbsent(target, BindResult::new); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = result.getPosition() == Vec3.ZERO ? new VertexData.UV(config.posU(), config.posV()) : null; VertexData.UV forwardUV = result.getForward() == Vec3.ZERO ? new VertexData.UV(config.forwardU(), config.forwardV()) : null; diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index 3f5dc027..32ce669c 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -5,8 +5,7 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import com.xtracr.realcamera.renderer.state.VertexData; -import it.unimi.dsi.fastutil.floats.Float2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.floats.FloatOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.util.Mth; @@ -211,7 +210,7 @@ public void write(FriendlyByteBuf byteBuf) { @JsonAdapter(DisableConfig.Adapter.class) public static class DisableConfig { - private final Float2ObjectOpenHashMap disableCacheMap = new Float2ObjectOpenHashMap<>(); + private final LongOpenHashSet disabledUVs = new LongOpenHashSet(), enabledUVs = new LongOpenHashSet(); private final String name; private final String textureId; private final boolean disableAll; @@ -222,7 +221,6 @@ public DisableConfig(String name, String textureId, boolean disableAll, UVRectan this.textureId = textureId; this.disableAll = disableAll; this.rectangles = rectangles; - disableCacheMap.defaultReturnValue(FloatOpenHashSet.of()); } public static DisableConfig read(FriendlyByteBuf byteBuf) { @@ -264,17 +262,15 @@ public void write(FriendlyByteBuf byteBuf) { public boolean disable(VertexData vertex) { final float u = vertex.u(), v = vertex.v(); - final FloatOpenHashSet cachedVs = disableCacheMap.get(u); - if (!cachedVs.isEmpty()) { - if (cachedVs.contains(v)) return true; - if (cachedVs.contains(-v)) return false; - } + final long packed = (long) Float.floatToIntBits(u) << 32 | Float.floatToIntBits(v); + if (enabledUVs.contains(packed)) return false; + if (disabledUVs.contains(packed)) return true; for (UVRectangle rect : rectangles) { if (!rect.contains(u, v)) continue; - disableCacheMap.computeIfAbsent(u, _ -> new FloatOpenHashSet()).add(v); + disabledUVs.add(packed); return true; } - disableCacheMap.computeIfAbsent(u, _ -> new FloatOpenHashSet()).add(-v); + enabledUVs.add(packed); return false; } diff --git a/gradle.properties b/gradle.properties index e08ad7e8..16bf9fb3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,17 +4,17 @@ org.gradle.parallel=true org.gradle.configuration-cache=false ## Environment Properties java_version=25 -minecraft_version=26.1.1 +minecraft_version=26.1.2 enabled_platforms=fabric,neoforge loom_version=1.16-SNAPSHOT -fabric_loader_version=0.19.0 -neoforge_version=26.1.1.14-beta +fabric_loader_version=0.19.2 +neoforge_version=26.1.2.36-beta moddev_version=2.0.141 ## Mod Properties mod_id=realcamera -mod_version=0.7.6-beta +mod_version=0.7.7-beta mod_group_id=com.xtracr.realcamera ## Dependencies -fabric_api_version=0.145.4+26.1.1 +fabric_api_version=0.147.0+26.1.2 cloth_config_version=26.1.154 modmenu_version=18.0.0-alpha.8 From f69509813971bb8a2114ba42cd9deefd38ae5eae Mon Sep 17 00:00:00 2001 From: xTracr Date: Tue, 12 May 2026 17:22:04 +0800 Subject: [PATCH 12/33] Extract RenderTypeUtil with evicting caches; finalize utility classes -- Upgrade gradle to 9.5.0 --- .gitignore | 3 +- .../renderer/BuiltIterableBuffer.java | 44 ++--------- .../xtracr/realcamera/util/CrosshairUtil.java | 2 +- .../com/xtracr/realcamera/util/LocUtil.java | 2 +- .../com/xtracr/realcamera/util/MathUtil.java | 2 +- .../xtracr/realcamera/util/RaycastUtil.java | 2 +- .../realcamera/util/RenderTypeUtil.java | 76 +++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 5 +- 8 files changed, 89 insertions(+), 47 deletions(-) create mode 100644 common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java diff --git a/.gitignore b/.gitignore index 36d81e47..87beff70 100644 --- a/.gitignore +++ b/.gitignore @@ -36,5 +36,6 @@ replay_*.log *.hprof *.jfr -# claude +# agent +AGENTS.md CLAUDE.md \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index 611914be..c684a565 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -1,56 +1,22 @@ package com.xtracr.realcamera.renderer; import com.mojang.blaze3d.vertex.MeshData; -import com.xtracr.realcamera.RealCamera; -import com.xtracr.realcamera.mixin.accessor.RenderTypeAccessor; import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.renderer.state.VertexData.UV; -import net.minecraft.client.renderer.rendertype.RenderSetup; +import com.xtracr.realcamera.util.RenderTypeUtil; import net.minecraft.client.renderer.rendertype.RenderType; import org.jspecify.annotations.Nullable; import java.awt.*; -import java.lang.reflect.Field; -import java.util.HashMap; import java.util.Map; public record BuiltIterableBuffer(RenderType renderType, String textureId, IterableVertexBuffer vertexBuffer) { - @Nullable - private static final Field TEXTURES_FIELD; - private static final Map TEXTURE_ID_CACHE = new HashMap<>(); - private static final Map> FIND_PRIMITIVE_CACHE = new HashMap<>(); - - static { - Field texturesField = null; - try { - texturesField = RenderSetup.class.getDeclaredField("textures"); - texturesField.setAccessible(true); - } catch (NoSuchFieldException e) { - RealCamera.LOGGER.error("Failed to find textures field in RenderSetup", e); - } - TEXTURES_FIELD = texturesField; - } - public static BuiltIterableBuffer buildFrom(RenderType renderType, MeshData meshData) { - String textureId = TEXTURE_ID_CACHE.computeIfAbsent(renderType, BuiltIterableBuffer::getTextureId); - return new BuiltIterableBuffer(renderType, textureId, new IterableVertexBuffer(meshData)); - } - - @SuppressWarnings("unchecked") - private static String getTextureId(RenderType renderType) { - if (TEXTURES_FIELD == null) return renderType.toString(); - RenderSetup renderSetup = ((RenderTypeAccessor) renderType).getState(); - try { - Map textureBindings = (Map) TEXTURES_FIELD.get(renderSetup); - RenderSetup.TextureBinding sampler0 = textureBindings.get("Sampler0"); - if (sampler0 != null) return sampler0.location().toString(); - } catch (IllegalAccessException | IllegalArgumentException | ClassCastException _) { - } - return renderType.toString(); + return new BuiltIterableBuffer(renderType, RenderTypeUtil.getTextureId(renderType), new IterableVertexBuffer(meshData)); } public boolean anyNotCached(UV[] uvs) { - Map cache = FIND_PRIMITIVE_CACHE.get(renderType); + Map cache = RenderTypeUtil.getPrimitiveCache(renderType); if (cache == null) return true; for (UV uv : uvs) { if (!cache.containsKey(uv)) return true; @@ -59,7 +25,7 @@ public boolean anyNotCached(UV[] uvs) { } public VertexData[] @Nullable [] findPrimitivesInCache(UV[] uvs) { - Map cache = FIND_PRIMITIVE_CACHE.get(renderType); + Map cache = RenderTypeUtil.getPrimitiveCache(renderType); int length = renderType.mode().primitiveLength, uvsLength = uvs.length; VertexData[][] primitives = new VertexData[uvsLength][]; if (cache == null) return primitives; @@ -116,7 +82,7 @@ public boolean anyNotCached(UV[] uvs) { uvCache[j * 2] = primitive[j].u(); uvCache[j * 2 + 1] = primitive[j].v(); } - FIND_PRIMITIVE_CACHE.computeIfAbsent(renderType, _ -> new HashMap<>()).put(uv, uvCache); + RenderTypeUtil.cachePrimitive(renderType, uv, uvCache); primitives[i] = VertexData.asImmutable(primitive); } return allFound; diff --git a/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java b/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java index 557c7dcb..16a7c2a6 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java @@ -8,7 +8,7 @@ import org.joml.Matrix3x2fStack; import org.joml.Matrix4fc; -public class CrosshairUtil { +public final class CrosshairUtil { public static EntityHitResult capturedEntityHitResult; public static Vec3 offset = Vec3.ZERO; diff --git a/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java b/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java index c2ea3007..3b0b14b8 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java @@ -4,7 +4,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -public class LocUtil { +public final class LocUtil { public static final String KEY_MOD_NAME = "general." + RealCamera.FULL_ID + ".modName"; public static MutableComponent MOD_NAME() { diff --git a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java index ab939a6a..315bc540 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -5,7 +5,7 @@ import org.joml.Matrix4fc; import org.joml.Vector4f; -public class MathUtil { +public final class MathUtil { public static double round(double d, int digits) { return Math.round(d * Math.pow(10, digits)) / Math.pow(10, digits); } diff --git a/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java b/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java index e2de0b92..c81c5103 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java @@ -6,7 +6,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; -public class RaycastUtil { +public final class RaycastUtil { /** * Updates raycast start and end points ensuring: *
  • End point is on camera's viewing direction diff --git a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java new file mode 100644 index 00000000..fa8df2b7 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java @@ -0,0 +1,76 @@ +package com.xtracr.realcamera.util; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.xtracr.realcamera.RealCamera; +import com.xtracr.realcamera.mixin.accessor.RenderTypeAccessor; +import com.xtracr.realcamera.renderer.state.VertexData.UV; +import net.minecraft.client.renderer.rendertype.RenderSetup; +import net.minecraft.client.renderer.rendertype.RenderType; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public final class RenderTypeUtil { + @Nullable + private static final Field TEXTURES_FIELD; + private static final LoadingCache TEXTURE_ID_CACHE = CacheBuilder.newBuilder() + .maximumSize(64) + .expireAfterAccess(60, TimeUnit.SECONDS) + .build(new TextureIdCacheLoader()); + private static final LoadingCache> PRIMITIVE_CACHE = CacheBuilder.newBuilder() + .maximumSize(64) + .expireAfterAccess(60, TimeUnit.SECONDS) + .build(new PrimitiveCacheLoader()); + + static { + Field texturesField = null; + try { + texturesField = RenderSetup.class.getDeclaredField("textures"); + texturesField.setAccessible(true); + } catch (NoSuchFieldException e) { + RealCamera.LOGGER.error("Failed to find textures field in RenderSetup", e); + } + TEXTURES_FIELD = texturesField; + } + + public static String getTextureId(RenderType renderType) { + return TEXTURE_ID_CACHE.getUnchecked(renderType); + } + + public static @Nullable Map getPrimitiveCache(RenderType renderType) { + return PRIMITIVE_CACHE.getIfPresent(renderType); + } + + public static void cachePrimitive(RenderType renderType, UV uv, float[] uvCoords) { + PRIMITIVE_CACHE.getUnchecked(renderType).put(uv, uvCoords); + } + + private static class TextureIdCacheLoader extends CacheLoader { + @SuppressWarnings("unchecked") + @Override + public @NonNull String load(@NonNull RenderType renderType) { + if (TEXTURES_FIELD == null) return renderType.toString(); + RenderSetup renderSetup = ((RenderTypeAccessor) renderType).getState(); + try { + Map textureBindings = (Map) TEXTURES_FIELD.get(renderSetup); + RenderSetup.TextureBinding sampler0 = textureBindings.get("Sampler0"); + if (sampler0 != null) return sampler0.location().toString(); + } catch (IllegalAccessException | IllegalArgumentException | ClassCastException _) { + } + return renderType.toString(); + } + } + + private static class PrimitiveCacheLoader extends CacheLoader> { + @Override + public @NonNull Map load(@NonNull RenderType renderType) { + return new HashMap<>(4); + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118f..358d405e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ +#Tue May 12 13:08:14 CST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d460430487fa4db4e9b9a01275b80ebcf33a318b Mon Sep 17 00:00:00 2001 From: xTracr Date: Tue, 12 May 2026 20:05:14 +0800 Subject: [PATCH 13/33] Remove AWT Polygon dependency with custom geometry methods; finalize non-API classes --- .../com/xtracr/realcamera/RealCameraCore.java | 2 +- .../xtracr/realcamera/api/RealCameraAPI.java | 2 +- .../compat/CompatibilityHelper.java | 2 +- .../realcamera/compat/DisableHelper.java | 2 +- .../realcamera/compat/LegacyBindingMode.java | 2 +- .../xtracr/realcamera/compat/YSMCompat.java | 2 +- .../xtracr/realcamera/config/BindTarget.java | 6 +-- .../xtracr/realcamera/config/ConfigFile.java | 2 +- .../realcamera/config/ConfigScreen.java | 2 +- .../xtracr/realcamera/config/ModConfig.java | 2 +- .../com/xtracr/realcamera/gui/GUIHelper.java | 2 +- .../xtracr/realcamera/gui/ModelAnalyser.java | 50 ++++--------------- .../realcamera/gui/ModelViewScreen.java | 48 +++++++++--------- .../renderer/BuiltIterableBuffer.java | 10 +--- .../renderer/IterableVertexBuffer.java | 14 +++--- .../renderer/MultiVertexCatcher.java | 8 +-- .../renderer/RoutingSubmitCollector.java | 4 +- .../renderer/gui/GuiCulledModelsRenderer.java | 2 +- .../gui/GuiFlattenedModelsRenderer.java | 2 +- .../realcamera/renderer/state/VertexData.java | 33 +++++++++++- .../com/xtracr/realcamera/util/MathUtil.java | 26 ++++++++++ .../xtracr/realcamera/RealCameraFabric.java | 2 +- .../realcamera/config/RealCameraMenu.java | 2 +- .../com/xtracr/realcamera/EventHandler.java | 2 +- .../xtracr/realcamera/RealCameraNeoForge.java | 2 +- 25 files changed, 125 insertions(+), 106 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 18ad5f6e..e83ad6e1 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -24,7 +24,7 @@ import org.joml.Matrix3f; import org.joml.Matrix4f; -public class RealCameraCore { +public final class RealCameraCore { private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final CameraTransform smoothedCamera = new CameraTransform(); private static BindResult lastResult = BindResult.EMPTY, newResult = BindResult.EMPTY; diff --git a/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java b/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java index c91225bb..2e0157dc 100644 --- a/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java +++ b/common/src/main/java/com/xtracr/realcamera/api/RealCameraAPI.java @@ -8,7 +8,7 @@ import java.util.Map; import java.util.function.BiFunction; -public class RealCameraAPI { +public final class RealCameraAPI { private static final List> FUNCTIONS = new ArrayList<>(); private static final Map, Integer> PRIORITIES = new Object2IntOpenHashMap<>(); diff --git a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java index 5f481a36..17776f4f 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java @@ -7,7 +7,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; -public class CompatibilityHelper { +public final class CompatibilityHelper { private static PlatformHelper platformHelper; private static Method NEA_playerTransformer_setDeltaTick; private static Field NEA_NEAnimationsLoader_INSTANCE; diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 70c6140a..172c77f7 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -15,7 +15,7 @@ import java.util.function.Predicate; import java.util.regex.Pattern; -public class DisableHelper { +public final class DisableHelper { public static final Entry MAIN_FEATURE, RENDER_MODEL, RENDER_HANDS; private static final Pattern MULTI_STAR = Pattern.compile("\\*+"); private static final Predicate FALSE = _ -> false; diff --git a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java index e12c664f..5cc4b2fb 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java @@ -15,7 +15,7 @@ import org.joml.Vector3f; import org.joml.Vector4f; -public class LegacyBindingMode { +public final class LegacyBindingMode { public static void register() { RealCameraAPI.registerFunction(100, LegacyBindingMode::computeBindResult); } diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index e00e6bf9..6f7c36f1 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -19,7 +19,7 @@ import java.util.HashMap; import java.util.Map; -public class YSMCompat { +public final class YSMCompat { private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final Map resultMap = new HashMap<>(); private static final TransformedVertexRecorder[] transformedRecorders = new TransformedVertexRecorder[4]; diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index 32ce669c..8e91c4b8 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -127,7 +127,7 @@ public void write(FriendlyByteBuf byteBuf) { } } - public static class OffsetConfig { + public static final class OffsetConfig { private float scale = 1, x = 0, y = 0, z = 0, pitch = 0, yaw = 0, roll = 0; public static OffsetConfig read(FriendlyByteBuf byteBuf) { @@ -209,7 +209,7 @@ public void write(FriendlyByteBuf byteBuf) { } @JsonAdapter(DisableConfig.Adapter.class) - public static class DisableConfig { + public static final class DisableConfig { private final LongOpenHashSet disabledUVs = new LongOpenHashSet(), enabledUVs = new LongOpenHashSet(); private final String name; private final String textureId; @@ -274,7 +274,7 @@ public boolean disable(VertexData vertex) { return false; } - public static class Adapter extends TypeAdapter { + public static final class Adapter extends TypeAdapter { @Override public void write(JsonWriter out, DisableConfig value) throws IOException { out.beginObject(); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java index eefa33e5..0325871b 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java @@ -11,7 +11,7 @@ import java.nio.file.Files; import java.nio.file.Path; -public class ConfigFile { +public final class ConfigFile { private static final ModConfig modConfig = new ModConfig(); private static final String FILE_NAME = RealCamera.MODID + ".json"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 1a56ded3..137a18b0 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -11,7 +11,7 @@ import java.util.List; -public class ConfigScreen { +public final class ConfigScreen { public static Screen create(Screen parent) { ConfigFile.load(); ModConfig config = ConfigFile.config(); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 50c64ae3..c7be2871 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.stream.IntStream; -public class ModConfig { +public final class ModConfig { public static final double MIN_OFFSET_D = -1.0, MAX_OFFSET_D = 1.0; public static final float MIN_OFFSET_F = -1.0f, MAX_OFFSET_F = 1.0f; public boolean enabled = false; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java index b31c9878..340bdd8c 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java @@ -16,7 +16,7 @@ import java.util.List; -public class GUIHelper { +public final class GUIHelper { @Nullable public static ScreenRectangle getBounds(int x0, int y0, int x1, int y1, Matrix3x2f pose, @Nullable ScreenRectangle scissorArea) { ScreenRectangle scissorArea2 = new ScreenRectangle(x0, y0, x1 - x0, y1 - y0).transformMaxBounds(pose); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 8d3b98f7..e4148537 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -24,20 +24,19 @@ import org.joml.Vector3f; import org.jspecify.annotations.Nullable; -import java.awt.*; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Set; -public class ModelAnalyser { +public final class ModelAnalyser { private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final Set UNFOCUSABLE_RENDER_TYPES = Set.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; private static final int z1 = 210, z2 = z1 + 10; public final List focusedPolyhedron = new ArrayList<>(); public final PoseStack modelPose = new PoseStack(), texturePose = new PoseStack(); - protected final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); + final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; private BindTarget target = BindTarget.EMPTY; @@ -55,17 +54,6 @@ private static boolean haveCommonVertex(VertexData[] p1, List prim return false; } - private static Polygon getPolygon(VertexData[] primitive) { - int length = primitive.length; - int[] xs = new int[length], ys = new int[length]; - for (int j = 0; j < length; j++) { - VertexData vertex = primitive[j]; - xs[j] = (int) vertex.x(); - ys[j] = (int) vertex.y(); - } - return new Polygon(xs, ys, length); - } - public void initialize(BindTarget target, int modelScale) { this.target = target; this.modelScale = modelScale; @@ -115,19 +103,12 @@ public void applyDisableConfigs(String textureId, Set hiddenNames) { public void computeFocusedOnTexture(int mouseX, int mouseY) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; - Matrix4f positionMatrix = texturePose.last().pose(); - Vector3f position = new Vector3f(); + Vector3f newMousePosition = new Vector3f(mouseX, mouseY, 0) + .mulPosition(texturePose.last().pose().invert(new Matrix4f())); + float newMouseX = newMousePosition.x(), newMouseY = newMousePosition.y(); for (BuiltModelRecord record : textureRecords) { - int length = record.renderType().mode().primitiveLength; - int[] xs = new int[length], ys = new int[length]; for (VertexData[] primitive : record.primitives()) { - for (int j = 0; j < length; j++) { - VertexData vertex = primitive[j]; - position.set(vertex.u(), vertex.v(), 0).mulPosition(positionMatrix); - xs[j] = (int) position.x(); - ys[j] = (int) position.y(); - } - if (new Polygon(xs, ys, length).contains(mouseX, mouseY)) { + if (VertexData.containsUV(primitive, newMouseX, newMouseY)) { focusedRecord = record; focusedPolyhedron.add(primitive); break; @@ -143,7 +124,7 @@ public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { if (UNFOCUSABLE_RENDER_TYPES.contains(record.renderType())) continue; VertexData[][] primitives = record.primitives(); for (VertexData[] primitive : primitives) { - if (!getPolygon(primitive).contains(mouseX, mouseY)) continue; + if (!VertexData.containsXY(primitive, mouseX, mouseY)) continue; VertexData vertex = primitive[0]; float deltaZ = vertex.normalZ() == 0 ? 0 : (vertex.normalX() * (mouseX - vertex.x()) + vertex.normalY() * (mouseY - vertex.y())) / vertex.normalZ(); sortByZ.add(new Object[]{record, primitive, vertex.z() - deltaZ}); @@ -175,20 +156,18 @@ public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { } if (sortByZ.isEmpty()) return; sortByZ.sort(Comparator.comparingDouble(array -> -(float) array[2])); - List polygons = new ArrayList<>(); focusedRecord = (BuiltModelRecord) sortByZ.getFirst()[0]; while (!sortByZ.isEmpty()) { VertexData[] first = (VertexData[]) sortByZ.getFirst()[1]; focusedPolyhedron.add(first); - polygons.add(getPolygon(first)); sortByZ.removeFirst(); sortByZ.removeIf(array -> { if (array[0] != focusedRecord) return true; VertexData[] primitive = (VertexData[]) array[1]; primitiveFor: for (VertexData vertex : primitive) { - for (Polygon polygon : polygons) - if (polygon.contains(vertex.x(), vertex.y())) continue primitiveFor; + for (VertexData[] focused : focusedPolyhedron) + if (VertexData.containsXY(focused, vertex.x(), vertex.y())) continue primitiveFor; return false; } return true; @@ -307,16 +286,7 @@ public void computeBindResult(BuiltIterableBuffer builtBuffer) { BindResult result = new BindResult(target); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV[] uvs = {new VertexData.UV(config.posU(), config.posV()), new VertexData.UV(config.forwardU(), config.forwardV()), new VertexData.UV(config.upwardU(), config.upwardV())}; - targetPrimitives = builtBuffer.findPrimitivesInCache(uvs); - if (builtBuffer.anyNotCached(uvs)) { - for (int i = 0; i < targetPrimitives.length; i++) { - if (targetPrimitives[i] != null) uvs[i] = null; - } - VertexData[][] newPrimitives = builtBuffer.findPrimitives(uvs); - for (int i = 0; i < targetPrimitives.length; i++) { - if (newPrimitives[i] != null) targetPrimitives[i] = newPrimitives[i]; - } - } + targetPrimitives = builtBuffer.findPrimitives(uvs); if (targetPrimitives[0] != null) result.setPosition(VertexData.position(targetPrimitives[0], config.posU(), config.posV())); if (targetPrimitives[1] != null) result.setForward(VertexData.normal(targetPrimitives[1]).scale(-1)); if (targetPrimitives[2] != null) result.setUpward(VertexData.normal(targetPrimitives[2]).scale(-1)); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index bc58e4dd..7c3f292b 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -50,11 +50,11 @@ import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; -public class ModelViewScreen extends Screen { +public final class ModelViewScreen extends Screen { public final ModelAnalyser analyser = new ModelAnalyser(); - protected int xSize = 450, ySize = 206, middleWidth = xSize - 200, widgetWidth = (xSize - middleWidth) / 4 - 8, widgetHeight = 18; - protected int x, y, page = 0; - protected InputConstants.Key modifierKey = ConfigFile.config().getScreenModifierKey(); + private final int xSize = 450, ySize = 206, middleWidth = xSize - 200, widgetWidth = (xSize - middleWidth) / 4 - 8, widgetHeight = 18; + private int x, y, page = 0; + private InputConstants.Key modifierKey = ConfigFile.config().getScreenModifierKey(); private boolean initialized; private int modelScale = 80, textureScale = 80, layers = 0, selectionRadius = 10; private double modelX, modelY, textureX, textureY, clickedX = -1, clickedY = -1; @@ -460,7 +460,7 @@ public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX applyAnalyser(graphics, mouseX, mouseY); } - protected void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY) { + private void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY) { String textureId = toggleCategoryButton.getValue() == Category.DISABLE ? disabledIdField.getValue() : ""; Set hiddenNames = hiddenNameMap.getOrDefault(nameField.getValue(), Set.of()); analyser.applyDisableConfigs(textureId, hiddenNames); @@ -483,7 +483,7 @@ protected void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mous } } - protected void renderModelViewArea(GuiGraphicsExtractor graphics, LivingEntity entity) { + private void renderModelViewArea(GuiGraphicsExtractor graphics, LivingEntity entity) { int x1 = modelViewArea.left(), y1 = modelViewArea.top(), x2 = modelViewArea.right(), y2 = modelViewArea.bottom(); Quaternionf rotation = new Quaternionf().rotateX((float) Math.PI / 6 + xRot).rotateY((float) Math.PI / 6 + yRot).rotateZ((float) Math.PI); float entityBodyYaw = entity.yBodyRot; @@ -505,7 +505,7 @@ protected void renderModelViewArea(GuiGraphicsExtractor graphics, LivingEntity e entity.yHeadRot = entityHeadYaw; } - protected void renderEntityWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset, Quaternionf rotation, LivingEntity entity) { + private void renderEntityWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset, Quaternionf rotation, LivingEntity entity) { PoseStack modelPose = analyser.modelPose; modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); modelPose.scale(scale, scale, -scale); @@ -521,21 +521,21 @@ protected void renderEntityWithAnalyser(GuiGraphicsExtractor graphics, int x1, i GUIHelper.culledModels(graphics, analyser.modelRecords, scale, transform, x1, y1, x2, y2); } - protected void renderTextureViewArea(GuiGraphicsExtractor graphics) { + private void renderTextureViewArea(GuiGraphicsExtractor graphics) { if (textureViewArea == null) return; int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); renderTextureWithAnalyser(graphics, x1, y1, x2, y2, (float) (textureScale * textureViewArea.width()) / 80, offset); } - protected void renderTextureWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset) { + private void renderTextureWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset) { analyser.texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); analyser.texturePose.scale(scale, scale, -scale); analyser.texturePose.translate(offset.x(), offset.y(), offset.z()); GUIHelper.flattenedModels(graphics, analyser.textureRecords, offset, x1, y1, x2, y2, scale); } - protected void importBindTarget(Button button) { + private void importBindTarget(Button button) { FriendlyByteBuf byteBuf = null; try { String base64 = minecraft.keyboardHandler.getClipboard(); @@ -562,7 +562,7 @@ protected void importBindTarget(Button button) { } } - protected void exportBindTarget(Button button) { + private void exportBindTarget(Button button) { FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); try { genBindTarget().write(byteBuf); @@ -583,7 +583,7 @@ protected void exportBindTarget(Button button) { } } - protected void loadBindTarget(BindTarget target) { + private void loadBindTarget(BindTarget target) { if (target.isEmpty()) return; nameField.setValue(target.name()); textureIdField.setValue(target.textureId()); @@ -616,7 +616,7 @@ protected void loadBindTarget(BindTarget target) { disableConfigs.addAll(List.of(target.disableConfigs())); } - protected BindTarget genBindTarget() { + private BindTarget genBindTarget() { TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); OffsetConfig offsets = new OffsetConfig() @@ -636,42 +636,42 @@ protected BindTarget genBindTarget() { return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, disableConfigArray); } - protected Tooltip createTooltip(String key, Object... args) { + private Tooltip createTooltip(String key, Object... args) { return Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP(key, args)); } - protected UVRectangleWidget createRectWidget(UVRectangle rect) { + private UVRectangleWidget createRectWidget(UVRectangle rect) { return new UVRectangleWidget(rect.uMin(), rect.vMin(), rect.uMax(), rect.vMax()); } - protected Button createButton(Component message, int width, Button.OnPress onPress) { + private Button createButton(Component message, int width, Button.OnPress onPress) { return Button.builder(message, onPress).size(width, widgetHeight).build(); } - protected CycleButton.Builder createCyclingButtonBuilder(Map messages, T defaultValue) { + private CycleButton.Builder createCyclingButtonBuilder(Map messages, T defaultValue) { return new CycleButton.Builder<>(messages::get, () -> defaultValue).withValues(messages.keySet()); } - protected DoubleSlider createSlider(String key, int width, double min, double max) { + private DoubleSlider createSlider(String key, int width, double min, double max) { return new DoubleSlider(width, widgetHeight, 0, min, max, d -> LocUtil.MODEL_VIEW_WIDGET(key, MathUtil.round(d, 2))); } - protected NumberField createFloatField(int width, float defaultValue, @Nullable NumberField copyFrom) { + private NumberField createFloatField(int width, float defaultValue, @Nullable NumberField copyFrom) { return NumberField.ofFloat(font, width - 2, widgetHeight - 2, defaultValue, copyFrom).setMax(1.0f).setMin(0f); } - protected EditBox createTextField(int width, int maxLength, @Nullable EditBox copyFrom) { + private EditBox createTextField(int width, int maxLength, @Nullable EditBox copyFrom) { EditBox editBox = new EditBox(font, 0, 0, width - 2, widgetHeight - 2, CommonComponents.EMPTY); editBox.setMaxLength(maxLength); if (copyFrom != null) editBox.setValue(copyFrom.getValue()); return editBox; } - protected boolean inModelViewArea(double x, double y) { + private boolean inModelViewArea(double x, double y) { return modelViewArea.containsPoint((int) x, (int) y); } - protected boolean inTextureViewArea(double x, double y) { + private boolean inTextureViewArea(double x, double y) { return textureViewArea != null && textureViewArea.containsPoint((int) x, (int) y); } @@ -836,8 +836,8 @@ public Category next() { } } - public class UVRectangleWidget extends AbstractWidget { - protected float uMin, vMin, uMax, vMax; + public final class UVRectangleWidget extends AbstractWidget { + private float uMin, vMin, uMax, vMax; public UVRectangleWidget(float uMin, float vMin, float uMax, float vMax) { super(0, 0, 16, 16, CommonComponents.EMPTY); diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index c684a565..2ab31848 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -7,7 +7,6 @@ import net.minecraft.client.renderer.rendertype.RenderType; import org.jspecify.annotations.Nullable; -import java.awt.*; import java.util.Map; public record BuiltIterableBuffer(RenderType renderType, String textureId, IterableVertexBuffer vertexBuffer) { @@ -58,22 +57,15 @@ public boolean anyNotCached(UV[] uvs) { } public VertexData[] @Nullable [] findPrimitives(UV[] uvs) { - final int resolution = 1000000; int length = renderType.mode().primitiveLength, uvsLength = uvs.length; - int[] us = new int[length], vs = new int[length]; VertexData[][] primitives = new VertexData[uvsLength][]; vertexBuffer.primitiveStream().anyMatch(primitive -> { - for (int i = 0; i < length; i++) { - us[i] = (int) (resolution * primitive[i].u()); - vs[i] = (int) (resolution * primitive[i].v()); - } - Polygon polygon = new Polygon(us, vs, length); boolean allFound = true; for (int i = 0; i < uvsLength; i++) { if (primitives[i] != null) continue; UV uv = uvs[i]; if (uv == null) continue; - if (!polygon.contains(resolution * uv.u(), resolution * uv.v())) { + if (!VertexData.containsUV(primitive, uv.u(), uv.v())) { allFound = false; continue; } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index d080fa59..f2270c8d 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -18,7 +18,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -public class IterableVertexBuffer implements Iterable { +public final class IterableVertexBuffer implements Iterable { private static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; private static final float NORMAL_SCALE = 1.0f / 127.0f; public final int vertexCount, vertexSize; @@ -238,7 +238,7 @@ public VertexData asImmutable() { } } - private class VertexIterator extends VertexPointer implements Iterator { + private final class VertexIterator extends VertexPointer implements Iterator { private final int byteCount = vertexCount * vertexSize; @Override @@ -253,7 +253,7 @@ public boolean hasNext() { } } - private class VertexSpliterator extends VertexPointer implements Spliterator { + private final class VertexSpliterator extends VertexPointer implements Spliterator { private final int endIndex; private int currentIndex; @@ -296,7 +296,7 @@ public int characteristics() { } } - private class PrimitiveReader implements Iterable { + private final class PrimitiveReader implements Iterable { private final int primitiveLength, primitiveStride, primitiveCount; private final boolean startWithFirst; @@ -348,7 +348,7 @@ public VertexData[] next() { } } - private class PrimitiveSpliterator implements Spliterator { + private final class PrimitiveSpliterator implements Spliterator { private final MutableVertex[] reusablePrimitive = new MutableVertex[primitiveLength]; private final int endIndex; private int currentIndex; @@ -398,7 +398,7 @@ public int characteristics() { } - private class FastQuadReader implements Iterable { + private final class FastQuadReader implements Iterable { private final int quadCount = vertexCount / 4; @Override @@ -452,7 +452,7 @@ public VertexData[] next() { } } - private class FastQuadSpliterator implements Spliterator { + private final class FastQuadSpliterator implements Spliterator { private final MutableVertex[] reusableQuad = new MutableVertex[4]; private final int endIndex; private int currentIndex; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java index 43ff4b47..b1a778ef 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java @@ -21,7 +21,7 @@ import java.util.SequencedMap; import java.util.function.Consumer; -public class MultiVertexCatcher { +public final class MultiVertexCatcher { private final SubmitNodeStorage storage = new SubmitNodeStorage(); private final MeshCatcher meshCatcher = new MeshCatcher(); @@ -108,11 +108,11 @@ public void endCatching(Consumer consumer) { meshCatcher.endCatching(consumer); } - static class MeshCatcher extends MultiBufferSource.BufferSource { + static final class MeshCatcher extends MultiBufferSource.BufferSource { private final SequencedMap bufferPools = new Object2ObjectLinkedOpenHashMap<>(); private final SequencedMap caughtMeshes = new Object2ObjectLinkedOpenHashMap<>(); - protected MeshCatcher() { + private MeshCatcher() { super(new ByteBufferBuilder(0), Object2ObjectSortedMaps.emptyMap()); } @@ -167,7 +167,7 @@ protected void endBatch(@NonNull RenderType renderType, BufferBuilder bufferBuil } } - private static class ByteBufferBuilderPool { + private static final class ByteBufferBuilderPool { private final int bufferSize; private ByteBufferBuilder[] pool = new ByteBufferBuilder[0]; private int next = 0; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java b/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java index fcd8c0cf..eac3cbaf 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/RoutingSubmitCollector.java @@ -26,7 +26,7 @@ import java.util.List; -public class RoutingSubmitCollector implements SubmitNodeCollector { +public final class RoutingSubmitCollector implements SubmitNodeCollector { private final SubmitNodeCollector defaultCollector; private final SubmitNodeCollector modelCollector; @@ -105,7 +105,7 @@ public void submitParticleGroup(@NonNull ParticleGroupRenderer particleGroupRend defaultCollector.submitParticleGroup(particleGroupRenderer); } - private class RoutingOrderedCollector implements OrderedSubmitNodeCollector { + private final class RoutingOrderedCollector implements OrderedSubmitNodeCollector { private final OrderedSubmitNodeCollector defaultDelegate; private final OrderedSubmitNodeCollector modelDelegate; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java index 25c39b35..7ef9788e 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java @@ -11,7 +11,7 @@ import org.joml.Matrix4f; import org.jspecify.annotations.NonNull; -public class GuiCulledModelsRenderer extends PictureInPictureRenderer { +public final class GuiCulledModelsRenderer extends PictureInPictureRenderer { public GuiCulledModelsRenderer(MultiBufferSource.BufferSource bufferSource) { super(bufferSource); } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java index 2513538e..0c95b6c0 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java @@ -11,7 +11,7 @@ import org.joml.Vector3f; import org.jspecify.annotations.NonNull; -public class GuiFlattenedModelsRenderer extends PictureInPictureRenderer { +public final class GuiFlattenedModelsRenderer extends PictureInPictureRenderer { public GuiFlattenedModelsRenderer(MultiBufferSource.BufferSource bufferSource) { super(bufferSource); } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java index 63e97959..18730375 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java @@ -1,6 +1,7 @@ package com.xtracr.realcamera.renderer.state; import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.util.MathUtil; import net.minecraft.world.phys.Vec3; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -41,6 +42,36 @@ static Vec3 normal(VertexData[] vertices) { }; } + static boolean containsUV(VertexData[] vertices, float u, float v) { + return switch (vertices.length) { + case 3 -> MathUtil.pointInTriangle(u, v, + vertices[0].u(), vertices[0].v(), + vertices[1].u(), vertices[1].v(), + vertices[2].u(), vertices[2].v()); + case 4 -> MathUtil.pointInQuad(u, v, + vertices[0].u(), vertices[0].v(), + vertices[1].u(), vertices[1].v(), + vertices[2].u(), vertices[2].v(), + vertices[3].u(), vertices[3].v()); + default -> false; + }; + } + + static boolean containsXY(VertexData[] vertices, float x, float y) { + return switch (vertices.length) { + case 3 -> MathUtil.pointInTriangle(x, y, + vertices[0].x(), vertices[0].y(), + vertices[1].x(), vertices[1].y(), + vertices[2].x(), vertices[2].y()); + case 4 -> MathUtil.pointInQuad(x, y, + vertices[0].x(), vertices[0].y(), + vertices[1].x(), vertices[1].y(), + vertices[2].x(), vertices[2].y(), + vertices[3].x(), vertices[3].y()); + default -> false; + }; + } + float x(); float y(); @@ -105,7 +136,7 @@ public int hashCode() { record ImmutableVertex(float x, float y, float z, int argb, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) implements VertexData { } - class MutableVertex implements VertexData { + final class MutableVertex implements VertexData { public float x, y, z; public int argb; public float u, v; diff --git a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java index 315bc540..9b75ffdb 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -5,6 +5,8 @@ import org.joml.Matrix4fc; import org.joml.Vector4f; +import java.awt.*; + public final class MathUtil { public static double round(double d, int digits) { return Math.round(d * Math.pow(10, digits)) / Math.pow(10, digits); @@ -26,6 +28,30 @@ public static double ceil(double... ds) { return Math.ceil(d); } + public static float cross(float a, float b, float c, float d) { + return a * d - b * c; + } + + public static boolean pointInTriangle(float x, float y, float x0, float y0, float x1, float y1, float x2, float y2) { + float abX = x1 - x0, abY = y1 - y0; + float acX = x2 - x0, acY = y2 - y0; + float alpha = cross(abX, abY, acX, acY); + if (alpha == 0) return false; + float apX = x - x0, apY = y - y0; + float beta = cross(apX, apY, acX, acY) / alpha; + if (beta < 0) return false; + float gamma = cross(abX, abY, apX, apY) / alpha; + if (gamma < 0) return false; + return beta + gamma <= 1; + } + + public static boolean pointInQuad(float x, float y, + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3) { + return pointInTriangle(x, y, x0, y0, x1, y1, x2, y2) + || pointInTriangle(x, y, x1, y1, x2, y2, x3, y3); + } + public static Vec3 getEulerAngleYXZ(Matrix3f normal) { if (normal.m21 <= -1.0) return new Vec3(Math.PI / 2, Math.atan2(normal.m10, normal.m00), 0.0); else if (normal.m21 >= 1.0) return new Vec3(-Math.PI / 2, -Math.atan2(normal.m10, normal.m00), 0.0); diff --git a/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java b/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java index 1b621dde..c1c9129f 100644 --- a/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java +++ b/fabric/src/main/java/com/xtracr/realcamera/RealCameraFabric.java @@ -12,7 +12,7 @@ import net.minecraft.client.KeyMapping; @Environment(EnvType.CLIENT) -public class RealCameraFabric implements ClientModInitializer, RealCamera { +public final class RealCameraFabric implements ClientModInitializer, RealCamera { @Override public void onInitializeClient() { initialize(); diff --git a/fabric/src/main/java/com/xtracr/realcamera/config/RealCameraMenu.java b/fabric/src/main/java/com/xtracr/realcamera/config/RealCameraMenu.java index 21c93225..9ebcb673 100644 --- a/fabric/src/main/java/com/xtracr/realcamera/config/RealCameraMenu.java +++ b/fabric/src/main/java/com/xtracr/realcamera/config/RealCameraMenu.java @@ -3,7 +3,7 @@ import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; -public class RealCameraMenu implements ModMenuApi { +public final class RealCameraMenu implements ModMenuApi { @Override public ConfigScreenFactory getModConfigScreenFactory() { return ConfigScreen::create; diff --git a/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java b/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java index c6aecff5..02f737d6 100644 --- a/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java +++ b/neoforge/src/main/java/com/xtracr/realcamera/EventHandler.java @@ -4,7 +4,7 @@ import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.common.NeoForge; -public class EventHandler { +public final class EventHandler { public static void addListeners() { NeoForge.EVENT_BUS.addListener(EventHandler::onClientTick); } diff --git a/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java b/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java index 4348ff19..0b9c01cf 100644 --- a/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java +++ b/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java @@ -18,7 +18,7 @@ import java.util.Map; @Mod(value = RealCamera.MODID, dist = Dist.CLIENT) -public class RealCameraNeoForge implements RealCamera { +public final class RealCameraNeoForge implements RealCamera { private final ModContainer modContainer; private final Map modIdMap = Map.of("cloth-config", "cloth_config"); From 0864ef159cee85317e84a08eb7bdb5270067141d Mon Sep 17 00:00:00 2001 From: xTracr Date: Tue, 12 May 2026 23:56:04 +0800 Subject: [PATCH 14/33] Store primitive index instead of UV array in cache; simplify vertex reading Replaces the UV coordinate float array cache with primitive index caching, enabling direct primitive lookup via IterableVertexBuffer.readPrimitiveAt. Removes the VertexPointer inner class and byte-pointer traversal in favor of index-based readVertexAt calls, centralizing vertex decoding. --- .../renderer/BuiltIterableBuffer.java | 46 ++--- .../renderer/IterableVertexBuffer.java | 171 ++++-------------- .../realcamera/util/RenderTypeUtil.java | 12 +- 3 files changed, 51 insertions(+), 178 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index 2ab31848..c6b2586f 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -15,7 +15,7 @@ public static BuiltIterableBuffer buildFrom(RenderType renderType, MeshData mesh } public boolean anyNotCached(UV[] uvs) { - Map cache = RenderTypeUtil.getPrimitiveCache(renderType); + Map cache = RenderTypeUtil.getPrimitiveCache(renderType); if (cache == null) return true; for (UV uv : uvs) { if (!cache.containsKey(uv)) return true; @@ -24,42 +24,27 @@ public boolean anyNotCached(UV[] uvs) { } public VertexData[] @Nullable [] findPrimitivesInCache(UV[] uvs) { - Map cache = RenderTypeUtil.getPrimitiveCache(renderType); - int length = renderType.mode().primitiveLength, uvsLength = uvs.length; + Map cache = RenderTypeUtil.getPrimitiveCache(renderType); + int uvsLength = uvs.length; VertexData[][] primitives = new VertexData[uvsLength][]; if (cache == null) return primitives; - float[][] uvCacheArray = new float[uvsLength][]; - boolean allNull = true; for (int i = 0; i < uvsLength; i++) { - uvCacheArray[i] = cache.get(uvs[i]); - if (uvCacheArray[i] != null) allNull = false; + if (uvs[i] == null) continue; + Integer primitiveIndex = cache.get(uvs[i]); + if (primitiveIndex == null) continue; + VertexData[] primitive = vertexBuffer.readPrimitiveAt(primitiveIndex); + if (!VertexData.containsUV(primitive, uvs[i].u(), uvs[i].v())) continue; + primitives[i] = primitive; } - if (allNull) return primitives; - vertexBuffer.primitiveStream().anyMatch(primitive -> { - float[] uvCache; - boolean allFound = true; - cacheFor: - for (int i = 0; i < uvsLength; i++) { - if (primitives[i] != null) continue; - uvCache = uvCacheArray[i]; - if (uvCache == null) continue; - for (int j = 0; j < length; j++) { - if (uvCache[j * 2] != primitive[j].u() || uvCache[j * 2 + 1] != primitive[j].v()) { - allFound = false; - continue cacheFor; - } - } - primitives[i] = VertexData.asImmutable(primitive); - } - return allFound; - }); return primitives; } public VertexData[] @Nullable [] findPrimitives(UV[] uvs) { - int length = renderType.mode().primitiveLength, uvsLength = uvs.length; + int uvsLength = uvs.length; VertexData[][] primitives = new VertexData[uvsLength][]; + int[] counter = new int[1]; vertexBuffer.primitiveStream().anyMatch(primitive -> { + int idx = counter[0]++; boolean allFound = true; for (int i = 0; i < uvsLength; i++) { if (primitives[i] != null) continue; @@ -69,12 +54,7 @@ public boolean anyNotCached(UV[] uvs) { allFound = false; continue; } - float[] uvCache = new float[length * 2]; - for (int j = 0; j < length; j++) { - uvCache[j * 2] = primitive[j].u(); - uvCache[j * 2 + 1] = primitive[j].v(); - } - RenderTypeUtil.cachePrimitive(renderType, uv, uvCache); + RenderTypeUtil.cachePrimitive(renderType, uv, idx); primitives[i] = VertexData.asImmutable(primitive); } return allFound; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index f2270c8d..ddcfa043 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -6,7 +6,6 @@ import com.mojang.blaze3d.vertex.VertexFormatElement; import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.renderer.state.VertexData.MutableVertex; -import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.NonNull; import java.nio.ByteBuffer; @@ -21,18 +20,17 @@ public final class IterableVertexBuffer implements Iterable { private static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; private static final float NORMAL_SCALE = 1.0f / 127.0f; - public final int vertexCount, vertexSize; - private final MutableVertex reusableVertex = VertexData.mutable(); + public final int vertexSize, vertexCount, primitiveLength, primitiveStride, primitiveCount; private final Iterable primitives; private final ByteBuffer buffer; private final int positionOffset, colorOffset, uvOffset, overlayOffset, lightOffset, normalOffset; private final boolean hasPosition, hasColor, hasUV, hasOverlay, hasLight, hasNormal, fullFormat; + private final boolean startWithFirst; public IterableVertexBuffer(MeshData meshData) { buffer = meshData.vertexBuffer(); MeshData.DrawState drawState = meshData.drawState(); VertexFormat format = drawState.format(); - vertexCount = drawState.vertexCount(); vertexSize = format.getVertexSize(); positionOffset = format.getOffset(VertexFormatElement.POSITION); colorOffset = format.getOffset(VertexFormatElement.COLOR); @@ -47,8 +45,14 @@ public IterableVertexBuffer(MeshData meshData) { hasLight = lightOffset != -1; hasNormal = normalOffset != -1; fullFormat = vertexSize == DefaultVertexFormat.ENTITY.getVertexSize(); - boolean isQuad = drawState.mode() == VertexFormat.Mode.QUADS; - primitives = fullFormat && isQuad ? new FastQuadReader() : new PrimitiveReader(drawState.mode()); + vertexCount = drawState.vertexCount(); + VertexFormat.Mode drawMode = drawState.mode(); + primitiveLength = drawMode.primitiveLength; + primitiveStride = drawMode.primitiveStride; + primitiveCount = (vertexCount - primitiveLength) / primitiveStride + 1; + startWithFirst = drawMode == VertexFormat.Mode.TRIANGLE_FAN; + boolean isQuad = drawMode == VertexFormat.Mode.QUADS; + primitives = fullFormat && isQuad ? new FastQuadReader() : new PrimitiveReader(); } public Iterable primitives() { @@ -65,7 +69,14 @@ public Stream primitiveStream() { public VertexData readVertexAt(int index) { Objects.checkIndex(index, vertexCount); - return readVertexAt(index, reusableVertex); + return readVertexAt(index, VertexData.mutable()); + } + + public VertexData[] readPrimitiveAt(int primitiveIndex) { + Objects.checkIndex(primitiveIndex, primitiveCount); + MutableVertex[] mutableVertices = new MutableVertex[primitiveLength]; + for (int i = 0; i < primitiveLength; i++) mutableVertices[i] = VertexData.mutable(); + return readPrimitiveAt(primitiveIndex, mutableVertices); } @Override @@ -129,131 +140,31 @@ private MutableVertex readVertexAt(int index, MutableVertex mutable) { return mutable; } - private class VertexPointer implements VertexData { - protected int bytePointer = 0; - - @Override - public float x() { - if (hasPosition) return buffer.getFloat(bytePointer + positionOffset); - return 0; - } - - @Override - public float y() { - if (hasPosition) return buffer.getFloat(bytePointer + positionOffset + 4); - return 0; - } - - @Override - public float z() { - if (hasPosition) return buffer.getFloat(bytePointer + positionOffset + 8); - return 0; - } - - @Override - public Vec3 position() { - if (hasPosition) - return new Vec3(buffer.getFloat(bytePointer + positionOffset), buffer.getFloat(bytePointer + positionOffset + 4), buffer.getFloat(bytePointer + positionOffset + 8)); - return Vec3.ZERO; - } - - @Override - public int argb() { - if (hasColor) return readColor(bytePointer + colorOffset); - return 0; - } - - @Override - public float u() { - if (hasUV) return buffer.getFloat(bytePointer + uvOffset); - return 0; - } - - @Override - public float v() { - if (hasUV) return buffer.getFloat(bytePointer + uvOffset + 4); - return 0; - } - - @Override - public UV uv() { - if (hasUV) - return new UV(buffer.getFloat(bytePointer + uvOffset), buffer.getFloat(bytePointer + uvOffset + 4)); - return new UV(0, 0); - } - - @Override - public int overlay() { - if (hasOverlay) return buffer.getInt(bytePointer + overlayOffset); - return 0; - } - - @Override - public int light() { - if (hasLight) return buffer.getInt(bytePointer + lightOffset); - return 0; - } - - @Override - public float normalX() { - if (hasNormal) return buffer.get(bytePointer + normalOffset) * NORMAL_SCALE; - return 0; - } - - @Override - public float normalY() { - if (hasNormal) return buffer.get(bytePointer + normalOffset + 1) * NORMAL_SCALE; - return 0; - } - - @Override - public float normalZ() { - if (hasNormal) return buffer.get(bytePointer + normalOffset + 2) * NORMAL_SCALE; - return 0; - } - - @Override - public Vec3 normal() { - if (hasNormal) - return new Vec3(buffer.get(bytePointer + normalOffset) * NORMAL_SCALE, buffer.get(bytePointer + normalOffset + 1) * NORMAL_SCALE, buffer.get(bytePointer + normalOffset + 2) * NORMAL_SCALE); - return Vec3.ZERO; - } - - @Override - public VertexData asImmutable() { - if (fullFormat) { - return new ImmutableVertex(buffer.getFloat(bytePointer), - buffer.getFloat(bytePointer + 4), - buffer.getFloat(bytePointer + 8), - readColor(bytePointer + 12), - buffer.getFloat(bytePointer + 16), - buffer.getFloat(bytePointer + 20), - buffer.getInt(bytePointer + 24), - buffer.getInt(bytePointer + 28), - buffer.get(bytePointer + 32) * NORMAL_SCALE, - buffer.get(bytePointer + 33) * NORMAL_SCALE, - buffer.get(bytePointer + 34) * NORMAL_SCALE); - } - return VertexData.super.asImmutable(); + private MutableVertex[] readPrimitiveAt(int index, MutableVertex[] mutableVertices) { + int vertexIndex = index * primitiveStride; + for (int i = startWithFirst ? 1 : 0; i < primitiveLength; i++) { + readVertexAt(vertexIndex + i, mutableVertices[i]); } + return mutableVertices; } - private final class VertexIterator extends VertexPointer implements Iterator { - private final int byteCount = vertexCount * vertexSize; + private final class VertexIterator implements Iterator { + private final MutableVertex reusableVertex = VertexData.mutable(); + private int currentIndex = 0; @Override public boolean hasNext() { - return bytePointer < byteCount - vertexSize; + return currentIndex < vertexCount; } @Override public @NonNull VertexData next() { - bytePointer += vertexSize; - return this; + return readVertexAt(currentIndex++, reusableVertex); } } - private final class VertexSpliterator extends VertexPointer implements Spliterator { + private final class VertexSpliterator implements Spliterator { + private final MutableVertex reusableVertex = VertexData.mutable(); private final int endIndex; private int currentIndex; @@ -265,8 +176,7 @@ public VertexSpliterator(int start, int end) { @Override public boolean tryAdvance(Consumer action) { if (currentIndex < endIndex) { - bytePointer = currentIndex * vertexSize; - action.accept(this); + action.accept(readVertexAt(currentIndex, reusableVertex)); currentIndex++; return true; } @@ -297,16 +207,6 @@ public int characteristics() { } private final class PrimitiveReader implements Iterable { - private final int primitiveLength, primitiveStride, primitiveCount; - private final boolean startWithFirst; - - public PrimitiveReader(VertexFormat.Mode drawMode) { - primitiveLength = drawMode.primitiveLength; - primitiveStride = drawMode.primitiveStride; - primitiveCount = (vertexCount - primitiveLength) / primitiveStride + 1; - startWithFirst = drawMode == VertexFormat.Mode.TRIANGLE_FAN; - } - @Override public @NonNull Iterator iterator() { return new PrimitiveIterator(); @@ -317,14 +217,7 @@ public Spliterator spliterator() { return new PrimitiveSpliterator(0, primitiveCount); } - private void readPrimitiveAt(int index, MutableVertex[] primitive) { - int vertexIndex = index * primitiveStride; - for (int i = startWithFirst ? 1 : 0; i < primitiveLength; i++) { - readVertexAt(vertexIndex + i, primitive[i]); - } - } - - private class PrimitiveIterator implements Iterator { + private final class PrimitiveIterator implements Iterator { private final MutableVertex[] reusablePrimitive = new MutableVertex[primitiveLength]; private int currentIndex = 0; diff --git a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java index fa8df2b7..8f5f9e9a 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java @@ -23,7 +23,7 @@ public final class RenderTypeUtil { .maximumSize(64) .expireAfterAccess(60, TimeUnit.SECONDS) .build(new TextureIdCacheLoader()); - private static final LoadingCache> PRIMITIVE_CACHE = CacheBuilder.newBuilder() + private static final LoadingCache> PRIMITIVE_CACHE = CacheBuilder.newBuilder() .maximumSize(64) .expireAfterAccess(60, TimeUnit.SECONDS) .build(new PrimitiveCacheLoader()); @@ -43,12 +43,12 @@ public static String getTextureId(RenderType renderType) { return TEXTURE_ID_CACHE.getUnchecked(renderType); } - public static @Nullable Map getPrimitiveCache(RenderType renderType) { + public static @Nullable Map getPrimitiveCache(RenderType renderType) { return PRIMITIVE_CACHE.getIfPresent(renderType); } - public static void cachePrimitive(RenderType renderType, UV uv, float[] uvCoords) { - PRIMITIVE_CACHE.getUnchecked(renderType).put(uv, uvCoords); + public static void cachePrimitive(RenderType renderType, UV uv, int primitiveIndex) { + PRIMITIVE_CACHE.getUnchecked(renderType).put(uv, primitiveIndex); } private static class TextureIdCacheLoader extends CacheLoader { @@ -67,9 +67,9 @@ private static class TextureIdCacheLoader extends CacheLoader> { + private static class PrimitiveCacheLoader extends CacheLoader> { @Override - public @NonNull Map load(@NonNull RenderType renderType) { + public @NonNull Map load(@NonNull RenderType renderType) { return new HashMap<>(4); } } From 0ed3c653eac11414cceded7bd2bd9588e54d0412 Mon Sep 17 00:00:00 2001 From: xTracr Date: Wed, 13 May 2026 13:40:09 +0800 Subject: [PATCH 15/33] Rename RenderTypeUtil to RenderTypeCache; refactor vertex catching and GUI state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename RenderTypeUtil → RenderTypeCache, use Object2IntMap for primitive cache - Rename MultiVertexCatcher.endCatching → forEachBuffer, separating batch finalization - Remove stored pose state from ModelAnalyser, pass as parameter instead - Tighten access modifiers, use var for map entries, clean up formatting - Bump version to 0.7.8-beta --- .../com/xtracr/realcamera/RealCameraCore.java | 16 ++--- .../realcamera/compat/DisableHelper.java | 2 +- .../xtracr/realcamera/compat/YSMCompat.java | 50 ++++++++-------- .../xtracr/realcamera/gui/ModelAnalyser.java | 20 +++---- .../realcamera/gui/ModelViewScreen.java | 59 ++++++++++--------- .../gui/components/NumberField.java | 21 +++---- .../renderer/BuiltIterableBuffer.java | 24 +++----- .../renderer/MultiVertexCatcher.java | 41 +++++++------ .../renderer/gui/GuiCulledModelsRenderer.java | 2 +- .../gui/GuiFlattenedModelsRenderer.java | 2 +- .../realcamera/renderer/state/VertexData.java | 10 +++- .../com/xtracr/realcamera/util/MathUtil.java | 9 +-- ...nderTypeUtil.java => RenderTypeCache.java} | 17 +++--- gradle.properties | 2 +- 14 files changed, 136 insertions(+), 139 deletions(-) rename common/src/main/java/com/xtracr/realcamera/util/{RenderTypeUtil.java => RenderTypeCache.java} (81%) diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index e83ad6e1..e7ea9f67 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -75,7 +75,7 @@ public static void computeCamera(Minecraft client, float partialTicks) { if (!newResult.available()) { EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, new PoseStack(), vertexCatcher.initCollector()); - vertexCatcher.endCatching(RealCameraCore::computeBindResult); + vertexCatcher.forEachBuffer(RealCameraCore::computeBindResult); } entity.setInvisible(invisible); if (newResult.available()) { @@ -116,7 +116,7 @@ public static void renderCameraEntity(Minecraft client, float partialTicks, Subm dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, collector); final float m02 = modelView.m02(), m12 = modelView.m12(), m22 = modelView.m22(), m32 = modelView.m32(); final float depth = currentTarget().disablingDepth(); - vertexCatcher.endCatching(builtBuffer -> { + vertexCatcher.forEachBuffer(builtBuffer -> { DisableConfig[] disableConfigs = currentTarget().filteredDisableConfigs(config -> builtBuffer.textureId().contains(config.textureId())); for (DisableConfig config : disableConfigs) if (config.disableAll()) return; submitNodeCollector.submitCustomGeometry(poseStack, builtBuffer.renderType(), (_, buffer) -> { @@ -147,10 +147,12 @@ private static void computeBindResult(BuiltIterableBuffer builtBuffer) { BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV[] uvs = {new VertexData.UV(config.posU(), config.posV()), new VertexData.UV(config.forwardU(), config.forwardV()), new VertexData.UV(config.upwardU(), config.upwardV())}; VertexData[][] primitives = builtBuffer.findPrimitivesInCache(uvs); - if (builtBuffer.anyNotCached(uvs)) { - for (int i = 0; i < primitives.length; i++) { - if (primitives[i] != null) uvs[i] = null; - } + boolean allFound = true; + for (int i = 0; i < primitives.length; i++) { + if (primitives[i] != null) uvs[i] = null; + else allFound = false; + } + if (!allFound) { VertexData[][] newPrimitives = builtBuffer.findPrimitives(uvs); for (int i = 0; i < primitives.length; i++) { if (newPrimitives[i] == null && primitives[i] == null) continue targetFor; @@ -165,4 +167,4 @@ private static void computeBindResult(BuiltIterableBuffer builtBuffer) { return; } } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 172c77f7..0be9eb8f 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -20,7 +20,7 @@ public final class DisableHelper { private static final Pattern MULTI_STAR = Pattern.compile("\\*+"); private static final Predicate FALSE = _ -> false; private static final Map entries = new HashMap<>(); - public static int exitTick = 0; + private static int exitTick = 0; static { MAIN_FEATURE = new Entry("mainFeature", player -> player.isSleeping() || player.isSpectator()); diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index 6f7c36f1..1b1223b7 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -10,8 +10,8 @@ import com.xtracr.realcamera.renderer.state.VertexData; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.entity.state.EntityRenderState; import net.minecraft.client.renderer.state.level.CameraRenderState; -import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -20,11 +20,9 @@ import java.util.Map; public final class YSMCompat { - private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final Map resultMap = new HashMap<>(); private static final TransformedVertexRecorder[] transformedRecorders = new TransformedVertexRecorder[4]; private static BindResult bindResult = BindResult.EMPTY; - private static boolean allCached = false; static { final float pitch = 1.9106332f, yaw = 2.0943951f; @@ -41,33 +39,28 @@ public static void register() { private static BindResult computeBindResult(Minecraft client, float partialTicks) { resultMap.clear(); bindResult = BindResult.EMPTY; - allCached = true; - Entity entity = client.getCameraEntity(); EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); + EntityRenderState renderState = dispatcher.extractEntity(client.getCameraEntity(), partialTicks); PoseStack poseStack = new PoseStack(); - for (TransformedVertexRecorder transformedRecorder : transformedRecorders) { + for (TransformedVertexRecorder recorder : transformedRecorders) { poseStack.pushPose(); - poseStack.mulPose(transformedRecorder.matrix4f.invert(new Matrix4f())); - dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); - vertexCatcher.endCatching(transformedRecorder::computeBindResultInCache); + poseStack.mulPose(recorder.matrix4f.invert(new Matrix4f())); + dispatcher.submit(renderState, new CameraRenderState(), 0, 0, 0, poseStack, recorder.vertexCatcher.initCollector()); + recorder.vertexCatcher.forEachBuffer(recorder::computeBindResultInCache); poseStack.popPose(); if (bindResult.available()) return bindResult; } - if (allCached) return BindResult.EMPTY; - for (TransformedVertexRecorder transformedRecorder : transformedRecorders) { - poseStack.pushPose(); - poseStack.mulPose(transformedRecorder.matrix4f.invert(new Matrix4f())); - dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); - vertexCatcher.endCatching(transformedRecorder::computeBindResult); - poseStack.popPose(); + for (TransformedVertexRecorder recorder : transformedRecorders) { + recorder.vertexCatcher.forEachBuffer(recorder::computeBindResult); if (bindResult.available()) return bindResult; } return BindResult.EMPTY; } - protected static class TransformedVertexRecorder { - protected final Matrix4f matrix4f = new Matrix4f(); - protected final Matrix3f matrix3f = new Matrix3f(); + private static final class TransformedVertexRecorder { + private final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); + private final Matrix4f matrix4f = new Matrix4f(); + private final Matrix3f matrix3f = new Matrix3f(); public TransformedVertexRecorder setRotation(float pitch, float yaw) { matrix4f.rotationYXZ(yaw, pitch, 0).invert(); @@ -83,14 +76,16 @@ public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { VertexData.UV posUV = new VertexData.UV(config.posU(), config.posV()); VertexData.UV forwardUV = new VertexData.UV(config.forwardU(), config.forwardV()); VertexData.UV upwardUV = new VertexData.UV(config.upwardU(), config.upwardV()); - if (builtBuffer.anyNotCached(new VertexData.UV[]{posUV, forwardUV, upwardUV})) allCached = false; if (result.getPosition() != Vec3.ZERO) posUV = null; if (result.getForward() != Vec3.ZERO) forwardUV = null; if (result.getUpward() != Vec3.ZERO) upwardUV = null; VertexData[][] primitives = builtBuffer.findPrimitivesInCache(new VertexData.UV[]{posUV, forwardUV, upwardUV}); - if (primitives[0] != null) result.setPosition(new Vec3(VertexData.position(primitives[0], config.posU(), config.posV()).toVector3f().mulPosition(matrix4f))); - if (primitives[1] != null) result.setForward(new Vec3(VertexData.normal(primitives[1]).toVector3f().mul(matrix3f))); - if (primitives[2] != null) result.setUpward(new Vec3(VertexData.normal(primitives[2]).toVector3f().mul(matrix3f))); + if (primitives[0] != null) + result.setPosition(new Vec3(VertexData.position(primitives[0], config.posU(), config.posV()).toVector3f().mulPosition(matrix4f))); + if (primitives[1] != null) + result.setForward(new Vec3(VertexData.normal(primitives[1]).toVector3f().mul(matrix3f))); + if (primitives[2] != null) + result.setUpward(new Vec3(VertexData.normal(primitives[2]).toVector3f().mul(matrix3f))); if (!result.available()) continue; bindResult = result; return; @@ -106,9 +101,12 @@ public void computeBindResult(BuiltIterableBuffer builtBuffer) { VertexData.UV forwardUV = result.getForward() == Vec3.ZERO ? new VertexData.UV(config.forwardU(), config.forwardV()) : null; VertexData.UV upwardUV = result.getUpward() == Vec3.ZERO ? new VertexData.UV(config.upwardU(), config.upwardV()) : null; VertexData[][] primitives = builtBuffer.findPrimitives(new VertexData.UV[]{posUV, forwardUV, upwardUV}); - if (primitives[0] != null) result.setPosition(new Vec3(VertexData.position(primitives[0], config.posU(), config.posV()).toVector3f().mulPosition(matrix4f))); - if (primitives[1] != null) result.setForward(new Vec3(VertexData.normal(primitives[1]).toVector3f().mul(matrix3f))); - if (primitives[2] != null) result.setUpward(new Vec3(VertexData.normal(primitives[2]).toVector3f().mul(matrix3f))); + if (primitives[0] != null) + result.setPosition(new Vec3(VertexData.position(primitives[0], config.posU(), config.posV()).toVector3f().mulPosition(matrix4f))); + if (primitives[1] != null) + result.setForward(new Vec3(VertexData.normal(primitives[1]).toVector3f().mul(matrix3f))); + if (primitives[2] != null) + result.setUpward(new Vec3(VertexData.normal(primitives[2]).toVector3f().mul(matrix3f))); if (!result.available()) continue; bindResult = result; return; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index e4148537..a5bd282b 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -1,5 +1,6 @@ package com.xtracr.realcamera.gui; +import com.google.common.collect.ImmutableSet; import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; @@ -31,11 +32,10 @@ public final class ModelAnalyser { private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); - private static final Set UNFOCUSABLE_RENDER_TYPES = Set.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); + private static final Set UNFOCUSABLE_RENDER_TYPES = ImmutableSet.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; private static final int z1 = 210, z2 = z1 + 10; public final List focusedPolyhedron = new ArrayList<>(); - public final PoseStack modelPose = new PoseStack(), texturePose = new PoseStack(); final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; @@ -60,8 +60,6 @@ public void initialize(BindTarget target, int modelScale) { modelRecords.clear(); textureRecords.clear(); focusedPolyhedron.clear(); - modelPose.setIdentity(); - texturePose.setIdentity(); targetPrimitives[0] = targetPrimitives[1] = targetPrimitives[2] = null; bindResult = BindResult.EMPTY; focusedRecord = currentRecord = null; @@ -101,14 +99,11 @@ public void applyDisableConfigs(String textureId, Set hiddenNames) { } } - public void computeFocusedOnTexture(int mouseX, int mouseY) { + public void computeFocusedOnTexture(float mouseU, float mouseV) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; - Vector3f newMousePosition = new Vector3f(mouseX, mouseY, 0) - .mulPosition(texturePose.last().pose().invert(new Matrix4f())); - float newMouseX = newMousePosition.x(), newMouseY = newMousePosition.y(); for (BuiltModelRecord record : textureRecords) { for (VertexData[] primitive : record.primitives()) { - if (VertexData.containsUV(primitive, newMouseX, newMouseY)) { + if (VertexData.containsUV(primitive, mouseU, mouseV)) { focusedRecord = record; focusedPolyhedron.add(primitive); break; @@ -241,8 +236,7 @@ public void drawFocusedInModelArea(GuiGraphicsExtractor graphics) { focusedPolyhedron.forEach(primitive -> GUIHelper.polygon(graphics, primitive, z1, focusedArgb)); } - public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics) { - Matrix4f positionMatrix = texturePose.last().pose(); + public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f texturePose) { int length = 0; VertexData[] transformed = new VertexData[0], reversed = new VertexData[0]; Vector3f position = new Vector3f(); @@ -254,7 +248,7 @@ public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics) { } for (int i = 0; i < length; i++) { VertexData vertex = primitive[i]; - position.set(vertex.u(), vertex.v(), 0).mulPosition(positionMatrix); + position.set(vertex.u(), vertex.v(), 0).mulPosition(texturePose); transformed[i] = reversed[length - 1 - i] = VertexData.immutable(position.x(), position.y(), 0, vertex.argb(), vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); } GUIHelper.polygon(graphics, transformed, 0, focusedArgb); @@ -266,7 +260,7 @@ public void updateModel(Minecraft client, Entity entity, float partialTicks, Pos EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); client.gameRenderer.getLighting().setupFor(Lighting.Entry.ENTITY_IN_UI); dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); - vertexCatcher.endCatching(this::computeBindResult); + vertexCatcher.forEachBuffer(this::computeBindResult); } public void computeBindResult(BuiltIterableBuffer builtBuffer) { diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 7c3f292b..bf4bd894 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -56,7 +56,7 @@ public final class ModelViewScreen extends Screen { private int x, y, page = 0; private InputConstants.Key modifierKey = ConfigFile.config().getScreenModifierKey(); private boolean initialized; - private int modelScale = 80, textureScale = 80, layers = 0, selectionRadius = 10; + private int modelScale = 80, textureScale = 80, layers = 0, selectionRadius = 10; private double modelX, modelY, textureX, textureY, clickedX = -1, clickedY = -1; private float xRot, yRot; private String focusedTextureId; @@ -466,7 +466,10 @@ private void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY analyser.applyDisableConfigs(textureId, hiddenNames); if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius); - if (inTextureViewArea(mouseX, mouseY)) analyser.computeFocusedOnTexture(mouseX, mouseY); + if (inTextureViewArea(mouseX, mouseY)) { + Vec2 mouseUV = translateXYToUV(mouseX, mouseY, textureViewArea); + analyser.computeFocusedOnTexture(mouseUV.x, mouseUV.y); + } if (inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(mouseX, mouseY, layers); if (toggleCategoryButton.getValue() == Category.CONFIGS || selectionModeButton.getValue() == 1) analyser.computeFocusedPolyhedron(); focusedPolyhedron = analyser.focusedPolyhedron.toArray(new VertexData[0][]); @@ -478,7 +481,13 @@ private void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY graphics.disableScissor(); if (textureViewArea != null) { GUIHelper.enableScissor(graphics, textureViewArea); - analyser.drawFocusedInTextureArea(graphics); + Matrix4f texturePose = new Matrix4f(); + int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); + float scale = (float) (textureScale * textureViewArea.width()) / 80; + texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + texturePose.scale(scale, scale, -scale); + texturePose.translate((float) textureX - 0.5f, (float) textureY - 0.5f, 0); + analyser.drawFocusedInTextureArea(graphics, texturePose); graphics.disableScissor(); } } @@ -506,7 +515,7 @@ private void renderModelViewArea(GuiGraphicsExtractor graphics, LivingEntity ent } private void renderEntityWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset, Quaternionf rotation, LivingEntity entity) { - PoseStack modelPose = analyser.modelPose; + PoseStack modelPose = new PoseStack(); modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); modelPose.scale(scale, scale, -scale); modelPose.translate(offset.x(), offset.y(), offset.z()); @@ -525,14 +534,26 @@ private void renderTextureViewArea(GuiGraphicsExtractor graphics) { if (textureViewArea == null) return; int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); - renderTextureWithAnalyser(graphics, x1, y1, x2, y2, (float) (textureScale * textureViewArea.width()) / 80, offset); + float scale = (float) (textureScale * textureViewArea.width()) / 80; + GUIHelper.flattenedModels(graphics, analyser.textureRecords, offset, x1, y1, x2, y2, scale); } - private void renderTextureWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset) { - analyser.texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - analyser.texturePose.scale(scale, scale, -scale); - analyser.texturePose.translate(offset.x(), offset.y(), offset.z()); - GUIHelper.flattenedModels(graphics, analyser.textureRecords, offset, x1, y1, x2, y2, scale); + private Vec2 translateUVToXY(float u, float v, ScreenRectangle screenArea) { + int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); + Vector3f vector3f = new Vector3f(u, v, 0) + .add((float) textureX - 0.5f, (float) textureY - 0.5f, 0) + .mul((float) (textureScale * screenArea.width()) / 80) + .add((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + return new Vec2(vector3f.x(), vector3f.y()); + } + + private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { + int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); + Vector3f vector3f = new Vector3f(x, y, 0) + .add(-(float) (x1 + x2) / 2.0f, -(float) (y1 + y2) / 2.0f, 0) + .mul((float) 80 / (textureScale * screenArea.width())) + .add((float) -textureX + 0.5f, (float) -textureY + 0.5f, 0); + return new Vec2(vector3f.x(), vector3f.y()); } private void importBindTarget(Button button) { @@ -878,24 +899,6 @@ public boolean mergeWith(UVRectangleWidget other) { return false; } - private Vec2 translateUVToXY(float u, float v, ScreenRectangle screenArea) { - int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); - Vector3f vector3f = new Vector3f(u, v, 0) - .add((float) textureX - 0.5f, (float) textureY - 0.5f, 0) - .mul((float) (textureScale * screenArea.width()) / 80) - .add((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - return new Vec2(vector3f.x(), vector3f.y()); - } - - private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { - int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); - Vector3f vector3f = new Vector3f(x, y, 0) - .add(-(float) (x1 + x2) / 2.0f, -(float) (y1 + y2) / 2.0f, 0) - .mul((float) 80 / (textureScale * screenArea.width())) - .add((float) -textureX + 0.5f, (float) -textureY + 0.5f, 0); - return new Vec2(vector3f.x(), vector3f.y()); - } - @Override protected void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { Vec2 minXY = translateUVToXY(uMin, vMin, textureViewArea), maxXY = translateUVToXY(uMax, vMax, textureViewArea); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java index f9dae213..070215ed 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java @@ -39,7 +39,7 @@ public static NumberField ofInt(Font font, int width, int height, int d public T getNumber() { try { - return getNumberInternal(); + return getNumberInternal(getValue()); } catch (NumberFormatException e) { return defaultValue; } catch (Exception e) { @@ -69,14 +69,15 @@ public NumberField setOnValueChange(Consumer consumer) { return this; } - abstract protected T getNumberInternal() throws NumberFormatException; + abstract protected T getNumberInternal(String str) throws NumberFormatException; protected void checkText() { super.setTooltip(tooltip); setTextColor(EditBox.DEFAULT_TEXT_COLOR); - if (getValue().isEmpty()) return; + String str = getValue(); + if (str.isEmpty()) return; try { - T value = getNumberInternal(); + T value = getNumberInternal(str); if (value.compareTo(minimum) < 0) throw new RuntimeException("< " + minimum); if (value.compareTo(maximum) > 0) throw new RuntimeException("> " + maximum); } catch (Exception e) { @@ -113,27 +114,27 @@ public void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int super.extractWidgetRenderState(graphics, mouseX, mouseY, partialTicks); } - private static class FloatField extends NumberField { + private static final class FloatField extends NumberField { FloatField(Font font, int width, int height, float defaultValue, @Nullable NumberField copyFrom) { super(font, width, height, defaultValue, Float.MAX_VALUE, -Float.MAX_VALUE, copyFrom); setMaxLength(16); } @Override - protected Float getNumberInternal() throws NumberFormatException { - return Float.parseFloat(getValue()); + protected Float getNumberInternal(String str) throws NumberFormatException { + return Float.parseFloat(str); } } - private static class IntField extends NumberField { + private static final class IntField extends NumberField { IntField(Font font, int width, int height, int defaultValue, @Nullable NumberField copyFrom) { super(font, width, height, defaultValue, Integer.MAX_VALUE, Integer.MIN_VALUE, copyFrom); setMaxLength(8); } @Override - protected Integer getNumberInternal() throws NumberFormatException { - return Integer.parseInt(getValue()); + protected Integer getNumberInternal(String str) throws NumberFormatException { + return Integer.parseInt(str); } } } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index c6b2586f..a2f817a7 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -3,35 +3,25 @@ import com.mojang.blaze3d.vertex.MeshData; import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.renderer.state.VertexData.UV; -import com.xtracr.realcamera.util.RenderTypeUtil; +import com.xtracr.realcamera.util.RenderTypeCache; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.client.renderer.rendertype.RenderType; import org.jspecify.annotations.Nullable; -import java.util.Map; - public record BuiltIterableBuffer(RenderType renderType, String textureId, IterableVertexBuffer vertexBuffer) { public static BuiltIterableBuffer buildFrom(RenderType renderType, MeshData meshData) { - return new BuiltIterableBuffer(renderType, RenderTypeUtil.getTextureId(renderType), new IterableVertexBuffer(meshData)); - } - - public boolean anyNotCached(UV[] uvs) { - Map cache = RenderTypeUtil.getPrimitiveCache(renderType); - if (cache == null) return true; - for (UV uv : uvs) { - if (!cache.containsKey(uv)) return true; - } - return false; + return new BuiltIterableBuffer(renderType, RenderTypeCache.getTextureId(renderType), new IterableVertexBuffer(meshData)); } public VertexData[] @Nullable [] findPrimitivesInCache(UV[] uvs) { - Map cache = RenderTypeUtil.getPrimitiveCache(renderType); + Object2IntMap cache = RenderTypeCache.getPrimitiveCache(renderType); int uvsLength = uvs.length; VertexData[][] primitives = new VertexData[uvsLength][]; if (cache == null) return primitives; for (int i = 0; i < uvsLength; i++) { if (uvs[i] == null) continue; - Integer primitiveIndex = cache.get(uvs[i]); - if (primitiveIndex == null) continue; + int primitiveIndex = cache.getInt(uvs[i]); + if (primitiveIndex == -1) continue; VertexData[] primitive = vertexBuffer.readPrimitiveAt(primitiveIndex); if (!VertexData.containsUV(primitive, uvs[i].u(), uvs[i].v())) continue; primitives[i] = primitive; @@ -54,7 +44,7 @@ public boolean anyNotCached(UV[] uvs) { allFound = false; continue; } - RenderTypeUtil.cachePrimitive(renderType, uv, idx); + RenderTypeCache.cachePrimitive(renderType, uv, idx); primitives[i] = VertexData.asImmutable(primitive); } return allFound; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java index b1a778ef..3b4e65ce 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java @@ -25,7 +25,8 @@ public final class MultiVertexCatcher { private final SubmitNodeStorage storage = new SubmitNodeStorage(); private final MeshCatcher meshCatcher = new MeshCatcher(); - private MultiVertexCatcher() { } + private MultiVertexCatcher() { + } public static MultiVertexCatcher create() { return new MultiVertexCatcher(); @@ -44,7 +45,7 @@ private static void renderModel(PoseStack poseStack, SubmitNodeStorage.Model private static void renderModelParts(PoseStack poseStack, Map> modelPartSubmitsMap, MultiBufferSource.BufferSource bufferSource) { poseStack.pushPose(); - for (Map.Entry> entry : modelPartSubmitsMap.entrySet()) { + for (var entry : modelPartSubmitsMap.entrySet()) { RenderType renderType = entry.getKey(); List modelPartSubmits = entry.getValue(); VertexConsumer buffer = bufferSource.getBuffer(renderType); @@ -60,7 +61,7 @@ private static void renderModelParts(PoseStack poseStack, Map> customGeometrySubmits, MultiBufferSource.BufferSource bufferSource) { - for (Map.Entry> entry : customGeometrySubmits.entrySet()) { + for (var entry : customGeometrySubmits.entrySet()) { VertexConsumer buffer = bufferSource.getBuffer(entry.getKey()); for (SubmitNodeStorage.CustomGeometrySubmit customGeometrySubmit : entry.getValue()) { customGeometrySubmit.customGeometryRenderer().render(customGeometrySubmit.pose(), buffer); @@ -68,11 +69,13 @@ private static void renderCustomGeometry(Map>> entry : ((ModelFeatureRenderer$StorageAccessor) collection.getModelSubmits()).getSolidModelSubmits().entrySet()) { + for (var entry : ((ModelFeatureRenderer$StorageAccessor) collection.getModelSubmits()).getSolidModelSubmits().entrySet()) { VertexConsumer buffer = meshCatcher.getBuffer(entry.getKey()); for (SubmitNodeStorage.ModelSubmit submit : entry.getValue()) { renderModel(poseStack, submit, buffer); @@ -83,11 +86,13 @@ private void renderSolidFeatures() { } } - /** @see FeatureRenderDispatcher#renderTranslucentFeatures() */ + /** + * @see FeatureRenderDispatcher#renderTranslucentFeatures() + */ private void renderTranslucentFeatures() { for (SubmitNodeCollection collection : storage.getSubmitsPerOrder().values()) { PoseStack poseStack = new PoseStack(); - for (SubmitNodeStorage.TranslucentModelSubmit submit : ((ModelFeatureRenderer$StorageAccessor) collection.getModelSubmits()).getTranslucentModelSubmits()) { + for (var submit : ((ModelFeatureRenderer$StorageAccessor) collection.getModelSubmits()).getTranslucentModelSubmits()) { renderModel(poseStack, submit.modelSubmit(), meshCatcher.getBuffer(submit.renderType())); } renderModelParts(poseStack, ((ModelPartFeatureRenderer$StorageAccessor) collection.getModelPartSubmits()).getTranslucentModelPartSubmits(), meshCatcher); @@ -100,12 +105,14 @@ public SubmitNodeCollector initCollector() { return storage; } - public void endCatching(Consumer consumer) { - if (storage.getSubmitsPerOrder().isEmpty()) return; - renderSolidFeatures(); - renderTranslucentFeatures(); - storage.clear(); - meshCatcher.endCatching(consumer); + public void forEachBuffer(Consumer consumer) { + if (!storage.getSubmitsPerOrder().isEmpty()) { + renderSolidFeatures(); + renderTranslucentFeatures(); + storage.clear(); + meshCatcher.endBatch(); + } + meshCatcher.forEachBuffer(consumer); } static final class MeshCatcher extends MultiBufferSource.BufferSource { @@ -136,11 +143,9 @@ public void initialize() { bufferPools.values().forEach(ByteBufferBuilderPool::release); } - public void endCatching(Consumer consumer) { - endBatch(); - for (Map.Entry entry : caughtMeshes.entrySet()) { - MeshData meshData = entry.getKey(); - consumer.accept(BuiltIterableBuffer.buildFrom(entry.getValue(), meshData)); + public void forEachBuffer(Consumer consumer) { + for (var entry : caughtMeshes.entrySet()) { + consumer.accept(BuiltIterableBuffer.buildFrom(entry.getValue(), entry.getKey())); } } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java index 7ef9788e..c5ff03e4 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java @@ -53,6 +53,6 @@ protected float getTranslateY(final int height, final int guiScale) { @Override protected @NonNull String getTextureLabel() { - return "realcamera.culled_model"; + return "realcamera.culled_models"; } } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java index 0c95b6c0..0664466b 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiFlattenedModelsRenderer.java @@ -44,6 +44,6 @@ protected float getTranslateY(final int height, final int guiScale) { @Override protected @NonNull String getTextureLabel() { - return "realcamera.texture"; + return "realcamera.flattened_models"; } } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java index 18730375..5f57de5e 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java @@ -134,7 +134,12 @@ public int hashCode() { } } - record ImmutableVertex(float x, float y, float z, int argb, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) implements VertexData { } + record ImmutableVertex(float x, float y, float z, int argb, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) implements VertexData { + @Override + public VertexData asImmutable() { + return this; + } + } final class MutableVertex implements VertexData { public float x, y, z; @@ -143,7 +148,8 @@ final class MutableVertex implements VertexData { public int overlay, light; public float normalX, normalY, normalZ; - private MutableVertex() { } + private MutableVertex() { + } @Override public float x() { diff --git a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java index 9b75ffdb..d69f24d0 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -5,8 +5,6 @@ import org.joml.Matrix4fc; import org.joml.Vector4f; -import java.awt.*; - public final class MathUtil { public static double round(double d, int digits) { return Math.round(d * Math.pow(10, digits)) / Math.pow(10, digits); @@ -45,11 +43,8 @@ public static boolean pointInTriangle(float x, float y, float x0, float y0, floa return beta + gamma <= 1; } - public static boolean pointInQuad(float x, float y, - float x0, float y0, float x1, float y1, - float x2, float y2, float x3, float y3) { - return pointInTriangle(x, y, x0, y0, x1, y1, x2, y2) - || pointInTriangle(x, y, x1, y1, x2, y2, x3, y3); + public static boolean pointInQuad(float x, float y, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { + return pointInTriangle(x, y, x0, y0, x1, y1, x2, y2) || pointInTriangle(x, y, x1, y1, x2, y2, x3, y3); } public static Vec3 getEulerAngleYXZ(Matrix3f normal) { diff --git a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java similarity index 81% rename from common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java rename to common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java index 8f5f9e9a..bbe55c13 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java @@ -6,24 +6,25 @@ import com.xtracr.realcamera.RealCamera; import com.xtracr.realcamera.mixin.accessor.RenderTypeAccessor; import com.xtracr.realcamera.renderer.state.VertexData.UV; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.minecraft.client.renderer.rendertype.RenderSetup; import net.minecraft.client.renderer.rendertype.RenderType; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import java.lang.reflect.Field; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; -public final class RenderTypeUtil { +public final class RenderTypeCache { @Nullable private static final Field TEXTURES_FIELD; private static final LoadingCache TEXTURE_ID_CACHE = CacheBuilder.newBuilder() .maximumSize(64) .expireAfterAccess(60, TimeUnit.SECONDS) .build(new TextureIdCacheLoader()); - private static final LoadingCache> PRIMITIVE_CACHE = CacheBuilder.newBuilder() + private static final LoadingCache> PRIMITIVE_CACHE = CacheBuilder.newBuilder() .maximumSize(64) .expireAfterAccess(60, TimeUnit.SECONDS) .build(new PrimitiveCacheLoader()); @@ -43,7 +44,7 @@ public static String getTextureId(RenderType renderType) { return TEXTURE_ID_CACHE.getUnchecked(renderType); } - public static @Nullable Map getPrimitiveCache(RenderType renderType) { + public static @Nullable Object2IntMap getPrimitiveCache(RenderType renderType) { return PRIMITIVE_CACHE.getIfPresent(renderType); } @@ -67,10 +68,12 @@ private static class TextureIdCacheLoader extends CacheLoader> { + private static class PrimitiveCacheLoader extends CacheLoader> { @Override - public @NonNull Map load(@NonNull RenderType renderType) { - return new HashMap<>(4); + public @NonNull Object2IntMap load(@NonNull RenderType renderType) { + Object2IntOpenHashMap map = new Object2IntOpenHashMap<>(4); + map.defaultReturnValue(-1); + return map; } } } diff --git a/gradle.properties b/gradle.properties index 16bf9fb3..d91b01e5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ neoforge_version=26.1.2.36-beta moddev_version=2.0.141 ## Mod Properties mod_id=realcamera -mod_version=0.7.7-beta +mod_version=0.7.8-beta mod_group_id=com.xtracr.realcamera ## Dependencies fabric_api_version=0.147.0+26.1.2 From 2fb24c10b591d7d34c1e58960bb8be0da0d109ab Mon Sep 17 00:00:00 2001 From: xTracr Date: Wed, 13 May 2026 14:52:39 +0800 Subject: [PATCH 16/33] Replace Object[] sort with record; make focusedPolyhedron private; fix pointInQuad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace Object[] sort entries with a typed ZEntry record in ModelAnalyser - Make focusedPolyhedron private, add getFocusedPolyhedron() accessor - Pass modelScale as parameter instead of storing field in ModelAnalyser - Replace List indexes with boolean[] visited for polyhedron building - Rename GUIHelper.polygon → triangleOrQuad, MeshCatcher.initialize → clear --- .../com/xtracr/realcamera/gui/GUIHelper.java | 13 ++-- .../xtracr/realcamera/gui/ModelAnalyser.java | 78 +++++++++---------- .../realcamera/gui/ModelViewScreen.java | 6 +- .../renderer/MultiVertexCatcher.java | 5 +- .../com/xtracr/realcamera/util/MathUtil.java | 2 +- 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java index 340bdd8c..98cde370 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java @@ -44,12 +44,13 @@ public static void outline(GuiGraphicsExtractor graphics, float x, float y, floa fill(graphics, x + width - 1, y + 1, x + width, y + height - 1, argb); } - public static void polygon(GuiGraphicsExtractor graphics, VertexData[] polygon, float z, int argb) { - if (polygon.length < 3) return; - float x0 = polygon[0].x(), y0 = polygon[0].y(); - float x1 = polygon[1].x(), y1 = polygon[1].y(); - float x2 = polygon[2].x(), y2 = polygon[2].y(); - float x3 = polygon.length > 3 ? polygon[3].x() : x2, y3 = polygon.length > 3 ? polygon[3].y() : y2; + public static void triangleOrQuad(GuiGraphicsExtractor graphics, VertexData[] vertices, float z, int argb) { + if (vertices.length < 3) return; + float x0 = vertices[0].x(), y0 = vertices[0].y(); + float x1 = vertices[1].x(), y1 = vertices[1].y(); + float x2 = vertices[2].x(), y2 = vertices[2].y(); + boolean isQuad = vertices.length > 3; + float x3 = isQuad ? vertices[3].x() : x2, y3 = isQuad ? vertices[3].y() : y2; ((GuiGraphicsExtractorAccessor) graphics).getGuiRenderState().addGuiElement(new ColoredFloatQuadRenderState( RenderPipelines.GUI, TextureSetup.noTexture(), new Matrix3x2f(graphics.pose()), x0, y0, z, x1, y1, z, x2, y2, z, x3, y3, z, argb, ((GuiGraphicsExtractorAccessor) graphics).getScissorStack().peek())); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index a5bd282b..51594bf0 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -35,14 +35,13 @@ public final class ModelAnalyser { private static final Set UNFOCUSABLE_RENDER_TYPES = ImmutableSet.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; private static final int z1 = 210, z2 = z1 + 10; - public final List focusedPolyhedron = new ArrayList<>(); + private final List focusedPolyhedron = new ArrayList<>(); final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; private BindTarget target = BindTarget.EMPTY; @Nullable private BuiltModelRecord focusedRecord, currentRecord; - private double modelScale; private static boolean haveCommonVertex(VertexData[] p1, List primitives) { final float precision = 1e-5f; @@ -56,7 +55,6 @@ private static boolean haveCommonVertex(VertexData[] p1, List prim public void initialize(BindTarget target, int modelScale) { this.target = target; - this.modelScale = modelScale; modelRecords.clear(); textureRecords.clear(); focusedPolyhedron.clear(); @@ -70,6 +68,10 @@ public String getFocusedTextureId() { return focusedRecord == null ? null : focusedRecord.textureId(); } + public VertexData[][] getFocusedPolyhedron() { + return focusedPolyhedron.toArray(new VertexData[0][]); + } + public void applyDisableConfigs(String textureId, Set hiddenNames) { for (BuiltModelRecord record : modelRecords) { if (record.containsTextureId(textureId)) textureRecords.add(record); @@ -114,7 +116,7 @@ public void computeFocusedOnTexture(float mouseU, float mouseV) { public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; - List sortByZ = new ArrayList<>(); + List sortByZ = new ArrayList<>(); for (BuiltModelRecord record : modelRecords) { if (UNFOCUSABLE_RENDER_TYPES.contains(record.renderType())) continue; VertexData[][] primitives = record.primitives(); @@ -122,19 +124,19 @@ public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { if (!VertexData.containsXY(primitive, mouseX, mouseY)) continue; VertexData vertex = primitive[0]; float deltaZ = vertex.normalZ() == 0 ? 0 : (vertex.normalX() * (mouseX - vertex.x()) + vertex.normalY() * (mouseY - vertex.y())) / vertex.normalZ(); - sortByZ.add(new Object[]{record, primitive, vertex.z() - deltaZ}); + sortByZ.add(new ZEntry(record, primitive, vertex.z() - deltaZ)); } } if (sortByZ.isEmpty()) return; - sortByZ.sort(Comparator.comparingDouble(array -> -(float) array[2])); - Object[] result = sortByZ.get(Math.min(sortByZ.size() - 1, layers)); - focusedRecord = (BuiltModelRecord) result[0]; - focusedPolyhedron.add((VertexData[]) result[1]); + sortByZ.sort(Comparator.comparingDouble(ZEntry::z).reversed()); + ZEntry result = sortByZ.get(Math.min(sortByZ.size() - 1, layers)); + focusedRecord = result.record(); + focusedPolyhedron.add(result.primitive()); } public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; - List sortByZ = new ArrayList<>(); + List sortByZ = new ArrayList<>(); for (BuiltModelRecord record : modelRecords) { if (UNFOCUSABLE_RENDER_TYPES.contains(record.renderType())) continue; VertexData[][] primitives = record.primitives(); @@ -146,19 +148,19 @@ public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { if (x < minX || y < minY || x > maxX || y > maxY) continue primitiveFor; if (vertex.z() > maxZ) maxZ = vertex.z(); } - sortByZ.add(new Object[]{record, primitive, maxZ}); + sortByZ.add(new ZEntry(record, primitive, maxZ)); } } if (sortByZ.isEmpty()) return; - sortByZ.sort(Comparator.comparingDouble(array -> -(float) array[2])); - focusedRecord = (BuiltModelRecord) sortByZ.getFirst()[0]; + sortByZ.sort(Comparator.comparingDouble((ZEntry entry) -> -entry.z())); + focusedRecord = sortByZ.getFirst().record(); while (!sortByZ.isEmpty()) { - VertexData[] first = (VertexData[]) sortByZ.getFirst()[1]; + VertexData[] first = sortByZ.getFirst().primitive(); focusedPolyhedron.add(first); sortByZ.removeFirst(); - sortByZ.removeIf(array -> { - if (array[0] != focusedRecord) return true; - VertexData[] primitive = (VertexData[]) array[1]; + sortByZ.removeIf(entry -> { + if (entry.record() != focusedRecord) return true; + VertexData[] primitive = entry.primitive(); primitiveFor: for (VertexData vertex : primitive) { for (VertexData[] focused : focusedPolyhedron) @@ -184,32 +186,27 @@ public void computeFocusedPolyhedron() { if (focusedIndex == -1) return; List polyhedron = new ArrayList<>(); polyhedron.add(focused); - List indexes = new ArrayList<>(List.of(focusedIndex)); - final int primitiveCount = primitives.length; + boolean[] visited = new boolean[primitives.length]; + visited[focusedIndex] = true; boolean added; do { added = false; - for (int i = 0; i < primitiveCount; i++) { + for (int i = 0; i < primitives.length; i++) { VertexData[] primitive = primitives[i]; - if (indexes.contains(i) | !haveCommonVertex(primitive, polyhedron)) continue; + if (visited[i] | !haveCommonVertex(primitive, polyhedron)) continue; polyhedron.add(primitive); - indexes.add(i); + visited[i] = true; added = true; } } while (added); - List resultIndexes = new ArrayList<>(List.of(focusedIndex)); - for (int i = focusedIndex + 1; i < primitiveCount; i++) { - if (!indexes.contains(i)) break; - resultIndexes.add(i); - } - for (int i = focusedIndex - 1; i >= 0; i--) { - if (!indexes.contains(i)) break; - resultIndexes.add(i); - } - resultIndexes.forEach(i -> focusedPolyhedron.add(primitives[i])); + for (int i = focusedIndex + 1; i < primitives.length && visited[i]; i++) + focusedPolyhedron.add(primitives[i]); + for (int i = focusedIndex - 1; i >= 0 && visited[i]; i--) + focusedPolyhedron.add(primitives[i]); + focusedPolyhedron.add(focused); } - public void drawCameraDirections(GuiGraphicsExtractor graphics) { + public void drawCameraDirections(GuiGraphicsExtractor graphics, double modelScale) { if (targetPrimitives[0] == null || targetPrimitives[1] == null || targetPrimitives[2] == null) return; Vec3 start = bindResult.getPosition(); Matrix3f normal = bindResult.getRotation(); @@ -219,10 +216,10 @@ public void drawCameraDirections(GuiGraphicsExtractor graphics) { GUIHelper.vector(graphics, start, new Vec3(normal.m00(), normal.m01(), normal.m02()).scale(modelScale / 6), z2, leftArgb); } - public void drawBindTarget(GuiGraphicsExtractor graphics) { + public void drawBindTarget(GuiGraphicsExtractor graphics, double modelScale) { if (currentRecord == null) return; TargetConfig config = target.targetConfig(); - if (targetPrimitives[0] != null) GUIHelper.polygon(graphics, targetPrimitives[0], z1, planeArgb); + if (targetPrimitives[0] != null) GUIHelper.triangleOrQuad(graphics, targetPrimitives[0], z1, planeArgb); if (targetPrimitives[1] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[1], config.forwardU(), config.forwardV()), VertexData.normal(targetPrimitives[1]).scale(-modelScale / 2), z2, forwardArgb); if (targetPrimitives[2] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[2], config.upwardU(), config.upwardV()), VertexData.normal(targetPrimitives[2]).scale(-modelScale / 2), z2, upwardArgb); } @@ -232,8 +229,8 @@ public void drawFocusedInModelArea(GuiGraphicsExtractor graphics) { VertexData[] focused = focusedPolyhedron.getFirst(); VertexData[] reversed = new VertexData[focused.length]; for (int i = 0; i < focused.length; i++) reversed[i] = focused[focused.length - 1 - i]; - GUIHelper.polygon(graphics, reversed, z1, focusedArgb); - focusedPolyhedron.forEach(primitive -> GUIHelper.polygon(graphics, primitive, z1, focusedArgb)); + GUIHelper.triangleOrQuad(graphics, reversed, z1, focusedArgb); + focusedPolyhedron.forEach(primitive -> GUIHelper.triangleOrQuad(graphics, primitive, z1, focusedArgb)); } public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f texturePose) { @@ -251,8 +248,8 @@ public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f tex position.set(vertex.u(), vertex.v(), 0).mulPosition(texturePose); transformed[i] = reversed[length - 1 - i] = VertexData.immutable(position.x(), position.y(), 0, vertex.argb(), vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); } - GUIHelper.polygon(graphics, transformed, 0, focusedArgb); - GUIHelper.polygon(graphics, reversed, 0, focusedArgb); + GUIHelper.triangleOrQuad(graphics, transformed, 0, focusedArgb); + GUIHelper.triangleOrQuad(graphics, reversed, 0, focusedArgb); } } @@ -289,4 +286,7 @@ public void computeBindResult(BuiltIterableBuffer builtBuffer) { bindResult = result.computeCamera(true); } } + + private record ZEntry(BuiltModelRecord record, VertexData[] primitive, float z) { + } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index bf4bd894..2a8ff320 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -472,12 +472,12 @@ private void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY } if (inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(mouseX, mouseY, layers); if (toggleCategoryButton.getValue() == Category.CONFIGS || selectionModeButton.getValue() == 1) analyser.computeFocusedPolyhedron(); - focusedPolyhedron = analyser.focusedPolyhedron.toArray(new VertexData[0][]); + focusedPolyhedron = analyser.getFocusedPolyhedron(); focusedTextureId = analyser.getFocusedTextureId(); GUIHelper.enableScissor(graphics, modelViewArea); if (toggleCategoryButton.getValue() != Category.PREVIEW) analyser.drawFocusedInModelArea(graphics); - if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics); - else analyser.drawCameraDirections(graphics); + if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics, modelScale); + else analyser.drawCameraDirections(graphics, modelScale); graphics.disableScissor(); if (textureViewArea != null) { GUIHelper.enableScissor(graphics, textureViewArea); diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java index 3b4e65ce..c80ee12b 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java @@ -101,7 +101,8 @@ private void renderTranslucentFeatures() { } public SubmitNodeCollector initCollector() { - meshCatcher.initialize(); + meshCatcher.clear(); + storage.clear(); return storage; } @@ -135,7 +136,7 @@ private MeshCatcher() { return bufferBuilder; } - public void initialize() { + public void clear() { for (MeshData meshData : caughtMeshes.keySet()) { meshData.close(); } diff --git a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java index d69f24d0..65c2e3f5 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -44,7 +44,7 @@ public static boolean pointInTriangle(float x, float y, float x0, float y0, floa } public static boolean pointInQuad(float x, float y, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { - return pointInTriangle(x, y, x0, y0, x1, y1, x2, y2) || pointInTriangle(x, y, x1, y1, x2, y2, x3, y3); + return pointInTriangle(x, y, x0, y0, x1, y1, x2, y2) || pointInTriangle(x, y, x0, y0, x2, y2, x3, y3); } public static Vec3 getEulerAngleYXZ(Matrix3f normal) { From 1ca1f249f0fbbd5c40ad031aeea3ba6cc4c5045d Mon Sep 17 00:00:00 2001 From: xTracr Date: Wed, 13 May 2026 17:18:46 +0800 Subject: [PATCH 17/33] Refactor ModelAnalyser to stateless design; consolidate render pipeline in ModelViewScreen --- .../xtracr/realcamera/gui/ModelAnalyser.java | 75 ++++------ .../realcamera/gui/ModelViewScreen.java | 131 +++++++++--------- 2 files changed, 96 insertions(+), 110 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 51594bf0..606922f7 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -36,46 +36,12 @@ public final class ModelAnalyser { private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; private static final int z1 = 210, z2 = z1 + 10; private final List focusedPolyhedron = new ArrayList<>(); - final List modelRecords = new ArrayList<>(), textureRecords = new ArrayList<>(); private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; - private BindTarget target = BindTarget.EMPTY; @Nullable private BuiltModelRecord focusedRecord, currentRecord; - private static boolean haveCommonVertex(VertexData[] p1, List primitives) { - final float precision = 1e-5f; - for (VertexData[] p2 : primitives) - for (VertexData v1 : p1) - for (VertexData v2 : p2) - if (Math.abs(v1.x() - v2.x()) < precision && Math.abs(v1.y() - v2.y()) < precision && Math.abs(v1.z() - v2.z()) < precision) - return true; - return false; - } - - public void initialize(BindTarget target, int modelScale) { - this.target = target; - modelRecords.clear(); - textureRecords.clear(); - focusedPolyhedron.clear(); - targetPrimitives[0] = targetPrimitives[1] = targetPrimitives[2] = null; - bindResult = BindResult.EMPTY; - focusedRecord = currentRecord = null; - target.offsets().setScale(target.offsets().getScale() * modelScale); - } - - public String getFocusedTextureId() { - return focusedRecord == null ? null : focusedRecord.textureId(); - } - - public VertexData[][] getFocusedPolyhedron() { - return focusedPolyhedron.toArray(new VertexData[0][]); - } - - public void applyDisableConfigs(String textureId, Set hiddenNames) { - for (BuiltModelRecord record : modelRecords) { - if (record.containsTextureId(textureId)) textureRecords.add(record); - } + public static void applyDisableConfigs(List modelRecords, BindTarget target, String textureId, Set hiddenNames) { for (int i = 0; i < modelRecords.size(); i++) { BuiltModelRecord record = modelRecords.get(i); List primitives = new ArrayList<>(); @@ -101,7 +67,25 @@ public void applyDisableConfigs(String textureId, Set hiddenNames) { } } - public void computeFocusedOnTexture(float mouseU, float mouseV) { + private static boolean haveCommonVertex(VertexData[] p1, List primitives) { + final float precision = 1e-5f; + for (VertexData[] p2 : primitives) + for (VertexData v1 : p1) + for (VertexData v2 : p2) + if (Math.abs(v1.x() - v2.x()) < precision && Math.abs(v1.y() - v2.y()) < precision && Math.abs(v1.z() - v2.z()) < precision) + return true; + return false; + } + + public VertexData[][] getFocusedPolyhedron() { + return focusedPolyhedron.toArray(new VertexData[0][]); + } + + public String getFocusedTextureId() { + return focusedRecord == null ? null : focusedRecord.textureId(); + } + + public void computeFocusedOnTexture(List textureRecords, float mouseU, float mouseV) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; for (BuiltModelRecord record : textureRecords) { for (VertexData[] primitive : record.primitives()) { @@ -114,7 +98,7 @@ public void computeFocusedOnTexture(float mouseU, float mouseV) { } } - public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { + public void computeFocusedOnModel(List modelRecords, int mouseX, int mouseY, int layers) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; List sortByZ = new ArrayList<>(); for (BuiltModelRecord record : modelRecords) { @@ -134,7 +118,7 @@ public void computeFocusedOnModel(int mouseX, int mouseY, int layers) { focusedPolyhedron.add(result.primitive()); } - public void computeFocusedOnModel(int minX, int minY, int maxX, int maxY) { + public void computeFocusedOnModel(List modelRecords, int minX, int minY, int maxX, int maxY) { if (focusedRecord != null && !focusedPolyhedron.isEmpty()) return; List sortByZ = new ArrayList<>(); for (BuiltModelRecord record : modelRecords) { @@ -216,8 +200,7 @@ public void drawCameraDirections(GuiGraphicsExtractor graphics, double modelScal GUIHelper.vector(graphics, start, new Vec3(normal.m00(), normal.m01(), normal.m02()).scale(modelScale / 6), z2, leftArgb); } - public void drawBindTarget(GuiGraphicsExtractor graphics, double modelScale) { - if (currentRecord == null) return; + public void drawBindTarget(GuiGraphicsExtractor graphics, BindTarget target, double modelScale) { TargetConfig config = target.targetConfig(); if (targetPrimitives[0] != null) GUIHelper.triangleOrQuad(graphics, targetPrimitives[0], z1, planeArgb); if (targetPrimitives[1] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[1], config.forwardU(), config.forwardV()), VertexData.normal(targetPrimitives[1]).scale(-modelScale / 2), z2, forwardArgb); @@ -230,7 +213,7 @@ public void drawFocusedInModelArea(GuiGraphicsExtractor graphics) { VertexData[] reversed = new VertexData[focused.length]; for (int i = 0; i < focused.length; i++) reversed[i] = focused[focused.length - 1 - i]; GUIHelper.triangleOrQuad(graphics, reversed, z1, focusedArgb); - focusedPolyhedron.forEach(primitive -> GUIHelper.triangleOrQuad(graphics, primitive, z1, focusedArgb)); + for (VertexData[] primitive : focusedPolyhedron) GUIHelper.triangleOrQuad(graphics, primitive, z1, focusedArgb); } public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f texturePose) { @@ -253,14 +236,16 @@ public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f tex } } - public void updateModel(Minecraft client, Entity entity, float partialTicks, PoseStack poseStack) { + public List captureModel(Minecraft client, Entity entity, float partialTicks, PoseStack poseStack, BindTarget target) { EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); client.gameRenderer.getLighting().setupFor(Lighting.Entry.ENTITY_IN_UI); dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, poseStack, vertexCatcher.initCollector()); - vertexCatcher.forEachBuffer(this::computeBindResult); + List records = new ArrayList<>(); + vertexCatcher.forEachBuffer(buf -> computeRecord(buf, records, target)); + return records; } - public void computeBindResult(BuiltIterableBuffer builtBuffer) { + private void computeRecord(BuiltIterableBuffer builtBuffer, List records, BindTarget target) { VertexData[] vertices = builtBuffer.vertexBuffer().stream().map(VertexData::asImmutable).toArray(VertexData[]::new); VertexFormat.Mode drawMode = builtBuffer.renderType().mode(); final int primitiveLength = drawMode.primitiveLength, primitiveStride = drawMode.primitiveStride; @@ -272,7 +257,7 @@ public void computeBindResult(BuiltIterableBuffer builtBuffer) { System.arraycopy(vertices, k + 1, primitives[i], 1, primitiveLength - 1); } BuiltModelRecord record = new BuiltModelRecord(builtBuffer.renderType(), builtBuffer.textureId(), vertices, primitives); - modelRecords.add(record); + records.add(record); if (!builtBuffer.textureId().contains(target.textureId()) || currentRecord != null) return; BindResult result = new BindResult(target); BindTarget.TargetConfig config = target.targetConfig(); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 2a8ff320..bda127fe 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -15,6 +15,7 @@ import com.xtracr.realcamera.gui.components.DoubleSlider; import com.xtracr.realcamera.gui.components.NumberField; import com.xtracr.realcamera.gui.components.SimpleIconButton; +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.util.LocUtil; import com.xtracr.realcamera.util.MathUtil; @@ -51,7 +52,6 @@ import java.util.zip.InflaterInputStream; public final class ModelViewScreen extends Screen { - public final ModelAnalyser analyser = new ModelAnalyser(); private final int xSize = 450, ySize = 206, middleWidth = xSize - 200, widgetWidth = (xSize - middleWidth) / 4 - 8, widgetHeight = 18; private int x, y, page = 0; private InputConstants.Key modifierKey = ConfigFile.config().getScreenModifierKey(); @@ -454,88 +454,89 @@ public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX graphics.fill(x, y, x + (xSize - middleWidth) / 2 - 4, y + ySize, 0xFF444444); graphics.fill(x + (xSize - middleWidth) / 2, y, x + (xSize + middleWidth) / 2, y + ySize, 0xFF222222); graphics.fill(x + (xSize + middleWidth) / 2 + 4, y, x + xSize, y + ySize, 0xFF444444); - analyser.initialize(genBindTarget(), modelScale); - renderModelViewArea(graphics, minecraft.player); - renderTextureViewArea(graphics); - applyAnalyser(graphics, mouseX, mouseY); - } - private void applyAnalyser(GuiGraphicsExtractor graphics, int mouseX, int mouseY) { + ModelAnalyser analyser = new ModelAnalyser(); + BindTarget target = genBindTarget(); + target.offsets().setScale(target.offsets().getScale() * modelScale); String textureId = toggleCategoryButton.getValue() == Category.DISABLE ? disabledIdField.getValue() : ""; Set hiddenNames = hiddenNameMap.getOrDefault(nameField.getValue(), Set.of()); - analyser.applyDisableConfigs(textureId, hiddenNames); + List modelRecords = captureRotatedEntity(analyser, target, minecraft.player); + List textureRecords = modelRecords.stream().filter(record -> record.containsTextureId(textureId)).toList(); + ModelAnalyser.applyDisableConfigs(modelRecords, target, textureId, hiddenNames); + computeFocusedPrimitives(analyser, modelRecords, textureRecords, mouseX, mouseY); + renderCulledModels(graphics, analyser, target, modelRecords); + if (textureViewArea != null) renderFlattenedModels(graphics, analyser, textureRecords); + } + + private List captureRotatedEntity(ModelAnalyser analyser, BindTarget target, LivingEntity entity) { + float entityBodyYaw = entity.yBodyRot; + float entityYaw = entity.getYRot(); + float entityPitch = entity.getXRot(); + float entityPrevHeadYaw = entity.yHeadRotO; + float entityHeadYaw = entity.yHeadRot; + entity.yBodyRot = 180.0f; + entity.setYRot(180.0f + (float) entityYawSlider.getDouble()); + entity.setXRot((float) entityPitchSlider.getDouble()); + entity.yHeadRot = entity.getYRot(); + entity.yHeadRotO = entity.getYRot(); + try { + int x1 = modelViewArea.left(), y1 = modelViewArea.top(), x2 = modelViewArea.right(), y2 = modelViewArea.bottom(); + Quaternionf rotation = new Quaternionf().rotateX((float) Math.PI / 6 + xRot).rotateY((float) Math.PI / 6 + yRot).rotateZ((float) Math.PI); + PoseStack modelPose = new PoseStack(); + modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + modelPose.scale(modelScale, modelScale, -modelScale); + modelPose.translate(modelX, modelY, 0); + modelPose.mulPose(rotation); + modelPose.translate(0, -entity.getBbHeight() / 2.0f, 0); + return analyser.captureModel(minecraft, entity, 1.0f, modelPose, target); + } finally { + entity.yBodyRot = entityBodyYaw; + entity.setYRot(entityYaw); + entity.setXRot(entityPitch); + entity.yHeadRotO = entityPrevHeadYaw; + entity.yHeadRot = entityHeadYaw; + } + } + + private void computeFocusedPrimitives(ModelAnalyser analyser, List modelRecords, List textureRecords, int mouseX, int mouseY) { if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) - analyser.computeFocusedOnModel(mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius); + analyser.computeFocusedOnModel(modelRecords, mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius); if (inTextureViewArea(mouseX, mouseY)) { Vec2 mouseUV = translateXYToUV(mouseX, mouseY, textureViewArea); - analyser.computeFocusedOnTexture(mouseUV.x, mouseUV.y); + analyser.computeFocusedOnTexture(textureRecords, mouseUV.x, mouseUV.y); } - if (inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(mouseX, mouseY, layers); + if (inModelViewArea(mouseX, mouseY)) analyser.computeFocusedOnModel(modelRecords, mouseX, mouseY, layers); if (toggleCategoryButton.getValue() == Category.CONFIGS || selectionModeButton.getValue() == 1) analyser.computeFocusedPolyhedron(); focusedPolyhedron = analyser.getFocusedPolyhedron(); focusedTextureId = analyser.getFocusedTextureId(); + } + + private void renderCulledModels(GuiGraphicsExtractor graphics, ModelAnalyser analyser, BindTarget target, List modelRecords) { + int x1 = modelViewArea.left(), y1 = modelViewArea.top(), x2 = modelViewArea.right(), y2 = modelViewArea.bottom(); GUIHelper.enableScissor(graphics, modelViewArea); + float invScale = 1.0f / modelScale; + Matrix4f modelTransform = new Matrix4f(); + modelTransform.scale(invScale, invScale, -invScale); + modelTransform.translate(-(float) (x1 + x2) / 2.0f, -(float) (y1 + y2) / 2.0f, 0); + GUIHelper.culledModels(graphics, modelRecords, modelScale, modelTransform, x1, y1, x2, y2); if (toggleCategoryButton.getValue() != Category.PREVIEW) analyser.drawFocusedInModelArea(graphics); - if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics, modelScale); + if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics, target, modelScale); else analyser.drawCameraDirections(graphics, modelScale); graphics.disableScissor(); - if (textureViewArea != null) { - GUIHelper.enableScissor(graphics, textureViewArea); - Matrix4f texturePose = new Matrix4f(); - int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); - float scale = (float) (textureScale * textureViewArea.width()) / 80; - texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - texturePose.scale(scale, scale, -scale); - texturePose.translate((float) textureX - 0.5f, (float) textureY - 0.5f, 0); - analyser.drawFocusedInTextureArea(graphics, texturePose); - graphics.disableScissor(); - } } - private void renderModelViewArea(GuiGraphicsExtractor graphics, LivingEntity entity) { - int x1 = modelViewArea.left(), y1 = modelViewArea.top(), x2 = modelViewArea.right(), y2 = modelViewArea.bottom(); - Quaternionf rotation = new Quaternionf().rotateX((float) Math.PI / 6 + xRot).rotateY((float) Math.PI / 6 + yRot).rotateZ((float) Math.PI); - float entityBodyYaw = entity.yBodyRot; - float entityYaw = entity.getYRot(); - float entityPitch = entity.getXRot(); - float entityPrevHeadYaw = entity.yHeadRotO; - float entityHeadYaw = entity.yHeadRot; - entity.yBodyRot = 180.0f; - entity.setYRot(180.0f + (float) entityYawSlider.getDouble()); - entity.setXRot((float) entityPitchSlider.getDouble()); - entity.yHeadRot = entity.getYRot(); - entity.yHeadRotO = entity.getYRot(); - Vector3f offset = new Vector3f((float) modelX, (float) modelY, 0); - renderEntityWithAnalyser(graphics, x1, y1, x2, y2, modelScale, offset, rotation, entity); - entity.yBodyRot = entityBodyYaw; - entity.setYRot(entityYaw); - entity.setXRot(entityPitch); - entity.yHeadRotO = entityPrevHeadYaw; - entity.yHeadRot = entityHeadYaw; - } - - private void renderEntityWithAnalyser(GuiGraphicsExtractor graphics, int x1, int y1, int x2, int y2, float scale, Vector3f offset, Quaternionf rotation, LivingEntity entity) { - PoseStack modelPose = new PoseStack(); - modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - modelPose.scale(scale, scale, -scale); - modelPose.translate(offset.x(), offset.y(), offset.z()); - modelPose.mulPose(rotation); - modelPose.translate(0, -entity.getBbHeight() / 2.0f, 0); - analyser.updateModel(minecraft, entity, 1.0f, modelPose); - Matrix4f transform = new Matrix4f(); - transform.translate(offset.x(), offset.y(), offset.z()); - transform.rotate(rotation); - transform.translate(0, -entity.getBbHeight() / 2.0f, 0); - transform.mul(modelPose.last().pose().invert(new Matrix4f())); - GUIHelper.culledModels(graphics, analyser.modelRecords, scale, transform, x1, y1, x2, y2); - } - - private void renderTextureViewArea(GuiGraphicsExtractor graphics) { - if (textureViewArea == null) return; + private void renderFlattenedModels(GuiGraphicsExtractor graphics, ModelAnalyser analyser, List textureRecords) { int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); - Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); + GUIHelper.enableScissor(graphics, textureViewArea); float scale = (float) (textureScale * textureViewArea.width()) / 80; - GUIHelper.flattenedModels(graphics, analyser.textureRecords, offset, x1, y1, x2, y2, scale); + Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); + GUIHelper.flattenedModels(graphics, textureRecords, offset, x1, y1, x2, y2, scale); + Matrix4f texturePose = new Matrix4f(); + texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + texturePose.scale(scale, scale, -scale); + texturePose.translate(offset); + analyser.drawFocusedInTextureArea(graphics, texturePose); + graphics.disableScissor(); } private Vec2 translateUVToXY(float u, float v, ScreenRectangle screenArea) { From 9d52edd84078c5117256d2a89b4d117983dc4aba Mon Sep 17 00:00:00 2001 From: xTracr Date: Wed, 13 May 2026 19:51:46 +0800 Subject: [PATCH 18/33] Extract config inner classes to top level; replace getter delegation with direct field access --- .../com/xtracr/realcamera/KeyMappings.java | 16 +- .../com/xtracr/realcamera/RealCameraCore.java | 14 +- .../com/xtracr/realcamera/api/BindResult.java | 13 +- .../realcamera/compat/DisableHelper.java | 16 +- .../realcamera/compat/LegacyBindingMode.java | 2 +- .../xtracr/realcamera/config/BindTarget.java | 229 +----------------- .../xtracr/realcamera/config/ConfigFile.java | 34 +-- .../realcamera/config/ConfigScreen.java | 6 +- .../realcamera/config/DisableConfig.java | 127 ++++++++++ .../xtracr/realcamera/config/ModConfig.java | 127 +--------- .../realcamera/config/OffsetConfig.java | 45 ++++ .../xtracr/realcamera/config/UVRectangle.java | 20 ++ .../xtracr/realcamera/gui/ModelAnalyser.java | 2 +- .../realcamera/gui/ModelViewScreen.java | 61 +++-- .../xtracr/realcamera/mixin/MixinCamera.java | 2 +- .../realcamera/mixin/MixinGameRenderer.java | 2 +- .../com/xtracr/realcamera/mixin/MixinGui.java | 4 +- .../xtracr/realcamera/mixin/MixinItem.java | 2 +- .../realcamera/mixin/MixinLevelRenderer.java | 4 +- .../realcamera/mixin/MixinLocalPlayer.java | 4 +- .../mixin/MixinStuckInBodyLayer.java | 2 +- .../renderer/BuiltIterableBuffer.java | 2 +- .../renderer/IterableVertexBuffer.java | 3 +- 23 files changed, 304 insertions(+), 433 deletions(-) create mode 100644 common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java create mode 100644 common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java create mode 100644 common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java diff --git a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java index 0fa37732..896b7ef8 100644 --- a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java +++ b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java @@ -19,13 +19,13 @@ public final class KeyMappings { static { MODEL_VIEW_SCREEN = createKeyMapping("modelViewScreen", client -> client.setScreen(new ModelViewScreen())); createKeyMapping("togglePerspective", InputConstants.KEY_F6, _ -> { - boolean enabled = ConfigFile.config().enabled(); + boolean enabled = ConfigFile.config().enabled; ConfigFile.load(); - ConfigFile.config().setEnabled(!enabled); + ConfigFile.config().enabled = !enabled; RealCameraCore.reset(); }); createKeyMapping("toggleAdjustMode", _ -> ConfigFile.config().cycleAdjustMode()); - createKeyMapping("toggleCameraMode", _ -> ConfigFile.config().setClassic(!ConfigFile.config().isClassic())); + createKeyMapping("toggleCameraMode", _ -> ConfigFile.config().isClassic = !ConfigFile.config().isClassic); createKeyMapping("adjustFRONT", _ -> ConfigFile.config().adjustOffsetX(1)); createKeyMapping("adjustBACK", _ -> ConfigFile.config().adjustOffsetX(-1)); createKeyMapping("adjustUP", _ -> ConfigFile.config().adjustOffsetY(1)); @@ -53,11 +53,15 @@ public static void register(Consumer registerer) { public static void handle(Minecraft client) { if (client.player == null) return; - KEY_MAPPINGS.forEach((keyMapping, whenPressed) -> { + boolean anyPressed = false; + for (var entry : KEY_MAPPINGS.entrySet()) { + KeyMapping keyMapping = entry.getKey(); + Consumer whenPressed = entry.getValue(); while (keyMapping.consumeClick()) { whenPressed.accept(client); - ConfigFile.save(); + anyPressed = true; } - }); + } + if (anyPressed) ConfigFile.save(); } } diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index e7ea9f67..4cd9e7ba 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -5,8 +5,8 @@ import com.xtracr.realcamera.api.RealCameraAPI; import com.xtracr.realcamera.compat.DisableHelper; import com.xtracr.realcamera.config.BindTarget; -import com.xtracr.realcamera.config.BindTarget.DisableConfig; import com.xtracr.realcamera.config.ConfigFile; +import com.xtracr.realcamera.config.DisableConfig; import com.xtracr.realcamera.renderer.BuiltIterableBuffer; import com.xtracr.realcamera.renderer.MultiVertexCatcher; import com.xtracr.realcamera.renderer.RoutingSubmitCollector; @@ -45,8 +45,8 @@ public static BindTarget currentTarget() { public static void initialize(Minecraft client, boolean renderLevel) { Entity entity = client.getCameraEntity(); - active = renderLevel && ConfigFile.config().enabled() && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); - rendering = ConfigFile.config().renderModel() && !DisableHelper.RENDER_MODEL.disabled(entity); + active = renderLevel && ConfigFile.config().enabled && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); + rendering = ConfigFile.config().renderModel && !DisableHelper.RENDER_MODEL.disabled(entity); } public static void reset() { @@ -84,8 +84,8 @@ public static void computeCamera(Minecraft client, float partialTicks) { } else { failureFrames++; Player player = client.player; - int retentionFrames = ConfigFile.config().getBindResultRetentionFrames(); - if (!ConfigFile.config().hideBindingFailureMessage() && failureFrames == retentionFrames + 1 && player != null) { + int retentionFrames = ConfigFile.config().binding.bindResultRetentionFrames; + if (!ConfigFile.config().binding.hideFailureMessage && failureFrames == retentionFrames + 1 && player != null) { player.sendSystemMessage(LocUtil.MESSAGE("bindingFailed", LocUtil.MOD_NAME(), LocUtil.MODEL_VIEW_TITLE(), KeyMappings.MODEL_VIEW_SCREEN.getTranslatedKeyMessage())); } if (!lastResult.available() || failureFrames > retentionFrames) { @@ -94,8 +94,8 @@ public static void computeCamera(Minecraft client, float partialTicks) { return; } } - smoothedCamera.lerpPosition(lastResult.getPosition(), 1 - ConfigFile.config().getDisplacementSmoothFactor()); - smoothedCamera.slerpRotation(lastResult.getRotation(), 1 - ConfigFile.config().getRotationSmoothFactor()); + smoothedCamera.lerpPosition(lastResult.getPosition(), 1 - ConfigFile.config().binding.displacementSmoothFactor); + smoothedCamera.slerpRotation(lastResult.getRotation(), 1 - ConfigFile.config().binding.rotationSmoothFactor); } public static void renderCameraEntity(Minecraft client, float partialTicks, SubmitNodeCollector submitNodeCollector, Matrix4f modelView) { diff --git a/common/src/main/java/com/xtracr/realcamera/api/BindResult.java b/common/src/main/java/com/xtracr/realcamera/api/BindResult.java index dd4051a2..61a6fd37 100644 --- a/common/src/main/java/com/xtracr/realcamera/api/BindResult.java +++ b/common/src/main/java/com/xtracr/realcamera/api/BindResult.java @@ -2,6 +2,7 @@ import com.xtracr.realcamera.config.BindTarget; import com.xtracr.realcamera.config.ConfigFile; +import com.xtracr.realcamera.config.OffsetConfig; import com.xtracr.realcamera.util.CameraTransform; import net.minecraft.world.phys.Vec3; import org.joml.Vector3f; @@ -18,7 +19,7 @@ public BindResult(BindTarget target) { } public static BindResult getOrCreate(String name) { - List fixedTargets = ConfigFile.config().getFixedTargetList(); + List fixedTargets = ConfigFile.config().binding.fixedTargetList; BindTarget target = fixedTargets.stream() .filter(t -> t.name().equals(name)) .findFirst() @@ -60,12 +61,12 @@ public BindResult computeCamera(boolean mirrored) { upward = forward.cross(upward.cross(forward)).normalize(); Vec3 left = upward.cross(forward).scale(orientation); rotation.set(left.toVector3f(), upward.toVector3f(), forward.toVector3f()); - BindTarget.OffsetConfig offsets = target.offsets(); - Vector3f offset = new Vector3f(offsets.getZ(), offsets.getY(), offsets.getX()).mul(offsets.getScale()).mul(rotation); + OffsetConfig offsets = target.offsets(); + Vector3f offset = new Vector3f(offsets.z, offsets.y, offsets.x).mul(offsets.scale).mul(rotation); position = position.add(offset.x(), offset.y(), offset.z()); - rotation.rotateLocal(orientation * (float) Math.toRadians(offsets.getYaw()), rotation.m10, rotation.m11, rotation.m12); - rotation.rotateLocal(orientation * (float) Math.toRadians(offsets.getPitch()), rotation.m00, rotation.m01, rotation.m02); - rotation.rotateLocal(orientation * (float) Math.toRadians(offsets.getRoll()), rotation.m20, rotation.m21, rotation.m22); + rotation.rotateLocal(orientation * (float) Math.toRadians(offsets.yaw), rotation.m10, rotation.m11, rotation.m12); + rotation.rotateLocal(orientation * (float) Math.toRadians(offsets.pitch), rotation.m00, rotation.m01, rotation.m02); + rotation.rotateLocal(orientation * (float) Math.toRadians(offsets.roll), rotation.m20, rotation.m21, rotation.m22); return this; } } diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 0be9eb8f..5d4ff186 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -26,15 +26,15 @@ public final class DisableHelper { MAIN_FEATURE = new Entry("mainFeature", player -> player.isSleeping() || player.isSpectator()); RENDER_MODEL = new Entry("renderModel", FALSE, Player::isScoping); RENDER_HANDS = new Entry("renderHands", _ -> RealCameraCore.isRendering()); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSneaking() && player.isCrouching()); - MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSneaking() && player.isCrouching()); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenSwimming() && checkCondition(player, player.isSwimming(), ConfigFile.config().getBindingOutTick())); - MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classicDisableWhenSwimming() && checkCondition(player, player.isSwimming(), ConfigFile.config().getClassicOutTick())); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().bindingDisableWhenCrawling() && checkCondition(player, player.isVisuallyCrawling(), ConfigFile.config().getBindingOutTick())); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenSneaking && player.isCrouching()); + MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classic.disableWhenSneaking && player.isCrouching()); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenSwimming && checkCondition(player, player.isSwimming(), ConfigFile.config().binding.outTick)); + MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classic.disableWhenSwimming && checkCondition(player, player.isSwimming(), ConfigFile.config().classic.outTick)); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenCrawling && checkCondition(player, player.isVisuallyCrawling(), ConfigFile.config().binding.outTick)); MAIN_FEATURE.registerOrInBinding(player -> { Item mainHand = player.getMainHandItem().getItem(); Item offHand = player.getOffhandItem().getItem(); - for (String pattern : ConfigFile.config().getDisableMainFeatureItems()) + for (String pattern : ConfigFile.config().binding.disableMainFeatureItems) if (matchesItemPattern(mainHand, pattern) || matchesItemPattern(offHand, pattern)) return true; return false; @@ -42,7 +42,7 @@ public final class DisableHelper { RENDER_MODEL.registerOrInBinding(player -> { Item mainHand = player.getMainHandItem().getItem(); Item offHand = player.getOffhandItem().getItem(); - for (String pattern : ConfigFile.config().getDisableRenderItems()) + for (String pattern : ConfigFile.config().binding.disableRenderItems) if (matchesItemPattern(mainHand, pattern) || matchesItemPattern(offHand, pattern)) return true; return false; @@ -134,7 +134,7 @@ public void registerOrInBinding(Predicate predicate) { public boolean disabled(Entity cameraEntity) { if (!(cameraEntity instanceof Player player)) return false; - return ConfigFile.config().isClassic() ? predicateInClassic.test(player) : predicateInBinding.test(player); + return ConfigFile.config().isClassic ? predicateInClassic.test(player) : predicateInBinding.test(player); } } } \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java index 5cc4b2fb..4d19147a 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java @@ -22,7 +22,7 @@ public static void register() { @SuppressWarnings("unchecked") private static BindResult computeBindResult(Minecraft client, float partialTicks) { - if (!ConfigFile.config().legacyBindingMode()) return BindResult.EMPTY; + if (!ConfigFile.config().binding.legacyMode) return BindResult.EMPTY; PoseStack poseStack = new PoseStack(); AbstractClientPlayer player = client.player; // WorldRenderer.render diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index 8e91c4b8..87956e33 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -1,16 +1,7 @@ package com.xtracr.realcamera.config; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.xtracr.realcamera.renderer.state.VertexData; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.util.Mth; -import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -62,7 +53,8 @@ private static BindTarget vanillaTarget(String name, int priority, boolean shoul String textureId = name.contains("skin") ? "minecraft:skins/" : "minecraft:textures/entity/player/"; TargetConfig targetConfig = new TargetConfig(0.1875f, 0.2f, 0.1875f, 0.075f, 0.1875f, 0.2f); BindConfig bindConfig = new BindConfig(shouldBind, true, shouldBind, shouldBind); - OffsetConfig offsets = new OffsetConfig().setX(-0.1f); + OffsetConfig offsets = new OffsetConfig(); + offsets.x = -0.1f; DisableConfig playerHead = new DisableConfig("player_head", textureId, false, new UVRectangle[]{new UVRectangle(0, 0, 1.0f, 0.25f)}); DisableConfig dragonHead = new DisableConfig("dragon_head", "minecraft:textures/entity/enderdragon/dragon.png", true, new UVRectangle[0]); DisableConfig[] disableConfigs = new DisableConfig[]{playerHead, dragonHead}; @@ -126,221 +118,4 @@ public void write(FriendlyByteBuf byteBuf) { byteBuf.writeByte(bindFlags); } } - - public static final class OffsetConfig { - private float scale = 1, x = 0, y = 0, z = 0, pitch = 0, yaw = 0, roll = 0; - - public static OffsetConfig read(FriendlyByteBuf byteBuf) { - return new OffsetConfig().setScale(byteBuf.readFloat()).setX(byteBuf.readFloat()).setY(byteBuf.readFloat()).setZ(byteBuf.readFloat()).setPitch(byteBuf.readFloat()).setYaw(byteBuf.readFloat()).setRoll(byteBuf.readFloat()); - } - - public float getScale() { - return scale; - } - - public OffsetConfig setScale(float scale) { - this.scale = scale; - return this; - } - - public float getX() { - return x; - } - - public OffsetConfig setX(float x) { - this.x = Mth.clamp(x, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); - return this; - } - - public float getY() { - return y; - } - - public OffsetConfig setY(float y) { - this.y = Mth.clamp(y, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); - return this; - } - - public float getZ() { - return z; - } - - public OffsetConfig setZ(float z) { - this.z = Mth.clamp(z, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); - return this; - } - - public float getPitch() { - return pitch; - } - - public OffsetConfig setPitch(float pitch) { - this.pitch = Mth.wrapDegrees(pitch); - return this; - } - - public float getYaw() { - return yaw; - } - - public OffsetConfig setYaw(float yaw) { - this.yaw = Mth.wrapDegrees(yaw); - return this; - } - - public float getRoll() { - return roll; - } - - public OffsetConfig setRoll(float roll) { - this.roll = Mth.wrapDegrees(roll); - return this; - } - - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeFloat(scale); - byteBuf.writeFloat(x); - byteBuf.writeFloat(y); - byteBuf.writeFloat(z); - byteBuf.writeFloat(pitch); - byteBuf.writeFloat(yaw); - byteBuf.writeFloat(roll); - } - } - - @JsonAdapter(DisableConfig.Adapter.class) - public static final class DisableConfig { - private final LongOpenHashSet disabledUVs = new LongOpenHashSet(), enabledUVs = new LongOpenHashSet(); - private final String name; - private final String textureId; - private final boolean disableAll; - private final UVRectangle[] rectangles; - - public DisableConfig(String name, String textureId, boolean disableAll, UVRectangle[] rectangles) { - this.name = name; - this.textureId = textureId; - this.disableAll = disableAll; - this.rectangles = rectangles; - } - - public static DisableConfig read(FriendlyByteBuf byteBuf) { - String name = byteBuf.readUtf(); - String textureId = byteBuf.readUtf(); - boolean disableAll = byteBuf.readBoolean(); - UVRectangle[] rectangles = new UVRectangle[byteBuf.readVarInt()]; - for (int i = 0; i < rectangles.length; i++) { - rectangles[i] = UVRectangle.read(byteBuf); - } - return new DisableConfig(name, textureId, disableAll, rectangles); - } - - public String name() { - return name; - } - - public String textureId() { - return textureId; - } - - public boolean disableAll() { - return disableAll; - } - - public UVRectangle[] rectangles() { - return rectangles; - } - - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeUtf(name); - byteBuf.writeUtf(textureId); - byteBuf.writeBoolean(disableAll); - byteBuf.writeVarInt(rectangles.length); - for (UVRectangle rect : rectangles) { - rect.write(byteBuf); - } - } - - public boolean disable(VertexData vertex) { - final float u = vertex.u(), v = vertex.v(); - final long packed = (long) Float.floatToIntBits(u) << 32 | Float.floatToIntBits(v); - if (enabledUVs.contains(packed)) return false; - if (disabledUVs.contains(packed)) return true; - for (UVRectangle rect : rectangles) { - if (!rect.contains(u, v)) continue; - disabledUVs.add(packed); - return true; - } - enabledUVs.add(packed); - return false; - } - - public static final class Adapter extends TypeAdapter { - @Override - public void write(JsonWriter out, DisableConfig value) throws IOException { - out.beginObject(); - out.name("name").value(value.name()); - out.name("textureId").value(value.textureId()); - out.name("disableAll").value(value.disableAll()); - out.name("rectangles"); - out.beginArray(); - for (UVRectangle rect : value.rectangles()) { - out.beginObject(); - out.name("uMin").value(rect.uMin()); - out.name("vMin").value(rect.vMin()); - out.name("uMax").value(rect.uMax()); - out.name("vMax").value(rect.vMax()); - out.endObject(); - } - out.endArray(); - out.endObject(); - } - - @Override - public DisableConfig read(JsonReader in) throws IOException { - in.beginObject(); - in.nextName(); - String name = in.nextString(); - in.nextName(); - String textureId = in.nextString(); - in.nextName(); - boolean disableAll = in.nextBoolean(); - in.nextName(); - in.beginArray(); - ArrayList rectangles = new ArrayList<>(); - while (in.hasNext()) { - in.beginObject(); - in.nextName(); - float uMin = (float) in.nextDouble(); - in.nextName(); - float vMin = (float) in.nextDouble(); - in.nextName(); - float uMax = (float) in.nextDouble(); - in.nextName(); - float vMax = (float) in.nextDouble(); - in.endObject(); - rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); - } - in.endArray(); - in.endObject(); - return new DisableConfig(name, textureId, disableAll, rectangles.toArray(UVRectangle[]::new)); - } - } - } - - public record UVRectangle(float uMin, float vMin, float uMax, float vMax) { - public static UVRectangle read(FriendlyByteBuf byteBuf) { - return new UVRectangle(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - - public boolean contains(float u, float v) { - return u >= uMin && u <= uMax && v >= vMin && v <= vMax; - } - - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeFloat(uMin); - byteBuf.writeFloat(vMin); - byteBuf.writeFloat(uMax); - byteBuf.writeFloat(vMax); - } - } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java index 0325871b..5ef4f551 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java @@ -1,45 +1,51 @@ package com.xtracr.realcamera.config; +import com.google.common.base.Suppliers; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.xtracr.realcamera.RealCamera; import net.minecraft.client.Minecraft; +import org.jspecify.annotations.Nullable; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; +import java.util.function.Supplier; public final class ConfigFile { - private static final ModConfig modConfig = new ModConfig(); private static final String FILE_NAME = RealCamera.MODID + ".json"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - private static final Path PATH; + private final static Supplier path = Suppliers.memoize(ConfigFile::getPath); + @Nullable + private static ModConfig config; - static { + private static Path getPath() { File configDir = new File(Minecraft.getInstance().gameDirectory, "config"); if (!configDir.exists()) configDir.mkdirs(); - PATH = configDir.toPath().resolve(FILE_NAME); + return configDir.toPath().resolve(FILE_NAME); } public static ModConfig config() { - return modConfig; + if (config == null) load(); + return config; } public static void load() { - try (BufferedReader reader = Files.newBufferedReader(PATH)) { - modConfig.set(GSON.fromJson(reader, ModConfig.class)); - modConfig.clamp(); + try (BufferedReader reader = Files.newBufferedReader(path.get())) { + config = GSON.fromJson(reader, ModConfig.class); + config.clamp(); } catch (Exception exception) { - RealCamera.LOGGER.warn("Failed to load " + FILE_NAME); + RealCamera.LOGGER.warn("Failed to load " + FILE_NAME, exception); + config = new ModConfig(); save(); } } public static void save() { - try (BufferedWriter writer = Files.newBufferedWriter(PATH)) { - GSON.toJson(modConfig, writer); + try (BufferedWriter writer = Files.newBufferedWriter(path.get())) { + GSON.toJson(config, writer); } catch (Exception exception) { RealCamera.LOGGER.warn("Failed to save " + FILE_NAME, exception); reset(); @@ -47,9 +53,9 @@ public static void save() { } public static void reset() { - try (BufferedWriter writer = Files.newBufferedWriter(PATH)) { - modConfig.set(new ModConfig()); - GSON.toJson(modConfig, writer); + try (BufferedWriter writer = Files.newBufferedWriter(path.get())) { + config = new ModConfig(); + GSON.toJson(config, writer); } catch (Exception exception) { RealCamera.LOGGER.warn("Failed to reset " + FILE_NAME, exception); } diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 137a18b0..adedb4f8 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -140,16 +140,16 @@ public static Screen create(Screen parent) { binding.addEntry(entryBuilder.startTextDescription(LocUtil.CONFIG_OPTION("toModelViewScreen", LocUtil.MODEL_VIEW_TITLE().withStyle(ChatFormatting.BLUE))) .build()); - binding.addEntry(entryBuilder.startKeyCodeField(LocUtil.CONFIG_OPTION("screenModifierKey", LocUtil.MODEL_VIEW_TITLE()), config.getScreenModifierKey()) + binding.addEntry(entryBuilder.startKeyCodeField(LocUtil.CONFIG_OPTION("screenModifierKey", LocUtil.MODEL_VIEW_TITLE()), InputConstants.getKey(config.binding.screenModifierKey)) .setDefaultValue(InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_LALT)) .setAllowMouse(false) .setAllowModifiers(false) .setKeySaveConsumer(k -> config.binding.screenModifierKey = k.getName()) .build()); - binding.addEntry(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("legacyBindingMode"), config.binding.legacyBindingMode) + binding.addEntry(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("legacyBindingMode"), config.binding.legacyMode) .setDefaultValue(false) .setTooltip(LocUtil.CONFIG_TOOLTIP("legacyBindingMode", LocUtil.MODEL_VIEW_TITLE())) - .setSaveConsumer(b -> config.binding.legacyBindingMode = b) + .setSaveConsumer(b -> config.binding.legacyMode = b) .build()); binding.addEntry(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("adjustOffset"), config.binding.adjustOffset) .setDefaultValue(true) diff --git a/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java b/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java new file mode 100644 index 00000000..4a144e99 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java @@ -0,0 +1,127 @@ +package com.xtracr.realcamera.config; + +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.xtracr.realcamera.renderer.state.VertexData; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import net.minecraft.network.FriendlyByteBuf; + +import java.io.IOException; +import java.util.ArrayList; + +@JsonAdapter(DisableConfig.Adapter.class) +public final class DisableConfig { + private final LongOpenHashSet disabledUVs = new LongOpenHashSet(), enabledUVs = new LongOpenHashSet(); + private final String name; + private final String textureId; + private final boolean disableAll; + private final UVRectangle[] rectangles; + + public DisableConfig(String name, String textureId, boolean disableAll, UVRectangle[] rectangles) { + this.name = name; + this.textureId = textureId; + this.disableAll = disableAll; + this.rectangles = rectangles; + } + + public static DisableConfig read(FriendlyByteBuf byteBuf) { + String name = byteBuf.readUtf(); + String textureId = byteBuf.readUtf(); + boolean disableAll = byteBuf.readBoolean(); + UVRectangle[] rectangles = new UVRectangle[byteBuf.readVarInt()]; + for (int i = 0; i < rectangles.length; i++) rectangles[i] = UVRectangle.read(byteBuf); + return new DisableConfig(name, textureId, disableAll, rectangles); + } + + public String name() { + return name; + } + + public String textureId() { + return textureId; + } + + public boolean disableAll() { + return disableAll; + } + + public UVRectangle[] rectangles() { + return rectangles; + } + + public void write(FriendlyByteBuf byteBuf) { + byteBuf.writeUtf(name); + byteBuf.writeUtf(textureId); + byteBuf.writeBoolean(disableAll); + byteBuf.writeVarInt(rectangles.length); + for (UVRectangle rect : rectangles) rect.write(byteBuf); + } + + public boolean disable(VertexData vertex) { + final float u = vertex.u(), v = vertex.v(); + final long packed = (long) Float.floatToIntBits(u) << 32 | Float.floatToIntBits(v); + if (enabledUVs.contains(packed)) return false; + if (disabledUVs.contains(packed)) return true; + for (UVRectangle rect : rectangles) { + if (!rect.contains(u, v)) continue; + disabledUVs.add(packed); + return true; + } + enabledUVs.add(packed); + return false; + } + + public static final class Adapter extends TypeAdapter { + @Override + public void write(JsonWriter out, DisableConfig value) throws IOException { + out.beginObject(); + out.name("name").value(value.name()); + out.name("textureId").value(value.textureId()); + out.name("disableAll").value(value.disableAll()); + out.name("rectangles"); + out.beginArray(); + for (UVRectangle rect : value.rectangles()) { + out.beginObject(); + out.name("uMin").value(rect.uMin()); + out.name("vMin").value(rect.vMin()); + out.name("uMax").value(rect.uMax()); + out.name("vMax").value(rect.vMax()); + out.endObject(); + } + out.endArray(); + out.endObject(); + } + + @Override + public DisableConfig read(JsonReader in) throws IOException { + in.beginObject(); + in.nextName(); + String name = in.nextString(); + in.nextName(); + String textureId = in.nextString(); + in.nextName(); + boolean disableAll = in.nextBoolean(); + in.nextName(); + in.beginArray(); + ArrayList rectangles = new ArrayList<>(); + while (in.hasNext()) { + in.beginObject(); + in.nextName(); + float uMin = (float) in.nextDouble(); + in.nextName(); + float vMin = (float) in.nextDouble(); + in.nextName(); + float uMax = (float) in.nextDouble(); + in.nextName(); + float vMax = (float) in.nextDouble(); + in.endObject(); + rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); + } + in.endArray(); + in.endObject(); + return new DisableConfig(name, textureId, disableAll, rectangles.toArray(UVRectangle[]::new)); + } + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index c7be2871..1b92df36 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -20,46 +20,12 @@ public final class ModConfig { public Classic classic = new Classic(); public Binding binding = new Binding(); - public void set(ModConfig modConfig) { - enabled = modConfig.enabled; - isClassic = modConfig.isClassic; - dynamicCrosshair = modConfig.dynamicCrosshair; - renderModel = modConfig.renderModel; - adjustStep = modConfig.adjustStep; - classic = modConfig.classic; - binding = modConfig.binding; - } - public void clamp() { adjustStep = Mth.clamp(adjustStep, 0.0, MAX_OFFSET_D); classic.clamp(); binding.clamp(); } - public boolean enabled() { - return enabled; - } - - public void setEnabled(boolean value) { - enabled = value; - } - - public boolean isClassic() { - return isClassic; - } - - public void setClassic(boolean value) { - isClassic = value; - } - - public boolean dynamicCrosshair() { - return dynamicCrosshair; - } - - public boolean renderModel() { - return renderModel; - } - public void cycleAdjustMode() { if (isClassic) classic.adjustMode = classic.adjustMode.cycle(); else binding.adjustOffset = !binding.adjustOffset; @@ -75,8 +41,9 @@ public void adjustOffsetX(int count) { classic.clamp(); } else { BindTarget target = RealCameraCore.currentTarget(); - if (binding.adjustOffset) target.offsets().setX(target.offsets().getX() + count * (float) adjustStep); - else target.offsets().setRoll(target.offsets().getRoll() + count * 100 * (float) adjustStep); + if (binding.adjustOffset) target.offsets().x += count * (float) adjustStep; + else target.offsets().roll += count * 100 * (float) adjustStep; + target.offsets().clamp(); } } @@ -90,8 +57,9 @@ public void adjustOffsetY(int count) { classic.clamp(); } else { BindTarget target = RealCameraCore.currentTarget(); - if (binding.adjustOffset) target.offsets().setY(target.offsets().getY() + count * (float) adjustStep); - else target.offsets().setYaw(target.offsets().getYaw() + count * 100 * (float) adjustStep); + if (binding.adjustOffset) target.offsets().y += count * (float) adjustStep; + else target.offsets().yaw += count * 100 * (float) adjustStep; + target.offsets().clamp(); } } @@ -105,24 +73,12 @@ public void adjustOffsetZ(int count) { classic.clamp(); } else { BindTarget target = RealCameraCore.currentTarget(); - if (binding.adjustOffset) target.offsets().setZ(target.offsets().getZ() + count * (float) adjustStep); - else target.offsets().setPitch(target.offsets().getPitch() + count * 100 * (float) adjustStep); + if (binding.adjustOffset) target.offsets().z += count * (float) adjustStep; + else target.offsets().pitch += count * 100 * (float) adjustStep; + target.offsets().clamp(); } } - // classic - public boolean classicDisableWhenSneaking() { - return classic.disableWhenSneaking; - } - - public boolean classicDisableWhenSwimming() { - return classic.disableWhenSwimming; - } - - public int getClassicOutTick() { - return classic.outTick; - } - public double getClassicX() { return classic.cameraX * classic.scale; } @@ -159,70 +115,7 @@ public float getClassicRoll() { return classic.roll; } - // binding - public InputConstants.Key getScreenModifierKey() { - return InputConstants.getKey(binding.screenModifierKey); - } - - public boolean legacyBindingMode() { - return binding.legacyBindingMode; - } - - public boolean renderStuckObjects() { - return binding.renderStuckObjects; - } - - public boolean hideBindingFailureMessage() { - return binding.hideFailureMessage; - } - - public boolean bindingDisableWhenCrawling() { - return binding.disableWhenCrawling; - } - - public boolean bindingDisableWhenSneaking() { - return binding.disableWhenSneaking; - } - - public boolean bindingDisableWhenSwimming() { - return binding.disableWhenSwimming; - } - - public int getBindingOutTick() { - return binding.outTick; - } - - public int getBindResultRetentionFrames() { - return binding.bindResultRetentionFrames; - } - - public double getDisplacementSmoothFactor() { - return binding.displacementSmoothFactor; - } - - public double getRotationSmoothFactor() { - return binding.rotationSmoothFactor; - } - - public List getDisableMainFeatureItems() { - return binding.disableMainFeatureItems; - } - - public List getDisableRenderItems() { - return binding.disableRenderItems; - } - - public List getFixedTargetList() { - return binding.fixedTargetList; - } - - public List getBindTargetList() { - binding.clamp(); - return binding.targetList; - } - public List getBindTargetList(String textureId) { - binding.clamp(); int activeConfigIndex = binding.activeConfigIndex; List matchedTargets = binding.targetList.stream().filter(target -> textureId.contains(target.textureId())).toList(); if (activeConfigIndex <= 0 || matchedTargets.isEmpty()) return matchedTargets; @@ -291,7 +184,7 @@ public AdjustMode cycle() { public static class Binding { protected static final List defaultDisableRenderItems = List.of("minecraft:filled_map"); public String screenModifierKey = InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_LALT).getName(); - public boolean legacyBindingMode = false; + public boolean legacyMode = false; public boolean adjustOffset = true; public boolean hideFailureMessage = false; public boolean renderStuckObjects = true; diff --git a/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java new file mode 100644 index 00000000..ea9cce32 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java @@ -0,0 +1,45 @@ +package com.xtracr.realcamera.config; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.Mth; + +public final class OffsetConfig { + public float scale = 1; + public float x, y, z, pitch, yaw, roll; + + public OffsetConfig() { + } + + public OffsetConfig(float scale, float x, float y, float z, float pitch, float yaw, float roll) { + this.scale = scale; + this.x = x; + this.y = y; + this.z = z; + this.pitch = pitch; + this.yaw = yaw; + this.roll = roll; + } + + public static OffsetConfig read(FriendlyByteBuf byteBuf) { + return new OffsetConfig(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); + } + + public void clamp() { + x = Mth.clamp(x, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + y = Mth.clamp(y, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + z = Mth.clamp(z, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + pitch = Mth.wrapDegrees(pitch); + yaw = Mth.wrapDegrees(yaw); + roll = Mth.wrapDegrees(roll); + } + + public void write(FriendlyByteBuf byteBuf) { + byteBuf.writeFloat(scale); + byteBuf.writeFloat(x); + byteBuf.writeFloat(y); + byteBuf.writeFloat(z); + byteBuf.writeFloat(pitch); + byteBuf.writeFloat(yaw); + byteBuf.writeFloat(roll); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java b/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java new file mode 100644 index 00000000..1a0708a4 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java @@ -0,0 +1,20 @@ +package com.xtracr.realcamera.config; + +import net.minecraft.network.FriendlyByteBuf; + +public record UVRectangle(float uMin, float vMin, float uMax, float vMax) { + public static UVRectangle read(FriendlyByteBuf byteBuf) { + return new UVRectangle(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); + } + + public boolean contains(float u, float v) { + return u >= uMin && u <= uMax && v >= vMin && v <= vMax; + } + + public void write(FriendlyByteBuf byteBuf) { + byteBuf.writeFloat(uMin); + byteBuf.writeFloat(vMin); + byteBuf.writeFloat(uMax); + byteBuf.writeFloat(vMax); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 606922f7..61651d97 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -6,8 +6,8 @@ import com.mojang.blaze3d.vertex.VertexFormat; import com.xtracr.realcamera.api.BindResult; import com.xtracr.realcamera.config.BindTarget; -import com.xtracr.realcamera.config.BindTarget.DisableConfig; import com.xtracr.realcamera.config.BindTarget.TargetConfig; +import com.xtracr.realcamera.config.DisableConfig; import com.xtracr.realcamera.renderer.BuiltIterableBuffer; import com.xtracr.realcamera.renderer.MultiVertexCatcher; import com.xtracr.realcamera.renderer.state.BuiltModelRecord; diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index bda127fe..667c5e55 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -6,11 +6,9 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.compat.CompatibilityHelper; -import com.xtracr.realcamera.config.BindTarget; -import com.xtracr.realcamera.config.BindTarget.*; -import com.xtracr.realcamera.config.ConfigFile; -import com.xtracr.realcamera.config.ConfigScreen; -import com.xtracr.realcamera.config.ModConfig; +import com.xtracr.realcamera.config.*; +import com.xtracr.realcamera.config.BindTarget.BindConfig; +import com.xtracr.realcamera.config.BindTarget.TargetConfig; import com.xtracr.realcamera.gui.components.CycleIconButton; import com.xtracr.realcamera.gui.components.DoubleSlider; import com.xtracr.realcamera.gui.components.NumberField; @@ -54,7 +52,7 @@ public final class ModelViewScreen extends Screen { private final int xSize = 450, ySize = 206, middleWidth = xSize - 200, widgetWidth = (xSize - middleWidth) / 4 - 8, widgetHeight = 18; private int x, y, page = 0; - private InputConstants.Key modifierKey = ConfigFile.config().getScreenModifierKey(); + private InputConstants.Key modifierKey = InputConstants.getKey(ConfigFile.config().binding.screenModifierKey); private boolean initialized; private int modelScale = 80, textureScale = 80, layers = 0, selectionRadius = 10; private double modelX, modelY, textureX, textureY, clickedX = -1, clickedY = -1; @@ -146,7 +144,7 @@ protected void init() { super.init(); x = (width - xSize) / 2; y = (height - ySize) / 2; - modifierKey = ConfigFile.config().getScreenModifierKey(); + modifierKey = InputConstants.getKey(ConfigFile.config().binding.screenModifierKey); initWidgets(page); if (!initialized) loadBindTarget(RealCameraCore.currentTarget()); initialized = true; @@ -378,8 +376,8 @@ private void initRightWidgets() { } } else { widgetsPerPage = 8; - List fixedTargetList = ConfigFile.config().getFixedTargetList().stream().filter(target -> target.name().equals(RealCameraCore.currentTarget().name())).toList(); - List targetList = ConfigFile.config().getBindTargetList(); + List fixedTargetList = ConfigFile.config().binding.fixedTargetList.stream().filter(target -> target.name().equals(RealCameraCore.currentTarget().name())).toList(); + List targetList = ConfigFile.config().binding.targetList; final int fixedTargetCount = fixedTargetList.size(); size = fixedTargetCount + targetList.size(); for (int i = page * widgetsPerPage; i < Math.min((page + 1) * widgetsPerPage, size); i++) { @@ -457,7 +455,7 @@ public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX ModelAnalyser analyser = new ModelAnalyser(); BindTarget target = genBindTarget(); - target.offsets().setScale(target.offsets().getScale() * modelScale); + target.offsets().scale *= modelScale; String textureId = toggleCategoryButton.getValue() == Category.DISABLE ? disabledIdField.getValue() : ""; Set hiddenNames = hiddenNameMap.getOrDefault(nameField.getValue(), Set.of()); List modelRecords = captureRotatedEntity(analyser, target, minecraft.player); @@ -621,19 +619,19 @@ private void loadBindTarget(BindTarget target) { bindYButton.setValue(target.bindConfig().bindY() ? 0 : 1); bindZButton.setValue(target.bindConfig().bindZ() ? 0 : 1); bindRotButton.setValue(target.bindConfig().bindRotation() ? 0 : 1); - scaleField.setNumber(target.offsets().getScale()); - offsetXSlider.setDouble(target.offsets().getX()); - offsetXField.setNumber(target.offsets().getX()); - offsetYSlider.setDouble(target.offsets().getY()); - offsetYField.setNumber(target.offsets().getY()); - offsetZSlider.setDouble(target.offsets().getZ()); - offsetZField.setNumber(target.offsets().getZ()); - offsetPitchSlider.setDouble(target.offsets().getPitch()); - offsetPitchField.setNumber(target.offsets().getPitch()); - offsetYawSlider.setDouble(target.offsets().getYaw()); - offsetYawField.setNumber(target.offsets().getYaw()); - offsetRollSlider.setDouble(target.offsets().getRoll()); - offsetRollField.setNumber(target.offsets().getRoll()); + scaleField.setNumber(target.offsets().scale); + offsetXSlider.setDouble(target.offsets().x); + offsetXField.setNumber(target.offsets().x); + offsetYSlider.setDouble(target.offsets().y); + offsetYField.setNumber(target.offsets().y); + offsetZSlider.setDouble(target.offsets().z); + offsetZField.setNumber(target.offsets().z); + offsetPitchSlider.setDouble(target.offsets().pitch); + offsetPitchField.setNumber(target.offsets().pitch); + offsetYawSlider.setDouble(target.offsets().yaw); + offsetYawField.setNumber(target.offsets().yaw); + offsetRollSlider.setDouble(target.offsets().roll); + offsetRollField.setNumber(target.offsets().roll); disableConfigs.clear(); disableConfigs.addAll(List.of(target.disableConfigs())); } @@ -641,14 +639,15 @@ private void loadBindTarget(BindTarget target) { private BindTarget genBindTarget() { TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); - OffsetConfig offsets = new OffsetConfig() - .setScale(scaleField.getNumber()) - .setX(toggleSliderButton.getValue() == 0 ? (float) offsetXSlider.getDouble() : offsetXField.getNumber()) - .setY(toggleSliderButton.getValue() == 0 ? (float) offsetYSlider.getDouble() : offsetYField.getNumber()) - .setZ(toggleSliderButton.getValue() == 0 ? (float) offsetZSlider.getDouble() : offsetZField.getNumber()) - .setPitch(toggleSliderButton.getValue() == 0 ? (float) offsetPitchSlider.getDouble() : offsetPitchField.getNumber()) - .setYaw(toggleSliderButton.getValue() == 0 ? (float) offsetYawSlider.getDouble() : offsetYawField.getNumber()) - .setRoll(toggleSliderButton.getValue() == 0 ? (float) offsetRollSlider.getDouble() : offsetRollField.getNumber()); + OffsetConfig offsets = new OffsetConfig( + scaleField.getNumber(), + toggleSliderButton.getValue() == 0 ? (float) offsetXSlider.getDouble() : offsetXField.getNumber(), + toggleSliderButton.getValue() == 0 ? (float) offsetYSlider.getDouble() : offsetYField.getNumber(), + toggleSliderButton.getValue() == 0 ? (float) offsetZSlider.getDouble() : offsetZField.getNumber(), + toggleSliderButton.getValue() == 0 ? (float) offsetPitchSlider.getDouble() : offsetPitchField.getNumber(), + toggleSliderButton.getValue() == 0 ? (float) offsetYawSlider.getDouble() : offsetYawField.getNumber(), + toggleSliderButton.getValue() == 0 ? (float) offsetRollSlider.getDouble() : offsetRollField.getNumber() + ); DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toArray(UVRectangle[]::new)); DisableConfig[] disableConfigArray = disableConfigs.toArray(new DisableConfig[0]); for (int i = 0; i < disableConfigArray.length; i++) { diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java index dae4e34b..e9d20c15 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java @@ -61,7 +61,7 @@ public abstract class MixinCamera { if (!RealCameraCore.isActive()) return; ModConfig config = ConfigFile.config(); Vec3 startVec = position; - if (config.isClassic()) { + if (config.isClassic) { double scale = entity instanceof LivingEntity livingEntity ? livingEntity.getScale() : 1; Vec3 offset = new Vec3(config.getClassicX(), config.getClassicY(), -config.getClassicZ()).scale(scale); Vec3 center = new Vec3(config.getCenterX(), config.getCenterY(), -config.getCenterZ()).scale(scale); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java index feafd99b..897705e6 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java @@ -28,7 +28,7 @@ public abstract class MixinGameRenderer { float partialTicks = deltaTracker.getGameTimeDeltaPartialTick(true); CompatibilityHelper.NEA_setDeltaTick(partialTicks); RealCameraCore.initialize(minecraft, renderLevel); - if (RealCameraCore.isActive() && !ConfigFile.config().isClassic()) { + if (RealCameraCore.isActive() && !ConfigFile.config().isClassic) { minecraft.getEntityRenderDispatcher().prepare(mainCamera, minecraft.crosshairPickEntity); RealCameraCore.computeCamera(minecraft, partialTicks); } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java index d5a25a84..5f1ccacd 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java @@ -15,7 +15,7 @@ public abstract class MixinGui { @Inject(method = "extractCrosshair", at = @At("HEAD")) private void realcamera$atRenderCrosshairHEAD(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { graphics.pose().pushMatrix(); CrosshairUtil.translateMatrices(graphics.pose()); } @@ -23,7 +23,7 @@ public abstract class MixinGui { @Inject(method = "extractCrosshair", at = @At("RETURN")) private void realcamera$atRenderCrosshairRETURN(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker, CallbackInfo ci) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { graphics.pose().popMatrix(); } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java index 2d99dcb1..1ae0dbd8 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinItem.java @@ -19,7 +19,7 @@ public abstract class MixinItem { @Inject(method = "getPlayerPOVHitResult", at = @At("HEAD"), cancellable = true) private static void realcamera$coverHitResult(Level level, Player player, ClipContext.Fluid fluid, CallbackInfoReturnable cir) { - if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { double interactionRange = player.blockInteractionRange(); Pair fromAndTo = RaycastUtil.getFromAndTo(player, interactionRange * interactionRange, 1.0f); cir.setReturnValue(level.clip(new ClipContext(fromAndTo.getFirst(), fromAndTo.getSecond(), ClipContext.Block.OUTLINE, fluid, player))); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java index c293afb3..7defc800 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java @@ -38,7 +38,7 @@ public abstract class MixinLevelRenderer { @Inject(method = "renderLevel", at = @At("HEAD")) private void realcamera$atRenderLevelHead(GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker, boolean renderOutline, CameraRenderState cameraState, Matrix4fc modelViewMatrix, GpuBufferSlice terrainFog, Vector4f fogColor, boolean shouldRenderSky, ChunkSectionsToRender chunkSectionsToRender, CallbackInfo ci) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { CrosshairUtil.update(minecraft, cameraState.pos, modelViewMatrix, cameraState.projectionMatrix); } } @@ -50,7 +50,7 @@ public abstract class MixinLevelRenderer { TickRateManager tickManager = minecraft.level.tickRateManager(); float partialTicks = minecraft.getDeltaTracker().getGameTimeDeltaPartialTick(!tickManager.isEntityFrozen(entity)); CameraRenderState cameraState = levelRenderState.cameraRenderState; - if (!ConfigFile.config().isClassic()) + if (!ConfigFile.config().isClassic) RealCameraCore.renderCameraEntity(minecraft, partialTicks, output, cameraState.viewRotationMatrix); else { Vec3 cameraPos = cameraState.pos; diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java index 307d0788..1e69cefa 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java @@ -37,7 +37,7 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { @WrapOperation(method = "pick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;")) private static @Nullable EntityHitResult realcamera$wrapGetEntityHitResult(Entity except, Vec3 from, Vec3 to, AABB box, Predicate matching, double maxValue, Operation original, Entity cameraEntity, double blockInteractionRange, double entityInteractionRange, float partialTicks) { - if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { double interactionRange = Math.max(blockInteractionRange, entityInteractionRange); Pair fromAndTo = RaycastUtil.getFromAndTo(cameraEntity, interactionRange * interactionRange, partialTicks); Vec3 newFrom = fromAndTo.getFirst(); @@ -58,7 +58,7 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { @Override public @NonNull HitResult pick(double maxDistance, float partialTicks, boolean includeFluids) { - if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { Pair fromAndTo = RaycastUtil.getFromAndTo(this, maxDistance * maxDistance, partialTicks); return level().clip(new ClipContext(fromAndTo.getFirst(), fromAndTo.getSecond(), ClipContext.Block.OUTLINE, includeFluids ? ClipContext.Fluid.ANY : ClipContext.Fluid.NONE, this)); } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java index c0cba4bd..fcbaea64 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinStuckInBodyLayer.java @@ -16,7 +16,7 @@ public abstract class MixinStuckInBodyLayer { @Inject(method = "submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/renderer/entity/state/AvatarRenderState;FF)V", at = @At("HEAD"), cancellable = true) private void realcamera$cancelRender(PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, AvatarRenderState state, float yRot, float xRot, CallbackInfo ci) { - if (RealCameraCore.isRendering() && state.id == Minecraft.getInstance().getCameraEntity().getId() && !ConfigFile.config().isClassic() && !ConfigFile.config().renderStuckObjects()) { + if (RealCameraCore.isRendering() && state.id == Minecraft.getInstance().getCameraEntity().getId() && !ConfigFile.config().isClassic && !ConfigFile.config().binding.renderStuckObjects) { ci.cancel(); } } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index a2f817a7..2f307a72 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -21,7 +21,7 @@ public static BuiltIterableBuffer buildFrom(RenderType renderType, MeshData mesh for (int i = 0; i < uvsLength; i++) { if (uvs[i] == null) continue; int primitiveIndex = cache.getInt(uvs[i]); - if (primitiveIndex == -1) continue; + if (primitiveIndex == -1 || primitiveIndex >= vertexBuffer.primitiveCount) continue; VertexData[] primitive = vertexBuffer.readPrimitiveAt(primitiveIndex); if (!VertexData.containsUV(primitive, uvs[i].u(), uvs[i].v())) continue; primitives[i] = primitive; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index ddcfa043..8ade0765 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -20,9 +20,10 @@ public final class IterableVertexBuffer implements Iterable { private static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; private static final float NORMAL_SCALE = 1.0f / 127.0f; - public final int vertexSize, vertexCount, primitiveLength, primitiveStride, primitiveCount; + public final int vertexCount, primitiveCount; private final Iterable primitives; private final ByteBuffer buffer; + private final int vertexSize, primitiveLength, primitiveStride; private final int positionOffset, colorOffset, uvOffset, overlayOffset, lightOffset, normalOffset; private final boolean hasPosition, hasColor, hasUV, hasOverlay, hasLight, hasNormal, fullFormat; private final boolean startWithFirst; From aa91a985965f46c043ddfc2222821943b76fbf61 Mon Sep 17 00:00:00 2001 From: xTracr Date: Thu, 14 May 2026 14:19:39 +0800 Subject: [PATCH 19/33] Create NumberWidgetPair and optimize polyhedron vertex lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -- Replace O(n²) haveCommonVertex with LongOpenHashSet quantized-key lookup for -- polyhedron expansion. Extract MutableVertex from VertexData inner class. -- Create NumberWidgetPair combining DoubleSlider and NumberField for offset -- controls. Replace varargs MathUtil.floor/ceil with fixed arity overloads. -- Rename DoubleSlider getDouble/setDouble to getNumber/setNumber. --- .../xtracr/realcamera/gui/ModelAnalyser.java | 45 ++-- .../realcamera/gui/ModelViewScreen.java | 232 +++++++----------- .../gui/components/CycleIconButton.java | 4 +- .../gui/components/DoubleSlider.java | 6 +- .../gui/components/NumberField.java | 32 +-- .../gui/components/NumberWidgetPair.java | 133 ++++++++++ .../renderer/IterableVertexBuffer.java | 2 +- .../renderer/state/MutableVertex.java | 67 +++++ .../realcamera/renderer/state/VertexData.java | 66 ----- .../com/xtracr/realcamera/util/MathUtil.java | 26 +- 10 files changed, 352 insertions(+), 261 deletions(-) create mode 100644 common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java create mode 100644 common/src/main/java/com/xtracr/realcamera/renderer/state/MutableVertex.java diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 61651d97..d4339b85 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -12,6 +12,7 @@ import com.xtracr.realcamera.renderer.MultiVertexCatcher; import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; @@ -34,12 +35,11 @@ public final class ModelAnalyser { private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final Set UNFOCUSABLE_RENDER_TYPES = ImmutableSet.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; - private static final int z1 = 210, z2 = z1 + 10; - private final List focusedPolyhedron = new ArrayList<>(); + private final List focusedPolyhedron = new ArrayList<>(); private static final int z1 = 210, z2 = z1 + 10; private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; @Nullable - private BuiltModelRecord focusedRecord, currentRecord; + private BuiltModelRecord focusedRecord; public static void applyDisableConfigs(List modelRecords, BindTarget target, String textureId, Set hiddenNames) { for (int i = 0; i < modelRecords.size(); i++) { @@ -67,14 +67,11 @@ public static void applyDisableConfigs(List modelRecords, Bind } } - private static boolean haveCommonVertex(VertexData[] p1, List primitives) { - final float precision = 1e-5f; - for (VertexData[] p2 : primitives) - for (VertexData v1 : p1) - for (VertexData v2 : p2) - if (Math.abs(v1.x() - v2.x()) < precision && Math.abs(v1.y() - v2.y()) < precision && Math.abs(v1.z() - v2.z()) < precision) - return true; - return false; + private static long quantizedKey(VertexData vertex) { + int x = Math.round(vertex.x() * 1e5f); + int y = Math.round(vertex.y() * 1e5f); + int z = Math.round(vertex.z() * 1e5f); + return ((long) x & 0x1FFFFF) | (((long) y & 0x1FFFFF) << 21) | (((long) z & 0x1FFFFF) << 42); } public VertexData[][] getFocusedPolyhedron() { @@ -136,7 +133,7 @@ public void computeFocusedOnModel(List modelRecords, int minX, } } if (sortByZ.isEmpty()) return; - sortByZ.sort(Comparator.comparingDouble((ZEntry entry) -> -entry.z())); + sortByZ.sort(Comparator.comparingDouble(ZEntry::z).reversed()); focusedRecord = sortByZ.getFirst().record(); while (!sortByZ.isEmpty()) { VertexData[] first = sortByZ.getFirst().primitive(); @@ -168,19 +165,22 @@ public void computeFocusedPolyhedron() { } } if (focusedIndex == -1) return; - List polyhedron = new ArrayList<>(); - polyhedron.add(focused); + LongOpenHashSet vertexSet = new LongOpenHashSet(); + for (VertexData vertex : focused) vertexSet.add(quantizedKey(vertex)); boolean[] visited = new boolean[primitives.length]; visited[focusedIndex] = true; boolean added; do { added = false; for (int i = 0; i < primitives.length; i++) { - VertexData[] primitive = primitives[i]; - if (visited[i] | !haveCommonVertex(primitive, polyhedron)) continue; - polyhedron.add(primitive); - visited[i] = true; - added = true; + if (visited[i]) continue; + for (VertexData vertex : primitives[i]) { + if (!vertexSet.contains(quantizedKey(vertex))) continue; + visited[i] = true; + for (VertexData vertex2 : primitives[i]) vertexSet.add(quantizedKey(vertex2)); + added = true; + break; + } } } while (added); for (int i = focusedIndex + 1; i < primitives.length && visited[i]; i++) @@ -258,7 +258,7 @@ private void computeRecord(BuiltIterableBuffer builtBuffer, List priorityField, focusedRectWidgetNumberField; private NumberField forwardUField, forwardVField, upwardUField, upwardVField, posUField, posVField; private NumberField uMinField, vMinField, uMaxField, vMaxField; - private NumberField offsetXField, offsetYField, offsetZField, offsetPitchField, offsetYawField, offsetRollField, scaleField, depthField; + private NumberField scaleField, depthField; private final List disableConfigs = new ArrayList<>(); private final List rectWidgets = new ArrayList<>(); private final Map> hiddenNameMap = new HashMap<>(); @@ -79,52 +83,39 @@ public final class ModelViewScreen extends Screen { private final CycleIconButton bindYButton = new CycleIconButton(16, 16, 0, 2); private final CycleIconButton bindZButton = new CycleIconButton(16, 16, 1, 2); private final CycleIconButton bindRotButton = new CycleIconButton(16, 16, 1, 2); - private final DoubleSlider entityPitchSlider = createSlider("pitch", widgetWidth * 2 + 4, -90.0, 90.0); - private final DoubleSlider entityYawSlider = createSlider("yaw", widgetWidth * 2 + 4, -60.0, 60.0); - private final DoubleSlider offsetXSlider = createSlider("offsetX", widgetWidth * 2 - 18, ModConfig.MIN_OFFSET_D, ModConfig.MAX_OFFSET_D); - private final DoubleSlider offsetYSlider = createSlider("offsetY", widgetWidth * 2 - 18, ModConfig.MIN_OFFSET_D, ModConfig.MAX_OFFSET_D); - private final DoubleSlider offsetZSlider = createSlider("offsetZ", widgetWidth * 2 - 18, ModConfig.MIN_OFFSET_D, ModConfig.MAX_OFFSET_D); - private final DoubleSlider offsetPitchSlider = createSlider("pitch", widgetWidth * 2 - 18, -180.0, 180.0); - private final DoubleSlider offsetYawSlider = createSlider("yaw", widgetWidth * 2 - 18, -180.0, 180.0); - private final DoubleSlider offsetRollSlider = createSlider("roll", widgetWidth * 2 - 18, -180.0, 180.0); + private final DoubleSlider entityPitchSlider = createSlider("pitch", wideWidgetWidth, -90.0, 90.0); + private final DoubleSlider entityYawSlider = createSlider("yaw", wideWidgetWidth, -60.0, 60.0); + private final NumberWidgetPair offsetXPair = new NumberWidgetPair(font, "offsetX", compactWidgetWidth, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + private final NumberWidgetPair offsetYPair = new NumberWidgetPair(font, "offsetY", compactWidgetWidth, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + private final NumberWidgetPair offsetZPair = new NumberWidgetPair(font, "offsetZ", compactWidgetWidth, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + private final NumberWidgetPair offsetPitchPair = new NumberWidgetPair(font, "pitch", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); + private final NumberWidgetPair offsetYawPair = new NumberWidgetPair(font, "yaw", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); + private final NumberWidgetPair offsetRollPair = new NumberWidgetPair(font, "roll", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); + private final List widgetPairs = List.of(offsetXPair, offsetYPair, offsetZPair, offsetPitchPair, offsetYawPair, offsetRollPair); private final CycleButton selectingButton = createCyclingButtonBuilder(ImmutableSortedMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("forwardVector").withStyle(ChatFormatting.GREEN), 1, LocUtil.MODEL_VIEW_WIDGET("upwardVector").withStyle(ChatFormatting.RED), 2, LocUtil.MODEL_VIEW_WIDGET("position").withStyle(ChatFormatting.BLUE)), 0) .withTooltip(_ -> createTooltip("selecting", modifierKey.getDisplayName(), modifierKey.getDisplayName())) - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selecting")); + .create(0, 0, wideWidgetWidth, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selecting")); private final CycleButton disableModeButton = createCyclingButtonBuilder(ImmutableMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("all").withStyle(ChatFormatting.GREEN), 1, LocUtil.MODEL_VIEW_WIDGET("part").withStyle(ChatFormatting.BLUE)), 0) .withTooltip(_ -> createTooltip("disableMode", modifierKey.getDisplayName())) - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("disableMode")); + .create(0, 0, wideWidgetWidth, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("disableMode")); private final CycleButton selectionModeButton = createCyclingButtonBuilder(ImmutableSortedMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("single"), 1, LocUtil.MODEL_VIEW_WIDGET("multiple"), 2, LocUtil.MODEL_VIEW_WIDGET("range").withStyle(ChatFormatting.BLUE)), 0) .withTooltip(_ -> createTooltip("selectionMode", modifierKey.getDisplayName(), modifierKey.getDisplayName())) - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selectionMode")); + .create(0, 0, wideWidgetWidth, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("selectionMode")); private final CycleButton toggleSliderButton = createCyclingButtonBuilder(ImmutableMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("toggleSliderToField"), 1, LocUtil.MODEL_VIEW_WIDGET("toggleFieldToSlider")), 0) - .withTooltip(_ -> createTooltip("toggleSlider")) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, CommonComponents.EMPTY, (_, i) -> { - if (i == 1) { - offsetXField.setNumber((float) offsetXSlider.getDouble()); - offsetYField.setNumber((float) offsetYSlider.getDouble()); - offsetZField.setNumber((float) offsetZSlider.getDouble()); - offsetPitchField.setNumber((float) offsetPitchSlider.getDouble()); - offsetYawField.setNumber((float) offsetYawSlider.getDouble()); - offsetRollField.setNumber((float) offsetRollSlider.getDouble()); - } else { - offsetXSlider.setDouble(offsetXField.getNumber()); - offsetYSlider.setDouble(offsetYField.getNumber()); - offsetZSlider.setDouble(offsetZField.getNumber()); - offsetPitchSlider.setDouble(offsetPitchField.getNumber()); - offsetYawSlider.setDouble(offsetYawField.getNumber()); - offsetRollSlider.setDouble(offsetRollField.getNumber()); - } + .create(0, 0, wideWidgetWidth, widgetHeight, CommonComponents.EMPTY, (_, i) -> { + boolean useSlider = i == 0; + for (NumberWidgetPair pair : widgetPairs) pair.syncAndSwitch(useSlider); initWidgets(page); }); private final CycleButton toggleCategoryButton = createCyclingButtonBuilder(ImmutableSortedMap.of( @@ -133,7 +124,7 @@ public final class ModelViewScreen extends Screen { Category.DISABLE, LocUtil.MODEL_VIEW_WIDGET(Category.DISABLE.next().id)), Category.CONFIGS) .withTooltip(category -> createTooltip(category.next().id)) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 - 18, widgetHeight, CommonComponents.EMPTY, (_, _) -> initWidgets(0)); + .create(0, 0, compactWidgetWidth, widgetHeight, CommonComponents.EMPTY, (_, _) -> initWidgets(0)); public ModelViewScreen() { super(LocUtil.MODEL_VIEW_TITLE()); @@ -168,9 +159,9 @@ private void initWidgets(int page) { addRenderableWidget(showTextureButton).setPosition(x + (xSize - middleWidth) / 2 + 4, y + 4); addRenderableWidget(pauseButton).setPosition(x + (xSize + middleWidth) / 2 - 38, y + 4); addRenderableWidget(new SimpleIconButton(x + (xSize + middleWidth) / 2 - 20, y + 4, 16, 16, 0, 0, _ -> { - modelScale = textureScale = 80; - entityYawSlider.setDouble(0); - entityPitchSlider.setDouble(0); + modelScale = textureScale = DEFAULT_SCALE; + entityYawSlider.setNumber(0); + entityPitchSlider.setNumber(0); modelX = modelY = textureX = textureY = 0; xRot = yRot = 0; layers = 0; @@ -186,19 +177,13 @@ private void initLeftWidgets() { upwardVField = createFloatField(widgetWidth, 0, upwardVField); posUField = createFloatField(widgetWidth, 0, posUField); posVField = createFloatField(widgetWidth, 0, posVField); - textureIdField = createTextField(widgetWidth * 2 + 4, 1024, textureIdField); - disabledIdField = createTextField(widgetWidth * 2 + 4, 1024, disabledIdField); + textureIdField = createTextField(wideWidgetWidth, 1024, textureIdField); + disabledIdField = createTextField(wideWidgetWidth, 1024, disabledIdField); focusedRectWidgetNumberField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, focusedRectWidgetNumberField).setMin(0).setMax(rectWidgets.size()); uMinField = createFloatField(widgetWidth * 2 - 24, 0, uMinField).setMin(-1f).setMax(2f); uMaxField = createFloatField(widgetWidth * 2 - 24, 0, uMaxField).setMin(-1f).setMax(2f); vMinField = createFloatField(widgetWidth * 2 - 24, 0, vMinField).setMin(-1f).setMax(2f); vMaxField = createFloatField(widgetWidth * 2 - 24, 0, vMaxField).setMin(-1f).setMax(2f); - offsetXField = createFloatField(widgetWidth * 2 - 20, 0, offsetXField).setMin(ModConfig.MIN_OFFSET_F).setMax(ModConfig.MAX_OFFSET_F); - offsetYField = createFloatField(widgetWidth * 2 - 20, 0, offsetYField).setMin(ModConfig.MIN_OFFSET_F).setMax(ModConfig.MAX_OFFSET_F); - offsetZField = createFloatField(widgetWidth * 2 - 20, 0, offsetZField).setMin(ModConfig.MIN_OFFSET_F).setMax(ModConfig.MAX_OFFSET_F); - offsetPitchField = createFloatField(widgetWidth * 2 - 20, 0, offsetPitchField).setMin(-180.0f).setMax(180.0f); - offsetYawField = createFloatField(widgetWidth * 2 - 20, 0, offsetYawField).setMin(-180.0f).setMax(180.0f); - offsetRollField = createFloatField(widgetWidth * 2 - 20, 0, offsetRollField).setMin(-180.0f).setMax(180.0f); scaleField = createFloatField(widgetWidth, 1.0f, scaleField).setMax(64.0f); depthField = createFloatField(widgetWidth, 0.2f, depthField).setMax(16.0f); GridLayout grid = new GridLayout(); @@ -221,40 +206,19 @@ private void initLeftWidgets() { rows.addChild(textureIdField, 2, smallSettings).setTooltip(createTooltip("textureId")); } case PREVIEW -> { - boolean useSliderOffset = toggleSliderButton.getValue() == 0; rows.addChild(toggleSliderButton, 2); - LayoutSettings sliderSettings = grid.newCellSettings().padding(-20, 2, 0, 0); - LayoutSettings fieldSettings = grid.newCellSettings().padding(-17, 3, 1, 1); + LayoutSettings numericControlSettings = grid.newCellSettings().padding(-20, 2, 0, 0); rows.addChild(bindXButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetXSlider, sliderSettings); - else rows.addChild(offsetXField, fieldSettings); + rows.addChild(offsetXPair, numericControlSettings); rows.addChild(bindYButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetYSlider, sliderSettings); - else rows.addChild(offsetYField, fieldSettings); + rows.addChild(offsetYPair, numericControlSettings); rows.addChild(bindZButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetZSlider, sliderSettings); - else rows.addChild(offsetZField, fieldSettings); + rows.addChild(offsetZPair, numericControlSettings); rows.addChild(bindRotButton, smallSettings).setTooltip(createTooltip("bindButtons")); - if (useSliderOffset) rows.addChild(offsetPitchSlider, sliderSettings); - else rows.addChild(offsetPitchField, fieldSettings); - if (useSliderOffset) rows.addChild(offsetYawSlider, 2, grid.newCellSettings().padding(26, 2, 0, 0)); - else rows.addChild(offsetYawField, 2, grid.newCellSettings().padding(29, 3, 1, 1)); - rows.addChild(new SimpleIconButton(0, 0, _ -> { - offsetXField.setNumber(0f); - offsetYField.setNumber(0f); - offsetZField.setNumber(0f); - offsetPitchField.setNumber(0f); - offsetYawField.setNumber(0f); - offsetRollField.setNumber(0f); - offsetXSlider.setDouble(0); - offsetYSlider.setDouble(0); - offsetZSlider.setDouble(0); - offsetPitchSlider.setDouble(0); - offsetYawSlider.setDouble(0); - offsetRollSlider.setDouble(0); - }), smallSettings); - if (useSliderOffset) rows.addChild(offsetRollSlider, sliderSettings); - else rows.addChild(offsetRollField, fieldSettings); + rows.addChild(offsetPitchPair, numericControlSettings); + rows.addChild(offsetYawPair, 2, grid.newCellSettings().padding(26, 2, 0, 0)); + rows.addChild(new SimpleIconButton(0, 0, _ -> widgetPairs.forEach(pair -> pair.setNumber(0))), smallSettings); + rows.addChild(offsetRollPair, numericControlSettings); rows.addChild(scaleField, smallSettings).setTooltip(createTooltip("scale")); rows.addChild(depthField, smallSettings).setTooltip(createTooltip("depth")); } @@ -309,14 +273,14 @@ else if (index > 0 && index <= rectWidgets.size()) { initWidgets(page); })); rows.addChild(priorityField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, priorityField), smallSettings).setTooltip(createTooltip("priority")); - rows.addChild(nameField = createTextField(widgetWidth * 2 + 4, 20, nameField), 2, smallSettings).setTooltip(createTooltip("targetName")); + rows.addChild(nameField = createTextField(wideWidgetWidth, 20, nameField), 2, smallSettings).setTooltip(createTooltip("targetName")); grid.arrangeElements(); FrameLayout.alignInRectangle(grid, x, y + 2, x + (xSize - middleWidth) / 2 - 4, y + ySize, 0, 0); grid.visitWidgets(this::addRenderableWidget); } private void initRightWidgets() { - disabledNameField = createTextField(widgetWidth * 2 - 18, 20, disabledNameField); + disabledNameField = createTextField(compactWidgetWidth, 20, disabledNameField); GridLayout grid = new GridLayout(); grid.defaultCellSetting().padding(4, 2, 0, 0); LayoutSettings smallSettings = grid.newCellSettings().padding(5, 3, 1, 1); @@ -360,7 +324,7 @@ private void initRightWidgets() { else hiddenNames.add(config.name()); }) .setPosition(x + (xSize + middleWidth) / 2 - 20, y + 5 + (widgetHeight + 2) * (2 + i % widgetsPerPage)); - rows.addChild(createButton(LocUtil.literal(config.name()), widgetWidth * 2 - 18, _ -> { + rows.addChild(createButton(LocUtil.literal(config.name()), compactWidgetWidth, _ -> { disabledNameField.setValue(config.name()); disabledIdField.setValue(config.textureId()); disableModeButton.setValue(config.disableAll() ? 0 : 1); @@ -383,7 +347,7 @@ private void initRightWidgets() { for (int i = page * widgetsPerPage; i < Math.min((page + 1) * widgetsPerPage, size); i++) { BindTarget target = i < fixedTargetCount ? fixedTargetList.get(i) : targetList.get(i - fixedTargetCount); String name = target.name(); - rows.addChild(createButton(LocUtil.literal(name), widgetWidth * 2 - 18, _ -> loadBindTarget(target)), 3) + rows.addChild(createButton(LocUtil.literal(name), compactWidgetWidth, _ -> loadBindTarget(target)), 3) .setTooltip(Tooltip.create(name.equals(RealCameraCore.currentTarget().name()) ? LocUtil.literal(name + "\n").append(LocUtil.MODEL_VIEW_WIDGET("currentConfig")) : LocUtil.literal(name)) @@ -406,18 +370,6 @@ private void initRightWidgets() { addRenderableWidget(new SimpleIconButton(x + xSize - 21, y + ySize - 20, 16, 16, 32, 0, _ -> initWidgets((page + 1) % pages))); } - public @NonNull UVRectangleWidget addRectWidget(@NonNull UVRectangleWidget rectWidget) { - UVRectangleWidget foundRectWidget = rectWidgets.stream().filter(r -> r.contains(rectWidget)).findFirst().orElse(null); - if (foundRectWidget == null) { - rectWidgets.add(rectWidget); - focusedRectWidgetNumberField.setMax(rectWidgets.size()); - rectWidgetsSizeWidget.setMessage(LocUtil.literal(String.valueOf(rectWidgets.size()))); - if (textureViewArea != null) addRenderableWidget(rectWidget); - return rectWidget; - } - return foundRectWidget; - } - public boolean deleteFocusedRectWidget() { if (focusedRectWidget == null) return false; rectWidgets.remove(focusedRectWidget); @@ -433,13 +385,13 @@ public void extractRenderState(@NonNull GuiGraphicsExtractor graphics, int mouse super.extractRenderState(graphics, mouseX, mouseY, partialTicks); if (toggleCategoryButton.getValue() == Category.DISABLE && selectionModeButton.getValue() == 2 && inModelViewArea(mouseX, mouseY)) { GUIHelper.enableScissor(graphics, modelViewArea); - GUIHelper.fill(graphics, mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius, 400, 0x4F3333CC); + GUIHelper.fill(graphics, mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius, 400, SELECTION_COLOR); graphics.disableScissor(); } if (textureViewArea != null) { GUIHelper.enableScissor(graphics, textureViewArea); if (clickedX >= 0 && clickedY >= 0) - graphics.fill(Math.min((int) clickedX, mouseX), Math.min((int) clickedY, mouseY), Math.max((int) clickedX, mouseX), Math.max((int) clickedY, mouseY), 0x4F3333CC); + graphics.fill(Math.min((int) clickedX, mouseX), Math.min((int) clickedY, mouseY), Math.max((int) clickedX, mouseX), Math.max((int) clickedY, mouseY), SELECTION_COLOR); if (disableModeButton.getValue() == 0) new UVRectangleWidget(0f, 0f, 1f, 1f).extractWidgetRenderState(graphics, mouseX, mouseY, partialTicks); graphics.disableScissor(); @@ -449,9 +401,9 @@ public void extractRenderState(@NonNull GuiGraphicsExtractor graphics, int mouse @Override public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { super.extractBackground(graphics, mouseX, mouseY, partialTicks); - graphics.fill(x, y, x + (xSize - middleWidth) / 2 - 4, y + ySize, 0xFF444444); - graphics.fill(x + (xSize - middleWidth) / 2, y, x + (xSize + middleWidth) / 2, y + ySize, 0xFF222222); - graphics.fill(x + (xSize + middleWidth) / 2 + 4, y, x + xSize, y + ySize, 0xFF444444); + graphics.fill(x, y, x + (xSize - middleWidth) / 2 - 4, y + ySize, SIDE_PANEL_BG); + graphics.fill(x + (xSize - middleWidth) / 2, y, x + (xSize + middleWidth) / 2, y + ySize, CENTER_PANEL_BG); + graphics.fill(x + (xSize + middleWidth) / 2 + 4, y, x + xSize, y + ySize, SIDE_PANEL_BG); ModelAnalyser analyser = new ModelAnalyser(); BindTarget target = genBindTarget(); @@ -473,15 +425,15 @@ private List captureRotatedEntity(ModelAnalyser analyser, Bind float entityPrevHeadYaw = entity.yHeadRotO; float entityHeadYaw = entity.yHeadRot; entity.yBodyRot = 180.0f; - entity.setYRot(180.0f + (float) entityYawSlider.getDouble()); - entity.setXRot((float) entityPitchSlider.getDouble()); + entity.setYRot(180.0f + (float) entityYawSlider.getNumber()); + entity.setXRot((float) entityPitchSlider.getNumber()); entity.yHeadRot = entity.getYRot(); entity.yHeadRotO = entity.getYRot(); try { int x1 = modelViewArea.left(), y1 = modelViewArea.top(), x2 = modelViewArea.right(), y2 = modelViewArea.bottom(); Quaternionf rotation = new Quaternionf().rotateX((float) Math.PI / 6 + xRot).rotateY((float) Math.PI / 6 + yRot).rotateZ((float) Math.PI); PoseStack modelPose = new PoseStack(); - modelPose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + modelPose.translate((x1 + x2) / 2.0f, (y1 + y2) / 2.0f, 0); modelPose.scale(modelScale, modelScale, -modelScale); modelPose.translate(modelX, modelY, 0); modelPose.mulPose(rotation); @@ -515,7 +467,7 @@ private void renderCulledModels(GuiGraphicsExtractor graphics, ModelAnalyser ana float invScale = 1.0f / modelScale; Matrix4f modelTransform = new Matrix4f(); modelTransform.scale(invScale, invScale, -invScale); - modelTransform.translate(-(float) (x1 + x2) / 2.0f, -(float) (y1 + y2) / 2.0f, 0); + modelTransform.translate(-(x1 + x2) / 2.0f, -(y1 + y2) / 2.0f, 0); GUIHelper.culledModels(graphics, modelRecords, modelScale, modelTransform, x1, y1, x2, y2); if (toggleCategoryButton.getValue() != Category.PREVIEW) analyser.drawFocusedInModelArea(graphics); if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics, target, modelScale); @@ -526,11 +478,11 @@ private void renderCulledModels(GuiGraphicsExtractor graphics, ModelAnalyser ana private void renderFlattenedModels(GuiGraphicsExtractor graphics, ModelAnalyser analyser, List textureRecords) { int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); GUIHelper.enableScissor(graphics, textureViewArea); - float scale = (float) (textureScale * textureViewArea.width()) / 80; + float scale = (textureScale * textureViewArea.width()) / (float) DEFAULT_SCALE; Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); GUIHelper.flattenedModels(graphics, textureRecords, offset, x1, y1, x2, y2, scale); Matrix4f texturePose = new Matrix4f(); - texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); + texturePose.translate((x1 + x2) / 2.0f, (y1 + y2) / 2.0f, 0); texturePose.scale(scale, scale, -scale); texturePose.translate(offset); analyser.drawFocusedInTextureArea(graphics, texturePose); @@ -538,21 +490,19 @@ private void renderFlattenedModels(GuiGraphicsExtractor graphics, ModelAnalyser } private Vec2 translateUVToXY(float u, float v, ScreenRectangle screenArea) { - int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); - Vector3f vector3f = new Vector3f(u, v, 0) - .add((float) textureX - 0.5f, (float) textureY - 0.5f, 0) - .mul((float) (textureScale * screenArea.width()) / 80) - .add((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - return new Vec2(vector3f.x(), vector3f.y()); + int left = screenArea.left(), width = screenArea.width(), top = screenArea.top(), height = screenArea.height(); + float scale = (textureScale * width) / (float) DEFAULT_SCALE; + float x = (u + (float) textureX - 0.5f) * scale + left + width / 2.0f; + float y = (v + (float) textureY - 0.5f) * scale + top + height / 2.0f; + return new Vec2(x, y); } private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { - int x1 = screenArea.left(), y1 = screenArea.top(), x2 = screenArea.right(), y2 = screenArea.bottom(); - Vector3f vector3f = new Vector3f(x, y, 0) - .add(-(float) (x1 + x2) / 2.0f, -(float) (y1 + y2) / 2.0f, 0) - .mul((float) 80 / (textureScale * screenArea.width())) - .add((float) -textureX + 0.5f, (float) -textureY + 0.5f, 0); - return new Vec2(vector3f.x(), vector3f.y()); + int left = screenArea.left(), width = screenArea.width(), top = screenArea.top(), height = screenArea.height(); + float invScale = (float) DEFAULT_SCALE / (textureScale * width); + float u = (x - left - width / 2.0f) * invScale - (float) textureX + 0.5f; + float v = (y - top - height / 2.0f) * invScale - (float) textureY + 0.5f; + return new Vec2(u, v); } private void importBindTarget(Button button) { @@ -619,19 +569,14 @@ private void loadBindTarget(BindTarget target) { bindYButton.setValue(target.bindConfig().bindY() ? 0 : 1); bindZButton.setValue(target.bindConfig().bindZ() ? 0 : 1); bindRotButton.setValue(target.bindConfig().bindRotation() ? 0 : 1); - scaleField.setNumber(target.offsets().scale); - offsetXSlider.setDouble(target.offsets().x); - offsetXField.setNumber(target.offsets().x); - offsetYSlider.setDouble(target.offsets().y); - offsetYField.setNumber(target.offsets().y); - offsetZSlider.setDouble(target.offsets().z); - offsetZField.setNumber(target.offsets().z); - offsetPitchSlider.setDouble(target.offsets().pitch); - offsetPitchField.setNumber(target.offsets().pitch); - offsetYawSlider.setDouble(target.offsets().yaw); - offsetYawField.setNumber(target.offsets().yaw); - offsetRollSlider.setDouble(target.offsets().roll); - offsetRollField.setNumber(target.offsets().roll); + OffsetConfig offsets = target.offsets(); + scaleField.setNumber(offsets.scale); + offsetXPair.setNumber(offsets.x); + offsetYPair.setNumber(offsets.y); + offsetZPair.setNumber(offsets.z); + offsetPitchPair.setNumber(offsets.pitch); + offsetYawPair.setNumber(offsets.yaw); + offsetRollPair.setNumber(offsets.roll); disableConfigs.clear(); disableConfigs.addAll(List.of(target.disableConfigs())); } @@ -641,12 +586,12 @@ private BindTarget genBindTarget() { BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); OffsetConfig offsets = new OffsetConfig( scaleField.getNumber(), - toggleSliderButton.getValue() == 0 ? (float) offsetXSlider.getDouble() : offsetXField.getNumber(), - toggleSliderButton.getValue() == 0 ? (float) offsetYSlider.getDouble() : offsetYField.getNumber(), - toggleSliderButton.getValue() == 0 ? (float) offsetZSlider.getDouble() : offsetZField.getNumber(), - toggleSliderButton.getValue() == 0 ? (float) offsetPitchSlider.getDouble() : offsetPitchField.getNumber(), - toggleSliderButton.getValue() == 0 ? (float) offsetYawSlider.getDouble() : offsetYawField.getNumber(), - toggleSliderButton.getValue() == 0 ? (float) offsetRollSlider.getDouble() : offsetRollField.getNumber() + offsetXPair.getNumber(), + offsetYPair.getNumber(), + offsetZPair.getNumber(), + offsetPitchPair.getNumber(), + offsetYawPair.getNumber(), + offsetRollPair.getNumber() ); DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toArray(UVRectangle[]::new)); DisableConfig[] disableConfigArray = disableConfigs.toArray(new DisableConfig[0]); @@ -657,6 +602,19 @@ private BindTarget genBindTarget() { return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, disableConfigArray); } + @NonNull + private UVRectangleWidget addRectWidget(@NonNull UVRectangleWidget rectWidget) { + UVRectangleWidget foundRectWidget = rectWidgets.stream().filter(r -> r.contains(rectWidget)).findFirst().orElse(null); + if (foundRectWidget == null) { + rectWidgets.add(rectWidget); + focusedRectWidgetNumberField.setMax(rectWidgets.size()); + rectWidgetsSizeWidget.setMessage(LocUtil.literal(String.valueOf(rectWidgets.size()))); + if (textureViewArea != null) addRenderableWidget(rectWidget); + return rectWidget; + } + return foundRectWidget; + } + private Tooltip createTooltip(String key, Object... args) { return Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP(key, args)); } @@ -822,11 +780,11 @@ public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmou selectionRadius = Mth.clamp(selectionRadius + (int) verticalAmount * 2, 2, 48); else layers = Math.max(0, layers + (int) verticalAmount); } else { - modelScale = Mth.clamp(modelScale + (int) verticalAmount * modelScale / 16, 16, 1024); + modelScale = Mth.clamp(modelScale + (int) verticalAmount * modelScale / 16, MIN_SCALE, MAX_SCALE); } return true; } else if (inTextureViewArea(mouseX, mouseY)) { - textureScale = Mth.clamp(textureScale + (int) verticalAmount * textureScale / 16, 16, 1024); + textureScale = Mth.clamp(textureScale + (int) verticalAmount * textureScale / 16, MIN_SCALE, MAX_SCALE); } return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); } @@ -857,7 +815,7 @@ public Category next() { } } - public final class UVRectangleWidget extends AbstractWidget { + private final class UVRectangleWidget extends AbstractWidget { private float uMin, vMin, uMax, vMax; public UVRectangleWidget(float uMin, float vMin, float uMax, float vMax) { @@ -908,10 +866,10 @@ protected void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, setWidth((int) width); setHeight((int) height); GUIHelper.enableScissor(graphics, textureViewArea); - GUIHelper.fill(graphics, x1, y1, x2, y2, 0x4F3333CC); - if (isHoveredOrFocused()) GUIHelper.fill(graphics, x1, y1, x2, y2, 0x2F3333CC); + GUIHelper.fill(graphics, x1, y1, x2, y2, SELECTION_COLOR); + if (isHoveredOrFocused()) GUIHelper.fill(graphics, x1, y1, x2, y2, SELECTION_HOVER_COLOR); if (isFocused() || this == focusedRectWidget) - GUIHelper.outline(graphics, x1, y1, width, height, 0xAAFFFFFF); + GUIHelper.outline(graphics, x1, y1, width, height, OUTLINE_COLOR); graphics.disableScissor(); } @@ -922,7 +880,7 @@ public boolean keyPressed(@NonNull KeyEvent event) { if (event.isSelection() && uMin < uMax && vMin < vMax) { textureX = 0.5 * (1 - uMin - uMax); textureY = 0.5 * (1 - vMin - vMax); - textureScale = (int) Mth.clamp(2560d / (textureViewArea.width() * Math.sqrt((uMax - uMin) * (vMax - vMin))), 16, 1024); + textureScale = (int) Mth.clamp(32d * DEFAULT_SCALE / (textureViewArea.width() * Math.sqrt((uMax - uMin) * (vMax - vMin))), MIN_SCALE, MAX_SCALE); return true; } return super.keyPressed(event); diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java b/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java index d251f011..02e97764 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/CycleIconButton.java @@ -67,7 +67,7 @@ public void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouse } @Override - protected void updateWidgetNarration(@NonNull NarrationElementOutput builder) { - defaultButtonNarrationText(builder); + protected void updateWidgetNarration(@NonNull NarrationElementOutput output) { + defaultButtonNarrationText(output); } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java b/common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java index fc319fd2..52862444 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/DoubleSlider.java @@ -17,17 +17,17 @@ public DoubleSlider(int width, int height, double value, double min, double max, this.max = max; } - public double getDouble() { + public double getNumber() { return min + (max - min) * value; } - public void setDouble(double value) { + public void setNumber(double value) { setValue((value - min) / (max - min)); } @Override protected void updateMessage() { - setMessage(textFactory.apply(getDouble())); + setMessage(textFactory.apply(getNumber())); } @Override diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java index 070215ed..c102c7d1 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberField.java @@ -29,14 +29,14 @@ public abstract class NumberField> extends EditBox { if (copyFrom != null) setNumber(copyFrom.getNumber()); } - public static NumberField ofFloat(Font font, int width, int height, float defaultValue, @Nullable NumberField copyFrom) { - return new FloatField(font, width, height, defaultValue, copyFrom); - } - public static NumberField ofInt(Font font, int width, int height, int defaultValue, @Nullable NumberField copyFrom) { return new IntField(font, width, height, defaultValue, copyFrom); } + public static NumberField ofFloat(Font font, int width, int height, float defaultValue, @Nullable NumberField copyFrom) { + return new FloatField(font, width, height, defaultValue, copyFrom); + } + public T getNumber() { try { return getNumberInternal(getValue()); @@ -114,18 +114,6 @@ public void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int super.extractWidgetRenderState(graphics, mouseX, mouseY, partialTicks); } - private static final class FloatField extends NumberField { - FloatField(Font font, int width, int height, float defaultValue, @Nullable NumberField copyFrom) { - super(font, width, height, defaultValue, Float.MAX_VALUE, -Float.MAX_VALUE, copyFrom); - setMaxLength(16); - } - - @Override - protected Float getNumberInternal(String str) throws NumberFormatException { - return Float.parseFloat(str); - } - } - private static final class IntField extends NumberField { IntField(Font font, int width, int height, int defaultValue, @Nullable NumberField copyFrom) { super(font, width, height, defaultValue, Integer.MAX_VALUE, Integer.MIN_VALUE, copyFrom); @@ -137,4 +125,16 @@ protected Integer getNumberInternal(String str) throws NumberFormatException { return Integer.parseInt(str); } } + + private static final class FloatField extends NumberField { + FloatField(Font font, int width, int height, float defaultValue, @Nullable NumberField copyFrom) { + super(font, width, height, defaultValue, Float.MAX_VALUE, -Float.MAX_VALUE, copyFrom); + setMaxLength(16); + } + + @Override + protected Float getNumberInternal(String str) throws NumberFormatException { + return Float.parseFloat(str); + } + } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java new file mode 100644 index 00000000..a610039d --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java @@ -0,0 +1,133 @@ +package com.xtracr.realcamera.gui.components; + +import com.xtracr.realcamera.util.LocUtil; +import com.xtracr.realcamera.util.MathUtil; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.CommonComponents; +import org.jspecify.annotations.NonNull; + +public final class NumberWidgetPair extends AbstractWidget { + private final DoubleSlider slider; + private final NumberField field; + private boolean useSlider; + + public NumberWidgetPair(Font font, String translationKey, int width, int height, float min, float max) { + super(0, 0, width, height, CommonComponents.EMPTY); + this.slider = new DoubleSlider(width, height, 0, min, max, d -> LocUtil.MODEL_VIEW_WIDGET(translationKey, MathUtil.round(d, 2))); + this.field = NumberField.ofFloat(font, width - 2, height - 2, 0, null).setMin(min).setMax(max); + setUseSlider(true); + } + + public void setNumber(float value) { + slider.setNumber(value); + field.setNumber(value); + } + + public float getNumber() { + return isUseSlider() ? (float) slider.getNumber() : field.getNumber(); + } + + public void setUseSlider(boolean useSlider) { + this.useSlider = useSlider; + slider.active = useSlider; + field.active = !useSlider; + } + + public boolean isUseSlider() { + return useSlider; + } + + public void syncAndSwitch(boolean useSlider) { + setUseSlider(useSlider); + if (useSlider) slider.setNumber(field.getNumber()); + else field.setNumber((float) slider.getNumber()); + } + + private AbstractWidget getActiveWidget() { + return isUseSlider() ? slider : field; + } + + @Override + public void setX(int x) { + super.setX(x); + slider.setX(x); + field.setX(x); + } + + @Override + public void setY(int y) { + super.setY(y); + slider.setY(y); + field.setY(y); + } + + @Override + public void setWidth(int width) { + super.setWidth(width); + slider.setWidth(width); + field.setWidth(width - 2); + } + + @Override + public void setHeight(int height) { + super.setHeight(height); + slider.setHeight(height); + field.setHeight(height - 2); + } + + @Override + public void extractWidgetRenderState(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, float partialTicks) { + getActiveWidget().extractRenderState(graphics, mouseX, mouseY, partialTicks); + } + + @Override + public boolean mouseClicked(@NonNull MouseButtonEvent event, boolean doubleClick) { + return getActiveWidget().mouseClicked(event, doubleClick); + } + + @Override + public boolean mouseDragged(@NonNull MouseButtonEvent event, double dx, double dy) { + return getActiveWidget().mouseDragged(event, dx, dy); + } + + @Override + public boolean mouseReleased(@NonNull MouseButtonEvent event) { + return getActiveWidget().mouseReleased(event); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + return getActiveWidget().mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + + @Override + public boolean keyPressed(@NonNull KeyEvent event) { + return getActiveWidget().keyPressed(event); + } + + @Override + public boolean charTyped(@NonNull CharacterEvent event) { + return getActiveWidget().charTyped(event); + } + + @Override + public void setFocused(boolean focused) { + super.setFocused(focused); + if (focused) getActiveWidget().setFocused(true); + else { + slider.setFocused(false); + field.setFocused(false); + } + } + + @Override + protected void updateWidgetNarration(@NonNull NarrationElementOutput output) { + getActiveWidget().updateNarration(output); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index 8ade0765..552056bf 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -5,7 +5,7 @@ import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormatElement; import com.xtracr.realcamera.renderer.state.VertexData; -import com.xtracr.realcamera.renderer.state.VertexData.MutableVertex; +import com.xtracr.realcamera.renderer.state.MutableVertex; import org.jspecify.annotations.NonNull; import java.nio.ByteBuffer; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/MutableVertex.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/MutableVertex.java new file mode 100644 index 00000000..82b2cb2c --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/MutableVertex.java @@ -0,0 +1,67 @@ +package com.xtracr.realcamera.renderer.state; + +public final class MutableVertex implements VertexData { + public float x, y, z; + public int argb; + public float u, v; + public int overlay, light; + public float normalX, normalY, normalZ; + + MutableVertex() { + } + + @Override + public float x() { + return x; + } + + @Override + public float y() { + return y; + } + + @Override + public float z() { + return z; + } + + @Override + public int argb() { + return argb; + } + + @Override + public float u() { + return u; + } + + @Override + public float v() { + return v; + } + + @Override + public int overlay() { + return overlay; + } + + @Override + public int light() { + return light; + } + + @Override + public float normalX() { + return normalX; + } + + @Override + public float normalY() { + return normalY; + } + + @Override + public float normalZ() { + return normalZ; + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java index 5f57de5e..c8c2a089 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/VertexData.java @@ -140,70 +140,4 @@ public VertexData asImmutable() { return this; } } - - final class MutableVertex implements VertexData { - public float x, y, z; - public int argb; - public float u, v; - public int overlay, light; - public float normalX, normalY, normalZ; - - private MutableVertex() { - } - - @Override - public float x() { - return x; - } - - @Override - public float y() { - return y; - } - - @Override - public float z() { - return z; - } - - @Override - public int argb() { - return argb; - } - - @Override - public float u() { - return u; - } - - @Override - public float v() { - return v; - } - - @Override - public int overlay() { - return overlay; - } - - @Override - public int light() { - return light; - } - - @Override - public float normalX() { - return normalX; - } - - @Override - public float normalY() { - return normalY; - } - - @Override - public float normalZ() { - return normalZ; - } - } } diff --git a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java index 65c2e3f5..72d08346 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -10,20 +10,22 @@ public static double round(double d, int digits) { return Math.round(d * Math.pow(10, digits)) / Math.pow(10, digits); } - public static double floor(double... ds) { - double d = ds[0]; - for (int i = 1; i < ds.length; i++) { - d = Math.min(d, ds[i]); - } - return Math.floor(d); + public static double floor(double d1, double d2) { + return Math.floor(Math.min(d1, d2)); } - public static double ceil(double... ds) { - double d = ds[0]; - for (int i = 1; i < ds.length; i++) { - d = Math.max(d, ds[i]); - } - return Math.ceil(d); + public static double floor(double d1, double d2, double d3, double d4) { + double min = Math.min(Math.min(Math.min(d1, d2), d3), d4); + return Math.floor(min); + } + + public static double ceil(double d1, double d2) { + return Math.ceil(Math.max(d1, d2)); + } + + public static double ceil(double d1, double d2, double d3, double d4) { + double max = Math.max(Math.max(Math.max(d1, d2), d3), d4); + return Math.ceil(max); } public static float cross(float a, float b, float c, float d) { From 688ba60dd9dfb6af075b799821485551d3365d72 Mon Sep 17 00:00:00 2001 From: xTracr Date: Wed, 20 May 2026 13:51:28 +0800 Subject: [PATCH 20/33] Move import/export serialization to BindTarget - Extract compressed Base64 serialization from ModelViewScreen into BindTarget.fromCompressedBase64()/toCompressedBase64() using DataResult. - Rename static fields to UPPER_CASE across all files (entries, defaultTargets, serialVersion, colors, Z values). - Add FALSE-predicate short-circuit in DisableHelper.Entry to avoid unnecessary predicate wrapping. --- .../realcamera/compat/DisableHelper.java | 12 +-- .../xtracr/realcamera/compat/YSMCompat.java | 22 +++--- .../xtracr/realcamera/config/BindTarget.java | 73 ++++++++++++++++-- .../realcamera/config/ConfigScreen.java | 2 +- .../xtracr/realcamera/config/ModConfig.java | 10 +-- .../xtracr/realcamera/gui/ModelAnalyser.java | 26 ++++--- .../realcamera/gui/ModelViewScreen.java | 76 ++++++------------- .../renderer/IterableVertexBuffer.java | 2 +- .../renderer/gui/GuiCulledModelsRenderer.java | 6 +- 9 files changed, 134 insertions(+), 95 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 5d4ff186..20f6f84f 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -19,7 +19,7 @@ public final class DisableHelper { public static final Entry MAIN_FEATURE, RENDER_MODEL, RENDER_HANDS; private static final Pattern MULTI_STAR = Pattern.compile("\\*+"); private static final Predicate FALSE = _ -> false; - private static final Map entries = new HashMap<>(); + private static final Map ENTRIES = new HashMap<>(); private static int exitTick = 0; static { @@ -66,7 +66,7 @@ private static boolean checkCondition(Player player, boolean condition, int outT @Deprecated public static void registerOr(String name, Predicate predicate) { - entries.get(name).registerOrInBinding(predicate::test); + ENTRIES.get(name).registerOrInBinding(predicate::test); } public static boolean matchesItemPattern(Item item, String pattern) { @@ -116,7 +116,7 @@ protected Entry(String name, Predicate predicate) { protected Entry(String name, Predicate predicateInClassic, Predicate predicateInBinding) { this.predicateInClassic = predicateInClassic; this.predicateInBinding = predicateInBinding; - entries.put(name, this); + ENTRIES.put(name, this); } public void registerOr(Predicate predicate) { @@ -125,11 +125,13 @@ public void registerOr(Predicate predicate) { } public void registerOrInClassic(Predicate predicate) { - this.predicateInClassic = this.predicateInClassic.or(predicate); + if (predicateInClassic == FALSE) predicateInClassic = predicate; + else predicateInClassic = predicateInClassic.or(predicate); } public void registerOrInBinding(Predicate predicate) { - this.predicateInBinding = this.predicateInBinding.or(predicate); + if (predicateInBinding == FALSE) predicateInBinding = predicate; + else predicateInBinding = predicateInBinding.or(predicate); } public boolean disabled(Entity cameraEntity) { diff --git a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java index 1b1223b7..a342c325 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/YSMCompat.java @@ -20,16 +20,16 @@ import java.util.Map; public final class YSMCompat { - private static final Map resultMap = new HashMap<>(); - private static final TransformedVertexRecorder[] transformedRecorders = new TransformedVertexRecorder[4]; + private static final Map RESULT_MAP = new HashMap<>(); + private static final TransformedVertexRecorder[] TRANSFORMED_RECORDERS = new TransformedVertexRecorder[4]; private static BindResult bindResult = BindResult.EMPTY; static { final float pitch = 1.9106332f, yaw = 2.0943951f; - transformedRecorders[0] = new TransformedVertexRecorder(); - transformedRecorders[1] = new TransformedVertexRecorder().setRotation(pitch, 0); - transformedRecorders[2] = new TransformedVertexRecorder().setRotation(pitch, yaw); - transformedRecorders[3] = new TransformedVertexRecorder().setRotation(pitch, 2 * yaw); + TRANSFORMED_RECORDERS[0] = new TransformedVertexRecorder(); + TRANSFORMED_RECORDERS[1] = new TransformedVertexRecorder().setRotation(pitch, 0); + TRANSFORMED_RECORDERS[2] = new TransformedVertexRecorder().setRotation(pitch, yaw); + TRANSFORMED_RECORDERS[3] = new TransformedVertexRecorder().setRotation(pitch, 2 * yaw); } public static void register() { @@ -37,12 +37,12 @@ public static void register() { } private static BindResult computeBindResult(Minecraft client, float partialTicks) { - resultMap.clear(); + RESULT_MAP.clear(); bindResult = BindResult.EMPTY; EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); EntityRenderState renderState = dispatcher.extractEntity(client.getCameraEntity(), partialTicks); PoseStack poseStack = new PoseStack(); - for (TransformedVertexRecorder recorder : transformedRecorders) { + for (TransformedVertexRecorder recorder : TRANSFORMED_RECORDERS) { poseStack.pushPose(); poseStack.mulPose(recorder.matrix4f.invert(new Matrix4f())); dispatcher.submit(renderState, new CameraRenderState(), 0, 0, 0, poseStack, recorder.vertexCatcher.initCollector()); @@ -50,7 +50,7 @@ private static BindResult computeBindResult(Minecraft client, float partialTicks poseStack.popPose(); if (bindResult.available()) return bindResult; } - for (TransformedVertexRecorder recorder : transformedRecorders) { + for (TransformedVertexRecorder recorder : TRANSFORMED_RECORDERS) { recorder.vertexCatcher.forEachBuffer(recorder::computeBindResult); if (bindResult.available()) return bindResult; } @@ -71,7 +71,7 @@ public TransformedVertexRecorder setRotation(float pitch, float yaw) { public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = resultMap.computeIfAbsent(target, BindResult::new); + BindResult result = RESULT_MAP.computeIfAbsent(target, BindResult::new); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = new VertexData.UV(config.posU(), config.posV()); VertexData.UV forwardUV = new VertexData.UV(config.forwardU(), config.forwardV()); @@ -95,7 +95,7 @@ public void computeBindResultInCache(BuiltIterableBuffer builtBuffer) { public void computeBindResult(BuiltIterableBuffer builtBuffer) { if (bindResult.available()) return; for (BindTarget target : ConfigFile.config().getBindTargetList(builtBuffer.textureId())) { - BindResult result = resultMap.computeIfAbsent(target, BindResult::new); + BindResult result = RESULT_MAP.computeIfAbsent(target, BindResult::new); BindTarget.TargetConfig config = target.targetConfig(); VertexData.UV posUV = result.getPosition() == Vec3.ZERO ? new VertexData.UV(config.posU(), config.posV()) : null; VertexData.UV forwardUV = result.getForward() == Vec3.ZERO ? new VertexData.UV(config.forwardU(), config.forwardV()) : null; diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index 87956e33..c36ab77e 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -1,10 +1,18 @@ package com.xtracr.realcamera.config; +import com.mojang.serialization.DataResult; +import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.util.Arrays; +import java.util.Base64; import java.util.List; import java.util.function.Predicate; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; public record BindTarget( String name, String textureId, int priority, float disablingDepth, @@ -12,12 +20,12 @@ public record BindTarget( BindConfig bindConfig, OffsetConfig offsets, DisableConfig[] disableConfigs) { - public static final List defaultTargets; + public static final List DEFAULT_TARGETS; public static final BindTarget EMPTY = blank(null, null); - private static final short serialVersion = 703; // 0.7.3 + private static final short SERIAL_VERSION = 703; // 0.7.3 static { - defaultTargets = List.of( + DEFAULT_TARGETS = List.of( BindTarget.vanillaTarget("minecraft_head", 5, false), BindTarget.vanillaTarget("skin_head", 5, false), BindTarget.vanillaTarget("minecraft_head_2", 1, true), @@ -33,8 +41,8 @@ public static BindTarget blank(String name, String textureId) { public static BindTarget read(FriendlyByteBuf byteBuf) throws IllegalArgumentException { short version = byteBuf.readShort(); - if (version != serialVersion) - throw new IllegalArgumentException("Invalid version: " + version + ", expected " + serialVersion); + if (version != SERIAL_VERSION) + throw new IllegalArgumentException("Invalid version: " + toSemVer(version) + ", expected " + toSemVer(SERIAL_VERSION)); String name = byteBuf.readUtf(); String textureId = byteBuf.readUtf(); int priority = byteBuf.readVarInt(); @@ -49,6 +57,40 @@ public static BindTarget read(FriendlyByteBuf byteBuf) throws IllegalArgumentExc return new BindTarget(name, textureId, priority, disablingDepth, targetConfig, bindConfig, offsets, disableConfigs); } + public static DataResult fromCompressedBase64(String base64) { + FriendlyByteBuf byteBuf = null; + try { + byte[] compressed = Base64.getDecoder().decode(base64); + InflaterInputStream inflaterStream = new InflaterInputStream(new ByteArrayInputStream(compressed)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int length; + while ((length = inflaterStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + byte[] bytes = outputStream.toByteArray(); + byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes)); + BindTarget target = BindTarget.read(byteBuf); + if (target.isEmpty()) return DataResult.error(() -> "Invalid config format"); + return DataResult.success(target); + } catch (Exception e) { + return DataResult.error(() -> { + String message = e.getClass().getSimpleName(); + if (e instanceof IllegalArgumentException) message += ": " + e.getMessage(); + return message; + }); + } finally { + if (byteBuf != null) byteBuf.release(); + } + } + + private static String toSemVer(short version) { + int major = version / 10000; + int minor = version % 10000 / 100; + int patch = version % 100; + return major + "." + minor + "." + patch; + } + private static BindTarget vanillaTarget(String name, int priority, boolean shouldBind) { String textureId = name.contains("skin") ? "minecraft:skins/" : "minecraft:textures/entity/player/"; TargetConfig targetConfig = new TargetConfig(0.1875f, 0.2f, 0.1875f, 0.075f, 0.1875f, 0.2f); @@ -70,7 +112,7 @@ public DisableConfig[] filteredDisableConfigs(Predicate filter) { } public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeShort(serialVersion); + byteBuf.writeShort(SERIAL_VERSION); byteBuf.writeUtf(name); byteBuf.writeUtf(textureId); byteBuf.writeVarInt(priority); @@ -84,6 +126,25 @@ public void write(FriendlyByteBuf byteBuf) { } } + public DataResult toCompressedBase64() { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + try { + write(byteBuf); + byte[] bytes = new byte[byteBuf.readableBytes()]; + byteBuf.getBytes(byteBuf.readerIndex(), bytes); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (DeflaterOutputStream deflaterStream = new DeflaterOutputStream(outputStream, new Deflater(Deflater.BEST_COMPRESSION))) { + deflaterStream.write(bytes); + } + String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + return DataResult.success(base64); + } catch (Exception e) { + return DataResult.error(() -> e.getClass().getSimpleName() + ": " + e.getMessage()); + } finally { + byteBuf.release(); + } + } + public record TargetConfig(float forwardU, float forwardV, float upwardU, float upwardV, float posU, float posV) { public static TargetConfig read(FriendlyByteBuf byteBuf) { return new TargetConfig(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index adedb4f8..77c91e68 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -217,7 +217,7 @@ public static Screen create(Screen parent) { .setSaveConsumer(l -> config.binding.disableMainFeatureItems = l) .build()); disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableRenderItems"), config.binding.disableRenderItems) - .setDefaultValue(ModConfig.Binding.defaultDisableRenderItems) + .setDefaultValue(ModConfig.Binding.DEFAULT_DISABLE_RENDER_ITEMS) .setTooltip(LocUtil.CONFIG_TOOLTIP("disableRenderItems")) .setSaveConsumer(l -> config.binding.disableRenderItems = l) .build()); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 1b92df36..55b69d56 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -182,7 +182,7 @@ public AdjustMode cycle() { } public static class Binding { - protected static final List defaultDisableRenderItems = List.of("minecraft:filled_map"); + protected static final List DEFAULT_DISABLE_RENDER_ITEMS = List.of("minecraft:filled_map"); public String screenModifierKey = InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_LALT).getName(); public boolean legacyMode = false; public boolean adjustOffset = true; @@ -197,9 +197,9 @@ public static class Binding { public double displacementSmoothFactor = 0.4; public double rotationSmoothFactor = 0.4; public List disableMainFeatureItems = List.of(); - public List disableRenderItems = defaultDisableRenderItems; + public List disableRenderItems = DEFAULT_DISABLE_RENDER_ITEMS; public List fixedTargetList = new ArrayList<>(); - public List targetList = new ArrayList<>(BindTarget.defaultTargets); + public List targetList = new ArrayList<>(BindTarget.DEFAULT_TARGETS); private void clamp() { try { @@ -216,10 +216,10 @@ private void clamp() { if (disableRenderItems == null) disableRenderItems = List.of(); if (fixedTargetList == null) fixedTargetList = new ArrayList<>(); else fixedTargetList.removeIf(BindTarget::isEmpty); - if (targetList == null) targetList = new ArrayList<>(BindTarget.defaultTargets); + if (targetList == null) targetList = new ArrayList<>(BindTarget.DEFAULT_TARGETS); else { targetList.removeIf(BindTarget::isEmpty); - if (targetList.isEmpty()) targetList = new ArrayList<>(BindTarget.defaultTargets); + if (targetList.isEmpty()) targetList = new ArrayList<>(BindTarget.DEFAULT_TARGETS); } } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index d4339b85..f963e14d 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -10,6 +10,7 @@ import com.xtracr.realcamera.config.DisableConfig; import com.xtracr.realcamera.renderer.BuiltIterableBuffer; import com.xtracr.realcamera.renderer.MultiVertexCatcher; +import com.xtracr.realcamera.renderer.gui.GuiCulledModelsRenderer; import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; @@ -34,8 +35,9 @@ public final class ModelAnalyser { private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); private static final Set UNFOCUSABLE_RENDER_TYPES = ImmutableSet.of(RenderTypes.armorEntityGlint(), RenderTypes.glintTranslucent(), RenderTypes.glint(), RenderTypes.entityGlint()); - private static final int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; - private final List focusedPolyhedron = new ArrayList<>(); private static final int z1 = 210, z2 = z1 + 10; + private static final int PLANE_ARGB = 0x6F3333CC, FORWARD_ARGB = 0xFF00CC00, UPWARD_ARGB = 0xFFCC0000, LEFT_ARGB = 0xFF0000CC, FOCUSED_ARGB = 0x4FFFFFFF; + private static final int Z_QUAD = GuiCulledModelsRenderer.MAX_Z + 10, Z_LINE = Z_QUAD + 10; + private final List focusedPolyhedron = new ArrayList<>(); private VertexData[][] targetPrimitives = new VertexData[3][]; private BindResult bindResult = BindResult.EMPTY; @Nullable @@ -195,16 +197,16 @@ public void drawCameraDirections(GuiGraphicsExtractor graphics, double modelScal Vec3 start = bindResult.getPosition(); Matrix3f normal = bindResult.getRotation(); if (normal.m00() == 0 && normal.m11() == 0 && normal.m22() == 0) return; - GUIHelper.vector(graphics, start, new Vec3(normal.m20(), normal.m21(), normal.m22()).scale(modelScale / 3), z2, forwardArgb); - GUIHelper.vector(graphics, start, new Vec3(normal.m10(), normal.m11(), normal.m12()).scale(modelScale / 6), z2, upwardArgb); - GUIHelper.vector(graphics, start, new Vec3(normal.m00(), normal.m01(), normal.m02()).scale(modelScale / 6), z2, leftArgb); + GUIHelper.vector(graphics, start, new Vec3(normal.m20(), normal.m21(), normal.m22()).scale(modelScale / 3), Z_LINE, FORWARD_ARGB); + GUIHelper.vector(graphics, start, new Vec3(normal.m10(), normal.m11(), normal.m12()).scale(modelScale / 6), Z_LINE, UPWARD_ARGB); + GUIHelper.vector(graphics, start, new Vec3(normal.m00(), normal.m01(), normal.m02()).scale(modelScale / 6), Z_LINE, LEFT_ARGB); } public void drawBindTarget(GuiGraphicsExtractor graphics, BindTarget target, double modelScale) { TargetConfig config = target.targetConfig(); - if (targetPrimitives[0] != null) GUIHelper.triangleOrQuad(graphics, targetPrimitives[0], z1, planeArgb); - if (targetPrimitives[1] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[1], config.forwardU(), config.forwardV()), VertexData.normal(targetPrimitives[1]).scale(-modelScale / 2), z2, forwardArgb); - if (targetPrimitives[2] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[2], config.upwardU(), config.upwardV()), VertexData.normal(targetPrimitives[2]).scale(-modelScale / 2), z2, upwardArgb); + if (targetPrimitives[0] != null) GUIHelper.triangleOrQuad(graphics, targetPrimitives[0], Z_QUAD, PLANE_ARGB); + if (targetPrimitives[1] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[1], config.forwardU(), config.forwardV()), VertexData.normal(targetPrimitives[1]).scale(-modelScale / 2), Z_LINE, FORWARD_ARGB); + if (targetPrimitives[2] != null) GUIHelper.vector(graphics, VertexData.position(targetPrimitives[2], config.upwardU(), config.upwardV()), VertexData.normal(targetPrimitives[2]).scale(-modelScale / 2), Z_LINE, UPWARD_ARGB); } public void drawFocusedInModelArea(GuiGraphicsExtractor graphics) { @@ -212,8 +214,8 @@ public void drawFocusedInModelArea(GuiGraphicsExtractor graphics) { VertexData[] focused = focusedPolyhedron.getFirst(); VertexData[] reversed = new VertexData[focused.length]; for (int i = 0; i < focused.length; i++) reversed[i] = focused[focused.length - 1 - i]; - GUIHelper.triangleOrQuad(graphics, reversed, z1, focusedArgb); - for (VertexData[] primitive : focusedPolyhedron) GUIHelper.triangleOrQuad(graphics, primitive, z1, focusedArgb); + GUIHelper.triangleOrQuad(graphics, reversed, Z_QUAD, FOCUSED_ARGB); + for (VertexData[] primitive : focusedPolyhedron) GUIHelper.triangleOrQuad(graphics, primitive, Z_QUAD, FOCUSED_ARGB); } public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f texturePose) { @@ -231,8 +233,8 @@ public void drawFocusedInTextureArea(GuiGraphicsExtractor graphics, Matrix4f tex position.set(vertex.u(), vertex.v(), 0).mulPosition(texturePose); transformed[i] = reversed[length - 1 - i] = VertexData.immutable(position.x(), position.y(), 0, vertex.argb(), vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); } - GUIHelper.triangleOrQuad(graphics, transformed, 0, focusedArgb); - GUIHelper.triangleOrQuad(graphics, reversed, 0, focusedArgb); + GUIHelper.triangleOrQuad(graphics, transformed, 0, FOCUSED_ARGB); + GUIHelper.triangleOrQuad(graphics, reversed, 0, FOCUSED_ARGB); } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 8fd1c0ba..3a3a3cca 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -4,21 +4,17 @@ import com.google.common.collect.ImmutableSortedMap; import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.serialization.DataResult; import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.compat.CompatibilityHelper; import com.xtracr.realcamera.config.*; import com.xtracr.realcamera.config.BindTarget.BindConfig; import com.xtracr.realcamera.config.BindTarget.TargetConfig; -import com.xtracr.realcamera.gui.components.CycleIconButton; -import com.xtracr.realcamera.gui.components.DoubleSlider; -import com.xtracr.realcamera.gui.components.NumberField; -import com.xtracr.realcamera.gui.components.NumberWidgetPair; -import com.xtracr.realcamera.gui.components.SimpleIconButton; +import com.xtracr.realcamera.gui.components.*; import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.util.LocUtil; import com.xtracr.realcamera.util.MathUtil; -import io.netty.buffer.Unpooled; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.components.*; @@ -31,7 +27,6 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; @@ -43,12 +38,7 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.util.*; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.InflaterInputStream; public final class ModelViewScreen extends Screen { private static final int SELECTION_COLOR = 0x4F3333CC, SELECTION_HOVER_COLOR = 0x2F3333CC, OUTLINE_COLOR = 0xAAFFFFFF; @@ -506,50 +496,33 @@ private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { } private void importBindTarget(Button button) { - FriendlyByteBuf byteBuf = null; - try { - String base64 = minecraft.keyboardHandler.getClipboard(); - byte[] compressed = Base64.getDecoder().decode(base64); - InflaterInputStream inflaterStream = new InflaterInputStream(new ByteArrayInputStream(compressed)); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] buffer = new byte[4096]; - int length; - while ((length = inflaterStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); + String base64 = minecraft.keyboardHandler.getClipboard(); + DataResult result = BindTarget.fromCompressedBase64(base64); + switch (result) { + case DataResult.Success success -> { + BindTarget target = success.value(); + loadBindTarget(target); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importSucceeded", LocUtil.literal("'" + target.name() + "'").withStyle(ChatFormatting.WHITE)).withStyle(ChatFormatting.GREEN))); + } + case DataResult.Error error -> { + String message = error.message(); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importFailed", message).withStyle(ChatFormatting.RED))); } - byte[] bytes = outputStream.toByteArray(); - byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes)); - BindTarget target = BindTarget.read(byteBuf); - if (target.isEmpty()) throw new IllegalArgumentException("Invalid config format"); - loadBindTarget(target); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importSucceeded", LocUtil.literal("'" + target.name() + "'").withStyle(ChatFormatting.WHITE)).withStyle(ChatFormatting.GREEN))); - } catch (Exception e) { - String message = e.getClass().getSimpleName(); - if (e instanceof IllegalArgumentException) message += ": " + e.getMessage(); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importFailed", message).withStyle(ChatFormatting.RED))); - } finally { - if (byteBuf != null) byteBuf.release(); } } private void exportBindTarget(Button button) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - try { - genBindTarget().write(byteBuf); - byte[] bytes = new byte[byteBuf.readableBytes()]; - byteBuf.getBytes(byteBuf.readerIndex(), bytes); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (DeflaterOutputStream deflaterStream = new DeflaterOutputStream(outputStream, new Deflater(Deflater.BEST_COMPRESSION))) { - deflaterStream.write(bytes); + DataResult result = genBindTarget().toCompressedBase64(); + switch (result) { + case DataResult.Success success -> { + String base64 = success.value(); + minecraft.keyboardHandler.setClipboard(base64); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportSucceeded").withStyle(ChatFormatting.GREEN))); + } + case DataResult.Error error -> { + String message = error.message(); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportFailed", message).withStyle(ChatFormatting.RED))); } - String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); - minecraft.keyboardHandler.setClipboard(base64); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportSucceeded").withStyle(ChatFormatting.GREEN))); - } catch (Exception e) { - String message = e.getClass().getSimpleName() + ": " + e.getMessage(); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportFailed", message).withStyle(ChatFormatting.RED))); - } finally { - byteBuf.release(); } } @@ -602,8 +575,7 @@ private BindTarget genBindTarget() { return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, disableConfigArray); } - @NonNull - private UVRectangleWidget addRectWidget(@NonNull UVRectangleWidget rectWidget) { + private UVRectangleWidget addRectWidget(UVRectangleWidget rectWidget) { UVRectangleWidget foundRectWidget = rectWidgets.stream().filter(r -> r.contains(rectWidget)).findFirst().orElse(null); if (foundRectWidget == null) { rectWidgets.add(rectWidget); diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index 552056bf..b39ade48 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -4,8 +4,8 @@ import com.mojang.blaze3d.vertex.MeshData; import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormatElement; -import com.xtracr.realcamera.renderer.state.VertexData; import com.xtracr.realcamera.renderer.state.MutableVertex; +import com.xtracr.realcamera.renderer.state.VertexData; import org.jspecify.annotations.NonNull; import java.nio.ByteBuffer; diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java index c5ff03e4..9898fd0b 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/gui/GuiCulledModelsRenderer.java @@ -12,6 +12,8 @@ import org.jspecify.annotations.NonNull; public final class GuiCulledModelsRenderer extends PictureInPictureRenderer { + public static final int MIN_Z = 0, MAX_Z = 200; + public GuiCulledModelsRenderer(MultiBufferSource.BufferSource bufferSource) { super(bufferSource); } @@ -25,14 +27,14 @@ public GuiCulledModelsRenderer(MultiBufferSource.BufferSource bufferSource) { protected void renderToTexture(@NonNull GuiCulledModelsRenderState renderState, @NonNull PoseStack poseStack) { poseStack.mulPose(renderState.transform()); - float minEntityZ = 0f, maxEntityZ = 200f; + float minEntityZ = MIN_Z, maxEntityZ = MAX_Z; for (BuiltModelRecord record : renderState.records()) { for (VertexData vertex : record.vertices()) { if (vertex.z() < minEntityZ) minEntityZ = vertex.z(); if (vertex.z() > maxEntityZ) maxEntityZ = vertex.z(); } } - Matrix4f positionMatrix = poseStack.last().pose().scale(1, 1, 200 / (maxEntityZ - minEntityZ)).translate(0, 0, -minEntityZ); + Matrix4f positionMatrix = poseStack.last().pose().scale(1, 1, MAX_Z / (maxEntityZ - minEntityZ)).translate(0, 0, -minEntityZ); Matrix3f normalMatrix = new Matrix3f(positionMatrix); for (BuiltModelRecord record : renderState.records()) { VertexConsumer buffer = bufferSource.getBuffer(record.renderType()); From 9d1e2b0707b49bcf54aba2c4b53628c4b09a13f0 Mon Sep 17 00:00:00 2001 From: xTracr Date: Thu, 21 May 2026 12:50:30 +0800 Subject: [PATCH 21/33] Extract serialization to config.serialization package; inline widgets initialization - Move BindTarget/DisableConfig/OffsetConfig/UVRectangle read methods and DisableConfigAdapter to a versioned serialization package for forward compatibility. - Inline allModelViewScreen widget field initialization to declaration site. --- .../xtracr/realcamera/config/BindTarget.java | 94 ------------------- .../xtracr/realcamera/config/ConfigFile.java | 12 +-- .../realcamera/config/DisableConfig.java | 70 +------------- .../realcamera/config/OffsetConfig.java | 4 - .../xtracr/realcamera/config/UVRectangle.java | 4 - .../serialization/ConfigSerializer.java | 93 ++++++++++++++++++ .../serialization/ConfigSerializer703.java | 78 +++++++++++++++ .../serialization/DisableConfigAdapter.java | 62 ++++++++++++ .../realcamera/gui/ModelViewScreen.java | 79 +++++++--------- .../renderer/IterableVertexBuffer.java | 1 - 10 files changed, 276 insertions(+), 221 deletions(-) create mode 100644 common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java create mode 100644 common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java create mode 100644 common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index c36ab77e..2e226b8a 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -1,18 +1,10 @@ package com.xtracr.realcamera.config; -import com.mojang.serialization.DataResult; -import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.util.Arrays; -import java.util.Base64; import java.util.List; import java.util.function.Predicate; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.InflaterInputStream; public record BindTarget( String name, String textureId, int priority, float disablingDepth, @@ -22,7 +14,6 @@ public record BindTarget( DisableConfig[] disableConfigs) { public static final List DEFAULT_TARGETS; public static final BindTarget EMPTY = blank(null, null); - private static final short SERIAL_VERSION = 703; // 0.7.3 static { DEFAULT_TARGETS = List.of( @@ -39,58 +30,6 @@ public static BindTarget blank(String name, String textureId) { return new BindTarget(name, textureId, 0, 0.2f, targetConfig, bindConfig, new OffsetConfig(), new DisableConfig[0]); } - public static BindTarget read(FriendlyByteBuf byteBuf) throws IllegalArgumentException { - short version = byteBuf.readShort(); - if (version != SERIAL_VERSION) - throw new IllegalArgumentException("Invalid version: " + toSemVer(version) + ", expected " + toSemVer(SERIAL_VERSION)); - String name = byteBuf.readUtf(); - String textureId = byteBuf.readUtf(); - int priority = byteBuf.readVarInt(); - float disablingDepth = byteBuf.readFloat(); - TargetConfig targetConfig = TargetConfig.read(byteBuf); - BindConfig bindConfig = BindConfig.read(byteBuf); - OffsetConfig offsets = OffsetConfig.read(byteBuf); - DisableConfig[] disableConfigs = new DisableConfig[byteBuf.readVarInt()]; - for (int i = 0; i < disableConfigs.length; i++) { - disableConfigs[i] = DisableConfig.read(byteBuf); - } - return new BindTarget(name, textureId, priority, disablingDepth, targetConfig, bindConfig, offsets, disableConfigs); - } - - public static DataResult fromCompressedBase64(String base64) { - FriendlyByteBuf byteBuf = null; - try { - byte[] compressed = Base64.getDecoder().decode(base64); - InflaterInputStream inflaterStream = new InflaterInputStream(new ByteArrayInputStream(compressed)); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] buffer = new byte[4096]; - int length; - while ((length = inflaterStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - byte[] bytes = outputStream.toByteArray(); - byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes)); - BindTarget target = BindTarget.read(byteBuf); - if (target.isEmpty()) return DataResult.error(() -> "Invalid config format"); - return DataResult.success(target); - } catch (Exception e) { - return DataResult.error(() -> { - String message = e.getClass().getSimpleName(); - if (e instanceof IllegalArgumentException) message += ": " + e.getMessage(); - return message; - }); - } finally { - if (byteBuf != null) byteBuf.release(); - } - } - - private static String toSemVer(short version) { - int major = version / 10000; - int minor = version % 10000 / 100; - int patch = version % 100; - return major + "." + minor + "." + patch; - } - private static BindTarget vanillaTarget(String name, int priority, boolean shouldBind) { String textureId = name.contains("skin") ? "minecraft:skins/" : "minecraft:textures/entity/player/"; TargetConfig targetConfig = new TargetConfig(0.1875f, 0.2f, 0.1875f, 0.075f, 0.1875f, 0.2f); @@ -112,7 +51,6 @@ public DisableConfig[] filteredDisableConfigs(Predicate filter) { } public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeShort(SERIAL_VERSION); byteBuf.writeUtf(name); byteBuf.writeUtf(textureId); byteBuf.writeVarInt(priority); @@ -126,30 +64,7 @@ public void write(FriendlyByteBuf byteBuf) { } } - public DataResult toCompressedBase64() { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - try { - write(byteBuf); - byte[] bytes = new byte[byteBuf.readableBytes()]; - byteBuf.getBytes(byteBuf.readerIndex(), bytes); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (DeflaterOutputStream deflaterStream = new DeflaterOutputStream(outputStream, new Deflater(Deflater.BEST_COMPRESSION))) { - deflaterStream.write(bytes); - } - String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); - return DataResult.success(base64); - } catch (Exception e) { - return DataResult.error(() -> e.getClass().getSimpleName() + ": " + e.getMessage()); - } finally { - byteBuf.release(); - } - } - public record TargetConfig(float forwardU, float forwardV, float upwardU, float upwardV, float posU, float posV) { - public static TargetConfig read(FriendlyByteBuf byteBuf) { - return new TargetConfig(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - public void write(FriendlyByteBuf byteBuf) { byteBuf.writeFloat(forwardU); byteBuf.writeFloat(forwardV); @@ -161,15 +76,6 @@ public void write(FriendlyByteBuf byteBuf) { } public record BindConfig(boolean bindX, boolean bindY, boolean bindZ, boolean bindRotation) { - public static BindConfig read(FriendlyByteBuf byteBuf) { - byte bindFlags = byteBuf.readByte(); - boolean bindX = (bindFlags & 0x01) != 0; - boolean bindY = (bindFlags & 0x02) != 0; - boolean bindZ = (bindFlags & 0x04) != 0; - boolean bindRotation = (bindFlags & 0x08) != 0; - return new BindConfig(bindX, bindY, bindZ, bindRotation); - } - public void write(FriendlyByteBuf byteBuf) { byte bindFlags = 0; if (bindX) bindFlags |= 0x01; diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java index 5ef4f551..548ee8f9 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java @@ -21,12 +21,6 @@ public final class ConfigFile { @Nullable private static ModConfig config; - private static Path getPath() { - File configDir = new File(Minecraft.getInstance().gameDirectory, "config"); - if (!configDir.exists()) configDir.mkdirs(); - return configDir.toPath().resolve(FILE_NAME); - } - public static ModConfig config() { if (config == null) load(); return config; @@ -60,4 +54,10 @@ public static void reset() { RealCamera.LOGGER.warn("Failed to reset " + FILE_NAME, exception); } } + + private static Path getPath() { + File configDir = new File(Minecraft.getInstance().gameDirectory, "config"); + if (!configDir.exists()) configDir.mkdirs(); + return configDir.toPath().resolve(FILE_NAME); + } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java b/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java index 4a144e99..e4958ac2 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java @@ -1,17 +1,12 @@ package com.xtracr.realcamera.config; -import com.google.gson.TypeAdapter; import com.google.gson.annotations.JsonAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; +import com.xtracr.realcamera.config.serialization.DisableConfigAdapter; import com.xtracr.realcamera.renderer.state.VertexData; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.network.FriendlyByteBuf; -import java.io.IOException; -import java.util.ArrayList; - -@JsonAdapter(DisableConfig.Adapter.class) +@JsonAdapter(DisableConfigAdapter.class) public final class DisableConfig { private final LongOpenHashSet disabledUVs = new LongOpenHashSet(), enabledUVs = new LongOpenHashSet(); private final String name; @@ -26,15 +21,6 @@ public DisableConfig(String name, String textureId, boolean disableAll, UVRectan this.rectangles = rectangles; } - public static DisableConfig read(FriendlyByteBuf byteBuf) { - String name = byteBuf.readUtf(); - String textureId = byteBuf.readUtf(); - boolean disableAll = byteBuf.readBoolean(); - UVRectangle[] rectangles = new UVRectangle[byteBuf.readVarInt()]; - for (int i = 0; i < rectangles.length; i++) rectangles[i] = UVRectangle.read(byteBuf); - return new DisableConfig(name, textureId, disableAll, rectangles); - } - public String name() { return name; } @@ -72,56 +58,4 @@ public boolean disable(VertexData vertex) { enabledUVs.add(packed); return false; } - - public static final class Adapter extends TypeAdapter { - @Override - public void write(JsonWriter out, DisableConfig value) throws IOException { - out.beginObject(); - out.name("name").value(value.name()); - out.name("textureId").value(value.textureId()); - out.name("disableAll").value(value.disableAll()); - out.name("rectangles"); - out.beginArray(); - for (UVRectangle rect : value.rectangles()) { - out.beginObject(); - out.name("uMin").value(rect.uMin()); - out.name("vMin").value(rect.vMin()); - out.name("uMax").value(rect.uMax()); - out.name("vMax").value(rect.vMax()); - out.endObject(); - } - out.endArray(); - out.endObject(); - } - - @Override - public DisableConfig read(JsonReader in) throws IOException { - in.beginObject(); - in.nextName(); - String name = in.nextString(); - in.nextName(); - String textureId = in.nextString(); - in.nextName(); - boolean disableAll = in.nextBoolean(); - in.nextName(); - in.beginArray(); - ArrayList rectangles = new ArrayList<>(); - while (in.hasNext()) { - in.beginObject(); - in.nextName(); - float uMin = (float) in.nextDouble(); - in.nextName(); - float vMin = (float) in.nextDouble(); - in.nextName(); - float uMax = (float) in.nextDouble(); - in.nextName(); - float vMax = (float) in.nextDouble(); - in.endObject(); - rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); - } - in.endArray(); - in.endObject(); - return new DisableConfig(name, textureId, disableAll, rectangles.toArray(UVRectangle[]::new)); - } - } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java index ea9cce32..22208f55 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java @@ -20,10 +20,6 @@ public OffsetConfig(float scale, float x, float y, float z, float pitch, float y this.roll = roll; } - public static OffsetConfig read(FriendlyByteBuf byteBuf) { - return new OffsetConfig(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - public void clamp() { x = Mth.clamp(x, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); y = Mth.clamp(y, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); diff --git a/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java b/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java index 1a0708a4..252d269f 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java +++ b/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java @@ -3,10 +3,6 @@ import net.minecraft.network.FriendlyByteBuf; public record UVRectangle(float uMin, float vMin, float uMax, float vMax) { - public static UVRectangle read(FriendlyByteBuf byteBuf) { - return new UVRectangle(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - public boolean contains(float u, float v) { return u >= uMin && u <= uMax && v >= vMin && v <= vMax; } diff --git a/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java b/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java new file mode 100644 index 00000000..f10e4dd4 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java @@ -0,0 +1,93 @@ +package com.xtracr.realcamera.config.serialization; + +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.DataResult; +import com.xtracr.realcamera.config.BindTarget; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.DecoderException; +import io.netty.handler.codec.EncoderException; +import net.minecraft.network.FriendlyByteBuf; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Base64; +import java.util.Map; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public interface ConfigSerializer { + ConfigSerializer SERIALIZER_703 = new ConfigSerializer703(); + Map SERIALIZERS = ImmutableMap.of( + SERIALIZER_703.version(), SERIALIZER_703 + ); + + static BindTarget readWithVersion(FriendlyByteBuf byteBuf) throws DecoderException, IllegalArgumentException { + short version = byteBuf.readShort(); + ConfigSerializer serializer = SERIALIZERS.get(version); + if (serializer == null) throw new IllegalArgumentException("Incompatible version: " + toSemVer(version)); + return serializer.readBindTarget(byteBuf); + } + + static void writeWithVersion(BindTarget bindTarget, FriendlyByteBuf byteBuf) throws EncoderException { + byteBuf.writeShort(SERIALIZER_703.version()); + bindTarget.write(byteBuf); + } + + static DataResult fromCompressedBase64(String base64) { + FriendlyByteBuf byteBuf = null; + try { + byte[] compressed = Base64.getDecoder().decode(base64); + InflaterInputStream inflaterStream = new InflaterInputStream(new ByteArrayInputStream(compressed)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int length; + while ((length = inflaterStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + byte[] bytes = outputStream.toByteArray(); + byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes)); + BindTarget target = readWithVersion(byteBuf); + if (target.isEmpty()) return DataResult.error(() -> "Invalid config format"); + return DataResult.success(target); + } catch (Exception e) { + return DataResult.error(() -> { + String message = e.getClass().getSimpleName(); + if (e instanceof IllegalArgumentException) message += ": " + e.getMessage(); + return message; + }); + } finally { + if (byteBuf != null) byteBuf.release(); + } + } + + static DataResult toCompressedBase64(BindTarget bindTarget) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + try { + writeWithVersion(bindTarget, byteBuf); + byte[] bytes = new byte[byteBuf.readableBytes()]; + byteBuf.getBytes(byteBuf.readerIndex(), bytes); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (DeflaterOutputStream deflaterStream = new DeflaterOutputStream(outputStream, new Deflater(Deflater.BEST_COMPRESSION))) { + deflaterStream.write(bytes); + } + String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + return DataResult.success(base64); + } catch (Exception e) { + return DataResult.error(() -> e.getClass().getSimpleName() + ": " + e.getMessage()); + } finally { + byteBuf.release(); + } + } + + private static String toSemVer(short version) { + int major = version / 10000; + int minor = version % 10000 / 100; + int patch = version % 100; + return major + "." + minor + "." + patch; + } + + short version(); + + BindTarget readBindTarget(FriendlyByteBuf byteBuf) throws DecoderException; +} diff --git a/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java b/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java new file mode 100644 index 00000000..9aa1b153 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java @@ -0,0 +1,78 @@ +package com.xtracr.realcamera.config.serialization; + +import com.xtracr.realcamera.config.BindTarget; +import com.xtracr.realcamera.config.DisableConfig; +import com.xtracr.realcamera.config.OffsetConfig; +import com.xtracr.realcamera.config.UVRectangle; +import io.netty.handler.codec.DecoderException; +import net.minecraft.network.FriendlyByteBuf; + +final class ConfigSerializer703 implements ConfigSerializer { + private static BindTarget.TargetConfig readTargetConfig(FriendlyByteBuf byteBuf) { + float forwardU = byteBuf.readFloat(); + float forwardV = byteBuf.readFloat(); + float upwardU = byteBuf.readFloat(); + float upwardV = byteBuf.readFloat(); + float posU = byteBuf.readFloat(); + float posV = byteBuf.readFloat(); + return new BindTarget.TargetConfig(forwardU, forwardV, upwardU, upwardV, posU, posV); + } + + private static BindTarget.BindConfig readBindConfig(FriendlyByteBuf byteBuf) { + byte bindFlags = byteBuf.readByte(); + boolean bindX = (bindFlags & 0x01) != 0; + boolean bindY = (bindFlags & 0x02) != 0; + boolean bindZ = (bindFlags & 0x04) != 0; + boolean bindRotation = (bindFlags & 0x08) != 0; + return new BindTarget.BindConfig(bindX, bindY, bindZ, bindRotation); + } + + private static OffsetConfig readOffsetConfig(FriendlyByteBuf byteBuf) { + float scale = byteBuf.readFloat(); + float x = byteBuf.readFloat(); + float y = byteBuf.readFloat(); + float z = byteBuf.readFloat(); + float pitch = byteBuf.readFloat(); + float yaw = byteBuf.readFloat(); + float roll = byteBuf.readFloat(); + return new OffsetConfig(scale, x, y, z, pitch, yaw, roll); + } + + private static DisableConfig readDisableConfig(FriendlyByteBuf byteBuf) { + String name = byteBuf.readUtf(); + String textureId = byteBuf.readUtf(); + boolean disableAll = byteBuf.readBoolean(); + UVRectangle[] rectangles = new UVRectangle[byteBuf.readVarInt()]; + for (int i = 0; i < rectangles.length; i++) rectangles[i] = readUVRectangle(byteBuf); + return new DisableConfig(name, textureId, disableAll, rectangles); + } + + private static UVRectangle readUVRectangle(FriendlyByteBuf byteBuf) { + float uMin = byteBuf.readFloat(); + float vMin = byteBuf.readFloat(); + float uMax = byteBuf.readFloat(); + float vMax = byteBuf.readFloat(); + return new UVRectangle(uMin, vMin, uMax, vMax); + } + + @Override + public short version() { + return 703; // 0.7.3 + } + + @Override + public BindTarget readBindTarget(FriendlyByteBuf byteBuf) throws DecoderException { + String name = byteBuf.readUtf(); + String textureId = byteBuf.readUtf(); + int priority = byteBuf.readVarInt(); + float disablingDepth = byteBuf.readFloat(); + BindTarget.TargetConfig targetConfig = readTargetConfig(byteBuf); + BindTarget.BindConfig bindConfig = readBindConfig(byteBuf); + OffsetConfig offsets = readOffsetConfig(byteBuf); + DisableConfig[] disableConfigs = new DisableConfig[byteBuf.readVarInt()]; + for (int i = 0; i < disableConfigs.length; i++) { + disableConfigs[i] = readDisableConfig(byteBuf); + } + return new BindTarget(name, textureId, priority, disablingDepth, targetConfig, bindConfig, offsets, disableConfigs); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java b/common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java new file mode 100644 index 00000000..4ec8383a --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java @@ -0,0 +1,62 @@ +package com.xtracr.realcamera.config.serialization; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.xtracr.realcamera.config.DisableConfig; +import com.xtracr.realcamera.config.UVRectangle; + +import java.io.IOException; +import java.util.ArrayList; + +public final class DisableConfigAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, DisableConfig value) throws IOException { + out.beginObject(); + out.name("name").value(value.name()); + out.name("textureId").value(value.textureId()); + out.name("disableAll").value(value.disableAll()); + out.name("rectangles"); + out.beginArray(); + for (UVRectangle rect : value.rectangles()) { + out.beginObject(); + out.name("uMin").value(rect.uMin()); + out.name("vMin").value(rect.vMin()); + out.name("uMax").value(rect.uMax()); + out.name("vMax").value(rect.vMax()); + out.endObject(); + } + out.endArray(); + out.endObject(); + } + + @Override + public DisableConfig read(JsonReader in) throws IOException { + in.beginObject(); + in.nextName(); + String name = in.nextString(); + in.nextName(); + String textureId = in.nextString(); + in.nextName(); + boolean disableAll = in.nextBoolean(); + in.nextName(); + in.beginArray(); + ArrayList rectangles = new ArrayList<>(); + while (in.hasNext()) { + in.beginObject(); + in.nextName(); + float uMin = (float) in.nextDouble(); + in.nextName(); + float vMin = (float) in.nextDouble(); + in.nextName(); + float uMax = (float) in.nextDouble(); + in.nextName(); + float vMax = (float) in.nextDouble(); + in.endObject(); + rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); + } + in.endArray(); + in.endObject(); + return new DisableConfig(name, textureId, disableAll, rectangles.toArray(UVRectangle[]::new)); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 3a3a3cca..76431770 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -10,6 +10,7 @@ import com.xtracr.realcamera.config.*; import com.xtracr.realcamera.config.BindTarget.BindConfig; import com.xtracr.realcamera.config.BindTarget.TargetConfig; +import com.xtracr.realcamera.config.serialization.ConfigSerializer; import com.xtracr.realcamera.gui.components.*; import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; @@ -58,15 +59,25 @@ public final class ModelViewScreen extends Screen { private VertexData[][] focusedPolyhedron = new VertexData[0][]; @Nullable private UVRectangleWidget focusedRectWidget; - private StringWidget rectWidgetsSizeWidget; - private EditBox textureIdField, nameField, disabledNameField, disabledIdField; - private NumberField priorityField, focusedRectWidgetNumberField; - private NumberField forwardUField, forwardVField, upwardUField, upwardVField, posUField, posVField; - private NumberField uMinField, vMinField, uMaxField, vMaxField; - private NumberField scaleField, depthField; - private final List disableConfigs = new ArrayList<>(); - private final List rectWidgets = new ArrayList<>(); - private final Map> hiddenNameMap = new HashMap<>(); + private final StringWidget rectWidgetsSizeWidget = new StringWidget(widgetWidth - 22, widgetHeight, CommonComponents.EMPTY, font); + private final EditBox nameField = createTextField(wideWidgetWidth, 20); + private final EditBox textureIdField = createTextField(wideWidgetWidth, 1024); + private final EditBox disabledNameField = createTextField(compactWidgetWidth, 20); + private final EditBox disabledIdField = createTextField(wideWidgetWidth, 1024); + private final NumberField priorityField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, null); + private final NumberField focusedRectWidgetNumberField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, null).setMin(0); + private final NumberField forwardUField = createFloatField(widgetWidth, 0); + private final NumberField forwardVField = createFloatField(widgetWidth, 0); + private final NumberField upwardUField = createFloatField(widgetWidth, 0); + private final NumberField upwardVField = createFloatField(widgetWidth, 0); + private final NumberField posUField = createFloatField(widgetWidth, 0); + private final NumberField posVField = createFloatField(widgetWidth, 0); + private final NumberField uMinField = createFloatField(widgetWidth * 2 - 24, 0).setMin(-1f).setMax(2f); + private final NumberField uMaxField = createFloatField(widgetWidth * 2 - 24, 0).setMin(-1f).setMax(2f); + private final NumberField vMinField = createFloatField(widgetWidth * 2 - 24, 0).setMin(-1f).setMax(2f); + private final NumberField vMaxField = createFloatField(widgetWidth * 2 - 24, 0).setMin(-1f).setMax(2f); + private final NumberField scaleField = createFloatField(widgetWidth, 1.0f).setMax(64.0f); + private final NumberField depthField = createFloatField(widgetWidth, 0.2f).setMax(16.0f); private final CycleIconButton showTextureButton = new CycleIconButton(48, 16, 0, 2).setOnValueChange(_ -> initWidgets(page)); private final CycleIconButton pauseButton = new CycleIconButton(0, 16, 0, 2); private final CycleIconButton bindXButton = new CycleIconButton(16, 16, 1, 2); @@ -81,6 +92,9 @@ public final class ModelViewScreen extends Screen { private final NumberWidgetPair offsetPitchPair = new NumberWidgetPair(font, "pitch", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); private final NumberWidgetPair offsetYawPair = new NumberWidgetPair(font, "yaw", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); private final NumberWidgetPair offsetRollPair = new NumberWidgetPair(font, "roll", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); + private final List disableConfigs = new ArrayList<>(); + private final List rectWidgets = new ArrayList<>(); + private final Map> hiddenNameMap = new HashMap<>(); private final List widgetPairs = List.of(offsetXPair, offsetYPair, offsetZPair, offsetPitchPair, offsetYawPair, offsetRollPair); private final CycleButton selectingButton = createCyclingButtonBuilder(ImmutableSortedMap.of( 0, LocUtil.MODEL_VIEW_WIDGET("forwardVector").withStyle(ChatFormatting.GREEN), @@ -160,22 +174,6 @@ private void initWidgets(int page) { } private void initLeftWidgets() { - rectWidgetsSizeWidget = new StringWidget(x + 4 + widgetWidth + 5 + font.width("/"), y + 4 + (widgetHeight + 2) * 3, widgetWidth - 22, widgetHeight, LocUtil.literal(String.valueOf(rectWidgets.size())), font); - forwardUField = createFloatField(widgetWidth, 0, forwardUField); - forwardVField = createFloatField(widgetWidth, 0, forwardVField); - upwardUField = createFloatField(widgetWidth, 0, upwardUField); - upwardVField = createFloatField(widgetWidth, 0, upwardVField); - posUField = createFloatField(widgetWidth, 0, posUField); - posVField = createFloatField(widgetWidth, 0, posVField); - textureIdField = createTextField(wideWidgetWidth, 1024, textureIdField); - disabledIdField = createTextField(wideWidgetWidth, 1024, disabledIdField); - focusedRectWidgetNumberField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, focusedRectWidgetNumberField).setMin(0).setMax(rectWidgets.size()); - uMinField = createFloatField(widgetWidth * 2 - 24, 0, uMinField).setMin(-1f).setMax(2f); - uMaxField = createFloatField(widgetWidth * 2 - 24, 0, uMaxField).setMin(-1f).setMax(2f); - vMinField = createFloatField(widgetWidth * 2 - 24, 0, vMinField).setMin(-1f).setMax(2f); - vMaxField = createFloatField(widgetWidth * 2 - 24, 0, vMaxField).setMin(-1f).setMax(2f); - scaleField = createFloatField(widgetWidth, 1.0f, scaleField).setMax(64.0f); - depthField = createFloatField(widgetWidth, 0.2f, depthField).setMax(16.0f); GridLayout grid = new GridLayout(); grid.defaultCellSetting().padding(4, 2, 0, 0); LayoutSettings smallSettings = grid.newCellSettings().padding(5, 3, 1, 1); @@ -217,7 +215,7 @@ private void initLeftWidgets() { rows.addChild(disableModeButton, 2); rows.addChild(disabledIdField, 2, smallSettings).setTooltip(createTooltip("textureId")); rows.addChild(selectionModeButton, 2); - rows.addChild(focusedRectWidgetNumberField, smallSettings).setOnValueChange(index -> { + rows.addChild(focusedRectWidgetNumberField.setMax(rectWidgets.size()), smallSettings).setOnValueChange(index -> { if (index == 0) focusedRectWidget = null; else if (index > 0 && index <= rectWidgets.size()) { focusedRectWidget = rectWidgets.get(index - 1); @@ -228,6 +226,8 @@ else if (index > 0 && index <= rectWidgets.size()) { } }).setTooltip(createTooltip("focusedRectangleNumber")); addRenderableWidget(new StringWidget(x + 4 + widgetWidth + 3, y + 4 + (widgetHeight + 2) * 3, 6, widgetHeight, LocUtil.literal("/"), font)); + rectWidgetsSizeWidget.setPosition(x + 4 + widgetWidth + 5 + font.width("/"), y + 4 + (widgetHeight + 2) * 3); + rectWidgetsSizeWidget.setMessage(LocUtil.literal(String.valueOf(rectWidgets.size()))); addRenderableWidget(rectWidgetsSizeWidget); rows.addChild(new SimpleIconButton(48, 0, _ -> deleteFocusedRectWidget()), grid.newCellSettings().padding(5 + widgetWidth - 18, 3, 1, 1)) .setTooltip(createTooltip("deleteSelectedRectangle")); @@ -262,15 +262,14 @@ else if (index > 0 && index <= rectWidgets.size()) { loadBindTarget(bindTarget); initWidgets(page); })); - rows.addChild(priorityField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, priorityField), smallSettings).setTooltip(createTooltip("priority")); - rows.addChild(nameField = createTextField(wideWidgetWidth, 20, nameField), 2, smallSettings).setTooltip(createTooltip("targetName")); + rows.addChild(priorityField, smallSettings).setTooltip(createTooltip("priority")); + rows.addChild(nameField, 2, smallSettings).setTooltip(createTooltip("targetName")); grid.arrangeElements(); FrameLayout.alignInRectangle(grid, x, y + 2, x + (xSize - middleWidth) / 2 - 4, y + ySize, 0, 0); grid.visitWidgets(this::addRenderableWidget); } private void initRightWidgets() { - disabledNameField = createTextField(compactWidgetWidth, 20, disabledNameField); GridLayout grid = new GridLayout(); grid.defaultCellSetting().padding(4, 2, 0, 0); LayoutSettings smallSettings = grid.newCellSettings().padding(5, 3, 1, 1); @@ -497,7 +496,7 @@ private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { private void importBindTarget(Button button) { String base64 = minecraft.keyboardHandler.getClipboard(); - DataResult result = BindTarget.fromCompressedBase64(base64); + DataResult result = ConfigSerializer.fromCompressedBase64(base64); switch (result) { case DataResult.Success success -> { BindTarget target = success.value(); @@ -512,7 +511,8 @@ private void importBindTarget(Button button) { } private void exportBindTarget(Button button) { - DataResult result = genBindTarget().toCompressedBase64(); + BindTarget target = genBindTarget(); + DataResult result = ConfigSerializer.toCompressedBase64(target); switch (result) { case DataResult.Success success -> { String base64 = success.value(); @@ -557,15 +557,7 @@ private void loadBindTarget(BindTarget target) { private BindTarget genBindTarget() { TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); - OffsetConfig offsets = new OffsetConfig( - scaleField.getNumber(), - offsetXPair.getNumber(), - offsetYPair.getNumber(), - offsetZPair.getNumber(), - offsetPitchPair.getNumber(), - offsetYawPair.getNumber(), - offsetRollPair.getNumber() - ); + OffsetConfig offsets = new OffsetConfig(scaleField.getNumber(), offsetXPair.getNumber(), offsetYPair.getNumber(), offsetZPair.getNumber(), offsetPitchPair.getNumber(), offsetYawPair.getNumber(), offsetRollPair.getNumber()); DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toArray(UVRectangle[]::new)); DisableConfig[] disableConfigArray = disableConfigs.toArray(new DisableConfig[0]); for (int i = 0; i < disableConfigArray.length; i++) { @@ -607,14 +599,13 @@ private DoubleSlider createSlider(String key, int width, double min, double max) return new DoubleSlider(width, widgetHeight, 0, min, max, d -> LocUtil.MODEL_VIEW_WIDGET(key, MathUtil.round(d, 2))); } - private NumberField createFloatField(int width, float defaultValue, @Nullable NumberField copyFrom) { - return NumberField.ofFloat(font, width - 2, widgetHeight - 2, defaultValue, copyFrom).setMax(1.0f).setMin(0f); + private NumberField createFloatField(int width, float defaultValue) { + return NumberField.ofFloat(font, width - 2, widgetHeight - 2, defaultValue, null).setMax(1.0f).setMin(0f); } - private EditBox createTextField(int width, int maxLength, @Nullable EditBox copyFrom) { + private EditBox createTextField(int width, int maxLength) { EditBox editBox = new EditBox(font, 0, 0, width - 2, widgetHeight - 2, CommonComponents.EMPTY); editBox.setMaxLength(maxLength); - if (copyFrom != null) editBox.setValue(copyFrom.getValue()); return editBox; } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java index b39ade48..9395c67d 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/IterableVertexBuffer.java @@ -289,7 +289,6 @@ public int characteristics() { return ORDERED | SIZED | SUBSIZED | NONNULL; } } - } private final class FastQuadReader implements Iterable { From 279e2b1d422dd319d9f8d6b9038e43eeedc6a9db Mon Sep 17 00:00:00 2001 From: xTracr Date: Sun, 14 Jun 2026 00:52:18 +0800 Subject: [PATCH 22/33] Refactor serialization to StreamCodec - Simplify renderCameraEntity matrix transform - Migrate from FriendlyByteBuf manual read/write to Minecraft StreamCodec - Rename config.serialization package to config.codec - Change array fields in config classes to list fields - Remove all manual write(FriendlyByteBuf) methods from config classes - DisableConfigAdapter: suppress unused nextName() returns with String _ --- .../com/xtracr/realcamera/RealCameraCore.java | 8 +- .../xtracr/realcamera/config/BindTarget.java | 45 ++------- .../realcamera/config/DisableConfig.java | 19 ++-- .../realcamera/config/OffsetConfig.java | 11 --- .../xtracr/realcamera/config/UVRectangle.java | 9 -- .../ConfigCodec.java} | 31 +++--- .../config/codec/ConfigCodec703.java | 95 +++++++++++++++++++ .../DisableConfigAdapter.java | 20 ++-- .../serialization/ConfigSerializer703.java | 78 --------------- .../realcamera/gui/ModelViewScreen.java | 22 ++--- gradle.properties | 8 +- gradle/wrapper/gradle-wrapper.properties | 3 +- 12 files changed, 151 insertions(+), 198 deletions(-) rename common/src/main/java/com/xtracr/realcamera/config/{serialization/ConfigSerializer.java => codec/ConfigCodec.java} (76%) create mode 100644 common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java rename common/src/main/java/com/xtracr/realcamera/config/{serialization => codec}/DisableConfigAdapter.java (84%) delete mode 100644 common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 4cd9e7ba..673c8ffc 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -99,12 +99,8 @@ public static void computeCamera(Minecraft client, float partialTicks) { } public static void renderCameraEntity(Minecraft client, float partialTicks, SubmitNodeCollector submitNodeCollector, Matrix4f modelView) { - Vec3 targetEulerAngle = MathUtil.getEulerAngleYXZ(lastResult.getRotation()); - Matrix4f invertedCameraPose = new Matrix4f() - .rotateZ((float) targetEulerAngle.z()) - .rotateX((float) targetEulerAngle.x()) - .rotateY((float) (Math.PI - targetEulerAngle.y())) - .transpose() + Matrix4f invertedCameraPose = new Matrix4f(lastResult.getRotation()) + .scale(-1f, 1f, -1f) .invert() .translate(Vec3.ZERO.subtract(lastResult.getPosition()).toVector3f()); PoseStack poseStack = new PoseStack(); diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java index 2e226b8a..10fb3f06 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -1,8 +1,5 @@ package com.xtracr.realcamera.config; -import net.minecraft.network.FriendlyByteBuf; - -import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -11,7 +8,7 @@ public record BindTarget( TargetConfig targetConfig, BindConfig bindConfig, OffsetConfig offsets, - DisableConfig[] disableConfigs) { + List disableConfigs) { public static final List DEFAULT_TARGETS; public static final BindTarget EMPTY = blank(null, null); @@ -27,7 +24,7 @@ public record BindTarget( public static BindTarget blank(String name, String textureId) { TargetConfig targetConfig = new TargetConfig(0, 0, 0, 0, 0, 0); BindConfig bindConfig = new BindConfig(false, true, false, false); - return new BindTarget(name, textureId, 0, 0.2f, targetConfig, bindConfig, new OffsetConfig(), new DisableConfig[0]); + return new BindTarget(name, textureId, 0, 0.2f, targetConfig, bindConfig, new OffsetConfig(), List.of()); } private static BindTarget vanillaTarget(String name, int priority, boolean shouldBind) { @@ -36,9 +33,9 @@ private static BindTarget vanillaTarget(String name, int priority, boolean shoul BindConfig bindConfig = new BindConfig(shouldBind, true, shouldBind, shouldBind); OffsetConfig offsets = new OffsetConfig(); offsets.x = -0.1f; - DisableConfig playerHead = new DisableConfig("player_head", textureId, false, new UVRectangle[]{new UVRectangle(0, 0, 1.0f, 0.25f)}); - DisableConfig dragonHead = new DisableConfig("dragon_head", "minecraft:textures/entity/enderdragon/dragon.png", true, new UVRectangle[0]); - DisableConfig[] disableConfigs = new DisableConfig[]{playerHead, dragonHead}; + DisableConfig playerHead = new DisableConfig("player_head", textureId, false, List.of(new UVRectangle(0, 0, 1.0f, 0.25f))); + DisableConfig dragonHead = new DisableConfig("dragon_head", "minecraft:textures/entity/enderdragon/dragon.png", true, List.of()); + List disableConfigs = List.of(playerHead, dragonHead); return new BindTarget(name, textureId, priority, 0.2f, targetConfig, bindConfig, offsets, disableConfigs); } @@ -47,42 +44,12 @@ public boolean isEmpty() { } public DisableConfig[] filteredDisableConfigs(Predicate filter) { - return Arrays.stream(disableConfigs).filter(filter).toArray(DisableConfig[]::new); - } - - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeUtf(name); - byteBuf.writeUtf(textureId); - byteBuf.writeVarInt(priority); - byteBuf.writeFloat(disablingDepth); - targetConfig.write(byteBuf); - bindConfig.write(byteBuf); - offsets.write(byteBuf); - byteBuf.writeVarInt(disableConfigs.length); - for (DisableConfig disableConfig : disableConfigs) { - disableConfig.write(byteBuf); - } + return disableConfigs.stream().filter(filter).toArray(DisableConfig[]::new); } public record TargetConfig(float forwardU, float forwardV, float upwardU, float upwardV, float posU, float posV) { - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeFloat(forwardU); - byteBuf.writeFloat(forwardV); - byteBuf.writeFloat(upwardU); - byteBuf.writeFloat(upwardV); - byteBuf.writeFloat(posU); - byteBuf.writeFloat(posV); - } } public record BindConfig(boolean bindX, boolean bindY, boolean bindZ, boolean bindRotation) { - public void write(FriendlyByteBuf byteBuf) { - byte bindFlags = 0; - if (bindX) bindFlags |= 0x01; - if (bindY) bindFlags |= 0x02; - if (bindZ) bindFlags |= 0x04; - if (bindRotation) bindFlags |= 0x08; - byteBuf.writeByte(bindFlags); - } } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java b/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java index e4958ac2..4572c856 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/DisableConfig.java @@ -1,10 +1,11 @@ package com.xtracr.realcamera.config; import com.google.gson.annotations.JsonAdapter; -import com.xtracr.realcamera.config.serialization.DisableConfigAdapter; +import com.xtracr.realcamera.config.codec.DisableConfigAdapter; import com.xtracr.realcamera.renderer.state.VertexData; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import net.minecraft.network.FriendlyByteBuf; + +import java.util.List; @JsonAdapter(DisableConfigAdapter.class) public final class DisableConfig { @@ -12,9 +13,9 @@ public final class DisableConfig { private final String name; private final String textureId; private final boolean disableAll; - private final UVRectangle[] rectangles; + private final List rectangles; - public DisableConfig(String name, String textureId, boolean disableAll, UVRectangle[] rectangles) { + public DisableConfig(String name, String textureId, boolean disableAll, List rectangles) { this.name = name; this.textureId = textureId; this.disableAll = disableAll; @@ -33,18 +34,10 @@ public boolean disableAll() { return disableAll; } - public UVRectangle[] rectangles() { + public List rectangles() { return rectangles; } - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeUtf(name); - byteBuf.writeUtf(textureId); - byteBuf.writeBoolean(disableAll); - byteBuf.writeVarInt(rectangles.length); - for (UVRectangle rect : rectangles) rect.write(byteBuf); - } - public boolean disable(VertexData vertex) { final float u = vertex.u(), v = vertex.v(); final long packed = (long) Float.floatToIntBits(u) << 32 | Float.floatToIntBits(v); diff --git a/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java index 22208f55..e3dded99 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java @@ -1,6 +1,5 @@ package com.xtracr.realcamera.config; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.util.Mth; public final class OffsetConfig { @@ -28,14 +27,4 @@ public void clamp() { yaw = Mth.wrapDegrees(yaw); roll = Mth.wrapDegrees(roll); } - - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeFloat(scale); - byteBuf.writeFloat(x); - byteBuf.writeFloat(y); - byteBuf.writeFloat(z); - byteBuf.writeFloat(pitch); - byteBuf.writeFloat(yaw); - byteBuf.writeFloat(roll); - } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java b/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java index 252d269f..320a906a 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java +++ b/common/src/main/java/com/xtracr/realcamera/config/UVRectangle.java @@ -1,16 +1,7 @@ package com.xtracr.realcamera.config; -import net.minecraft.network.FriendlyByteBuf; - public record UVRectangle(float uMin, float vMin, float uMax, float vMax) { public boolean contains(float u, float v) { return u >= uMin && u <= uMax && v >= vMin && v <= vMax; } - - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeFloat(uMin); - byteBuf.writeFloat(vMin); - byteBuf.writeFloat(uMax); - byteBuf.writeFloat(vMax); - } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java similarity index 76% rename from common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java rename to common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java index f10e4dd4..61900302 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java @@ -1,12 +1,13 @@ -package com.xtracr.realcamera.config.serialization; +package com.xtracr.realcamera.config.codec; import com.google.common.collect.ImmutableMap; import com.mojang.serialization.DataResult; import com.xtracr.realcamera.config.BindTarget; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -16,26 +17,26 @@ import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; -public interface ConfigSerializer { - ConfigSerializer SERIALIZER_703 = new ConfigSerializer703(); - Map SERIALIZERS = ImmutableMap.of( +public interface ConfigCodec extends StreamCodec { + ConfigCodec SERIALIZER_703 = new ConfigCodec703(); + Map SERIALIZERS = ImmutableMap.of( SERIALIZER_703.version(), SERIALIZER_703 ); - static BindTarget readWithVersion(FriendlyByteBuf byteBuf) throws DecoderException, IllegalArgumentException { + static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderException, IllegalArgumentException { short version = byteBuf.readShort(); - ConfigSerializer serializer = SERIALIZERS.get(version); + ConfigCodec serializer = SERIALIZERS.get(version); if (serializer == null) throw new IllegalArgumentException("Incompatible version: " + toSemVer(version)); - return serializer.readBindTarget(byteBuf); + return serializer.decode(byteBuf); } - static void writeWithVersion(BindTarget bindTarget, FriendlyByteBuf byteBuf) throws EncoderException { + static void writeWithVersion(ByteBuf byteBuf, BindTarget bindTarget) throws EncoderException { byteBuf.writeShort(SERIALIZER_703.version()); - bindTarget.write(byteBuf); + SERIALIZER_703.encode(byteBuf, bindTarget); } static DataResult fromCompressedBase64(String base64) { - FriendlyByteBuf byteBuf = null; + ByteBuf byteBuf = null; try { byte[] compressed = Base64.getDecoder().decode(base64); InflaterInputStream inflaterStream = new InflaterInputStream(new ByteArrayInputStream(compressed)); @@ -46,7 +47,7 @@ static DataResult fromCompressedBase64(String base64) { outputStream.write(buffer, 0, length); } byte[] bytes = outputStream.toByteArray(); - byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes)); + byteBuf = Unpooled.wrappedBuffer(bytes); BindTarget target = readWithVersion(byteBuf); if (target.isEmpty()) return DataResult.error(() -> "Invalid config format"); return DataResult.success(target); @@ -62,9 +63,9 @@ static DataResult fromCompressedBase64(String base64) { } static DataResult toCompressedBase64(BindTarget bindTarget) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + ByteBuf byteBuf = Unpooled.buffer(); try { - writeWithVersion(bindTarget, byteBuf); + writeWithVersion(byteBuf, bindTarget); byte[] bytes = new byte[byteBuf.readableBytes()]; byteBuf.getBytes(byteBuf.readerIndex(), bytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -88,6 +89,4 @@ private static String toSemVer(short version) { } short version(); - - BindTarget readBindTarget(FriendlyByteBuf byteBuf) throws DecoderException; } diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java new file mode 100644 index 00000000..59a681e2 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java @@ -0,0 +1,95 @@ +package com.xtracr.realcamera.config.codec; + +import com.xtracr.realcamera.config.BindTarget; +import com.xtracr.realcamera.config.BindTarget.BindConfig; +import com.xtracr.realcamera.config.BindTarget.TargetConfig; +import com.xtracr.realcamera.config.DisableConfig; +import com.xtracr.realcamera.config.OffsetConfig; +import com.xtracr.realcamera.config.UVRectangle; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.DecoderException; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import org.jspecify.annotations.NonNull; + +import java.util.List; + +final class ConfigCodec703 implements ConfigCodec { + static final StreamCodec TARGET_CONFIG_CODEC = StreamCodec.composite( + ByteBufCodecs.FLOAT, TargetConfig::forwardU, + ByteBufCodecs.FLOAT, TargetConfig::forwardV, + ByteBufCodecs.FLOAT, TargetConfig::upwardU, + ByteBufCodecs.FLOAT, TargetConfig::upwardV, + ByteBufCodecs.FLOAT, TargetConfig::posU, + ByteBufCodecs.FLOAT, TargetConfig::posV, + TargetConfig::new + ); + static final StreamCodec BIND_CONFIG_CODEC = StreamCodec.composite( + ByteBufCodecs.BYTE, + bindConfig -> { + byte bindFlags = 0; + if (bindConfig.bindX()) bindFlags |= 0x01; + if (bindConfig.bindY()) bindFlags |= 0x02; + if (bindConfig.bindZ()) bindFlags |= 0x04; + if (bindConfig.bindRotation()) bindFlags |= 0x08; + return bindFlags; + }, + bindFlags -> { + boolean bindX = (bindFlags & 0x01) != 0; + boolean bindY = (bindFlags & 0x02) != 0; + boolean bindZ = (bindFlags & 0x04) != 0; + boolean bindRotation = (bindFlags & 0x08) != 0; + return new BindConfig(bindX, bindY, bindZ, bindRotation); + } + ); + static final StreamCodec OFFSET_CONFIG_CODEC = StreamCodec.composite( + ByteBufCodecs.FLOAT, offsets -> offsets.x, + ByteBufCodecs.FLOAT, offsets -> offsets.x, + ByteBufCodecs.FLOAT, offsets -> offsets.y, + ByteBufCodecs.FLOAT, offsets -> offsets.z, + ByteBufCodecs.FLOAT, offsets -> offsets.pitch, + ByteBufCodecs.FLOAT, offsets -> offsets.yaw, + ByteBufCodecs.FLOAT, offsets -> offsets.roll, + OffsetConfig::new + ); + static final StreamCodec> UV_RECTANGLES_CODEC = StreamCodec.composite( + ByteBufCodecs.FLOAT, UVRectangle::uMin, + ByteBufCodecs.FLOAT, UVRectangle::vMin, + ByteBufCodecs.FLOAT, UVRectangle::uMax, + ByteBufCodecs.FLOAT, UVRectangle::vMax, + UVRectangle::new + ).apply(ByteBufCodecs.list()); + static final StreamCodec> DISABLE_CONFIGS_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, DisableConfig::name, + ByteBufCodecs.STRING_UTF8, DisableConfig::textureId, + ByteBufCodecs.BOOL, DisableConfig::disableAll, + UV_RECTANGLES_CODEC, DisableConfig::rectangles, + DisableConfig::new + ).apply(ByteBufCodecs.list()); + static final StreamCodec BIND_TARGET_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, BindTarget::name, + ByteBufCodecs.STRING_UTF8, BindTarget::textureId, + ByteBufCodecs.VAR_INT, BindTarget::priority, + ByteBufCodecs.FLOAT, BindTarget::disablingDepth, + TARGET_CONFIG_CODEC, BindTarget::targetConfig, + BIND_CONFIG_CODEC, BindTarget::bindConfig, + OFFSET_CONFIG_CODEC, BindTarget::offsets, + DISABLE_CONFIGS_CODEC, BindTarget::disableConfigs, + BindTarget::new + ); + + @Override + public short version() { + return 703; // 0.7.3 + } + + @Override + public @NonNull BindTarget decode(@NonNull ByteBuf byteBuf) throws DecoderException { + return BIND_TARGET_CODEC.decode(byteBuf); + } + + @Override + public void encode(@NonNull ByteBuf byteBuf, @NonNull BindTarget bindTarget) { + BIND_TARGET_CODEC.encode(byteBuf, bindTarget); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java b/common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java similarity index 84% rename from common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java rename to common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java index 4ec8383a..9f51eb65 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/serialization/DisableConfigAdapter.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java @@ -1,4 +1,4 @@ -package com.xtracr.realcamera.config.serialization; +package com.xtracr.realcamera.config.codec; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; @@ -33,30 +33,30 @@ public void write(JsonWriter out, DisableConfig value) throws IOException { @Override public DisableConfig read(JsonReader in) throws IOException { in.beginObject(); - in.nextName(); + String _ = in.nextName(); String name = in.nextString(); - in.nextName(); + String _ = in.nextName(); String textureId = in.nextString(); - in.nextName(); + String _ = in.nextName(); boolean disableAll = in.nextBoolean(); - in.nextName(); + String _ = in.nextName(); in.beginArray(); ArrayList rectangles = new ArrayList<>(); while (in.hasNext()) { in.beginObject(); - in.nextName(); + String _ = in.nextName(); float uMin = (float) in.nextDouble(); - in.nextName(); + String _ = in.nextName(); float vMin = (float) in.nextDouble(); - in.nextName(); + String _ = in.nextName(); float uMax = (float) in.nextDouble(); - in.nextName(); + String _ = in.nextName(); float vMax = (float) in.nextDouble(); in.endObject(); rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); } in.endArray(); in.endObject(); - return new DisableConfig(name, textureId, disableAll, rectangles.toArray(UVRectangle[]::new)); + return new DisableConfig(name, textureId, disableAll, rectangles); } } diff --git a/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java b/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java deleted file mode 100644 index 9aa1b153..00000000 --- a/common/src/main/java/com/xtracr/realcamera/config/serialization/ConfigSerializer703.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.xtracr.realcamera.config.serialization; - -import com.xtracr.realcamera.config.BindTarget; -import com.xtracr.realcamera.config.DisableConfig; -import com.xtracr.realcamera.config.OffsetConfig; -import com.xtracr.realcamera.config.UVRectangle; -import io.netty.handler.codec.DecoderException; -import net.minecraft.network.FriendlyByteBuf; - -final class ConfigSerializer703 implements ConfigSerializer { - private static BindTarget.TargetConfig readTargetConfig(FriendlyByteBuf byteBuf) { - float forwardU = byteBuf.readFloat(); - float forwardV = byteBuf.readFloat(); - float upwardU = byteBuf.readFloat(); - float upwardV = byteBuf.readFloat(); - float posU = byteBuf.readFloat(); - float posV = byteBuf.readFloat(); - return new BindTarget.TargetConfig(forwardU, forwardV, upwardU, upwardV, posU, posV); - } - - private static BindTarget.BindConfig readBindConfig(FriendlyByteBuf byteBuf) { - byte bindFlags = byteBuf.readByte(); - boolean bindX = (bindFlags & 0x01) != 0; - boolean bindY = (bindFlags & 0x02) != 0; - boolean bindZ = (bindFlags & 0x04) != 0; - boolean bindRotation = (bindFlags & 0x08) != 0; - return new BindTarget.BindConfig(bindX, bindY, bindZ, bindRotation); - } - - private static OffsetConfig readOffsetConfig(FriendlyByteBuf byteBuf) { - float scale = byteBuf.readFloat(); - float x = byteBuf.readFloat(); - float y = byteBuf.readFloat(); - float z = byteBuf.readFloat(); - float pitch = byteBuf.readFloat(); - float yaw = byteBuf.readFloat(); - float roll = byteBuf.readFloat(); - return new OffsetConfig(scale, x, y, z, pitch, yaw, roll); - } - - private static DisableConfig readDisableConfig(FriendlyByteBuf byteBuf) { - String name = byteBuf.readUtf(); - String textureId = byteBuf.readUtf(); - boolean disableAll = byteBuf.readBoolean(); - UVRectangle[] rectangles = new UVRectangle[byteBuf.readVarInt()]; - for (int i = 0; i < rectangles.length; i++) rectangles[i] = readUVRectangle(byteBuf); - return new DisableConfig(name, textureId, disableAll, rectangles); - } - - private static UVRectangle readUVRectangle(FriendlyByteBuf byteBuf) { - float uMin = byteBuf.readFloat(); - float vMin = byteBuf.readFloat(); - float uMax = byteBuf.readFloat(); - float vMax = byteBuf.readFloat(); - return new UVRectangle(uMin, vMin, uMax, vMax); - } - - @Override - public short version() { - return 703; // 0.7.3 - } - - @Override - public BindTarget readBindTarget(FriendlyByteBuf byteBuf) throws DecoderException { - String name = byteBuf.readUtf(); - String textureId = byteBuf.readUtf(); - int priority = byteBuf.readVarInt(); - float disablingDepth = byteBuf.readFloat(); - BindTarget.TargetConfig targetConfig = readTargetConfig(byteBuf); - BindTarget.BindConfig bindConfig = readBindConfig(byteBuf); - OffsetConfig offsets = readOffsetConfig(byteBuf); - DisableConfig[] disableConfigs = new DisableConfig[byteBuf.readVarInt()]; - for (int i = 0; i < disableConfigs.length; i++) { - disableConfigs[i] = readDisableConfig(byteBuf); - } - return new BindTarget(name, textureId, priority, disablingDepth, targetConfig, bindConfig, offsets, disableConfigs); - } -} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 76431770..e7d5fe46 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -10,7 +10,7 @@ import com.xtracr.realcamera.config.*; import com.xtracr.realcamera.config.BindTarget.BindConfig; import com.xtracr.realcamera.config.BindTarget.TargetConfig; -import com.xtracr.realcamera.config.serialization.ConfigSerializer; +import com.xtracr.realcamera.config.codec.ConfigCodec; import com.xtracr.realcamera.gui.components.*; import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; @@ -291,7 +291,7 @@ private void initRightWidgets() { button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyTextureId").withStyle(ChatFormatting.RED))); } else { button.setTooltip(createTooltip("saveAs")); - DisableConfig disableConfig = new DisableConfig(name, textureId, disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toArray(UVRectangle[]::new)); + DisableConfig disableConfig = new DisableConfig(name, textureId, disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toList()); for (int i = 0; i < disableConfigs.size(); i++) { if (disableConfigs.get(i).name().equals(name)) { disableConfigs.set(i, disableConfig); @@ -496,7 +496,7 @@ private Vec2 translateXYToUV(float x, float y, ScreenRectangle screenArea) { private void importBindTarget(Button button) { String base64 = minecraft.keyboardHandler.getClipboard(); - DataResult result = ConfigSerializer.fromCompressedBase64(base64); + DataResult result = ConfigCodec.fromCompressedBase64(base64); switch (result) { case DataResult.Success success -> { BindTarget target = success.value(); @@ -512,7 +512,7 @@ private void importBindTarget(Button button) { private void exportBindTarget(Button button) { BindTarget target = genBindTarget(); - DataResult result = ConfigSerializer.toCompressedBase64(target); + DataResult result = ConfigCodec.toCompressedBase64(target); switch (result) { case DataResult.Success success -> { String base64 = success.value(); @@ -551,20 +551,20 @@ private void loadBindTarget(BindTarget target) { offsetYawPair.setNumber(offsets.yaw); offsetRollPair.setNumber(offsets.roll); disableConfigs.clear(); - disableConfigs.addAll(List.of(target.disableConfigs())); + disableConfigs.addAll(target.disableConfigs()); } private BindTarget genBindTarget() { TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); OffsetConfig offsets = new OffsetConfig(scaleField.getNumber(), offsetXPair.getNumber(), offsetYPair.getNumber(), offsetZPair.getNumber(), offsetPitchPair.getNumber(), offsetYawPair.getNumber(), offsetRollPair.getNumber()); - DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toArray(UVRectangle[]::new)); - DisableConfig[] disableConfigArray = disableConfigs.toArray(new DisableConfig[0]); - for (int i = 0; i < disableConfigArray.length; i++) { - if (disableConfigArray[i].name().equals(currentDisableConfig.name())) - disableConfigArray[i] = currentDisableConfig; + DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toList()); + List newDisableConfigs = new ArrayList<>(disableConfigs); + for (int i = 0; i < newDisableConfigs.size(); i++) { + if (newDisableConfigs.get(i).name().equals(currentDisableConfig.name())) + newDisableConfigs.set(i, currentDisableConfig); } - return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, disableConfigArray); + return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, newDisableConfigs); } private UVRectangleWidget addRectWidget(UVRectangleWidget rectWidget) { diff --git a/gradle.properties b/gradle.properties index d91b01e5..1539e38e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,14 +7,14 @@ java_version=25 minecraft_version=26.1.2 enabled_platforms=fabric,neoforge loom_version=1.16-SNAPSHOT -fabric_loader_version=0.19.2 -neoforge_version=26.1.2.36-beta +fabric_loader_version=0.19.3 +neoforge_version=26.1.2.73 moddev_version=2.0.141 ## Mod Properties mod_id=realcamera mod_version=0.7.8-beta mod_group_id=com.xtracr.realcamera ## Dependencies -fabric_api_version=0.147.0+26.1.2 +fabric_api_version=0.150.0+26.1.2 cloth_config_version=26.1.154 -modmenu_version=18.0.0-alpha.8 +modmenu_version=18.0.0-beta.1 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 358d405e..1a704683 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Tue May 12 13:08:14 CST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d1b16d4c4bb503e6083dfb892b3d62b332bec319 Mon Sep 17 00:00:00 2001 From: xTracr Date: Tue, 16 Jun 2026 13:05:06 +0800 Subject: [PATCH 23/33] Some minor improvements --- .../xtracr/realcamera/config/ConfigFile.java | 1 + .../com/xtracr/realcamera/config/ModConfig.java | 4 ++-- .../realcamera/config/codec/ConfigCodec.java | 17 ++++++++--------- .../realcamera/config/codec/ConfigCodec703.java | 2 +- .../gui/components/NumberWidgetPair.java | 12 ++++++------ .../xtracr/realcamera/mixin/MixinCamera.java | 4 ++-- .../realcamera/mixin/MixinGameRenderer.java | 4 ++-- .../realcamera/mixin/MixinLocalPlayer.java | 5 +++-- .../renderer/BuiltIterableBuffer.java | 1 + gradle.properties | 2 +- 10 files changed, 27 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java index 548ee8f9..e5af6e36 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java @@ -55,6 +55,7 @@ public static void reset() { } } + @SuppressWarnings("ResultOfMethodCallIgnored") private static Path getPath() { File configDir = new File(Minecraft.getInstance().gameDirectory, "config"); if (!configDir.exists()) configDir.mkdirs(); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 55b69d56..4fea0a8f 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -12,13 +12,13 @@ public final class ModConfig { public static final double MIN_OFFSET_D = -1.0, MAX_OFFSET_D = 1.0; public static final float MIN_OFFSET_F = -1.0f, MAX_OFFSET_F = 1.0f; + public final Classic classic = new Classic(); + public final Binding binding = new Binding(); public boolean enabled = false; public boolean isClassic = false; public boolean dynamicCrosshair = false; public boolean renderModel = true; public double adjustStep = 0.01; - public Classic classic = new Classic(); - public Binding binding = new Binding(); public void clamp() { adjustStep = Mth.clamp(adjustStep, 0.0, MAX_OFFSET_D); diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java index 61900302..bde2f41f 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java @@ -1,38 +1,37 @@ package com.xtracr.realcamera.config.codec; -import com.google.common.collect.ImmutableMap; import com.mojang.serialization.DataResult; import com.xtracr.realcamera.config.BindTarget; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; +import it.unimi.dsi.fastutil.shorts.Short2ReferenceMap; import net.minecraft.network.codec.StreamCodec; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Base64; -import java.util.Map; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; public interface ConfigCodec extends StreamCodec { - ConfigCodec SERIALIZER_703 = new ConfigCodec703(); - Map SERIALIZERS = ImmutableMap.of( - SERIALIZER_703.version(), SERIALIZER_703 + ConfigCodec CODEC_703 = new ConfigCodec703(); + Short2ReferenceMap CODECS = Short2ReferenceMap.ofEntries( + Short2ReferenceMap.entry(CODEC_703.version(), CODEC_703) ); static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderException, IllegalArgumentException { short version = byteBuf.readShort(); - ConfigCodec serializer = SERIALIZERS.get(version); - if (serializer == null) throw new IllegalArgumentException("Incompatible version: " + toSemVer(version)); + ConfigCodec serializer = CODECS.get(version); + if (serializer == null) throw new IllegalArgumentException("Incompatible version: " + toSemVer(version)); return serializer.decode(byteBuf); } static void writeWithVersion(ByteBuf byteBuf, BindTarget bindTarget) throws EncoderException { - byteBuf.writeShort(SERIALIZER_703.version()); - SERIALIZER_703.encode(byteBuf, bindTarget); + byteBuf.writeShort(CODEC_703.version()); + CODEC_703.encode(byteBuf, bindTarget); } static DataResult fromCompressedBase64(String base64) { diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java index 59a681e2..b662afc7 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java @@ -43,7 +43,7 @@ final class ConfigCodec703 implements ConfigCodec { } ); static final StreamCodec OFFSET_CONFIG_CODEC = StreamCodec.composite( - ByteBufCodecs.FLOAT, offsets -> offsets.x, + ByteBufCodecs.FLOAT, offsets -> offsets.scale, ByteBufCodecs.FLOAT, offsets -> offsets.x, ByteBufCodecs.FLOAT, offsets -> offsets.y, ByteBufCodecs.FLOAT, offsets -> offsets.z, diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java index a610039d..6013ab89 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/NumberWidgetPair.java @@ -24,13 +24,17 @@ public NumberWidgetPair(Font font, String translationKey, int width, int height, setUseSlider(true); } + public float getNumber() { + return isUseSlider() ? (float) slider.getNumber() : field.getNumber(); + } + public void setNumber(float value) { slider.setNumber(value); field.setNumber(value); } - public float getNumber() { - return isUseSlider() ? (float) slider.getNumber() : field.getNumber(); + public boolean isUseSlider() { + return useSlider; } public void setUseSlider(boolean useSlider) { @@ -39,10 +43,6 @@ public void setUseSlider(boolean useSlider) { field.active = !useSlider; } - public boolean isUseSlider() { - return useSlider; - } - public void syncAndSwitch(boolean useSlider) { setUseSlider(useSlider); if (useSlider) slider.setNumber(field.getNumber()); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java index e9d20c15..3f84c012 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java @@ -119,10 +119,10 @@ public abstract class MixinCamera { protected abstract float calculateFov(float partialTicks); @Shadow - protected abstract void move(float x, float y, float z); + protected abstract void move(float forwards, float up, float right); @Shadow - protected abstract void setRotation(float yaw, float pitch); + protected abstract void setRotation(float yRot, float xRot); @Shadow protected abstract void setPosition(Vec3 position); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java index 897705e6..9818279f 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java @@ -24,10 +24,10 @@ public abstract class MixinGameRenderer { private Camera mainCamera; @Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;update(Lnet/minecraft/client/DeltaTracker;)V")) - private void realcamera$atCameraUpdate(DeltaTracker deltaTracker, boolean renderLevel, CallbackInfo ci) { + private void realcamera$atCameraUpdate(DeltaTracker deltaTracker, boolean advanceGameTime, CallbackInfo ci) { float partialTicks = deltaTracker.getGameTimeDeltaPartialTick(true); CompatibilityHelper.NEA_setDeltaTick(partialTicks); - RealCameraCore.initialize(minecraft, renderLevel); + RealCameraCore.initialize(minecraft, advanceGameTime); if (RealCameraCore.isActive() && !ConfigFile.config().isClassic) { minecraft.getEntityRenderDispatcher().prepare(mainCamera, minecraft.crosshairPickEntity); RealCameraCore.computeCamera(minecraft, partialTicks); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java index 1e69cefa..fe437128 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java @@ -36,7 +36,7 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { } @WrapOperation(method = "pick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;")) - private static @Nullable EntityHitResult realcamera$wrapGetEntityHitResult(Entity except, Vec3 from, Vec3 to, AABB box, Predicate matching, double maxValue, Operation original, Entity cameraEntity, double blockInteractionRange, double entityInteractionRange, float partialTicks) { + private static @Nullable EntityHitResult realcamera$wrapGetEntityHitResult(Entity except, Vec3 from, Vec3 _to, AABB box, Predicate matching, double maxValue, Operation original, Entity cameraEntity, double blockInteractionRange, double entityInteractionRange, float partialTicks) { if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { double interactionRange = Math.max(blockInteractionRange, entityInteractionRange); Pair fromAndTo = RaycastUtil.getFromAndTo(cameraEntity, interactionRange * interactionRange, partialTicks); @@ -48,7 +48,7 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { CrosshairUtil.capturedEntityHitResult = ProjectileUtil.getEntityHitResult(except, newFrom, newTo, newBox, matching, sqDistance); return CrosshairUtil.capturedEntityHitResult; } - return original.call(except, from, to, box, matching, maxValue); + return original.call(except, from, _to, box, matching, maxValue); } @Inject(method = "getRopeHoldPosition", at = @At("HEAD"), cancellable = true) @@ -56,6 +56,7 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { if (DisableHelper.RENDER_HANDS.disabled(this)) cir.setReturnValue(super.getRopeHoldPosition(partialTickTime)); } + @SuppressWarnings("resource") @Override public @NonNull HitResult pick(double maxDistance, float partialTicks, boolean includeFluids) { if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java index 2f307a72..45f27f86 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -29,6 +29,7 @@ public static BuiltIterableBuffer buildFrom(RenderType renderType, MeshData mesh return primitives; } + @SuppressWarnings("ResultOfMethodCallIgnored") public VertexData[] @Nullable [] findPrimitives(UV[] uvs) { int uvsLength = uvs.length; VertexData[][] primitives = new VertexData[uvsLength][]; diff --git a/gradle.properties b/gradle.properties index 1539e38e..4a404320 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -# Done to increase the memory available to gradle. +# Done to increase the memory available to Gradle. org.gradle.jvmargs=-Xmx4G -XX:+UseG1GC org.gradle.parallel=true org.gradle.configuration-cache=false From f37a309389da40dc8ade5f78bd686a065924e53a Mon Sep 17 00:00:00 2001 From: rsdadada Date: Tue, 23 Jun 2026 19:14:50 +0800 Subject: [PATCH 24/33] =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=8B=89=E5=8F=96?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20#213?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix model view config interactions * Clarify disable setting add tooltip --- .../realcamera/gui/ModelViewScreen.java | 167 ++++++++++++++---- .../assets/realcamera/lang/be_by.json | 4 +- .../assets/realcamera/lang/en_us.json | 4 +- .../assets/realcamera/lang/es_es.json | 4 +- .../assets/realcamera/lang/fr_fr.json | 4 +- .../assets/realcamera/lang/ja_jp.json | 4 +- .../assets/realcamera/lang/ko_kr.json | 4 +- .../resources/assets/realcamera/lang/lzh.json | 4 +- .../assets/realcamera/lang/pl_pl.json | 4 +- .../assets/realcamera/lang/pt_br.json | 4 +- .../assets/realcamera/lang/pt_pt.json | 4 +- .../assets/realcamera/lang/ru_ru.json | 4 +- .../assets/realcamera/lang/tr_tr.json | 4 +- .../assets/realcamera/lang/uk_ua.json | 4 +- .../assets/realcamera/lang/zh_cn.json | 4 +- .../assets/realcamera/lang/zh_hk.json | 4 +- .../assets/realcamera/lang/zh_tw.json | 4 +- 17 files changed, 168 insertions(+), 63 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index e7d5fe46..7c071f39 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -45,6 +45,7 @@ public final class ModelViewScreen extends Screen { private static final int SELECTION_COLOR = 0x4F3333CC, SELECTION_HOVER_COLOR = 0x2F3333CC, OUTLINE_COLOR = 0xAAFFFFFF; private static final int SIDE_PANEL_BG = 0xFF444444, CENTER_PANEL_BG = 0xFF222222; private static final int DEFAULT_SCALE = 80, MIN_SCALE = 16, MAX_SCALE = 1024; + private static final int CONFIG_NAME_MAX_LENGTH = 20; private final int xSize = 450, ySize = 206, middleWidth = xSize - 200, widgetWidth = (xSize - middleWidth) / 4 - 8, widgetHeight = 18, wideWidgetWidth = widgetWidth * 2 + 4, compactWidgetWidth = widgetWidth * 2 - 18; private int x, y, page = 0; private InputConstants.Key modifierKey = InputConstants.getKey(ConfigFile.config().binding.screenModifierKey); @@ -60,9 +61,9 @@ public final class ModelViewScreen extends Screen { @Nullable private UVRectangleWidget focusedRectWidget; private final StringWidget rectWidgetsSizeWidget = new StringWidget(widgetWidth - 22, widgetHeight, CommonComponents.EMPTY, font); - private final EditBox nameField = createTextField(wideWidgetWidth, 20); + private final EditBox nameField = createTextField(wideWidgetWidth, CONFIG_NAME_MAX_LENGTH); private final EditBox textureIdField = createTextField(wideWidgetWidth, 1024); - private final EditBox disabledNameField = createTextField(compactWidgetWidth, 20); + private final EditBox disabledNameField = createTextField(compactWidgetWidth, CONFIG_NAME_MAX_LENGTH); private final EditBox disabledIdField = createTextField(wideWidgetWidth, 1024); private final NumberField priorityField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, null); private final NumberField focusedRectWidgetNumberField = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, null).setMin(0); @@ -255,14 +256,21 @@ else if (index > 0 && index <= rectWidgets.size()) { button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyName").withStyle(ChatFormatting.RED))); return; } + if (textureIdField.getValue().isBlank()) { + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyTextureId").withStyle(ChatFormatting.RED))); + return; + } + if (toggleCategoryButton.getValue() == Category.DISABLE && !syncDisableDraft(button, true)) return; button.setTooltip(null); BindTarget bindTarget = genBindTarget(); ConfigFile.config().putBindTarget(bindTarget); ConfigFile.save(); - loadBindTarget(bindTarget); initWidgets(page); })); rows.addChild(priorityField, smallSettings).setTooltip(createTooltip("priority")); + boolean editableName = toggleCategoryButton.getValue() == Category.CONFIGS; + nameField.setEditable(editableName); + if (!editableName && nameField.isFocused()) nameField.setFocused(false); rows.addChild(nameField, 2, smallSettings).setTooltip(createTooltip("targetName")); grid.arrangeElements(); FrameLayout.alignInRectangle(grid, x, y + 2, x + (xSize - middleWidth) / 2 - 4, y + ySize, 0, 0); @@ -284,22 +292,8 @@ private void initRightWidgets() { size = disableConfigs.size(); rows.addChild(disabledNameField, 3, smallSettings).setTooltip(createTooltip("disabledName")); rows.addChild(new SimpleIconButton(64, 0, button -> { - String name = disabledNameField.getValue(), textureId = disabledIdField.getValue(); - if (name.isBlank()) { - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyName").withStyle(ChatFormatting.RED))); - } else if (textureId.isBlank()) { - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyTextureId").withStyle(ChatFormatting.RED))); - } else { + if (syncDisableDraft(button, false)) { button.setTooltip(createTooltip("saveAs")); - DisableConfig disableConfig = new DisableConfig(name, textureId, disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toList()); - for (int i = 0; i < disableConfigs.size(); i++) { - if (disableConfigs.get(i).name().equals(name)) { - disableConfigs.set(i, disableConfig); - initWidgets(page); - return; - } - } - disableConfigs.add(disableConfig); initWidgets(page); } }), smallSettings).setTooltip(createTooltip("saveAs")); @@ -314,16 +308,13 @@ private void initRightWidgets() { }) .setPosition(x + (xSize + middleWidth) / 2 - 20, y + 5 + (widgetHeight + 2) * (2 + i % widgetsPerPage)); rows.addChild(createButton(LocUtil.literal(config.name()), compactWidgetWidth, _ -> { - disabledNameField.setValue(config.name()); - disabledIdField.setValue(config.textureId()); - disableModeButton.setValue(config.disableAll() ? 0 : 1); - rectWidgets.clear(); - for (UVRectangle rect : config.rectangles()) rectWidgets.add(createRectWidget(rect)); + loadDisableConfig(config); initWidgets(page); }), 3).setTooltip(Tooltip.create(LocUtil.literal(config.name()))); rows.addChild(new SimpleIconButton(48, 0, _ -> { disableConfigs.removeIf(disableConfig -> disableConfig.name().equals(config.name())); - if (disabledNameField.getValue().equals(config.name())) rectWidgets.clear(); + hiddenNameMap.values().forEach(names -> names.remove(config.name())); + if (disabledNameField.getValue().equals(config.name())) clearDisableDraft(); initWidgets(page * widgetsPerPage > size - 2 && size > 1 ? page - 1 : page); }), smallSettings); } @@ -335,6 +326,7 @@ private void initRightWidgets() { size = fixedTargetCount + targetList.size(); for (int i = page * widgetsPerPage; i < Math.min((page + 1) * widgetsPerPage, size); i++) { BindTarget target = i < fixedTargetCount ? fixedTargetList.get(i) : targetList.get(i - fixedTargetCount); + final int targetIndex = i; String name = target.name(); rows.addChild(createButton(LocUtil.literal(name), compactWidgetWidth, _ -> loadBindTarget(target)), 3) .setTooltip(Tooltip.create(name.equals(RealCameraCore.currentTarget().name()) ? @@ -345,6 +337,7 @@ private void initRightWidgets() { rows.addChild(new SimpleIconButton(48, 0, _ -> { targetList.remove(target); ConfigFile.save(); + if (nameField.getValue().equals(target.name())) loadAdjacentBindTarget(fixedTargetList, targetList, targetIndex); initWidgets(page * widgetsPerPage > size - 2 && size > 1 ? page - 1 : page); }), smallSettings); } @@ -526,6 +519,123 @@ private void exportBindTarget(Button button) { } } + private void clearDisableDraft() { + disabledNameField.setValue(""); + disabledIdField.setValue(""); + focusedRectWidget = null; + rectWidgets.clear(); + focusedRectWidgetNumberField.setMax(0); + focusedRectWidgetNumberField.setNumber(0); + rectWidgetsSizeWidget.setMessage(LocUtil.literal("0")); + uMinField.setNumber(0f); + vMinField.setNumber(0f); + uMaxField.setNumber(0f); + vMaxField.setNumber(0f); + } + + private void loadDisableConfig(DisableConfig config) { + disabledNameField.setValue(config.name()); + disabledIdField.setValue(config.textureId()); + disableModeButton.setValue(config.disableAll() ? 0 : 1); + focusedRectWidget = null; + rectWidgets.clear(); + for (UVRectangle rect : config.rectangles()) rectWidgets.add(createRectWidget(rect)); + focusedRectWidgetNumberField.setMax(rectWidgets.size()); + focusedRectWidgetNumberField.setNumber(0); + rectWidgetsSizeWidget.setMessage(LocUtil.literal(String.valueOf(rectWidgets.size()))); + } + + private boolean syncDisableDraft(Button button, boolean autoName) { + String name = disabledNameField.getValue(); + String textureId = disabledIdField.getValue(); + if (name.isBlank()) { + if (!autoName) { + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyName").withStyle(ChatFormatting.RED))); + return false; + } + if (!hasMeaningfulDisableDraft()) { + if (textureId.isBlank() && !rectWidgets.isEmpty()) { + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyTextureId").withStyle(ChatFormatting.RED))); + return false; + } + return true; + } + name = generateDisableConfigName(textureId); + disabledNameField.setValue(name); + } + if (textureId.isBlank()) { + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyTextureId").withStyle(ChatFormatting.RED))); + return false; + } + DisableConfig disableConfig = new DisableConfig(name, textureId, disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toList()); + upsertDisableConfig(disableConfig); + return true; + } + + private boolean hasMeaningfulDisableDraft() { + return !disabledIdField.getValue().isBlank() && (disableModeButton.getValue() == 0 || !rectWidgets.isEmpty()); + } + + private void upsertDisableConfig(DisableConfig disableConfig) { + for (int i = 0; i < disableConfigs.size(); i++) { + if (disableConfigs.get(i).name().equals(disableConfig.name())) { + disableConfigs.set(i, disableConfig); + return; + } + } + disableConfigs.add(disableConfig); + } + + private String generateDisableConfigName(String textureId) { + String base = textureId.trim(); + int separatorIndex = Math.max(base.lastIndexOf('/'), base.lastIndexOf(':')); + if (separatorIndex >= 0 && separatorIndex < base.length() - 1) base = base.substring(separatorIndex + 1); + int extensionIndex = base.lastIndexOf('.'); + if (extensionIndex > 0) base = base.substring(0, extensionIndex); + base = sanitizeDisableConfigName(base); + if (base.length() > CONFIG_NAME_MAX_LENGTH) base = base.substring(0, CONFIG_NAME_MAX_LENGTH); + + String candidate = base; + for (int suffix = 2; disableConfigNameExists(candidate); suffix++) { + String suffixText = "_" + suffix; + int baseLength = Math.min(base.length(), Math.max(1, CONFIG_NAME_MAX_LENGTH - suffixText.length())); + candidate = base.substring(0, baseLength) + suffixText; + } + return candidate; + } + + private String sanitizeDisableConfigName(String name) { + StringBuilder builder = new StringBuilder(); + boolean lastWasSeparator = false; + for (int i = 0; i < name.length(); i++) { + char c = Character.toLowerCase(name.charAt(i)); + if (Character.isLetterOrDigit(c)) { + builder.append(c); + lastWasSeparator = false; + } else if ((c == '_' || c == '-') && builder.length() > 0 && !lastWasSeparator) { + builder.append(c); + lastWasSeparator = true; + } else if (builder.length() > 0 && !lastWasSeparator) { + builder.append('_'); + lastWasSeparator = true; + } + } + while (!builder.isEmpty() && (builder.charAt(builder.length() - 1) == '_' || builder.charAt(builder.length() - 1) == '-')) + builder.deleteCharAt(builder.length() - 1); + return builder.isEmpty() ? "disable" : builder.toString(); + } + + private boolean disableConfigNameExists(String name) { + return disableConfigs.stream().anyMatch(disableConfig -> disableConfig.name().equals(name)); + } + + private void loadAdjacentBindTarget(List fixedTargetList, List targetList, int deletedIndex) { + List targets = new ArrayList<>(fixedTargetList); + targets.addAll(targetList); + if (targets.isEmpty()) loadBindTarget(BindTarget.blank("", "")); + else loadBindTarget(targets.get(Math.min(deletedIndex, targets.size() - 1))); + } + private void loadBindTarget(BindTarget target) { if (target.isEmpty()) return; nameField.setValue(target.name()); @@ -552,19 +662,14 @@ private void loadBindTarget(BindTarget target) { offsetRollPair.setNumber(offsets.roll); disableConfigs.clear(); disableConfigs.addAll(target.disableConfigs()); + clearDisableDraft(); } private BindTarget genBindTarget() { TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); OffsetConfig offsets = new OffsetConfig(scaleField.getNumber(), offsetXPair.getNumber(), offsetYPair.getNumber(), offsetZPair.getNumber(), offsetPitchPair.getNumber(), offsetYawPair.getNumber(), offsetRollPair.getNumber()); - DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toList()); - List newDisableConfigs = new ArrayList<>(disableConfigs); - for (int i = 0; i < newDisableConfigs.size(); i++) { - if (newDisableConfigs.get(i).name().equals(currentDisableConfig.name())) - newDisableConfigs.set(i, currentDisableConfig); - } - return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, newDisableConfigs); + return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, new ArrayList<>(disableConfigs)); } private UVRectangleWidget addRectWidget(UVRectangleWidget rectWidget) { diff --git a/common/src/main/resources/assets/realcamera/lang/be_by.json b/common/src/main/resources/assets/realcamera/lang/be_by.json index 7c8ee0ce..9d9bcf82 100644 --- a/common/src/main/resources/assets/realcamera/lang/be_by.json +++ b/common/src/main/resources/assets/realcamera/lang/be_by.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпарт %s паспяховы!", "screen.tooltip.xtracr_realcamera.modelView_preview": "У рэжыме прадпрагляду вы можаце наладжваць зрух і паварот камеры", "screen.tooltip.xtracr_realcamera.modelView_priority": "Прыярытэт пры прывязцы, чым больш значэнне, тым вышэй прыярытэт і размяшчэнне справей у спісе", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Захаваць як\n(Калі існуе канфігурацыя з такой жа назвай, вы таксама можаце націснуць кнопку захавання злева)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Дадаць/абнавіць гэту наладу адключэння\nНацісніце Захаваць злева, каб захаваць канфігурацыю", "screen.tooltip.xtracr_realcamera.modelView_scale": "Маштаб, які кіруе памерам зрухаў", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Левы клік каб атрымаць UV-каардынаты пад паказальнікам мышы\nТры наборы UV-каардынат ніжэй, зверху ўніз, гэта UV-каардынаты вектара наперад, вектара уверх і пункту прывязкі на мэтавай плоскасці\nЗаўвага: %s+Пракрутка каб пераключацца паміж рознымі слаямі мадэлі. Увод UV-каардынат уручную дазваляе дакладней прывязацца да мэтавай пазіцыі", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Вызначае рэжым хуткага выбару %s+Левы клік\n(%s+Пракрутка каб змяніць дыяпазон выбару ў рэжыме дыяпазону)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектар уверх", "screen.widget.xtracr_realcamera.modelView_yaw": "Рысканне = %s", "screen.xtracr_realcamera.modelView_title": "Прагляд мадэлі" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 73f7e51a..6742f95a 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s succeeded!", "screen.tooltip.xtracr_realcamera.modelView_preview": "In the preview mode, you can adjust the camera's offset and rotation", "screen.tooltip.xtracr_realcamera.modelView_priority": "Priority when binding, the larger the value the higher the priority, and the higher the sorting on the right side", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Save as\n(When there is a setting with the same name, you can also press the save button on the left)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Add/update this disable setting\nPress Save on the left to save the config", "screen.tooltip.xtracr_realcamera.modelView_scale": "Scale, which controls the size of the offsets", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Left Click to get the UV coordinates at the mouse pointer\nThe three sets of UV coordinates below are, from top to bottom, the UV coordinates of the forward vector, the upward vector, and the binding point on the target plane\nNote: %s+Scroll to switch between the different layers of the model. Manually inputting UV coordinates allows you to bind more accurately to the target position", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Decide the mode of %s+Left Click quick selection\n(%s+Scroll to change the selection range in the range mode)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Upward Vector", "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", "screen.xtracr_realcamera.modelView_title": "Model View" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/es_es.json b/common/src/main/resources/assets/realcamera/lang/es_es.json index 5139d5df..34a28c5f 100644 --- a/common/src/main/resources/assets/realcamera/lang/es_es.json +++ b/common/src/main/resources/assets/realcamera/lang/es_es.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "¡Importación %s exitosa!", "screen.tooltip.xtracr_realcamera.modelView_preview": "En el modo de vista previa, puedes ajustar el desplazamiento y rotación de la cámara", "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridad al vincular, cuanto mayor sea el valor, mayor será la prioridad y más alto será el orden en el lado derecho", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Guardar como\n(Cuando existe una configuración con el mismo nombre, también puede usar el botón guardar a la izquierda)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Añadir/actualizar este ajuste de desactivación\nPulsa Guardar a la izquierda para guardar la configuración", "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla el tamaño de los desplazamientos", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clic izquierdo para obtener las coordenadas UV en el puntero del ratón\nLos tres conjuntos de coordenadas UV a continuación son, de arriba a abajo, las coordenadas UV del vector adelante, el vector arriba y el punto de vinculación en el plano objetivo\nNota: %s+Desplazarse para cambiar entre las diferentes capas del modelo. Ingresar manualmente las coordenadas UV permite vincular con mayor precisión a la posición objetivo", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina el modo de selección rápida %s+Clic izquierdo\n(%s+Desplazarse para cambiar el rango de selección en el modo de rango)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vector Arriba", "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", "screen.xtracr_realcamera.modelView_title": "Vista de Modelo" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/fr_fr.json b/common/src/main/resources/assets/realcamera/lang/fr_fr.json index a174e7ea..627a22e0 100644 --- a/common/src/main/resources/assets/realcamera/lang/fr_fr.json +++ b/common/src/main/resources/assets/realcamera/lang/fr_fr.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importation %s réussie !", "screen.tooltip.xtracr_realcamera.modelView_preview": "En mode aperçu, vous pouvez ajuster le décalage et la rotation de la caméra", "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorité lors de la liaison, plus la valeur est grande, plus la priorité est élevée et plus le tri est haut sur le côté droit", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Enregistrer sous\n(Lorsqu'il existe une configuration avec le même nom, vous pouvez également utiliser le bouton enregistrer à gauche)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Ajouter/mettre à jour ce paramètre de désactivation\nCliquez sur Enregistrer à gauche pour enregistrer la configuration", "screen.tooltip.xtracr_realcamera.modelView_scale": "Échelle, qui contrôle la taille des décalages", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clic gauche pour obtenir les coordonnées UV au niveau du pointeur de la souris\nLes trois ensembles de coordonnées UV ci-dessous sont, de haut en bas, les coordonnées UV du vecteur avant, du vecteur haut et du point de liaison sur le plan cible\nNote : %s+Défilement pour basculer entre les différentes couches du modèle. La saisie manuelle des coordonnées UV permet de se lier plus précisément à la position cible", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Détermine le mode de sélection rapide %s+Clic gauche\n(%s+Défilement pour changer la plage de sélection en mode plage)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vecteur Haut", "screen.widget.xtracr_realcamera.modelView_yaw": "Lacet = %s", "screen.xtracr_realcamera.modelView_title": "Vue Modèle" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/ja_jp.json b/common/src/main/resources/assets/realcamera/lang/ja_jp.json index 0858a1fb..51fee066 100644 --- a/common/src/main/resources/assets/realcamera/lang/ja_jp.json +++ b/common/src/main/resources/assets/realcamera/lang/ja_jp.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%sのインポートに成功しました!", "screen.tooltip.xtracr_realcamera.modelView_preview": "プレビューモードでカメラの様々なオフセットを調整できます", "screen.tooltip.xtracr_realcamera.modelView_priority": "バインディング時の優先度、値が大きいほど優先度が高く右側のソートで上位に表示", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "名前を付けて保存\n(同名設定がある場合も左の保存ボタンを使用できます)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "この無効化設定を追加/更新\n左の保存を押して設定を保存", "screen.tooltip.xtracr_realcamera.modelView_scale": "スケール、オフセットのサイズを制御", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左クリックでマウスポインタ位置のUV座標を取得\n下の3組のUV座標は上から順に前方ベクトル、上方ベクトル、ターゲット平面上のバインディング点のUV座標\n注: %s+スクロールでモデルの異なるレイヤー間を切り替えられます。手動でUV座標を入力するとターゲット位置に正確にバインドできます", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+左クリッククイック選択のモードを決定\n(%s+スクロールで範囲モードの選択範囲を変更)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "上方ベクトル", "screen.widget.xtracr_realcamera.modelView_yaw": "ヨー = %s", "screen.xtracr_realcamera.modelView_title": "モデルビュー" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/ko_kr.json b/common/src/main/resources/assets/realcamera/lang/ko_kr.json index af9931ee..69abb565 100644 --- a/common/src/main/resources/assets/realcamera/lang/ko_kr.json +++ b/common/src/main/resources/assets/realcamera/lang/ko_kr.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s 가져오기 성공!", "screen.tooltip.xtracr_realcamera.modelView_preview": "미리보기 모드에서 카메라의 다양한 오프셋 조정 가능", "screen.tooltip.xtracr_realcamera.modelView_priority": "바인딩 시 우선순위, 값이 클수록 우선순위가 높으며 오른쪽 정렬에서 위쪽에 표시", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "다른 이름으로 저장\n(동일 이름 설정이 있을 때 왼쪽 저장 버튼도 사용 가능)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "이 비활성화 설정 추가/업데이트\n왼쪽 저장을 눌러 구성을 저장", "screen.tooltip.xtracr_realcamera.modelView_scale": "크기 조절, 오프셋 크기 제어", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+왼쪽 클릭으로 마우스 포인터 위치의 UV 좌표 얻기\n아래 세 가지 UV 좌표는 위에서부터 전방 벡터, 상향 벡터, 대상 평면의 바인딩 지점 UV 좌표입니다\n참고: %s+스크롤로 모델의 다른 레이어 간 전환, 수동 UV 좌표 입력으로 대상 위치에 더 정확하게 바인딩 가능", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+왼쪽 클릭 빠른 선택 모드 결정\n(%s+스크롤로 범위 모드에서 선택 범위 변경)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "상향 벡터", "screen.widget.xtracr_realcamera.modelView_yaw": "요 = %s", "screen.xtracr_realcamera.modelView_title": "모델 뷰" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/lzh.json b/common/src/main/resources/assets/realcamera/lang/lzh.json index a0ed305b..9288909d 100644 --- a/common/src/main/resources/assets/realcamera/lang/lzh.json +++ b/common/src/main/resources/assets/realcamera/lang/lzh.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "入%s成!", "screen.tooltip.xtracr_realcamera.modelView_preview": "於覽式可調鏡觀諸偏移", "screen.tooltip.xtracr_realcamera.modelView_priority": "系定之先級,值愈大愈先,且右列愈前", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "存為\n(當有同名設時,亦可用左存鈕)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "增/更新此禁用設\n再按左存鈕以存目前設", "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放之度,控偏移量之大小", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左鍵可取光標處UV座標\n下三組UV座標自上而下為前向矢、上向矢與的平面上系點之UV座標\n註:%s鍵+滾輪可易模型之層,手輸UV座標可精系的位", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "定%s+左鍵速擇之法\n(%s鍵+滾輪可易域擇之範)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "上向矢", "screen.widget.xtracr_realcamera.modelView_yaw": "偏航 = %s", "screen.xtracr_realcamera.modelView_title": "模型觀象" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/pl_pl.json b/common/src/main/resources/assets/realcamera/lang/pl_pl.json index 0b75ce8a..307450a5 100644 --- a/common/src/main/resources/assets/realcamera/lang/pl_pl.json +++ b/common/src/main/resources/assets/realcamera/lang/pl_pl.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Import %s powiódł się!", "screen.tooltip.xtracr_realcamera.modelView_preview": "W trybie podglądu możesz dostosować przesunięcie i obrót kamery", "screen.tooltip.xtracr_realcamera.modelView_priority": "Priorytet powiązania: im większa wartość, tym wyższy priorytet i wyższe sortowanie po prawej stronie", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Zapisz jako\n(Gdy istnieje konfiguracja o tej samej nazwie, możesz również użyć przycisku zapisu po lewej stronie)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Dodaj/zaktualizuj to ustawienie wyłączenia\nKliknij Zapisz po lewej, aby zapisać konfigurację", "screen.tooltip.xtracr_realcamera.modelView_scale": "Skala, która kontroluje rozmiar przesunięć", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+LKliknij, aby uzyskać współrzędne UV w miejscu wskaźnika myszy\nTrzy zestawy współrzędnych UV poniżej, od góry do dołu, to współrzędne UV wektora do przodu, wektora w górę i punktu wiązania na płaszczyźnie docelowej\nUwaga: %s+Przewiń, aby przełączać się między różnymi warstwami modelu. Ręczne wprowadzanie współrzędnych UV pozwala dokładniej powiązać z pozycją docelową", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Określa tryb szybkiego wyboru %s+LKliknięcia\n(%s+Przewiń, aby zmienić zakres wyboru w trybie zakresu)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Wektor w górę", "screen.widget.xtracr_realcamera.modelView_yaw": "Odchylenie = %s", "screen.xtracr_realcamera.modelView_title": "Widok modelu" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/pt_br.json b/common/src/main/resources/assets/realcamera/lang/pt_br.json index 8b604596..307cd322 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_br.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_br.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Adicionar/atualizar esta configuração de desativação\nPressione Salvar à esquerda para salvar a configuração", "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla o tamanho dos deslocamentos", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clique Esquerdo para obter as coordenadas UV no ponteiro do mouse\nOs três conjuntos de coordenadas UV abaixo são, de cima para baixo, as coordenadas UV do vetor de frente, do vetor para cima e do ponto de vinculação no plano alvo\nNota: %s+Rolar para alternar entre as diferentes camadas do modelo. Inserir manualmente as coordenadas UV permite vincular com mais precisão à posição alvo", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina o modo de seleção rápida %s+Clique Esquerdo\n(%s+Rolar para alterar o intervalo de seleção no modo de intervalo)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vetor para Cima", "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", "screen.xtracr_realcamera.modelView_title": "Visualização de Modelo" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/pt_pt.json b/common/src/main/resources/assets/realcamera/lang/pt_pt.json index ccbb4f41..fa3e5579 100644 --- a/common/src/main/resources/assets/realcamera/lang/pt_pt.json +++ b/common/src/main/resources/assets/realcamera/lang/pt_pt.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Importação %s bem-sucedida!", "screen.tooltip.xtracr_realcamera.modelView_preview": "No modo de pré-visualização, você pode ajustar o deslocamento e rotação da câmera", "screen.tooltip.xtracr_realcamera.modelView_priority": "Prioridade ao vincular, quanto maior o valor maior a prioridade e maior a ordenação no lado direito", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Salvar como\n(Quando existe uma configuração com o mesmo nome, você também pode usar o botão salvar à esquerda)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Adicionar/atualizar esta configuração de desativação\nPrima Salvar à esquerda para salvar a configuração", "screen.tooltip.xtracr_realcamera.modelView_scale": "Escala, que controla o tamanho dos deslocamentos", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Clique Esquerdo para obter as coordenadas UV no ponteiro do mouse\nOs três conjuntos de coordenadas UV abaixo são, de cima para baixo, as coordenadas UV do vetor de frente, do vetor para cima e do ponto de vinculação no plano alvo\nNota: %s+Rolar para alternar entre as diferentes camadas do modelo. Inserir manualmente as coordenadas UV permite vincular com mais precisão à posição alvo", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Determina o modo de seleção rápida %s+Clique Esquerdo\n(%s+Rolar para alterar o intervalo de seleção no modo de intervalo)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Vetor para Cima", "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", "screen.xtracr_realcamera.modelView_title": "Visualização de Modelo" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/ru_ru.json b/common/src/main/resources/assets/realcamera/lang/ru_ru.json index eb8eec98..b9475e1e 100644 --- a/common/src/main/resources/assets/realcamera/lang/ru_ru.json +++ b/common/src/main/resources/assets/realcamera/lang/ru_ru.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Импорт %s успешен!", "screen.tooltip.xtracr_realcamera.modelView_preview": "В режиме предпросмотра вы можете настроить смещение и вращение камеры", "screen.tooltip.xtracr_realcamera.modelView_priority": "Приоритет при привязке: чем больше значение, тем выше приоритет и выше сортировка на правой стороне", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Сохранить как\n(При наличии настройки с тем же именем вы также можете использовать кнопку сохранения слева)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Добавить/обновить эту настройку отключения\nНажмите Сохранить слева, чтобы сохранить конфигурацию", "screen.tooltip.xtracr_realcamera.modelView_scale": "Масштаб, который контролирует размер смещений", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Левый клик чтобы получить UV-координаты в месте указателя мыши\nТри набора UV-координат ниже, сверху вниз, это UV-координаты вектора направления, вектора вверх и точки привязки на целевой плоскости\nПримечание: %s+Прокрутка для переключения между различными слоями модели. Ручной ввод UV-координат позволяет более точно привязаться к целевой позиции", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Определяет режим быстрого выбора %s+Левый клик\n(%s+Прокрутка для изменения диапазона выбора в режиме диапазона)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектор вверх", "screen.widget.xtracr_realcamera.modelView_yaw": "Рыскание = %s", "screen.xtracr_realcamera.modelView_title": "Просмотр Модели" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/tr_tr.json b/common/src/main/resources/assets/realcamera/lang/tr_tr.json index 2dd336f2..21ac2edc 100644 --- a/common/src/main/resources/assets/realcamera/lang/tr_tr.json +++ b/common/src/main/resources/assets/realcamera/lang/tr_tr.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "%s içe aktarma başarılı!", "screen.tooltip.xtracr_realcamera.modelView_preview": "Önizleme modunda kameranın çeşitli ofsetlerini ayarlayabilirsiniz", "screen.tooltip.xtracr_realcamera.modelView_priority": "Bağlama önceliği, değer ne kadar büyükse öncelik o kadar yüksektir ve sağ taraftaki sıralama da o kadar yukarıdadır", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Farklı Kaydet\n(Aynı isimde bir ayar olduğunda, soldaki kaydet düğmesini de kullanabilirsiniz)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Bu devre dışı bırakma ayarını ekle/güncelle\nYapılandırmayı kaydetmek için soldaki Kaydet'e basın", "screen.tooltip.xtracr_realcamera.modelView_scale": "Ölçek, ofsetlerin boyutunu kontrol eder", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Sol Tık ile fare işaretçisindeki UV koordinatlarını alın\nAşağıdaki üç UV koordinat seti, yukarıdan aşağıya doğru, ileri vektör, yukarı vektör ve hedef düzlemdeki bağlama noktasının UV koordinatlarıdır\nNot: %s+Kaydırma ile modelin farklı katmanları arasında geçiş yapabilirsiniz. UV koordinatlarını manuel olarak girerek hedef konuma daha hassas bir şekilde bağlanabilirsiniz", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "%s+Sol Tık hızlı seçim modunu belirler\n(%s+Kaydırma ile aralık modundaki seçim aralığını değiştirin)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Yukarı Vektörü", "screen.widget.xtracr_realcamera.modelView_yaw": "Yaw = %s", "screen.xtracr_realcamera.modelView_title": "Model Görünümü" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/uk_ua.json b/common/src/main/resources/assets/realcamera/lang/uk_ua.json index 27307c1b..4efac461 100644 --- a/common/src/main/resources/assets/realcamera/lang/uk_ua.json +++ b/common/src/main/resources/assets/realcamera/lang/uk_ua.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "Імпорт %s успішний!", "screen.tooltip.xtracr_realcamera.modelView_preview": "У режимі попереднього перегляду ви можете налаштувати зміщення та обертання камери", "screen.tooltip.xtracr_realcamera.modelView_priority": "Пріоритет при прив'язці: чим більше значення, тим вищий пріоритет і вище сортування на правій стороні", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Зберегти як\n(При наявності налаштування з тим же ім'ям ви також можете використовувати кнопку збереження зліва)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "Додати/оновити це налаштування вимкнення\nНатисніть Зберегти ліворуч, щоб зберегти конфігурацію", "screen.tooltip.xtracr_realcamera.modelView_scale": "Масштаб, який контролює розмір зміщень", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+Лівий клік щоб отримати UV-координати в місці вказівника миші\nТри набори UV-координат нижче, зверху вниз, це UV-координати вектора напрямку, вектора вгору та точки прив'язки на цільовій площині\nПримітка: %s+Прокрутка для перемикання між різними шарами моделі. Ручний ввід UV-координат дозволяє точніше прив'язатися до цільової позиції", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "Визначає режим швидкого вибору %s+Лівий клік\n(%s+Прокрутка для зміни діапазону вибору в режимі діапазону)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "Вектор вгору", "screen.widget.xtracr_realcamera.modelView_yaw": "Рискання = %s", "screen.xtracr_realcamera.modelView_title": "Перегляд Моделі" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 3ffd60e7..61b86c8a 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "导入%s成功!", "screen.tooltip.xtracr_realcamera.modelView_preview": "在预览模式可以调整相机的各个偏移量", "screen.tooltip.xtracr_realcamera.modelView_priority": "绑定时的优先级,值越大优先级越高,并且在右侧排序越靠上", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "保存为\n(当存在同名设置时,也可使用左侧保存按钮)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "添加/更新此禁用设置\n再点左侧保存以保存到当前配置", "screen.tooltip.xtracr_realcamera.modelView_scale": "缩放比例,控制偏移量的大小", "screen.tooltip.xtracr_realcamera.modelView_selecting": "%s+左键可获取鼠标指针处的UV坐标\n下方三组UV坐标由上到下依次为向前矢量、向上矢量和目标平面上绑定点的UV坐标\n注:%s键+滚轮可在模型的不同层间切换,手动输入UV坐标可以更加精确地绑定到目标位置", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "决定%s+左键快速选择的模式\n(%s键+滚轮可改变范围模式下的选择范围)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上矢量", "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", "screen.xtracr_realcamera.modelView_title": "模型视图" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/zh_hk.json b/common/src/main/resources/assets/realcamera/lang/zh_hk.json index c75986e5..a33d49f0 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_hk.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_hk.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "新增/更新此禁用設定\n再按左側儲存以儲存到目前設定", "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放比例,控制偏移量的大小", "screen.tooltip.xtracr_realcamera.modelView_selecting": "左Alt+左鍵可獲取鼠標指針處的UV座標\n下方三組UV座標由上到下依次為向前向量、向上向量和目標平面上綁定點的UV座標\n註:左Alt鍵+滾輪可在模型的不同層間切換,手動輸入UV座標可以更加精確地綁定到目標位置", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "決定左Alt+左鍵快速選擇的模式\n(左Alt鍵+滾輪可改變範圍模式下的選擇範圍)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上向量", "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", "screen.xtracr_realcamera.modelView_title": "模型視圖" -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/realcamera/lang/zh_tw.json b/common/src/main/resources/assets/realcamera/lang/zh_tw.json index c75986e5..a33d49f0 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_tw.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_tw.json @@ -91,7 +91,7 @@ "screen.tooltip.xtracr_realcamera.modelView_importSucceeded": "導入%s成功!", "screen.tooltip.xtracr_realcamera.modelView_preview": "在預覽模式可以調整相機的各個偏移量", "screen.tooltip.xtracr_realcamera.modelView_priority": "綁定時的優先級,值越大優先級越高,並且在右側排序越靠上", - "screen.tooltip.xtracr_realcamera.modelView_saveAs": "儲存為\n(當存在同名設置時,也可使用左側儲存按鈕)", + "screen.tooltip.xtracr_realcamera.modelView_saveAs": "新增/更新此禁用設定\n再按左側儲存以儲存到目前設定", "screen.tooltip.xtracr_realcamera.modelView_scale": "縮放比例,控制偏移量的大小", "screen.tooltip.xtracr_realcamera.modelView_selecting": "左Alt+左鍵可獲取鼠標指針處的UV座標\n下方三組UV座標由上到下依次為向前向量、向上向量和目標平面上綁定點的UV座標\n註:左Alt鍵+滾輪可在模型的不同層間切換,手動輸入UV座標可以更加精確地綁定到目標位置", "screen.tooltip.xtracr_realcamera.modelView_selectionMode": "決定左Alt+左鍵快速選擇的模式\n(左Alt鍵+滾輪可改變範圍模式下的選擇範圍)", @@ -125,4 +125,4 @@ "screen.widget.xtracr_realcamera.modelView_upwardVector": "向上向量", "screen.widget.xtracr_realcamera.modelView_yaw": "偏航角 = %s", "screen.xtracr_realcamera.modelView_title": "模型視圖" -} \ No newline at end of file +} From b7791326bf475ce61459bc30c51f0afb2faecf3e Mon Sep 17 00:00:00 2001 From: xTracr Date: Tue, 23 Jun 2026 23:31:51 +0800 Subject: [PATCH 25/33] Refactor ConfigCodec to final class and fix entity hit result - Rename MODID to MOD_ID across all usages for consistent naming - Convert ConfigCodec from interface to final class, removing redundant version() method - Make ModelViewScreen dimensions responsive to window size - Fix y-axis bounds bug in ColoredFloatLineRenderState --- .gitignore | 3 +++ .../com/xtracr/realcamera/RealCamera.java | 6 ++--- .../com/xtracr/realcamera/RealCameraCore.java | 4 ++-- .../xtracr/realcamera/config/ConfigFile.java | 2 +- .../realcamera/config/codec/ConfigCodec.java | 23 +++++++++---------- .../config/codec/ConfigCodec703.java | 21 ++--------------- .../realcamera/gui/ModelViewScreen.java | 16 ++++++++----- .../gui/components/SimpleIconButton.java | 2 +- .../realcamera/mixin/MixinLocalPlayer.java | 6 ++--- .../gui/ColoredFloatLineRenderState.java | 2 +- gradle.properties | 2 +- .../xtracr/realcamera/RealCameraNeoForge.java | 2 +- settings.gradle.kts | 4 ++++ 13 files changed, 42 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index 87beff70..42fee5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ replay_*.log *.hprof *.jfr +# local docs and resources +.local/ + # agent AGENTS.md CLAUDE.md \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/RealCamera.java b/common/src/main/java/com/xtracr/realcamera/RealCamera.java index 94ede4e8..29c931c1 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCamera.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCamera.java @@ -7,9 +7,9 @@ import org.slf4j.LoggerFactory; public interface RealCamera extends PlatformHelper { - String MODID = "realcamera"; - String FULL_ID = "xtracr_" + MODID; - Logger LOGGER = LoggerFactory.getLogger(MODID); + String MOD_ID = "realcamera"; + String FULL_ID = "xtracr_" + MOD_ID; + Logger LOGGER = LoggerFactory.getLogger(MOD_ID); default void initialize() { ConfigFile.load(); diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 673c8ffc..5f1a60ba 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -43,9 +43,9 @@ public static BindTarget currentTarget() { return lastResult.target; } - public static void initialize(Minecraft client, boolean renderLevel) { + public static void initialize(Minecraft client, boolean advanceGameTime) { Entity entity = client.getCameraEntity(); - active = renderLevel && ConfigFile.config().enabled && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); + active = advanceGameTime && ConfigFile.config().enabled && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); rendering = ConfigFile.config().renderModel && !DisableHelper.RENDER_MODEL.disabled(entity); } diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java index e5af6e36..61c6fba5 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigFile.java @@ -15,7 +15,7 @@ import java.util.function.Supplier; public final class ConfigFile { - private static final String FILE_NAME = RealCamera.MODID + ".json"; + private static final String FILE_NAME = RealCamera.MOD_ID + ".json"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private final static Supplier path = Suppliers.memoize(ConfigFile::getPath); @Nullable diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java index bde2f41f..035c9488 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java @@ -16,25 +16,26 @@ import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; -public interface ConfigCodec extends StreamCodec { - ConfigCodec CODEC_703 = new ConfigCodec703(); - Short2ReferenceMap CODECS = Short2ReferenceMap.ofEntries( - Short2ReferenceMap.entry(CODEC_703.version(), CODEC_703) +public final class ConfigCodec { + static final short CURRENT_VERSION = 703; + static final StreamCodec CODEC_703 = ConfigCodec703.CODEC; + static final Short2ReferenceMap> CODECS = Short2ReferenceMap.ofEntries( + Short2ReferenceMap.entry(CURRENT_VERSION, CODEC_703) ); - static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderException, IllegalArgumentException { + public static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderException, IllegalArgumentException { short version = byteBuf.readShort(); - ConfigCodec serializer = CODECS.get(version); + StreamCodec serializer = CODECS.get(version); if (serializer == null) throw new IllegalArgumentException("Incompatible version: " + toSemVer(version)); return serializer.decode(byteBuf); } - static void writeWithVersion(ByteBuf byteBuf, BindTarget bindTarget) throws EncoderException { - byteBuf.writeShort(CODEC_703.version()); + public static void writeWithVersion(ByteBuf byteBuf, BindTarget bindTarget) throws EncoderException { + byteBuf.writeShort(CURRENT_VERSION); CODEC_703.encode(byteBuf, bindTarget); } - static DataResult fromCompressedBase64(String base64) { + public static DataResult fromCompressedBase64(String base64) { ByteBuf byteBuf = null; try { byte[] compressed = Base64.getDecoder().decode(base64); @@ -61,7 +62,7 @@ static DataResult fromCompressedBase64(String base64) { } } - static DataResult toCompressedBase64(BindTarget bindTarget) { + public static DataResult toCompressedBase64(BindTarget bindTarget) { ByteBuf byteBuf = Unpooled.buffer(); try { writeWithVersion(byteBuf, bindTarget); @@ -86,6 +87,4 @@ private static String toSemVer(short version) { int patch = version % 100; return major + "." + minor + "." + patch; } - - short version(); } diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java index b662afc7..71704076 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java @@ -7,14 +7,12 @@ import com.xtracr.realcamera.config.OffsetConfig; import com.xtracr.realcamera.config.UVRectangle; import io.netty.buffer.ByteBuf; -import io.netty.handler.codec.DecoderException; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; -import org.jspecify.annotations.NonNull; import java.util.List; -final class ConfigCodec703 implements ConfigCodec { +final class ConfigCodec703 { static final StreamCodec TARGET_CONFIG_CODEC = StreamCodec.composite( ByteBufCodecs.FLOAT, TargetConfig::forwardU, ByteBufCodecs.FLOAT, TargetConfig::forwardV, @@ -66,7 +64,7 @@ final class ConfigCodec703 implements ConfigCodec { UV_RECTANGLES_CODEC, DisableConfig::rectangles, DisableConfig::new ).apply(ByteBufCodecs.list()); - static final StreamCodec BIND_TARGET_CODEC = StreamCodec.composite( + static final StreamCodec CODEC = StreamCodec.composite( ByteBufCodecs.STRING_UTF8, BindTarget::name, ByteBufCodecs.STRING_UTF8, BindTarget::textureId, ByteBufCodecs.VAR_INT, BindTarget::priority, @@ -77,19 +75,4 @@ final class ConfigCodec703 implements ConfigCodec { DISABLE_CONFIGS_CODEC, BindTarget::disableConfigs, BindTarget::new ); - - @Override - public short version() { - return 703; // 0.7.3 - } - - @Override - public @NonNull BindTarget decode(@NonNull ByteBuf byteBuf) throws DecoderException { - return BIND_TARGET_CODEC.decode(byteBuf); - } - - @Override - public void encode(@NonNull ByteBuf byteBuf, @NonNull BindTarget bindTarget) { - BIND_TARGET_CODEC.encode(byteBuf, bindTarget); - } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 7c071f39..784c30f6 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -46,8 +46,8 @@ public final class ModelViewScreen extends Screen { private static final int SIDE_PANEL_BG = 0xFF444444, CENTER_PANEL_BG = 0xFF222222; private static final int DEFAULT_SCALE = 80, MIN_SCALE = 16, MAX_SCALE = 1024; private static final int CONFIG_NAME_MAX_LENGTH = 20; - private final int xSize = 450, ySize = 206, middleWidth = xSize - 200, widgetWidth = (xSize - middleWidth) / 4 - 8, widgetHeight = 18, wideWidgetWidth = widgetWidth * 2 + 4, compactWidgetWidth = widgetWidth * 2 - 18; - private int x, y, page = 0; + private final int widgetWidth = 42, widgetHeight = 18, wideWidgetWidth = widgetWidth * 2 + 4, compactWidgetWidth = widgetWidth * 2 - 18; + private int x, y, xSize, ySize, middleWidth, page = 0; private InputConstants.Key modifierKey = InputConstants.getKey(ConfigFile.config().binding.screenModifierKey); private boolean initialized; private int modelScale = DEFAULT_SCALE, textureScale = DEFAULT_SCALE, layers = 0, selectionRadius = 10; @@ -138,6 +138,9 @@ public ModelViewScreen() { @Override protected void init() { super.init(); + xSize = Math.clamp(width - 10, 10, 450); + ySize = Math.clamp(height - 10, 10, 206); + middleWidth = Math.max(10, xSize - 200); x = (width - xSize) / 2; y = (height - ySize) / 2; modifierKey = InputConstants.getKey(ConfigFile.config().binding.screenModifierKey); @@ -397,7 +400,7 @@ public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX ModelAnalyser.applyDisableConfigs(modelRecords, target, textureId, hiddenNames); computeFocusedPrimitives(analyser, modelRecords, textureRecords, mouseX, mouseY); renderCulledModels(graphics, analyser, target, modelRecords); - if (textureViewArea != null) renderFlattenedModels(graphics, analyser, textureRecords); + renderFlattenedModels(graphics, analyser, textureRecords); } private List captureRotatedEntity(ModelAnalyser analyser, BindTarget target, LivingEntity entity) { @@ -458,6 +461,7 @@ private void renderCulledModels(GuiGraphicsExtractor graphics, ModelAnalyser ana } private void renderFlattenedModels(GuiGraphicsExtractor graphics, ModelAnalyser analyser, List textureRecords) { + if (textureViewArea == null) return; int x1 = textureViewArea.left(), y1 = textureViewArea.top(), x2 = textureViewArea.right(), y2 = textureViewArea.bottom(); GUIHelper.enableScissor(graphics, textureViewArea); float scale = (textureScale * textureViewArea.width()) / (float) DEFAULT_SCALE; @@ -598,7 +602,7 @@ private String generateDisableConfigName(String textureId) { String candidate = base; for (int suffix = 2; disableConfigNameExists(candidate); suffix++) { String suffixText = "_" + suffix; - int baseLength = Math.min(base.length(), Math.max(1, CONFIG_NAME_MAX_LENGTH - suffixText.length())); + int baseLength = Math.clamp(CONFIG_NAME_MAX_LENGTH - suffixText.length(), 1, base.length()); candidate = base.substring(0, baseLength) + suffixText; } return candidate; @@ -612,10 +616,10 @@ private String sanitizeDisableConfigName(String name) { if (Character.isLetterOrDigit(c)) { builder.append(c); lastWasSeparator = false; - } else if ((c == '_' || c == '-') && builder.length() > 0 && !lastWasSeparator) { + } else if ((c == '_' || c == '-') && !builder.isEmpty() && !lastWasSeparator) { builder.append(c); lastWasSeparator = true; - } else if (builder.length() > 0 && !lastWasSeparator) { + } else if (!builder.isEmpty() && !lastWasSeparator) { builder.append('_'); lastWasSeparator = true; } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java b/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java index e3de55a2..b6634bb2 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/components/SimpleIconButton.java @@ -8,7 +8,7 @@ import net.minecraft.resources.Identifier; public class SimpleIconButton extends Button { - public static final Identifier ICON_TEXTURE = Identifier.fromNamespaceAndPath(RealCamera.MODID, "textures/gui/icon.png"); + public static final Identifier ICON_TEXTURE = Identifier.fromNamespaceAndPath(RealCamera.MOD_ID, "textures/gui/icon.png"); protected final Identifier texture; protected final int textureWidth, textureHeight, u, v; diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java index fe437128..ff623676 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java @@ -9,7 +9,6 @@ import com.xtracr.realcamera.config.ConfigFile; import com.xtracr.realcamera.util.CrosshairUtil; import com.xtracr.realcamera.util.RaycastUtil; -import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.LocalPlayer; @@ -42,9 +41,8 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { Pair fromAndTo = RaycastUtil.getFromAndTo(cameraEntity, interactionRange * interactionRange, partialTicks); Vec3 newFrom = fromAndTo.getFirst(); Vec3 newTo = fromAndTo.getSecond(); - Minecraft client = Minecraft.getInstance(); - double sqDistance = client.hitResult != null ? client.hitResult.getLocation().distanceToSqr(newFrom) : newTo.distanceToSqr(newFrom); - AABB newBox = cameraEntity.getBoundingBox().expandTowards(cameraEntity.getViewVector(partialTicks).scale(interactionRange)).inflate(1.0, 1.0, 1.0); + double sqDistance = newTo.distanceToSqr(newFrom); + AABB newBox = cameraEntity.getBoundingBox().expandTowards(newTo.subtract(newFrom)).inflate(1.0, 1.0, 1.0); CrosshairUtil.capturedEntityHitResult = ProjectileUtil.getEntityHitResult(except, newFrom, newTo, newBox, matching, sqDistance); return CrosshairUtil.capturedEntityHitResult; } diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java index 565a5289..14423344 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/state/gui/ColoredFloatLineRenderState.java @@ -41,7 +41,7 @@ public ColoredFloatLineRenderState( ) { this(pipeline, textureSetup, pose, x, y, z, vectorX, vectorY, vectorZ, argb, scissorArea, GUIHelper.getBounds((int) MathUtil.floor(x, x + vectorX), (int) MathUtil.floor(y, y + vectorY), - (int) MathUtil.ceil(x, x + vectorX), (int) MathUtil.ceil(x, x + vectorX), pose, scissorArea)); + (int) MathUtil.ceil(x, x + vectorX), (int) MathUtil.ceil(y, y + vectorY), pose, scissorArea)); } @Override diff --git a/gradle.properties b/gradle.properties index 4a404320..88e0b1cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.configuration-cache=false java_version=25 minecraft_version=26.1.2 enabled_platforms=fabric,neoforge -loom_version=1.16-SNAPSHOT +loom_version=1.17-SNAPSHOT fabric_loader_version=0.19.3 neoforge_version=26.1.2.73 moddev_version=2.0.141 diff --git a/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java b/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java index 0b9c01cf..d2c9e86a 100644 --- a/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java +++ b/neoforge/src/main/java/com/xtracr/realcamera/RealCameraNeoForge.java @@ -17,7 +17,7 @@ import java.util.Map; -@Mod(value = RealCamera.MODID, dist = Dist.CLIENT) +@Mod(value = RealCamera.MOD_ID, dist = Dist.CLIENT) public final class RealCameraNeoForge implements RealCamera { private final ModContainer modContainer; private final Map modIdMap = Map.of("cloth-config", "cloth_config"); diff --git a/settings.gradle.kts b/settings.gradle.kts index 6c49b8d6..ea77fc0b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,6 +17,10 @@ pluginManagement { } } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + rootProject.name = "RealCamera" include("common") From 3598405cbe926fcfacc725db1ec66ea1c293828b Mon Sep 17 00:00:00 2001 From: xTracr Date: Thu, 25 Jun 2026 13:00:27 +0800 Subject: [PATCH 26/33] Improve json adapter copied from #214 --- .../com/xtracr/realcamera/RealCameraCore.java | 15 +++--- .../config/codec/DisableConfigAdapter.java | 54 +++++++++++-------- .../realcamera/mixin/MixinLocalPlayer.java | 5 +- .../renderer/MultiVertexCatcher.java | 4 +- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 5f1a60ba..a08d45c8 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -71,13 +71,16 @@ public static void computeCamera(Minecraft client, float partialTicks) { Entity entity = client.getCameraEntity(); boolean invisible = entity.isInvisible(); entity.setInvisible(false); - newResult = RealCameraAPI.computeBindResult(client, partialTicks); - if (!newResult.available()) { - EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); - dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, new PoseStack(), vertexCatcher.initCollector()); - vertexCatcher.forEachBuffer(RealCameraCore::computeBindResult); + try { + newResult = RealCameraAPI.computeBindResult(client, partialTicks); + if (!newResult.available()) { + EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); + dispatcher.submit(dispatcher.extractEntity(entity, partialTicks), new CameraRenderState(), 0, 0, 0, new PoseStack(), vertexCatcher.initCollector()); + vertexCatcher.forEachBuffer(RealCameraCore::computeBindResult); + } + } finally { + entity.setInvisible(invisible); } - entity.setInvisible(invisible); if (newResult.available()) { failureFrames = 0; lastResult = newResult.computeCamera(false); diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java b/common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java index 9f51eb65..86166def 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/DisableConfigAdapter.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.List; public final class DisableConfigAdapter extends TypeAdapter { @Override @@ -32,31 +33,42 @@ public void write(JsonWriter out, DisableConfig value) throws IOException { @Override public DisableConfig read(JsonReader in) throws IOException { + String name = ""; + String textureId = ""; + boolean disableAll = false; + List rectangles = new ArrayList<>(); + in.beginObject(); - String _ = in.nextName(); - String name = in.nextString(); - String _ = in.nextName(); - String textureId = in.nextString(); - String _ = in.nextName(); - boolean disableAll = in.nextBoolean(); - String _ = in.nextName(); - in.beginArray(); - ArrayList rectangles = new ArrayList<>(); while (in.hasNext()) { - in.beginObject(); - String _ = in.nextName(); - float uMin = (float) in.nextDouble(); - String _ = in.nextName(); - float vMin = (float) in.nextDouble(); - String _ = in.nextName(); - float uMax = (float) in.nextDouble(); - String _ = in.nextName(); - float vMax = (float) in.nextDouble(); - in.endObject(); - rectangles.add(new UVRectangle(uMin, vMin, uMax, vMax)); + switch (in.nextName()) { + case "name" -> name = in.nextString(); + case "textureId" -> textureId = in.nextString(); + case "disableAll" -> disableAll = in.nextBoolean(); + case "rectangles" -> { + in.beginArray(); + while (in.hasNext()) rectangles.add(readRectangle(in)); + in.endArray(); + } + default -> in.skipValue(); + } } - in.endArray(); in.endObject(); return new DisableConfig(name, textureId, disableAll, rectangles); } + + private UVRectangle readRectangle(JsonReader in) throws IOException { + float uMin = 0, vMin = 0, uMax = 0, vMax = 0; + in.beginObject(); + while (in.hasNext()) { + switch (in.nextName()) { + case "uMin" -> uMin = (float) in.nextDouble(); + case "vMin" -> vMin = (float) in.nextDouble(); + case "uMax" -> uMax = (float) in.nextDouble(); + case "vMax" -> vMax = (float) in.nextDouble(); + default -> in.skipValue(); + } + } + in.endObject(); + return new UVRectangle(uMin, vMin, uMax, vMax); + } } diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java index ff623676..a8646b2d 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java @@ -44,9 +44,10 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { double sqDistance = newTo.distanceToSqr(newFrom); AABB newBox = cameraEntity.getBoundingBox().expandTowards(newTo.subtract(newFrom)).inflate(1.0, 1.0, 1.0); CrosshairUtil.capturedEntityHitResult = ProjectileUtil.getEntityHitResult(except, newFrom, newTo, newBox, matching, sqDistance); - return CrosshairUtil.capturedEntityHitResult; + } else { + CrosshairUtil.capturedEntityHitResult = original.call(except, from, _to, box, matching, maxValue); } - return original.call(except, from, _to, box, matching, maxValue); + return CrosshairUtil.capturedEntityHitResult; } @Inject(method = "getRopeHoldPosition", at = @At("HEAD"), cancellable = true) diff --git a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java index c80ee12b..e91727da 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java @@ -32,17 +32,18 @@ public static MultiVertexCatcher create() { return new MultiVertexCatcher(); } + @SuppressWarnings("resource") private static void renderModel(PoseStack poseStack, SubmitNodeStorage.ModelSubmit submit, VertexConsumer buffer) { poseStack.pushPose(); poseStack.last().set(submit.pose()); Model model = submit.model(); - //noinspection resource VertexConsumer wrappedBuffer = submit.sprite() == null ? buffer : submit.sprite().wrap(buffer); model.setupAnim(submit.state()); model.renderToBuffer(poseStack, wrappedBuffer, submit.lightCoords(), submit.overlayCoords(), submit.tintedColor()); poseStack.popPose(); } + @SuppressWarnings("resource") private static void renderModelParts(PoseStack poseStack, Map> modelPartSubmitsMap, MultiBufferSource.BufferSource bufferSource) { poseStack.pushPose(); for (var entry : modelPartSubmitsMap.entrySet()) { @@ -51,7 +52,6 @@ private static void renderModelParts(PoseStack poseStack, Map Date: Wed, 1 Jul 2026 15:36:15 +0800 Subject: [PATCH 27/33] Update issue templates (#218) - Merged disableWhenSneaking and disableWhenCrawling setting, added disableWhenFlying --- .github/ISSUE_TEMPLATE/bug_report_cn.yml | 30 +++++++++---- .github/ISSUE_TEMPLATE/bug_report_en.yml | 28 +++++++++--- .github/ISSUE_TEMPLATE/feature_request_cn.yml | 43 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request_en.yml | 43 +++++++++++++++++++ .../com/xtracr/realcamera/KeyMappings.java | 4 +- .../realcamera/compat/DisableHelper.java | 6 +-- .../realcamera/config/ConfigScreen.java | 20 ++++----- .../xtracr/realcamera/config/ModConfig.java | 10 ++--- .../realcamera/config/codec/ConfigCodec.java | 2 +- .../assets/realcamera/lang/en_us.json | 22 +++++----- .../assets/realcamera/lang/zh_cn.json | 22 +++++----- 11 files changed, 172 insertions(+), 58 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/feature_request_cn.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request_en.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml index 6e50b14e..d38034fe 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_cn.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -7,41 +7,55 @@ body: - type: markdown attributes: value: | - 请确保您使用的是最新版的RC,您反馈的bug很可能已经在更新版本中修复 + 请确保您使用的是最新版的RealCamera,您反馈的bug很可能已经在更新版本中修复 (查看尾缀是否与最新工件相同) 在反馈bug前,请先尝试搜索是否已有相似的问题,请不要重复打开相同的issue 所有有关YSM的问题,请您优先寻求他人的帮助,或者观看配置模型教程 - 而不是直接在issue中提问。 + 而不是直接在issue中提问 - type: checkboxes id: preliminary attributes: label: 我已确认 ... options: - - label: 我正在使用最新版的RC + - label: 我正在使用最新版的RealCamera required: true - - label: 无法在关闭主要功能时复现 + - label: issues里没有相关的问题 required: true - type: input - id: minecraft-version-loader + id: minecraft-version attributes: - label: Minecraft版本和加载器 + label: Minecraft版本 description: | - 请填写游戏版本与所使用的加载器. + 你所使用的Minecraft的版本. 你可以在游戏主界面作下角或者游戏启动时的日志开头等地方找到. validations: required: true + - type: checkboxes + id: bug-type + attributes: + label: 问题类型 + options: + - label: 开启时主功能时出现bug + required: false + - label: 与其他模组的兼容问题 + required: false + - label: 在fabric端出现 + required: false + - label: 在(neo)forge端出现 + required: false + - type: textarea id: incompatible-mods attributes: label: 不兼容的mod description: >- 和bug相关的模组 -
    请在反馈问题前尝试尽可能移除不相干的模组的情况下复现bug +
    请在反馈问题前移除不相干的模组的情况下复现bug placeholder: 'Mods list here' render: 'raw' validations: diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.yml b/.github/ISSUE_TEMPLATE/bug_report_en.yml index 2be682d9..f24fce85 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_en.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_en.yml @@ -12,7 +12,7 @@ body: Before reporting a bug, please search for similar issues first and avoid opening duplicate issues For all YSM-related questions, please seek help from others or watch configuration model tutorials first - instead of asking directly in the issue. + instead of asking directly in the issue - type: checkboxes id: preliminary @@ -21,27 +21,41 @@ body: options: - label: I am using the latest version of RealCamera required: true - - label: Unable to reproduce when main feature is disabled + - label: No related issues found in the issue tracker. required: true + - label: Appears on Fabric + required: false + - label: Appears on (Neo)Forge + required: false - type: input - id: minecraft-version-loader + id: minecraft-version attributes: - label: Minecraft Version and Loader + label: Minecraft Version description: | - Please specify the game version and your mod loader. + The Minecraft version you are using. You can find them at the corner of main menu or in the log while startup. validations: required: true + - type: checkboxes + id: bug-type + attributes: + label: 问题类型 + options: + - label: Bug occurs when enabling main feature + required: false + - label: Incompatibility with other mods + required: false + - type: textarea id: incompatible-mods attributes: label: Incompatible Mods description: >- - The mods related to the bug. -
    Try to remove unrelated plugins and mods before reporting + The mods related to the bug +
    Reproduce the bug with unrelated mods removed before reporting placeholder: 'Mods list here' render: 'raw' validations: diff --git a/.github/ISSUE_TEMPLATE/feature_request_cn.yml b/.github/ISSUE_TEMPLATE/feature_request_cn.yml new file mode 100644 index 00000000..f960b8d0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request_cn.yml @@ -0,0 +1,43 @@ +name: 新功能建议 +description: 为我们提供新的想法 +title: "[new feature]:" +labels: [ "new feature" ] +body: + - type: markdown + attributes: + value: | + 感谢您花时间提出新的功能想法! + 请确保最新版本内没有这个功能! + + - type: textarea + id: feature-description + attributes: + label: 这个功能是什么? + description: 请清晰地描述您希望添加的功能 + placeholder: 我希望... + validations: + required: true + + - type: textarea + id: problem-and-solution + attributes: + label: 这个功能可以解决什么问题? + description: 请详细说明其作用 + placeholder: 这个功能可以帮助解决... + validations: + required: true + + - type: textarea + id: ideal-solution + attributes: + label: 这个功能理想中的解决方案是什么样的? + description: 例如新的按钮应该在何处,哪里需要新的配置选项 + placeholder: 我希望... + validations: + required: true + + - type: textarea + id: additional-context + attributes: + label: 其他信息 + description: 任何关于功能的上下文或截图 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request_en.yml b/.github/ISSUE_TEMPLATE/feature_request_en.yml new file mode 100644 index 00000000..0ae65664 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request_en.yml @@ -0,0 +1,43 @@ +name: New Feature Request +description: Suggest an idea for this project +title: "[new feature]: " +labels: [ "new feature" ] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to suggest a new feature! + Check the latest build to confirm the feature is missing. + + - type: textarea + id: feature-description + attributes: + label: What is this feature about? + description: A clear and concise description of what the feature is. + placeholder: I would like to... + validations: + required: true + + - type: textarea + id: problem-and-solution + attributes: + label: What problem does this feature solve? + description: Please elaborate on its purpose + placeholder: This feature helps resolve... + validations: + required: true + + - type: textarea + id: ideal-solution + attributes: + label: What does your ideal solution look like? + description: For example, where new buttons or config options should be placed + placeholder: I would like... + validations: + required: true + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Any relevant information or screenshots regarding the feature \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java index 896b7ef8..9c6fd98a 100644 --- a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java +++ b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java @@ -26,12 +26,12 @@ public final class KeyMappings { }); createKeyMapping("toggleAdjustMode", _ -> ConfigFile.config().cycleAdjustMode()); createKeyMapping("toggleCameraMode", _ -> ConfigFile.config().isClassic = !ConfigFile.config().isClassic); - createKeyMapping("adjustFRONT", _ -> ConfigFile.config().adjustOffsetX(1)); - createKeyMapping("adjustBACK", _ -> ConfigFile.config().adjustOffsetX(-1)); createKeyMapping("adjustUP", _ -> ConfigFile.config().adjustOffsetY(1)); createKeyMapping("adjustDOWN", _ -> ConfigFile.config().adjustOffsetY(-1)); createKeyMapping("adjustLEFT", _ -> ConfigFile.config().adjustOffsetZ(1)); createKeyMapping("adjustRIGHT", _ -> ConfigFile.config().adjustOffsetZ(-1)); + createKeyMapping("adjustFRONT", _ -> ConfigFile.config().adjustOffsetX(1)); + createKeyMapping("adjustBACK", _ -> ConfigFile.config().adjustOffsetX(-1)); createKeyMapping("activeConfigIndexNEXT", _ -> ConfigFile.config().binding.activeConfigIndex += 1); createKeyMapping("activeConfigIndexPREV", _ -> ConfigFile.config().binding.activeConfigIndex -= 1); createKeyMapping("activeConfigIndexRESET", _ -> ConfigFile.config().binding.activeConfigIndex = 0); diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 20f6f84f..2f59cdfa 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -28,9 +28,9 @@ public final class DisableHelper { RENDER_HANDS = new Entry("renderHands", _ -> RealCameraCore.isRendering()); MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenSneaking && player.isCrouching()); MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classic.disableWhenSneaking && player.isCrouching()); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenSwimming && checkCondition(player, player.isSwimming(), ConfigFile.config().binding.outTick)); - MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classic.disableWhenSwimming && checkCondition(player, player.isSwimming(), ConfigFile.config().classic.outTick)); - MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenCrawling && checkCondition(player, player.isVisuallyCrawling(), ConfigFile.config().binding.outTick)); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenSwimming && checkCondition(player, player.isVisuallySwimming(), ConfigFile.config().binding.exitTick)); + MAIN_FEATURE.registerOrInClassic(player -> ConfigFile.config().classic.disableWhenSwimming && checkCondition(player, player.isVisuallySwimming(), ConfigFile.config().classic.exitTick)); + MAIN_FEATURE.registerOrInBinding(player -> ConfigFile.config().binding.disableWhenFlying && player.isFallFlying()); MAIN_FEATURE.registerOrInBinding(player -> { Item mainHand = player.getMainHandItem().getItem(); Item offHand = player.getOffhandItem().getItem(); diff --git a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index 77c91e68..a0ed7953 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java @@ -60,12 +60,12 @@ public static Screen create(Screen parent) { .setDefaultValue(false) .setSaveConsumer(b -> config.classic.disableWhenSwimming = b) .build()); - classic.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("outTick"), config.classic.outTick) + classic.addEntry(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("exitTick"), config.classic.exitTick) .setDefaultValue(13) .setMin(0) .setMax(40) - .setTooltip(LocUtil.CONFIG_TOOLTIP("outTick")) - .setSaveConsumer(i -> config.classic.outTick = i) + .setTooltip(LocUtil.CONFIG_TOOLTIP("exitTick")) + .setSaveConsumer(i -> config.classic.exitTick = i) .build()); classic.addEntry(entryBuilder.startDoubleField(LocUtil.CONFIG_OPTION("scale"), config.classic.scale) .setDefaultValue(8.0) @@ -196,20 +196,20 @@ public static Screen create(Screen parent) { .setDefaultValue(false) .setSaveConsumer(b -> config.binding.disableWhenSneaking = b) .build()); - disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenCrawling"), config.binding.disableWhenCrawling) - .setDefaultValue(false) - .setSaveConsumer(b -> config.binding.disableWhenCrawling = b) - .build()); disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenSwimming"), config.binding.disableWhenSwimming) .setDefaultValue(false) .setSaveConsumer(b -> config.binding.disableWhenSwimming = b) .build()); - disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("outTick"), config.binding.outTick) + disableConfig.add(entryBuilder.startBooleanToggle(LocUtil.CONFIG_OPTION("disableWhenFlying"), config.binding.disableWhenFlying) + .setDefaultValue(false) + .setSaveConsumer(b -> config.binding.disableWhenFlying = b) + .build()); + disableConfig.add(entryBuilder.startIntField(LocUtil.CONFIG_OPTION("exitTick"), config.binding.exitTick) .setDefaultValue(13) .setMin(0) .setMax(40) - .setTooltip(LocUtil.CONFIG_TOOLTIP("outTick")) - .setSaveConsumer(i -> config.binding.outTick = i) + .setTooltip(LocUtil.CONFIG_TOOLTIP("exitTick")) + .setSaveConsumer(i -> config.binding.exitTick = i) .build()); disableConfig.add(entryBuilder.startStrList(LocUtil.CONFIG_OPTION("disableMainFeatureItems"), config.binding.disableMainFeatureItems) .setDefaultValue(List.of()) diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index 4fea0a8f..87e9abdd 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -143,7 +143,7 @@ public static class Classic { public AdjustMode adjustMode = AdjustMode.CAMERA; public boolean disableWhenSneaking = false; public boolean disableWhenSwimming = false; - public int outTick = 13; + public int exitTick = 13; public double scale = 8.0; public double cameraX = -0.5; public double cameraY = 0.04; @@ -157,7 +157,7 @@ public static class Classic { private void clamp() { if (adjustMode == null) adjustMode = AdjustMode.CAMERA; - outTick = Mth.clamp(outTick, 0, 40); + exitTick = Mth.clamp(exitTick, 0, 40); scale = Mth.clamp(scale, 0.0, 64.0); cameraX = Mth.clamp(cameraX, MIN_OFFSET_D, MAX_OFFSET_D); cameraY = Mth.clamp(cameraY, MIN_OFFSET_D, MAX_OFFSET_D); @@ -188,10 +188,10 @@ public static class Binding { public boolean adjustOffset = true; public boolean hideFailureMessage = false; public boolean renderStuckObjects = true; - public boolean disableWhenCrawling = false; public boolean disableWhenSneaking = false; public boolean disableWhenSwimming = false; - public int outTick = 13; + public boolean disableWhenFlying = false; + public int exitTick = 13; public int bindResultRetentionFrames = 2; public int activeConfigIndex = 0; public double displacementSmoothFactor = 0.4; @@ -207,7 +207,7 @@ private void clamp() { } catch (Exception e) { screenModifierKey = InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_LALT).getName(); } - outTick = Mth.clamp(outTick, 0, 40); + exitTick = Mth.clamp(exitTick, 0, 40); bindResultRetentionFrames = Math.max(bindResultRetentionFrames, 0); activeConfigIndex = Math.max(activeConfigIndex, 0); displacementSmoothFactor = Mth.clamp(displacementSmoothFactor, 0.0, 1.0); diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java index 035c9488..bfc0d1fd 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java @@ -32,7 +32,7 @@ public static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderExceptio public static void writeWithVersion(ByteBuf byteBuf, BindTarget bindTarget) throws EncoderException { byteBuf.writeShort(CURRENT_VERSION); - CODEC_703.encode(byteBuf, bindTarget); + CODECS.get(CURRENT_VERSION).encode(byteBuf, bindTarget); } public static DataResult fromCompressedBase64(String base64) { diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index 6742f95a..dcfac604 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -14,17 +14,17 @@ "config.option.xtracr_realcamera.classicAdjustMode": "Adjust Mode", "config.option.xtracr_realcamera.disableConfig": "Disable Config", "config.option.xtracr_realcamera.disableMainFeatureItems": "Disable main feature when holding", - "config.option.xtracr_realcamera.disableRenderItems": "Disable rendering when holding", - "config.option.xtracr_realcamera.disableWhenCrawling": "Disable main feature when crawling", + "config.option.xtracr_realcamera.disableRenderItems": "Disable body rendering when holding", "config.option.xtracr_realcamera.disableWhenSneaking": "Disable main feature when sneaking", - "config.option.xtracr_realcamera.disableWhenSwimming": "Disable main feature when swimming", + "config.option.xtracr_realcamera.disableWhenSwimming": "Disable main feature when swimming(crawling)", + "config.option.xtracr_realcamera.disableWhenFlying": "Disable main feature when flying", "config.option.xtracr_realcamera.displacementSmoothFactor": "Displacement Smooth Factor", "config.option.xtracr_realcamera.dynamicCrosshair": "Dynamic Crosshair", "config.option.xtracr_realcamera.enabled": "Mod Enabled", "config.option.xtracr_realcamera.hideBindingFailureMessage": "Hide Binding Failure Message", "config.option.xtracr_realcamera.isClassic": "Classic Mode", "config.option.xtracr_realcamera.legacyBindingMode": "Legacy Binding Mode", - "config.option.xtracr_realcamera.outTick": "Restriction exit delay (in ticks)", + "config.option.xtracr_realcamera.exitTick": "Restriction exit delay (in ticks)", "config.option.xtracr_realcamera.pitch": "Pitch", "config.option.xtracr_realcamera.renderModel": "Render Player Model", "config.option.xtracr_realcamera.renderStuckObjects": "Render Stuck Objects", @@ -50,7 +50,7 @@ "config.tooltip.xtracr_realcamera.dynamicCrosshair": "When enabled, the crosshair will follow the player's view, ensuring consistent hit result\nRecommended to enable when Jade, WTHIT or similar mods are installed", "config.tooltip.xtracr_realcamera.isClassic": "Classic mode only makes simple changes to the position and rotation of camera", "config.tooltip.xtracr_realcamera.legacyBindingMode": "Using the binding mode of legacy version (v0.5), only vanilla model and actions based on vanilla model are supported\nIts properties can be set in 'LEGACY_MODE' of the %s screen when enabled", - "config.tooltip.xtracr_realcamera.outTick": "The time before re-enabling main feature after exiting restricted states (e.g., swimming, crawling) (1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.exitTick": "The time before re-enabling main feature after exiting restricted states (e.g., swimming, crawling) (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.renderModel": "Render player model in first-person perspective", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Arrows, bee stings and other objects that can be stuck in the player's body", "config.tooltip.xtracr_realcamera.rerenderModel": "Render the model again at the original rendering time to avoid some visual problems caused by rendering early", @@ -61,12 +61,12 @@ "key.xtracr_realcamera.activeConfigIndexNEXT": "Switch to next configuration", "key.xtracr_realcamera.activeConfigIndexPREV": "Switch to previous configuration", "key.xtracr_realcamera.activeConfigIndexRESET": "Reset configuration index", - "key.xtracr_realcamera.adjustBACK": "Adjust BACK", - "key.xtracr_realcamera.adjustDOWN": "Adjust DOWN", - "key.xtracr_realcamera.adjustFRONT": "Adjust FRONT", - "key.xtracr_realcamera.adjustLEFT": "Adjust LEFT", - "key.xtracr_realcamera.adjustRIGHT": "Adjust RIGHT", - "key.xtracr_realcamera.adjustUP": "Adjust UP", + "key.xtracr_realcamera.adjustUP": "Adjust UP (Rotate Up)", + "key.xtracr_realcamera.adjustDOWN": "Adjust DOWN (Rotate Down)", + "key.xtracr_realcamera.adjustLEFT": "Adjust LEFT (Rotate Left)", + "key.xtracr_realcamera.adjustRIGHT": "Adjust RIGHT (Rotate Right)", + "key.xtracr_realcamera.adjustFRONT": "Adjust FRONT (Roll Right)", + "key.xtracr_realcamera.adjustBACK": "Adjust BACK (Roll Left)", "key.xtracr_realcamera.modelViewScreen": "Open Model View Screen", "key.xtracr_realcamera.toggleAdjustMode": "Toggle Adjust Mode", "key.xtracr_realcamera.toggleCameraMode": "Toggle Camera Mode", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 61b86c8a..0f4ebc19 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -14,17 +14,17 @@ "config.option.xtracr_realcamera.classicAdjustMode": "调整模式", "config.option.xtracr_realcamera.disableConfig": "禁用配置", "config.option.xtracr_realcamera.disableMainFeatureItems": "在手持...时禁用主要功能", - "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用渲染", - "config.option.xtracr_realcamera.disableWhenCrawling": "爬行时禁用主要功能", + "config.option.xtracr_realcamera.disableRenderItems": "在手持...时禁用身体渲染", "config.option.xtracr_realcamera.disableWhenSneaking": "潜行时禁用主要功能", - "config.option.xtracr_realcamera.disableWhenSwimming": "游泳时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenSwimming": "游泳(爬行)时禁用主要功能", + "config.option.xtracr_realcamera.disableWhenFlying": "飞行时禁用主要功能", "config.option.xtracr_realcamera.displacementSmoothFactor": "位移平滑系数", "config.option.xtracr_realcamera.dynamicCrosshair": "动态十字准心", "config.option.xtracr_realcamera.enabled": "开启功能", "config.option.xtracr_realcamera.hideBindingFailureMessage": "隐藏绑定失败消息", "config.option.xtracr_realcamera.isClassic": "经典模式", "config.option.xtracr_realcamera.legacyBindingMode": "旧绑定模式", - "config.option.xtracr_realcamera.outTick": "禁用状态退出延迟(单位:tick)", + "config.option.xtracr_realcamera.exitTick": "禁用状态退出延迟(单位:tick)", "config.option.xtracr_realcamera.pitch": "俯仰角", "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物体", @@ -50,7 +50,7 @@ "config.tooltip.xtracr_realcamera.dynamicCrosshair": "在开启状态下,十字准心会随着玩家的视线移动,确保命中结果不受影响\n在安装了Jade、WTHIT或类似模组时建议启用", "config.tooltip.xtracr_realcamera.isClassic": "经典模式只对摄像头的位置和旋转做简单的修改", "config.tooltip.xtracr_realcamera.legacyBindingMode": "使用旧版本(v0.5)的绑定模式,仅支持原版模型和基于原版模型的动作\n开启后可在%s界面的'LEGACY_MODE'中设置属性", - "config.tooltip.xtracr_realcamera.outTick": "玩家停止某些状态(如游泳、爬行)后重启主要功能的时间(1 tick = 0.05s)", + "config.tooltip.xtracr_realcamera.exitTick": "玩家停止某些状态(如游泳、爬行)后重启主要功能的时间(1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.renderModel": "在第一人称视角下渲染玩家模型", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它会卡在玩家身体里的物体", "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染时机重新渲染模型,以避免一些因提前渲染导致的视觉问题", @@ -61,12 +61,12 @@ "key.xtracr_realcamera.activeConfigIndexNEXT": "切换到下一个配置", "key.xtracr_realcamera.activeConfigIndexPREV": "切换到上一个配置", "key.xtracr_realcamera.activeConfigIndexRESET": "重置配置索引", - "key.xtracr_realcamera.adjustBACK": "向后调整", - "key.xtracr_realcamera.adjustDOWN": "向下调整", - "key.xtracr_realcamera.adjustFRONT": "向前调整", - "key.xtracr_realcamera.adjustLEFT": "向左调整", - "key.xtracr_realcamera.adjustRIGHT": "向右调整", - "key.xtracr_realcamera.adjustUP": "向上调整", + "key.xtracr_realcamera.adjustUP": "向上调整(向上旋转)", + "key.xtracr_realcamera.adjustDOWN": "向下调整(向下旋转)", + "key.xtracr_realcamera.adjustLEFT": "向左调整(向左旋转)", + "key.xtracr_realcamera.adjustRIGHT": "向右调整(向右旋转)", + "key.xtracr_realcamera.adjustFRONT": "向前调整(向右滚转)", + "key.xtracr_realcamera.adjustBACK": "向后调整(向左滚转)", "key.xtracr_realcamera.modelViewScreen": "打开模型视图界面", "key.xtracr_realcamera.toggleAdjustMode": "切换调整模式", "key.xtracr_realcamera.toggleCameraMode": "切换摄像头模式", From 120cf424e2da4f7ae3a7f97332b8b62dfbae6dfa Mon Sep 17 00:00:00 2001 From: H31M5 <2211923909@qq.com> Date: Thu, 2 Jul 2026 23:48:44 +0800 Subject: [PATCH 28/33] Added compatibility with Entity_Model_Features (#219) * Added compatibility with Entity_Model_Features * Fix: Update issue template --- .github/ISSUE_TEMPLATE/bug_report_cn.yml | 6 +++--- .github/ISSUE_TEMPLATE/bug_report_en.yml | 2 +- .../realcamera/compat/CompatibilityHelper.java | 14 ++++++++++++++ .../com/xtracr/realcamera/gui/ModelViewScreen.java | 2 ++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml index d38034fe..0d86254e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_cn.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -31,7 +31,7 @@ body: description: | 你所使用的Minecraft的版本. - 你可以在游戏主界面作下角或者游戏启动时的日志开头等地方找到. + 你可以在游戏主界面左下角或者游戏启动时的日志开头等地方找到. validations: required: true @@ -40,7 +40,7 @@ body: attributes: label: 问题类型 options: - - label: 开启时主功能时出现bug + - label: 开启主功能时出现bug required: false - label: 与其他模组的兼容问题 required: false @@ -89,5 +89,5 @@ body: description: >- 你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能
    你可以日志上传到类似 https://paste.ubuntu.com/ 或者 https://mclo.gs/ 的网站并在此贴出链接 -
    **请不要在此此处直接粘贴大段的日志文本!!** +
    **请不要在此处直接粘贴大段的日志文本!!** placeholder: '把日志文件往这丢或者使用外部链接' \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.yml b/.github/ISSUE_TEMPLATE/bug_report_en.yml index f24fce85..72032021 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_en.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_en.yml @@ -42,7 +42,7 @@ body: - type: checkboxes id: bug-type attributes: - label: 问题类型 + label: Question Type options: - label: Bug occurs when enabling main feature required: false diff --git a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java index 17776f4f..117d43dd 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java @@ -6,8 +6,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.function.Function; public final class CompatibilityHelper { + public static boolean isRenderInScreen; private static PlatformHelper platformHelper; private static Method NEA_playerTransformer_setDeltaTick; private static Field NEA_NEAnimationsLoader_INSTANCE; @@ -50,6 +52,18 @@ public static void initialize(PlatformHelper platformHelper) { } catch (Exception e) { RealCamera.LOGGER.warn("Compatibility with SuperbWarfare is outdated: [{}] {}", e.getClass().getName(), e.getMessage()); } + if (isModLoaded("entity_model_features")) try { + Class EMF_EMFAnimationApi = Class.forName("traben.entity_model_features.EMFAnimationApi"); + if ((int) EMF_EMFAnimationApi.getMethod("getApiVersion").invoke(null) >= 9) { + Function function = _ -> isRenderInScreen; + Method EMF_registerPauseCondition = EMF_EMFAnimationApi.getMethod("registerPauseCondition", Function.class); + EMF_registerPauseCondition.invoke(null, function); + } else { + throw new IllegalStateException("EntityModelFeatures API is outdated, players‘s heads in the modelView may flicker"); + } + } catch (Exception e) { + RealCamera.LOGGER.warn("Compatibility with EntityModelFeatures is outdated: [{}] {}", e.getClass().getName(), e.getMessage()); + } } private static boolean SBW_gunsIsZooming() { diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 784c30f6..434a2886 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -404,6 +404,7 @@ public void extractBackground(@NonNull GuiGraphicsExtractor graphics, int mouseX } private List captureRotatedEntity(ModelAnalyser analyser, BindTarget target, LivingEntity entity) { + CompatibilityHelper.isRenderInScreen = true; float entityBodyYaw = entity.yBodyRot; float entityYaw = entity.getYRot(); float entityPitch = entity.getXRot(); @@ -425,6 +426,7 @@ private List captureRotatedEntity(ModelAnalyser analyser, Bind modelPose.translate(0, -entity.getBbHeight() / 2.0f, 0); return analyser.captureModel(minecraft, entity, 1.0f, modelPose, target); } finally { + CompatibilityHelper.isRenderInScreen = false; entity.yBodyRot = entityBodyYaw; entity.setYRot(entityYaw); entity.setXRot(entityPitch); From a0e473ea206d1131e0f661ab6664bd0e11d041fd Mon Sep 17 00:00:00 2001 From: rsdadada Date: Sat, 4 Jul 2026 10:34:37 +0800 Subject: [PATCH 29/33] [codex] Restore live disable draft preview (#223) * Fix live disable draft preview * Apply suggestion from @xTracr Co-authored-by: xTracr <57320980+xTracr@users.noreply.github.com> Signed-off-by: rsdadada * Inline disable preview config overlay * Simplify live disable draft handling * Remove redundant disable draft helper --------- Signed-off-by: rsdadada Co-authored-by: xTracr <57320980+xTracr@users.noreply.github.com> --- .../java/com/xtracr/realcamera/gui/ModelViewScreen.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 434a2886..eeaeba5f 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -268,6 +268,7 @@ else if (index > 0 && index <= rectWidgets.size()) { BindTarget bindTarget = genBindTarget(); ConfigFile.config().putBindTarget(bindTarget); ConfigFile.save(); + if (toggleCategoryButton.getValue() != Category.DISABLE) loadBindTarget(bindTarget); initWidgets(page); })); rows.addChild(priorityField, smallSettings).setTooltip(createTooltip("priority")); @@ -672,10 +673,16 @@ private void loadBindTarget(BindTarget target) { } private BindTarget genBindTarget() { + DisableConfig currentDisableConfig = new DisableConfig(disabledNameField.getValue(), disabledIdField.getValue(), disableModeButton.getValue() == 0, rectWidgets.stream().map(UVRectangleWidget::toUVRectangle).toList()); + List newDisableConfigs = new ArrayList<>(disableConfigs); + for (int i = 0; i < newDisableConfigs.size(); i++) { + if (newDisableConfigs.get(i).name().equals(currentDisableConfig.name())) + newDisableConfigs.set(i, currentDisableConfig); + } TargetConfig targetConfig = new TargetConfig(forwardUField.getNumber(), forwardVField.getNumber(), upwardUField.getNumber(), upwardVField.getNumber(), posUField.getNumber(), posVField.getNumber()); BindConfig bindConfig = new BindConfig(bindXButton.getValue() == 0, bindYButton.getValue() == 0, bindZButton.getValue() == 0, bindRotButton.getValue() == 0); OffsetConfig offsets = new OffsetConfig(scaleField.getNumber(), offsetXPair.getNumber(), offsetYPair.getNumber(), offsetZPair.getNumber(), offsetPitchPair.getNumber(), offsetYawPair.getNumber(), offsetRollPair.getNumber()); - return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, new ArrayList<>(disableConfigs)); + return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, newDisableConfigs); } private UVRectangleWidget addRectWidget(UVRectangleWidget rectWidget) { From e85f6461fb029e7e394ef8449bdb78cd8060246c Mon Sep 17 00:00:00 2001 From: xTracr Date: Sat, 4 Jul 2026 12:16:47 +0800 Subject: [PATCH 30/33] Bump version and upgrade gradle --- .../java/com/xtracr/realcamera/config/codec/ConfigCodec.java | 3 +-- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java index bfc0d1fd..78b492e7 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec.java @@ -18,9 +18,8 @@ public final class ConfigCodec { static final short CURRENT_VERSION = 703; - static final StreamCodec CODEC_703 = ConfigCodec703.CODEC; static final Short2ReferenceMap> CODECS = Short2ReferenceMap.ofEntries( - Short2ReferenceMap.entry(CURRENT_VERSION, CODEC_703) + Short2ReferenceMap.entry(CURRENT_VERSION, ConfigCodec703.CODEC) ); public static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderException, IllegalArgumentException { diff --git a/gradle.properties b/gradle.properties index 88e0b1cd..728a8b62 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ neoforge_version=26.1.2.73 moddev_version=2.0.141 ## Mod Properties mod_id=realcamera -mod_version=0.7.8-beta +mod_version=0.7.9-beta mod_group_id=com.xtracr.realcamera ## Dependencies fabric_api_version=0.150.0+26.1.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1a704683..7e7d24f6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From d40d7a50c29b323e5f13834f080127bf19e84948 Mon Sep 17 00:00:00 2001 From: dqsk_zze <1935752350@qq.com> Date: Sun, 5 Jul 2026 19:40:10 +0800 Subject: [PATCH 31/33] Update README.md (#226) Signed-off-by: dqsk_zze <1935752350@qq.com> --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 82d22a72..78beb517 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### [中文](README_ZH.md) Make the camera more realistic in the first-person view. -Supported versions: 1.18.2 - 1.20.4 Forge, 1.18.2 - 26.1 Fabric, 1.21 - 26.1 NeoForge. +Supported versions: 1.18.2 - 1.20.4 Forge, 1.18.2 - 26.2 Fabric, 1.21 - 26.2 NeoForge. Download the mod from [Releases](https://github.com/xTracr/RealCamera/releases), [Modrinth](https://modrinth.com/mod/real-camera) or [CurseForge](https://curseforge.com/minecraft/mc-mods/real-camera) Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/build.yml) @@ -31,11 +31,14 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Configs can have their priority adjusted - higher priority configs appear higher in the right-side list * Disable depth in `Preview` section to hide models blocking the view * About `Disable` section (current version still rough, complex operations): - * When texture ID field is empty, use Left Alt+Left Click to select texture + * When texture ID field is empty, use Left Alt+Mouse Left Click to select texture * Model parts contained by blue boxes won't be rendered * Left-click drag to select in texture view, other keys cancel selection * Left Alt+Left Click quickly selects hovered parts - * In `All` mode, entire texture's model won't render (blue box containing the texture in left panel indicates this) + * When Selection mode is `range` , texture in blue box will be hidden. By using Left Alt+Mouse Wheel, you can change the range of the blue box + * When Selection mode is `multiple` , it's better to disable player's part and armor but Mod models can't use it sometimes + * When Disable mode is `part` , you can choose the texture you want to hide + * When Disable mode is `All` , entire texture's model won't render (blue box containing the texture in left panel indicates this) * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) ## Dependencies @@ -57,8 +60,8 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Why does it show binding failed when use YSM models? * Snapshot 0.6.15 "try" to fix problems, but it didn't fix completely * If Minecraft version is 1.20.1, then bind upward vector to head left (or right) side, and set roll angle to 90 (or -90) in preview section -* Why does the head of YSM model disappear when in the Model View Screen? - * You downloaded Better Combat, just put it away +* Why does the disabled texture appear when i downloaded Better Combat and attack? + * Open settings of Better Combat and change Auto to False in First person player animation ### Compatibility From c561d0cfcfc180ef5522709535858db698bc674f Mon Sep 17 00:00:00 2001 From: dqsk_zze <1935752350@qq.com> Date: Sun, 5 Jul 2026 19:40:17 +0800 Subject: [PATCH 32/33] Update README_ZH.md (#227) Signed-off-by: dqsk_zze <1935752350@qq.com> --- README_ZH.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README_ZH.md b/README_ZH.md index 6f2ae5d0..fc04e1c0 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -3,7 +3,7 @@ ### [English](README.md) 使第一人称视角下的摄像头更加真实。 -支持的版本: 1.18.2 - 1.20.4 Forge,1.18.2 - 26.1 Fabric,1.21 - 26.1 NeoForge +支持的版本: 1.18.2 - 1.20.4 Forge,1.18.2 - 26.2 Fabric,1.21 - 26.2 NeoForge 从[Releases](https://github.com/xTracr/RealCamera/releases)、[Modrinth](https://modrinth.com/mod/real-camera)或[CurseForge](https://curseforge.com/minecraft/mc-mods/real-camera)下载 快照版在[这里](https://github.com/xTracr/RealCamera/actions/workflows/build.yml) @@ -35,7 +35,10 @@ * 被蓝框包含的部分不会被渲染。 * 在左侧材质视图中鼠标左键框选,其它键取消选择 * Alt+左键可快速选中被鼠标指针指向的部分 - * `全部`模式下,整个材质所对应的模型都不会被渲染(左侧会有一个包含整个材质的蓝框来表示这一点) + * 选择模式为范围,蓝框范围内被选中的面会被禁用,使用「Alt+鼠标滚轮」切换选中范围 + * 选择模式为多选,可以更好禁用原版玩家的部位,穿戴的盔甲等,但部分Mod 模型不一定适用 + * 禁用模式为部分,可以禁用被选择的贴图 + * 禁用模式为全部,整个材质所对应的模型都不会被渲染(左侧会有一个包含整个材质的蓝框来表示这一点) * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) ## 依赖项目 @@ -57,8 +60,8 @@ * 为什么ysm模型有时候会弹出绑定失败? * 快照0.6.15“尝试”修复了ysm问题,但没有修复透彻 * 如果Minecraft版本为1.20.1,那么需要将向上矢量绑定在头部的左面(或右面),并在预览界面中将翻滚角设置为90度(或-90度) -* 为什么配置ysm时候,模型视图界面中ysm模型头部消失? - * 安装了Better Combat模组,去掉就可以了 +* 为什么装了Better Combat模组后,禁用的材质在挥舞武器时会重新出现? + * 前往该模组的设置界面,把First person player animation 的Auto 改为False ### 兼容性 From 10b19a4e3033580b12ee5ed9fe6eab756f6da4b8 Mon Sep 17 00:00:00 2001 From: H31M5 <2211923909@qq.com> Date: Fri, 10 Jul 2026 16:15:38 +0800 Subject: [PATCH 33/33] Update readme and issues templates (#230) --- .github/ISSUE_TEMPLATE/bug_report_cn.yml | 18 +++++++---- .github/ISSUE_TEMPLATE/bug_report_en.yml | 12 ++++--- .github/workflows/build.yml | 1 + README.md | 32 ++++++++++++------- README_ZH.md | 32 ++++++++++++------- .../assets/realcamera/lang/en_us.json | 2 -- .../assets/realcamera/lang/zh_cn.json | 2 -- 7 files changed, 60 insertions(+), 39 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml index 0d86254e..62cef475 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_cn.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -55,8 +55,8 @@ body: label: 不兼容的mod description: >- 和bug相关的模组 -
    请在反馈问题前移除不相干的模组的情况下复现bug - placeholder: 'Mods list here' +
    请在反馈问题前移除所有不相干的模组的情况下复现bug + placeholder: '与问题有关的模组列表' render: 'raw' validations: required: true @@ -66,7 +66,8 @@ body: attributes: label: 错误描述 description: >- - 请尽可能详细的描述遇到的问题. + 请尽可能详细的描述遇到的问题 +
    同时也请务必携带复现时的视频或截图,这对于我们理解问题非常有帮助
    越清晰和详尽的描述会使该bug的处理优先级更高 validations: required: true @@ -76,9 +77,9 @@ body: attributes: label: 复现步骤 placeholder: | - 1. Join the game... + 1. 进入游戏... - 2. Change some settings... + 2. 做出某些改变... 3. ... @@ -87,7 +88,10 @@ body: attributes: label: 日志和崩溃报告 description: >- - 你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能 + 如果为非崩溃问题,请不要上传日志,这样会不利于我们理解问题 +
    你可以在/logs/lastest.log 和 /crash-report 中找到错误报告,或者使用启动器的导出功能
    你可以日志上传到类似 https://paste.ubuntu.com/ 或者 https://mclo.gs/ 的网站并在此贴出链接 -
    **请不要在此处直接粘贴大段的日志文本!!** +
    **请不要在此处直接粘贴大段的日志文本!!!** +
    **请不要在此处直接粘贴大段的日志文本!!!** +
    **请不要在此处直接粘贴大段的日志文本!!!** placeholder: '把日志文件往这丢或者使用外部链接' \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.yml b/.github/ISSUE_TEMPLATE/bug_report_en.yml index 72032021..92e716d9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_en.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_en.yml @@ -55,7 +55,7 @@ body: label: Incompatible Mods description: >- The mods related to the bug -
    Reproduce the bug with unrelated mods removed before reporting +
    Reproduce the bug with all unrelated mods removed before reporting placeholder: 'Mods list here' render: 'raw' validations: @@ -66,7 +66,8 @@ body: attributes: label: Bug Description description: >- - Please describe the issue you encountered in as much detail as possible. + Please describe the issue you encountered in as much detail as possible +
    Please also attach screenshots or reproduction videos, as they help us diagnose the problem effectively
    Clearer and more detailed descriptions will receive higher processing priority validations: required: true @@ -87,7 +88,10 @@ body: attributes: label: Logs & Crash Reports description: >- - You can find error reports in /logs/latest.log and /crash-reports, or use the launcher's export function + If your issue is not a crash, please do not upload log files, as they will hinder our understanding of the problem +
    You can find error reports in /logs/latest.log and /crash-reports, or use the launcher's export function
    You can upload logs to sites like https://paste.ubuntu.com/ or https://mclo.gs/ and post the link here -
    **DO NOT PASTE LARGE LOGS DIRECTLY HERE!!** +
    **DO NOT PASTE LARGE LOGS DIRECTLY HERE!!!** +
    **DO NOT PASTE LARGE LOGS DIRECTLY HERE!!!** +
    **DO NOT PASTE LARGE LOGS DIRECTLY HERE!!!** placeholder: 'Drag log file here or use external link' \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7414c951..1de9b1fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ name: Build on: pull_request: paths-ignore: + - '**/ISSUE_TEMPLATE/**' - '**/lang/**' - '**.md' - 'LICENSE' diff --git a/README.md b/README.md index 78beb517..33594776 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Bind the camera to a specific part of the body. * Customize the position and rotation of the camera. * Render player model in first-person perspective. -* Use F6 to toggle the feature on or off and other hotkeys to adjust the camera. +* Use 「F6」 to toggle the feature on or off and other hotkeys to adjust the camera. * Configure these features in the Config Screen (Cloth Config required) and the Model View Screen (0.6+). ### Configuration (0.6+) @@ -25,20 +25,27 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * From the top right button, enter the `Preview` section, where you can see the relative relationship between the camera and the model and make certain adjustments (you can also adjust through key bindings). * ![gui_preview](https://cdn.modrinth.com/data/fYYSAh4R/images/44c87a6f1750f8d1b03422120e6042d1098896cb.png) * Enter a name and save. +* ~~If you have difficulty configuring the settings, you can also enable `Mod Settings > Binding Mode > Legacy Binding Mode` +
    Note: This setting is exclusive to vanilla Minecraft.~~ #### Tips * Configs can have their priority adjusted - higher priority configs appear higher in the right-side list +* In the mod settings, you can manually switch between available configurations by modifying the configuration index. You can also set it to a non-zero value to lock the active configuration +* When the main feature is enabled, hover over the configuration entries. The one annotated with `Current Config` is the configuration currently in use * Disable depth in `Preview` section to hide models blocking the view -* About `Disable` section (current version still rough, complex operations): - * When texture ID field is empty, use Left Alt+Mouse Left Click to select texture - * Model parts contained by blue boxes won't be rendered - * Left-click drag to select in texture view, other keys cancel selection - * Left Alt+Left Click quickly selects hovered parts - * When Selection mode is `range` , texture in blue box will be hidden. By using Left Alt+Mouse Wheel, you can change the range of the blue box - * When Selection mode is `multiple` , it's better to disable player's part and armor but Mod models can't use it sometimes - * When Disable mode is `part` , you can choose the texture you want to hide - * When Disable mode is `All` , entire texture's model won't render (blue box containing the texture in left panel indicates this) +* About `Disable` section: + * When texture ID field is empty, use 「Left Alt + Left Click」 to select a texture + * Selection modes: + * Single & Multiple selection: Press 「Left Alt + Left Click」 to select the faces to disable + * Range selection: Press 「Left Alt + Left Click」 to confirm the selection area, and use 「Alt + Scroll Wheel」 to adjust the size of the selection area + * In the left texture view of the player rendering area: + * Press 「Left Click」 to start/end drag selection, press any other key to cancel the selection + * Faces selected via drag selection have the same effect as faces disabled via Multiple selection + * Notably, disabling faces this way is generally more performance-efficient than other methods + * Disable modes: + * In `part` mode, selected faces will not be rendered (you can preview the effect by toggling off the visibility of the disable configuration on the right pane) + * In `All` mode, entire texture's model won't render (blue box containing the texture in left panel indicates this) * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) ## Dependencies @@ -58,8 +65,9 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Why can't i open the Config Screen? * Please downlowd [Cloth Config API](https://modrinth.com/mod/cloth-config) * Why does it show binding failed when use YSM models? - * Snapshot 0.6.15 "try" to fix problems, but it didn't fix completely - * If Minecraft version is 1.20.1, then bind upward vector to head left (or right) side, and set roll angle to 90 (or -90) in preview section + * Snapshot 0.6.15 "try" to fix problems, but it didn't fully fix completely + * When your model rotates to a specific angle, the position you bound may disappear due to YSM's `face culling feature`, resulting in binding failure + * You can alleviate this problem by increasing the `Bind Result Retention Frames` * Why does the disabled texture appear when i downloaded Better Combat and attack? * Open settings of Better Combat and change Auto to False in First person player animation diff --git a/README_ZH.md b/README_ZH.md index fc04e1c0..64ae27ad 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -12,7 +12,7 @@ * 将摄像头绑定到身体的特定部位 * 自定义摄像头的位置和旋转角度 * 在第一人称视角下渲染玩家模型 -* 按下F6来开关,另外一些键来调整摄像头 +* 按下「F6」来开关,另外一些键来调整摄像头 * 在配置界面(需要Cloth Config)和模型视图(0.6+)界面,配置以上特性 ### 配置(0.6+) @@ -25,20 +25,27 @@ * 从右上角的按钮进入`预览`界面,在这里可以看到摄像头与模型的相对关系,并进行一定的调整(也可以通过按键绑定调整) * ![gui_preview](https://cdn.modrinth.com/data/fYYSAh4R/images/44c87a6f1750f8d1b03422120e6042d1098896cb.png) * 输入名称并保存 +* ~~如果实在不会配置,也可以将`模组设置 > 绑定模式 > 旧绑定模式`打开 +
    注意:该设置仅限原版~~ #### Tips * 可以更改配置的优先级,优先级越高的配置,在右侧排序越靠上 +* 在模组设置中,你可以通过修改配置索引来主动切换允许的配置,也可以调整到非0的数来锁定配置 +* 当开启主功能时,将鼠标放到配置上方,其中有注释`当前配置`的即为此时使用的配置 * 在`预览`界面可以更改禁用深度来禁用眼前的模型的渲染 -* 关于`禁用`界面(当前版本尚不完善,操作较为繁琐): - * 在左侧材质id输入框为空时,可以使用Alt+左键选择材质 - * 被蓝框包含的部分不会被渲染。 - * 在左侧材质视图中鼠标左键框选,其它键取消选择 - * Alt+左键可快速选中被鼠标指针指向的部分 - * 选择模式为范围,蓝框范围内被选中的面会被禁用,使用「Alt+鼠标滚轮」切换选中范围 - * 选择模式为多选,可以更好禁用原版玩家的部位,穿戴的盔甲等,但部分Mod 模型不一定适用 - * 禁用模式为部分,可以禁用被选择的贴图 - * 禁用模式为全部,整个材质所对应的模型都不会被渲染(左侧会有一个包含整个材质的蓝框来表示这一点) +* 关于`禁用`界面: + * 在左侧材质id输入框为空时,使用「Alt+左键」选择材质 + * 选择模式: + * 单选、多选:按下「Alt+左键」以选择需要禁用的面 + * 范围:按下「Alt+左键」以确定被选择区域,使用「Alt+滚轮」以更改被选择区域的大小 + * 在玩家渲染左侧材质视图中: + * 按下「鼠标左键」开始/结束框选,其它键取消选择 + * 被框选中的面效果与多选禁用的面效果相同 + * 值得一提的是,使用这种方式被禁用面,通常比使用其他方法更加节省性能 + * 禁用模式: + * `部分`模式下,被选择的面不会渲染(可以通过关闭右侧禁用配置的可见性来预览) + * `全部`模式下,整个材质所对应的模型都不会渲染(会有一个包含整个材质的蓝框来表示这一点) * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) ## 依赖项目 @@ -58,8 +65,9 @@ * 为什么打不开配置界面(模组设置)? * 没有安装[Cloth Config API](https://modrinth.com/mod/cloth-config) * 为什么ysm模型有时候会弹出绑定失败? - * 快照0.6.15“尝试”修复了ysm问题,但没有修复透彻 - * 如果Minecraft版本为1.20.1,那么需要将向上矢量绑定在头部的左面(或右面),并在预览界面中将翻滚角设置为90度(或-90度) + * 快照0.6.15“尝试”修复了ysm问题,但没有完全修复透彻 + * 当你的模型旋转到特定角时,由于ysm的`面剔除功能`,你绑定的位置可能消失,导致绑定失败 + * 可以通过增加`绑定结果保留帧数`来缓解这个问题 * 为什么装了Better Combat模组后,禁用的材质在挥舞武器时会重新出现? * 前往该模组的设置界面,把First person player animation 的Auto 改为False diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index dcfac604..50fd10fe 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -28,7 +28,6 @@ "config.option.xtracr_realcamera.pitch": "Pitch", "config.option.xtracr_realcamera.renderModel": "Render Player Model", "config.option.xtracr_realcamera.renderStuckObjects": "Render Stuck Objects", - "config.option.xtracr_realcamera.rerenderModel": "Rerender Model", "config.option.xtracr_realcamera.roll": "Roll", "config.option.xtracr_realcamera.rotationSmoothFactor": "Rotation Smooth Factor", "config.option.xtracr_realcamera.scale": "Scale", @@ -53,7 +52,6 @@ "config.tooltip.xtracr_realcamera.exitTick": "The time before re-enabling main feature after exiting restricted states (e.g., swimming, crawling) (1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.renderModel": "Render player model in first-person perspective", "config.tooltip.xtracr_realcamera.renderStuckObjects": "Arrows, bee stings and other objects that can be stuck in the player's body", - "config.tooltip.xtracr_realcamera.rerenderModel": "Render the model again at the original rendering time to avoid some visual problems caused by rendering early", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "Smooth factor of camera rotation, the higher the value, the smoother the movement", "config.tooltip.xtracr_realcamera.scale": "Control the size of the offsets", "general.xtracr_realcamera.modName": "Real Camera", diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 0f4ebc19..b5f22c3d 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -28,7 +28,6 @@ "config.option.xtracr_realcamera.pitch": "俯仰角", "config.option.xtracr_realcamera.renderModel": "渲染玩家模型", "config.option.xtracr_realcamera.renderStuckObjects": "渲染卡在身上的物体", - "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", "config.option.xtracr_realcamera.roll": "翻滚角", "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", "config.option.xtracr_realcamera.scale": "缩放比例", @@ -53,7 +52,6 @@ "config.tooltip.xtracr_realcamera.exitTick": "玩家停止某些状态(如游泳、爬行)后重启主要功能的时间(1 tick = 0.05s)", "config.tooltip.xtracr_realcamera.renderModel": "在第一人称视角下渲染玩家模型", "config.tooltip.xtracr_realcamera.renderStuckObjects": "箭,蜂刺和其它会卡在玩家身体里的物体", - "config.tooltip.xtracr_realcamera.rerenderModel": "在原本的渲染时机重新渲染模型,以避免一些因提前渲染导致的视觉问题", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相机旋转平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", "general.xtracr_realcamera.modName": "Real Camera",