├── .gitattributes ├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── 1.png ├── 2.png ├── 3.png ├── 4.png └── logo.png ├── nbtedit-common ├── build.gradle └── src │ ├── generated │ └── resources │ │ ├── .cache │ │ ├── 389e3a88cd1a087f6956d4058ad04dba575e640f │ │ └── 94e5143f2f45998e4eef93f35114a94d6661df8d │ │ └── assets │ │ └── nbtedit │ │ └── lang │ │ ├── en_us.json │ │ └── zh_cn.json │ └── main │ ├── java │ └── cx │ │ └── rain │ │ └── mc │ │ └── nbtedit │ │ ├── NBTEdit.java │ │ ├── NBTEditPlatform.java │ │ ├── api │ │ ├── command │ │ │ ├── IModPermission.java │ │ │ └── ModPermissions.java │ │ ├── config │ │ │ └── IModConfig.java │ │ └── netowrking │ │ │ └── IModNetworking.java │ │ ├── command │ │ └── NBTEditCommand.java │ │ ├── editor │ │ ├── AccessibilityHelper.java │ │ ├── ClipboardHelper.java │ │ ├── EditorButton.java │ │ ├── EditorHelper.java │ │ ├── NbtTree.java │ │ ├── NbtType.java │ │ ├── NodeParser.java │ │ ├── NodeSortHelper.java │ │ └── TagReadingHelper.java │ │ ├── gui │ │ ├── EditorScreen.java │ │ ├── component │ │ │ ├── AbstractComponent.java │ │ │ ├── AbstractComposedComponent.java │ │ │ ├── ButtonComponent.java │ │ │ ├── EditBoxComponent.java │ │ │ ├── IComponent.java │ │ │ ├── IComposedComponent.java │ │ │ ├── IScrollHandler.java │ │ │ ├── ScrollBar.java │ │ │ └── ScrollableViewport.java │ │ ├── editor │ │ │ ├── EditingWindow.java │ │ │ ├── EditorButtonComponent.java │ │ │ ├── NbtTreeView.java │ │ │ └── NbtTreeViewNode.java │ │ ├── screen │ │ │ └── AbstractScreen.java │ │ └── window │ │ │ ├── AbstractWindow.java │ │ │ ├── IWindow.java │ │ │ └── IWindowHolder.java │ │ ├── networking │ │ ├── NetworkClientHandler.java │ │ ├── NetworkEditingHelper.java │ │ ├── NetworkServerHandler.java │ │ ├── NetworkingConstants.java │ │ ├── NetworkingHelper.java │ │ └── packet │ │ │ ├── c2s │ │ │ ├── BlockEntityRaytraceResultPacket.java │ │ │ ├── EntityRaytraceResultPacket.java │ │ │ └── ItemStackRaytraceResultPacket.java │ │ │ ├── common │ │ │ ├── BlockEntityEditingPacket.java │ │ │ ├── EntityEditingPacket.java │ │ │ └── ItemStackEditingPacket.java │ │ │ └── s2c │ │ │ └── RaytracePacket.java │ │ └── utility │ │ ├── ModConstants.java │ │ ├── RayTraceHelper.java │ │ └── ScreenHelper.java │ └── resources │ ├── assets │ └── nbtedit │ │ └── textures │ │ └── gui │ │ └── sprites │ │ ├── editor │ │ ├── arrow_down.png │ │ ├── arrow_down_highlighted.png │ │ ├── arrow_right.png │ │ ├── arrow_right_highlighted.png │ │ ├── copy.png │ │ ├── cut.png │ │ ├── delete.png │ │ ├── edit.png │ │ └── paste.png │ │ ├── tag_type │ │ ├── byte.png │ │ ├── byte_array.png │ │ ├── compound.png │ │ ├── double.png │ │ ├── float.png │ │ ├── int.png │ │ ├── int_array.png │ │ ├── list.png │ │ ├── long.png │ │ ├── long_array.png │ │ ├── short.png │ │ └── string.png │ │ └── window.png │ ├── build_info.properties │ ├── logo.png │ └── nbtedit.accesswidener ├── nbtedit-fabric ├── build.gradle └── src │ └── main │ ├── java │ └── cx │ │ └── rain │ │ └── mc │ │ └── nbtedit │ │ └── fabric │ │ ├── NBTEditFabric.java │ │ ├── NBTEditFabricClient.java │ │ ├── NBTEditPlatformImpl.java │ │ ├── command │ │ ├── FabricPermissionApiImpl.java │ │ └── VanillaPermissionImpl.java │ │ ├── config │ │ ├── ConfigBean.java │ │ └── ModConfigImpl.java │ │ └── networking │ │ ├── ModNetworkingImpl.java │ │ ├── NBTEditNetworkingClient.java │ │ └── NBTEditNetworkingServer.java │ └── resources │ ├── fabric.mod.json │ └── logo-fabric.png ├── nbtedit-forge ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── java │ └── cx │ │ └── rain │ │ └── mc │ │ └── nbtedit │ │ └── forge │ │ ├── NBTEditForge.java │ │ ├── NBTEditPlatformImpl.java │ │ ├── command │ │ ├── ModPermissionImpl.java │ │ └── NBTEditCommandRegister.java │ │ ├── config │ │ └── ModConfigImpl.java │ │ ├── keybinding │ │ ├── NBTEditKeyBindings.java │ │ └── OnNBTEditShortcut.java │ │ └── networking │ │ └── ModNetworkingImpl.java │ └── resources │ ├── META-INF │ └── mods.toml │ ├── logo-forge.png │ └── pack.mcmeta ├── nbtedit-neoforge ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── java │ └── cx │ │ └── rain │ │ └── mc │ │ └── nbtedit │ │ └── neoforge │ │ ├── NBTEditNeoForge.java │ │ ├── NBTEditPlatformImpl.java │ │ ├── command │ │ ├── ModPermissionImpl.java │ │ └── NBTEditCommandRegister.java │ │ ├── config │ │ └── ModConfigImpl.java │ │ ├── data │ │ ├── DataGen.java │ │ └── provider │ │ │ ├── LanguageProviderENUS.java │ │ │ └── LanguageProviderZHCN.java │ │ ├── keybinding │ │ ├── NBTEditKeyBindings.java │ │ └── OnNBTEditShortcut.java │ │ └── networking │ │ └── ModNetworkingImpl.java │ └── resources │ ├── META-INF │ └── neoforge.mods.toml │ ├── logo-neoforge.png │ └── pack.mcmeta └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable autocrlf on generated files, they always generate with LF 2 | # Add any extra files or paths here to make git stop saying they 3 | # are changed when only line endings change. 4 | src/generated/**/.cache/cache text eol=lf 5 | src/generated/**/*.json text eol=lf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea 15 | 16 | # gradle 17 | build 18 | .gradle 19 | 20 | # other 21 | eclipse 22 | run/ 23 | runs/ 24 | 25 | # Files from Forge MDK 26 | forge*changelog.txt 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # In-Game NBTEdit / 游戏内NBT编辑器 2 | A Minecraft mod allows you to edit any NBT tags of the game content with a GUI while in-game. Such as TileEntities, Entities. It may help map creators to make custom items or help mod creators to debug. 3 | 本模组可以用于在游戏内编辑物品、实体或方块的 NBT ,可能会对地图制作者制作自定义物品或模组开发者 Debug 有所帮助。 4 | 5 | **Forge, NeoForge, Fabric are supported!** 6 | **Forge、NeoForge、Fabric 均已支持!** 7 | 8 | 9 | 10 | [Documents before version 5.2.0 (5.2.0 版本之前的文档)](https://github.com/qyl27/NBTEdit/blob/1.20.3/README.md) 11 | 12 | ## Usage(食用方法) 13 | 14 | ### Shortcuts(快捷键) 15 | Press `N` (by default) to edit your target BlockEntity, Entity or ItemStack in main hand (if target is missing). 16 | 使用 `N` 键(默认情况下)打开编辑界面。编辑的目标为十字准星指向的方块实体或者实体,如果没有指向则编辑主手上的物品。 17 | 18 | - `Ctrl` + `C` to Copy a node. (复制) 19 | - `Ctrl` + `V` to Paste a node. (粘贴) 20 | - `Ctrl` + `X` to Cut a node. (剪切) 21 | - `Ctrl` + `D` to Delete a node. (删除) 22 | 23 | ### Commands(命令) 24 | 25 | - `/nbtedit me` 26 | Edit player themselves. 27 | 编辑玩家自身。 28 | 29 | - `/nbtedit hand` 30 | Edit ItemStack in player's main hand. 31 | 编辑玩家主手上的物品。 32 | 33 | - `/nbtedit ` 34 | Edit BlockEntity at x y z. 35 | 编辑位于 x y z 的方块实体。 36 | 37 | - `/nbtedit ` 38 | Edit Entity with entity selector. 39 | 编辑由 entity selector 选择的实体。 40 | 41 | ### Permissions(权限) 42 | 43 | | Name(权限名) | Default Level(默认等级) | Description(说明) | 44 | | -------------- | ------------------------- | ------------------------------------------------------------ | 45 | | use | 2 | Open the editor to edit the NBT.
使用编辑器编辑 NBT 的权限。 | 46 | | read_only | 1 | Open the editor to view NBT, but can't save.
使用编辑器查看 NBT 的权限,保存按钮会被禁用。 | 47 | | edit_on_player | 4 | Use the editor on player, some issue may be caused. USE AT YOUR OWN RISK!
使用编辑器编辑玩家的权限,可能会造成一些问题。谨慎使用。 | 48 | 49 | If you're using Forge or NeoForge, you may need a permission plugin like LuckPerms to grant permission node `nbtedit.` to any player, or use as the same as Fabric. 50 | 在 Forge 或者 NeoForge 平台使用,可以搭配权限管理模组(例如 LuckPerms)授予玩家 `nbtedit.<权限名>` 的权限节点,或者像 Fabric 一样调整配置文件。 51 | 52 | 53 | 54 | ### Configurations(配置文件) 55 | 56 | #### Forge/NeoForge 57 | Location(位置): `.minecraft/config/nbtedit.toml` 58 | 59 | ```toml 60 | # General settings. 61 | [general] 62 | # Enable debug logs. Necessary if you are reporting bugs. (显示调试日志,反馈问题时需要。) 63 | debug = false 64 | 65 | # Permission node levels. Like vanilla, should in 0 ~ 5 range. (权限节点默认等级,取值和原版相同。) 66 | [general.permission] 67 | use = 2 68 | read_only = 1 69 | edit_on_player = 4 70 | ``` 71 | 72 | #### Fabric 73 | Location(位置): `.minecraft/config/nbtedit.json` 74 | 75 | ```json5 76 | { 77 | "debug": false, // Enable debug logs. Necessary if you are reporting bugs. (显示调试日志,反馈问题时需要。) 78 | "permissionsLevels": { // Permission node levels. Like vanilla, should in 0 ~ 5 range. (权限节点默认等级,取值和原版相同。) 79 | "read_only": 1, 80 | "edit_on_player": 4, 81 | "use": 2 82 | } 83 | } 84 | ``` 85 | 86 | 87 | 88 | ## Origin(原帖地址) 89 | 90 | http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/1286750-in-game-nbtedit-edit-mob-spawners-attributes-in 91 | 92 | ## Screenshots(使用截图) 93 | ![使用截图 #1](https://github.com/qyl27/NBTEdit/raw/1.21/img/2.png) 94 | ![使用截图 #2](https://github.com/qyl27/NBTEdit/raw/1.21/img/3.png) 95 | 96 | ## Common issues(常见问题) 97 | - I was kicked when I tried to save my edit(在尝试保存时被服务器踢出): 98 | If it shows `Payload may not be larger than 32767 bytes`, please use [Packet Fixer](https://www.curseforge.com/minecraft/mc-mods/packet-fixer) by [TonimatasDEV](https://github.com/TonimatasDEV) to fix it. 99 | 如果客户端显示 `Payload may not be larger than 32767 bytes`,请使用 [TonimatasDEV](https://github.com/TonimatasDEV) 的 [Packet Fixer](https://www.curseforge.com/minecraft/mc-mods/packet-fixer) 修复。 100 | 101 | 102 | ## Bug report / Feature request(反馈/催更) 103 | Please go to the [issues page](https://github.com/qyl27/NBTEdit/issues) of GitHub repo. 104 | 请到 [Issues 页面](https://github.com/qyl27/NBTEdit/issues) 提出。 105 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import java.time.OffsetDateTime 2 | 3 | plugins { 4 | id 'com.gradleup.shadow' version '8.3.+' apply false 5 | id 'me.shedaniel.unified-publishing' version '0.1.+' apply false 6 | id 'architectury-plugin' version '3.4-SNAPSHOT' 7 | id 'dev.architectury.loom' version '1.9-SNAPSHOT' apply false 8 | } 9 | 10 | def ENV = System.getenv() 11 | 12 | var publishVersion = project.mod_version 13 | publishVersion += "+mc${project.minecraft_version}" 14 | var mavenVersion = publishVersion 15 | if (!ENV.MOD_RELEASE) { 16 | mavenVersion += '-SNAPSHOT' 17 | } 18 | 19 | ext.publishVersion = publishVersion 20 | ext.mavenVersion = mavenVersion 21 | 22 | subprojects { 23 | apply plugin: 'java' 24 | apply plugin: 'architectury-plugin' 25 | apply plugin: 'dev.architectury.loom' 26 | 27 | architectury { 28 | minecraft = project.minecraft_version 29 | } 30 | 31 | loom { 32 | silentMojangMappingsLicense() 33 | } 34 | 35 | dependencies { 36 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 37 | 38 | mappings loom.layered() { 39 | officialMojangMappings() 40 | parchment("org.parchmentmc.data:parchment-${project.parchment_minecraft_version}:${project.parchment_version}@zip") 41 | } 42 | } 43 | 44 | tasks.withType(JavaCompile) { 45 | options.encoding = 'UTF-8' 46 | options.release = 21 47 | } 48 | 49 | java { 50 | withSourcesJar() 51 | } 52 | 53 | processResources { 54 | var resourcesToReplace = ['build_info.properties', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', 'pack.mcmeta', 'fabric.mod.json'] 55 | var replaceTokens = [ 56 | 'archives_base_name' : rootProject.archives_base_name, 57 | 'mod_id' : rootProject.mod_id, 58 | 'mod_name' : rootProject.mod_name, 59 | 'mod_full_name' : rootProject.mod_full_name, 60 | 'mod_version' : rootProject.mod_version, 61 | 'minecraft_version' : rootProject.minecraft_version, 62 | 'parchment_minecraft_version' : rootProject.parchment_minecraft_version, 63 | 'parchment_version' : rootProject.parchment_version, 64 | 'fabric_loader_version' : rootProject.fabric_loader_version, 65 | 'fabric_api_version' : rootProject.fabric_api_version, 66 | 'mod_menu_version' : rootProject.mod_menu_version, 67 | 'forge_version' : rootProject.forge_version, 68 | 'neoforge_version' : rootProject.neoforge_version, 69 | 'forge_loader_version_range' : rootProject.forge_loader_version_range, 70 | 'forge_version_range' : rootProject.forge_version_range, 71 | 'forge_minecraft_version_range' : rootProject.forge_minecraft_version_range, 72 | 'neoforge_loader_version_range' : rootProject.neoforge_loader_version_range, 73 | 'neoforge_version_range' : rootProject.neoforge_version_range, 74 | 'neoforge_minecraft_version_range': rootProject.neoforge_minecraft_version_range, 75 | 'fabric_loader_version_range' : rootProject.fabric_loader_version_range, 76 | 'fabric_api_version_range' : rootProject.fabric_api_version_range, 77 | 'fabric_permission_api_version_range' : rootProject.fabric_permission_api_version_range, 78 | 'fabric_minecraft_version_range' : rootProject.fabric_minecraft_version_range, 79 | 'build_time' : OffsetDateTime.now(), 80 | 'build_version' : publishVersion 81 | ] 82 | 83 | inputs.properties replaceTokens 84 | filesMatching(resourcesToReplace) { 85 | expand replaceTokens 86 | } 87 | 88 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 89 | } 90 | } 91 | 92 | allprojects { 93 | apply plugin: 'maven-publish' 94 | 95 | group = 'cx.rain.mc.nbtedit' 96 | version = project.mod_version 97 | 98 | repositories { 99 | maven { 100 | name = 'ParchmentMC' 101 | url = 'https://maven.parchmentmc.org' 102 | } 103 | 104 | maven { 105 | name = 'Mod Menu' 106 | url = 'https://maven.terraformersmc.com/releases' 107 | } 108 | 109 | maven { 110 | name = 'Curse maven' 111 | url = 'https://cursemaven.com' 112 | content { 113 | includeGroup 'curse.maven' 114 | } 115 | } 116 | 117 | maven { 118 | name = 'NeoForged' 119 | url = 'https://maven.neoforged.net/releases/' 120 | } 121 | 122 | mavenCentral() 123 | } 124 | 125 | publishing { 126 | repositories { 127 | mavenLocal() 128 | 129 | maven { 130 | name = 'YuluoMaven' 131 | 132 | def releaseUrl = 'https://maven.yuluo.dev/repository/maven-releases/' 133 | def snapshotUrl = 'https://maven.yuluo.dev/repository/maven-snapshots/' 134 | url = ENV.MOD_RELEASE ? releaseUrl : snapshotUrl 135 | 136 | credentials { 137 | username ENV.MOD_MAVEN_USER 138 | password ENV.MOD_MAVEN_PASS 139 | } 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G 2 | org.gradle.daemon=false 3 | 4 | enabled_platforms=forge,fabric,neoforge 5 | 6 | archives_base_name=nbtedit 7 | 8 | mod_id=nbtedit 9 | mod_name=NBTEdit 10 | mod_full_name=In-game NBTEdit Reborn 11 | mod_version=5.2.11 12 | 13 | minecraft_version=1.21.4 14 | 15 | parchment_minecraft_version=1.21.4 16 | parchment_version=2025.01.05 17 | 18 | fabric_loader_version=0.16.10 19 | fabric_api_version=0.114.3+1.21.4 20 | fabric_permission_api_version=0.3.3 21 | mod_menu_version=13.0.0 22 | 23 | forge_version=54.0.17 24 | neoforge_version=21.4.59-beta 25 | 26 | forge_loader_version_range=[54,) 27 | forge_version_range=[54,) 28 | forge_minecraft_version_range=[1.21.4,) 29 | 30 | neoforge_loader_version_range=[4,) 31 | neoforge_version_range=[21.4,) 32 | neoforge_minecraft_version_range=[1.21.4,) 33 | 34 | fabric_loader_version_range=>=0.16 35 | fabric_api_version_range=* 36 | fabric_permission_api_version_range=>=0.3.3 37 | fabric_minecraft_version_range=>=1.21.4 38 | 39 | releasing_minecraft_versions=1.21.4 40 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/img/4.png -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/img/logo.png -------------------------------------------------------------------------------- /nbtedit-common/build.gradle: -------------------------------------------------------------------------------- 1 | architectury { 2 | common(rootProject.enabled_platforms.split(',')) 3 | } 4 | 5 | loom { 6 | accessWidenerPath = file("src/main/resources/nbtedit.accesswidener") 7 | } 8 | 9 | dependencies { 10 | modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" 11 | } 12 | 13 | sourceSets { 14 | main { 15 | resources { 16 | srcDir file('src/generated/resources') 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /nbtedit-common/src/generated/resources/.cache/389e3a88cd1a087f6956d4058ad04dba575e640f: -------------------------------------------------------------------------------- 1 | // 1.21 2024-08-25T11:17:22.9099094 Languages: zh_cn for mod: nbtedit 2 | db149823212bad31c630c24f6e1df2851808b222 assets/nbtedit/lang/zh_cn.json 3 | -------------------------------------------------------------------------------- /nbtedit-common/src/generated/resources/.cache/94e5143f2f45998e4eef93f35114a94d6661df8d: -------------------------------------------------------------------------------- 1 | // 1.21 2024-08-25T11:17:22.9129092 Languages: en_us for mod: nbtedit 2 | 7aa4d407b69070b6d6e850b78a43f46547c3fc94 assets/nbtedit/lang/en_us.json 3 | -------------------------------------------------------------------------------- /nbtedit-common/src/generated/resources/assets/nbtedit/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.nbtedit.button.add": "Add %1$s Tag", 3 | "gui.nbtedit.button.cancel": "Cancel", 4 | "gui.nbtedit.button.copy": "Copy", 5 | "gui.nbtedit.button.cut": "Cut", 6 | "gui.nbtedit.button.delete": "Delete", 7 | "gui.nbtedit.button.edit": "Edit", 8 | "gui.nbtedit.button.ok": "OK", 9 | "gui.nbtedit.button.paste": "Paste", 10 | "gui.nbtedit.button.quit": "Quit", 11 | "gui.nbtedit.button.save": "Save", 12 | "gui.nbtedit.edit_box.name": "Name", 13 | "gui.nbtedit.edit_box.value": "Value", 14 | "gui.nbtedit.label.name": "Name", 15 | "gui.nbtedit.label.value": "Value", 16 | "gui.nbtedit.title.editing_window": "Editing Tag", 17 | "gui.nbtedit.title.editing_window.narration": "Tag Editing Window", 18 | "gui.nbtedit.title.editor.read_only": "[Read-only] ", 19 | "gui.nbtedit.title.editor_block_entity": "Editing BlockEntity (%1$s, %2$s, %3$s)", 20 | "gui.nbtedit.title.editor_block_entity.narration": "BlockEntity NBT editor", 21 | "gui.nbtedit.title.editor_entity": "Editing Entity (%1$s)", 22 | "gui.nbtedit.title.editor_entity.narration": "Entity NBT editor", 23 | "gui.nbtedit.title.editor_item_stack": "Editing ItemStack (%1$s)", 24 | "gui.nbtedit.title.editor_item_stack.narration": "ItemStack NBT editor", 25 | "gui.nbtedit.title.scroll_bar": "Scrollbar", 26 | "gui.nbtedit.title.scroll_bar.narration": "Drag to scroll", 27 | "gui.nbtedit.title.tree_view": "NBT Tree", 28 | "gui.nbtedit.title.tree_view.narration": "NBT Node Tree", 29 | "gui.nbtedit.title.tree_view_node": "NBT Node", 30 | "gui.nbtedit.title.tree_view_node.narration": "NBT Node: %1$s", 31 | "gui.nbtedit.tooltip.button_add": "Add tag typed %1$s.", 32 | "gui.nbtedit.tooltip.button_cancel": "Cancel", 33 | "gui.nbtedit.tooltip.button_copy": "Copy selected tag.", 34 | "gui.nbtedit.tooltip.button_cut": "Cut selected tag.", 35 | "gui.nbtedit.tooltip.button_delete": "Delete selected tag.", 36 | "gui.nbtedit.tooltip.button_edit": "Edit selected tag.", 37 | "gui.nbtedit.tooltip.button_ok": "OK", 38 | "gui.nbtedit.tooltip.button_paste": "Paste tag into selected container.", 39 | "gui.nbtedit.tooltip.button_quit": "Discard and quit the editor.", 40 | "gui.nbtedit.tooltip.button_save": "Save and quit the editor.", 41 | "gui.nbtedit.tooltip.button_save.disabled": "Cannot be saved, the editor is read-only.", 42 | "gui.nbtedit.tooltip.preview_component": "[Text Preview] ", 43 | "gui.nbtedit.tooltip.preview_component.narration": "Text Preview: ", 44 | "gui.nbtedit.tooltip.preview_item": "[Item Preview] ", 45 | "gui.nbtedit.tooltip.preview_item.narration": "Item Preview: ", 46 | "gui.nbtedit.tooltip.preview_uuid": "[UUID Preview] ", 47 | "gui.nbtedit.tooltip.preview_uuid.narration": "UUID Preview: ", 48 | "key.category.nbtedit": "In-game NBTEdit Reborn", 49 | "key.nbtedit.shortcut": "Open the NBT editor", 50 | "message.nbtedit.cannot_edit_other_player": "Sorry, but you cannot edit other player.", 51 | "message.nbtedit.editing.block_entity": "Editing BlockEntity (%1$s, %2$s, %3$s).", 52 | "message.nbtedit.editing.entity": "Editing Entity (%1$s).", 53 | "message.nbtedit.editing.item_stack": "Editing ItemStack (%1$s).", 54 | "message.nbtedit.nbt_type.byte": "Byte", 55 | "message.nbtedit.nbt_type.byte_array": "Byte Array", 56 | "message.nbtedit.nbt_type.compound": "Compound", 57 | "message.nbtedit.nbt_type.double": "Double", 58 | "message.nbtedit.nbt_type.float": "Float", 59 | "message.nbtedit.nbt_type.int": "Integer", 60 | "message.nbtedit.nbt_type.int_array": "Integer Array", 61 | "message.nbtedit.nbt_type.list": "List", 62 | "message.nbtedit.nbt_type.long": "Long", 63 | "message.nbtedit.nbt_type.long_array": "Long Array", 64 | "message.nbtedit.nbt_type.short": "Short", 65 | "message.nbtedit.nbt_type.string": "String", 66 | "message.nbtedit.no_permission": "You have no permission to use NBTEdit.", 67 | "message.nbtedit.not_a_player": "Only players can use this command.", 68 | "message.nbtedit.not_loaded": "Block pos was not loaded.", 69 | "message.nbtedit.nothing_to_edit": "There is no any target for editing.", 70 | "message.nbtedit.saved.successful": "Save successful!", 71 | "message.nbtedit.saving.failed.block_entity_not_exists": "Save failed! the BlockEntity is no longer exists.", 72 | "message.nbtedit.saving.failed.entity_not_exists": "Save failed! the Entity is no longer exists.", 73 | "message.nbtedit.saving.failed.invalid_nbt": "Save failed! Invalid NBT.", 74 | "message.nbtedit.target_is_not_block_entity": "There is no BlockEntity to edit.", 75 | "message.nbtedit.unknown_entity_id": "Invalid Entity ID." 76 | } -------------------------------------------------------------------------------- /nbtedit-common/src/generated/resources/assets/nbtedit/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.nbtedit.button.add": "添加 %1$s 标签", 3 | "gui.nbtedit.button.cancel": "取消", 4 | "gui.nbtedit.button.copy": "复制", 5 | "gui.nbtedit.button.cut": "剪切", 6 | "gui.nbtedit.button.delete": "删除", 7 | "gui.nbtedit.button.edit": "编辑", 8 | "gui.nbtedit.button.ok": "确定", 9 | "gui.nbtedit.button.paste": "粘贴", 10 | "gui.nbtedit.button.quit": "退出", 11 | "gui.nbtedit.button.save": "保存", 12 | "gui.nbtedit.edit_box.name": "名称", 13 | "gui.nbtedit.edit_box.value": "数值", 14 | "gui.nbtedit.label.name": "名称", 15 | "gui.nbtedit.label.value": "数值", 16 | "gui.nbtedit.title.editing_window": "编辑 NBT 标签", 17 | "gui.nbtedit.title.editing_window.narration": "NBT 标签编辑窗口", 18 | "gui.nbtedit.title.editor.read_only": "(只读)", 19 | "gui.nbtedit.title.editor_block_entity": "编辑方块实体(%1$s, %2$s, %3$s)", 20 | "gui.nbtedit.title.editor_block_entity.narration": "方块实体 NBT 编辑器", 21 | "gui.nbtedit.title.editor_entity": "编辑实体(ID:%1$s)", 22 | "gui.nbtedit.title.editor_entity.narration": "实体 NBT 编辑器", 23 | "gui.nbtedit.title.editor_item_stack": "编辑物品(%1$s)", 24 | "gui.nbtedit.title.editor_item_stack.narration": "物品 NBT 编辑器", 25 | "gui.nbtedit.title.scroll_bar": "滚动条", 26 | "gui.nbtedit.title.scroll_bar.narration": "按住拖动", 27 | "gui.nbtedit.title.tree_view": "NBT 树", 28 | "gui.nbtedit.title.tree_view.narration": "NBT 节点树", 29 | "gui.nbtedit.title.tree_view_node": "NBT 节点", 30 | "gui.nbtedit.title.tree_view_node.narration": "NBT 节点:%1$s", 31 | "gui.nbtedit.tooltip.button_add": "添加 %1$s 类型的标签", 32 | "gui.nbtedit.tooltip.button_cancel": "取消", 33 | "gui.nbtedit.tooltip.button_copy": "复制选中的标签", 34 | "gui.nbtedit.tooltip.button_cut": "剪切选中的标签", 35 | "gui.nbtedit.tooltip.button_delete": "删除选中的标签", 36 | "gui.nbtedit.tooltip.button_edit": "编辑选中的标签", 37 | "gui.nbtedit.tooltip.button_ok": "确定", 38 | "gui.nbtedit.tooltip.button_paste": "在选中的容器中粘贴标签", 39 | "gui.nbtedit.tooltip.button_quit": "退出编辑器但不保存", 40 | "gui.nbtedit.tooltip.button_save": "保存并退出编辑器", 41 | "gui.nbtedit.tooltip.button_save.disabled": "无法保存,因为此编辑器是只读的", 42 | "gui.nbtedit.tooltip.preview_component": "【文本预览】", 43 | "gui.nbtedit.tooltip.preview_component.narration": "文本预览:", 44 | "gui.nbtedit.tooltip.preview_item": "【物品预览】", 45 | "gui.nbtedit.tooltip.preview_item.narration": "物品预览:", 46 | "gui.nbtedit.tooltip.preview_uuid": "【UUID 预览】", 47 | "gui.nbtedit.tooltip.preview_uuid.narration": "UUID 预览:", 48 | "key.category.nbtedit": "游戏内 NBT 编辑器 (重制版)", 49 | "key.nbtedit.shortcut": "打开编辑器", 50 | "message.nbtedit.cannot_edit_other_player": "你不能编辑其他玩家。", 51 | "message.nbtedit.editing.block_entity": "编辑方块实体(%1$s, %2$s, %3$s)。", 52 | "message.nbtedit.editing.entity": "编辑实体(ID:%1$s)。", 53 | "message.nbtedit.editing.item_stack": "编辑物品(%1$s)。", 54 | "message.nbtedit.nbt_type.byte": "字节", 55 | "message.nbtedit.nbt_type.byte_array": "字节数组", 56 | "message.nbtedit.nbt_type.compound": "组合", 57 | "message.nbtedit.nbt_type.double": "双精度浮点数", 58 | "message.nbtedit.nbt_type.float": "浮点数", 59 | "message.nbtedit.nbt_type.int": "整数", 60 | "message.nbtedit.nbt_type.int_array": "整数数组", 61 | "message.nbtedit.nbt_type.list": "列表", 62 | "message.nbtedit.nbt_type.long": "长整数", 63 | "message.nbtedit.nbt_type.long_array": "长整数数组", 64 | "message.nbtedit.nbt_type.short": "短整数", 65 | "message.nbtedit.nbt_type.string": "字符串", 66 | "message.nbtedit.no_permission": "你没有权限使用 NBTEdit!", 67 | "message.nbtedit.not_a_player": "只有在游戏中的玩家可以使用这个命令。", 68 | "message.nbtedit.not_loaded": "方块还未加载。", 69 | "message.nbtedit.nothing_to_edit": "没有任何目标可供编辑。", 70 | "message.nbtedit.saved.successful": "保存成功。", 71 | "message.nbtedit.saving.failed.block_entity_not_exists": "保存失败。目标方块实体已经不存在了!", 72 | "message.nbtedit.saving.failed.entity_not_exists": "保存失败。目标实体不存在了!", 73 | "message.nbtedit.saving.failed.invalid_nbt": "保存失败。无效的 NBT!", 74 | "message.nbtedit.target_is_not_block_entity": "没有目标方块实体可供编辑。", 75 | "message.nbtedit.unknown_entity_id": "无效的实体 ID。" 76 | } -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/NBTEdit.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit; 2 | 3 | import net.minecraft.SharedConstants; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.IOException; 8 | import java.time.OffsetDateTime; 9 | import java.util.Properties; 10 | 11 | public class NBTEdit { 12 | public static final String MODID = "nbtedit"; 13 | public static final String NAME = "In-game NBTEdit Reborn"; 14 | public static final String VERSION; 15 | public static final OffsetDateTime BUILD_TIME; 16 | 17 | static { 18 | var properties = new Properties(); 19 | var version = ""; 20 | OffsetDateTime buildTime; 21 | try { 22 | properties.load(NBTEdit.class.getResourceAsStream("/build_info.properties")); 23 | version = properties.getProperty("build_version"); 24 | buildTime = OffsetDateTime.parse(properties.getProperty("build_time")); 25 | } catch (IOException ex) { 26 | version = "Unknown"; 27 | buildTime = null; 28 | } 29 | VERSION = version; 30 | BUILD_TIME = buildTime; 31 | } 32 | 33 | private static NBTEdit INSTANCE; 34 | 35 | private final Logger logger = LoggerFactory.getLogger(NAME); 36 | 37 | public NBTEdit() { 38 | INSTANCE = this; 39 | 40 | logger.info("Loading NBTEdit ver: {} on mc {}, build at {}", 41 | VERSION, 42 | SharedConstants.getCurrentVersion().getName(), 43 | BUILD_TIME != null ? BUILD_TIME : "B.C. 3200"); 44 | } 45 | 46 | public static NBTEdit getInstance() { 47 | return INSTANCE; 48 | } 49 | 50 | public Logger getLogger() { 51 | return logger; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/NBTEditPlatform.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit; 2 | 3 | import cx.rain.mc.nbtedit.api.command.IModPermission; 4 | import cx.rain.mc.nbtedit.api.config.IModConfig; 5 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 6 | import dev.architectury.injectables.annotations.ExpectPlatform; 7 | 8 | public class NBTEditPlatform { 9 | @ExpectPlatform 10 | public static IModNetworking getNetworking() { 11 | throw new RuntimeException(); 12 | } 13 | 14 | @ExpectPlatform 15 | public static IModConfig getConfig() { 16 | throw new RuntimeException(); 17 | } 18 | 19 | @ExpectPlatform 20 | public static IModPermission getPermission() { 21 | throw new RuntimeException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/api/command/IModPermission.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.api.command; 2 | 3 | import net.minecraft.commands.CommandSourceStack; 4 | import net.minecraft.server.level.ServerPlayer; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public interface IModPermission { 8 | boolean hasPermission(@NotNull CommandSourceStack sourceStack, @NotNull ModPermissions permission); 9 | 10 | boolean hasPermission(@NotNull ServerPlayer player, @NotNull ModPermissions permission); 11 | 12 | default boolean canOpenEditor(@NotNull ServerPlayer player) { 13 | return hasPermission(player, ModPermissions.USE) || hasPermission(player, ModPermissions.READ_ONLY); 14 | } 15 | 16 | default boolean isReadOnly(@NotNull ServerPlayer player) { 17 | return !hasPermission(player, ModPermissions.USE) && hasPermission(player, ModPermissions.READ_ONLY); 18 | } 19 | 20 | default boolean canSave(@NotNull ServerPlayer player) { 21 | return hasPermission(player, ModPermissions.USE); 22 | } 23 | 24 | default boolean canEditOnPlayer(@NotNull ServerPlayer player) { 25 | return hasPermission(player, ModPermissions.EDIT_ON_PLAYER); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/api/command/ModPermissions.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.api.command; 2 | 3 | public enum ModPermissions { 4 | USE(2, "use"), 5 | READ_ONLY(1, "read_only"), 6 | EDIT_ON_PLAYER(4, "edit_on_player"), 7 | ; 8 | 9 | private final int level; 10 | private final String name; 11 | 12 | ModPermissions(int level, String name) { 13 | this.level = level; 14 | this.name = name; 15 | } 16 | 17 | public int getDefaultLevel() { 18 | return level; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/api/config/IModConfig.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.api.config; 2 | 3 | public interface IModConfig { 4 | boolean isDebug(); 5 | } 6 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/api/netowrking/IModNetworking.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.api.netowrking; 2 | 3 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 4 | import net.minecraft.server.level.ServerPlayer; 5 | 6 | public interface IModNetworking { 7 | void sendTo(ServerPlayer player, CustomPacketPayload packet); 8 | void sendToServer(CustomPacketPayload packet); 9 | } 10 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/command/NBTEditCommand.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.command; 2 | 3 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 4 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 5 | import cx.rain.mc.nbtedit.NBTEdit; 6 | import cx.rain.mc.nbtedit.NBTEditPlatform; 7 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 8 | import cx.rain.mc.nbtedit.networking.NetworkEditingHelper; 9 | import com.mojang.brigadier.context.CommandContext; 10 | import cx.rain.mc.nbtedit.networking.packet.s2c.RaytracePacket; 11 | import net.minecraft.commands.CommandSourceStack; 12 | import net.minecraft.commands.arguments.EntityArgument; 13 | import net.minecraft.commands.arguments.coordinates.BlockPosArgument; 14 | 15 | import static net.minecraft.commands.Commands.argument; 16 | import static net.minecraft.commands.Commands.literal; 17 | 18 | public class NBTEditCommand { 19 | 20 | public static final LiteralArgumentBuilder NBTEDIT = literal("nbtedit") 21 | .requires(source -> NBTEditPlatform.getPermission().hasPermission(source, ModPermissions.USE)) 22 | .executes(NBTEditCommand::onUse) 23 | .then(argument("entity", EntityArgument.entity()) 24 | .executes(NBTEditCommand::onEntity)) 25 | .then(argument("block", BlockPosArgument.blockPos()) 26 | .executes(NBTEditCommand::onBlockEntity)) 27 | .then(literal("me") 28 | .executes(NBTEditCommand::onEntityMe)) 29 | .then(literal("hand") 30 | .executes(NBTEditCommand::onItemHand)); 31 | 32 | private static int onUse(final CommandContext context) throws CommandSyntaxException { 33 | var player = context.getSource().getPlayerOrException(); 34 | NBTEditPlatform.getNetworking().sendTo(player, new RaytracePacket()); 35 | 36 | NBTEdit.getInstance().getLogger().info("Player " + player.getName().getString() + " issued command /nbtedit."); 37 | return 1; 38 | } 39 | 40 | private static int onEntity(final CommandContext context) throws CommandSyntaxException { 41 | var player = context.getSource().getPlayerOrException(); 42 | var entity = EntityArgument.getEntity(context, "entity"); 43 | 44 | NBTEdit.getInstance().getLogger().info("Player " + player.getName().getString() + 45 | " issued command /nbtedit with an entity."); 46 | NetworkEditingHelper.editEntity(player, entity.getUUID()); 47 | return 1; 48 | } 49 | 50 | private static int onBlockEntity(final CommandContext context) throws CommandSyntaxException { 51 | var player = context.getSource().getPlayerOrException(); 52 | var pos = BlockPosArgument.getBlockPos(context, "block"); 53 | 54 | NBTEdit.getInstance().getLogger().info("Player " + player.getName().getString() + 55 | " issued command /nbtedit with an block at XYZ: " + 56 | pos.getX() + " " + pos.getY() + " " + pos.getZ() + "."); 57 | NetworkEditingHelper.editBlockEntity(player, pos); 58 | return 1; 59 | } 60 | 61 | private static int onEntityMe(final CommandContext context) throws CommandSyntaxException { 62 | var player = context.getSource().getPlayerOrException(); 63 | 64 | NBTEdit.getInstance().getLogger().info("Player " + player.getName().getString() + 65 | " issued command /nbtedit to edit itself."); 66 | NetworkEditingHelper.editEntity(player, player.getUUID()); 67 | return 1; 68 | } 69 | 70 | private static int onItemHand(final CommandContext context) throws CommandSyntaxException { 71 | var player = context.getSource().getPlayerOrException(); 72 | NBTEdit.getInstance().getLogger().info("Player " + player.getName().getString() + 73 | " issued command /nbtedit to edit hand."); 74 | 75 | var stack = player.getMainHandItem(); 76 | NetworkEditingHelper.editItemStack(player, stack); 77 | return 1; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/AccessibilityHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import cx.rain.mc.nbtedit.utility.ModConstants; 4 | import net.minecraft.ChatFormatting; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.gui.components.Tooltip; 7 | import net.minecraft.network.chat.Component; 8 | import net.minecraft.world.entity.player.Player; 9 | import net.minecraft.world.item.Item; 10 | import net.minecraft.world.item.TooltipFlag; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public class AccessibilityHelper { 14 | private static Minecraft getMinecraft() { 15 | return Minecraft.getInstance(); 16 | } 17 | 18 | public static Component buildText(NbtTree.Node node) { 19 | return Component.literal(node.getAsString()); 20 | } 21 | 22 | public static Component buildNarration(NbtTree.Node node) { 23 | return Component.translatable(ModConstants.GUI_TITLE_TREE_VIEW_NODE_NARRATION, node.getAsString()); 24 | } 25 | 26 | public static @Nullable Tooltip buildTooltip(Player player, NbtTree.Node node) { 27 | var tag = node.getTag(); 28 | var showPreview = false; 29 | var previewTitle = ""; 30 | var previewNarrationTitle = ""; 31 | var previewContent = Component.empty(); 32 | 33 | var item = TagReadingHelper.tryReadItem(player, tag); 34 | if (item != null) { 35 | showPreview = true; 36 | previewTitle = ModConstants.GUI_TOOLTIP_PREVIEW_ITEM; 37 | previewNarrationTitle = ModConstants.GUI_TOOLTIP_PREVIEW_ITEM_NARRATION; 38 | 39 | var lines = item.getTooltipLines(Item.TooltipContext.of(player.level()), player, TooltipFlag.ADVANCED); 40 | for (int i = 0; i < lines.size(); i++) { 41 | previewContent.append(lines.get(i)); 42 | if (i != lines.size() - 1) { 43 | previewContent.append("\n"); 44 | } 45 | } 46 | } 47 | 48 | var uuid = TagReadingHelper.tryReadUuid(tag); 49 | if (!showPreview && uuid != null) { 50 | showPreview = true; 51 | previewTitle = ModConstants.GUI_TOOLTIP_PREVIEW_UUID; 52 | previewNarrationTitle = ModConstants.GUI_TOOLTIP_PREVIEW_UUID_NARRATION; 53 | previewContent.append(uuid.toString()); 54 | } 55 | 56 | var text = TagReadingHelper.tryReadText(player, tag); 57 | if (!showPreview && text != null) { 58 | showPreview = true; 59 | previewTitle = ModConstants.GUI_TOOLTIP_PREVIEW_COMPONENT; 60 | previewNarrationTitle = ModConstants.GUI_TOOLTIP_PREVIEW_COMPONENT_NARRATION; 61 | previewContent.append(text); 62 | } 63 | 64 | if (showPreview) { 65 | var preview = Component.translatable(previewTitle) 66 | .append(Component.literal("\n").withStyle(ChatFormatting.RESET) 67 | .append(previewContent)); 68 | var previewNarration = Component.translatable(previewNarrationTitle) 69 | .append(Component.literal("\n").withStyle(ChatFormatting.RESET) 70 | .append(previewContent)); 71 | 72 | return Tooltip.create(preview, previewNarration); 73 | } 74 | 75 | return null; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/ClipboardHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import net.minecraft.client.Minecraft; 4 | 5 | public class ClipboardHelper { 6 | public static void setNode(NbtTree.Node node) { 7 | var data = node.asString(); 8 | Minecraft.getInstance().keyboardHandler.setClipboard(data); 9 | } 10 | 11 | public static NbtTree.Node getNode() { 12 | var data = Minecraft.getInstance().keyboardHandler.getClipboard(); 13 | return NbtTree.Node.fromString(data); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/EditorButton.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.ModConstants; 5 | import net.minecraft.nbt.Tag; 6 | import net.minecraft.network.chat.Component; 7 | import net.minecraft.resources.ResourceLocation; 8 | 9 | public enum EditorButton { 10 | BYTE(0, ModConstants.NBT_TYPE_BYTE, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/byte")), 11 | SHORT(1, ModConstants.NBT_TYPE_SHORT, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/short")), 12 | INT(2, ModConstants.NBT_TYPE_INT, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/int")), 13 | LONG(3, ModConstants.NBT_TYPE_LONG, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/long")), 14 | FLOAT(4, ModConstants.NBT_TYPE_FLOAT, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/float")), 15 | DOUBLE(5, ModConstants.NBT_TYPE_DOUBLE, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/double")), 16 | BYTE_ARRAY(6, ModConstants.NBT_TYPE_BYTE_ARRAY, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/byte_array")), 17 | STRING(7, ModConstants.NBT_TYPE_STRING, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/string")), 18 | LIST(8, ModConstants.NBT_TYPE_LIST, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/list")), 19 | COMPOUND(9, ModConstants.NBT_TYPE_COMPOUND, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/compound")), 20 | INT_ARRAY(10, ModConstants.NBT_TYPE_INT_ARRAY, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/int_array")), 21 | LONG_ARRAY(11, ModConstants.NBT_TYPE_LONG_ARRAY, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "tag_type/long_array")), 22 | EDIT(12, ModConstants.GUI_BUTTON_EDIT, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/edit")), 23 | DELETE(13, ModConstants.GUI_BUTTON_DELETE, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/delete")), 24 | PASTE(14, ModConstants.GUI_BUTTON_PASTE, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/paste")), 25 | CUT(15, ModConstants.GUI_BUTTON_CUT, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/cut")), 26 | COPY(16, ModConstants.GUI_BUTTON_COPY, ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/copy")), 27 | ; 28 | 29 | private final int id; 30 | private final Component name; 31 | private final ResourceLocation sprite; 32 | 33 | EditorButton(int id, String name, ResourceLocation sprite) { 34 | this.id = id; 35 | this.name = Component.translatable(name); 36 | this.sprite = sprite; 37 | } 38 | 39 | public int getId() { 40 | return id; 41 | } 42 | 43 | public ResourceLocation getSprite() { 44 | return sprite; 45 | } 46 | 47 | public Component getName() { 48 | return name; 49 | } 50 | 51 | public static EditorButton of(int id) { 52 | for (var v : values()) { 53 | if (v.getId() == id) { 54 | return v; 55 | } 56 | } 57 | 58 | return BYTE; 59 | } 60 | 61 | public static EditorButton ofTag(Tag t) { 62 | return switch (t.getId()) { 63 | case 1 -> BYTE; 64 | case 2 -> SHORT; 65 | case 3 -> INT; 66 | case 4 -> LONG; 67 | case 5 -> FLOAT; 68 | case 6 -> DOUBLE; 69 | case 7 -> BYTE_ARRAY; 70 | case 8 -> STRING; 71 | case 9 -> LIST; 72 | case 10 -> COMPOUND; 73 | case 11 -> INT_ARRAY; 74 | case 12 -> LONG_ARRAY; 75 | default -> throw new IllegalStateException("Unexpected value: " + t.getId()); 76 | }; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/EditorHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import net.minecraft.nbt.*; 4 | 5 | public class EditorHelper { 6 | public static Tag newTag(int buttonId) { 7 | return switch (buttonId) { 8 | case 0 -> ByteTag.valueOf((byte) 0); 9 | case 1 -> ShortTag.valueOf((short) 0); 10 | case 2 -> IntTag.valueOf(0); 11 | case 3 -> LongTag.valueOf(0); 12 | case 4 -> FloatTag.valueOf(0.0f); 13 | case 5 -> DoubleTag.valueOf(0.0); 14 | case 6 -> new ByteArrayTag(new byte[0]); 15 | case 7 -> StringTag.valueOf(""); 16 | case 8 -> new ListTag(); 17 | case 9 -> new CompoundTag(); 18 | case 10 -> new IntArrayTag(new int[0]); 19 | case 11 -> new LongArrayTag(new long[0]); 20 | default -> null; 21 | }; 22 | } 23 | 24 | public static String newTagName(int buttonId, NbtTree.Node parent) { 25 | var type = NbtType.ofButtonId(buttonId); 26 | if (!parent.hasChild()) { 27 | return type + " 1"; 28 | } 29 | 30 | for (int i = 1; i <= parent.getChildren().size() + 1; ++i) { 31 | String name = type.getTagName() + " " + i; 32 | if (isNameValidInNode(name, parent)) { 33 | return name; 34 | } 35 | } 36 | 37 | return type + " INF"; 38 | } 39 | 40 | public static boolean isNameValidInNode(String name, NbtTree.Node parent) { 41 | for (var node : parent.getChildren()) { 42 | if (node.getName().equals(name)) { 43 | return false; 44 | } 45 | } 46 | return true; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/NbtType.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import cx.rain.mc.nbtedit.utility.ModConstants; 4 | import net.minecraft.network.chat.Component; 5 | 6 | public enum NbtType { 7 | BYTE(1, ModConstants.NBT_TYPE_BYTE, "Byte"), 8 | SHORT(2, ModConstants.NBT_TYPE_SHORT, "Short"), 9 | INT(3, ModConstants.NBT_TYPE_INT, "Int"), 10 | LONG(4, ModConstants.NBT_TYPE_LONG, "Long"), 11 | FLOAT(5, ModConstants.NBT_TYPE_FLOAT, "Float"), 12 | DOUBLE(6, ModConstants.NBT_TYPE_DOUBLE, "Double"), 13 | BYTE_ARRAY(7, ModConstants.NBT_TYPE_BYTE_ARRAY, "ByteArray"), 14 | STRING(8, ModConstants.NBT_TYPE_STRING, "String"), 15 | LIST(9, ModConstants.NBT_TYPE_LIST, "List"), 16 | COMPOUND(10, ModConstants.NBT_TYPE_COMPOUND, "Compound"), 17 | INT_ARRAY(11, ModConstants.NBT_TYPE_INT_ARRAY, "IntArray"), 18 | LONG_ARRAY(12, ModConstants.NBT_TYPE_LONG_ARRAY, "LongArray"), 19 | ; 20 | 21 | private final int id; 22 | private final Component name; 23 | private final String tagName; 24 | 25 | NbtType(int id, String name, String tagName) { 26 | this.id = id; 27 | this.name = Component.translatable(name); 28 | this.tagName = tagName; 29 | } 30 | 31 | public int getId() { 32 | return id; 33 | } 34 | 35 | public Component getName() { 36 | return name; 37 | } 38 | 39 | public String getTagName() { 40 | return tagName; 41 | } 42 | 43 | public static NbtType of(int id) { 44 | for (var v : values()) { 45 | if (v.getId() == id) { 46 | return v; 47 | } 48 | } 49 | 50 | return BYTE; 51 | } 52 | 53 | public static NbtType ofButtonId(int id) { 54 | return of(id + 1); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/NodeParser.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import net.minecraft.nbt.*; 4 | 5 | import java.util.Locale; 6 | 7 | /** 8 | * Parse string with silent exception. 9 | */ 10 | public class NodeParser { 11 | 12 | public static String getString(NbtTree.Node node) { 13 | var tag = node.getTag(); 14 | 15 | if (tag instanceof ByteTag b) { 16 | return Byte.toString(b.getAsByte()); 17 | } 18 | 19 | if (tag instanceof ShortTag s) { 20 | return Short.toString(s.getAsShort()); 21 | } 22 | 23 | if (tag instanceof IntTag i) { 24 | return Integer.toString(i.getAsInt()); 25 | } 26 | 27 | if (tag instanceof LongTag l) { 28 | return Long.toString(l.getAsLong()); 29 | } 30 | 31 | if (tag instanceof FloatTag f) { 32 | return Float.toString(f.getAsFloat()); 33 | } 34 | 35 | if (tag instanceof DoubleTag d) { 36 | return Double.toString(d.getAsDouble()); 37 | } 38 | 39 | if (tag instanceof StringTag s) { 40 | return s.getAsString(); 41 | } 42 | 43 | if (tag instanceof ByteArrayTag ba) { 44 | var s = new StringBuilder(); 45 | for (var b : ba.getAsByteArray()) { 46 | s.append(b).append(", "); 47 | } 48 | return s.toString(); 49 | } 50 | 51 | if (tag instanceof IntArrayTag ia) { 52 | var s = new StringBuilder(); 53 | for (var i : ia.getAsIntArray()) { 54 | s.append(i).append(", "); 55 | } 56 | return s.toString(); 57 | } 58 | 59 | if (tag instanceof LongArrayTag la) { 60 | var s = new StringBuilder(); 61 | for (var l : la.getAsLongArray()) { 62 | s.append(l).append(", "); 63 | } 64 | return s.toString(); 65 | } 66 | 67 | // List or Compound, returns empty. 68 | return ""; 69 | } 70 | 71 | public static Tag getTag(NbtTree.Node node, String value) { 72 | Tag tag = node.getTag(); 73 | try { 74 | if (tag instanceof ByteTag) { 75 | return ByteTag.valueOf(parseByte(value)); 76 | } 77 | if (tag instanceof ShortTag) { 78 | return ShortTag.valueOf(parseShort(value)); 79 | } 80 | if (tag instanceof IntTag) { 81 | return IntTag.valueOf(parseInt(value)); 82 | } 83 | if (tag instanceof LongTag) { 84 | return LongTag.valueOf(parseLong(value)); 85 | } 86 | if (tag instanceof FloatTag) { 87 | return FloatTag.valueOf(parseFloat(value)); 88 | } 89 | if (tag instanceof DoubleTag) { 90 | return DoubleTag.valueOf(parseDouble(value)); 91 | } 92 | if (tag instanceof ByteArrayTag) { 93 | return new ByteArrayTag(parseByteArray(value)); 94 | } 95 | if (tag instanceof IntArrayTag) { 96 | return new IntArrayTag(parseIntArray(value)); 97 | } 98 | if (tag instanceof LongArrayTag) { 99 | return new LongArrayTag(parseLongArray(value)); 100 | } 101 | if (tag instanceof StringTag) { 102 | return StringTag.valueOf(value); 103 | } 104 | } catch (Exception ignored) { 105 | } 106 | 107 | return EndTag.INSTANCE; 108 | } 109 | 110 | public static byte parseByte(String s) { 111 | try { 112 | var c = s.toLowerCase(Locale.ROOT); 113 | if (c.endsWith("b")) { 114 | c = c.substring(0, c.length() - 1); 115 | } 116 | return Byte.parseByte(c); 117 | } catch (NumberFormatException e) { 118 | return 0; 119 | } 120 | } 121 | 122 | public static short parseShort(String s) { 123 | try { 124 | var c = s.toLowerCase(Locale.ROOT); 125 | if (c.endsWith("s")) { 126 | c = c.substring(0, c.length() - 1); 127 | } 128 | return Short.parseShort(c); 129 | } catch (NumberFormatException e) { 130 | return 0; 131 | } 132 | } 133 | 134 | public static int parseInt(String s) { 135 | try { 136 | return Integer.parseInt(s); 137 | } catch (NumberFormatException e) { 138 | return 0; 139 | } 140 | } 141 | 142 | public static long parseLong(String s) { 143 | try { 144 | var c = s.toLowerCase(Locale.ROOT); 145 | if (c.endsWith("l")) { 146 | c = c.substring(0, c.length() - 1); 147 | } 148 | return Long.parseLong(c); 149 | } catch (NumberFormatException e) { 150 | return 0; 151 | } 152 | } 153 | 154 | public static float parseFloat(String s) { 155 | try { 156 | var c = s.toLowerCase(Locale.ROOT); 157 | if (c.endsWith("f")) { 158 | c = c.substring(0, c.length() - 1); 159 | } 160 | return Float.parseFloat(c); 161 | } catch (NumberFormatException e) { 162 | return 0; 163 | } 164 | } 165 | 166 | public static double parseDouble(String s) { 167 | try { 168 | var c = s.toLowerCase(Locale.ROOT); 169 | if (c.endsWith("d")) { 170 | c = c.substring(0, c.length() - 1); 171 | } 172 | return Double.parseDouble(c); 173 | } catch (NumberFormatException e) { 174 | return 0; 175 | } 176 | } 177 | 178 | public static byte[] parseByteArray(String s) { 179 | try { 180 | var input = s.split(","); 181 | var arr = new byte[input.length]; 182 | for (int i = 0; i < input.length; ++i) { 183 | var c = input[i].toLowerCase(Locale.ROOT).strip(); 184 | if (c.endsWith("b")) { 185 | c = c.substring(0, c.length() - 1); 186 | } 187 | 188 | arr[i] = parseByte(c); 189 | } 190 | return arr; 191 | } catch (NumberFormatException e) { 192 | return new byte[] {0}; 193 | } 194 | } 195 | 196 | public static int[] parseIntArray(String s) { 197 | try { 198 | var input = s.split(","); 199 | var arr = new int[input.length]; 200 | for (int i = 0; i < input.length; ++i) { 201 | var c = input[i].strip(); 202 | arr[i] = parseInt(c); 203 | } 204 | return arr; 205 | } catch (NumberFormatException e) { 206 | return new int[] {0}; 207 | } 208 | } 209 | 210 | public static long[] parseLongArray(String s) throws NumberFormatException { 211 | try { 212 | var input = s.split(","); 213 | var arr = new long[input.length]; 214 | for (int i = 0; i < input.length; ++i) { 215 | var c = input[i].toLowerCase(Locale.ROOT).strip(); 216 | if (c.endsWith("l")) { 217 | c = c.substring(0, c.length() - 1); 218 | } 219 | arr[i] = parseInt(c); 220 | } 221 | return arr; 222 | } catch (NumberFormatException e) { 223 | throw new NumberFormatException("Not a valid long array"); 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/NodeSortHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import net.minecraft.nbt.CompoundTag; 4 | import net.minecraft.nbt.ListTag; 5 | 6 | import java.util.Comparator; 7 | 8 | public class NodeSortHelper implements Comparator> { 9 | private static NodeSortHelper INSTANCE; 10 | 11 | public static NodeSortHelper get() { 12 | if (INSTANCE == null) { 13 | return new NodeSortHelper(); 14 | } 15 | return INSTANCE; 16 | } 17 | 18 | public NodeSortHelper() { 19 | INSTANCE = this; 20 | } 21 | 22 | @Override 23 | public int compare(NbtTree.Node a, NbtTree.Node b) { 24 | var name1 = a.getName(); 25 | var name2 = b.getName(); 26 | var tag1 = a.getTag(); 27 | var tag2 = b.getTag(); 28 | if (tag1 instanceof CompoundTag || tag1 instanceof ListTag) { 29 | if (tag2 instanceof CompoundTag || tag2 instanceof ListTag) { 30 | int difference = tag1.getId() - tag2.getId(); 31 | return (difference == 0) ? name1.compareTo(name2) : difference; 32 | } 33 | return 1; 34 | } 35 | if (tag2 instanceof CompoundTag || tag2 instanceof ListTag) { 36 | return -1; 37 | } 38 | int difference = tag1.getId() - tag2.getId(); 39 | return (difference == 0) ? name1.compareTo(name2) : difference; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/editor/TagReadingHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.editor; 2 | 3 | import net.minecraft.nbt.*; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.item.ItemStack; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.UUID; 10 | 11 | /** 12 | * Client only. 13 | */ 14 | public class TagReadingHelper { 15 | public static @Nullable ItemStack tryReadItem(Player player, @Nullable Tag tag) { 16 | if (tag instanceof CompoundTag compoundTag) { 17 | try { 18 | var optional = ItemStack.CODEC 19 | .parse(player.registryAccess().createSerializationContext(NbtOps.INSTANCE), compoundTag) 20 | .result(); 21 | if (optional.isPresent()) { 22 | var itemStack = optional.get(); 23 | if (!itemStack.isEmpty()) { 24 | return itemStack; 25 | } 26 | } 27 | } catch (Exception ignored) { 28 | } 29 | } 30 | 31 | return null; 32 | } 33 | 34 | public static @Nullable UUID tryReadUuid(@Nullable Tag tag) { 35 | if (tag instanceof IntArrayTag intArrayTag) { 36 | try { 37 | return NbtUtils.loadUUID(intArrayTag); 38 | } catch (Exception ignored) { 39 | } 40 | } 41 | 42 | return null; 43 | } 44 | 45 | public static @Nullable Component tryReadText(Player player, @Nullable Tag tag) { 46 | if (tag instanceof StringTag stringTag) { 47 | try { 48 | return Component.Serializer.fromJson(stringTag.getAsString(), player.registryAccess()); 49 | } catch (Exception ignored) { 50 | } 51 | } 52 | 53 | return null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/AbstractComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.components.AbstractWidget; 5 | import net.minecraft.network.chat.Component; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.function.Consumer; 9 | 10 | public abstract class AbstractComponent extends AbstractWidget implements IComponent { 11 | 12 | @Nullable 13 | private IComposedComponent parent; 14 | 15 | public AbstractComponent(int x, int y, int width, int height, Component message) { 16 | super(x, y, width, height, message); 17 | } 18 | 19 | protected final Minecraft getMinecraft() { 20 | return Minecraft.getInstance(); 21 | } 22 | 23 | @Override 24 | public @Nullable IComposedComponent getParent() { 25 | return parent; 26 | } 27 | 28 | @Override 29 | public void setParent(@Nullable IComposedComponent parent) { 30 | this.parent = parent; 31 | } 32 | 33 | @Override 34 | public void visitWidgets(Consumer consumer) { 35 | consumer.accept(this); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/AbstractComposedComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import net.minecraft.client.gui.GuiGraphics; 4 | import net.minecraft.client.gui.components.events.ContainerEventHandler; 5 | import net.minecraft.client.gui.components.events.GuiEventListener; 6 | import net.minecraft.network.chat.Component; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public abstract class AbstractComposedComponent extends AbstractComponent implements IComposedComponent, ContainerEventHandler { 14 | private final List children = new ArrayList<>(); 15 | 16 | @Nullable 17 | private GuiEventListener focused; 18 | private boolean dragging; 19 | 20 | public AbstractComposedComponent(int x, int y, int width, int height, Component message) { 21 | super(x, y, width, height, message); 22 | } 23 | 24 | @Override 25 | public void addChild(@NotNull IComponent child) { 26 | children.add(child); 27 | child.setParent(this); 28 | } 29 | 30 | @Override 31 | public void removeChild(@NotNull IComponent child) { 32 | children.remove(child); 33 | child.setParent(null); 34 | } 35 | 36 | @Override 37 | public List getChildren() { 38 | return List.copyOf(children); 39 | } 40 | 41 | @Override 42 | public @NotNull List children() { 43 | return getChildren(); 44 | } 45 | 46 | @Override 47 | public boolean isDragging() { 48 | return dragging; 49 | } 50 | 51 | @Override 52 | public void setDragging(boolean dragging) { 53 | this.dragging = dragging; 54 | } 55 | 56 | @Nullable 57 | @Override 58 | public GuiEventListener getFocused() { 59 | return focused; 60 | } 61 | 62 | @Override 63 | public void setFocused(@Nullable GuiEventListener focused) { 64 | if (this.focused != null) { 65 | this.focused.setFocused(false); 66 | } 67 | 68 | if (focused != null) { 69 | focused.setFocused(true); 70 | } 71 | 72 | this.focused = focused; 73 | } 74 | 75 | @Override 76 | public void tick() { 77 | super.tick(); 78 | 79 | for (var child : getChildren()) { 80 | child.tick(); 81 | } 82 | } 83 | 84 | @Override 85 | public void update() { 86 | super.update(); 87 | 88 | for (var child : getChildren()) { 89 | child.update(); 90 | } 91 | } 92 | 93 | protected abstract void createChildren(); 94 | 95 | @Override 96 | public final void initialize() { 97 | createChildren(); 98 | 99 | for (var child : getChildren()) { 100 | child.initialize(); 101 | } 102 | 103 | super.initialize(); 104 | } 105 | 106 | @Override 107 | public void unInitialize() { 108 | for (var child : getChildren()) { 109 | child.unInitialize(); 110 | } 111 | 112 | clearChildren(); 113 | 114 | super.unInitialize(); 115 | } 116 | 117 | @Override 118 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 119 | return IComposedComponent.super.mouseClicked(mouseX, mouseY, button); 120 | } 121 | 122 | @Override 123 | public boolean mouseReleased(double mouseX, double mouseY, int button) { 124 | return IComposedComponent.super.mouseReleased(mouseX, mouseY, button); 125 | } 126 | 127 | @Override 128 | public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { 129 | return IComposedComponent.super.mouseDragged(mouseX, mouseY, button, dragX, dragY); 130 | } 131 | 132 | @Override 133 | public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) { 134 | return IComposedComponent.super.mouseScrolled(mouseX, mouseY, scrollX, scrollY); 135 | } 136 | 137 | @Override 138 | public boolean keyPressed(int keyCode, int scanCode, int modifiers) { 139 | return IComposedComponent.super.keyPressed(keyCode, scanCode, modifiers); 140 | } 141 | 142 | @Override 143 | public boolean keyReleased(int keyCode, int scanCode, int modifiers) { 144 | return IComposedComponent.super.keyReleased(keyCode, scanCode, modifiers); 145 | } 146 | 147 | @Override 148 | public boolean charTyped(char codePoint, int modifiers) { 149 | return IComposedComponent.super.charTyped(codePoint, modifiers); 150 | } 151 | 152 | @Override 153 | protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { 154 | for (var c : getChildren()) { 155 | c.render(guiGraphics, mouseX, mouseY, partialTick); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/ButtonComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import net.minecraft.client.gui.components.Button; 4 | import net.minecraft.client.gui.components.Tooltip; 5 | import net.minecraft.network.chat.Component; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class ButtonComponent extends Button implements IComponent { 9 | @Nullable 10 | private IComposedComponent parent; 11 | 12 | public ButtonComponent(int x, int y, int width, int height, Component message, OnPress onPress, CreateNarration createNarration) { 13 | super(x, y, width, height, message, onPress, createNarration); 14 | } 15 | 16 | @Override 17 | public @Nullable IComposedComponent getParent() { 18 | return parent; 19 | } 20 | 21 | @Override 22 | public void setParent(@Nullable IComposedComponent parent) { 23 | this.parent = parent; 24 | } 25 | 26 | public static Builder getBuilder(Component message, OnPress onPress) { 27 | return new Builder(message, onPress); 28 | } 29 | 30 | public static class Builder { 31 | private final Component message; 32 | private final OnPress onPress; 33 | @Nullable 34 | private Tooltip tooltip; 35 | private int x; 36 | private int y; 37 | private int width = 150; 38 | private int height = 20; 39 | private CreateNarration createNarration; 40 | 41 | public Builder(Component message, OnPress onPress) { 42 | this.createNarration = Button.DEFAULT_NARRATION; 43 | this.message = message; 44 | this.onPress = onPress; 45 | } 46 | 47 | public Builder pos(int x, int y) { 48 | this.x = x; 49 | this.y = y; 50 | return this; 51 | } 52 | 53 | public Builder width(int width) { 54 | this.width = width; 55 | return this; 56 | } 57 | 58 | public Builder size(int width, int height) { 59 | this.width = width; 60 | this.height = height; 61 | return this; 62 | } 63 | 64 | public Builder bounds(int x, int y, int width, int height) { 65 | return this.pos(x, y).size(width, height); 66 | } 67 | 68 | public Builder tooltip(@Nullable Tooltip tooltip) { 69 | this.tooltip = tooltip; 70 | return this; 71 | } 72 | 73 | public Builder createNarration(CreateNarration createNarration) { 74 | this.createNarration = createNarration; 75 | return this; 76 | } 77 | 78 | public ButtonComponent build() { 79 | var button = new ButtonComponent(this.x, this.y, this.width, this.height, this.message, this.onPress, this.createNarration); 80 | button.setTooltip(this.tooltip); 81 | return button; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/EditBoxComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import net.minecraft.client.gui.Font; 4 | import net.minecraft.client.gui.components.EditBox; 5 | import net.minecraft.network.chat.Component; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class EditBoxComponent extends EditBox implements IComponent { 9 | @Nullable 10 | private IComposedComponent parent; 11 | 12 | public EditBoxComponent(Font font, int x, int y, int width, int height, Component message) { 13 | super(font, x, y, width, height, message); 14 | } 15 | 16 | @Override 17 | public boolean isHovered() { 18 | return super.isHovered(); 19 | } 20 | 21 | @Override 22 | public @Nullable IComposedComponent getParent() { 23 | return parent; 24 | } 25 | 26 | @Override 27 | public void setParent(@Nullable IComposedComponent parent) { 28 | this.parent = parent; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/IComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import net.minecraft.client.gui.components.AbstractWidget; 4 | import net.minecraft.client.gui.components.Renderable; 5 | import net.minecraft.client.gui.components.events.GuiEventListener; 6 | import net.minecraft.client.gui.layouts.LayoutElement; 7 | import net.minecraft.client.gui.narration.NarratableEntry; 8 | import net.minecraft.client.gui.narration.NarrationElementOutput; 9 | import net.minecraft.client.gui.navigation.ScreenRectangle; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.function.Consumer; 14 | 15 | public interface IComponent extends Renderable, GuiEventListener, LayoutElement, NarratableEntry { 16 | default void tick() { 17 | } 18 | 19 | default void update() { 20 | } 21 | 22 | default void initialize() { 23 | } 24 | 25 | default void unInitialize() { 26 | } 27 | 28 | IComposedComponent getParent(); 29 | 30 | void setParent(@Nullable IComposedComponent parent); 31 | 32 | boolean isHovered(); 33 | 34 | @Override 35 | default void visitWidgets(Consumer consumer) { 36 | } 37 | 38 | @Override 39 | default @NotNull ScreenRectangle getRectangle() { 40 | return new ScreenRectangle(this.getX(), this.getY(), this.getWidth(), this.getHeight()); 41 | } 42 | 43 | @Override 44 | default @NotNull NarrationPriority narrationPriority() { 45 | if (this.isFocused()) { 46 | return NarrationPriority.FOCUSED; 47 | } else { 48 | return isHovered() ? NarrationPriority.HOVERED : NarrationPriority.NONE; 49 | } 50 | } 51 | 52 | @Override 53 | default void updateNarration(NarrationElementOutput narrationElementOutput) { 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/IComposedComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import net.minecraft.client.gui.components.events.ContainerEventHandler; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.List; 7 | 8 | public interface IComposedComponent extends IComponent, ContainerEventHandler { 9 | void addChild(@NotNull IComponent child); 10 | 11 | void removeChild(@NotNull IComponent child); 12 | 13 | List getChildren(); 14 | 15 | default void clearChildren() { 16 | for (var c : getChildren()) { 17 | c.setParent(null); 18 | removeChild(c); 19 | } 20 | } 21 | 22 | @Override 23 | default boolean mouseClicked(double mouseX, double mouseY, int button) { 24 | return ContainerEventHandler.super.mouseClicked(mouseX, mouseY, button); 25 | } 26 | 27 | @Override 28 | default boolean mouseReleased(double mouseX, double mouseY, int button) { 29 | return ContainerEventHandler.super.mouseReleased(mouseX, mouseY, button); 30 | } 31 | 32 | @Override 33 | default boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { 34 | return ContainerEventHandler.super.mouseDragged(mouseX, mouseY, button, dragX, dragY); 35 | } 36 | 37 | @Override 38 | default boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) { 39 | return ContainerEventHandler.super.mouseScrolled(mouseX, mouseY, scrollX, scrollY); 40 | } 41 | 42 | @Override 43 | default boolean keyPressed(int keyCode, int scanCode, int modifiers) { 44 | return ContainerEventHandler.super.keyPressed(keyCode, scanCode, modifiers); 45 | } 46 | 47 | @Override 48 | default boolean keyReleased(int keyCode, int scanCode, int modifiers) { 49 | return ContainerEventHandler.super.keyReleased(keyCode, scanCode, modifiers); 50 | } 51 | 52 | @Override 53 | default boolean charTyped(char codePoint, int modifiers) { 54 | return ContainerEventHandler.super.charTyped(codePoint, modifiers); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/IScrollHandler.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | @FunctionalInterface 4 | public interface IScrollHandler { 5 | void onScroll(int offset); 6 | } 7 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/component/ScrollBar.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.component; 2 | 3 | import cx.rain.mc.nbtedit.utility.ModConstants; 4 | import net.minecraft.client.gui.GuiGraphics; 5 | import net.minecraft.client.gui.components.WidgetSprites; 6 | import net.minecraft.client.gui.narration.NarratedElementType; 7 | import net.minecraft.client.gui.narration.NarrationElementOutput; 8 | import net.minecraft.client.renderer.RenderType; 9 | import net.minecraft.network.chat.Component; 10 | import net.minecraft.resources.ResourceLocation; 11 | import net.minecraft.util.Mth; 12 | import org.lwjgl.glfw.GLFW; 13 | 14 | public class ScrollBar extends AbstractComponent { 15 | private static final WidgetSprites BACKGROUND_SPRITES = new WidgetSprites(ResourceLocation.withDefaultNamespace("widget/text_field"), ResourceLocation.withDefaultNamespace("widget/text_field_highlighted")); 16 | private static final ResourceLocation SCROLLER_SPRITE = ResourceLocation.withDefaultNamespace("widget/scroller"); 17 | 18 | private final int scrollUnit = getMinecraft().font.lineHeight + 2; 19 | 20 | private final boolean horizontal; 21 | private final IScrollHandler toScroll; 22 | private final int contentLength; 23 | 24 | /** 25 | * Offset between scroll-base to the actual viewport start. 26 | * (In pixels.) 27 | */ 28 | private int scrollAmount = 0; 29 | private boolean dragging = false; 30 | 31 | public ScrollBar(int x, int y, int width, int height, IScrollHandler toScroll, int contentLength) { 32 | this(x, y, width, height, toScroll, contentLength, false); 33 | } 34 | 35 | public ScrollBar(int x, int y, int width, int height, IScrollHandler toScroll, int contentLength, boolean horizontal) { 36 | super(x, y, width, height, Component.translatable(ModConstants.GUI_TITLE_SCROLL_BAR)); 37 | 38 | this.horizontal = horizontal; 39 | this.toScroll = toScroll; 40 | this.contentLength = contentLength; 41 | } 42 | 43 | public boolean isHorizontal() { 44 | return horizontal; 45 | } 46 | 47 | public boolean isVertical() { 48 | return !horizontal; 49 | } 50 | 51 | public int getPrimaryStart() { 52 | if (isHorizontal()) { 53 | return getX(); 54 | } 55 | 56 | return getY(); 57 | } 58 | 59 | public int getPrimaryLength() { 60 | if (isHorizontal()) { 61 | return getWidth(); 62 | } 63 | 64 | return getHeight(); 65 | } 66 | 67 | /** 68 | * Get scroll rate (value between 0 ~ 1). 69 | * @return the scroll rate 70 | */ 71 | public double getScrollRate() { 72 | return Mth.clamp(((double) scrollAmount) / (contentLength - getPrimaryLength()), 0, 1); 73 | } 74 | 75 | /** 76 | * Set scroll rate (value between 0 ~ 1). 77 | * @param scrollRate the scroll rate 78 | */ 79 | public void setScrollRate(double scrollRate) { 80 | var actual = Mth.clamp(scrollRate, 0, 1); 81 | var newScrollAmount = (int) (actual * (contentLength - getPrimaryLength())); 82 | setScrollAmount(newScrollAmount); 83 | } 84 | 85 | private int getScrollBarLength() { 86 | return Mth.clamp((int)((float)(getPrimaryLength() * getPrimaryLength()) / (float)contentLength), 32, getPrimaryLength()); 87 | } 88 | 89 | private int getMaxScrollAmount() { 90 | return contentLength - getPrimaryLength(); 91 | } 92 | 93 | public int getScrollAmount() { 94 | return scrollAmount; 95 | } 96 | 97 | public void setScrollAmount(int amount) { 98 | scrollAmount = Mth.clamp(amount, 0, getMaxScrollAmount()); 99 | } 100 | 101 | private void addScrollAmount(int value) { 102 | setScrollAmount(getScrollAmount() + value); 103 | toScroll.onScroll(value); 104 | } 105 | 106 | @Override 107 | protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { 108 | ResourceLocation resourceLocation = BACKGROUND_SPRITES.get(false, false); 109 | guiGraphics.blitSprite(RenderType::guiTextured, resourceLocation, getX(), getY(), getWidth(), getHeight()); 110 | 111 | var barLength = this.getScrollBarLength(); 112 | var barOffset = (int) (getScrollRate() * (getPrimaryLength() - barLength)); 113 | 114 | if (isHorizontal()) { 115 | guiGraphics.blitSprite(RenderType::guiTextured, SCROLLER_SPRITE, getX() + barOffset, getY(), barLength, getHeight()); 116 | } else { 117 | guiGraphics.blitSprite(RenderType::guiTextured, SCROLLER_SPRITE, getX(), getY() + barOffset, getWidth(), barLength); 118 | } 119 | } 120 | 121 | @Override 122 | protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { 123 | narrationElementOutput.add(NarratedElementType.TITLE, Component.translatable(ModConstants.GUI_TITLE_SCROLL_BAR_NARRATION)); 124 | } 125 | 126 | public boolean isDragging() { 127 | return dragging; 128 | } 129 | 130 | @Override 131 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 132 | if (isMouseOver(mouseX, mouseY)) { 133 | dragging = true; 134 | return true; 135 | } 136 | 137 | return super.mouseClicked(mouseX, mouseY, button); 138 | } 139 | 140 | @Override 141 | public boolean mouseReleased(double mouseX, double mouseY, int button) { 142 | if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { 143 | dragging = false; 144 | } 145 | 146 | return super.mouseReleased(mouseX, mouseY, button); 147 | } 148 | 149 | @Override 150 | public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { 151 | if (isActive() && dragging) { 152 | var mousePrimary = isVertical() ? mouseY : mouseX; 153 | var dragPrimary = isVertical() ? dragY : dragX; 154 | 155 | if (mousePrimary < (double) getPrimaryStart()) { 156 | this.addScrollAmount(-scrollUnit); 157 | } else if (mousePrimary > (double)(getPrimaryStart() + getPrimaryLength())) { 158 | this.addScrollAmount(scrollUnit); 159 | } else { 160 | var d = Mth.clamp(this.getMaxScrollAmount() / (getPrimaryLength() - getScrollBarLength()), 0, 1); 161 | this.addScrollAmount((int) (dragPrimary * d)); 162 | } 163 | return true; 164 | } 165 | 166 | return false; 167 | } 168 | 169 | @Override 170 | public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) { 171 | var scrollPrimary = isVertical() ? scrollY : scrollX; 172 | addScrollAmount((int) (scrollUnit * -scrollPrimary)); 173 | 174 | return true; 175 | } 176 | 177 | @Override 178 | public boolean keyReleased(int keyCode, int scanCode, int modifiers) { 179 | if (isHoveredOrFocused()) { 180 | if (keyCode == GLFW.GLFW_KEY_UP) { 181 | addScrollAmount(-scrollUnit); 182 | return true; 183 | } else if (keyCode == GLFW.GLFW_KEY_DOWN) { 184 | addScrollAmount(scrollUnit); 185 | return true; 186 | } 187 | } 188 | 189 | return super.keyReleased(keyCode, scanCode, modifiers); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/editor/EditingWindow.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.editor; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.editor.NbtTree; 5 | import cx.rain.mc.nbtedit.editor.NodeParser; 6 | import cx.rain.mc.nbtedit.editor.TagReadingHelper; 7 | import cx.rain.mc.nbtedit.gui.component.ButtonComponent; 8 | import cx.rain.mc.nbtedit.gui.component.EditBoxComponent; 9 | import cx.rain.mc.nbtedit.gui.window.AbstractWindow; 10 | import cx.rain.mc.nbtedit.gui.window.IWindowHolder; 11 | import cx.rain.mc.nbtedit.utility.ModConstants; 12 | import net.minecraft.client.gui.GuiGraphics; 13 | import net.minecraft.client.gui.narration.NarratedElementType; 14 | import net.minecraft.client.gui.narration.NarrationElementOutput; 15 | import net.minecraft.client.renderer.RenderType; 16 | import net.minecraft.nbt.NbtUtils; 17 | import net.minecraft.network.chat.Component; 18 | import net.minecraft.resources.ResourceLocation; 19 | import org.lwjgl.glfw.GLFW; 20 | 21 | import java.util.UUID; 22 | 23 | public class EditingWindow extends AbstractWindow { 24 | public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "window"); 25 | public static final int WIDTH = 178; 26 | public static final int HEIGHT = 93; 27 | 28 | private final NbtTree.Node node; 29 | private final boolean nameEditable; 30 | private final boolean valueEditable; 31 | 32 | private EditBoxComponent nameField; 33 | private EditBoxComponent valueField; 34 | 35 | private boolean parseAsUuid = false; 36 | 37 | public EditingWindow(int x, int y, NbtTree.Node node, boolean nameEditable, boolean valueEditable) { 38 | super(x, y, WIDTH, HEIGHT, Component.translatable(ModConstants.GUI_TITLE_EDITING_WINDOW)); 39 | 40 | this.node = node; 41 | this.nameEditable = nameEditable; 42 | this.valueEditable = valueEditable; 43 | } 44 | 45 | @Override 46 | public void tick() { 47 | super.tick(); 48 | 49 | if (nameEditable && nameField != null) { 50 | nameField.tick(); 51 | } 52 | 53 | if (valueEditable && valueField != null) { 54 | valueField.tick(); 55 | } 56 | } 57 | 58 | @Override 59 | protected void createChildren() { 60 | var name = (nameField == null) ? node.getName() : nameField.getValue(); 61 | var value = (valueField == null) ? NodeParser.getString(node) : valueField.getValue(); 62 | 63 | var uuid = TagReadingHelper.tryReadUuid(node.getTag()); 64 | if (uuid != null) { 65 | value = uuid.toString(); 66 | parseAsUuid = true; 67 | } 68 | 69 | clearChildren(); 70 | 71 | nameField = new EditBoxComponent(getMinecraft().font, getX() + 47, getY() + 20, 116, 15, 72 | Component.translatable(ModConstants.GUI_EDIT_BOX_NAME)); 73 | nameField.setMaxLength(Integer.MAX_VALUE); 74 | nameField.setValue(name); 75 | nameField.setEditable(nameEditable); 76 | nameField.active = nameEditable; 77 | nameField.setBordered(false); 78 | addChild(nameField); 79 | 80 | valueField = new EditBoxComponent(getMinecraft().font, getX() + 47, getY() + 46, 116, 15, 81 | Component.translatable(ModConstants.GUI_EDIT_BOX_VALUE)); 82 | valueField.setMaxLength(Integer.MAX_VALUE); 83 | valueField.setValue(value); 84 | valueField.setEditable(valueEditable); 85 | valueField.active = valueEditable; 86 | valueField.setBordered(false); 87 | addChild(valueField); 88 | 89 | var saveButton = ButtonComponent.getBuilder(Component.translatable(ModConstants.GUI_BUTTON_OK), b -> onOk()) 90 | .pos(getX() + 9, getY() + 62) 91 | .size(75, 20) 92 | .createNarration(n -> Component.translatable(ModConstants.GUI_TOOLTIP_BUTTON_OK)) 93 | .build(); 94 | addChild(saveButton); 95 | 96 | var cancelButton = ButtonComponent.getBuilder(Component.translatable(ModConstants.GUI_BUTTON_CANCEL), b -> onCancel()) 97 | .pos(getX() + 93, getY() + 62) 98 | .size(75, 20) 99 | .createNarration(n -> Component.translatable(ModConstants.GUI_TOOLTIP_BUTTON_CANCEL)) 100 | .build(); 101 | addChild(cancelButton); 102 | } 103 | 104 | private void onOk() { 105 | if (nameEditable) { 106 | node.setName(nameField.getValue()); 107 | } 108 | 109 | if (valueEditable) { 110 | if (parseAsUuid) { 111 | try { 112 | var uuid = UUID.fromString(valueField.getValue()); 113 | node.setTag(NbtUtils.createUUID(uuid)); 114 | } catch (Exception ignored) { 115 | } 116 | } else { 117 | node.setTag(NodeParser.getTag(node, valueField.getValue())); 118 | } 119 | } 120 | 121 | onCancel(); 122 | } 123 | 124 | private void onCancel() { 125 | if (getParent() != null) { 126 | getParent().update(); 127 | 128 | if (getParent() instanceof IWindowHolder holder) { 129 | holder.closeWindow(this); 130 | } 131 | } 132 | } 133 | 134 | @Override 135 | protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { 136 | guiGraphics.blitSprite(RenderType::guiTextured, TEXTURE, getX(), getY(), getWidth(), getHeight()); 137 | 138 | if (!nameEditable) { 139 | guiGraphics.fill(getX() + 43, getY() + 16, getX() + 170, getY() + 31, 0x80000000); 140 | } 141 | 142 | if (!valueEditable) { 143 | guiGraphics.fill(getX() + 43, getY() + 43, getX() + 170, getY() + 59, 0x80000000); 144 | } 145 | 146 | super.renderWidget(guiGraphics, mouseX, mouseY, partialTick); 147 | } 148 | 149 | @Override 150 | protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { 151 | narrationElementOutput.add(NarratedElementType.TITLE, Component.translatable(ModConstants.GUI_TITLE_EDITING_WINDOW_NARRATION)); 152 | } 153 | 154 | @Override 155 | public boolean keyPressed(int keyCode, int scanCode, int modifiers) { 156 | if (keyCode == GLFW.GLFW_KEY_ESCAPE) { 157 | onCancel(); 158 | return true; 159 | } 160 | 161 | return super.keyPressed(keyCode, scanCode, modifiers); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/editor/EditorButtonComponent.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.editor; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.editor.EditorButton; 5 | import cx.rain.mc.nbtedit.gui.component.ButtonComponent; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.components.Tooltip; 8 | import net.minecraft.client.renderer.RenderType; 9 | import net.minecraft.network.chat.Component; 10 | import net.minecraft.resources.ResourceLocation; 11 | 12 | import java.time.Duration; 13 | 14 | public class EditorButtonComponent extends ButtonComponent { 15 | private final EditorButton button; 16 | 17 | public EditorButtonComponent(EditorButton id, int x, int y, Component message, OnPress onPressed) { 18 | super(x, y, 9, 9, message, onPressed, DEFAULT_NARRATION); 19 | 20 | button = id; 21 | } 22 | 23 | public void setActive(boolean active) { 24 | this.active = active; 25 | 26 | if (active) { 27 | setTooltip(Tooltip.create(getMessage(), createNarrationMessage())); 28 | setTooltipDelay(Duration.ofMillis(200)); 29 | } else { 30 | setTooltip(null); 31 | } 32 | } 33 | 34 | public boolean isHover(int mouseX, int mouseY) { 35 | return isActive() 36 | && mouseX >= getX() 37 | && mouseY >= getY() 38 | && mouseX < getX() + getWidth() 39 | && mouseY < getY() + getHeight(); 40 | } 41 | 42 | @Override 43 | protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { 44 | if (isHover(mouseX, mouseY)) { 45 | graphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0x80ffffff); 46 | } 47 | 48 | graphics.blitSprite(RenderType::guiTextured, button.getSprite(), getX(), getY(), getWidth(), getHeight()); 49 | 50 | if (!isActive()) { 51 | graphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0x80000000); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/editor/NbtTreeView.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.editor; 2 | 3 | import cx.rain.mc.nbtedit.editor.NbtTree; 4 | import cx.rain.mc.nbtedit.gui.component.AbstractComposedComponent; 5 | import cx.rain.mc.nbtedit.utility.ModConstants; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | import net.minecraft.client.gui.components.events.GuiEventListener; 9 | import net.minecraft.client.gui.narration.NarrationElementOutput; 10 | import net.minecraft.network.chat.Component; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.function.Consumer; 16 | 17 | public class NbtTreeView extends AbstractComposedComponent { 18 | 19 | private final List nodes = new ArrayList<>(); 20 | private final NbtTree tree; 21 | private final Consumer onFocusedUpdated; 22 | 23 | public NbtTreeView(NbtTree tree, int x, int y, Consumer onFocusedUpdated) { 24 | super(x, y, 100, 100, Component.translatable(ModConstants.GUI_TITLE_TREE_VIEW)); 25 | 26 | this.tree = tree; 27 | this.onFocusedUpdated = onFocusedUpdated; 28 | } 29 | 30 | @Override 31 | public void setFocused(@Nullable GuiEventListener focused) { 32 | super.setFocused(focused); 33 | 34 | if (focused instanceof NbtTreeViewNode) { 35 | onFocusedUpdated.accept(this); 36 | } 37 | } 38 | 39 | public @Nullable NbtTreeViewNode getFocusedChild() { 40 | if (getFocused() instanceof NbtTreeViewNode node) { 41 | return node; 42 | } 43 | 44 | return null; 45 | } 46 | 47 | public void setFocusedNode(@Nullable NbtTree.Node node) { 48 | setFocused(null); 49 | 50 | if (node != null) { 51 | for (var n : nodes) { 52 | if (n.getNode() == node) { 53 | setFocused(n); 54 | break; 55 | } 56 | } 57 | } 58 | } 59 | 60 | public @Nullable NbtTree.Node getFocusedNode() { 61 | var c = getFocusedChild(); 62 | return c != null ? c.getNode() : null; 63 | } 64 | 65 | public static final int START_X = 10; 66 | public static final int START_Y = 2; 67 | public static final int NODE_GAP_X = 10; 68 | public static final int NODE_GAP_Y = Minecraft.getInstance().font.lineHeight + 2; 69 | 70 | private int nodeOffsetX = 0; 71 | private int nodeOffsetY = 0; 72 | 73 | private int maxWidth = 0; 74 | private int maxHeight = 0; 75 | 76 | public void update(boolean callParent) { 77 | if (callParent) { 78 | getParent().update(); 79 | } else { 80 | update(); 81 | } 82 | } 83 | 84 | @Override 85 | public void update() { 86 | unInitialize(); 87 | initialize(); 88 | 89 | super.update(); 90 | } 91 | 92 | @Override 93 | protected void createChildren() { 94 | nodeOffsetX = START_X; 95 | nodeOffsetY = START_Y; 96 | maxWidth = 0; 97 | maxHeight = 0; 98 | 99 | addNodes(tree.getRoot()); 100 | setFocusedNode(getFocusedNode()); 101 | 102 | setWidth(maxWidth); 103 | setHeight(maxHeight); 104 | } 105 | 106 | @Override 107 | public void unInitialize() { 108 | nodes.clear(); 109 | 110 | super.unInitialize(); 111 | } 112 | 113 | private void addNodes(NbtTree.Node root) { 114 | var node = new NbtTreeViewNode(nodeOffsetX, nodeOffsetY, root, this); 115 | nodes.add(node); 116 | addChild(node); 117 | 118 | var w = node.getX() + node.getWidth(); 119 | if (w > maxWidth) { 120 | maxWidth = w; 121 | } 122 | 123 | var h = node.getY() + node.getHeight(); 124 | if (h > maxHeight) { 125 | maxHeight = h; 126 | } 127 | 128 | nodeOffsetY += NODE_GAP_Y; 129 | 130 | if (root.shouldShowChildren()) { 131 | nodeOffsetX += NODE_GAP_X; 132 | for (var child : root.getChildren()) { 133 | addNodes(child); 134 | } 135 | nodeOffsetX -= NODE_GAP_X; 136 | } 137 | } 138 | 139 | @Override 140 | protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/editor/NbtTreeViewNode.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.editor; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.editor.EditorButton; 5 | import cx.rain.mc.nbtedit.editor.NbtTree; 6 | import cx.rain.mc.nbtedit.editor.AccessibilityHelper; 7 | import cx.rain.mc.nbtedit.gui.component.AbstractComponent; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.gui.GuiGraphics; 10 | import net.minecraft.client.gui.narration.NarratedElementType; 11 | import net.minecraft.client.gui.narration.NarrationElementOutput; 12 | import net.minecraft.client.renderer.RenderType; 13 | import net.minecraft.network.chat.Component; 14 | import net.minecraft.resources.ResourceLocation; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.time.Duration; 18 | 19 | public class NbtTreeViewNode extends AbstractComponent { 20 | public static final ResourceLocation WIDGET_TEXTURE = 21 | ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "textures/gui/widgets.png"); 22 | 23 | public static final ResourceLocation ARROW_RIGHT = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/arrow_right"); 24 | public static final ResourceLocation ARROW_DOWN = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/arrow_down"); 25 | public static final ResourceLocation ARROW_RIGHT_HIGHLIGHTED = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/arrow_right_highlighted"); 26 | public static final ResourceLocation ARROW_DOWN_HIGHLIGHTED = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editor/arrow_down_highlighted"); 27 | 28 | private final NbtTreeView treeView; 29 | private final NbtTree.Node node; 30 | 31 | public NbtTreeViewNode(int x, int y, NbtTree.Node node, @NotNull NbtTreeView parent) { 32 | super(x, y, 0, Minecraft.getInstance().font.lineHeight, Component.empty()); 33 | 34 | this.treeView = parent; 35 | this.node = node; 36 | 37 | setMessage(AccessibilityHelper.buildText(node)); 38 | setWidth(getMinecraft().font.width(getMessage()) + 12); 39 | } 40 | 41 | @Override 42 | public void initialize() { 43 | super.initialize(); 44 | 45 | setTooltip(AccessibilityHelper.buildTooltip(getMinecraft().player, node)); 46 | setTooltipDelay(Duration.ofMillis(200)); 47 | } 48 | 49 | public NbtTreeView getParent() { 50 | return treeView; 51 | } 52 | 53 | public NbtTree.Node getNode() { 54 | return node; 55 | } 56 | 57 | public boolean isMouseInsideText(double mouseX, double mouseY) { 58 | return mouseX >= getX() && mouseY >= getY() && mouseX < getX() + getWidth() && mouseY < getY() + getHeight(); 59 | } 60 | 61 | public boolean isMouseInsideSpoiler(double mouseX, double mouseY) { 62 | return mouseX >= getX() - 9 && mouseY >= getY() && mouseX < getX() && mouseY < getY() + getHeight(); 63 | } 64 | 65 | @Override 66 | protected void updateWidgetNarration(NarrationElementOutput narration) { 67 | narration.add(NarratedElementType.TITLE, AccessibilityHelper.buildNarration(node)); 68 | } 69 | 70 | @Override 71 | public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { 72 | var isSelected = getParent().getFocusedNode() != null 73 | && getParent().getFocusedNode() == this.getNode(); 74 | var isTextHover = isMouseInsideText(mouseX, mouseY); 75 | var isSpoilerHover = isMouseInsideSpoiler(mouseX, mouseY); 76 | var color = isSelected ? 0xFFE0E0E0 : isTextHover ? 0xFFFFFFA0 : (node.hasParent()) ? 0xFFE0E0E0 : 0xFFA0A0A0; 77 | 78 | if (isSelected) { 79 | graphics.fill(getX() + 11, getY(), getX() + getWidth(), getY() + getHeight(), 0x80000000); 80 | } 81 | 82 | ResourceLocation arrowSprite; 83 | if (node.shouldShowChildren()) { 84 | if (isSpoilerHover) { 85 | arrowSprite = ARROW_DOWN_HIGHLIGHTED; 86 | } else { 87 | arrowSprite = ARROW_DOWN; 88 | } 89 | } else { 90 | if (isSpoilerHover) { 91 | arrowSprite = ARROW_RIGHT_HIGHLIGHTED; 92 | } else { 93 | arrowSprite = ARROW_RIGHT; 94 | } 95 | } 96 | 97 | if (node.hasChild()) { 98 | graphics.blitSprite(RenderType::guiTextured, arrowSprite, getX() - 9, getY(), 9, getHeight()); 99 | } 100 | 101 | var tagSprite = EditorButton.ofTag(node.getTag()).getSprite(); 102 | graphics.blitSprite(RenderType::guiTextured, tagSprite, getX() + 1, getY(), 9, getHeight()); 103 | graphics.drawString(getMinecraft().font, getMessage(), getX() + 11, getY() + (getHeight() - 8) / 2, color); 104 | } 105 | 106 | @Override 107 | public boolean isMouseOver(double mouseX, double mouseY) { 108 | return this.active 109 | && this.visible 110 | && (isMouseInsideText(mouseX, mouseY) || isMouseInsideSpoiler(mouseX, mouseY)); 111 | } 112 | 113 | @Override 114 | public void onClick(double mouseX, double mouseY) { 115 | if (isMouseInsideSpoiler(mouseX, mouseY)) { 116 | node.setShowChildren(!node.shouldShowChildren()); 117 | getParent().update(true); 118 | } 119 | 120 | if (isMouseInsideText(mouseX, mouseY)) { 121 | getParent().setFocused(this); 122 | getParent().update(true); 123 | } 124 | 125 | super.onClick(mouseX, mouseY); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/window/AbstractWindow.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.window; 2 | 3 | import cx.rain.mc.nbtedit.gui.component.AbstractComposedComponent; 4 | import net.minecraft.network.chat.Component; 5 | 6 | public abstract class AbstractWindow extends AbstractComposedComponent implements IWindow { 7 | public AbstractWindow(int x, int y, int width, int height, Component message) { 8 | super(x, y, width, height, message); 9 | } 10 | 11 | @Override 12 | public IWindowHolder getHolder() { 13 | return (IWindowHolder) getParent(); 14 | } 15 | 16 | @Override 17 | public void onOpen() { 18 | initialize(); 19 | } 20 | 21 | @Override 22 | public void onClose() { 23 | unInitialize(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/window/IWindow.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.window; 2 | 3 | import cx.rain.mc.nbtedit.gui.component.IComponent; 4 | 5 | public interface IWindow extends IComponent { 6 | default void onOpen() { 7 | } 8 | default void onClose() { 9 | } 10 | 11 | default void onShown() { 12 | } 13 | default void onHidden() { 14 | } 15 | 16 | IWindowHolder getHolder(); 17 | } 18 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/gui/window/IWindowHolder.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.gui.window; 2 | 3 | import cx.rain.mc.nbtedit.gui.component.IComposedComponent; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.List; 8 | 9 | public interface IWindowHolder extends IComposedComponent { 10 | @NotNull 11 | List getWindows(); 12 | void addWindow(@NotNull IWindow window, boolean mutex, boolean show); 13 | void closeWindow(@NotNull IWindow window); 14 | 15 | void show(@NotNull IWindow window); 16 | void hide(@NotNull IWindow window); 17 | 18 | @Nullable 19 | IWindow getMutexWindow(); 20 | void setMutexWindow(@Nullable IWindow window); 21 | @Nullable 22 | IWindow getFocusedWindow(); 23 | void setFocusedWindow(@Nullable IWindow window); 24 | 25 | default void addWindow(@NotNull IWindow window) { 26 | addWindow(window, false, true); 27 | } 28 | 29 | default boolean isFocused(@NotNull IWindow window) { 30 | return getFocusedWindow() == window; 31 | } 32 | 33 | default boolean isWindowMutex(@NotNull IWindow window) { 34 | return getMutexWindow() == window; 35 | } 36 | 37 | default boolean hasMutexWindow() { 38 | return getMutexWindow() != null; 39 | } 40 | 41 | default boolean hasWindow() { 42 | return !getWindows().isEmpty(); 43 | } 44 | 45 | default boolean hasWindow(@NotNull IWindow window) { 46 | return getWindows().contains(window); 47 | } 48 | 49 | default void closeWindows() { 50 | for (var window : getWindows()) { 51 | closeWindow(window); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/NetworkClientHandler.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking; 2 | 3 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 4 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 5 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 6 | import cx.rain.mc.nbtedit.networking.packet.s2c.RaytracePacket; 7 | import cx.rain.mc.nbtedit.utility.ModConstants; 8 | import cx.rain.mc.nbtedit.utility.RayTraceHelper; 9 | import cx.rain.mc.nbtedit.utility.ScreenHelper; 10 | import net.minecraft.ChatFormatting; 11 | import net.minecraft.client.Minecraft; 12 | import net.minecraft.client.player.LocalPlayer; 13 | import net.minecraft.network.chat.Component; 14 | 15 | public class NetworkClientHandler { 16 | 17 | private static LocalPlayer getPlayer() { 18 | return Minecraft.getInstance().player; 19 | } 20 | 21 | public static void handleRaytrace(RaytracePacket packet) { 22 | RayTraceHelper.doRayTrace(); 23 | } 24 | 25 | public static void handleBlockEntityEditing(BlockEntityEditingPacket packet) { 26 | var pos = packet.pos(); 27 | ScreenHelper.showNBTEditScreen(pos, packet.tag(), packet.readOnly()); 28 | } 29 | 30 | public static void handleEntityEditing(EntityEditingPacket packet) { 31 | ScreenHelper.showNBTEditScreen(packet.uuid(), packet.id(), packet.tag(), packet.readOnly()); 32 | } 33 | 34 | public static void handleItemStackEditing(ItemStackEditingPacket packet) { 35 | var stack = packet.itemStack(); 36 | ScreenHelper.showNBTEditScreen(stack, packet.tag(), packet.readOnly()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/NetworkEditingHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.NBTEditPlatform; 5 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 6 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 7 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 8 | import cx.rain.mc.nbtedit.utility.ModConstants; 9 | import net.minecraft.ChatFormatting; 10 | import net.minecraft.core.BlockPos; 11 | import net.minecraft.nbt.CompoundTag; 12 | import net.minecraft.network.chat.Component; 13 | import net.minecraft.server.level.ServerPlayer; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.ItemStack; 16 | 17 | import java.util.UUID; 18 | 19 | public class NetworkEditingHelper { 20 | public static void editBlockEntity(ServerPlayer player, BlockPos pos) { 21 | player.getServer().execute(() -> { 22 | if (!NetworkingHelper.checkReadPermission(player)) { 23 | return; 24 | } 25 | 26 | if (!NetworkingHelper.checkPosLoaded(player, pos)) { 27 | return; 28 | } 29 | 30 | NBTEdit.getInstance().getLogger().debug("Player {} requested BlockEntity at {} {} {}.", 31 | player.getName().getString(), pos.getX(), pos.getY(), pos.getZ()); 32 | 33 | var blockEntity = player.serverLevel().getBlockEntity(pos); 34 | if (blockEntity == null) { 35 | player.createCommandSourceStack().sendFailure(Component 36 | .translatable(ModConstants.MESSAGE_TARGET_IS_NOT_BLOCK_ENTITY) 37 | .withStyle(ChatFormatting.RED)); 38 | return; 39 | } 40 | 41 | player.sendSystemMessage(Component 42 | .translatable(ModConstants.MESSAGE_EDITING_BLOCK_ENTITY, pos.getX(), pos.getY(), pos.getZ()) 43 | .withStyle(ChatFormatting.GREEN)); 44 | 45 | var tag = blockEntity.saveWithFullMetadata(player.getServer().registryAccess()); 46 | NBTEditPlatform.getNetworking().sendTo(player, new BlockEntityEditingPacket(tag, NBTEditPlatform.getPermission().isReadOnly(player), pos)); 47 | }); 48 | } 49 | 50 | public static void editEntity(ServerPlayer player, UUID entityUuid) { 51 | player.getServer().execute(() -> { 52 | if (!NetworkingHelper.checkReadPermission(player)) { 53 | return; 54 | } 55 | 56 | var entity = player.serverLevel().getEntity(entityUuid); 57 | assert entity != null; 58 | 59 | if (entity instanceof Player 60 | && entity != player 61 | && !NetworkingHelper.checkEditOnPlayerPermission(player)) { 62 | NBTEdit.getInstance().getLogger().info("Player {} tried to use nbtedit on a player which is not allowed.", 63 | player.getName().getString()); 64 | return; 65 | } 66 | 67 | NBTEdit.getInstance().getLogger().debug("Player {} is editing entity {}.", 68 | player.getName().getString(), player == entity ? "themself" : entity.getUUID()); 69 | 70 | player.sendSystemMessage(Component 71 | .translatable(ModConstants.MESSAGE_EDITING_ENTITY, entityUuid.toString()) 72 | .withStyle(ChatFormatting.GREEN)); 73 | 74 | var tag = new CompoundTag(); 75 | if (entity instanceof Player) { 76 | entity.saveWithoutId(tag); 77 | } else { 78 | entity.saveAsPassenger(tag); 79 | } 80 | NBTEditPlatform.getNetworking().sendTo(player, new EntityEditingPacket(tag, NBTEditPlatform.getPermission().isReadOnly(player), entity.getUUID(), entity.getId())); 81 | }); 82 | } 83 | 84 | public static void editItemStack(ServerPlayer player, ItemStack stack) { 85 | player.getServer().execute(() -> { 86 | if (!NetworkingHelper.checkReadPermission(player)) { 87 | return; 88 | } 89 | 90 | if (stack.isEmpty()) { 91 | player.sendSystemMessage(Component.literal(ModConstants.MESSAGE_NOTHING_TO_EDIT).withStyle(ChatFormatting.RED)); 92 | return; 93 | } 94 | 95 | NBTEdit.getInstance().getLogger().debug("Player {} is editing ItemStack named {}.", 96 | player.getName().getString(), stack.getDisplayName().getString()); 97 | 98 | player.sendSystemMessage(Component 99 | .translatable(ModConstants.MESSAGE_EDITING_ITEM_STACK, stack.getDisplayName().getString()) 100 | .withStyle(ChatFormatting.GREEN)); 101 | 102 | var tag = (CompoundTag) stack.saveOptional(player.getServer().registryAccess()); 103 | NBTEditPlatform.getNetworking().sendTo(player, new ItemStackEditingPacket(tag, NBTEditPlatform.getPermission().isReadOnly(player), stack)); 104 | }); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/NetworkingConstants.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import io.netty.buffer.ByteBuf; 5 | import net.minecraft.nbt.CompoundTag; 6 | import net.minecraft.nbt.NbtAccounter; 7 | import net.minecraft.network.codec.ByteBufCodecs; 8 | import net.minecraft.network.codec.StreamCodec; 9 | import net.minecraft.resources.ResourceLocation; 10 | 11 | public class NetworkingConstants { 12 | // TAG Codec, 128M is the maximum size of NBT Tag that I can imagine. 13 | public static final StreamCodec TAG = ByteBufCodecs.compoundTagCodec(() -> new NbtAccounter(128_000_000L, 512)); 14 | 15 | // Common 16 | public static final ResourceLocation BLOCK_ENTITY_EDITING_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "block_entity_editing"); 17 | public static final ResourceLocation ENTITY_EDITING_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "entity_editing"); 18 | public static final ResourceLocation ITEM_STACK_EDITING_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "item_stack_editing"); 19 | 20 | // C2S 21 | public static final ResourceLocation BLOCK_ENTITY_RAYTRACE_RESULT_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "block_entity_raytrace_result"); 22 | public static final ResourceLocation ENTITY_RAYTRACE_RESULT_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "entity_raytrace_result"); 23 | public static final ResourceLocation ITEM_STACK_RAYTRACE_RESULT_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "item_stack_raytrace_result"); 24 | 25 | // S2C 26 | public static final ResourceLocation RAYTRACE_REQUEST_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "raytrace_request"); 27 | } 28 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/NetworkingHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking; 2 | 3 | import cx.rain.mc.nbtedit.NBTEditPlatform; 4 | import cx.rain.mc.nbtedit.utility.ModConstants; 5 | import net.minecraft.ChatFormatting; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.network.chat.Component; 8 | import net.minecraft.server.level.ServerPlayer; 9 | 10 | public class NetworkingHelper { 11 | public static boolean checkReadPermission(ServerPlayer player) { 12 | var result = NBTEditPlatform.getPermission().canOpenEditor(player); 13 | 14 | if (!result) { 15 | player.sendSystemMessage(Component.translatable(ModConstants.MESSAGE_NO_PERMISSION) 16 | .withStyle(ChatFormatting.RED)); 17 | } 18 | 19 | return result; 20 | } 21 | 22 | public static boolean checkWritePermission(ServerPlayer player) { 23 | var result = NBTEditPlatform.getPermission().canSave(player); 24 | 25 | if (!result) { 26 | player.sendSystemMessage(Component.translatable(ModConstants.MESSAGE_NO_PERMISSION) 27 | .withStyle(ChatFormatting.RED)); 28 | } 29 | 30 | return result; 31 | } 32 | 33 | public static boolean checkEditOnPlayerPermission(ServerPlayer player) { 34 | var result = NBTEditPlatform.getPermission().canEditOnPlayer(player); 35 | 36 | if (!result) { 37 | player.sendSystemMessage(Component.translatable(ModConstants.MESSAGE_CANNOT_EDIT_OTHER_PLAYER) 38 | .withStyle(ChatFormatting.RED)); 39 | } 40 | 41 | return result; 42 | } 43 | 44 | public static boolean checkPosLoaded(ServerPlayer player, BlockPos pos) { 45 | var result = player.serverLevel().isLoaded(pos); 46 | 47 | if (!result) { 48 | player.sendSystemMessage(Component.translatable(ModConstants.MESSAGE_NOT_LOADED) 49 | .withStyle(ChatFormatting.RED)); 50 | } 51 | 52 | return result; 53 | } 54 | 55 | public static boolean isDebug() { 56 | return NBTEditPlatform.getConfig().isDebug(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/c2s/BlockEntityRaytraceResultPacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.c2s; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.network.RegistryFriendlyByteBuf; 6 | import net.minecraft.network.codec.StreamCodec; 7 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public record BlockEntityRaytraceResultPacket(BlockPos pos) implements CustomPacketPayload { 11 | public static final Type TYPE = new Type<>(NetworkingConstants.BLOCK_ENTITY_RAYTRACE_RESULT_ID); 12 | public static final StreamCodec CODEC = StreamCodec.composite( 13 | BlockPos.STREAM_CODEC, BlockEntityRaytraceResultPacket::pos, 14 | BlockEntityRaytraceResultPacket::new 15 | ); 16 | 17 | @Override 18 | public @NotNull Type type() { 19 | return TYPE; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/c2s/EntityRaytraceResultPacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.c2s; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.core.UUIDUtil; 5 | import net.minecraft.network.RegistryFriendlyByteBuf; 6 | import net.minecraft.network.codec.ByteBufCodecs; 7 | import net.minecraft.network.codec.StreamCodec; 8 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.UUID; 12 | 13 | public record EntityRaytraceResultPacket(UUID uuid, int id) implements CustomPacketPayload { 14 | public static final Type TYPE = new Type<>(NetworkingConstants.ENTITY_RAYTRACE_RESULT_ID); 15 | public static final StreamCodec CODEC = StreamCodec.composite( 16 | UUIDUtil.STREAM_CODEC, EntityRaytraceResultPacket::uuid, 17 | ByteBufCodecs.VAR_INT, EntityRaytraceResultPacket::id, 18 | EntityRaytraceResultPacket::new 19 | ); 20 | 21 | @Override 22 | public @NotNull Type type() { 23 | return TYPE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/c2s/ItemStackRaytraceResultPacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.c2s; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.network.RegistryFriendlyByteBuf; 5 | import net.minecraft.network.codec.StreamCodec; 6 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 7 | import net.minecraft.world.item.ItemStack; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public record ItemStackRaytraceResultPacket(ItemStack itemStack) implements CustomPacketPayload { 11 | public static final Type TYPE = new Type<>(NetworkingConstants.ITEM_STACK_RAYTRACE_RESULT_ID); 12 | public static final StreamCodec CODEC = StreamCodec.composite( 13 | ItemStack.STREAM_CODEC, ItemStackRaytraceResultPacket::itemStack, 14 | ItemStackRaytraceResultPacket::new 15 | ); 16 | 17 | @Override 18 | public @NotNull Type type() { 19 | return TYPE; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/common/BlockEntityEditingPacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.common; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.nbt.CompoundTag; 6 | import net.minecraft.network.RegistryFriendlyByteBuf; 7 | import net.minecraft.network.codec.ByteBufCodecs; 8 | import net.minecraft.network.codec.StreamCodec; 9 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public record BlockEntityEditingPacket(CompoundTag tag, boolean readOnly, BlockPos pos) implements CustomPacketPayload { 13 | public static final Type TYPE = new Type<>(NetworkingConstants.BLOCK_ENTITY_EDITING_ID); 14 | public static final StreamCodec CODEC = StreamCodec.composite( 15 | NetworkingConstants.TAG, BlockEntityEditingPacket::tag, 16 | ByteBufCodecs.BOOL, BlockEntityEditingPacket::readOnly, 17 | BlockPos.STREAM_CODEC, BlockEntityEditingPacket::pos, 18 | BlockEntityEditingPacket::new 19 | ); 20 | 21 | @Override 22 | public @NotNull Type type() { 23 | return TYPE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/common/EntityEditingPacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.common; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.core.UUIDUtil; 5 | import net.minecraft.nbt.CompoundTag; 6 | import net.minecraft.network.RegistryFriendlyByteBuf; 7 | import net.minecraft.network.codec.ByteBufCodecs; 8 | import net.minecraft.network.codec.StreamCodec; 9 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.UUID; 13 | 14 | public record EntityEditingPacket(CompoundTag tag, boolean readOnly, UUID uuid, int id) implements CustomPacketPayload { 15 | public static final Type TYPE = new Type<>(NetworkingConstants.ENTITY_EDITING_ID); 16 | public static final StreamCodec CODEC = StreamCodec.composite( 17 | NetworkingConstants.TAG, EntityEditingPacket::tag, 18 | ByteBufCodecs.BOOL, EntityEditingPacket::readOnly, 19 | UUIDUtil.STREAM_CODEC, EntityEditingPacket::uuid, 20 | ByteBufCodecs.VAR_INT, EntityEditingPacket::id, 21 | EntityEditingPacket::new 22 | ); 23 | 24 | @Override 25 | public @NotNull Type type() { 26 | return TYPE; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/common/ItemStackEditingPacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.common; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.core.UUIDUtil; 5 | import net.minecraft.nbt.CompoundTag; 6 | import net.minecraft.network.RegistryFriendlyByteBuf; 7 | import net.minecraft.network.codec.ByteBufCodecs; 8 | import net.minecraft.network.codec.StreamCodec; 9 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 10 | import net.minecraft.world.item.ItemStack; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.UUID; 14 | 15 | public record ItemStackEditingPacket(CompoundTag tag, boolean readOnly, ItemStack itemStack) implements CustomPacketPayload { 16 | public static final Type TYPE = new Type<>(NetworkingConstants.ITEM_STACK_EDITING_ID); 17 | public static final StreamCodec CODEC = StreamCodec.composite( 18 | NetworkingConstants.TAG, ItemStackEditingPacket::tag, 19 | ByteBufCodecs.BOOL, ItemStackEditingPacket::readOnly, 20 | ItemStack.STREAM_CODEC, ItemStackEditingPacket::itemStack, 21 | ItemStackEditingPacket::new 22 | ); 23 | 24 | @Override 25 | public @NotNull Type type() { 26 | return TYPE; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/networking/packet/s2c/RaytracePacket.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.networking.packet.s2c; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkingConstants; 4 | import net.minecraft.network.RegistryFriendlyByteBuf; 5 | import net.minecraft.network.codec.StreamCodec; 6 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public record RaytracePacket() implements CustomPacketPayload { 10 | public static final Type TYPE = new Type<>(NetworkingConstants.RAYTRACE_REQUEST_ID); 11 | public static final StreamCodec CODEC = StreamCodec.of( 12 | (b, p) -> {}, (b) -> new RaytracePacket() 13 | ); 14 | 15 | @Override 16 | public @NotNull Type type() { 17 | return TYPE; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/utility/ModConstants.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.utility; 2 | 3 | public class ModConstants { 4 | // Translation keys here. 5 | public static final String KEY_CATEGORY = "key.category.nbtedit"; 6 | public static final String KEY_NBTEDIT_SHORTCUT = "key.nbtedit.shortcut"; 7 | 8 | public static final String MESSAGE_NOT_PLAYER = "message.nbtedit.not_a_player"; 9 | public static final String MESSAGE_NO_PERMISSION = "message.nbtedit.no_permission"; 10 | public static final String MESSAGE_NOT_LOADED = "message.nbtedit.not_loaded"; 11 | public static final String MESSAGE_TARGET_IS_NOT_BLOCK_ENTITY = "message.nbtedit.target_is_not_block_entity"; 12 | public static final String MESSAGE_NOTHING_TO_EDIT = "message.nbtedit.nothing_to_edit"; 13 | public static final String MESSAGE_CANNOT_EDIT_OTHER_PLAYER = "message.nbtedit.cannot_edit_other_player"; 14 | public static final String MESSAGE_UNKNOWN_ENTITY_ID = "message.nbtedit.unknown_entity_id"; 15 | public static final String MESSAGE_EDITING_ENTITY = "message.nbtedit.editing.entity"; 16 | public static final String MESSAGE_EDITING_BLOCK_ENTITY = "message.nbtedit.editing.block_entity"; 17 | public static final String MESSAGE_EDITING_ITEM_STACK = "message.nbtedit.editing.item_stack"; 18 | public static final String MESSAGE_SAVING_SUCCESSFUL = "message.nbtedit.saved.successful"; 19 | public static final String MESSAGE_SAVING_FAILED_INVALID_NBT = "message.nbtedit.saving.failed.invalid_nbt"; 20 | public static final String MESSAGE_SAVING_FAILED_BLOCK_ENTITY_NOT_EXISTS = "message.nbtedit.saving.failed.block_entity_not_exists"; 21 | public static final String MESSAGE_SAVING_FAILED_ENTITY_NOT_EXISTS = "message.nbtedit.saving.failed.entity_not_exists"; 22 | 23 | public static final String NBT_TYPE_BYTE = "message.nbtedit.nbt_type.byte"; 24 | public static final String NBT_TYPE_SHORT = "message.nbtedit.nbt_type.short"; 25 | public static final String NBT_TYPE_INT = "message.nbtedit.nbt_type.int"; 26 | public static final String NBT_TYPE_LONG = "message.nbtedit.nbt_type.long"; 27 | public static final String NBT_TYPE_FLOAT = "message.nbtedit.nbt_type.float"; 28 | public static final String NBT_TYPE_DOUBLE = "message.nbtedit.nbt_type.double"; 29 | public static final String NBT_TYPE_BYTE_ARRAY = "message.nbtedit.nbt_type.byte_array"; 30 | public static final String NBT_TYPE_STRING = "message.nbtedit.nbt_type.string"; 31 | public static final String NBT_TYPE_LIST = "message.nbtedit.nbt_type.list"; 32 | public static final String NBT_TYPE_COMPOUND = "message.nbtedit.nbt_type.compound"; 33 | public static final String NBT_TYPE_INT_ARRAY = "message.nbtedit.nbt_type.int_array"; 34 | public static final String NBT_TYPE_LONG_ARRAY = "message.nbtedit.nbt_type.long_array"; 35 | 36 | public static final String GUI_TITLE_EDITOR_READ_ONLY = "gui.nbtedit.title.editor.read_only"; 37 | public static final String GUI_TITLE_EDITOR_ENTITY = "gui.nbtedit.title.editor_entity"; 38 | public static final String GUI_TITLE_EDITOR_BLOCK_ENTITY = "gui.nbtedit.title.editor_block_entity"; 39 | public static final String GUI_TITLE_EDITOR_ITEM_STACK = "gui.nbtedit.title.editor_item_stack"; 40 | public static final String GUI_TITLE_EDITOR_ENTITY_NARRATION = "gui.nbtedit.title.editor_entity.narration"; 41 | public static final String GUI_TITLE_EDITOR_BLOCK_ENTITY_NARRATION = "gui.nbtedit.title.editor_block_entity.narration"; 42 | public static final String GUI_TITLE_EDITOR_ITEM_STACK_NARRATION = "gui.nbtedit.title.editor_item_stack.narration"; 43 | 44 | public static final String GUI_TITLE_TREE_VIEW = "gui.nbtedit.title.tree_view"; 45 | public static final String GUI_TITLE_TREE_VIEW_NODE = "gui.nbtedit.title.tree_view_node"; 46 | public static final String GUI_TITLE_TREE_VIEW_NARRATION = "gui.nbtedit.title.tree_view.narration"; 47 | public static final String GUI_TITLE_TREE_VIEW_NODE_NARRATION = "gui.nbtedit.title.tree_view_node.narration"; 48 | public static final String GUI_TITLE_SCROLL_BAR = "gui.nbtedit.title.scroll_bar"; 49 | public static final String GUI_TITLE_SCROLL_BAR_NARRATION = "gui.nbtedit.title.scroll_bar.narration"; 50 | 51 | public static final String GUI_TITLE_EDITING_WINDOW = "gui.nbtedit.title.editing_window"; 52 | public static final String GUI_TITLE_EDITING_WINDOW_NARRATION = "gui.nbtedit.title.editing_window.narration"; 53 | public static final String GUI_LABEL_NAME = "gui.nbtedit.label.name"; 54 | public static final String GUI_LABEL_VALUE = "gui.nbtedit.label.value"; 55 | public static final String GUI_EDIT_BOX_NAME = "gui.nbtedit.edit_box.name"; 56 | public static final String GUI_EDIT_BOX_VALUE = "gui.nbtedit.edit_box.value"; 57 | 58 | public static final String GUI_BUTTON_COPY = "gui.nbtedit.button.copy"; 59 | public static final String GUI_BUTTON_PASTE = "gui.nbtedit.button.paste"; 60 | public static final String GUI_BUTTON_CUT = "gui.nbtedit.button.cut"; 61 | public static final String GUI_BUTTON_EDIT = "gui.nbtedit.button.edit"; 62 | public static final String GUI_BUTTON_DELETE = "gui.nbtedit.button.delete"; 63 | public static final String GUI_BUTTON_ADD = "gui.nbtedit.button.add"; 64 | public static final String GUI_BUTTON_SAVE = "gui.nbtedit.button.save"; 65 | public static final String GUI_BUTTON_QUIT = "gui.nbtedit.button.quit"; 66 | public static final String GUI_BUTTON_OK = "gui.nbtedit.button.ok"; 67 | public static final String GUI_BUTTON_CANCEL = "gui.nbtedit.button.cancel"; 68 | 69 | // Todo: unused 70 | public static final String GUI_TOOLTIP_BUTTON_COPY = "gui.nbtedit.tooltip.button_copy"; 71 | public static final String GUI_TOOLTIP_BUTTON_PASTE = "gui.nbtedit.tooltip.button_paste"; 72 | public static final String GUI_TOOLTIP_BUTTON_CUT = "gui.nbtedit.tooltip.button_cut"; 73 | public static final String GUI_TOOLTIP_BUTTON_EDIT = "gui.nbtedit.tooltip.button_edit"; 74 | public static final String GUI_TOOLTIP_BUTTON_DELETE = "gui.nbtedit.tooltip.button_delete"; 75 | public static final String GUI_TOOLTIP_BUTTON_ADD = "gui.nbtedit.tooltip.button_add"; 76 | 77 | public static final String GUI_TOOLTIP_BUTTON_SAVE = "gui.nbtedit.tooltip.button_save"; 78 | public static final String GUI_TOOLTIP_BUTTON_SAVE_DISABLED = "gui.nbtedit.tooltip.button_save.disabled"; 79 | public static final String GUI_TOOLTIP_BUTTON_QUIT = "gui.nbtedit.tooltip.button_quit"; 80 | public static final String GUI_TOOLTIP_BUTTON_OK = "gui.nbtedit.tooltip.button_ok"; 81 | public static final String GUI_TOOLTIP_BUTTON_CANCEL = "gui.nbtedit.tooltip.button_cancel"; 82 | 83 | public static final String GUI_TOOLTIP_PREVIEW_COMPONENT = "gui.nbtedit.tooltip.preview_component"; 84 | public static final String GUI_TOOLTIP_PREVIEW_ITEM = "gui.nbtedit.tooltip.preview_item"; 85 | public static final String GUI_TOOLTIP_PREVIEW_UUID = "gui.nbtedit.tooltip.preview_uuid"; 86 | public static final String GUI_TOOLTIP_PREVIEW_COMPONENT_NARRATION = "gui.nbtedit.tooltip.preview_component.narration"; 87 | public static final String GUI_TOOLTIP_PREVIEW_ITEM_NARRATION = "gui.nbtedit.tooltip.preview_item.narration"; 88 | public static final String GUI_TOOLTIP_PREVIEW_UUID_NARRATION = "gui.nbtedit.tooltip.preview_uuid.narration"; 89 | } 90 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/utility/RayTraceHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.utility; 2 | 3 | import cx.rain.mc.nbtedit.NBTEditPlatform; 4 | import cx.rain.mc.nbtedit.networking.packet.c2s.BlockEntityRaytraceResultPacket; 5 | import cx.rain.mc.nbtedit.networking.packet.c2s.EntityRaytraceResultPacket; 6 | import cx.rain.mc.nbtedit.networking.packet.c2s.ItemStackRaytraceResultPacket; 7 | import net.minecraft.ChatFormatting; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.network.chat.Component; 10 | import net.minecraft.world.phys.BlockHitResult; 11 | import net.minecraft.world.phys.EntityHitResult; 12 | import net.minecraft.world.phys.HitResult; 13 | 14 | public class RayTraceHelper { 15 | public static void doRayTrace() { 16 | var player = Minecraft.getInstance().player; 17 | var result = Minecraft.getInstance().hitResult; 18 | 19 | if (result != null) { 20 | if (result.getType() == HitResult.Type.BLOCK) { 21 | var block = (BlockHitResult) result; 22 | NBTEditPlatform.getNetworking().sendToServer(new BlockEntityRaytraceResultPacket(block.getBlockPos())); 23 | } else if (result.getType() == HitResult.Type.ENTITY) { 24 | var entity = ((EntityHitResult) result).getEntity(); 25 | NBTEditPlatform.getNetworking().sendToServer(new EntityRaytraceResultPacket(entity.getUUID(), entity.getId())); 26 | } else if (!player.getMainHandItem().isEmpty()) { 27 | NBTEditPlatform.getNetworking().sendToServer(new ItemStackRaytraceResultPacket(player.getMainHandItem())); 28 | } else { 29 | player.displayClientMessage(Component 30 | .translatable(ModConstants.MESSAGE_NOTHING_TO_EDIT) 31 | .withStyle(ChatFormatting.RED), false); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/java/cx/rain/mc/nbtedit/utility/ScreenHelper.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.utility; 2 | 3 | import cx.rain.mc.nbtedit.NBTEditPlatform; 4 | import cx.rain.mc.nbtedit.gui.EditorScreen; 5 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 6 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 7 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.core.BlockPos; 10 | import net.minecraft.nbt.CompoundTag; 11 | import net.minecraft.network.chat.Component; 12 | import net.minecraft.world.item.ItemStack; 13 | 14 | import java.util.UUID; 15 | 16 | public class ScreenHelper { 17 | public static void showNBTEditScreen(BlockPos pos, CompoundTag tag, boolean readOnly) { 18 | Minecraft.getInstance().setScreen(new EditorScreen(tag, 19 | Component.translatable(ModConstants.GUI_TITLE_EDITOR_BLOCK_ENTITY, pos.getX(), pos.getY(), pos.getZ()), 20 | newTag -> NBTEditPlatform.getNetworking().sendToServer(new BlockEntityEditingPacket(newTag, false, pos)), readOnly)); 21 | } 22 | 23 | public static void showNBTEditScreen(UUID uuid, int id, CompoundTag tag, boolean readOnly) { 24 | Minecraft.getInstance().setScreen(new EditorScreen(tag, 25 | Component.translatable(ModConstants.GUI_TITLE_EDITOR_ENTITY, uuid.toString()), 26 | newTag -> NBTEditPlatform.getNetworking().sendToServer(new EntityEditingPacket(newTag, false, uuid, id)), readOnly)); 27 | } 28 | 29 | public static void showNBTEditScreen(ItemStack itemStack, CompoundTag tag, boolean readOnly) { 30 | Minecraft.getInstance().setScreen(new EditorScreen(tag, 31 | Component.translatable(ModConstants.GUI_TITLE_EDITOR_ITEM_STACK, itemStack.getDisplayName().getString()), 32 | newTag -> NBTEditPlatform.getNetworking().sendToServer(new ItemStackEditingPacket(newTag, false, itemStack)), readOnly)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_down.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_down_highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_down_highlighted.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_right.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_right_highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/arrow_right_highlighted.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/copy.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/cut.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/delete.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/edit.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/editor/paste.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/byte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/byte.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/byte_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/byte_array.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/compound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/compound.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/double.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/double.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/float.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/float.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/int.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/int.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/int_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/int_array.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/list.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/long.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/long_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/long_array.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/short.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/short.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/tag_type/string.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/assets/nbtedit/textures/gui/sprites/window.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/build_info.properties: -------------------------------------------------------------------------------- 1 | build_version=${build_version} 2 | build_time=${build_time} 3 | -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-common/src/main/resources/logo.png -------------------------------------------------------------------------------- /nbtedit-common/src/main/resources/nbtedit.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v2 named 2 | accessible field net/minecraft/nbt/CompoundTag tags Ljava/util/Map; 3 | accessible field net/minecraft/nbt/ListTag list Ljava/util/List; 4 | accessible method net/minecraft/server/level/ServerPlayer initMenu (Lnet/minecraft/world/inventory/AbstractContainerMenu;)V 5 | #accessible field net/minecraft/client/gui/screens/Screen children Ljava/util/List; 6 | #accessible field net/minecraft/client/gui/screens/Screen renderables Ljava/util/List; 7 | -------------------------------------------------------------------------------- /nbtedit-fabric/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.gradleup.shadow' 3 | id 'me.shedaniel.unified-publishing' 4 | } 5 | 6 | architectury { 7 | platformSetupLoomIde() 8 | fabric() 9 | } 10 | 11 | loom { 12 | accessWidenerPath = project(':nbtedit-common').loom.accessWidenerPath 13 | } 14 | 15 | configurations { 16 | common { 17 | canBeResolved = true 18 | canBeConsumed = false 19 | } 20 | compileClasspath.extendsFrom common 21 | runtimeClasspath.extendsFrom common 22 | developmentFabric.extendsFrom common 23 | 24 | shadowBundle { 25 | canBeResolved = true 26 | canBeConsumed = false 27 | } 28 | } 29 | 30 | dependencies { 31 | modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" 32 | modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" 33 | 34 | modRuntimeOnly "com.terraformersmc:modmenu:${rootProject.mod_menu_version}" 35 | 36 | modCompileOnly "me.lucko:fabric-permissions-api:${rootProject.fabric_permission_api_version}" 37 | 38 | common(project(path: ':nbtedit-common', configuration: 'namedElements')) { transitive false } 39 | shadowBundle project(path: ':nbtedit-common', configuration: 'transformProductionFabric') 40 | } 41 | 42 | processResources { 43 | inputs.property 'build_version', project.version 44 | 45 | filesMatching('fabric.mod.json') { 46 | expand 'version': project.version 47 | } 48 | } 49 | 50 | shadowJar { 51 | exclude 'architectury.common.json' 52 | 53 | configurations = [project.configurations.shadowBundle] 54 | archiveClassifier = 'dev-shadow' 55 | } 56 | 57 | remapJar { 58 | injectAccessWidener = true 59 | input.set shadowJar.archiveFile 60 | dependsOn shadowJar 61 | } 62 | 63 | sourcesJar { 64 | def commonSources = project(':nbtedit-common').sourcesJar 65 | dependsOn commonSources 66 | from commonSources.archiveFile.map { zipTree(it) } 67 | } 68 | 69 | components.java { 70 | withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { 71 | skip() 72 | } 73 | } 74 | 75 | publishing { 76 | publications { 77 | mavenFabric(MavenPublication) { 78 | artifactId = project.name 79 | version = mavenVersion 80 | from components.java 81 | } 82 | } 83 | } 84 | 85 | unifiedPublishing { 86 | project { 87 | displayName = "NBTEdit Fabric ${project.minecraft_version}-${project.mod_version}" 88 | version = publishVersion 89 | gameVersions = [project.minecraft_version] 90 | gameLoaders = ['fabric'] 91 | releaseType = 'release' 92 | changelog = 'See the GitHub repository for more information. \nhttps://github.com/qyl27/NBTEdit' 93 | 94 | mainPublication tasks.remapJar 95 | 96 | relations { 97 | depends { 98 | curseforge = 'fabric-api' 99 | modrinth = 'fabric-api' 100 | } 101 | 102 | optional { 103 | curseforge = 'luckperms' 104 | modrinth = 'luckperms' 105 | } 106 | } 107 | 108 | curseforge { 109 | token = Objects.requireNonNullElse(System.getenv('CURSEFORGE_TOKEN'), "") 110 | id = '678133' 111 | } 112 | 113 | modrinth { 114 | token = Objects.requireNonNullElse(System.getenv('MODRINTH_TOKEN'), "") 115 | id = 'Vr2eDeCw' 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/NBTEditFabric.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.command.NBTEditCommand; 5 | import net.fabricmc.api.ModInitializer; 6 | import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public class NBTEditFabric implements ModInitializer { 11 | private static NBTEditFabric INSTANCE; 12 | 13 | private final Logger log = LoggerFactory.getLogger(this.getClass()); 14 | 15 | protected NBTEdit nbtedit; 16 | 17 | public NBTEditFabric() { 18 | INSTANCE = this; 19 | } 20 | 21 | public static NBTEditFabric getInstance() { 22 | return INSTANCE; 23 | } 24 | 25 | public Logger getLogger() { 26 | return log; 27 | } 28 | 29 | @Override 30 | public void onInitialize() { 31 | CommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess, environment) -> 32 | dispatcher.register(NBTEditCommand.NBTEDIT))); 33 | 34 | nbtedit = new NBTEdit(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/NBTEditFabricClient.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric; 2 | 3 | import com.mojang.blaze3d.platform.InputConstants; 4 | import cx.rain.mc.nbtedit.NBTEditPlatform; 5 | import cx.rain.mc.nbtedit.fabric.networking.ModNetworkingImpl; 6 | import cx.rain.mc.nbtedit.utility.ModConstants; 7 | import cx.rain.mc.nbtedit.utility.RayTraceHelper; 8 | import net.fabricmc.api.ClientModInitializer; 9 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 10 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 11 | import net.minecraft.client.KeyMapping; 12 | import org.lwjgl.glfw.GLFW; 13 | 14 | public class NBTEditFabricClient implements ClientModInitializer { 15 | private static final KeyMapping NBTEDIT_KEY = KeyBindingHelper.registerKeyBinding(new KeyMapping( 16 | ModConstants.KEY_NBTEDIT_SHORTCUT, 17 | InputConstants.Type.KEYSYM, 18 | GLFW.GLFW_KEY_N, 19 | ModConstants.KEY_CATEGORY)); 20 | 21 | @Override 22 | public void onInitializeClient() { 23 | ((ModNetworkingImpl) NBTEditPlatform.getNetworking()).addClient(); 24 | 25 | ClientTickEvents.END_CLIENT_TICK.register(client -> { 26 | while (NBTEDIT_KEY.consumeClick()) { 27 | RayTraceHelper.doRayTrace(); 28 | } 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/NBTEditPlatformImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.api.command.IModPermission; 5 | import cx.rain.mc.nbtedit.api.config.IModConfig; 6 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 7 | import cx.rain.mc.nbtedit.fabric.command.FabricPermissionApiImpl; 8 | import cx.rain.mc.nbtedit.fabric.command.VanillaPermissionImpl; 9 | import cx.rain.mc.nbtedit.fabric.config.ModConfigImpl; 10 | import cx.rain.mc.nbtedit.fabric.networking.ModNetworkingImpl; 11 | import net.fabricmc.loader.api.FabricLoader; 12 | 13 | public class NBTEditPlatformImpl { 14 | private static final ModNetworkingImpl NETWORKING = new ModNetworkingImpl(); 15 | 16 | private static final ModConfigImpl CONFIG; 17 | private static final IModPermission PERMISSION; 18 | 19 | static { 20 | CONFIG = new ModConfigImpl(FabricLoader.getInstance().getGameDir().toFile()); 21 | 22 | { 23 | IModPermission impl = null; 24 | try { 25 | if (FabricLoader.getInstance().isModLoaded("fabric-permissions-api-v0")) { 26 | impl = new FabricPermissionApiImpl(CONFIG); 27 | NBTEdit.getInstance().getLogger().info("Fabric Permissions API detected, using it."); 28 | } 29 | } catch (Throwable ignored) { 30 | } 31 | if (impl == null) { 32 | impl = new VanillaPermissionImpl(CONFIG); 33 | } 34 | PERMISSION = impl; 35 | } 36 | } 37 | 38 | public static IModNetworking getNetworking() { 39 | return NETWORKING; 40 | } 41 | 42 | public static IModConfig getConfig() { 43 | return CONFIG; 44 | } 45 | 46 | public static IModPermission getPermission() { 47 | return PERMISSION; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/command/FabricPermissionApiImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.command; 2 | 3 | import cx.rain.mc.nbtedit.api.command.IModPermission; 4 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 5 | import cx.rain.mc.nbtedit.fabric.config.ModConfigImpl; 6 | import me.lucko.fabric.api.permissions.v0.Permissions; 7 | import net.minecraft.commands.CommandSourceStack; 8 | import net.minecraft.server.level.ServerPlayer; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class FabricPermissionApiImpl implements IModPermission { 12 | private final ModConfigImpl config; 13 | 14 | public FabricPermissionApiImpl(ModConfigImpl config) { 15 | this.config = config; 16 | } 17 | 18 | @Override 19 | public boolean hasPermission(@NotNull CommandSourceStack sourceStack, @NotNull ModPermissions permission) { 20 | return Permissions.check(sourceStack, "nbtedit.%s".formatted(permission.getName()), config.getPermissionsLevel(permission)); 21 | } 22 | 23 | @Override 24 | public boolean hasPermission(@NotNull ServerPlayer player, @NotNull ModPermissions permission) { 25 | return Permissions.check(player, "nbtedit.%s".formatted(permission.getName()), config.getPermissionsLevel(permission)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/command/VanillaPermissionImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.command; 2 | 3 | import cx.rain.mc.nbtedit.api.command.IModPermission; 4 | import cx.rain.mc.nbtedit.fabric.config.ModConfigImpl; 5 | import net.minecraft.commands.CommandSourceStack; 6 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 7 | import net.minecraft.server.level.ServerPlayer; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class VanillaPermissionImpl implements IModPermission { 11 | private final ModConfigImpl config; 12 | 13 | public VanillaPermissionImpl(ModConfigImpl config) { 14 | this.config = config; 15 | } 16 | 17 | @Override 18 | public boolean hasPermission(@NotNull CommandSourceStack sourceStack, @NotNull ModPermissions permission) { 19 | return sourceStack.hasPermission(config.getPermissionsLevel(permission)); 20 | } 21 | 22 | @Override 23 | public boolean hasPermission(@NotNull ServerPlayer player, @NotNull ModPermissions permission) { 24 | return player.hasPermissions(config.getPermissionsLevel(permission)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/config/ConfigBean.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.config; 2 | 3 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class ConfigBean { 9 | public boolean debug = false; 10 | public Map permissionsLevels = new HashMap<>(); 11 | 12 | public ConfigBean() { 13 | for (var p : ModPermissions.values()) { 14 | permissionsLevels.put(p.getName(), p.getDefaultLevel()); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/config/ModConfigImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.config; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 6 | import cx.rain.mc.nbtedit.api.config.IModConfig; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.util.Map; 12 | 13 | public class ModConfigImpl implements IModConfig { 14 | public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 15 | 16 | protected File configDir; 17 | protected File configFile; 18 | protected ConfigBean config = new ConfigBean(); 19 | 20 | public ModConfigImpl(File gameDir) { 21 | configDir = new File(gameDir, "config"); 22 | configFile = new File(configDir, "nbtedit.json"); 23 | if (!configDir.exists()) { 24 | configDir.mkdirs(); 25 | } 26 | 27 | loadConfig(); 28 | } 29 | 30 | private void loadConfig() { 31 | if (configFile.exists()) { 32 | try { 33 | config = GSON.fromJson(Files.readString(configFile.toPath()), ConfigBean.class); 34 | } catch (IOException ex) { 35 | ex.printStackTrace(); 36 | } 37 | } 38 | 39 | saveConfig(); 40 | } 41 | 42 | private void saveConfig() { 43 | try { 44 | var json = GSON.toJson(config); 45 | Files.writeString(configFile.toPath(), json); 46 | } catch (IOException ex) { 47 | ex.printStackTrace(); 48 | } 49 | } 50 | 51 | @Override 52 | public boolean isDebug() { 53 | return config.debug; 54 | } 55 | 56 | public Map getPermissionsLevel() { 57 | return config.permissionsLevels; 58 | } 59 | 60 | public int getPermissionsLevel(ModPermissions permission) { 61 | return config.permissionsLevels.getOrDefault(permission.getName(), permission.getDefaultLevel()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/networking/ModNetworkingImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.networking; 2 | 3 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 4 | import cx.rain.mc.nbtedit.networking.NetworkEditingHelper; 5 | import cx.rain.mc.nbtedit.networking.NetworkServerHandler; 6 | import cx.rain.mc.nbtedit.networking.packet.c2s.BlockEntityRaytraceResultPacket; 7 | import cx.rain.mc.nbtedit.networking.packet.c2s.EntityRaytraceResultPacket; 8 | import cx.rain.mc.nbtedit.networking.packet.c2s.ItemStackRaytraceResultPacket; 9 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 10 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 11 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 12 | import cx.rain.mc.nbtedit.networking.packet.s2c.RaytracePacket; 13 | import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; 14 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 15 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 16 | import net.minecraft.server.level.ServerPlayer; 17 | 18 | public class ModNetworkingImpl implements IModNetworking { 19 | private NBTEditNetworkingClient client; 20 | 21 | public ModNetworkingImpl() { 22 | PayloadTypeRegistry.playS2C().register(RaytracePacket.TYPE, RaytracePacket.CODEC); 23 | PayloadTypeRegistry.playS2C().register(BlockEntityEditingPacket.TYPE, BlockEntityEditingPacket.CODEC); 24 | PayloadTypeRegistry.playS2C().register(EntityEditingPacket.TYPE, EntityEditingPacket.CODEC); 25 | PayloadTypeRegistry.playS2C().register(ItemStackEditingPacket.TYPE, ItemStackEditingPacket.CODEC); 26 | 27 | PayloadTypeRegistry.playC2S().register(BlockEntityRaytraceResultPacket.TYPE, BlockEntityRaytraceResultPacket.CODEC); 28 | PayloadTypeRegistry.playC2S().register(EntityRaytraceResultPacket.TYPE, EntityRaytraceResultPacket.CODEC); 29 | PayloadTypeRegistry.playC2S().register(ItemStackRaytraceResultPacket.TYPE, ItemStackRaytraceResultPacket.CODEC); 30 | PayloadTypeRegistry.playC2S().register(BlockEntityEditingPacket.TYPE, BlockEntityEditingPacket.CODEC); 31 | PayloadTypeRegistry.playC2S().register(EntityEditingPacket.TYPE, EntityEditingPacket.CODEC); 32 | PayloadTypeRegistry.playC2S().register(ItemStackEditingPacket.TYPE, ItemStackEditingPacket.CODEC); 33 | 34 | ServerPlayNetworking.registerGlobalReceiver(BlockEntityRaytraceResultPacket.TYPE, this::serverHandle); 35 | ServerPlayNetworking.registerGlobalReceiver(EntityRaytraceResultPacket.TYPE, this::serverHandle); 36 | ServerPlayNetworking.registerGlobalReceiver(ItemStackRaytraceResultPacket.TYPE, this::serverHandle); 37 | ServerPlayNetworking.registerGlobalReceiver(BlockEntityEditingPacket.TYPE, this::serverHandle); 38 | ServerPlayNetworking.registerGlobalReceiver(EntityEditingPacket.TYPE, this::serverHandle); 39 | ServerPlayNetworking.registerGlobalReceiver(ItemStackEditingPacket.TYPE, this::serverHandle); 40 | } 41 | 42 | public void addClient() { 43 | client = new NBTEditNetworkingClient(); 44 | } 45 | 46 | private void serverHandle(BlockEntityRaytraceResultPacket packet, ServerPlayNetworking.Context context) { 47 | context.player().getServer().execute(() -> NetworkServerHandler.handleBlockEntityResult(context.player(), packet)); 48 | } 49 | 50 | private void serverHandle(EntityRaytraceResultPacket packet, ServerPlayNetworking.Context context) { 51 | context.player().getServer().execute(() -> NetworkServerHandler.handleEntityResult(context.player(), packet)); 52 | } 53 | 54 | private void serverHandle(ItemStackRaytraceResultPacket packet, ServerPlayNetworking.Context context) { 55 | context.player().getServer().execute(() -> NetworkServerHandler.handleItemStackResult(context.player(), packet)); 56 | } 57 | 58 | private void serverHandle(BlockEntityEditingPacket packet, ServerPlayNetworking.Context context) { 59 | context.player().getServer().execute(() -> NetworkServerHandler.saveBlockEntity(context.player(), packet)); 60 | } 61 | 62 | private void serverHandle(EntityEditingPacket packet, ServerPlayNetworking.Context context) { 63 | context.player().getServer().execute(() -> NetworkServerHandler.saveEntity(context.player(), packet)); 64 | } 65 | 66 | private void serverHandle(ItemStackEditingPacket packet, ServerPlayNetworking.Context context) { 67 | context.player().getServer().execute(() -> NetworkServerHandler.saveItemStack(context.player(), packet)); 68 | } 69 | 70 | @Override 71 | public void sendTo(ServerPlayer player, CustomPacketPayload packet) { 72 | ServerPlayNetworking.send(player, packet); 73 | } 74 | 75 | @Override 76 | public void sendToServer(CustomPacketPayload packet) { 77 | if (client != null) { 78 | client.send(packet); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/networking/NBTEditNetworkingClient.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.networking; 2 | 3 | import cx.rain.mc.nbtedit.networking.NetworkClientHandler; 4 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 5 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 6 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 7 | import cx.rain.mc.nbtedit.networking.packet.s2c.RaytracePacket; 8 | import cx.rain.mc.nbtedit.utility.RayTraceHelper; 9 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 10 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 11 | 12 | public class NBTEditNetworkingClient { 13 | public NBTEditNetworkingClient() { 14 | ClientPlayNetworking.registerGlobalReceiver(RaytracePacket.TYPE, this::clientHandle); 15 | ClientPlayNetworking.registerGlobalReceiver(BlockEntityEditingPacket.TYPE, this::clientHandle); 16 | ClientPlayNetworking.registerGlobalReceiver(EntityEditingPacket.TYPE, this::clientHandle); 17 | ClientPlayNetworking.registerGlobalReceiver(ItemStackEditingPacket.TYPE, this::clientHandle); 18 | } 19 | 20 | private void clientHandle(RaytracePacket packet, ClientPlayNetworking.Context context) { 21 | context.client().execute(() -> NetworkClientHandler.handleRaytrace(packet)); 22 | } 23 | 24 | private void clientHandle(BlockEntityEditingPacket packet, ClientPlayNetworking.Context context) { 25 | context.client().execute(() -> NetworkClientHandler.handleBlockEntityEditing(packet)); 26 | } 27 | 28 | private void clientHandle(EntityEditingPacket packet, ClientPlayNetworking.Context context) { 29 | context.client().execute(() -> NetworkClientHandler.handleEntityEditing(packet)); 30 | } 31 | 32 | private void clientHandle(ItemStackEditingPacket packet, ClientPlayNetworking.Context context) { 33 | context.client().execute(() -> NetworkClientHandler.handleItemStackEditing(packet)); 34 | } 35 | 36 | public void send(CustomPacketPayload packet) { 37 | ClientPlayNetworking.send(packet); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/java/cx/rain/mc/nbtedit/fabric/networking/NBTEditNetworkingServer.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.fabric.networking; 2 | 3 | public class NBTEditNetworkingServer { 4 | 5 | public NBTEditNetworkingServer() { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "nbtedit", 4 | "version": "${mod_version}", 5 | "name": "${mod_full_name}", 6 | "description": "A Minecraft mod allows you edit any NBT tags of the game content while in game.", 7 | "authors": [ 8 | "qyl27" 9 | ], 10 | "contact": { 11 | "homepage": "https://github.com/qyl27/NBTEdit", 12 | "sources": "https://github.com/qyl27/NBTEdit", 13 | "issues": "https://github.com/qyl27/NBTEdit/issues" 14 | }, 15 | "icon": "logo-fabric.png", 16 | "license": "GPLv3", 17 | "environment": "*", 18 | "entrypoints": { 19 | "main": [ 20 | "cx.rain.mc.nbtedit.fabric.NBTEditFabric" 21 | ], 22 | "client": [ 23 | "cx.rain.mc.nbtedit.fabric.NBTEditFabricClient" 24 | ] 25 | }, 26 | "depends": { 27 | "fabric": "${fabric_api_version_range}", 28 | "fabricloader": "${fabric_loader_version_range}", 29 | "minecraft": "${fabric_minecraft_version_range}" 30 | }, 31 | "suggests": { 32 | "fabric-permissions-api-v0": "${fabric_permission_api_version_range}" 33 | } 34 | } -------------------------------------------------------------------------------- /nbtedit-fabric/src/main/resources/logo-fabric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-fabric/src/main/resources/logo-fabric.png -------------------------------------------------------------------------------- /nbtedit-forge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.gradleup.shadow' 3 | id 'me.shedaniel.unified-publishing' 4 | } 5 | 6 | architectury { 7 | platformSetupLoomIde() 8 | forge() 9 | } 10 | 11 | loom { 12 | accessWidenerPath = project(':nbtedit-common').loom.accessWidenerPath 13 | 14 | forge { 15 | convertAccessWideners = true 16 | extraAccessWideners.add loom.accessWidenerPath.get().asFile.name 17 | } 18 | } 19 | 20 | configurations { 21 | common { 22 | canBeResolved = true 23 | canBeConsumed = false 24 | } 25 | compileClasspath.extendsFrom common 26 | runtimeClasspath.extendsFrom common 27 | developmentForge.extendsFrom common 28 | 29 | shadowBundle { 30 | canBeResolved = true 31 | canBeConsumed = false 32 | } 33 | } 34 | 35 | dependencies { 36 | forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}" 37 | 38 | common(project(path: ':nbtedit-common', configuration: 'namedElements')) { transitive false } 39 | shadowBundle project(path: ':nbtedit-common', configuration: 'transformProductionForge') 40 | } 41 | 42 | shadowJar { 43 | exclude 'fabric.mod.json' 44 | exclude 'architectury.common.json' 45 | 46 | configurations = [project.configurations.shadowBundle] 47 | archiveClassifier = 'dev-shadow' 48 | } 49 | 50 | remapJar { 51 | input.set shadowJar.archiveFile 52 | dependsOn shadowJar 53 | } 54 | 55 | sourcesJar { 56 | def commonSources = project(':nbtedit-common').sourcesJar 57 | dependsOn commonSources 58 | from commonSources.archiveFile.map { zipTree(it) } 59 | } 60 | 61 | components.java { 62 | withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { 63 | skip() 64 | } 65 | } 66 | 67 | publishing { 68 | publications { 69 | mavenForge(MavenPublication) { 70 | artifactId = project.name 71 | version = mavenVersion 72 | from components.java 73 | } 74 | } 75 | } 76 | 77 | unifiedPublishing { 78 | project { 79 | displayName = "NBTEdit Forge ${project.minecraft_version}-${project.mod_version}" 80 | version = publishVersion 81 | gameVersions = [project.minecraft_version] 82 | gameLoaders = ['forge'] 83 | releaseType = 'release' 84 | changelog = 'See the GitHub repository for more information. \nhttps://github.com/qyl27/NBTEdit' 85 | 86 | mainPublication tasks.remapJar 87 | 88 | curseforge { 89 | token = Objects.requireNonNullElse(System.getenv('CURSEFORGE_TOKEN'), "") 90 | id = '678133' 91 | } 92 | 93 | modrinth { 94 | token = Objects.requireNonNullElse(System.getenv('MODRINTH_TOKEN'), "") 95 | id = 'Vr2eDeCw' 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /nbtedit-forge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=forge -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/NBTEditForge.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.forge.config.ModConfigImpl; 5 | import net.minecraftforge.fml.ModLoadingContext; 6 | import net.minecraftforge.fml.common.Mod; 7 | import net.minecraftforge.fml.config.ModConfig; 8 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 9 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 10 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 11 | 12 | @Mod(value = NBTEdit.MODID) 13 | public class NBTEditForge { 14 | private final NBTEdit nbtedit; 15 | 16 | public NBTEditForge() { 17 | NBTEditPlatformImpl.load(); 18 | 19 | nbtedit = new NBTEdit(); 20 | 21 | ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigImpl.CONFIG, "nbtedit.toml"); 22 | 23 | final var bus = FMLJavaModLoadingContext.get().getModEventBus(); 24 | bus.addListener(this::setup); 25 | bus.addListener(this::setupClient); 26 | 27 | nbtedit.getLogger().info("NBTEdit loaded!"); 28 | } 29 | 30 | private void setup(FMLCommonSetupEvent event) { 31 | } 32 | 33 | private void setupClient(FMLClientSetupEvent event) { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/NBTEditPlatformImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge; 2 | 3 | import cx.rain.mc.nbtedit.api.command.IModPermission; 4 | import cx.rain.mc.nbtedit.api.config.IModConfig; 5 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 6 | import cx.rain.mc.nbtedit.forge.command.ModPermissionImpl; 7 | import cx.rain.mc.nbtedit.forge.config.ModConfigImpl; 8 | import cx.rain.mc.nbtedit.forge.networking.ModNetworkingImpl; 9 | 10 | public class NBTEditPlatformImpl { 11 | private static final ModNetworkingImpl NETWORKING = new ModNetworkingImpl(); 12 | private static final ModConfigImpl CONFIG = new ModConfigImpl(); 13 | private static final ModPermissionImpl PERMISSION = new ModPermissionImpl(); 14 | 15 | public static IModNetworking getNetworking() { 16 | return NETWORKING; 17 | } 18 | 19 | public static IModConfig getConfig() { 20 | return CONFIG; 21 | } 22 | 23 | public static IModPermission getPermission() { 24 | return PERMISSION; 25 | } 26 | 27 | static void load() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/command/ModPermissionImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge.command; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 5 | import cx.rain.mc.nbtedit.api.command.IModPermission; 6 | import cx.rain.mc.nbtedit.forge.config.ModConfigImpl; 7 | import net.minecraft.commands.CommandSourceStack; 8 | import net.minecraft.server.level.ServerPlayer; 9 | import net.minecraftforge.eventbus.api.SubscribeEvent; 10 | import net.minecraftforge.fml.common.Mod; 11 | import net.minecraftforge.server.permission.PermissionAPI; 12 | import net.minecraftforge.server.permission.events.PermissionGatherEvent; 13 | import net.minecraftforge.server.permission.nodes.PermissionNode; 14 | import net.minecraftforge.server.permission.nodes.PermissionTypes; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | @Mod.EventBusSubscriber(modid = NBTEdit.MODID) 21 | public class ModPermissionImpl implements IModPermission { 22 | public static final Map> NODES = new HashMap<>(); 23 | 24 | private static PermissionNode bool(String name, int defaultLevel) { 25 | return new PermissionNode<>(NBTEdit.MODID, name, PermissionTypes.BOOLEAN, 26 | (player, uuid, context) -> player != null && player.hasPermissions(defaultLevel)); 27 | } 28 | 29 | @SubscribeEvent 30 | public static void registerPermission(PermissionGatherEvent.Nodes event) { 31 | for (var p : ModPermissions.values()) { 32 | var node = bool(p.getName(), ModConfigImpl.PERMISSION_LEVELS.get(p).get()); 33 | NODES.put(p, node); 34 | event.addNodes(node); 35 | } 36 | } 37 | 38 | @Override 39 | public boolean hasPermission(@NotNull CommandSourceStack sourceStack, @NotNull ModPermissions permission) { 40 | return sourceStack.hasPermission(permission.getDefaultLevel()); 41 | } 42 | 43 | @Override 44 | public boolean hasPermission(@NotNull ServerPlayer player, @NotNull ModPermissions permission) { 45 | return PermissionAPI.getPermission(player, NODES.get(permission)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/command/NBTEditCommandRegister.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge.command; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.command.NBTEditCommand; 5 | import net.minecraftforge.event.RegisterCommandsEvent; 6 | import net.minecraftforge.eventbus.api.SubscribeEvent; 7 | import net.minecraftforge.fml.common.Mod; 8 | 9 | @Mod.EventBusSubscriber(modid = NBTEdit.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) 10 | public class NBTEditCommandRegister { 11 | @SubscribeEvent 12 | public static void onRegisterCommands(RegisterCommandsEvent event) { 13 | var dispatcher = event.getDispatcher(); 14 | dispatcher.register(NBTEditCommand.NBTEDIT); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/config/ModConfigImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge.config; 2 | 3 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 4 | import cx.rain.mc.nbtedit.api.config.IModConfig; 5 | import net.minecraftforge.common.ForgeConfigSpec; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class ModConfigImpl implements IModConfig { 11 | public static ForgeConfigSpec CONFIG; 12 | 13 | public static ForgeConfigSpec.BooleanValue DEBUG; 14 | 15 | public static Map> PERMISSION_LEVELS = new HashMap<>(); 16 | 17 | static { 18 | var builder = new ForgeConfigSpec.Builder(); 19 | 20 | builder.comment("General settings.") 21 | .push("general"); 22 | 23 | DEBUG = builder 24 | .comment("Enable debug logs. Necessary if you are reporting bugs.") 25 | .define("debug", false); 26 | 27 | builder.comment("Permission node levels. Like vanilla, should in 0 ~ 5 range.") 28 | .push("permission"); 29 | 30 | for (var p : ModPermissions.values()) { 31 | var spec = builder.define(p.getName(), p.getDefaultLevel()); 32 | PERMISSION_LEVELS.put(p, spec); 33 | } 34 | 35 | builder.pop(); 36 | builder.pop(); 37 | 38 | CONFIG = builder.build(); 39 | } 40 | 41 | @Override 42 | public boolean isDebug() { 43 | return DEBUG.get(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/keybinding/NBTEditKeyBindings.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge.keybinding; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.ModConstants; 5 | import com.mojang.blaze3d.platform.InputConstants; 6 | import net.minecraft.client.KeyMapping; 7 | import net.minecraftforge.api.distmarker.Dist; 8 | import net.minecraftforge.client.event.RegisterKeyMappingsEvent; 9 | import net.minecraftforge.client.settings.KeyConflictContext; 10 | import net.minecraftforge.client.settings.KeyModifier; 11 | import net.minecraftforge.eventbus.api.SubscribeEvent; 12 | import net.minecraftforge.fml.common.Mod; 13 | import org.lwjgl.glfw.GLFW; 14 | 15 | @Mod.EventBusSubscriber(modid = NBTEdit.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) 16 | public class NBTEditKeyBindings { 17 | public static final KeyMapping NBTEDIT_SHORTCUT = new KeyMapping(ModConstants.KEY_NBTEDIT_SHORTCUT, 18 | KeyConflictContext.IN_GAME, KeyModifier.NONE, InputConstants.Type.KEYSYM, 19 | GLFW.GLFW_KEY_N, ModConstants.KEY_CATEGORY); 20 | 21 | @SubscribeEvent 22 | public static void onRegisterKeyMappings(RegisterKeyMappingsEvent event) { 23 | NBTEdit.getInstance().getLogger().info("Register key binding."); 24 | event.register(NBTEDIT_SHORTCUT); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/keybinding/OnNBTEditShortcut.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge.keybinding; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.RayTraceHelper; 5 | import net.minecraftforge.api.distmarker.Dist; 6 | import net.minecraftforge.client.event.InputEvent; 7 | import net.minecraftforge.eventbus.api.SubscribeEvent; 8 | import net.minecraftforge.fml.common.Mod; 9 | 10 | @Mod.EventBusSubscriber(modid = NBTEdit.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) 11 | public class OnNBTEditShortcut { 12 | @SubscribeEvent 13 | public static void onKeyboardInput(InputEvent.Key event) { 14 | if (NBTEditKeyBindings.NBTEDIT_SHORTCUT.consumeClick()) { 15 | RayTraceHelper.doRayTrace(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/java/cx/rain/mc/nbtedit/forge/networking/ModNetworkingImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.forge.networking; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 5 | import cx.rain.mc.nbtedit.networking.NetworkClientHandler; 6 | import cx.rain.mc.nbtedit.networking.NetworkServerHandler; 7 | import cx.rain.mc.nbtedit.networking.packet.c2s.BlockEntityRaytraceResultPacket; 8 | import cx.rain.mc.nbtedit.networking.packet.c2s.EntityRaytraceResultPacket; 9 | import cx.rain.mc.nbtedit.networking.packet.c2s.ItemStackRaytraceResultPacket; 10 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 11 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 12 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 13 | import cx.rain.mc.nbtedit.networking.packet.s2c.RaytracePacket; 14 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 15 | import net.minecraft.resources.ResourceLocation; 16 | import net.minecraft.server.level.ServerPlayer; 17 | import net.minecraftforge.event.network.CustomPayloadEvent; 18 | import net.minecraftforge.network.*; 19 | 20 | public class ModNetworkingImpl implements IModNetworking { 21 | private static final ResourceLocation CHANNEL_ID = ResourceLocation.fromNamespaceAndPath(NBTEdit.MODID, "editing"); 22 | 23 | private final SimpleChannel channel; 24 | 25 | public ModNetworkingImpl() { 26 | channel = ChannelBuilder.named(CHANNEL_ID) 27 | .networkProtocolVersion(NBTEdit.VERSION.hashCode()) 28 | .optionalClient() 29 | .optionalServer() 30 | .simpleChannel(); 31 | 32 | registerMessages(); 33 | } 34 | 35 | private void registerMessages() { 36 | channel.play() 37 | .clientbound() 38 | .add(RaytracePacket.class, RaytracePacket.CODEC, this::clientHandle); 39 | 40 | channel.play() 41 | .serverbound() 42 | .add(BlockEntityRaytraceResultPacket.class, BlockEntityRaytraceResultPacket.CODEC, this::serverHandle) 43 | .add(EntityRaytraceResultPacket.class, EntityRaytraceResultPacket.CODEC, this::serverHandle) 44 | .add(ItemStackRaytraceResultPacket.class, ItemStackRaytraceResultPacket.CODEC, this::serverHandle); 45 | 46 | channel.play() 47 | .bidirectional() 48 | .add(BlockEntityEditingPacket.class, BlockEntityEditingPacket.CODEC, this::handle) 49 | .add(EntityEditingPacket.class, EntityEditingPacket.CODEC, this::handle) 50 | .add(ItemStackEditingPacket.class, ItemStackEditingPacket.CODEC, this::handle); 51 | } 52 | 53 | private void clientHandle(RaytracePacket packet, CustomPayloadEvent.Context context) { 54 | context.enqueueWork(() -> NetworkClientHandler.handleRaytrace(packet)); 55 | } 56 | 57 | private void serverHandle(BlockEntityRaytraceResultPacket packet, CustomPayloadEvent.Context context) { 58 | context.enqueueWork(() -> NetworkServerHandler.handleBlockEntityResult(context.getSender(), packet)); 59 | } 60 | 61 | private void serverHandle(EntityRaytraceResultPacket packet, CustomPayloadEvent.Context context) { 62 | context.enqueueWork(() -> NetworkServerHandler.handleEntityResult(context.getSender(), packet)); 63 | } 64 | 65 | private void serverHandle(ItemStackRaytraceResultPacket packet, CustomPayloadEvent.Context context) { 66 | context.enqueueWork(() -> NetworkServerHandler.handleItemStackResult(context.getSender(), packet)); 67 | } 68 | 69 | private void handle(BlockEntityEditingPacket packet, CustomPayloadEvent.Context context) { 70 | if (context.isClientSide()) { 71 | context.enqueueWork(() -> NetworkClientHandler.handleBlockEntityEditing(packet)); 72 | } else { 73 | context.enqueueWork(() -> NetworkServerHandler.saveBlockEntity(context.getSender(), packet)); 74 | } 75 | } 76 | 77 | private void handle(EntityEditingPacket packet, CustomPayloadEvent.Context context) { 78 | if (context.isClientSide()) { 79 | context.enqueueWork(() -> NetworkClientHandler.handleEntityEditing(packet)); 80 | } else { 81 | context.enqueueWork(() -> NetworkServerHandler.saveEntity(context.getSender(), packet)); 82 | } 83 | } 84 | 85 | private void handle(ItemStackEditingPacket packet, CustomPayloadEvent.Context context) { 86 | if (context.isClientSide()) { 87 | context.enqueueWork(() -> NetworkClientHandler.handleItemStackEditing(packet)); 88 | } else { 89 | context.enqueueWork(() -> NetworkServerHandler.saveItemStack(context.getSender(), packet)); 90 | } 91 | } 92 | 93 | @Override 94 | public void sendTo(ServerPlayer player, CustomPacketPayload packet) { 95 | channel.send(packet, player.connection.getConnection()); 96 | } 97 | 98 | @Override 99 | public void sendToServer(CustomPacketPayload packet) { 100 | channel.send(packet, PacketDistributor.SERVER.noArg()); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="${forge_loader_version_range}" 3 | license="GPLv3" 4 | issueTrackerURL="https://github.com/qyl27/NBTEdit/issues" 5 | 6 | [[mods]] 7 | modId="nbtedit" 8 | version="${mod_version}" 9 | displayName="${mod_full_name}" 10 | #updateJSONURL="https://change.me.example.invalid/updates.json" 11 | displayURL="https://github.com/qyl27/NBTEdit" 12 | logoFile="logo-forge.png" 13 | credits="DavidGoldman, MoeBoy76, Jay113355 and other contributers." 14 | authors="qyl27" 15 | displayTest="MATCH_VERSION" 16 | description=''' 17 | A Minecraft mod allows you edit any NBT tags of the game content while in game. Such as TileEntities, Entities. 18 | It can help many map creator to make custom items or help many mod creator to debug. 19 | ''' 20 | 21 | [[dependencies.nbtedit]] 22 | modId="forge" 23 | mandatory=true 24 | versionRange="${forge_version_range}" 25 | ordering="NONE" 26 | side="BOTH" 27 | 28 | [[dependencies.nbtedit]] 29 | modId="minecraft" 30 | mandatory=true 31 | versionRange="${forge_minecraft_version_range}" 32 | ordering="NONE" 33 | side="BOTH" 34 | -------------------------------------------------------------------------------- /nbtedit-forge/src/main/resources/logo-forge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-forge/src/main/resources/logo-forge.png -------------------------------------------------------------------------------- /nbtedit-forge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": { 4 | "text": "${mod_id} resources" 5 | }, 6 | "pack_format": 61 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /nbtedit-neoforge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.gradleup.shadow' 3 | id 'me.shedaniel.unified-publishing' 4 | } 5 | 6 | architectury { 7 | platformSetupLoomIde() 8 | neoForge() 9 | } 10 | 11 | loom { 12 | accessWidenerPath = project(':nbtedit-common').loom.accessWidenerPath 13 | 14 | neoForge { 15 | } 16 | 17 | runs { 18 | clientData { 19 | clientData() 20 | 21 | programArgs '--all', '--mod', 'nbtedit' 22 | programArgs '--output', file('../nbtedit-common/src/generated/resources').absolutePath 23 | programArgs '--existing', file('../nbtedit-common/src/main/resources').absolutePath 24 | } 25 | } 26 | } 27 | 28 | configurations { 29 | common { 30 | canBeResolved = true 31 | canBeConsumed = false 32 | } 33 | compileClasspath.extendsFrom common 34 | runtimeClasspath.extendsFrom common 35 | developmentNeoForge.extendsFrom common 36 | 37 | shadowBundle { 38 | canBeResolved = true 39 | canBeConsumed = false 40 | } 41 | } 42 | 43 | dependencies { 44 | neoForge "net.neoforged:neoforge:${project.neoforge_version}" 45 | 46 | common(project(path: ':nbtedit-common', configuration: 'namedElements')) { transitive false } 47 | shadowBundle project(path: ':nbtedit-common', configuration: 'transformProductionNeoForge') 48 | } 49 | 50 | shadowJar { 51 | exclude 'fabric.mod.json' 52 | exclude 'architectury.common.json' 53 | 54 | configurations = [project.configurations.shadowBundle] 55 | archiveClassifier = 'dev-shadow' 56 | } 57 | 58 | remapJar { 59 | input.set shadowJar.archiveFile 60 | dependsOn shadowJar 61 | atAccessWideners.add(loom.accessWidenerPath.get().asFile.name) 62 | } 63 | 64 | sourcesJar { 65 | def commonSources = project(':nbtedit-common').sourcesJar 66 | dependsOn commonSources 67 | from commonSources.archiveFile.map { zipTree(it) } 68 | } 69 | 70 | components.java { 71 | withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { 72 | skip() 73 | } 74 | } 75 | 76 | publishing { 77 | publications { 78 | mavenForge(MavenPublication) { 79 | artifactId = project.name 80 | version = mavenVersion 81 | from components.java 82 | } 83 | } 84 | } 85 | 86 | unifiedPublishing { 87 | project { 88 | displayName = "NBTEdit NeoForge ${project.minecraft_version}-${project.mod_version}" 89 | version = publishVersion 90 | gameVersions = [project.minecraft_version] 91 | gameLoaders = ['neoforge'] 92 | releaseType = 'release' 93 | changelog = 'See the GitHub repository for more information. \nhttps://github.com/qyl27/NBTEdit' 94 | 95 | mainPublication tasks.remapJar 96 | 97 | curseforge { 98 | token = Objects.requireNonNullElse(System.getenv('CURSEFORGE_TOKEN'), "") 99 | id = '678133' 100 | } 101 | 102 | modrinth { 103 | token = Objects.requireNonNullElse(System.getenv('MODRINTH_TOKEN'), "") 104 | id = 'Vr2eDeCw' 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /nbtedit-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=neoforge -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/NBTEditNeoForge.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.neoforge.config.ModConfigImpl; 5 | import net.neoforged.bus.api.IEventBus; 6 | import net.neoforged.fml.ModContainer; 7 | import net.neoforged.fml.common.Mod; 8 | import net.neoforged.fml.config.ModConfig; 9 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 10 | import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; 11 | 12 | @Mod(value = NBTEdit.MODID) 13 | public class NBTEditNeoForge { 14 | 15 | public NBTEditNeoForge(IEventBus bus, ModContainer container) { 16 | NBTEditPlatformImpl.load(); 17 | 18 | var nbtedit = new NBTEdit(); 19 | 20 | container.registerConfig(ModConfig.Type.COMMON, ModConfigImpl.CONFIG, "nbtedit.toml"); 21 | 22 | bus.addListener(this::setup); 23 | bus.addListener(this::setupClient); 24 | 25 | nbtedit.getLogger().info("NBTEdit loaded!"); 26 | } 27 | 28 | private void setup(FMLCommonSetupEvent event) { 29 | } 30 | 31 | private void setupClient(FMLClientSetupEvent event) { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/NBTEditPlatformImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge; 2 | 3 | import cx.rain.mc.nbtedit.api.command.IModPermission; 4 | import cx.rain.mc.nbtedit.api.config.IModConfig; 5 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 6 | import cx.rain.mc.nbtedit.neoforge.command.ModPermissionImpl; 7 | import cx.rain.mc.nbtedit.neoforge.config.ModConfigImpl; 8 | import cx.rain.mc.nbtedit.neoforge.networking.ModNetworkingImpl; 9 | 10 | public class NBTEditPlatformImpl { 11 | private static final ModNetworkingImpl NETWORKING = new ModNetworkingImpl(); 12 | private static final ModConfigImpl CONFIG = new ModConfigImpl(); 13 | private static final ModPermissionImpl PERMISSION = new ModPermissionImpl(); 14 | 15 | public static IModNetworking getNetworking() { 16 | return NETWORKING; 17 | } 18 | 19 | public static IModConfig getConfig() { 20 | return CONFIG; 21 | } 22 | 23 | public static IModPermission getPermission() { 24 | return PERMISSION; 25 | } 26 | 27 | static void load() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/command/ModPermissionImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.command; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.api.command.IModPermission; 5 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 6 | import cx.rain.mc.nbtedit.neoforge.config.ModConfigImpl; 7 | import net.minecraft.commands.CommandSourceStack; 8 | import net.minecraft.server.level.ServerPlayer; 9 | import net.neoforged.bus.api.SubscribeEvent; 10 | import net.neoforged.fml.common.EventBusSubscriber; 11 | import net.neoforged.neoforge.server.permission.PermissionAPI; 12 | import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent; 13 | import net.neoforged.neoforge.server.permission.nodes.PermissionNode; 14 | import net.neoforged.neoforge.server.permission.nodes.PermissionTypes; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | @EventBusSubscriber(modid = NBTEdit.MODID) 21 | public class ModPermissionImpl implements IModPermission { 22 | public static final Map> NODES = new HashMap<>(); 23 | 24 | private static PermissionNode bool(String name, int defaultLevel) { 25 | return new PermissionNode<>(NBTEdit.MODID, name, PermissionTypes.BOOLEAN, 26 | (player, uuid, context) -> player != null && player.hasPermissions(defaultLevel)); 27 | } 28 | 29 | @SubscribeEvent 30 | public static void registerPermission(PermissionGatherEvent.Nodes event) { 31 | for (var p : ModPermissions.values()) { 32 | var node = bool(p.getName(), ModConfigImpl.PERMISSION_LEVELS.get(p).get()); 33 | NODES.put(p, node); 34 | event.addNodes(node); 35 | } 36 | } 37 | 38 | @Override 39 | public boolean hasPermission(@NotNull CommandSourceStack sourceStack, @NotNull ModPermissions permission) { 40 | if (sourceStack.getPlayer() instanceof ServerPlayer player) { 41 | return hasPermission(player, permission); 42 | } 43 | return sourceStack.hasPermission(permission.getDefaultLevel()); 44 | } 45 | 46 | @Override 47 | public boolean hasPermission(@NotNull ServerPlayer player, @NotNull ModPermissions permission) { 48 | return PermissionAPI.getPermission(player, NODES.get(permission)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/command/NBTEditCommandRegister.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.command; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.command.NBTEditCommand; 5 | import net.neoforged.bus.api.SubscribeEvent; 6 | import net.neoforged.fml.common.EventBusSubscriber; 7 | import net.neoforged.neoforge.event.RegisterCommandsEvent; 8 | 9 | @EventBusSubscriber(modid = NBTEdit.MODID, bus = EventBusSubscriber.Bus.GAME) 10 | public class NBTEditCommandRegister { 11 | @SubscribeEvent 12 | public static void onRegisterCommands(RegisterCommandsEvent event) { 13 | var dispatcher = event.getDispatcher(); 14 | dispatcher.register(NBTEditCommand.NBTEDIT); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/config/ModConfigImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.config; 2 | 3 | import cx.rain.mc.nbtedit.api.command.ModPermissions; 4 | import cx.rain.mc.nbtedit.api.config.IModConfig; 5 | import net.neoforged.neoforge.common.ModConfigSpec; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class ModConfigImpl implements IModConfig { 11 | public static ModConfigSpec CONFIG; 12 | 13 | public static ModConfigSpec.BooleanValue DEBUG; 14 | 15 | public static Map> PERMISSION_LEVELS = new HashMap<>(); 16 | 17 | static { 18 | var builder = new ModConfigSpec.Builder(); 19 | 20 | builder.comment("General settings.") 21 | .push("general"); 22 | 23 | DEBUG = builder 24 | .comment("Enable debug logs. Necessary if you are reporting bugs.") 25 | .define("debug", false); 26 | 27 | builder.comment("Permission node levels. Like vanilla, should in 0 ~ 5 range.") 28 | .push("permission"); 29 | 30 | for (var p : ModPermissions.values()) { 31 | var spec = builder.define(p.getName(), p.getDefaultLevel()); 32 | PERMISSION_LEVELS.put(p, spec); 33 | } 34 | 35 | builder.pop(); 36 | builder.pop(); 37 | 38 | CONFIG = builder.build(); 39 | } 40 | 41 | @Override 42 | public boolean isDebug() { 43 | return DEBUG.get(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/data/DataGen.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.data; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.neoforge.data.provider.LanguageProviderENUS; 5 | import cx.rain.mc.nbtedit.neoforge.data.provider.LanguageProviderZHCN; 6 | import net.minecraft.data.DataGenerator; 7 | import net.neoforged.bus.api.SubscribeEvent; 8 | import net.neoforged.fml.common.EventBusSubscriber; 9 | import net.neoforged.neoforge.data.event.GatherDataEvent; 10 | 11 | @EventBusSubscriber(modid = NBTEdit.MODID, bus = EventBusSubscriber.Bus.MOD) 12 | public class DataGen { 13 | @SubscribeEvent 14 | public static void onGatherData(GatherDataEvent.Client event) { 15 | DataGenerator generator = event.getGenerator(); 16 | var packOutput = generator.getPackOutput(); 17 | 18 | generator.addProvider(true, new LanguageProviderENUS(packOutput)); 19 | generator.addProvider(true, new LanguageProviderZHCN(packOutput)); 20 | } 21 | } -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/data/provider/LanguageProviderENUS.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.data.provider; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.ModConstants; 5 | import net.minecraft.data.PackOutput; 6 | import net.neoforged.neoforge.common.data.LanguageProvider; 7 | 8 | public class LanguageProviderENUS extends LanguageProvider { 9 | public LanguageProviderENUS(PackOutput packOutput) { 10 | super(packOutput, NBTEdit.MODID, "en_us"); 11 | } 12 | 13 | @Override 14 | protected void addTranslations() { 15 | add(ModConstants.KEY_CATEGORY, "In-game NBTEdit Reborn"); 16 | add(ModConstants.KEY_NBTEDIT_SHORTCUT, "Open the NBT editor"); 17 | 18 | add(ModConstants.MESSAGE_NOT_PLAYER, "Only players can use this command."); 19 | add(ModConstants.MESSAGE_NO_PERMISSION, "You have no permission to use NBTEdit."); 20 | add(ModConstants.MESSAGE_NOT_LOADED, "Block pos was not loaded."); 21 | add(ModConstants.MESSAGE_NOTHING_TO_EDIT, "There is no any target for editing."); 22 | add(ModConstants.MESSAGE_TARGET_IS_NOT_BLOCK_ENTITY, "There is no BlockEntity to edit."); 23 | add(ModConstants.MESSAGE_CANNOT_EDIT_OTHER_PLAYER, "Sorry, but you cannot edit other player."); 24 | add(ModConstants.MESSAGE_UNKNOWN_ENTITY_ID, "Invalid Entity ID."); 25 | add(ModConstants.MESSAGE_EDITING_ENTITY, "Editing Entity (%1$s)."); 26 | add(ModConstants.MESSAGE_EDITING_BLOCK_ENTITY, "Editing BlockEntity (%1$s, %2$s, %3$s)."); 27 | add(ModConstants.MESSAGE_EDITING_ITEM_STACK, "Editing ItemStack (%1$s)."); 28 | add(ModConstants.MESSAGE_SAVING_SUCCESSFUL, "Save successful!"); 29 | add(ModConstants.MESSAGE_SAVING_FAILED_INVALID_NBT, "Save failed! Invalid NBT."); 30 | add(ModConstants.MESSAGE_SAVING_FAILED_BLOCK_ENTITY_NOT_EXISTS, "Save failed! the BlockEntity is no longer exists."); 31 | add(ModConstants.MESSAGE_SAVING_FAILED_ENTITY_NOT_EXISTS, "Save failed! the Entity is no longer exists."); 32 | 33 | add(ModConstants.NBT_TYPE_BYTE, "Byte"); 34 | add(ModConstants.NBT_TYPE_SHORT, "Short"); 35 | add(ModConstants.NBT_TYPE_INT, "Integer"); 36 | add(ModConstants.NBT_TYPE_LONG, "Long"); 37 | add(ModConstants.NBT_TYPE_FLOAT, "Float"); 38 | add(ModConstants.NBT_TYPE_DOUBLE, "Double"); 39 | add(ModConstants.NBT_TYPE_BYTE_ARRAY, "Byte Array"); 40 | add(ModConstants.NBT_TYPE_STRING, "String"); 41 | add(ModConstants.NBT_TYPE_LIST, "List"); 42 | add(ModConstants.NBT_TYPE_COMPOUND, "Compound"); 43 | add(ModConstants.NBT_TYPE_INT_ARRAY, "Integer Array"); 44 | add(ModConstants.NBT_TYPE_LONG_ARRAY, "Long Array"); 45 | 46 | add(ModConstants.GUI_TITLE_EDITOR_READ_ONLY, "[Read-only] "); 47 | add(ModConstants.GUI_TITLE_EDITOR_ENTITY, "Editing Entity (%1$s)"); 48 | add(ModConstants.GUI_TITLE_EDITOR_BLOCK_ENTITY, "Editing BlockEntity (%1$s, %2$s, %3$s)"); 49 | add(ModConstants.GUI_TITLE_EDITOR_ITEM_STACK, "Editing ItemStack (%1$s)"); 50 | add(ModConstants.GUI_TITLE_EDITOR_ENTITY_NARRATION, "Entity NBT editor"); 51 | add(ModConstants.GUI_TITLE_EDITOR_BLOCK_ENTITY_NARRATION, "BlockEntity NBT editor"); 52 | add(ModConstants.GUI_TITLE_EDITOR_ITEM_STACK_NARRATION, "ItemStack NBT editor"); 53 | 54 | add(ModConstants.GUI_TITLE_TREE_VIEW, "NBT Tree"); 55 | add(ModConstants.GUI_TITLE_TREE_VIEW_NODE, "NBT Node"); 56 | add(ModConstants.GUI_TITLE_TREE_VIEW_NARRATION, "NBT Node Tree"); 57 | add(ModConstants.GUI_TITLE_TREE_VIEW_NODE_NARRATION, "NBT Node: %1$s"); 58 | add(ModConstants.GUI_TITLE_SCROLL_BAR, "Scrollbar"); 59 | add(ModConstants.GUI_TITLE_SCROLL_BAR_NARRATION, "Drag to scroll"); 60 | 61 | add(ModConstants.GUI_TITLE_EDITING_WINDOW, "Editing Tag"); 62 | add(ModConstants.GUI_TITLE_EDITING_WINDOW_NARRATION, "Tag Editing Window"); 63 | add(ModConstants.GUI_LABEL_NAME, "Name"); 64 | add(ModConstants.GUI_LABEL_VALUE, "Value"); 65 | add(ModConstants.GUI_EDIT_BOX_NAME, "Name"); 66 | add(ModConstants.GUI_EDIT_BOX_VALUE, "Value"); 67 | 68 | add(ModConstants.GUI_BUTTON_COPY, "Copy"); 69 | add(ModConstants.GUI_BUTTON_PASTE, "Paste"); 70 | add(ModConstants.GUI_BUTTON_CUT, "Cut"); 71 | add(ModConstants.GUI_BUTTON_EDIT, "Edit"); 72 | add(ModConstants.GUI_BUTTON_DELETE, "Delete"); 73 | add(ModConstants.GUI_BUTTON_ADD, "Add %1$s Tag"); 74 | add(ModConstants.GUI_BUTTON_SAVE, "Save"); 75 | add(ModConstants.GUI_BUTTON_QUIT, "Quit"); 76 | add(ModConstants.GUI_BUTTON_OK, "OK"); 77 | add(ModConstants.GUI_BUTTON_CANCEL, "Cancel"); 78 | 79 | add(ModConstants.GUI_TOOLTIP_BUTTON_COPY, "Copy selected tag."); 80 | add(ModConstants.GUI_TOOLTIP_BUTTON_PASTE, "Paste tag into selected container."); 81 | add(ModConstants.GUI_TOOLTIP_BUTTON_CUT, "Cut selected tag."); 82 | add(ModConstants.GUI_TOOLTIP_BUTTON_EDIT, "Edit selected tag."); 83 | add(ModConstants.GUI_TOOLTIP_BUTTON_DELETE, "Delete selected tag."); 84 | add(ModConstants.GUI_TOOLTIP_BUTTON_ADD, "Add tag typed %1$s."); 85 | 86 | add(ModConstants.GUI_TOOLTIP_BUTTON_SAVE, "Save and quit the editor."); 87 | add(ModConstants.GUI_TOOLTIP_BUTTON_SAVE_DISABLED, "Cannot be saved, the editor is read-only."); 88 | add(ModConstants.GUI_TOOLTIP_BUTTON_QUIT, "Discard and quit the editor."); 89 | add(ModConstants.GUI_TOOLTIP_BUTTON_OK, "OK"); 90 | add(ModConstants.GUI_TOOLTIP_BUTTON_CANCEL, "Cancel"); 91 | 92 | add(ModConstants.GUI_TOOLTIP_PREVIEW_COMPONENT, "[Text Preview] "); 93 | add(ModConstants.GUI_TOOLTIP_PREVIEW_COMPONENT_NARRATION, "Text Preview: "); 94 | add(ModConstants.GUI_TOOLTIP_PREVIEW_ITEM, "[Item Preview] "); 95 | add(ModConstants.GUI_TOOLTIP_PREVIEW_ITEM_NARRATION, "Item Preview: "); 96 | add(ModConstants.GUI_TOOLTIP_PREVIEW_UUID, "[UUID Preview] "); 97 | add(ModConstants.GUI_TOOLTIP_PREVIEW_UUID_NARRATION, "UUID Preview: "); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/data/provider/LanguageProviderZHCN.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.data.provider; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.ModConstants; 5 | import net.minecraft.data.PackOutput; 6 | import net.neoforged.neoforge.common.data.LanguageProvider; 7 | 8 | public class LanguageProviderZHCN extends LanguageProvider { 9 | public LanguageProviderZHCN(PackOutput packOutput) { 10 | super(packOutput, NBTEdit.MODID, "zh_cn"); 11 | } 12 | 13 | @Override 14 | protected void addTranslations() { 15 | add(ModConstants.KEY_CATEGORY, "游戏内 NBT 编辑器 (重制版)"); 16 | add(ModConstants.KEY_NBTEDIT_SHORTCUT, "打开编辑器"); 17 | 18 | add(ModConstants.MESSAGE_NOT_PLAYER, "只有在游戏中的玩家可以使用这个命令。"); 19 | add(ModConstants.MESSAGE_NO_PERMISSION, "你没有权限使用 NBTEdit!"); 20 | add(ModConstants.MESSAGE_NOT_LOADED, "方块还未加载。"); 21 | add(ModConstants.MESSAGE_NOTHING_TO_EDIT, "没有任何目标可供编辑。"); 22 | add(ModConstants.MESSAGE_TARGET_IS_NOT_BLOCK_ENTITY, "没有目标方块实体可供编辑。"); 23 | add(ModConstants.MESSAGE_CANNOT_EDIT_OTHER_PLAYER, "你不能编辑其他玩家。"); 24 | add(ModConstants.MESSAGE_UNKNOWN_ENTITY_ID, "无效的实体 ID。"); 25 | add(ModConstants.MESSAGE_EDITING_ENTITY, "编辑实体(ID:%1$s)。"); 26 | add(ModConstants.MESSAGE_EDITING_BLOCK_ENTITY, "编辑方块实体(%1$s, %2$s, %3$s)。"); 27 | add(ModConstants.MESSAGE_EDITING_ITEM_STACK, "编辑物品(%1$s)。"); 28 | add(ModConstants.MESSAGE_SAVING_SUCCESSFUL, "保存成功。"); 29 | add(ModConstants.MESSAGE_SAVING_FAILED_INVALID_NBT, "保存失败。无效的 NBT!"); 30 | add(ModConstants.MESSAGE_SAVING_FAILED_BLOCK_ENTITY_NOT_EXISTS, "保存失败。目标方块实体已经不存在了!"); 31 | add(ModConstants.MESSAGE_SAVING_FAILED_ENTITY_NOT_EXISTS, "保存失败。目标实体不存在了!"); 32 | 33 | add(ModConstants.NBT_TYPE_BYTE, "字节"); 34 | add(ModConstants.NBT_TYPE_SHORT, "短整数"); 35 | add(ModConstants.NBT_TYPE_INT, "整数"); 36 | add(ModConstants.NBT_TYPE_LONG, "长整数"); 37 | add(ModConstants.NBT_TYPE_FLOAT, "浮点数"); 38 | add(ModConstants.NBT_TYPE_DOUBLE, "双精度浮点数"); 39 | add(ModConstants.NBT_TYPE_BYTE_ARRAY, "字节数组"); 40 | add(ModConstants.NBT_TYPE_STRING, "字符串"); 41 | add(ModConstants.NBT_TYPE_LIST, "列表"); 42 | add(ModConstants.NBT_TYPE_COMPOUND, "组合"); 43 | add(ModConstants.NBT_TYPE_INT_ARRAY, "整数数组"); 44 | add(ModConstants.NBT_TYPE_LONG_ARRAY, "长整数数组"); 45 | 46 | add(ModConstants.GUI_TITLE_EDITOR_READ_ONLY, "(只读)"); 47 | add(ModConstants.GUI_TITLE_EDITOR_ENTITY, "编辑实体(ID:%1$s)"); 48 | add(ModConstants.GUI_TITLE_EDITOR_BLOCK_ENTITY, "编辑方块实体(%1$s, %2$s, %3$s)"); 49 | add(ModConstants.GUI_TITLE_EDITOR_ITEM_STACK, "编辑物品(%1$s)"); 50 | add(ModConstants.GUI_TITLE_EDITOR_ENTITY_NARRATION, "实体 NBT 编辑器"); 51 | add(ModConstants.GUI_TITLE_EDITOR_BLOCK_ENTITY_NARRATION, "方块实体 NBT 编辑器"); 52 | add(ModConstants.GUI_TITLE_EDITOR_ITEM_STACK_NARRATION, "物品 NBT 编辑器"); 53 | 54 | add(ModConstants.GUI_TITLE_TREE_VIEW, "NBT 树"); 55 | add(ModConstants.GUI_TITLE_TREE_VIEW_NODE, "NBT 节点"); 56 | add(ModConstants.GUI_TITLE_TREE_VIEW_NARRATION, "NBT 节点树"); 57 | add(ModConstants.GUI_TITLE_TREE_VIEW_NODE_NARRATION, "NBT 节点:%1$s"); 58 | add(ModConstants.GUI_TITLE_SCROLL_BAR, "滚动条"); 59 | add(ModConstants.GUI_TITLE_SCROLL_BAR_NARRATION, "按住拖动"); 60 | 61 | add(ModConstants.GUI_TITLE_EDITING_WINDOW, "编辑 NBT 标签"); 62 | add(ModConstants.GUI_TITLE_EDITING_WINDOW_NARRATION, "NBT 标签编辑窗口"); 63 | add(ModConstants.GUI_LABEL_NAME, "名称"); 64 | add(ModConstants.GUI_LABEL_VALUE, "数值"); 65 | add(ModConstants.GUI_EDIT_BOX_NAME, "名称"); 66 | add(ModConstants.GUI_EDIT_BOX_VALUE, "数值"); 67 | 68 | add(ModConstants.GUI_BUTTON_COPY, "复制"); 69 | add(ModConstants.GUI_BUTTON_PASTE, "粘贴"); 70 | add(ModConstants.GUI_BUTTON_CUT, "剪切"); 71 | add(ModConstants.GUI_BUTTON_EDIT, "编辑"); 72 | add(ModConstants.GUI_BUTTON_DELETE, "删除"); 73 | add(ModConstants.GUI_BUTTON_ADD, "添加 %1$s 标签"); 74 | add(ModConstants.GUI_BUTTON_SAVE, "保存"); 75 | add(ModConstants.GUI_BUTTON_QUIT, "退出"); 76 | add(ModConstants.GUI_BUTTON_OK, "确定"); 77 | add(ModConstants.GUI_BUTTON_CANCEL, "取消"); 78 | 79 | add(ModConstants.GUI_TOOLTIP_BUTTON_COPY, "复制选中的标签"); 80 | add(ModConstants.GUI_TOOLTIP_BUTTON_PASTE, "在选中的容器中粘贴标签"); 81 | add(ModConstants.GUI_TOOLTIP_BUTTON_CUT, "剪切选中的标签"); 82 | add(ModConstants.GUI_TOOLTIP_BUTTON_EDIT, "编辑选中的标签"); 83 | add(ModConstants.GUI_TOOLTIP_BUTTON_DELETE, "删除选中的标签"); 84 | add(ModConstants.GUI_TOOLTIP_BUTTON_ADD, "添加 %1$s 类型的标签"); 85 | 86 | add(ModConstants.GUI_TOOLTIP_BUTTON_SAVE, "保存并退出编辑器"); 87 | add(ModConstants.GUI_TOOLTIP_BUTTON_SAVE_DISABLED, "无法保存,因为此编辑器是只读的"); 88 | add(ModConstants.GUI_TOOLTIP_BUTTON_QUIT, "退出编辑器但不保存"); 89 | add(ModConstants.GUI_TOOLTIP_BUTTON_OK, "确定"); 90 | add(ModConstants.GUI_TOOLTIP_BUTTON_CANCEL, "取消"); 91 | 92 | add(ModConstants.GUI_TOOLTIP_PREVIEW_COMPONENT, "【文本预览】"); 93 | add(ModConstants.GUI_TOOLTIP_PREVIEW_COMPONENT_NARRATION, "文本预览:"); 94 | add(ModConstants.GUI_TOOLTIP_PREVIEW_ITEM, "【物品预览】"); 95 | add(ModConstants.GUI_TOOLTIP_PREVIEW_ITEM_NARRATION, "物品预览:"); 96 | add(ModConstants.GUI_TOOLTIP_PREVIEW_UUID, "【UUID 预览】"); 97 | add(ModConstants.GUI_TOOLTIP_PREVIEW_UUID_NARRATION, "UUID 预览:"); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/keybinding/NBTEditKeyBindings.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.keybinding; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.ModConstants; 5 | import com.mojang.blaze3d.platform.InputConstants; 6 | import net.minecraft.client.KeyMapping; 7 | import net.neoforged.api.distmarker.Dist; 8 | import net.neoforged.bus.api.SubscribeEvent; 9 | import net.neoforged.fml.common.EventBusSubscriber; 10 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 11 | import net.neoforged.neoforge.client.settings.KeyConflictContext; 12 | import net.neoforged.neoforge.client.settings.KeyModifier; 13 | import org.lwjgl.glfw.GLFW; 14 | 15 | @EventBusSubscriber(modid = NBTEdit.MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) 16 | public class NBTEditKeyBindings { 17 | public static final KeyMapping NBTEDIT_SHORTCUT = new KeyMapping(ModConstants.KEY_NBTEDIT_SHORTCUT, 18 | KeyConflictContext.IN_GAME, KeyModifier.NONE, InputConstants.Type.KEYSYM, 19 | GLFW.GLFW_KEY_N, ModConstants.KEY_CATEGORY); 20 | 21 | @SubscribeEvent 22 | public static void onRegisterKeyMappings(RegisterKeyMappingsEvent event) { 23 | NBTEdit.getInstance().getLogger().info("Register key binding."); 24 | event.register(NBTEDIT_SHORTCUT); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/keybinding/OnNBTEditShortcut.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.keybinding; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.utility.RayTraceHelper; 5 | import net.neoforged.api.distmarker.Dist; 6 | import net.neoforged.bus.api.SubscribeEvent; 7 | import net.neoforged.fml.common.EventBusSubscriber; 8 | import net.neoforged.neoforge.client.event.InputEvent; 9 | 10 | @EventBusSubscriber(modid = NBTEdit.MODID, bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) 11 | public class OnNBTEditShortcut { 12 | @SubscribeEvent 13 | public static void onKeyboardInput(InputEvent.Key event) { 14 | if (NBTEditKeyBindings.NBTEDIT_SHORTCUT.consumeClick()) { 15 | RayTraceHelper.doRayTrace(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/java/cx/rain/mc/nbtedit/neoforge/networking/ModNetworkingImpl.java: -------------------------------------------------------------------------------- 1 | package cx.rain.mc.nbtedit.neoforge.networking; 2 | 3 | import cx.rain.mc.nbtedit.NBTEdit; 4 | import cx.rain.mc.nbtedit.api.netowrking.IModNetworking; 5 | import cx.rain.mc.nbtedit.networking.NetworkClientHandler; 6 | import cx.rain.mc.nbtedit.networking.NetworkServerHandler; 7 | import cx.rain.mc.nbtedit.networking.packet.c2s.BlockEntityRaytraceResultPacket; 8 | import cx.rain.mc.nbtedit.networking.packet.c2s.EntityRaytraceResultPacket; 9 | import cx.rain.mc.nbtedit.networking.packet.c2s.ItemStackRaytraceResultPacket; 10 | import cx.rain.mc.nbtedit.networking.packet.common.BlockEntityEditingPacket; 11 | import cx.rain.mc.nbtedit.networking.packet.common.EntityEditingPacket; 12 | import cx.rain.mc.nbtedit.networking.packet.common.ItemStackEditingPacket; 13 | import cx.rain.mc.nbtedit.networking.packet.s2c.RaytracePacket; 14 | import net.minecraft.client.Minecraft; 15 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 16 | import net.minecraft.server.level.ServerPlayer; 17 | import net.neoforged.bus.api.SubscribeEvent; 18 | import net.neoforged.fml.common.EventBusSubscriber; 19 | import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; 20 | import net.neoforged.neoforge.network.handling.IPayloadContext; 21 | 22 | @EventBusSubscriber(modid = NBTEdit.MODID, bus = EventBusSubscriber.Bus.MOD) 23 | public class ModNetworkingImpl implements IModNetworking { 24 | 25 | @SubscribeEvent 26 | public static void register(RegisterPayloadHandlersEvent event) { 27 | var registrar = event.registrar(NBTEdit.VERSION); 28 | 29 | registrar.playToClient(RaytracePacket.TYPE, RaytracePacket.CODEC, ModNetworkingImpl::clientHandle); 30 | 31 | registrar.playToServer(BlockEntityRaytraceResultPacket.TYPE, BlockEntityRaytraceResultPacket.CODEC, ModNetworkingImpl::serverHandle); 32 | registrar.playToServer(EntityRaytraceResultPacket.TYPE, EntityRaytraceResultPacket.CODEC, ModNetworkingImpl::serverHandle); 33 | registrar.playToServer(ItemStackRaytraceResultPacket.TYPE, ItemStackRaytraceResultPacket.CODEC, ModNetworkingImpl::serverHandle); 34 | 35 | registrar.playBidirectional(BlockEntityEditingPacket.TYPE, BlockEntityEditingPacket.CODEC, ModNetworkingImpl::handle); 36 | registrar.playBidirectional(EntityEditingPacket.TYPE, EntityEditingPacket.CODEC, ModNetworkingImpl::handle); 37 | registrar.playBidirectional(ItemStackEditingPacket.TYPE, ItemStackEditingPacket.CODEC, ModNetworkingImpl::handle); 38 | } 39 | 40 | private static void clientHandle(RaytracePacket packet, IPayloadContext context) { 41 | context.enqueueWork(() -> NetworkClientHandler.handleRaytrace(packet)); 42 | } 43 | 44 | private static void serverHandle(BlockEntityRaytraceResultPacket packet, IPayloadContext context) { 45 | context.enqueueWork(() -> { 46 | var player = context.player(); 47 | if (player instanceof ServerPlayer serverPlayer) { 48 | NetworkServerHandler.handleBlockEntityResult(serverPlayer, packet); 49 | } 50 | }); 51 | } 52 | 53 | private static void serverHandle(EntityRaytraceResultPacket packet, IPayloadContext context) { 54 | context.enqueueWork(() -> { 55 | var player = context.player(); 56 | if (player instanceof ServerPlayer serverPlayer) { 57 | NetworkServerHandler.handleEntityResult(serverPlayer, packet); 58 | } 59 | }); 60 | } 61 | 62 | private static void serverHandle(ItemStackRaytraceResultPacket packet, IPayloadContext context) { 63 | context.enqueueWork(() -> { 64 | var player = context.player(); 65 | if (player instanceof ServerPlayer serverPlayer) { 66 | NetworkServerHandler.handleItemStackResult(serverPlayer, packet); 67 | } 68 | }); 69 | } 70 | 71 | private static void handle(BlockEntityEditingPacket packet, IPayloadContext context) { 72 | if (context.flow().isClientbound()) { 73 | context.enqueueWork(() -> NetworkClientHandler.handleBlockEntityEditing(packet)); 74 | return; 75 | } 76 | 77 | if (context.flow().isServerbound()) { 78 | context.enqueueWork(() -> { 79 | var player = context.player(); 80 | if (player instanceof ServerPlayer serverPlayer) { 81 | NetworkServerHandler.saveBlockEntity(serverPlayer, packet); 82 | } 83 | }); 84 | } 85 | } 86 | 87 | private static void handle(EntityEditingPacket packet, IPayloadContext context) { 88 | if (context.flow().isClientbound()) { 89 | context.enqueueWork(() -> NetworkClientHandler.handleEntityEditing(packet)); 90 | return; 91 | } 92 | 93 | if (context.flow().isServerbound()) { 94 | context.enqueueWork(() -> { 95 | var player = context.player(); 96 | if (player instanceof ServerPlayer serverPlayer) { 97 | NetworkServerHandler.saveEntity(serverPlayer, packet); 98 | } 99 | }); 100 | } 101 | } 102 | 103 | private static void handle(ItemStackEditingPacket packet, IPayloadContext context) { 104 | if (context.flow().isClientbound()) { 105 | context.enqueueWork(() -> NetworkClientHandler.handleItemStackEditing(packet)); 106 | return; 107 | } 108 | 109 | if (context.flow().isServerbound()) { 110 | context.enqueueWork(() -> { 111 | var player = context.player(); 112 | if (player instanceof ServerPlayer serverPlayer) { 113 | NetworkServerHandler.saveItemStack(serverPlayer, packet); 114 | } 115 | }); 116 | } 117 | } 118 | 119 | public ModNetworkingImpl() { 120 | } 121 | 122 | @Override 123 | public void sendTo(ServerPlayer player, CustomPacketPayload packet) { 124 | player.connection.send(packet); 125 | } 126 | 127 | @Override 128 | public void sendToServer(CustomPacketPayload packet) { 129 | var connection = Minecraft.getInstance().getConnection(); 130 | if (connection != null) { 131 | connection.send(packet); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="${neoforge_loader_version_range}" 3 | license="GPLv3" 4 | issueTrackerURL="https://github.com/qyl27/NBTEdit/issues" 5 | 6 | [[mods]] 7 | modId="nbtedit" 8 | version="${mod_version}" 9 | displayName="${mod_full_name}" 10 | #updateJSONURL="https://change.me.example.invalid/updates.json" 11 | displayURL="https://github.com/qyl27/NBTEdit" 12 | logoFile="logo-neoforge.png" 13 | credits="DavidGoldman, MoeBoy76, Jay113355 and other contributers." 14 | authors="qyl27" 15 | displayTest="MATCH_VERSION" 16 | description=''' 17 | A Minecraft mod allows you edit any NBT tags of the game content while in game. Such as TileEntities, Entities. 18 | It can help many map creator to make custom items or help many mod creator to debug. 19 | ''' 20 | 21 | [[accessTransformers]] 22 | file="META-INF/accesstransformer.cfg" 23 | 24 | [[dependencies.nbtedit]] 25 | modId="neoforge" 26 | type="required" 27 | versionRange="${neoforge_version_range}" 28 | ordering="NONE" 29 | side="BOTH" 30 | 31 | [[dependencies.nbtedit]] 32 | modId="minecraft" 33 | type="required" 34 | versionRange="${neoforge_minecraft_version_range}" 35 | ordering="NONE" 36 | side="BOTH" 37 | -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/resources/logo-neoforge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qyl27/NBTEdit/3919c961785682f7c8445e90c767c622d7a684a8/nbtedit-neoforge/src/main/resources/logo-neoforge.png -------------------------------------------------------------------------------- /nbtedit-neoforge/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": { 4 | "text": "${mod_id} resources" 5 | }, 6 | "pack_format": 32 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url = 'https://maven.architectury.dev/' } 4 | maven { url = 'https://maven.fabricmc.net/' } 5 | mavenCentral() 6 | maven { url = "https://maven.neoforged.net/releases/" } 7 | maven { url = 'https://maven.minecraftforge.net/' } 8 | gradlePluginPortal() 9 | } 10 | } 11 | 12 | rootProject.name = 'nbtedit' 13 | 14 | include(':nbtedit-common') 15 | include(':nbtedit-fabric') 16 | include(':nbtedit-forge') 17 | include(':nbtedit-neoforge') 18 | --------------------------------------------------------------------------------