diff --git a/.github/ISSUE_TEMPLATE/bug_report_cn.yml b/.github/ISSUE_TEMPLATE/bug_report_cn.yml index 8999102c..62cef475 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_cn.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_cn.yml @@ -7,42 +7,56 @@ 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 - placeholder: 'Mods list here' +
请在反馈问题前移除所有不相干的模组的情况下复现bug + placeholder: '与问题有关的模组列表' render: 'raw' validations: required: true @@ -52,7 +66,8 @@ body: attributes: label: 错误描述 description: >- - 请尽可能详细的描述遇到的问题. + 请尽可能详细的描述遇到的问题 +
同时也请务必携带复现时的视频或截图,这对于我们理解问题非常有帮助
越清晰和详尽的描述会使该bug的处理优先级更高 validations: required: true @@ -62,9 +77,9 @@ body: attributes: label: 复现步骤 placeholder: | - 1. Join the game... + 1. 进入游戏... - 2. Change some settings... + 2. 做出某些改变... 3. ... @@ -73,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: '把日志文件往这丢或者使用外部链接' +
**请不要在此处直接粘贴大段的日志文本!!!** +
**请不要在此处直接粘贴大段的日志文本!!!** +
**请不要在此处直接粘贴大段的日志文本!!!** + 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 000632d0..92e716d9 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: Question Type + 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 all unrelated mods removed before reporting placeholder: 'Mods list here' render: 'raw' validations: @@ -52,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 @@ -73,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!!** - placeholder: 'Drag log file here or use external link' +
**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/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/.github/workflows/build.yml b/.github/workflows/build.yml index 3a55202b..2c1ce2a5 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' @@ -27,7 +28,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: "temurin" - java-version: 17 + java-version: 21 - name: Make Gradle Wrapper Executable if: ${{ runner.os != 'Windows' }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f297d1ca..6096f2cd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,7 +26,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: "temurin" - java-version: 17 + java-version: 21 - name: Make Gradle Wrapper Executable if: ${{ runner.os != 'Windows' }} diff --git a/README.md b/README.md index 42992dad..cdd3d1ff 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.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) @@ -12,86 +12,98 @@ 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+) * 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. +* ~~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 selector +* 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+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) +* 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 * 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 -* Why can't i open the Config Screen? - * Please downlowd [Cloth Config API](https://modrinth.com/mod/cloth-config) + * Set the key binding by yourself +* Why can't I open the Config Screen? + * Please download [Cloth Config API](https://modrinth.com/mod/cloth-config) * Why does it show binding failed when use YSM models? - * On Minecraft 1.20.1, use a Real Camera build with the dedicated YSM projection sampler; the old side-face binding and roll workaround is no longer required -* Why does the head of YSM model disappear when in the Model View Screen? - * You downloaded Better Combat, just put it away + * 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 ### 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 58f7d15c..07557e6e 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.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) @@ -12,85 +12,97 @@ * 将摄像头绑定到身体的特定部位 * 自定义摄像头的位置和旋转角度 * 在第一人称视角下渲染玩家模型 -* 按下F6来开关,另外一些键来调整摄像头 +* 按下「F6」来开关,另外一些键来调整摄像头 * 在配置界面(需要Cloth Config)和模型视图(0.6+)界面,配置以上特性 ### 配置(0.6+) * 理论上支持大多数模组模型,但需要手动进行配置: * 首先设置`打开模型视图界面`的按键绑定 - * ![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 * 可以更改配置的优先级,优先级越高的配置,在右侧排序越靠上 +* 在模组设置中,你可以通过修改配置选择器来主动切换允许的配置 +* 当开启主功能时,将鼠标放到配置上方,其中有注释`当前配置`的即为此时使用的配置 * 在`预览`界面可以更改禁用深度来禁用眼前的模型的渲染 -* 关于`禁用`界面(当前版本尚不完善,操作较为繁琐): - * 在左侧材质id输入框为空时,可以使用Alt+左键选择材质 - * 被蓝框包含的部分不会被渲染。 - * 在左侧材质视图中鼠标左键框选,其它键取消选择 - * Alt+左键可快速选中被鼠标指针指向的部分 - * `全部`模式下,整个材质所对应的模型都不会被渲染(左侧会有一个包含整个材质的蓝框来表示这一点) - * ![gui_disable](https://cdn.modrinth.com/data/fYYSAh4R/images/b49ac4da6bf8a59f13c7e93ca1ef76b73e5d23b4.png) +* 关于`禁用`界面: + * 在左侧材质id输入框为空时,使用「Alt+左键」选择材质 + * 选择模式: + * 单选、多选:按下「Alt+左键」以选择需要禁用的面 + * 范围:按下「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模型有时候会弹出绑定失败? - * 在 Minecraft 1.20.1 中,请使用带有 YSM 专用投影采样器的 Real Camera 版本;无需再使用侧面绑定与翻滚角补偿 -* 为什么配置ysm时候,模型视图界面中ysm模型头部消失? - * 安装了Better Combat模组,去掉就可以了 + * 快照0.6.15“尝试”修复了ysm问题,但没有完全修复透彻 + * 当你的模型旋转到特定角时,由于ysm的`面剔除功能`,你绑定的位置可能消失,导致绑定失败 + * 可以通过增加`绑定结果保留帧数`来缓解这个问题 +* 为什么装了Better Combat模组后,禁用的材质在挥舞武器时会重新出现? + * 前往该模组的设置界面,把First person player animation 的Auto 改为False ### 兼容性 * 不兼容: - * 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 4a6dc1fa..00000000 --- a/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -plugins { - id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.10-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() - //mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2" - } -} - -allprojects { - apply plugin: "java" - apply plugin: "architectury-plugin" - apply plugin: "maven-publish" - - base { - archivesName = rootProject.archives_base_name - } - - version = rootProject.mod_version + (findProperty("commitSHA") ? "-${(commitSHA as String).substring(0,7)}" : "") - group = rootProject.maven_group - - 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 = 17 - } - - java { - withSourcesJar() - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..2db443ba --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,22 @@ +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://libraries.minecraft.net/") + maven("https://maven.shedaniel.me/") + maven("https://maven.terraformersmc.com/") + maven("https://maven.fabricmc.net/") + maven("https://maven.minecraftforge.net/") + maven("https://api.modrinth.com/maven/") + // maven("https://cursemaven.com") + // maven("https://www.jitpack.io" + } +} 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..01cb7847 --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,63 @@ +plugins { + id("net.fabricmc.fabric-loom-remap") + id("maven-publish") +} + +repositories { + maven("https://libraries.minecraft.net/") + maven("https://maven.fabricmc.net/") + maven("https://maven.shedaniel.me/") + gradlePluginPortal() +} + +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") + mappings(loom.officialMojangMappings()) + + compileOnly("org.spongepowered:mixin:0.8.5") + compileOnly("io.github.llamalad7:mixinextras-common:0.5.3") + annotationProcessor("io.github.llamalad7:mixinextras-common:0.5.3") + // We depend on Fabric Loader here to use the Fabric @Environment annotations, + modCompileOnly("net.fabricmc:fabric-loader:$fabricLoaderVersion") + + // Cloth Config + modCompileOnly("me.shedaniel.cloth:cloth-config-fabric:$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 599002ec..3a022cc6 100644 --- a/common/src/main/java/com/xtracr/realcamera/KeyMappings.java +++ b/common/src/main/java/com/xtracr/realcamera/KeyMappings.java @@ -12,25 +12,25 @@ import java.util.function.Consumer; public final class KeyMappings { - private static final Map> KEY_MAPPINGS = new HashMap<>(); 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 -> { - boolean enabled = ConfigFile.config().enabled(); + boolean enabled = ConfigFile.config().enabled; ConfigFile.load(); - ConfigFile.config().setEnabled(!enabled); + ConfigFile.config().enabled = !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("toggleCameraMode", client -> ConfigFile.config().isClassic = !ConfigFile.config().isClassic); 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("adjustFRONT", client -> ConfigFile.config().adjustOffsetX(1)); + createKeyMapping("adjustBACK", client -> ConfigFile.config().adjustOffsetX(-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); @@ -41,7 +41,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_CATEGORY_GENERAL); + KeyMapping keyMapping = new KeyMapping("key." + RealCamera.FULL_ID + "." + id, code, LocUtil.KEY_MOD_NAME); KEY_MAPPINGS.put(keyMapping, whenPressed); return keyMapping; } 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 591b9089..a1f14d9e 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -17,6 +17,7 @@ import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.util.Mth; 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; @@ -43,8 +44,8 @@ public static BindTarget currentTarget() { public static void initialize(Minecraft client) { Entity entity = client.getCameraEntity(); - active = ConfigFile.config().enabled() && client.options.getCameraType().isFirstPerson() && entity != null && !DisableHelper.MAIN_FEATURE.disabled(entity); - rendering = ConfigFile.config().renderModel() && !DisableHelper.RENDER_MODEL.disabled(entity); + active = 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() { @@ -63,7 +64,7 @@ public static float getYaw(float f) { } public static float getRoll(float f) { - if (ConfigFile.config().isClassic()) return f + ConfigFile.config().getClassicRoll(); + if (ConfigFile.config().isClassic) return f + ConfigFile.config().getClassicRoll(); return (float) getEulerAngle(0, 0, f).z(); } @@ -92,25 +93,25 @@ public static void computeCamera(Minecraft client, float deltaTick) { Entity entity = client.getCameraEntity(); boolean invisible = entity.isInvisible(); entity.setInvisible(false); - newResult = RealCameraAPI.computeBindResult(client, deltaTick); - if (!newResult.available()) { - EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); - try { + try { + newResult = RealCameraAPI.computeBindResult(client, deltaTick); + if (!newResult.available()) { + EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); dispatcher.render(entity, 0, 0, 0, Mth.lerp(deltaTick, entity.yRotO, entity.getYRot()), deltaTick, new PoseStack(), vertexCatcher, dispatcher.getPackedLightCoords(entity, deltaTick)); vertexCatcher.forEachBuffer(RealCameraCore::computeBindResult); - } finally { - vertexCatcher.clear(); } + } finally { + vertexCatcher.clear(); + entity.setInvisible(invisible); } - entity.setInvisible(invisible); if (newResult.available()) { failureFrames = 0; lastResult = newResult.computeCamera(false); } else { failureFrames++; - Entity player = client.player; - int retentionFrames = ConfigFile.config().getBindResultRetentionFrames(); - if (!ConfigFile.config().hideBindingFailureMessage() && failureFrames == retentionFrames + 1 && player != null) { + Player player = client.player; + 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) { @@ -119,8 +120,8 @@ public static void computeCamera(Minecraft client, float deltaTick) { 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 deltaTick, MultiBufferSource bufferSource) { @@ -175,8 +176,19 @@ private static 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())}; - VertexData[][] primitives = builtBuffer.resolvePrimitives(uvs); - for (VertexData[] primitive : primitives) if (primitive == null) continue targetFor; + VertexData[][] primitives = builtBuffer.findPrimitivesInCache(uvs); + 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; + else if (newPrimitives[i] != null) primitives[i] = newPrimitives[i]; + } + } if (primitives[0] != null) result.setPosition(VertexData.position(primitives[0], config.posU(), config.posV())); if (primitives[1] != null) result.setForward(VertexData.normal(primitives[1])); if (primitives[2] != null) result.setUpward(VertexData.normal(primitives[2])); 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 ac7dd12d..61a6fd37 100644 --- a/common/src/main/java/com/xtracr/realcamera/api/BindResult.java +++ b/common/src/main/java/com/xtracr/realcamera/api/BindResult.java @@ -19,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() 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 fcc4df84..b225c705 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java @@ -12,8 +12,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.function.Function; -public class CompatibilityHelper { +public final class CompatibilityHelper { + public static boolean isRenderInScreen; private static PlatformHelper platformHelper; private static Method NEA_playerTransformer_setDeltaTick; private static Field NEA_NEAnimationsLoader_INSTANCE; @@ -58,6 +60,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 = object -> 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()); + } if (isModLoaded("tacz")) try { TACZ_IClientPlayerGunOperator = Class.forName("com.tacz.guns.api.client.gameplay.IClientPlayerGunOperator"); TACZ_IClientPlayerGunOperator_fromLocalPlayer = TACZ_IClientPlayerGunOperator.getMethod("fromLocalPlayer", LocalPlayer.class); @@ -107,7 +121,7 @@ public static void NEA_setDeltaTick(float deltaTick) { } public static void forceSetCameraPos(Camera camera) { - if (RealCameraCore.isActive() && !ConfigFile.config().isClassic()) { + if (RealCameraCore.isActive() && !ConfigFile.config().isClassic) { ((CameraAccessor) camera).invokeSetPosition(RealCameraCore.getCameraPos(camera.getPosition())); } } 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 558e6d49..61f1d073 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -15,25 +15,26 @@ 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 = player -> 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; + private static final Map ENTRIES = new HashMap<>(); + private static int exitTick = 0; 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() && 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 = new Entry("mainFeature", player -> player.isSleeping() || player.isSpectator()); + RENDER_MODEL = new Entry("renderModel", FALSE, Player::isScoping); + RENDER_HANDS = new Entry("renderHands", player -> 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.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(); - for (String pattern : ConfigFile.config().getDisableMainFeatureItems()) + for (String pattern : ConfigFile.config().binding.disableMainFeatureItems) if (matchesItemPattern(mainHand, pattern) || matchesItemPattern(offHand, pattern)) return true; return false; @@ -41,7 +42,7 @@ public 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; @@ -65,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) { @@ -115,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) { @@ -124,16 +125,18 @@ 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) { 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 4579387f..c0a7241c 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/LegacyBindingMode.java @@ -24,7 +24,7 @@ public static void register() { } private static BindResult computeBindResult(Minecraft client, float deltaTick) { - 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/compat/TetrahedralProbeSet.java b/common/src/main/java/com/xtracr/realcamera/compat/TetrahedralProbeSet.java index 03ebaa74..8975ade8 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/TetrahedralProbeSet.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/TetrahedralProbeSet.java @@ -1,7 +1,6 @@ package com.xtracr.realcamera.compat; import org.joml.Matrix4f; -import org.joml.Matrix4fc; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -25,10 +24,6 @@ final class TetrahedralProbeSet { private TetrahedralProbeSet() { } - static Vector3fc direction(int pass) { - return DIRECTIONS[pass]; - } - static Matrix4f projection(int pass) { return PROJECTIONS[pass]; } 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 8f2063e8..10fb3f06 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindTarget.java @@ -35,7 +35,8 @@ private static BindTarget vanillaTarget(String name, int priority, boolean shoul offsets.x = -0.1f; 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()); - return new BindTarget(name, textureId, priority, 0.2f, targetConfig, bindConfig, offsets, List.of(playerHead, dragonHead)); + List disableConfigs = List.of(playerHead, dragonHead); + return new BindTarget(name, textureId, priority, 0.2f, targetConfig, bindConfig, offsets, disableConfigs); } public boolean isEmpty() { 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..23512dcb 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,45 @@ 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.jetbrains.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 class ConfigFile { - private static final ModConfig modConfig = new ModConfig(); - private static final String FILE_NAME = RealCamera.MODID + ".json"; +public final class ConfigFile { + private static final String FILE_NAME = RealCamera.MOD_ID + ".json"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - private static final Path PATH; - - static { - File configDir = new File(Minecraft.getInstance().gameDirectory, "config"); - if (!configDir.exists()) configDir.mkdirs(); - PATH = configDir.toPath().resolve(FILE_NAME); - } + private final static Supplier path = Suppliers.memoize(ConfigFile::getPath); + @Nullable + private static ModConfig config; 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,11 +47,18 @@ 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); } } + + @SuppressWarnings("ResultOfMethodCallIgnored") + 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/ConfigScreen.java b/common/src/main/java/com/xtracr/realcamera/config/ConfigScreen.java index f6399e09..a0ed7953 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(); @@ -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) @@ -140,7 +140,7 @@ 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) @@ -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()) @@ -225,4 +225,4 @@ public static Screen create(Screen parent) { 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 5d95a3f4..9eb9d1fe 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -9,26 +9,16 @@ 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 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 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); @@ -36,30 +26,6 @@ public void 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; @@ -113,24 +79,6 @@ public void adjustOffsetZ(int count) { } } - // classic - public boolean classicDisableWhenSneaking() { - return classic.disableWhenSneaking; - } - - public boolean classicDisableWhenSwimming() { - return classic.disableWhenSwimming; - } - - public int getClassicOutTick() { - return classic.outTick; - } - - @Deprecated - public int getClassicSwimOutTick() { - return getClassicOutTick(); - } - public double getClassicX() { return classic.cameraX * classic.scale; } @@ -167,75 +115,7 @@ public float getClassicRoll() { return classic.roll; } - // binding - public InputConstants.Key getScreenModifierKey() { - return InputConstants.getKey(binding.screenModifierKey); - } - - public boolean legacyBindingMode() { - return binding.legacyMode; - } - - 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; - } - - @Deprecated - public int getBindingSwimOutTick() { - return getBindingOutTick(); - } - - 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; @@ -263,9 +143,7 @@ public static class Classic { public AdjustMode adjustMode = AdjustMode.CAMERA; public boolean disableWhenSneaking = false; public boolean disableWhenSwimming = false; - public int outTick = 13; - @Deprecated - public Integer swimOutTick = null; + public int exitTick = 13; public double scale = 8.0; public double cameraX = -0.5; public double cameraY = 0.04; @@ -279,11 +157,7 @@ public static class Classic { private void clamp() { if (adjustMode == null) adjustMode = AdjustMode.CAMERA; - if (swimOutTick != null) { - if (outTick == 13) outTick = swimOutTick; - swimOutTick = null; - } - 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); @@ -311,17 +185,13 @@ public static class Binding { 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; - @Deprecated - public Boolean legacyBindingMode = null; 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; - @Deprecated - public Integer swimOutTick = null; + public boolean disableWhenFlying = false; + public int exitTick = 13; public int bindResultRetentionFrames = 2; public int activeConfigIndex = 0; public double displacementSmoothFactor = 0.4; @@ -337,15 +207,7 @@ private void clamp() { } catch (Exception e) { screenModifierKey = InputConstants.Type.KEYSYM.getOrCreate(InputConstants.KEY_LALT).getName(); } - if (swimOutTick != null) { - if (outTick == 13) outTick = swimOutTick; - swimOutTick = null; - } - if (legacyBindingMode != null) { - legacyMode = legacyBindingMode; - legacyBindingMode = null; - } - 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); @@ -361,4 +223,4 @@ private void clamp() { } } } -} +} \ No newline at end of file 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 51136433..e3dded99 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/OffsetConfig.java @@ -27,73 +27,4 @@ public void clamp() { yaw = Mth.wrapDegrees(yaw); roll = Mth.wrapDegrees(roll); } - - 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 = x; - clamp(); - return this; - } - - public float getY() { - return y; - } - - public OffsetConfig setY(float y) { - this.y = y; - clamp(); - return this; - } - - public float getZ() { - return z; - } - - public OffsetConfig setZ(float z) { - this.z = z; - clamp(); - return this; - } - - public float getPitch() { - return pitch; - } - - public OffsetConfig setPitch(float pitch) { - this.pitch = pitch; - clamp(); - return this; - } - - public float getYaw() { - return yaw; - } - - public OffsetConfig setYaw(float yaw) { - this.yaw = yaw; - clamp(); - return this; - } - - public float getRoll() { - return roll; - } - - public OffsetConfig setRoll(float roll) { - this.roll = roll; - clamp(); - return this; - } } 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 78bbd5dc..9762c2d5 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 @@ -2,40 +2,43 @@ import com.mojang.serialization.DataResult; 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 com.xtracr.realcamera.config.codec.utli.StreamCodec; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import net.minecraft.network.FriendlyByteBuf; +import io.netty.handler.codec.DecoderException; +import io.netty.handler.codec.EncoderException; +import it.unimi.dsi.fastutil.shorts.Short2ReferenceMap; +import it.unimi.dsi.fastutil.shorts.Short2ReferenceOpenHashMap; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.util.ArrayList; import java.util.Base64; -import java.util.List; +import java.util.Map; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; public final class ConfigCodec { - private static final short CURRENT_VERSION = 703; - - private ConfigCodec() { - } + static final short CURRENT_VERSION = 703; + static final Short2ReferenceMap> CODECS = new Short2ReferenceOpenHashMap<>(Map.of( + CURRENT_VERSION, ConfigCodec703.CODEC + )); - public static BindTarget readWithVersion(FriendlyByteBuf byteBuf) throws IllegalArgumentException { + public static BindTarget readWithVersion(ByteBuf byteBuf) throws DecoderException, IllegalArgumentException { short version = byteBuf.readShort(); - if (version != CURRENT_VERSION) throw new IllegalArgumentException("Invalid version: " + version + ", expected " + CURRENT_VERSION); - return readTarget(byteBuf); + StreamCodec serializer = CODECS.get(version); + if (serializer == null) throw new IllegalArgumentException("Incompatible version: " + toSemVer(version)); + return serializer.decode(byteBuf); } - public static void writeWithVersion(FriendlyByteBuf byteBuf, BindTarget bindTarget) { + public static void writeWithVersion(ByteBuf byteBuf, BindTarget bindTarget) throws EncoderException { byteBuf.writeShort(CURRENT_VERSION); - writeTarget(byteBuf, bindTarget); + CODECS.get(CURRENT_VERSION).encode(byteBuf, bindTarget); } public 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)); @@ -45,7 +48,8 @@ public static DataResult fromCompressedBase64(String base64) { while ((length = inflaterStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } - byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(outputStream.toByteArray())); + byte[] bytes = outputStream.toByteArray(); + byteBuf = Unpooled.wrappedBuffer(bytes); BindTarget target = readWithVersion(byteBuf); if (target.isEmpty()) return DataResult.error(() -> "Invalid config format"); return DataResult.success(target); @@ -61,7 +65,7 @@ public static DataResult fromCompressedBase64(String base64) { } public static DataResult toCompressedBase64(BindTarget bindTarget) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + ByteBuf byteBuf = Unpooled.buffer(); try { writeWithVersion(byteBuf, bindTarget); byte[] bytes = new byte[byteBuf.readableBytes()]; @@ -70,7 +74,8 @@ public static DataResult toCompressedBase64(BindTarget bindTarget) { try (DeflaterOutputStream deflaterStream = new DeflaterOutputStream(outputStream, new Deflater(Deflater.BEST_COMPRESSION))) { deflaterStream.write(bytes); } - return DataResult.success(Base64.getEncoder().encodeToString(outputStream.toByteArray())); + String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + return DataResult.success(base64); } catch (Exception e) { return DataResult.error(() -> e.getClass().getSimpleName() + ": " + e.getMessage()); } finally { @@ -78,103 +83,10 @@ public static DataResult toCompressedBase64(BindTarget bindTarget) { } } - private static BindTarget readTarget(FriendlyByteBuf byteBuf) { - 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); - int size = byteBuf.readVarInt(); - List disableConfigs = new ArrayList<>(size); - for (int i = 0; i < size; i++) disableConfigs.add(readDisableConfig(byteBuf)); - return new BindTarget(name, textureId, priority, disablingDepth, targetConfig, bindConfig, offsets, disableConfigs); - } - - private static void writeTarget(FriendlyByteBuf byteBuf, BindTarget bindTarget) { - byteBuf.writeUtf(bindTarget.name()); - byteBuf.writeUtf(bindTarget.textureId()); - byteBuf.writeVarInt(bindTarget.priority()); - byteBuf.writeFloat(bindTarget.disablingDepth()); - writeTargetConfig(byteBuf, bindTarget.targetConfig()); - writeBindConfig(byteBuf, bindTarget.bindConfig()); - writeOffsetConfig(byteBuf, bindTarget.offsets()); - byteBuf.writeVarInt(bindTarget.disableConfigs().size()); - for (DisableConfig disableConfig : bindTarget.disableConfigs()) writeDisableConfig(byteBuf, disableConfig); - } - - private static BindTarget.TargetConfig readTargetConfig(FriendlyByteBuf byteBuf) { - return new BindTarget.TargetConfig(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - - private static void writeTargetConfig(FriendlyByteBuf byteBuf, BindTarget.TargetConfig config) { - byteBuf.writeFloat(config.forwardU()); - byteBuf.writeFloat(config.forwardV()); - byteBuf.writeFloat(config.upwardU()); - byteBuf.writeFloat(config.upwardV()); - byteBuf.writeFloat(config.posU()); - byteBuf.writeFloat(config.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 void writeBindConfig(FriendlyByteBuf byteBuf, BindTarget.BindConfig bindConfig) { - byte bindFlags = 0; - if (bindConfig.bindX()) bindFlags |= 0x01; - if (bindConfig.bindY()) bindFlags |= 0x02; - if (bindConfig.bindZ()) bindFlags |= 0x04; - if (bindConfig.bindRotation()) bindFlags |= 0x08; - byteBuf.writeByte(bindFlags); - } - - private static OffsetConfig readOffsetConfig(FriendlyByteBuf byteBuf) { - return new OffsetConfig(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - - private static void writeOffsetConfig(FriendlyByteBuf byteBuf, OffsetConfig offsets) { - byteBuf.writeFloat(offsets.scale); - byteBuf.writeFloat(offsets.x); - byteBuf.writeFloat(offsets.y); - byteBuf.writeFloat(offsets.z); - byteBuf.writeFloat(offsets.pitch); - byteBuf.writeFloat(offsets.yaw); - byteBuf.writeFloat(offsets.roll); - } - - private static DisableConfig readDisableConfig(FriendlyByteBuf byteBuf) { - String name = byteBuf.readUtf(); - String textureId = byteBuf.readUtf(); - boolean disableAll = byteBuf.readBoolean(); - int size = byteBuf.readVarInt(); - List rectangles = new ArrayList<>(size); - for (int i = 0; i < size; i++) rectangles.add(readUVRectangle(byteBuf)); - return new DisableConfig(name, textureId, disableAll, rectangles); - } - - private static void writeDisableConfig(FriendlyByteBuf byteBuf, DisableConfig disableConfig) { - byteBuf.writeUtf(disableConfig.name()); - byteBuf.writeUtf(disableConfig.textureId()); - byteBuf.writeBoolean(disableConfig.disableAll()); - byteBuf.writeVarInt(disableConfig.rectangles().size()); - for (UVRectangle rect : disableConfig.rectangles()) writeUVRectangle(byteBuf, rect); - } - - private static UVRectangle readUVRectangle(FriendlyByteBuf byteBuf) { - return new UVRectangle(byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat(), byteBuf.readFloat()); - } - - private static void writeUVRectangle(FriendlyByteBuf byteBuf, UVRectangle rect) { - byteBuf.writeFloat(rect.uMin()); - byteBuf.writeFloat(rect.vMin()); - byteBuf.writeFloat(rect.uMax()); - byteBuf.writeFloat(rect.vMax()); + private static String toSemVer(short version) { + int major = version / 10000; + int minor = version % 10000 / 100; + int patch = version % 100; + return major + "." + minor + "." + patch; } -} +} \ No newline at end of file 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..edd0cf04 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/ConfigCodec703.java @@ -0,0 +1,79 @@ +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 com.xtracr.realcamera.config.codec.utli.ByteBufCodecs; +import com.xtracr.realcamera.config.codec.utli.CodecUtil; +import com.xtracr.realcamera.config.codec.utli.StreamCodec; +import io.netty.buffer.ByteBuf; + +import java.util.List; + +final class ConfigCodec703 { + static final StreamCodec TARGET_CONFIG_CODEC = CodecUtil.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.of( + 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 = CodecUtil.composite( + ByteBufCodecs.FLOAT, offsets -> offsets.scale, + 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.list(CodecUtil.composite( + ByteBufCodecs.FLOAT, UVRectangle::uMin, + ByteBufCodecs.FLOAT, UVRectangle::vMin, + ByteBufCodecs.FLOAT, UVRectangle::uMax, + ByteBufCodecs.FLOAT, UVRectangle::vMax, + UVRectangle::new + )); + static final StreamCodec> DISABLE_CONFIGS_CODEC = StreamCodec.list(CodecUtil.composite( + ByteBufCodecs.STRING_UTF8, DisableConfig::name, + ByteBufCodecs.STRING_UTF8, DisableConfig::textureId, + ByteBufCodecs.BOOL, DisableConfig::disableAll, + UV_RECTANGLES_CODEC, DisableConfig::rectangles, + DisableConfig::new + )); + static final StreamCodec CODEC = CodecUtil.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 + ); +} \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/utli/ByteBufCodecs.java b/common/src/main/java/com/xtracr/realcamera/config/codec/utli/ByteBufCodecs.java new file mode 100644 index 00000000..a3152f50 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/utli/ByteBufCodecs.java @@ -0,0 +1,52 @@ +package com.xtracr.realcamera.config.codec.utli; + +import io.netty.buffer.ByteBuf; + +import java.nio.charset.StandardCharsets; + +/** + * A polyfill for {@code net.minecraft.network.codec.ByteBufCodecs} in Minecraft 1.21.1. + */ +public final class ByteBufCodecs { + public static final StreamCodec FLOAT = StreamCodec.of(ByteBuf::writeFloat, ByteBuf::readFloat); + public static final StreamCodec BYTE = StreamCodec.of((buf, val) -> buf.writeByte(val), ByteBuf::readByte); + public static final StreamCodec BOOL = StreamCodec.of(ByteBuf::writeBoolean, ByteBuf::readBoolean); + public static final StreamCodec VAR_INT = StreamCodec.of(ByteBufCodecs::writeVarInt, ByteBufCodecs::readVarInt); + public static final StreamCodec STRING_UTF8 = StreamCodec.of(ByteBufCodecs::writeString, ByteBufCodecs::readString); + + public static int readVarInt(ByteBuf buf) { + int i = 0; + int j = 0; + byte b; + do { + b = buf.readByte(); + i |= (b & 0x7F) << j++ * 7; + if (j > 5) { + throw new RuntimeException("VarInt is too big"); + } + } while ((b & 0x80) == 0x80); + return i; + } + + public static void writeVarInt(ByteBuf buf, int value) { + int i = value; + while ((i & -128) != 0) { + buf.writeByte(i & 127 | 128); + i >>>= 7; + } + buf.writeByte(i); + } + + public static String readString(ByteBuf buf) { + int length = readVarInt(buf); + byte[] bytes = new byte[length]; + buf.readBytes(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + + public static void writeString(ByteBuf buf, String value) { + byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + writeVarInt(buf, bytes.length); + buf.writeBytes(bytes); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/utli/CodecUtil.java b/common/src/main/java/com/xtracr/realcamera/config/codec/utli/CodecUtil.java new file mode 100644 index 00000000..cfa25a47 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/utli/CodecUtil.java @@ -0,0 +1,93 @@ +package com.xtracr.realcamera.config.codec.utli; + +import java.util.function.Function; + +/** + * A polyfill for composite constructors in {@code net.minecraft.network.codec.StreamCodec} for Minecraft 1.21.1. + */ +@SuppressWarnings({"unchecked", "unused"}) +public final class CodecUtil { + private CodecUtil() {} + + @FunctionalInterface public interface Constructor4 { R apply(A a, B b, C c, D d); } + @FunctionalInterface public interface Constructor5 { R apply(A a, B b, C c, D d, E e); } + @FunctionalInterface public interface Constructor6 { R apply(A a, B b, C c, D d, E e, F f); } + @FunctionalInterface public interface Constructor7 { R apply(A a, B b, C c, D d, E e, F f, G g); } + @FunctionalInterface public interface Constructor8 { R apply(A a, B b, C c, D d, E e, F f, G g, H h); } + @FunctionalInterface public interface Constructor9 { R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i); } + + private static StreamCodec composite(final StreamCodec[] codecs, final Function[] getters, final Function constructor) { + return new StreamCodec<>() { + @Override + public T decode(B buf) { + Object[] values = new Object[codecs.length]; + for (int i = 0; i < codecs.length; i++) { + values[i] = codecs[i].decode(buf); + } + return constructor.apply(values); + } + + @Override + public void encode(B buf, T value) { + for (int i = 0; i < codecs.length; i++) { + ((StreamCodec) codecs[i]).encode(buf, ((Function) getters[i]).apply(value)); + } + } + }; + } + + public static StreamCodec composite( + StreamCodec c1, Function g1, StreamCodec c2, Function g2, + StreamCodec c3, Function g3, StreamCodec c4, Function g4, + Constructor4 constructor) { + return composite(new StreamCodec[]{c1, c2, c3, c4}, new Function[]{g1, g2, g3, g4}, + (vals) -> constructor.apply((F1) vals[0], (F2) vals[1], (F3) vals[2], (F4) vals[3])); + } + + public static StreamCodec composite( + StreamCodec c1, Function g1, StreamCodec c2, Function g2, + StreamCodec c3, Function g3, StreamCodec c4, Function g4, + StreamCodec c5, Function g5, Constructor5 constructor) { + return composite(new StreamCodec[]{c1, c2, c3, c4, c5}, new Function[]{g1, g2, g3, g4, g5}, + (vals) -> constructor.apply((F1) vals[0], (F2) vals[1], (F3) vals[2], (F4) vals[3], (F5) vals[4])); + } + + public static StreamCodec composite( + StreamCodec c1, Function g1, StreamCodec c2, Function g2, + StreamCodec c3, Function g3, StreamCodec c4, Function g4, + StreamCodec c5, Function g5, StreamCodec c6, Function g6, + Constructor6 constructor) { + return composite(new StreamCodec[]{c1, c2, c3, c4, c5, c6}, new Function[]{g1, g2, g3, g4, g5, g6}, + (vals) -> constructor.apply((F1) vals[0], (F2) vals[1], (F3) vals[2], (F4) vals[3], (F5) vals[4], (F6) vals[5])); + } + + public static StreamCodec composite( + StreamCodec c1, Function g1, StreamCodec c2, Function g2, + StreamCodec c3, Function g3, StreamCodec c4, Function g4, + StreamCodec c5, Function g5, StreamCodec c6, Function g6, + StreamCodec c7, Function g7, + Constructor7 constructor) { + return composite(new StreamCodec[]{c1, c2, c3, c4, c5, c6, c7}, new Function[]{g1, g2, g3, g4, g5, g6, g7}, + (vals) -> constructor.apply((F1) vals[0], (F2) vals[1], (F3) vals[2], (F4) vals[3], (F5) vals[4], (F6) vals[5], (F7) vals[6])); + } + + public static StreamCodec composite( + StreamCodec c1, Function g1, StreamCodec c2, Function g2, + StreamCodec c3, Function g3, StreamCodec c4, Function g4, + StreamCodec c5, Function g5, StreamCodec c6, Function g6, + StreamCodec c7, Function g7, StreamCodec c8, Function g8, + Constructor8 constructor) { + return composite(new StreamCodec[]{c1, c2, c3, c4, c5, c6, c7, c8}, new Function[]{g1, g2, g3, g4, g5, g6, g7, g8}, + (vals) -> constructor.apply((F1) vals[0], (F2) vals[1], (F3) vals[2], (F4) vals[3], (F5) vals[4], (F6) vals[5], (F7) vals[6], (F8) vals[7])); + } + + public static StreamCodec composite( + StreamCodec c1, Function g1, StreamCodec c2, Function g2, + StreamCodec c3, Function g3, StreamCodec c4, Function g4, + StreamCodec c5, Function g5, StreamCodec c6, Function g6, + StreamCodec c7, Function g7, StreamCodec c8, Function g8, + StreamCodec c9, Function g9, Constructor9 constructor) { + return composite(new StreamCodec[]{c1, c2, c3, c4, c5, c6, c7, c8, c9}, new Function[]{g1, g2, g3, g4, g5, g6, g7, g8, g9}, + (vals) -> constructor.apply((F1) vals[0], (F2) vals[1], (F3) vals[2], (F4) vals[3], (F5) vals[4], (F6) vals[5], (F7) vals[6], (F8) vals[7], (F9) vals[8])); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/xtracr/realcamera/config/codec/utli/StreamCodec.java b/common/src/main/java/com/xtracr/realcamera/config/codec/utli/StreamCodec.java new file mode 100644 index 00000000..67936152 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/config/codec/utli/StreamCodec.java @@ -0,0 +1,74 @@ +package com.xtracr.realcamera.config.codec.utli; + +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * A polyfill for {@code net.minecraft.network.codec.StreamCodec} in Minecraft 1.21.1. + */ +public interface StreamCodec { + + V decode(B buf); + + void encode(B buf, V value); + + static StreamCodec of(BiConsumer encoder, Function decoder) { + return new StreamCodec<>() { + @Override + public V decode(B buf) { + return decoder.apply(buf); + } + + @Override + public void encode(B buf, V value) { + encoder.accept(buf, value); + } + }; + } + + static StreamCodec of(StreamCodec fieldCodec, Function toField, Function fromField) { + return new StreamCodec<>() { + @Override + public T decode(B buf) { + F fieldValue = fieldCodec.decode(buf); + return fromField.apply(fieldValue); + } + + @Override + public void encode(B buf, T value) { + F fieldValue = toField.apply(value); + fieldCodec.encode(buf, fieldValue); + } + }; + } + + static StreamCodec> list(StreamCodec elementCodec) { + return new StreamCodec<>() { + @Override + public List decode(B buf) { + if (!(buf instanceof ByteBuf byteBuf)) + throw new UnsupportedOperationException("List codec only supports ByteBuf"); + int size = ByteBufCodecs.readVarInt(byteBuf); + List list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(elementCodec.decode(buf)); + } + return list; + } + + @Override + public void encode(B buf, List value) { + if (!(buf instanceof ByteBuf byteBuf)) + throw new UnsupportedOperationException("List codec only supports ByteBuf"); + ByteBufCodecs.writeVarInt(byteBuf, value.size()); + for (V element : value) { + elementCodec.encode(buf, element); + } + } + }; + } +} \ No newline at end of file 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 cd0e414a..c430e5c8 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/GUIHelper.java @@ -1,14 +1,21 @@ package com.xtracr.realcamera.gui; import com.mojang.blaze3d.vertex.VertexConsumer; +import com.xtracr.realcamera.renderer.state.BuiltModelRecord; import com.xtracr.realcamera.renderer.state.VertexData; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.renderer.RenderType; import net.minecraft.world.phys.Vec3; +import org.joml.Matrix3f; import org.joml.Matrix4f; +import org.joml.Vector3f; + +import java.util.List; + +public class GUIHelper { + public static final int MODEL_MIN_Z = 0, MODEL_MAX_Z = 200; -public final class GUIHelper { public static void enableScissor(GuiGraphics graphics, ScreenRectangle rectangle) { graphics.enableScissor(rectangle.left(), rectangle.top(), rectangle.right(), rectangle.bottom()); } @@ -57,4 +64,42 @@ public static void vector(GuiGraphics graphics, Vec3 start, Vec3 vector, float z buffer.vertex((float) (start.x + vector.x), (float) (start.y + vector.y), z).color(argb).normal((float) vector.x, (float) vector.y, 0).endVertex(); graphics.flush(); } + + public static void culledModels(GuiGraphics graphics, List modelRecords, Matrix4f transform) { + float minEntityZ = MODEL_MIN_Z, maxEntityZ = MODEL_MAX_Z; + for (BuiltModelRecord 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(transform).scale(1, 1, MODEL_MAX_Z / (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); + } + }); + graphics.flush(); + } + + public static void flattenedModels(GuiGraphics graphics, List textureRecords, Matrix4f positionMatrix) { + 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); + int argb = vertex.argb(); + buffer.vertex(position.x(), position.y(), 0 , + (float) (argb >> 16 & 0xFF) / 255, (float) (argb >> 8 & 0xFF) / 255, (float) (argb & 0xFF) / 255, (float) (argb >> 24) / 255, + vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); + + } + }); + } } 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 4b2969f0..36bd58be 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -1,8 +1,8 @@ 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.VertexConsumer; import com.mojang.blaze3d.vertex.VertexFormat; import com.xtracr.realcamera.api.BindResult; import com.xtracr.realcamera.config.BindTarget; @@ -29,54 +29,18 @@ import java.util.List; 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 int planeArgb = 0x6F3333CC, forwardArgb = 0xFF00CC00, upwardArgb = 0xFFCC0000, leftArgb = 0xFF0000CC, focusedArgb = 0x4FFFFFFF; - private static final int z1 = 210, z2 = z1 + 10; +public final class ModelAnalyser { + private static final MultiVertexCatcher vertexCatcher = MultiVertexCatcher.create(); + private static final Set UNFOCUSABLE_RENDER_TYPES = ImmutableSet.of(RenderType.armorEntityGlint(), RenderType.glintTranslucent(), RenderType.glint(), RenderType.entityGlint()); + 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 = GUIHelper.MODEL_MAX_Z + 10, Z_LINE = Z_QUAD + 10; private final List focusedPolyhedron = new ArrayList<>(); - public final PoseStack modelPose = new PoseStack(), texturePose = new PoseStack(); - private 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 BuiltModelRecord focusedRecord; - 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 void initialize(BindTarget target, int modelScale) { - this.target = target; - this.modelScale = modelScale; - modelRecords.clear(); - textureRecords.clear(); - focusedPolyhedron.clear(); - modelPose.setIdentity(); - texturePose.setIdentity(); - 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)) continue; - 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<>(); @@ -102,14 +66,26 @@ public void applyDisableConfigs(String textureId, Set hiddenNames) { } } - public void computeFocusedOnTexture(int mouseX, int mouseY) { + 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() { + 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; - 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; @@ -118,7 +94,7 @@ public void computeFocusedOnTexture(int mouseX, int mouseY) { } } - 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) { @@ -138,7 +114,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) { @@ -206,27 +182,28 @@ public void computeFocusedPolyhedron() { } } } while (added); - 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]); + 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(GuiGraphics graphics) { + public void drawCameraDirections(GuiGraphics graphics, double modelScale) { 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.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(GuiGraphics graphics) { - if (currentRecord == null) return; + public void drawBindTarget(GuiGraphics 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(GuiGraphics graphics) { @@ -234,12 +211,11 @@ public void drawFocusedInModelArea(GuiGraphics graphics) { VertexData[] focused = focusedPolyhedron.get(0); 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)); + GUIHelper.triangleOrQuad(graphics, reversed, Z_QUAD, FOCUSED_ARGB); + focusedPolyhedron.forEach(primitive -> GUIHelper.triangleOrQuad(graphics, primitive, Z_QUAD, FOCUSED_ARGB)); } - public void drawFocusedInTextureArea(GuiGraphics graphics) { - Matrix4f positionMatrix = texturePose.last().pose(); + public void drawFocusedInTextureArea(GuiGraphics graphics, Matrix4f texturePose) { int length = 0; VertexData[] transformed = new VertexData[0], reversed = new VertexData[0]; Vector3f position = new Vector3f(); @@ -251,72 +227,28 @@ public void drawFocusedInTextureArea(GuiGraphics 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.triangleOrQuad(graphics, transformed, 0, focusedArgb); - GUIHelper.triangleOrQuad(graphics, reversed, 0, focusedArgb); - } - } - - public void drawModel(GuiGraphics graphics, PoseStack poseStack) { - poseStack.pushPose(); - poseStack.mulPoseMatrix(modelPose.last().pose().invert(new Matrix4f())); - float minEntityZ = 0f, maxEntityZ = 200f; - for (BuiltModelRecord record : modelRecords) { - for (VertexData vertex : record.vertices()) { - if (vertex.z() < minEntityZ) minEntityZ = vertex.z(); - if (vertex.z() > maxEntityZ) maxEntityZ = vertex.z(); - } + GUIHelper.triangleOrQuad(graphics, transformed, 0, FOCUSED_ARGB); + GUIHelper.triangleOrQuad(graphics, reversed, 0, FOCUSED_ARGB); } - 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); - int argb = vertex.argb(); - buffer.vertex(position.x(), position.y(), 0 , - (float) (argb >> 16 & 0xFF) / 255, (float) (argb >> 8 & 0xFF) / 255, (float) (argb & 0xFF) / 255, (float) (argb >> 24) / 255, - vertex.u(), vertex.v(), vertex.overlay(), vertex.light(), 0, 0, 1); - } - }); - graphics.flush(); } - public void updateModel(Minecraft client, Entity entity, float deltaTick, PoseStack poseStack) { + public List captureModel(Minecraft client, Entity entity, float partialTicks, PoseStack poseStack, BindTarget target) { Lighting.setupForEntityInInventory(); EntityRenderDispatcher dispatcher = client.getEntityRenderDispatcher(); dispatcher.setRenderShadow(false); - MultiVertexCatcher catcher = MultiVertexCatcher.defaultImpl(); - try { - dispatcher.render(entity, 0, 0, 0, 0, deltaTick, poseStack, catcher, 0xF000f0); - catcher.forEachBuffer(this::computeBindResult); - } finally { - catcher.clear(); - dispatcher.setRenderShadow(true); - Lighting.setupFor3DItems(); - } + dispatcher.render(entity, 0, 0, 0, 0, partialTicks, poseStack, vertexCatcher, 0xF000f0); + List records = new ArrayList<>(); + vertexCatcher.forEachBuffer(buf -> computeRecord(buf, records, target)); + vertexCatcher.clear(); + dispatcher.setRenderShadow(true); + Lighting.setupFor3DItems(); + 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; @@ -328,20 +260,18 @@ 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); - if (!builtBuffer.textureId().contains(target.textureId()) || currentRecord != null) return; + records.add(record); + if (!builtBuffer.textureId().contains(target.textureId()) || !bindResult.target.isEmpty()) return; BindResult result = new BindResult(target); - BindTarget.TargetConfig config = target.targetConfig(); + 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.resolvePrimitives(uvs); + 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)); - if (result.weakAvailable()) { - currentRecord = record; - bindResult = result.computeCamera(true); - } + if (result.weakAvailable()) bindResult = result.computeCamera(true); } - private record ZEntry(BuiltModelRecord record, VertexData[] primitive, float z) { } -} + private record ZEntry(BuiltModelRecord record, VertexData[] primitive, float z) { + } +} \ No newline at end of file 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 63bd7eaf..471f7de7 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -3,27 +3,21 @@ 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.mojang.serialization.DataResult; 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.DisableConfig; -import com.xtracr.realcamera.config.ModConfig; -import com.xtracr.realcamera.config.OffsetConfig; -import com.xtracr.realcamera.config.UVRectangle; +import com.xtracr.realcamera.config.*; +import com.xtracr.realcamera.config.BindTarget.BindConfig; +import com.xtracr.realcamera.config.BindTarget.TargetConfig; import com.xtracr.realcamera.config.codec.ConfigCodec; -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 com.xtracr.realcamera.renderer.state.VertexData; import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.*; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -34,6 +28,7 @@ import net.minecraft.client.gui.navigation.CommonInputs; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; @@ -46,14 +41,16 @@ import java.util.*; -public class ModelViewScreen extends Screen { +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; - 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 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 = 80, textureScale = 80, layers = 0, selectionRadius = 10; + private int modelScale = DEFAULT_SCALE, textureScale = DEFAULT_SCALE, layers = 0, selectionRadius = 10; private double modelX, modelY, textureX, textureY, clickedX = -1, clickedY = -1; private float xRot, yRot; private String focusedTextureId; @@ -63,64 +60,76 @@ public 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 NumberWidgetPair offsetXPair, offsetYPair, offsetZPair, offsetPitchPair, offsetYawPair, offsetRollPair; - private List widgetPairs = List.of(); - 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, Minecraft.getInstance().font); + private final EditBox nameField = createTextField(wideWidgetWidth, CONFIG_NAME_MAX_LENGTH); + private final EditBox textureIdField = createTextField(wideWidgetWidth, 1024); + private final EditBox disabledNameField = createTextField(compactWidgetWidth, CONFIG_NAME_MAX_LENGTH); + private final EditBox disabledIdField = createTextField(wideWidgetWidth, 1024); + private final NumberField priorityField = NumberField.ofInt(Minecraft.getInstance().font, widgetWidth - 2, widgetHeight - 2, 0, null); + private final NumberField focusedRectWidgetNumberField = NumberField.ofInt(Minecraft.getInstance().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(i -> 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 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(Minecraft.getInstance().font, "offsetX", compactWidgetWidth, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + private final NumberWidgetPair offsetYPair = new NumberWidgetPair(Minecraft.getInstance().font, "offsetY", compactWidgetWidth, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + private final NumberWidgetPair offsetZPair = new NumberWidgetPair(Minecraft.getInstance().font, "offsetZ", compactWidgetWidth, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); + private final NumberWidgetPair offsetPitchPair = new NumberWidgetPair(Minecraft.getInstance().font, "pitch", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); + private final NumberWidgetPair offsetYawPair = new NumberWidgetPair(Minecraft.getInstance().font, "yaw", compactWidgetWidth, widgetHeight, -180.0f, 180.0f); + private final NumberWidgetPair offsetRollPair = new NumberWidgetPair(Minecraft.getInstance().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), - 1, LocUtil.MODEL_VIEW_WIDGET("upwardVector").withStyle(ChatFormatting.RED), - 2, LocUtil.MODEL_VIEW_WIDGET("position").withStyle(ChatFormatting.BLUE))) - .withInitialValue(0) + 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(i -> 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))) - .withInitialValue(0) + 0, LocUtil.MODEL_VIEW_WIDGET("all").withStyle(ChatFormatting.GREEN), + 1, LocUtil.MODEL_VIEW_WIDGET("part").withStyle(ChatFormatting.BLUE)), 0) .withTooltip(i -> 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))) - .withInitialValue(0) + 0, LocUtil.MODEL_VIEW_WIDGET("single"), + 1, LocUtil.MODEL_VIEW_WIDGET("multiple"), + 2, LocUtil.MODEL_VIEW_WIDGET("range").withStyle(ChatFormatting.BLUE)), 0) .withTooltip(i -> 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"))) - .withInitialValue(0) - .withTooltip(i -> createTooltip("toggleSlider")) + 0, LocUtil.MODEL_VIEW_WIDGET("toggleSliderToField"), + 1, LocUtil.MODEL_VIEW_WIDGET("toggleFieldToSlider")), 0) .displayOnlyValue() - .create(0, 0, widgetWidth * 2 + 4, widgetHeight, LocUtil.MODEL_VIEW_WIDGET("toggleSlider"), (button, i) -> { + .create(0, 0, wideWidgetWidth, widgetHeight, CommonComponents.EMPTY, (button, i) -> { boolean useSlider = i == 0; - widgetPairs.forEach(pair -> pair.syncAndSwitch(useSlider)); + for (NumberWidgetPair pair : widgetPairs) pair.syncAndSwitch(useSlider); 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, LocUtil.MODEL_VIEW_WIDGET("toggleCategory"), (button, i) -> initWidgets(0)); + .create(0, 0, compactWidgetWidth, widgetHeight, CommonComponents.EMPTY, (button, value) -> initWidgets(0)); public ModelViewScreen() { super(LocUtil.MODEL_VIEW_TITLE()); @@ -134,23 +143,12 @@ protected void init() { middleWidth = Math.max(10, xSize - 200); 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; } - private void initOffsetPairs() { - if (offsetXPair != null) return; - offsetXPair = new NumberWidgetPair(font, "offsetX", widgetWidth * 2 - 18, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); - offsetYPair = new NumberWidgetPair(font, "offsetY", widgetWidth * 2 - 18, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); - offsetZPair = new NumberWidgetPair(font, "offsetZ", widgetWidth * 2 - 18, widgetHeight, ModConfig.MIN_OFFSET_F, ModConfig.MAX_OFFSET_F); - offsetPitchPair = new NumberWidgetPair(font, "pitch", widgetWidth * 2 - 18, widgetHeight, -180.0f, 180.0f); - offsetYawPair = new NumberWidgetPair(font, "yaw", widgetWidth * 2 - 18, widgetHeight, -180.0f, 180.0f); - offsetRollPair = new NumberWidgetPair(font, "roll", widgetWidth * 2 - 18, widgetHeight, -180.0f, 180.0f); - widgetPairs = List.of(offsetXPair, offsetYPair, offsetZPair, offsetPitchPair, offsetYawPair, offsetRollPair); - } - private void initWidgets(int page) { this.page = page; if (toggleCategoryButton.getValue() == Category.DISABLE && showTextureButton.getValue() == 0) { @@ -165,10 +163,11 @@ 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 SimpleIconButton(x + (xSize + middleWidth) / 2 - 20, y + 4, 16, 16, 0, 0, button -> { - modelScale = textureScale = 80; + modelScale = textureScale = DEFAULT_SCALE; entityYawSlider.setNumber(0); entityPitchSlider.setNumber(0); modelX = modelY = textureX = textureY = 0; @@ -179,23 +178,6 @@ private void initWidgets(int page) { } private void initLeftWidgets() { - initOffsetPairs(); - rectWidgetsSizeWidget = new StringWidget(x + 4 + widgetWidth + 5, 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(widgetWidth * 2 + 4, 1024, textureIdField); - disabledIdField = createTextField(widgetWidth * 2 + 4, 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); @@ -237,7 +219,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); @@ -248,6 +230,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, button -> deleteFocusedRectWidget()), grid.newCellSettings().padding(5 + widgetWidth - 18, 3, 1, 1)) .setTooltip(createTooltip("deleteSelectedRectangle")); @@ -284,10 +268,10 @@ 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 = NumberField.ofInt(font, widgetWidth - 2, widgetHeight - 2, 0, priorityField), smallSettings).setTooltip(createTooltip("priority")); - nameField = createTextField(widgetWidth * 2 + 4, 20, nameField); + rows.addChild(priorityField, smallSettings).setTooltip(createTooltip("priority")); boolean editableName = toggleCategoryButton.getValue() == Category.CONFIGS; nameField.setEditable(editableName); if (!editableName && nameField.isFocused()) nameField.setFocused(false); @@ -298,14 +282,15 @@ else if (index > 0 && index <= rectWidgets.size()) { } private void initRightWidgets() { - disabledNameField = createTextField(widgetWidth * 2 - 18, 20, disabledNameField); GridLayout grid = new GridLayout(); grid.defaultCellSetting().padding(4, 2, 0, 0); LayoutSettings smallSettings = grid.newCellSettings().padding(5, 3, 1, 1); GridLayout.RowHelper rows = grid.createRowHelper(4); rows.addChild(toggleCategoryButton, 3); rows.addChild(new SimpleIconButton(80, 0, button -> { - if (CompatibilityHelper.isModLoaded("cloth-config")) minecraft.setScreen(ConfigScreen.create(this)); + if (CompatibilityHelper.isModLoaded("cloth-config")) { + minecraft.setScreen(ConfigScreen.create(this)); + } }), smallSettings).setTooltip(createTooltip("toConfigScreen")); final int widgetsPerPage, size; if (toggleCategoryButton.getValue() == Category.DISABLE) { @@ -317,18 +302,18 @@ private void initRightWidgets() { button.setTooltip(createTooltip("saveAs")); initWidgets(page); } - }), smallSettings).setTooltip(createTooltip("saveAs")); + }), smallSettings).setTooltip(createTooltip("saveAs")); 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<>()); + Set hiddenNames = hiddenNameMap.computeIfAbsent(targetName, str -> 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 -> { + .setPosition(x + (xSize + middleWidth) / 2 - 20, y + 5 + (widgetHeight + 2) * (2 + i % widgetsPerPage)); + rows.addChild(createButton(LocUtil.literal(config.name()), compactWidgetWidth, button -> { loadDisableConfig(config); initWidgets(page); }), 3).setTooltip(Tooltip.create(LocUtil.literal(config.name()))); @@ -341,18 +326,19 @@ 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++) { 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), widgetWidth * 2 - 18, button -> loadBindTarget(target)), 3) + rows.addChild(createButton(LocUtil.literal(name), compactWidgetWidth, button -> loadBindTarget(target)), 3) .setTooltip(Tooltip.create(name.equals(RealCameraCore.currentTarget().name()) ? LocUtil.literal(name + "\n").append(LocUtil.MODEL_VIEW_WIDGET("currentConfig")) : - LocUtil.literal(name))); + LocUtil.literal(name)) + ); if (i < fixedTargetCount) continue; rows.addChild(new SimpleIconButton(48, 0, button -> { targetList.remove(target); @@ -367,22 +353,11 @@ 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, 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)); + 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, button -> initWidgets((page + 1) % pages))); } - public @NotNull UVRectangleWidget addRectWidget(@NotNull 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); @@ -393,11 +368,186 @@ public boolean deleteFocusedRectWidget() { return true; } - private boolean syncDisableDraft(AbstractButton button, boolean allowEmptyName) { - String name = disabledNameField.getValue().trim(); - String textureId = disabledIdField.getValue().trim(); + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + this.renderBackground(graphics); + ModelAnalyser analyser = new ModelAnalyser(); + BindTarget target = genBindTarget(); + 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); + 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); + renderFlattenedModels(graphics, analyser, textureRecords); + super.render(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, 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), SELECTION_COLOR); + if (disableModeButton.getValue() == 0) + new UVRectangleWidget(0f, 0f, 1f, 1f).renderWidget(graphics, mouseX, mouseY, partialTicks); + graphics.disableScissor(); + } + } + + @Override + public void renderBackground(GuiGraphics graphics) { + super.renderBackground(graphics); + 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); + } + + private List captureRotatedEntity(ModelAnalyser analyser, BindTarget target, LivingEntity entity) { + CompatibilityHelper.isRenderInScreen = true; + 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.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((x1 + x2) / 2.0f, (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 { + CompatibilityHelper.isRenderInScreen = false; + 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(modelRecords, mouseX - selectionRadius, mouseY - selectionRadius, mouseX + selectionRadius, mouseY + selectionRadius); + if (inTextureViewArea(mouseX, mouseY)) { + Vec2 mouseUV = translateXYToUV(mouseX, mouseY, textureViewArea); + analyser.computeFocusedOnTexture(textureRecords, mouseUV.x, mouseUV.y); + } + 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(GuiGraphics graphics, ModelAnalyser analyser, BindTarget target, List modelRecords) { + GUIHelper.enableScissor(graphics, modelViewArea); + GUIHelper.culledModels(graphics, modelRecords, new Matrix4f()); + if (toggleCategoryButton.getValue() != Category.PREVIEW) analyser.drawFocusedInModelArea(graphics); + if (toggleCategoryButton.getValue() == Category.CONFIGS) analyser.drawBindTarget(graphics, target, modelScale); + else analyser.drawCameraDirections(graphics, modelScale); + graphics.disableScissor(); + } + + private void renderFlattenedModels(GuiGraphics 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; + Vector3f offset = new Vector3f((float) textureX - 0.5f, (float) textureY - 0.5f, 0); + Matrix4f texturePose = new Matrix4f(); + texturePose.translate((x1 + x2) / 2.0f, (y1 + y2) / 2.0f, 0); + texturePose.scale(scale, scale, -scale); + texturePose.translate(offset); + GUIHelper.flattenedModels(graphics, textureRecords, texturePose); + analyser.drawFocusedInTextureArea(graphics, texturePose); + graphics.disableScissor(); + } + + private Vec2 translateUVToXY(float u, float v, ScreenRectangle screenArea) { + 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 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) { + String base64 = minecraft.keyboardHandler.getClipboard().strip(); + DataResult result = ConfigCodec.fromCompressedBase64(base64); + + result.result().ifPresentOrElse(target -> { + loadBindTarget(target); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importSucceeded", LocUtil.literal("'" + target.name() + "'").withStyle(ChatFormatting.WHITE)).withStyle(ChatFormatting.GREEN))); + }, () -> result.error().ifPresent(partialResult -> { + String message = partialResult.message(); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importFailed", message).withStyle(ChatFormatting.RED))); + })); + } + + private void exportBindTarget(Button button) { + BindTarget target = genBindTarget(); + DataResult result = ConfigCodec.toCompressedBase64(target); + + result.result().ifPresentOrElse(base64 -> { + minecraft.keyboardHandler.setClipboard(base64); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportSucceeded").withStyle(ChatFormatting.GREEN))); + }, () -> result.error().ifPresent(partialResult -> { + String message = partialResult.message(); + button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportFailed", message).withStyle(ChatFormatting.RED))); + })); + } + + 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(AbstractButton button, boolean autoName) { + String name = disabledNameField.getValue(); + String textureId = disabledIdField.getValue(); if (name.isBlank()) { - if (!allowEmptyName) { + if (!autoName) { button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("emptyName").withStyle(ChatFormatting.RED))); return false; } @@ -460,18 +610,17 @@ 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; } } - while (builder.length() > 0 && (builder.charAt(builder.length() - 1) == '_' || builder.charAt(builder.length() - 1) == '-')) { + while (!builder.isEmpty() && (builder.charAt(builder.length() - 1) == '_' || builder.charAt(builder.length() - 1) == '-')) builder.deleteCharAt(builder.length() - 1); - } - return builder.length() == 0 ? "disable" : builder.toString(); + return builder.isEmpty() ? "disable" : builder.toString(); } private boolean disableConfigNameExists(String name) { @@ -485,144 +634,7 @@ private void loadAdjacentBindTarget(List fixedTargetList, List= 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); - graphics.disableScissor(); - } - } - - @Override - public void renderBackground(GuiGraphics graphics) { - super.renderBackground(graphics); - 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); - } - - protected void applyAnalyser(GuiGraphics 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); - 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() == Category.CONFIGS || selectionModeButton.getValue() == 1) analyser.computeFocusedPolyhedron(); - focusedPolyhedron = analyser.getFocusedPolyhedron(); - 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) { - 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); - float entityBodyYaw = entity.yBodyRot; - float entityYaw = entity.getYRot(); - float entityPitch = entity.getXRot(); - float entityPrevHeadYaw = entity.yHeadRotO; - float entityHeadYaw = entity.yHeadRot; - try { - entity.yBodyRot = 180.0f; - entity.setYRot(180.0f + (float) entityYawSlider.getNumber()); - entity.setXRot((float) entityPitchSlider.getNumber()); - 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); - } finally { - entity.yBodyRot = entityBodyYaw; - entity.setYRot(entityYaw); - entity.setXRot(entityPitch); - entity.yHeadRotO = entityPrevHeadYaw; - 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.mulPoseMatrix(new Matrix4f().scaling(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 renderTextureViewArea(GuiGraphics 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) { - analyser.texturePose.translate((float) (x1 + x2) / 2.0f, (float) (y1 + y2) / 2.0f, 0); - analyser.texturePose.mulPoseMatrix(new Matrix4f().scaling(scale, scale, -scale)); - analyser.texturePose.translate(offset.x(), offset.y(), offset.z()); - } - - protected void importBindTarget(Button button) { - DataResult result = ConfigCodec.fromCompressedBase64(minecraft.keyboardHandler.getClipboard()); - result.result().ifPresentOrElse(target -> { - loadBindTarget(target); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importSucceeded", LocUtil.literal("'" + target.name() + "'").withStyle(ChatFormatting.WHITE)).withStyle(ChatFormatting.GREEN))); - }, () -> { - String message = result.error().map(error -> error.message()).orElse("Unknown error"); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("importFailed", message).withStyle(ChatFormatting.RED))); - }); - } - - protected void exportBindTarget(Button button) { - DataResult result = ConfigCodec.toCompressedBase64(genBindTarget()); - result.result().ifPresentOrElse(base64 -> { - minecraft.keyboardHandler.setClipboard(base64); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportSucceeded").withStyle(ChatFormatting.GREEN))); - }, () -> { - String message = result.error().map(error -> error.message()).orElse("Unknown error"); - button.setTooltip(Tooltip.create(LocUtil.MODEL_VIEW_TOOLTIP("exportFailed", message).withStyle(ChatFormatting.RED))); - }); - } - - protected void loadBindTarget(BindTarget target) { + private void loadBindTarget(BindTarget target) { if (target.isEmpty()) return; nameField.setValue(target.name()); textureIdField.setValue(target.textureId()); @@ -638,86 +650,81 @@ protected 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()); - initOffsetPairs(); - offsetXPair.setNumber(target.offsets().getX()); - offsetYPair.setNumber(target.offsets().getY()); - offsetZPair.setNumber(target.offsets().getZ()); - offsetPitchPair.setNumber(target.offsets().getPitch()); - offsetYawPair.setNumber(target.offsets().getYaw()); - offsetRollPair.setNumber(target.offsets().getRoll()); + 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(target.disableConfigs()); clearDisableDraft(); } - protected BindTarget genBindTarget() { - initOffsetPairs(); - 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(offsetXPair.getNumber()) - .setY(offsetYPair.getNumber()) - .setZ(offsetZPair.getNumber()) - .setPitch(offsetPitchPair.getNumber()) - .setYaw(offsetYawPair.getNumber()) - .setRoll(offsetRollPair.getNumber()); - return new BindTarget(nameField.getValue(), textureIdField.getValue(), priorityField.getNumber(), depthField.getNumber(), targetConfig, bindConfig, offsets, new ArrayList<>(disableConfigs)); + 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, newDisableConfigs); } - private void clearDisableDraft() { - disabledNameField.setValue(""); - disabledIdField.setValue(""); - disableModeButton.setValue(0); - rectWidgets.clear(); - focusedRectWidget = null; - focusedRectWidgetNumberField.setMax(0); - focusedRectWidgetNumberField.setNumber(0); - rectWidgetsSizeWidget.setMessage(LocUtil.literal("0")); - uMinField.setNumber(0f); - vMinField.setNumber(0f); - uMaxField.setNumber(0f); - vMaxField.setNumber(0f); + private UVRectangleWidget addRectWidget(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; } - 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) { - return new CycleButton.Builder(messages::get).withValues(messages.keySet()); + private CycleButton.Builder createCyclingButtonBuilder(Map messages, T defaultValue) { + return new CycleButton.Builder(messages::get).withInitialValue(defaultValue).withValues(messages.keySet()); } - protected DoubleSlider createSlider(String key, int width, double min, double max) { + @SuppressWarnings("SameParameterValue") + 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) { - 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(Minecraft.getInstance().font, width - 2, widgetHeight - 2, defaultValue, null).setMax(1.0f).setMin(0f); } - protected EditBox createTextField(int width, int maxLength, @Nullable EditBox copyFrom) { - EditBox editBox = new EditBox(font, 0, 0, width - 2, widgetHeight - 2, Component.empty()); + private EditBox createTextField(int width, int maxLength) { + EditBox editBox = new EditBox(Minecraft.getInstance().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) { - return x >= modelViewArea.left() && y >= modelViewArea.top() && x <= modelViewArea.right() && y <= modelViewArea.bottom(); + private boolean inModelViewArea(double x, double y) { + return x >= modelViewArea.left() && x < modelViewArea.right() && y >= modelViewArea.top() && y < modelViewArea.bottom(); } - protected boolean inTextureViewArea(double x, double y) { - return textureViewArea != null && x >= textureViewArea.left() && y >= textureViewArea.top() && x <= textureViewArea.right() && y <= textureViewArea.bottom(); + private boolean inTextureViewArea(double x, double y) { + return textureViewArea != null && x >= textureViewArea.left() && x < textureViewArea.right() && y >= textureViewArea.top() && y < textureViewArea.bottom(); } public boolean leftClickedWithModifier(double mouseX, double mouseY) { @@ -803,7 +810,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } else if (inTextureViewArea(mouseX, mouseY)) { if (super.mouseClicked(mouseX, mouseY, button)) 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, mouseX), yMin = (float) Math.min(storedY, mouseY), xMax = (float) Math.max(storedX, mouseX), yMax = (float) Math.max(storedY, mouseY); setFocused(addRectWidget(new UVRectangleWidget(xMin, yMin, xMax, yMax, textureViewArea))); return true; } @@ -817,11 +824,13 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { @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); - return true; + if (button == InputConstants.MOUSE_BUTTON_LEFT) { + if (!InputConstants.isKeyDown(minecraft.getWindow().getWindow(), modifierKey.getValue())) { + if (inModelViewArea(mouseX, mouseY)) { + xRot += (float) (Math.PI * deltaY / ySize); + yRot -= (float) (Math.PI * deltaX / middleWidth); + return true; + } } } else if (button == InputConstants.MOUSE_BUTTON_RIGHT) { if (inModelViewArea(mouseX, mouseY)) { @@ -846,11 +855,11 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amount) { selectionRadius = Mth.clamp(selectionRadius + (int) amount * 2, 2, 48); else layers = Math.max(0, layers + (int) amount); } else { - modelScale = Mth.clamp(modelScale + (int) amount * modelScale / 16, 16, 1024); + modelScale = Mth.clamp(modelScale + (int) amount * modelScale / 16, MIN_SCALE, MAX_SCALE); } return true; } else if (inTextureViewArea(mouseX, mouseY)) { - textureScale = Mth.clamp(textureScale + (int) amount * textureScale / 16, 16, 1024); + textureScale = Mth.clamp(textureScale + (int) amount * textureScale / 16, MIN_SCALE, MAX_SCALE); } return super.mouseScrolled(mouseX, mouseY, amount); } @@ -869,11 +878,23 @@ public boolean isPauseScreen() { return pauseButton.getValue() == 1; } - public class UVRectangleWidget extends AbstractWidget { - protected float uMin, vMin, uMax, vMax; + private enum Category { + CONFIGS, + PREVIEW, + DISABLE; + + public final String id = name().toLowerCase(); + + public Category next() { + return values()[(ordinal() + 1) % values().length]; + } + } + + private 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, Component.empty()); + super(0, 0, 16, 16, CommonComponents.EMPTY); this.uMin = uMin; this.vMin = vMin; this.uMax = uMax; @@ -881,7 +902,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; @@ -911,36 +932,19 @@ 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 renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float deltaTick) { + protected void renderWidget(GuiGraphics 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); setY((int) y1); setWidth((int) width); - this.height = (int) height; + this.height = ((int) height); 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.outline(graphics, x1, y1, width, height, 0xAAFFFFFF); + 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, OUTLINE_COLOR); graphics.disableScissor(); } @@ -951,7 +955,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (CommonInputs.selected(keyCode) && 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(keyCode, scanCode, modifiers); @@ -971,18 +975,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(@NotNull NarrationElementOutput narrationElementOutput) { } } -} +} \ No newline at end of file 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 a12cba48..f2ce16cb 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 @@ -23,7 +23,7 @@ public double getNumber() { public void setNumber(double value) { this.value = Mth.clamp((value - min) / (max - min), 0, 1); - updateMessage(); + applyValue(); } @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 28a07f83..bfa6fae0 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 @@ -27,14 +27,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()); @@ -71,7 +71,7 @@ public NumberField setOnValueChange(Consumer consumer) { protected void checkText() { super.setTooltip(tooltip); - setTextColor(0xE0E0E0); + setTextColor(EditBox.DEFAULT_TEXT_COLOR); String str = getValue(); if (str.isEmpty()) return; try { @@ -111,27 +111,27 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float del super.renderWidget(graphics, mouseX, mouseY, deltaTick); } - private static 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); + 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 Float getNumberInternal(String str) throws NumberFormatException { - return Float.parseFloat(str); + protected Integer getNumberInternal(String str) throws NumberFormatException { + return Integer.parseInt(str); } } - private static 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); + 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 Integer getNumberInternal(String str) throws NumberFormatException { - return Integer.parseInt(str); + 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 index 0675c4ef..d233fe0a 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 @@ -20,13 +20,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) { @@ -35,10 +39,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()); @@ -101,8 +101,8 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { } @Override - public boolean charTyped(char chr, int modifiers) { - return getActiveWidget().charTyped(chr, modifiers); + public boolean charTyped(char codePoint, int modifiers) { + return getActiveWidget().charTyped(codePoint, modifiers); } @Override 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 9e3a87d4..a8b0bf00 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 @@ -9,8 +9,9 @@ import java.util.function.Consumer; +@SuppressWarnings("removal") public class SimpleIconButton extends AbstractButton { - public static final ResourceLocation ICON_TEXTURE = new ResourceLocation(RealCamera.MODID, "textures/gui/icon.png"); + public static final ResourceLocation ICON_TEXTURE = new ResourceLocation(RealCamera.MOD_ID, "textures/gui/icon.png"); protected final ResourceLocation texture; protected final int textureWidth, textureHeight, u, v; private final Consumer onPress; 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 cf0bf1ae..15c956f4 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java @@ -33,12 +33,12 @@ public abstract class MixinCamera { private float yRot; @Inject(method = "setup", at = @At("RETURN")) - private void realcamera$setupCamera(BlockGetter area, Entity entity, boolean thirdPerson, boolean inverseView, float deltaTick, CallbackInfo ci) { + private void realcamera$setupCamera(BlockGetter blockGetter, Entity entity, boolean bl, boolean bl2, @SuppressWarnings("NameDoesntMatchTargetClass") float deltaTick, CallbackInfo ci) { if (!RealCameraCore.isActive()) return; ModConfig config = ConfigFile.config(); Vec3 startVec = position; AABB box = entity.getBoundingBox(); - 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); @@ -92,5 +92,5 @@ public abstract class MixinCamera { protected abstract void setRotation(float yaw, float pitch); @Shadow - protected abstract void setPosition(Vec3 position); + protected abstract void setPosition(Vec3 vec3); } 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 c47b624f..34af123b 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGameRenderer.java @@ -34,7 +34,7 @@ public abstract class MixinGameRenderer { @ModifyVariable(method = "pick", at = @At("STORE"), ordinal = 0) private EntityHitResult realcamera$modifyEntityHitResult(EntityHitResult entityHitResult) { CrosshairUtil.capturedEntityHitResult = entityHitResult; - if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { Entity cameraEntity = minecraft.getCameraEntity(); Pair fromAndTo = RaycastUtil.getFromAndTo(cameraEntity, minecraft.gameMode.getPickRange() * minecraft.gameMode.getPickRange(), minecraft.getFrameTime()); Vec3 from = fromAndTo.getFirst(); @@ -47,10 +47,10 @@ public abstract class MixinGameRenderer { } @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$atBeforeCameraSetup(float deltaTick, long limitTime, PoseStack poseStack, CallbackInfo ci) { + private void realcamera$atBeforeCameraSetup(float deltaTick, long l, PoseStack poseStack, CallbackInfo ci) { CompatibilityHelper.NEA_setDeltaTick(deltaTick); RealCameraCore.initialize(minecraft); - if (RealCameraCore.isActive() && !ConfigFile.config().isClassic()) { + if (RealCameraCore.isActive() && !ConfigFile.config().isClassic) { EntityRenderDispatcher dispatcher = minecraft.getEntityRenderDispatcher(); dispatcher.prepare(minecraft.level, mainCamera, minecraft.crosshairPickEntity); RealCameraCore.computeCamera(minecraft, deltaTick); 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 e80db273..45f519a3 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinGui.java @@ -14,7 +14,7 @@ public abstract class MixinGui { @Inject(method = "renderCrosshair", at = @At("HEAD")) private void realcamera$atRenderCrosshairHEAD(GuiGraphics guiGraphics, CallbackInfo ci) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { guiGraphics.pose().pushPose(); CrosshairUtil.translateMatrices(guiGraphics.pose()); } @@ -22,7 +22,7 @@ public abstract class MixinGui { @Inject(method = "renderCrosshair", at = @At("RETURN")) private void realcamera$atRenderCrosshairRETURN(GuiGraphics guiGraphics, CallbackInfo ci) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { guiGraphics.pose().popPose(); } } 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 696fe290..675522be 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()) { Pair fromAndTo = RaycastUtil.getFromAndTo(player, 25.0d, 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 cdddea59..3a0d4dbd 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java @@ -24,10 +24,10 @@ public abstract class MixinLevelRenderer { @Final private RenderBuffers renderBuffers; @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;endLastBatch()V", ordinal = 0)) - private void realcamera$renderCameraEntity(PoseStack poseStack, float deltaTick, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) { + private void realcamera$renderCameraEntity(PoseStack poseStack, @SuppressWarnings("NameDoesntMatchTargetClass") float deltaTick, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci) { if (!RealCameraCore.isRendering()) return; MultiBufferSource.BufferSource bufferSource = renderBuffers.bufferSource(); - if (!ConfigFile.config().isClassic()) { + if (!ConfigFile.config().isClassic) { RealCameraCore.renderCameraEntity(minecraft, deltaTick, bufferSource); } else { Vec3 cameraPos = camera.getPosition(); @@ -36,5 +36,5 @@ public abstract class MixinLevelRenderer { } @Shadow - protected abstract void renderEntity(Entity entity, double cameraX, double cameraY, double cameraZ, float deltaTick, PoseStack poseStack, MultiBufferSource bufferSource); + protected abstract void renderEntity(Entity entity, double d, double e, double f, float g, PoseStack poseStack, MultiBufferSource multiBufferSource); } 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 916a4234..4a826741 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLocalPlayer.java @@ -31,7 +31,7 @@ public MixinLocalPlayer(ClientLevel world, GameProfile profile) { @Override public @NotNull HitResult pick(double maxDistance, float deltaTick, boolean includeFluids) { - if (!ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { + if (!ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { Pair fromAndTo = RaycastUtil.getFromAndTo(this, maxDistance * maxDistance, deltaTick); 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/MixinPlayerRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java index a04f7f03..634e99b8 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinPlayerRenderer.java @@ -9,7 +9,7 @@ @Mixin(PlayerRenderer.class) public abstract class MixinPlayerRenderer { @Redirect(method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFF)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)); + private double realcamera$fixVanillaFallFlying(double a) { + return Math.acos(Mth.clamp(a, -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..41f9c7c6 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 = "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()) { + if (livingEntity instanceof LocalPlayer && RealCameraCore.isRendering() && !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 6622f90a..dee97ba7 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/BuiltIterableBuffer.java @@ -12,10 +12,6 @@ public record BuiltIterableBuffer(RenderType renderType, String textureId, IterableVertexBuffer vertexBuffer, PrimitiveLayoutKey primitiveLayoutKey) { - public static BuiltIterableBuffer buildFrom(RenderType renderType, BufferBuilder.RenderedBuffer meshData) { - return buildFrom(renderType, meshData, 0); - } - public static BuiltIterableBuffer buildFrom(RenderType renderType, BufferBuilder.RenderedBuffer meshData, int meshOrdinal) { String textureId = RenderTypeCache.getTextureId(renderType); IterableVertexBuffer vertexBuffer = new IterableVertexBuffer(meshData); @@ -25,16 +21,6 @@ public static BuiltIterableBuffer buildFrom(RenderType renderType, BufferBuilder return new BuiltIterableBuffer(renderType, textureId, vertexBuffer, primitiveLayoutKey); } - public boolean anyNotCached(UV[] uvs) { - Object2IntMap cache = RenderTypeCache.getPrimitiveCache(primitiveLayoutKey); - if (cache == null) return true; - for (UV uv : uvs) { - if (uv == null) continue; - if (cache.getInt(uv) == -1) return true; - } - return false; - } - public VertexData[] @Nullable [] findPrimitivesInCache(UV[] uvs) { Object2IntMap cache = RenderTypeCache.getPrimitiveCache(primitiveLayoutKey); int uvsLength = uvs.length; @@ -43,33 +29,15 @@ public boolean anyNotCached(UV[] uvs) { for (int i = 0; i < uvsLength; i++) { if (uvs[i] == null) continue; int primitiveIndex = cache.getInt(uvs[i]); - if (primitiveIndex == -1) continue; - VertexData[] primitive; - try { - primitive = vertexBuffer.readPrimitiveAt(primitiveIndex); - } catch (IndexOutOfBoundsException ignored) { - return invalidatePrimitiveCache(uvsLength); - } - if (!VertexData.containsUV(primitive, uvs[i].u(), uvs[i].v())) return invalidatePrimitiveCache(uvsLength); + 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; } return primitives; } - public VertexData[] @Nullable [] resolvePrimitives(UV[] uvs) { - VertexData[][] primitives = findPrimitivesInCache(uvs); - if (!anyNotCached(uvs)) return primitives; - UV[] missingUVs = uvs.clone(); - for (int i = 0; i < primitives.length; i++) { - if (primitives[i] != null) missingUVs[i] = null; - } - VertexData[][] resolvedPrimitives = findPrimitives(missingUVs); - for (int i = 0; i < primitives.length; i++) { - if (resolvedPrimitives[i] != null) primitives[i] = resolvedPrimitives[i]; - } - return primitives; - } - + @SuppressWarnings("ResultOfMethodCallIgnored") public VertexData[] @Nullable [] findPrimitives(UV[] uvs) { int uvsLength = uvs.length; VertexData[][] primitives = new VertexData[uvsLength][]; @@ -92,9 +60,4 @@ public boolean anyNotCached(UV[] uvs) { }); return primitives; } - - private VertexData[][] invalidatePrimitiveCache(int uvsLength) { - RenderTypeCache.invalidatePrimitiveCache(primitiveLayoutKey); - return new VertexData[uvsLength][]; - } } 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 3f996134..c9e6be43 100644 --- a/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java +++ b/common/src/main/java/com/xtracr/realcamera/renderer/MultiVertexCatcher.java @@ -57,7 +57,7 @@ protected MeshCatcher() { } @Override - protected @NotNull BufferBuilder getBuilderRaw(RenderType renderType) { + public @NotNull BufferBuilder getBuilderRaw(RenderType renderType) { return bufferPools.computeIfAbsent(renderType, type -> new BufferBuilderPool(type.bufferSize())).getBuffer(); } diff --git a/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java b/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java index 84dd7416..8009ce19 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java +++ b/common/src/main/java/com/xtracr/realcamera/util/CameraTransform.java @@ -26,8 +26,8 @@ public final void setRotation(Matrix3fc mat) { rotation.set(mat); } - public final void lerpPosition(Vec3 vec, double alpha) { - position = position.lerp(vec, alpha); + public final void lerpPosition(Vec3 vec, double a) { + position = position.lerp(vec, a); } public final void slerpRotation(Matrix3fc mat, double alpha) { 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..0eef1561 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/CrosshairUtil.java @@ -2,28 +2,27 @@ 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.Matrix4fc; -public class CrosshairUtil { +public final 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); + poseStack.translate((float) offset.x, (float) -offset.y, 0f); } - 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/LocUtil.java b/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java index ab6dab6c..3b0b14b8 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/LocUtil.java @@ -6,7 +6,6 @@ public final class LocUtil { public static final String KEY_MOD_NAME = "general." + RealCamera.FULL_ID + ".modName"; - public static final String KEY_CATEGORY_GENERAL = "key.category." + RealCamera.FULL_ID + ".general"; public static MutableComponent MOD_NAME() { return Component.translatable(KEY_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 3076c983..0e1b120e 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/MathUtil.java @@ -10,24 +10,6 @@ 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 d1, double d2) { - return Math.floor(Math.min(d1, d2)); - } - - 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) { return a * d - b * c; } @@ -45,11 +27,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, x0, y0, 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, x0, y0, x2, y2, x3, y3); } public static Vec3 getEulerAngleYXZ(Matrix3f normal) { 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 cdddcc90..5d153447 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java +++ b/common/src/main/java/com/xtracr/realcamera/util/RaycastUtil.java @@ -7,6 +7,11 @@ import net.minecraft.world.phys.Vec3; public final class RaycastUtil { + /** + * 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 deltaTick) { Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera(); Vec3 eyePos = entity.getEyePosition(deltaTick); diff --git a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java index da26def9..625c8caf 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java +++ b/common/src/main/java/com/xtracr/realcamera/util/RenderTypeCache.java @@ -41,17 +41,13 @@ public static void cachePrimitive(PrimitiveLayoutKey layoutKey, UV uv, int primi PRIMITIVE_CACHE.getUnchecked(layoutKey).put(uv, primitiveIndex); } - public static void invalidatePrimitiveCache(PrimitiveLayoutKey layoutKey) { - PRIMITIVE_CACHE.invalidate(layoutKey); - } - private static class TextureIdCacheLoader extends CacheLoader { @Override public @NotNull String load(@NotNull RenderType renderType) { try { - RenderType.CompositeState state = ((CompositeRenderTypeAccessor) (Object) renderType).invokeState(); - RenderStateShard.EmptyTextureStateShard textureState = ((CompositeStateAccessor) (Object) state).getTextureState(); - Optional textureId = ((EmptyTextureStateShardAccessor) (Object) textureState).invokeCutoutTexture(); + RenderType.CompositeState state = ((CompositeRenderTypeAccessor) renderType).invokeState(); + @SuppressWarnings("DataFlowIssue") RenderStateShard.EmptyTextureStateShard textureState = ((CompositeStateAccessor) (Object) state).getTextureState(); + Optional textureId = ((EmptyTextureStateShardAccessor) textureState).invokeCutoutTexture(); if (textureId.isPresent()) return textureId.get().toString(); } catch (ClassCastException | NullPointerException ignored) { } 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..50fd10fe 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -14,21 +14,20 @@ "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", - "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", @@ -50,10 +49,9 @@ "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", "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", @@ -61,12 +59,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..b5f22c3d 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -14,21 +14,20 @@ "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": "渲染卡在身上的物体", - "config.option.xtracr_realcamera.rerenderModel": "重新渲染模型", "config.option.xtracr_realcamera.roll": "翻滚角", "config.option.xtracr_realcamera.rotationSmoothFactor": "旋转平滑系数", "config.option.xtracr_realcamera.scale": "缩放比例", @@ -50,10 +49,9 @@ "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": "在原本的渲染时机重新渲染模型,以避免一些因提前渲染导致的视觉问题", "config.tooltip.xtracr_realcamera.rotationSmoothFactor": "相机旋转平滑系数,值越大越平滑", "config.tooltip.xtracr_realcamera.scale": "控制偏移量的大小", "general.xtracr_realcamera.modName": "Real Camera", @@ -61,12 +59,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": "切换摄像头模式", diff --git a/common/src/main/resources/realcamera-common.mixins.json b/common/src/main/resources/realcamera-common.mixins.json index a853b9c0..e550d9f7 100644 --- a/common/src/main/resources/realcamera-common.mixins.json +++ b/common/src/main/resources/realcamera-common.mixins.json @@ -27,5 +27,6 @@ ], "injectors": { "defaultRequire": 1 - } + }, + "refmap": "realcamera-common.refmap.json" } diff --git a/fabric/build.gradle b/fabric/build.gradle deleted file mode 100644 index 6e67a066..00000000 --- a/fabric/build.gradle +++ /dev/null @@ -1,70 +0,0 @@ -plugins { - id "com.github.johnrengelman.shadow" version "8.1.1" -} - -archivesBaseName = rootProject.archives_base_name + "-" + 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..673fea80 --- /dev/null +++ b/fabric/build.gradle.kts @@ -0,0 +1,103 @@ +plugins { + id("net.fabricmc.fabric-loom-remap") + 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") + mappings(loom.officialMojangMappings()) + + modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") + modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") + + // Cloth Config + modRuntimeOnly("me.shedaniel.cloth:cloth-config-fabric:$clothConfigVersion") + // Modmenu + modImplementation("com.terraformersmc:modmenu:$modMenuVersion") { + exclude(group = "net.fabricmc.fabric-api") + } + + implementation(commonProject.sourceSets.main.get().output) +} + +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 index 6f9d84f5..f83ebbd1 100644 --- a/fabric/src/main/java/com/xtracr/realcamera/EventHandler.java +++ b/fabric/src/main/java/com/xtracr/realcamera/EventHandler.java @@ -7,8 +7,8 @@ public class EventHandler { public static void onWorldRenderStart(WorldRenderContext context) { - if (ConfigFile.config().dynamicCrosshair() && RealCameraCore.isActive()) { - CrosshairUtil.update(Minecraft.getInstance(), context.camera(), context.matrixStack().last().pose(), context.projectionMatrix()); + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { + CrosshairUtil.update(Minecraft.getInstance(), context.camera().getPosition(), context.matrixStack().last().pose(), context.projectionMatrix()); } } } diff --git a/fabric/src/main/java/com/xtracr/realcamera/mixin/GameRendererEvents.java b/fabric/src/main/java/com/xtracr/realcamera/mixin/GameRendererEvents.java index dbfe36db..61ebca2c 100644 --- a/fabric/src/main/java/com/xtracr/realcamera/mixin/GameRendererEvents.java +++ b/fabric/src/main/java/com/xtracr/realcamera/mixin/GameRendererEvents.java @@ -12,7 +12,7 @@ @Mixin(GameRenderer.class) public abstract class GameRendererEvents { @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", shift = At.Shift.AFTER)) - private void realcamera$onAfterCameraUpdate(float tickDelta, long limitTime, PoseStack poseStack, CallbackInfo cInfo) { + private void realcamera$onAfterCameraUpdate(float f, long l, PoseStack poseStack, CallbackInfo cInfo) { if (RealCameraCore.isActive()) { poseStack.mulPose(Axis.ZP.rotationDegrees(RealCameraCore.getRoll(0))); } diff --git a/forge/.gitignore b/forge/.gitignore new file mode 100644 index 00000000..a14cdf7f --- /dev/null +++ b/forge/.gitignore @@ -0,0 +1 @@ +!libs/ \ No newline at end of file diff --git a/forge/build.gradle b/forge/build.gradle deleted file mode 100644 index 1f7c9612..00000000 --- a/forge/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -plugins { - id "com.github.johnrengelman.shadow" version "8.1.1" -} - -archivesBaseName = rootProject.archives_base_name + "-" + rootProject.minecraft_version + "-forge" - -architectury { - platformSetupLoomIde() - forge() -} - -loom { - forge { - convertAccessWideners = true - extraAccessWideners.add loom.accessWidenerPath.get().asFile.name - mixinConfig "realcamera-common.mixins.json" - mixinConfig "realcamera.mixins.json" - } -} - -configurations { - common - shadowCommon - compileClasspath.extendsFrom common - runtimeClasspath.extendsFrom common - developmentForge.extendsFrom common -} - -dependencies { - forge "net.minecraftforge:forge:${rootProject.forge_version}" - - // Cloth Config - modRuntimeOnly "me.shedaniel.cloth:cloth-config-forge:${rootProject.cloth_config_version}" - - common(project(path: ":common", configuration: "namedElements")) { transitive false } - shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive false } -} - -processResources { - inputs.property "version", project.version - filesMatching("META-INF/mods.toml") { - expand "version": project.version - } -} - -shadowJar { - exclude "fabric.mod.json" - exclude "architectury.common.json" - configurations = [project.configurations.shadowCommon] - archiveClassifier = "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/forge/build.gradle.kts b/forge/build.gradle.kts new file mode 100644 index 00000000..ce6c4ac6 --- /dev/null +++ b/forge/build.gradle.kts @@ -0,0 +1,251 @@ +buildscript { + repositories { mavenCentral() } + dependencies { classpath("org.ow2.asm:asm:9.5") } +} + +plugins { + id("java-library") + id("net.minecraftforge.gradle") + id("net.minecraftforge.renamer") + 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 forgeVersion = project.property("forge_version") as String + +val clothConfigVersion = project.property("cloth_config_version") as String + +val mapFile = file("libs/mappings_official-1.20.1-20230612.114412-map2srg.tsrg.gz") +renamer.mappings.setFrom(mapFile) + +base { + archivesName = "$modId-$minecraftVersion-forge" +} + +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 { + implementation(minecraft.dependency("net.minecraftforge:forge:$forgeVersion")) + compileOnly("org.spongepowered:mixin:0.8.5") + compileOnly("io.github.llamalad7:mixinextras-forge:0.5.0") + annotationProcessor("io.github.llamalad7:mixinextras-forge:0.5.0") + + // Cloth Config + implementation(renamer.dependency("me.shedaniel.cloth:cloth-config-forge:$clothConfigVersion")) + + implementation(commonProject.sourceSets.main.get().output) +} + +configurations.named("annotationProcessor") { + extendsFrom(configurations.named("implementation").get()) +} + +// Merge mappings from TSRG into the refmap. +// Multi-module Mixin AP combined with Forge's SRG mappings necessitates these workarounds. +// If FG7 resolves these issues in the future, they may no longer be needed +tasks.named("compileJava", JavaCompile::class).configure { + doLast { + val tsrg = layout.buildDirectory.file("tmp/compileJava/compileJava-mappings.tsrg").get().asFile + val refmap = layout.buildDirectory.file("tmp/compileJava/compileJava-refmap.json").get().asFile + if (!tsrg.exists() || !refmap.exists()) return@doLast + val lines = tsrg.readLines().map { it.trim().split(" ") } + val fieldsByClass = mutableMapOf>() + lines.filter { it.size == 3 && "(" !in it.joinToString() } + .forEach { fieldsByClass.getOrPut(it[0]) { mutableMapOf() }[it[1]] = it[2] } + val methodsByClass = mutableMapOf>() + lines.filter { it.size == 4 } + .forEach { methodsByClass.getOrPut(it[0]) { mutableMapOf() }[it[1]] = it[3] } + if (fieldsByClass.isEmpty() && methodsByClass.isEmpty()) return@doLast + var text = refmap.readText() + val allClasses = (fieldsByClass.keys + methodsByClass.keys).toSet() + + fun buildInsert(fields: Map, methods: Map): String { + val entries = mutableListOf() + fields.forEach { (name, srg) -> entries.add(""""$name": "$srg"""") } + methods.forEach { (name, srg) -> entries.add(""""$name": "$srg"""") } + return entries.joinToString(",\n") + } + + allClasses.forEach { cls -> + val fields = fieldsByClass[cls] ?: emptyMap() + val methods = methodsByClass[cls] ?: emptyMap() + val insert = buildInsert(fields, methods) + if (insert.isEmpty()) return@forEach + text = text.replace(Regex(""""\Q$cls\E":\s*\{""")) { "${it.value}\n$insert," } + } + + val seargeKey = """"searge": {""" + val seargeIdx = text.indexOf(seargeKey) + if (seargeIdx >= 0) { + allClasses.forEach { cls -> + val seargeSection = text.substring(seargeIdx) + if (!seargeSection.contains(""""$cls":""")) { + val fields = fieldsByClass[cls] ?: emptyMap() + val methods = methodsByClass[cls] ?: emptyMap() + val entries = mutableListOf() + fields.forEach { (name, srg) -> entries.add(""""$name": "$srg"""") } + methods.forEach { (name, srg) -> entries.add(""""$name": "$srg"""") } + if (entries.isNotEmpty()) { + val newEntry = """"$cls": {${entries.joinToString(",\n")}},""" + text = text.substring(0, seargeIdx + seargeKey.length) + newEntry + text.substring(seargeIdx + seargeKey.length) + } + } + } + } + refmap.writeText(text) + } +} + +// Never use Forge for debugging modifications unless absolutely necessary!!! +minecraft { + mavenizer(repositories) + mappings("official", minecraftVersion) + useDefaultAccessTransformer() + accessTransformers.setFrom(file("src/main/resources/META-INF/accesstransformer.cfg")) + + runs { + configureEach { + workingDir.convention(layout.projectDirectory.dir("run")) + //systemProperty("forge.logging.console.level", "debug") + systemProperty("eventbus.api.strictRuntimeChecks", "true") + } + register("client") { + systemProperty("forge.enabledGameTestNamespaces", modId) + workingDir.convention(layout.projectDirectory.dir("run/client")) + } + register("server") { + systemProperty("forge.enabledGameTestNamespaces", modId) + workingDir.convention(layout.projectDirectory.dir("run/server")) + args("--nogui") + } + } +} + +sourceSets.named("main") { + java { srcDir(commonProject.sourceSets.main.get().java.srcDirs) } + resources { srcDir(commonProject.sourceSets.main.get().resources.srcDirs) } +} + +tasks.named("processResources") { + inputs.property("version", project.version) + filesMatching("META-INF/mods.toml") { + expand("version" to project.version) + } +} + +tasks.named("build") { + dependsOn(tasks.named("renameJar")) +} + +tasks.named("assemble") { + dependsOn(tasks.named("renameJar")) +} + +tasks.named("jar") { + from(sourceSets.main.get().output) + from(commonProject.sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + doFirst { + // Same root cause as above — fixes the same category of issue, but not the same problem. + // Rename @Shadow fields/methods in compiled classes to SRG names via ASM + val tsrg = layout.buildDirectory.file("tmp/compileJava/compileJava-mappings.tsrg").get().asFile + if (!tsrg.exists()) return@doFirst + val lines = tsrg.readLines().map { it.trim().split(" ") } + val fieldRenames = mutableMapOf>() + val methodRenames = mutableMapOf>>() + for (parts in lines) { + when (parts.size) { + 3 if "(" !in parts.joinToString() -> fieldRenames.getOrPut(parts[0]) { mutableMapOf() }[parts[1]] = parts[2] + 4 -> methodRenames.getOrPut(parts[0]) { mutableMapOf() } + .getOrPut(parts[1]) { mutableMapOf() }[parts[2]] = parts[3] + } + } + for (cls in (fieldRenames.keys + methodRenames.keys)) { + val classFile = File(tasks.named("compileJava").get().destinationDirectory.get().asFile, "$cls.class") + if (!classFile.exists()) continue + val fMap = fieldRenames[cls] ?: emptyMap() + val mMap = methodRenames[cls] ?: emptyMap() + val cr = org.objectweb.asm.ClassReader(classFile.readBytes()) + val cw = org.objectweb.asm.ClassWriter(cr, org.objectweb.asm.ClassWriter.COMPUTE_MAXS) + cr.accept(object : org.objectweb.asm.ClassVisitor(org.objectweb.asm.Opcodes.ASM9, cw) { + override fun visitField(acc: Int, name: String, desc: String, sig: String?, value: Any?) = + super.visitField(acc, fMap[name] ?: name, desc, sig, value) + override fun visitMethod(acc: Int, name: String, desc: String, sig: String?, exs: Array?): org.objectweb.asm.MethodVisitor { + val dMap = mMap[name] ?: emptyMap() + val mv = super.visitMethod(acc, dMap[desc] ?: name, desc, sig, exs) + return object : org.objectweb.asm.MethodVisitor(org.objectweb.asm.Opcodes.ASM9, mv) { + override fun visitFieldInsn(op: Int, owner: String, name: String, desc: String) = + super.visitFieldInsn(op, owner, fMap[name] ?: name, desc) + override fun visitMethodInsn(op: Int, owner: String, name: String, desc: String, itf: Boolean) { + val dm = mMap[name] ?: emptyMap() + super.visitMethodInsn(op, owner, dm[desc] ?: name, desc, itf) + } + } + } + }, 0) + classFile.writeBytes(cw.toByteArray()) + } + } +} + +renamer.classes(tasks.named("jar", Jar::class)) { + archiveClassifier.set("renamed") + accessTransformers.set(true) +} + +tasks.named("renameJar") { + doLast { + // Replace the original jar with the renamed jar and delete the renamed file. + val jarTask = tasks.named("jar").get() + val jarFile = jarTask.archiveFile.get().asFile + val renamedFile = File(jarFile.parentFile, jarFile.name.replace(".jar", "-renamed.jar")) + if (renamedFile.exists()) { + renamedFile.copyTo(jarFile, overwrite = true) + renamedFile.delete() + } + } +} + +renamer.enableMixinRefmaps { + config("realcamera-common.mixins.json") + refMap.set("realcamera-common.refmap.json") +} + +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.named("jar")) + archives(sourcesJarTask) +} + +publishing { + publications { + register("forgeJar") { + artifactId = base.archivesName.get() + artifact(tasks.named("jar")) + artifact(sourcesJarTask) + } + } +} \ No newline at end of file diff --git a/forge/libs/mappings_official-1.20.1-20230612.114412-map2srg.tsrg.gz b/forge/libs/mappings_official-1.20.1-20230612.114412-map2srg.tsrg.gz new file mode 100644 index 00000000..89ed94d3 Binary files /dev/null and b/forge/libs/mappings_official-1.20.1-20230612.114412-map2srg.tsrg.gz differ diff --git a/forge/src/main/java/com/xtracr/realcamera/EventHandler.java b/forge/src/main/java/com/xtracr/realcamera/EventHandler.java index d0c5b487..4a1f4947 100644 --- a/forge/src/main/java/com/xtracr/realcamera/EventHandler.java +++ b/forge/src/main/java/com/xtracr/realcamera/EventHandler.java @@ -20,8 +20,8 @@ public static void onCameraSetup(ViewportEvent.ComputeCameraAngles event) { 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.getPoseStack().last().pose(), event.getProjectionMatrix()); + if (ConfigFile.config().dynamicCrosshair && RealCameraCore.isActive()) { + CrosshairUtil.update(Minecraft.getInstance(), event.getCamera().getPosition(), event.getPoseStack().last().pose(), event.getProjectionMatrix()); } } } diff --git a/forge/src/main/java/com/xtracr/realcamera/RealCameraForge.java b/forge/src/main/java/com/xtracr/realcamera/RealCameraForge.java index c18ed323..8235897f 100644 --- a/forge/src/main/java/com/xtracr/realcamera/RealCameraForge.java +++ b/forge/src/main/java/com/xtracr/realcamera/RealCameraForge.java @@ -14,7 +14,8 @@ import java.util.Map; -@Mod(RealCamera.MODID) +@SuppressWarnings("removal") +@Mod(RealCamera.MOD_ID) public class RealCameraForge implements RealCamera { private final Map modIdMap = Map.of("cloth-config", "cloth_config"); diff --git a/forge/src/main/resources/META-INF/accesstransformer.cfg b/forge/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..5200bebe --- /dev/null +++ b/forge/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,7 @@ +public net.minecraft.client.renderer.MultiBufferSource$BufferSource getBuilderRaw(Lnet/minecraft/client/renderer/RenderType;)Lcom/mojang/blaze3d/vertex/BufferBuilder; +public net.minecraft.client.renderer.RenderType$CompositeRenderType +public net.minecraft.client.renderer.RenderType$CompositeState +public net.minecraft.client.renderer.RenderStateShard$EmptyTextureStateShard +public net.minecraft.client.renderer.RenderType$CompositeRenderType state()Lnet/minecraft/client/renderer/RenderType$CompositeState; +public net.minecraft.client.renderer.RenderType$CompositeState textureState +public net.minecraft.client.renderer.RenderStateShard$EmptyTextureStateShard cutoutTexture()Ljava/util/Optional; \ No newline at end of file diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 3a8a31fb..9f983c98 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -11,7 +11,7 @@ logoFile = "icon.png" credits = "" authors = "xTracr" # Display Test controls the display for your mod in the server connection screen -# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. +# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behavior and should be what you choose if you have server and client elements to your mod. # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. # IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. # NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. diff --git a/gradle.properties b/gradle.properties index a98c0b66..c8cd5c3c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,18 +1,22 @@ -# 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.caching=true -# Loader Properties +org.gradle.configuration-cache=false +## Environment Properties +java_version=21 minecraft_version=1.20.1 enabled_platforms=fabric,forge -forge_version=1.20.1-47.3.1 -fabric_loader_version=0.15.10 -#yarn_mappings=1.20.1+build.10 -# Mod Properties -mod_version=0.7.8-beta -maven_group=com.xtracr.realcamera -archives_base_name=realcamera -# Dependencies +loom_version=1.17-SNAPSHOT +fabric_loader_version=0.19.3 +forge_version=1.20.1-47.4.22 +forge_gradle_version=[7.0.29, 8.0) +forge_renamer_version=1.1.7 +moddev_version=2.0.141 +## Mod Properties +mod_id=realcamera +mod_version=0.7.9-beta +mod_group_id=com.xtracr.realcamera +## Dependencies fabric_api_version=0.92.2+1.20.1 cloth_config_version=11.1.118 modmenu_version=7.2.2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975c..b1b8ef56 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ca025c83..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-8.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf93008..249efbb0 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. @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -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/3d91ce3b8caaf77ad09f381f43615b715b53f72c/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/. @@ -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..a51ec4f5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,12 +19,12 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,30 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :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 %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 1da00016..00000000 --- a/settings.gradle +++ /dev/null @@ -1,14 +0,0 @@ -pluginManagement { - repositories { - maven { url "https://maven.fabricmc.net/" } - maven { url "https://maven.architectury.dev/" } - maven { url "https://maven.minecraftforge.net/" } - gradlePluginPortal() - } -} - -include("common") -include("fabric") -include("forge") - -rootProject.name = "RealCamera" diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..9dc39e86 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,34 @@ +pluginManagement { + repositories { + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + maven { + name = "Forge" + url = uri("https://maven.minecraftforge.net/") + } + maven { + name = "Minecraft" + url = uri("https://libraries.minecraft.net/") + } + gradlePluginPortal() + } + + plugins { + id("net.fabricmc.fabric-loom") version providers.gradleProperty("loom_version") + id("net.fabricmc.fabric-loom-remap") version providers.gradleProperty("loom_version") + id("net.minecraftforge.gradle") version providers.gradleProperty("forge_gradle_version") + id("net.minecraftforge.renamer") version providers.gradleProperty("forge_renamer_version") + } +} + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + +rootProject.name = "RealCamera" + +include("common") +include("fabric") +include("forge")