From 7e68e318883a7e56ae2c39f3a9aeab126d73e185 Mon Sep 17 00:00:00 2001 From: 3944Realms Date: Tue, 26 Aug 2025 16:44:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E4=BD=9C=E4=B8=BA=E6=B7=B7=E6=B7=86?= =?UTF-8?q?=E6=BC=94=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 12 + .gitignore | 45 + .idea/.gitignore | 8 + .idea/copyright/profiles_settings.xml | 10 + .idea/gradle.xml | 18 + .idea/inspectionProfiles/Project_Default.xml | 8 + .idea/intellij-javadocs-4.0.1.xml | 204 ++++ .idea/misc.xml | 14 + .idea/uiDesigner.xml | 124 ++ .idea/vcs.xml | 6 + LICENSE.GPL3 | 674 +++++++++++ build.gradle | 223 ++++ dict.py | 71 ++ dict/class_dict.txt | 1000 +++++++++++++++++ dict/member_dict.txt | 1000 +++++++++++++++++ dict/package_dict.txt | 1000 +++++++++++++++++ gitattributes | 5 + gradle.properties | 64 ++ gradle/libs.versions.toml | 10 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 251 +++++ gradlew.bat | 94 ++ proguard.pro | 78 ++ settings.gradle | 11 + .../1de3d2ee724999f84a11b20b51c37030049be277 | 2 + .../2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac | 2 + .../31f65342fc4da49cb4df4f994bdb8a2aa9453b5d | 3 + .../735031f3addf80804addae5e3f53249900116f1e | 2 + .../82018c5420b46ddbb7071e62df09fdecd98133e6 | 2 + .../9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e | 1 + .../9fc560db70239f9631ea2b54518b8d5ada1a7b88 | 1 + .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 + .../d7cb74d6995b7cac24bbd97d180aabe19e79a2c1 | 1 + .../assets/superleadrope/lang/en_us.json | 8 + .../assets/superleadrope/lang/lzh.json | 8 + .../assets/superleadrope/lang/zh_cn.json | 8 + .../assets/superleadrope/lang/zh_tw.json | 8 + .../models/item/broken_super_lead_rope.json | 6 + .../models/item/super_lead_rope.json | 14 + .../assets/superleadrope/sounds.json | 24 + .../superleadrope/CommonEventHandler.java | 112 ++ .../superleadrope/SuperLeadRope.java | 40 + .../client/ClientEventHandler.java | 65 ++ .../client/model/SuperLeashKnotModel.java | 71 ++ .../client/model/geom/SLPModelLayers.java | 31 + .../client/renderer/SLPRenderType.java | 49 + .../entity/SuperLeashKnotRenderer.java | 68 ++ .../renderer/entity/SuperLeashRenderer.java | 153 +++ .../resolver/SuperLeashStateResolver.java | 201 ++++ .../renderer/state/SuperLeashRenderState.java | 57 + .../superleadrope/config/CommonConfig.java | 19 + .../content/capability/CapabilityHandler.java | 41 + .../capability/CapabilityRemainder.java | 26 + .../content/capability/LeashDataImpl.java | 752 +++++++++++++ .../content/capability/LeashDataProvider.java | 52 + .../inter/ILeashDataCapability.java | 162 +++ .../content/entity/SuperLeashEntity.java | 69 ++ .../content/entity/SuperLeashKnotEntity.java | 154 +++ .../content/item/SuperLeadRopeItem.java | 182 +++ .../core/leash/LeashInteractHandler.java | 103 ++ .../core/leash/LeashSyncManager.java | 39 + .../core/register/SLPEntityTypes.java | 58 + .../superleadrope/core/register/SLPItems.java | 35 + .../core/register/SLPSoundEvents.java | 44 + .../datagen/SLPDataGenEvent.java | 89 ++ .../datagen/data/SLPAdvancementKey.java | 44 + .../datagen/data/SLPItemTags.java | 36 + .../datagen/data/SLPLangKeyValue.java | 171 +++ .../datagen/provider/SLPBlockTagProvider.java | 40 + .../provider/SLPItemModelProvider.java | 93 ++ .../provider/SLPItemRecipeProvider.java | 34 + .../datagen/provider/SLPItemTagProvider.java | 41 + .../datagen/provider/SLPLanguageProvider.java | 56 + .../provider/SLPSoundDefinitionsProvider.java | 62 + .../superleadrope/network/NetworkHandler.java | 50 + .../network/toClient/LeashDataSyncPacket.java | 64 ++ .../utils/coremods/InvokerMethod.java | 24 + .../utils/lang/LanguageEnum.java | 28 + .../superleadrope/utils/lang/ModPartEnum.java | 37 + .../resources/META-INF/accesstransformer.cfg | 0 src/main/resources/META-INF/coremods.json | 1 + src/main/resources/META-INF/mods.toml | 64 ++ .../sounds/item/superlead/lead_break.ogg | Bin 0 -> 12113 bytes .../sounds/item/superlead/lead_tied1.ogg | Bin 0 -> 6604 bytes .../sounds/item/superlead/lead_tied2.ogg | Bin 0 -> 6364 bytes .../sounds/item/superlead/lead_tied3.ogg | Bin 0 -> 6687 bytes .../sounds/item/superlead/lead_untied1.ogg | Bin 0 -> 7329 bytes .../sounds/item/superlead/lead_untied2.ogg | Bin 0 -> 7608 bytes .../sounds/item/superlead/lead_untied3.ogg | Bin 0 -> 8069 bytes .../textures/entity/super_lead_knot.png | Bin 0 -> 405 bytes .../textures/item/broken_super_lead_rope.png | Bin 0 -> 262 bytes .../textures/item/super_lead_rope.png | Bin 0 -> 252 bytes src/main/resources/pack.mcmeta | 6 + src/main/resources/superleadrope_logo.png | Bin 0 -> 6652 bytes 95 files changed, 8552 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/intellij-javadocs-4.0.1.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 LICENSE.GPL3 create mode 100644 build.gradle create mode 100644 dict.py create mode 100644 dict/class_dict.txt create mode 100644 dict/member_dict.txt create mode 100644 dict/package_dict.txt create mode 100644 gitattributes create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 proguard.pro create mode 100644 settings.gradle create mode 100644 src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 create mode 100644 src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac create mode 100644 src/generated/resources/.cache/31f65342fc4da49cb4df4f994bdb8a2aa9453b5d create mode 100644 src/generated/resources/.cache/735031f3addf80804addae5e3f53249900116f1e create mode 100644 src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 create mode 100644 src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e create mode 100644 src/generated/resources/.cache/9fc560db70239f9631ea2b54518b8d5ada1a7b88 create mode 100644 src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 create mode 100644 src/generated/resources/.cache/d7cb74d6995b7cac24bbd97d180aabe19e79a2c1 create mode 100644 src/generated/resources/assets/superleadrope/lang/en_us.json create mode 100644 src/generated/resources/assets/superleadrope/lang/lzh.json create mode 100644 src/generated/resources/assets/superleadrope/lang/zh_cn.json create mode 100644 src/generated/resources/assets/superleadrope/lang/zh_tw.json create mode 100644 src/generated/resources/assets/superleadrope/models/item/broken_super_lead_rope.json create mode 100644 src/generated/resources/assets/superleadrope/models/item/super_lead_rope.json create mode 100644 src/generated/resources/assets/superleadrope/sounds.json create mode 100644 src/main/java/top/r3944realms/superleadrope/CommonEventHandler.java create mode 100644 src/main/java/top/r3944realms/superleadrope/SuperLeadRope.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/ClientEventHandler.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/model/SuperLeashKnotModel.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/model/geom/SLPModelLayers.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/renderer/SLPRenderType.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashKnotRenderer.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashRenderer.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/renderer/resolver/SuperLeashStateResolver.java create mode 100644 src/main/java/top/r3944realms/superleadrope/client/renderer/state/SuperLeashRenderState.java create mode 100644 src/main/java/top/r3944realms/superleadrope/config/CommonConfig.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityHandler.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityRemainder.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataImpl.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/capability/inter/ILeashDataCapability.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashEntity.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashKnotEntity.java create mode 100644 src/main/java/top/r3944realms/superleadrope/content/item/SuperLeadRopeItem.java create mode 100644 src/main/java/top/r3944realms/superleadrope/core/leash/LeashInteractHandler.java create mode 100644 src/main/java/top/r3944realms/superleadrope/core/leash/LeashSyncManager.java create mode 100644 src/main/java/top/r3944realms/superleadrope/core/register/SLPEntityTypes.java create mode 100644 src/main/java/top/r3944realms/superleadrope/core/register/SLPItems.java create mode 100644 src/main/java/top/r3944realms/superleadrope/core/register/SLPSoundEvents.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/SLPDataGenEvent.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/data/SLPAdvancementKey.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/data/SLPItemTags.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/data/SLPLangKeyValue.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPBlockTagProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemModelProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemRecipeProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemTagProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPLanguageProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPSoundDefinitionsProvider.java create mode 100644 src/main/java/top/r3944realms/superleadrope/network/NetworkHandler.java create mode 100644 src/main/java/top/r3944realms/superleadrope/network/toClient/LeashDataSyncPacket.java create mode 100644 src/main/java/top/r3944realms/superleadrope/utils/coremods/InvokerMethod.java create mode 100644 src/main/java/top/r3944realms/superleadrope/utils/lang/LanguageEnum.java create mode 100644 src/main/java/top/r3944realms/superleadrope/utils/lang/ModPartEnum.java create mode 100644 src/main/resources/META-INF/accesstransformer.cfg create mode 100644 src/main/resources/META-INF/coremods.json create mode 100644 src/main/resources/META-INF/mods.toml create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_break.ogg create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied1.ogg create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied2.ogg create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied3.ogg create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_untied1.ogg create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_untied2.ogg create mode 100644 src/main/resources/assets/superleadrope/sounds/item/superlead/lead_untied3.ogg create mode 100644 src/main/resources/assets/superleadrope/textures/entity/super_lead_knot.png create mode 100644 src/main/resources/assets/superleadrope/textures/item/broken_super_lead_rope.png create mode 100644 src/main/resources/assets/superleadrope/textures/item/super_lead_rope.png create mode 100644 src/main/resources/pack.mcmeta create mode 100644 src/main/resources/superleadrope_logo.png diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f91f646 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..529eeb7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +/run/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store +# Ignore Gradle build output directory +build diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e87ebd2 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..8567d4d --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..fdea32d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.idea/intellij-javadocs-4.0.1.xml b/.idea/intellij-javadocs-4.0.1.xml new file mode 100644 index 0000000..6ae9a3c --- /dev/null +++ b/.idea/intellij-javadocs-4.0.1.xml @@ -0,0 +1,204 @@ + + + + + UPDATE + false + true + + TYPE + METHOD + FIELD + + + PUBLIC + PROTECTED + DEFAULT + + + + + + ^.*(public|protected|private)*.+interface\s+\w+.* + /**\n + * The interface ${name}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> + */ + + + ^.*(public|protected|private)*.+enum\s+\w+.* + /**\n + * The enum ${name}.\n + */ + + + ^.*(public|protected|private)*.+class\s+\w+.* + /**\n + * The type ${name}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> + */ + + + .+ + /**\n + * The type ${name}.\n + */ + + + + + .+ + /**\n + * Instantiates a new ${name}.\n +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + + + ^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+ + /**\n + * Gets ${partName}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${partName}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + ^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+ + /**\n + * Sets ${partName}.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${partName}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + ^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+ + /**\n + * The entry point of application.\n + + <#if element.parameterList.parameters?has_content> + *\n +</#if> + * @param ${element.parameterList.parameters[0].name} the input arguments\n +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + .+ + /**\n + * ${name}<#if isNotVoid> ${return}</#if>.\n +<#if element.typeParameters?has_content> * \n +</#if> +<#list element.typeParameters as typeParameter> + * @param <${typeParameter.name}> the type parameter\n +</#list> +<#if element.parameterList.parameters?has_content> + *\n +</#if> +<#list element.parameterList.parameters as parameter> + * @param ${parameter.name} the ${paramNames[parameter.name]}\n +</#list> +<#if isNotVoid> + *\n + * @return the ${return}\n +</#if> +<#if element.throwsList.referenceElements?has_content> + *\n +</#if> +<#list element.throwsList.referenceElements as exception> + * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n +</#list> + */ + + + + + ^.*(public|protected|private)*.+static.*(\w\s\w)+.+ + /**\n + * The constant ${element.getName()}.\n + */ + + + ^.*(public|protected|private)*.*(\w\s\w)+.+ + /**\n + <#if element.parent.isInterface()> + * The constant ${element.getName()}.\n +<#else> + * The ${name}.\n +</#if> */ + + + .+ + /**\n + <#if element.parent.isEnum()> + *${name} ${typeName}.\n +<#else> + * The ${name}.\n +</#if>*/ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..1867029 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE.GPL3 b/LICENSE.GPL3 new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/LICENSE.GPL3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c68ae09 --- /dev/null +++ b/build.gradle @@ -0,0 +1,223 @@ +import proguard.gradle.ProGuardTask + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.guardsquare:proguard-gradle:7.7.0' + } +} + +plugins { + id 'java' + id 'idea' + id 'java-library' + id 'maven-publish' + id 'org.jetbrains.dokka' version '1.9.10' + id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'net.neoforged.moddev.legacyforge' version '2.0.103' +} + +def enableProguard = project.hasProperty("enableProguard") && project.enableProguard.toBoolean() + +tasks.named('wrapper', Wrapper).configure { + distributionType = Wrapper.DistributionType.BIN +} + +group = mod_group_id +version = "${minecraft_version}-${mod_version}" + +java { + toolchain.languageVersion = JavaLanguageVersion.of(17) +} + +base { + archivesName = mod_id +} + +println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" + +repositories { + maven { url = "https://libraries.minecraft.net/" } + maven { url = "https://neoforged.forgecdn.net/releases" } + maven { url = "https://neoforged.forgecdn.net/mojang-meta" } +} + +legacyForge { + version = "${minecraft_version}-${forge_version}" + accessTransformers = project.files "src/main/resources/META-INF/accesstransformer.cfg" + + parchment { + minecraftVersion = "${minecraft_version}" + mappingsVersion = "${mapping_lasting_version}" + } + + runs { + configureEach { + systemProperty 'forge.logging.console.level', 'debug' + systemProperty 'forge.logging.markers', 'REGISTRIES' + logLevel = org.slf4j.event.Level.DEBUG + } + clientAuth { + devLogin = true + client() + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + } + client { + client() + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + } + gameTestServer { + type = "gameTestServer" + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + } + data { + systemProperty('gradle.task', 'runData') + data() + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + programArguments.addAll '--mod', project.mod_id, '--all', + '--output', file('src/generated/resources/').getAbsolutePath(), + '--existing', file('src/main/resources/').getAbsolutePath() + } + server { + server() + } + } + + mods { + "${mod_id}" { + sourceSet(sourceSets.main) + } + } +} + +// 源码资源目录 +sourceSets.main.resources { srcDir 'src/generated/resources' } + +// ========== 依赖 ========== +configurations { + runtimeClasspath.extendsFrom localRuntime +} + +dependencies { + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' +} + +// ========== 编译配置 ========== +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +dokkaJavadoc { + outputDirectory = file("$buildDir/javadoc") +} + +// ========== 打包配置 ========== +jar { + manifest { + attributes([ + 'Specification-Title' : mod_id, + 'Specification-Vendor' : mod_authors, + 'Specification-Version' : '1', + 'Implementation-Title' : project.name, + 'Implementation-Version' : archiveVersion, + 'Implementation-Vendor' : mod_authors, + 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + ]) + } + archiveFileName = "${mod_id}-${mod_version}-origin.jar" + finalizedBy 'proguard' +} + +// 资源处理 +processResources { + def props = [ + minecraft_version : minecraft_version, + minecraft_version_range: minecraft_version_range, + forge_version : forge_version, + forge_version_range : forge_version_range, + loader_version_range : loader_version_range, + mod_id : mod_id, + mod_name : mod_name, + mod_license : mod_license, + mod_version : mod_version, + mod_authors : mod_authors, + mod_description : mod_description + ] + inputs.properties props + + filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { + expand props + [project: project] + } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +// ShadowJar 禁止缓存优化 +shadowJar { + outputs.upToDateWhen { false } +} + +// 本地 Maven 发布 +publishing { + publications { + create('mavenJava', MavenPublication) { + artifact jar + } + } + repositories { + maven { + url "file://${project.projectDir}/mcmodsrepo" + } + } +} + +// ========== ProGuard 配置 ========== +tasks.register('proguard', ProGuardTask) { + onlyIf { enableProguard } // 只有 enableProguard=true 才会执行 + dependsOn(tasks.jar) + configuration 'proguard.pro' + + // JDK jmods 库 + libraryjars "${System.getProperty('java.home')}/jmods" + + // 项目依赖作为库输入 + configurations.compileClasspath.files.each { file -> + libraryjars file.absolutePath + } + + // 输入输出 + def inputJar = tasks.jar.archiveFile.get().asFile + injars(inputJar) + outjars("${project.buildDir}/libs/[NOTUSE]${mod_id}-${minecraft_version}-${mod_version}-proguard.jar") + doFirst { + copy { + from inputJar + into "${project.buildDir}/libs" + rename { "[NOTUSE]${mod_id}-${minecraft_version}-${mod_version}-origin.jar" } + } + } + inputs.files(tasks.jar.archiveFile) + finalizedBy 'reobfJar' +} + +// ========== Forge reobf 绑定 ========== +afterEvaluate { + tasks.named('reobfJar') { + if (enableProguard) { + dependsOn('proguard') + input = file("${buildDir}/libs/[NOTUSE]${mod_id}-${minecraft_version}-${mod_version}-proguard.jar") + } else { + dependsOn('jar') + input = tasks.jar.archiveFile.get().asFile + } + } +} + +// IDEA 支持 +idea { + module { + downloadSources = true + downloadJavadoc = true + } +} diff --git a/dict.py b/dict.py new file mode 100644 index 0000000..c0cbeff --- /dev/null +++ b/dict.py @@ -0,0 +1,71 @@ +# Super Lead rope mod +# Copyright (C) 2025 R3944Realms +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +import os +import random + +# 确保输出目录存在 +os.makedirs("dict", exist_ok=True) + +# 全局已使用名字集合,保证三类字典互不重复 +used_names = set() + +def gen_dict(count: int, length: int, filename: str, charset: str): + """ + 生成字典文件: + - 首字符必须是字母 + - 剩余字符可以是 charset 中任意字符 + - 保证全局唯一 + """ + if length < 1: + raise ValueError("长度必须至少为 1") + + # 首字符必须是字母 + first_chars = [c for c in charset if c.isalpha()] + if not first_chars: + raise ValueError("字符集必须包含至少一个字母作为首字符") + + chars = list(charset) + max_combinations = len(first_chars) * (len(chars) ** (length - 1)) + if count > max_combinations: + raise ValueError(f"要求数量 {count} 超过最大可能组合数 {max_combinations}") + + generated = set() + while len(generated) < count: + s = random.choice(first_chars) + s += ''.join(random.choice(chars) for _ in range(length - 1)) + if s in used_names: + continue # 跳过已使用的名字 + generated.add(s) + used_names.add(s) + + with open(filename, "w") as f: + for s in generated: + f.write(s + "\n") + + print(f"生成完成,共 {len(generated)} 个写入 {filename}") + + +if __name__ == "__main__": + # 字符集定义 + charset_class = "o0OQ" + charset_member = "i1lI" + charset_package = "UvuV" + + # 生成类名字典 + gen_dict(count=1000, length=10, filename="dict/class_dict.txt", charset=charset_class) + + # 生成字段/方法字典 + gen_dict(count=1000, length=10, filename="dict/member_dict.txt", charset=charset_member) + + # 生成包名字典 + gen_dict(count=1000, length=10, filename="dict/package_dict.txt", charset=charset_package) diff --git a/dict/class_dict.txt b/dict/class_dict.txt new file mode 100644 index 0000000..3a6f59a --- /dev/null +++ b/dict/class_dict.txt @@ -0,0 +1,1000 @@ +oOQ0QoQoQO +QOoo0QOQQO +QooQQQ0OOO +o00oOo0QQQ +OoOQ0o0O0O +QQ0OQ00000 +Q00Qooo0QO +oQOoooOo0Q +Q000OQoOOO +oQQooo0Qo0 +Q0OQ0Oo0QQ +oQoOoOQQ00 +OQQQ00oooo +oOO0Ooo0QO +oO0o00OOQQ +oo0O000ooo +OQQO0OoQOo +oQQO0oo000 +OQOoo0oQOo +o0Q00Q0QoO +Qo0O0QQooo +OoOoQooQO0 +QoQoOoQOoo +OoO0Qo0OO0 +oQoQ0O0QoQ +OQ0QQO00Q0 +O0OQoQ0OOO +oQOoOOoOQQ +Ooo0OoQ00o +QO00Q0oOO0 +O0QOoOQoOQ +OOoo0QQQ0Q +o0OOQQoOQQ +Ooo0Q0QQQQ +oQQO0OooQo +QQoO0QoQQo +QooQQQ0o0O +QQ0oQ0oOoQ +oQoOQOQOO0 +QQOQ0OQQoo +Qo0QoQOoQo +QOOO0O0O00 +O0Qo0QQo0O +oOOQoOQ0oO +QoooQoO0Qo +oQoo00Oo0O +QOOOO0Qoo0 +OOQOooO000 +O0oQO0oQQ0 +o0Qo00o0OO +OQ0o000Q00 +oOQo0oO0OO +OQo0OQQO0Q +Qo0oQQOOoO +QQOOO0OQoQ +QoOOOQ0OOQ +OQooOoQQO0 +Q0OoQOOOQO +oOo0o0QoOQ +oo0o0oOQ00 +oooQo0oOO0 +Qo0oOoOQ0Q +QOO0OQ0O00 +ooQo0oOOO0 +O0OQoOOOO0 +Q0Qo0Oo00Q +Qo0QOooOQo +oQoO0ooOo0 +QooQQo0Ooo +oo0oOO0o00 +QOQQo0Q0oO +Q0oQ0oQOQQ +oQoQoO00oO +QOO0o0oo0Q +QO0o00O0Qo +o0OQoO00o0 +oQo00QO0oo +OoOQ0QQo0o +OOoQQQ0O0Q +Qo0QOOoQoo +oQ0Q0QQ0Q0 +OQ0Q0QQO00 +Q0O00O000Q +QoQQQ0Q000 +OoO0oo0ooQ +QoQO0O00O0 +ooOQQQoOoo +OOOOoOQo0o +QoOoo0OQOo +oOQoOQOoQ0 +OOoOOQ0O0Q +OoOQ0OoOo0 +OQ0QOOOoQ0 +OQo0o0QQ0o +ooOoOO0oOQ +QQOoooQQOQ +oQOOQOOQ0Q +QQ00OQOoOo +OQ0O0QooQo +OQ00Q00QOQ +O0OOQ0OOoo +QO00OQooo0 +O0oOoQ0OoQ +QO0OoQoO0O +QQo0oo0oQo +Qo00QoOO00 +QOo0QOoQoQ +oo00QOoQoO +Oo0oQ0QQOO +QQooQo0OoO +oOoOQOOO0o +QQoQo00000 +Qo0Q0QQ0OQ +oQ0Q0OQQo0 +o0oo00OQ0O +OOQooO0O00 +oQ00oQOO0o +OQoQOQoooo +QQoQooo00Q +Q00QO0O00o +o00QQ0Q0OQ +QQOQo0oQo0 +OooO0OQ0Q0 +o0O0000oO0 +oQo0QO0Ooo +oOQQO0Q0Q0 +QOo00O0O0O +oO0Oooo0OQ +o0ooQoQQOO +QoQ0OO0000 +Q0O0O0OQo0 +OOOoQO0OOO +QQ000oO0oQ +QOoQ0OQoQO +QOOQ0oQOQo +oQQo00Ooo0 +Q0O0oQQOoQ +o00000O00o +oO0o0OoQoO +oOQoOOO0Qo +OQo00OOOOO +OQO0oQQo0Q +oOOOQ0QOO0 +OQOO0Q0oO0 +OoOOOoO0QQ +O00QOOQOQO +QQOQO0oOOQ +QQOQOQOOQ0 +OO0OQ0QOoO +o0ooQoQoOo +OQooQQ0000 +OOOoQQQ0OO +oQ0ooOoOoo +OOQo0OoOoo +QQQ0QQOOoO +QQ0QQoQQOo +QoQOQOOQQo +O000QoQoQQ +oOO0o0QoQo +ooQOoo00o0 +oO0oooo0QO +OOQ00O0OO0 +QoOQ0oOOOQ +QQOo0OoQo0 +o00QQQoQ0Q +oQQoo0QOOo +QQooQQoo00 +o0QQ0QQQOQ +oQoQQ0Qo00 +QOOoQQOQOo +oQOQOQQQ0Q +o0O00QQOO0 +o0QOOQQoO0 +QQQoQQOoQo +QQo0o00OOO +oQQ0QOO000 +oQoQ00o0QQ +QQO00Q0oO0 +OoOQ0OOo0Q +oQoQo0OQQQ +Q00oOQQOOQ +QoOO0Q0o0O +Q0QoQQOOoo +O0000QQ00O +OQOQQ00QOo +OooOoOO0oO +OO0OoOo0oO +oO0Oo0oo0o +Q0Q00Q0oQo +Q0o0OoOQQ0 +oooQooQoo0 +QQOOOQoQ00 +QQQOOQ0O0Q +QoQoOO0OQ0 +OQO00O0O00 +Q0Q0oo0oQ0 +OooO0Oo000 +oQQOQ0o0QO +oQQ0OQoOoo +QoQQoQ0OOQ +OOoQOQQQOO +QooQO000OQ +oo0OoQ000O +oQ0OooQo00 +oooOo0Q0O0 +oo0QQoQ0oO +oO0OQO0oQQ +QoQ0OQQQ00 +oOooOoQoOo +OoOQo0OoQQ +QOOOQOQ00o +OOO0ooOoQQ +OOQOoOo0o0 +Q0QO0O0oQQ +Q0OoQQoooQ +oo00QOQQ0o +O0oOQ0OOO0 +Qoo0Oo0o0Q +QQOo000OQO +QQ00o0OQOo +oOOoOOoQoo +oOQ0OOO0OQ +oO0O000QoO +oO0o0o0OoQ +ooo0ooOoQQ +QQOO0QQOoo +QOoQO0Q0Q0 +O0oo0oQ0o0 +O0OQQoQ0QO +QQOQQQQooQ +oOO0QQoO0Q +oOOoQ00oOO +O00QO0O0o0 +oO00OQO0QO +QoOQQQOoQO +Q00OO0oOO0 +ooOQ0QOoOo +o000oQQQoQ +o0o000O0oQ +OQQQO000Q0 +O0o0ooQQQQ +oOo0o0O00Q +QoOo0Q0oOQ +oQQ0oOo0O0 +O0oo0o00Q0 +QQoOOoQo0O +Ooo0O0OQOQ +Q0OO0Q0OO0 +oQQo0oOQ0o +o0Q00oOoOO +o0OQOoOoOo +OQoOO0QQ00 +ooQQOOOQQ0 +OQ0OOoQ0OO +Q0oo00OOoO +O0oooQ0OQQ +OOQ0OQooO0 +o0oOoOQOOo +QQQ0Qoo000 +Qo0QoQo0Q0 +QO0OoQO00O +Q0o0Oo0Q0o +oQo0OOoOOo +O0O0OOOoQO +OQOQQQ0OQ0 +o0QoQ0oOOQ +OQOQ0oQOQ0 +Qoo0QoOQO0 +QQoOQo00Q0 +oOQQoooQ0o +Q0OQ00o0Qo +OoQOQOQoOO +QOoo0QQoOO +o0oo00OQQ0 +Oooooooo00 +ooOQ0OO0O0 +QOQO00Oo00 +OQQOoooOOo +oQ00OQ000Q +oQQOQoQQQo +OoQQo000QQ +QO0OoQoQ0Q +o000QQQOQ0 +Q0Q0OOQOo0 +QOQQOQ0o0o +O0oOQ0oOOQ +OQooQQoo0Q +OO0oQooOQQ +O0oO0QO0oO +Q0oQOQo0O0 +OOQ0QOooQo +OQoQQ0OOQQ +Q0O0oQ000O +o000OO0o0o +oQo0OQQOo0 +Q0Q0OoQOOo +OQoO0oOOQQ +OQQOOoQ0Q0 +o0Q00oOQo0 +O0OQ0o0oo0 +oQooQOQQQo +Qo0Oo0QooO +QQQoQoOQoQ +oO0QoO0QO0 +o0o0O0ooQo +oQoOoOQO0O +QoQQ0QoQ0o +QQ0OOOQOO0 +QO0OOO0000 +OQOoO000oO +O0OQO00QQO +OQQQ0oO0O0 +Q00OOoQo0o +OooOoo0Q00 +oQQQQ0oo0Q +OoO0QOo0Qo +Qoo0o000QO +Oo0QQoQOoO +Q0o0oOO0Oo +oOO0QQQOoO +Oo0OQoQOQ0 +Q0QOOoooOO +QOO0ooOOOo +oo00o00oQO +Q0QOOOQO0Q +ooO0QQQQo0 +oooQQQoO0Q +oQO00OOQOo +OOOQo0Q0QQ +OQQ000OOO0 +Qo0Q0QQ0QO +O0QQQQoO0o +ooQ0OoQ0Q0 +QQQOo000OQ +QooOoQ0oQQ +OOOoQo0Q0o +oo0QoOQQOQ +Q0Q000O0Oo +oQ0QOQO0OQ +OooQQ0o0oO +OoQ0OoO0Oo +QO00ooOoQ0 +OQ0QQOOOQO +OQOOO0QO0O +Q0OQOoOQoO +oQQ0O00o00 +o0O0o0QoO0 +OoQQOOo00o +OOQQO0oQoO +QQOQOQO00o +QQ0oooQ0oo +oQo00OoQ00 +OQQoO00OQO +OOQoOQoOoO +QQ00OQ00oo +QOoo0OOQQO +o0QQ0OO0O0 +OQ0OOoOO0o +OQOQQO0ooO +OOQQOQoO0O +QoQQooQ000 +oO00o0OQQ0 +QQQ0o0oQ0O +oQO00000Qo +o0OooQQ00O +OoOQQoOOQO +o0Q0QoQo0o +QQ00OO00QO +QQOo0QO0Oo +Qooo0Q000o +Ooo0oOQooO +QoQ0QOoQ0Q +oO0OQOO00O +oQOQ0Q0OQo +OOo0Q0Q0o0 +OoOQO0oQoO +QQ00oQoQo0 +oQooo0QQ0O +QQOQQoQQQ0 +O000OoQOoO +oQOoooOO0o +QQ0ooOoOo0 +oo00o00Ooo +Oo000oQooQ +oooOQOOOO0 +OQo0o0Q00Q +OQQooooOQ0 +OQ0OQoQOOQ +QoQOQ0QoQ0 +oQOQoooOOQ +Q0oOQ0oOQ0 +QO0ooQOOQo +O000o0OQQ0 +QoQOoQ0O0Q +O0QOoO00oO +Qo00OQ00O0 +oQQoQO0Q0o +O0QO0o0ooo +OooQ0QOQo0 +QQO00O00QO +Oo00o00o0Q +o0OOoQoOQO +O0OOOQO0QO +QO0Q0o0QoO +OQ0QoOOooo +OQ0QQOo000 +O0OQQ00QoO +QoOOoo0OOQ +Q0QQo0Q0QO +Q00O00OQ0O +O00oO00QO0 +Ooo0Q0QOOO +QQQ0oOOoOQ +QoOOQQQ0OQ +QoQ00oQQ0Q +O00O0OQO0Q +Q00O0oO0oQ +QQOQoO0oOO +QQ0oQ0oooo +o0oO0OoQOQ +OOO0OOoOQ0 +oO0QoOooQ0 +OQ0QOQoo0O +ooQOO0oO00 +o0O00QoOOo +O0Oo00ooO0 +o0O000oooQ +QoOQOO000O +OQQ00QQ0Qo +QoOOQoQOQo +OOO00OQ0oo +QooOOOOO0o +OQ0o0QQoOo +Qo00oo0o00 +O0QOO000QQ +oO0QoO0OOQ +QQoO0oooo0 +O0QO0Oo0oo +OOQoo0QO0O +Q0OoQQQO00 +oOo0OO0OO0 +ooOQQo0QoQ +oQOQQQQ0OQ +QOOOoO0Q0O +OQoQ0OOo00 +QQoQQoO0oQ +QoOoOoOooO +oQoQOQOO0O +oo0OOOOQ0Q +OQoOoQoQ0Q +oOQ0oOQQOo +OQO0oQoQ00 +o0oo0oo0Oo +oOoOOQooQO +OOOOOQ0oQO +Q0Oooo0o0O +o0OQoQOQQQ +oooQQOQOOO +o00QOoQQQQ +OQQOoQQQ0Q +OoOoO0Ooo0 +Qo0QQ0O0Q0 +QoQo0O0o0O +o0oQ00oO0o +QQQQ0oQ0OO +oQOQ0OoOO0 +QQ0o0O0oQO +o0QQ0QOQo0 +O0QQOooo0o +OOQQQ00O00 +ooQoOOQOQ0 +oo0Q00OOQo +QOQ00o0Ooo +oQOo00O00o +o0O0O0Q0QO +QQooQQQoQ0 +OOQQoQoQoo +O000QOoQQQ +Q0QO0OQ0Oo +QOoO0O0ooO +OO0oooo0OO +OQooOQoO0o +OoooQ0O0OQ +oOOOQQOOQo +OQ0Q00Q00Q +QQ0ooQO0OO +Oo0Q000Ooo +OOOQ0OOOoo +OQ000o0QOQ +QQOQoO0oOo +oQOOQoOOOO +QoOQ00o000 +Oo0OOQOQOO +Q0QQQO0QQ0 +oQ00Q0OoQo +OQ0QO0oOQQ +oOOQooO00o +QQOQQOOQ0o +QQQo0o0oOO +oQ0OoQoQOQ +Q0oOoQQO0Q +o00OoO0O00 +OoOQoQQ0o0 +O0QOOOQQQO +Oo000O0QOQ +OoQoOoo0Q0 +QoOQOOO00o +oQo0oOoOOQ +oOOoQoOQo0 +Q0QoQQOOQQ +Q0Oo00OOOo +Oo0Q0OOo0o +QQO0oooQQ0 +oooQo0Oooo +O0o0QOQQ0Q +OQOoO0OQoo +QQQOO0OQoo +ooOooOQO00 +QoQoOQO0O0 +OooQ00oOOO +oQ00OOQo00 +QQO0OQ0OoQ +OoQOoO0OO0 +oo0Q0OOo0Q +OoOO0OOO0Q +QOOoo0Oo0O +Q00OQ00oQo +Q0Q0QOoQOo +oOOO0QQ0Qo +OOQooOOQOQ +QQoQOo0ooo +ooOQOoOOQQ +o0oO0oOo0o +OOQQOO0QQO +oOQOoQoo00 +OQOoo0Q0oO +oQoOOOQoo0 +Qooo0Q0oQo +oQQQQ0OO0O +QQOo000000 +o0OoQoQOoo +OOoQ0QOOo0 +oO0oQ0QQoQ +OoO0o0OOoo +o0oQoQOo0Q +QQ00O0QOQ0 +QoQQoQ0O00 +OQOoO0OQOo +QOOQ00Q0OO +Q00QOQoO0Q +Q0oO0OoOOo +Ooo0QoQ0Qo +OoQoQoQoO0 +Q0OQo00000 +QoQ0OoQoOO +QOooOQQOoo +o0QQ00oQ0O +QQOQQ0OQoQ +oQ0Q0o0Q0Q +o0Q0QQOQ0o +O0QQQoO0Q0 +O00QOQQOQ0 +ooo00QOooO +O0QQo0ooOQ +oQ0QQQ0OoQ +o0o00OQo0Q +oo0QQ0OOOo +ooO000QoO0 +QoQOOQO000 +OQQ0o0O00o +oOQ00O00oO +QO0oOQoooo +O00Qo0QQQQ +OoQOo0Q00Q +OQQooOo0OO +O000OoQ0oo +oQOQ0QOooQ +OQoQ0OQOQQ +oQO0o0oOoQ +ooo0OoQQ0O +ooOOoQ0oQ0 +OQ00oo0Qo0 +OOQOoQoQQO +oQoQO0OOoO +OOOoo0O0Q0 +oooOQo0OO0 +OQo0QOO0Oo +O0OOo00OQo +Oo0Q0oQ00o +Q0o00Ooooo +ooQQ00QOQ0 +OooQ00QQOQ +o0O0OOQOQO +QQoQoO0QQ0 +o00QoQ0OQ0 +QO00QoQOo0 +OO0QQoooo0 +OOOooQO0QQ +oo00O00QOo +oOooOQO00O +Q0QoOQOOoo +OO000OQOQQ +OOQOoo0Q00 +oQ00QoOQ0o +QOOOQOOOQQ +oo0o00ooQ0 +QQQOOQOoOO +oOQ0OQ0o0o +OoQ0oQ0O0o +OQ0Q00oOO0 +oOO000Q0oQ +QQ0oo0Q0O0 +QOOQo0OoQQ +O0oOOQo0oo +OQ0Q0oOoOo +o0oo0QOOQO +OQooOQOQQo +O0QQo0QoOQ +O0QOOoOoOO +oQ0o0oQ0O0 +o00O0O0oOO +OQoOQoQoOo +oOoO0QQoQQ +Qoo0oQQ0QO +OoQ0OQOQ00 +QQO00Q000O +Q000QQOQOO +OoOO00Oooo +ooooOo0oOO +ooooooOQQQ +QoQoo00Q00 +ooQoOQQO0O +Oo00O0oQQQ +QQoQ0O0OoQ +o0oQ0QQQOO +QQO00OQooO +OQoQoo0Ooo +ooQQ0oOQQ0 +oQ0Q0oOOO0 +QQ0QQOOQQO +oOQoQOOo00 +oOQ0oQo0Q0 +OoQo0oQOQo +Q0OO0ooOOo +QooOQQO0OO +Q0QO00OQOO +o0QQQQQ0QQ +o0QOo0O0oo +Q0O00o0oQo +OQQ0oo00oQ +OQQOOoQOO0 +OQ0QO0Qo00 +Q0O0oQOoQ0 +QO0o00oOOO +QQQQQO0QQo +Q00Q0QOQOO +QoOo0QQ0QO +O00OooOQ0O +Q0oO00QQOO +OoO0oooo0Q +QO0Qoo00Qo +o0oo00oQoO +OO0Q0QQQ00 +Q0Q0ooQQOo +Qo0QQQ0OQo +QO00QOOQO0 +oo0oOQOQ00 +QoOQOQOo0O +OQQQ0QQO0Q +QO0QQOOoQO +OoQQOoOQ0Q +oOooQQQooQ +oOOOoOQ0OO +oo0QOoOo00 +O0oOoOQoQQ +QoQQQ0o0oO +oOQ0o0O0Qo +OOQoOOoO0Q +oQ0QQO000O +QoOoOoo00o +oooQOOooo0 +oQoQO0OQoQ +oO0OOO00QQ +ooQOoOQQ0Q +OoOQoOQo00 +o0O0o0O0QQ +oO000QOoOo +Q0oo00OOQo +oO0Q0OO000 +QoO0QQ00OO +QOoQ0ooOoQ +o0QQOOoOoO +oOoQ00OQoQ +oOooooOOOO +QQo00o0QoO +QQ000OQQoO +OQoOoQOoOO +QOooOoO00Q +OQQQQO0oQO +QQQoOQQo0O +OO0oQ0oo0Q +o0oQOQOOQ0 +o0QQ00ooO0 +oOOOQooooQ +oo000Q000o +Oo0QQO0000 +OQOoOoO0Q0 +QOQo00OO0O +oo0oQQQOOO +oQoQ0QOo0o +ooQQ0ooQ0Q +QQQQOQQOoo +Q0OOQQOo0Q +OoO0o00QoO +oQOo0Q00O0 +OQ0OQoOQOO +Q00Oo0OOQO +Oo00Q0OOoo +oQooQOo0QO +oQooOOoQ00 +QO0o0o0oOO +o0oo0O000Q +oQOQoOQoOO +oo0oOo0QOQ +QOoQO000Q0 +o0Q0O0QoOo +QoOO0oQQ0O +OoOoO00ooQ +QQoQQQOO0o +oooO0oOOoo +O0O0QoOoO0 +ooOOOQOOQQ +oOOoQ0Q00o +QQQ0oo0oOo +OOoQQQo0OQ +O00Q00Qoo0 +OOQ0Q00ooO +OOQQQ0ooO0 +OQOQ0QQoQo +Qo0o0OQoOO +Q0o0Q0oOoo +QooQQO0QQ0 +QO0Oo0oQ0Q +O00O0o0Q0O +QoOooOOQo0 +O0O00QQ00Q +oOO0oO0QoQ +QoOQO0oOQQ +ooo00OOoo0 +QQ0oO00QoO +OoQOooO000 +QQQOO00O0O +QOO0OoOQ0O +OQQQOQQ0OQ +QOQ0OO0QOO +oQQOOo0o00 +O0Q0QOOQQQ +Q0o0OQOQQ0 +QOQoQo0OQQ +Q0OOoOQOoO +QQ0oQ00ooQ +OQo0QoOoQQ +QQO0O0QOO0 +Qo00QQOOoo +o0oQQO0OO0 +QoQOOOQQoO +oQoO0Q0QOQ +ooo000oo00 +oOQOO000QO +OQ00OoOO0O +oQQ0Q0oOOo +OO00000OQo +O00oO0oQQ0 +OOO0OooQ0O +QOOQ0o0OoO +o0o0o0OQOQ +QOo0Q0O0o0 +OQoQQQoQo0 +ooQ0QooOQO +o0ooQo00OO +OoOO0Oo0O0 +O0oQQO00OO +QQOooOO0Oo +oQQQOOQ00o +Qo0OO0QoQO +oQOo0QQoo0 +OO0QOO0Q00 +Q00OoQOQQO +OoOo0Q00oQ +QQ0oQoO00O +QooOOo0o0Q +o0Q00oooo0 +oo000OoQo0 +oo0ooQ0ooQ +OOoOOQ0OOO +QoQOOQQoo0 +O0OQoQQOQ0 +QQOQo00ooo +oO0Q00OQO0 +o000Q0O0oO +o00ooQQOoQ +oOOoOoO00o +QOoOoOQQQQ +OQQ00O0oOo +oQOQ00oQOO +oOoQQOOO0o +QooQOQOOoO +ooo0Qoo0o0 +OQQQoO0Ooo +oOOooo0QOO +oQ00oooo0o +oQ0o0OO00O +OOQOO0oO0O +O0OOooQoo0 +QQOQoO0ooo +O0QOQOOo0Q +O0QoQOOO00 +Q0Oo0o00Qo +QQoOo0oO0o +oo00000OOo +o0oOOOO0OQ +QO0OQ0OOo0 +ooOO0OQQ0Q +OOoOQ0Qoo0 +QOQOQ0o0QQ +OQ0Q00QoOQ +OoO0Q0Q0OO +OOQQQoOQQQ +oQ00OoQQoo +oOOQ0Q0O0o +oQoQQoOQOO +QO0Q000O0O +oo000Q0oQQ +Q000QooO0Q +ooo0Q0oQ0O +QO0OOOQQO0 +o00QO00OQ0 +ooo0Q00QOQ +QOoooO0OQQ +OQ0QoOoQo0 +OoQ0QOQQQO +OQQo0oOOO0 +QOooO000oQ +oOO0QQ0QOo +QQQ0o00Q0O +QO0OoOQQQ0 +o0OQ00QOoo +Q0OQOoOOO0 +oo0Q0ooQQ0 +oOOOOOooOO +QQOQ00QoQo +Q0OoOQQ0QO +QQQ0Q0o0QO +OQoQ0oQoQO +ooQOoQ0Q0O +o0o0oOQo00 +O0OOQQOQQQ +QQQoQ0o0oo +QOo0o00oO0 +oQoOoO0oO0 +OooOooQOQO +ooQoQQOoOQ +QoOo0QQo0O +OOOQQQo000 +QQ0o0QQ0QQ +O0Q0OooOoo +oOQQ0o00oo +Qo0oOoOoOO +OoOQO0oOOQ +oQQQ0QoOO0 +OQoOo0QQQQ +o0o0Qo0Q0Q +oQOOOoooOo +Q0oO00o0o0 +o0oQ0QQ0OQ +QoQOO0ooQo +OOoQO0OOOQ +oQ0OOO0ooo +oo00oo0000 +QooOO0oo00 +Q0OOQoQQQo +OQO0Ooo0OQ +O0oooQQQO0 +oQO0o0oQOo +OOOQOQoOo0 +oO0ooQQ0QO +oQQ0OQQo00 +OO000o0o00 +QoooQ0OO0Q +o0oQoQQo0o +QQ00O0QOOQ +QQQ0OQOQO0 +QQQoQOOooO +QQoOo0Q0o0 +OOoOOQooOQ +OQ0QOOQOOo +QOQQOQOoOQ +QOO000O0o0 +QOoQ00QoQ0 +OoO0QOQO0Q +Ooo0ooooQQ +QQoQOoOoOQ +ooooOQQo00 +OQOQoOQooo +OoQQQQ0Ooo +o0QOoQ00OQ +QoQOOQ00Qo +ooOQoOOQ0o +Q0o0QooQO0 +QOQOooQQo0 +o00oQOO00Q +QO0oQ00O0O +Q0OQ000Q00 +oo0OoQ0QQO +OQO0OQQQoo +O0oQ00Q0Q0 +OQooQQQ0oO +QoQ00o0Qoo +oQ0o0OoQQO +o00QOQQoQ0 +o0OQ0QQoOQ +Oo0O0O0OQQ +oOoQo0QoOQ +OOOOo0OQ00 +OooQO00QoQ +OQ000OoQQo +Q0OOOO0O0Q +OOQOQO0QQO +o000oOOooO +QOoQooOOOo +Oo0oOQ0QOQ +o0OQO0QQoO +O0Qo0OQ0oo +Q0o0OQQoOo +QOOOQQOOOO +OQ0QQooO0O +O0O0oOooOO +oQQOOOQQ0O +oQ0o0Oo0QO +o00QQQQOoQ +O00oQ0oQoo +OoQ0O0Qo0O +OOQo0QQOQ0 +ooQoQQoQoo +Qo0QoOOOo0 +oO0o000QoQ +OQQOQoQoQO +oooQ0ooQOQ +QQQooQO0QQ +QOoooOQ0Qo +QO0OQQ0Qoo +O0OQOOooQQ +QQo0OoooOo +Q0OoQ00Q00 +o0o00OQ0oo +oOQQOOoQoO +o0QOoQO0QO +OQQQooQo0Q +OoQ0Q0OoQQ +oo0QO0OoQo +OQQQOo0oQ0 +OoO0QOo0Q0 +O00QQOQ0oQ +Oo00OOQQQO +o0QOQoQOOO +O0oo0Qo0Qo +oOO0oQQ00o +QQOQ00ooOQ +o00OoQQOo0 +O0oo0O0o00 +OoQQ0QoOoo +OQ00OQQOQo +O0ooQOoQoQ +ooOOOOOoOo +QO0oOo0o0O +oo0OQo00oQ +QoQoQOO00o +oO00OoQO0Q +oOo00O00OO +O0Q00oooOo +OooOO0000Q +OoO0Oo0o0Q +QQ0OOOooQQ +QO0QQO0QQO +OO0O00OQOo +Q0QoQooQQQ +oOo0oOooQ0 +QoOOOOO0Qo +O0O0ooooO0 +QQ0Q00OooO +OOQ0oo0ooo +Q0ooOQ0000 +QO0QoOooQQ +O0O0Qo0oOO +Q0O000oQQQ +oQOQQooOOQ +ooOOoQQQQO +QoQ00OoQQo +O000O0QO0Q +QQ00QQo0Q0 diff --git a/dict/member_dict.txt b/dict/member_dict.txt new file mode 100644 index 0000000..f7f89dc --- /dev/null +++ b/dict/member_dict.txt @@ -0,0 +1,1000 @@ +i1ilI111l1 +ll11lIliil +llIiiI1lIi +iiIlilI1Ii +llIi1I1I11 +i11iIi1Ii1 +lli1l1Ii11 +Ill1l1iI1I +Iiii1I1Il1 +l11lI1l11l +ll1IIlIl1I +liIlIllli1 +ll1Iili1Il +l1lI1IlIl1 +liiil1llii +lIIIIl1ili +lIlIllI1iI +liii1l1lli +iii1iilIIl +ilillIiIi1 +IIIlIi1li1 +ii11iIi1II +Il1liI1li1 +il1iilIllI +lilIii1lIi +I1l1111I1l +l1li1II1i1 +iiliIiiiI1 +li1il1lIil +iiii1lilii +IilIliilIi +lIl1l11Iii +IiIlIiili1 +lli1iiilll +iIilii1li1 +llllII1lII +iIiI1lilll +lIIiI1ilIi +li1ll11111 +lli1Ilil1i +lIl1IiI1il +I1i11I1lII +illllIiiiI +IiiliI11I1 +lilli1IiIi +iIiIlI11li +i11iiI1ill +llll1I1iI1 +IIilIillli +I111l1111l +IlllI1I1iI +Ilil1ilIIi +i1ill1llII +iIll1i1Iil +i11illII1i +l1iI11Iili +llllII1I1l +I11iiIi1Ii +II1ii1II1I +lli1llIi1l +ll1i11111I +IIl1l1IlII +IiliI1II1l +IliiiI1I11 +Ii1I1lIiII +liIII11lIi +lilII11iil +IiliIiiiil +lil1li11ii +IIIlIl111i +IliIiillli +Iiii1I1iII +l1IIlli1ii +ii1IIIIIIl +i1ilIil1Il +illI1iIlli +Iii1ll11I1 +Ii1lI1llI1 +Ilil1llI1I +IIII1liiIl +lI1l11I11i +lIl1Il11Ii +iillili1li +liIiIillIi +llIliiiili +I11li1IlIl +I1i11ll1Ii +il1lilliIi +lilI1iIIIi +llIil1II11 +IilIIl1ili +llIli1i1II +I11I1IIIi1 +iiIi1I1Il1 +Il11i1iIIl +lll11i1iIi +liIl1II11l +llll1ii1iI +IiiI1liIll +IIii1ili1l +IIiiIl1l1l +I1iil11lIl +IIIiIiilIl +ili1IlIIlI +l1IIl1iIIi +I1IiliIi1i +Ili1iII11i +li1IlliI1I +Iili111lii +iilii1I11i +lil1Iili1l +iiIil1i1ll +l1lllIlI1i +liIiIlI1ll +Il11i1I1ll +IliillilI1 +IllII1iIIl +IIiI11l1Il +i11Il111il +Iil1IiIilI +i1iIiiI1l1 +llI1l11IlI +llIIl1Il1l +lll1ill1II +iiIi1iil1i +lIi1I1i1il +l1IiIlIili +Iii11ili1I +Iil1iIlill +liIlIlIIIi +lliIIi1ii1 +i111l1IIil +liIiii11ii +lI1l1Ilill +II1I1I1IIi +i1i1ill11l +illlIIiIl1 +i1i1Ii11II +iillI1lllI +l1I1illi11 +ilIIi1I1li +lIIIi111lI +ilII1lillI +IiIl1Iii1l +IIlliIIllI +Ili1Illi1I +iiI111Ii11 +IlIiii1Ili +li1I11iiii +IiiI11I1Il +li1iIiIl11 +iI1ii1lil1 +i1IliIIIii +ilIiiliIlI +IIiiIliiI1 +ll1IliIilI +i1lilIliIi +i1IiI11iIi +lIllIII11I +IIliIii1iI +II1IliiIIi +I1liIl1lIl +iIIIIiIi1i +IIlllIil11 +lilIlIiiIl +lili1i1lll +i1I1ililIi +illIiiIIIl +i1I1IiliI1 +llIlillIII +Ii1111iIiI +I1iIi1I1I1 +I1iIillIl1 +llIili1i1l +I111I1lllI +IilI1ilIiI +III1ll11ll +il1IiiIlIl +I1illliIli +i1ii1iIii1 +IlliIIIiII +ii1iIIIIli +I1lilill1i +iI11lIIli1 +IIiiII11i1 +Ilii1iIIii +iiiIiI1Iil +iIII1IIll1 +liIi11iIiI +IiillI1llI +IiiI1IilII +i1I1lIIlil +IiIillIili +iII1lIll1i +iIIl11lIIl +ill1iI1llI +l1lill1Il1 +lI1Ii1IiiI +IiiIilI1ll +lIllIlIlll +lIlliilIII +iIIlIlII1l +IiIllli1ll +li11i1iIII +IIi1lIi1I1 +I1i1il1Il1 +iiIi11illl +lillIi1i11 +I1iIill1II +IIIII1II11 +llIii1li1I +li1iilil11 +I1111IilI1 +IIIilliIII +Il1II1IiIi +l1l1IIiIl1 +ii1i1IIiIi +IilIlliiii +IIlIlli1Ii +ii1I1IIl11 +i11Ilil1i1 +lII1iiiili +il1lllliiI +l1liIi11li +i11llIllIi +iIi1IIl1ll +l1lIl1iIli +illiII1I11 +Ii11I1Ii1l +I11iI1i11i +iliiIlliII +llIliiIIii +llIIiI11ii +l1lIllI1I1 +lI1llil11I +lIii1IIill +i1liIIliIl +Illiiii11i +l1Ii11II1i +I1llii11l1 +lIi1l1l1Ii +illiii1IiI +Ili1lllill +IlII1l11I1 +IIi1IIilll +l1lI1ili11 +iiillli11i +i11iI11i1I +iiiIlI11il +Iiil11lI1i +ilIi1lII11 +ii11I1lIil +iIII1ilI1l +ilil1illil +lIl1I1Iiii +lil1ililil +lilIIliliI +I1iliIi1Ii +ilI11lI1Il +l1iil1li11 +lIliil1I11 +i111IIIII1 +lIIIiI1Iil +l1I111I1Il +l11illIi1i +iIlI111i1I +l1I1lIiI11 +liIililill +IIi1I1lIli +iII1llIliI +ll1IIi11ii +IIi1lIllii +lllll1iii1 +iIlIl11l11 +Iii1lIl1ll +ii11I111ii +IIIllIiIi1 +l1l1II111l +IliliiiiII +I1lI1l1lII +IlIIl1III1 +ii1illiil1 +ll1Il1iIiI +I1111i1I11 +lIi1llli1l +l1llllliIi +l11IlIliI1 +ilIliiIiI1 +IiII1l1lI1 +l1i111llI1 +I1lIlill1l +iillIlliii +l1lI1lil1l +III1lI11li +l1lliii1I1 +Ii11iiiIIi +IIIIIlIIiI +iili1IlIi1 +ll1illi1lI +I1IIIIlI1I +Il11IiiIII +IliIi1IilI +I1lIiIl1I1 +IIliI11IIi +il11lIi1il +IiliIlIIiI +i1Il1i11I1 +l11iii1Il1 +IIiiiIIli1 +IIlllII1ll +I1IIiIl11I +lli1ii1Il1 +lIiIliIl1l +I11Ilii1Il +llIlli1iIi +II1lIi11li +IIi11li111 +ilI1li1lii +IliiIi1Ill +i1iIl1Ii11 +lIIil11l1l +I1I1Ill11l +ilIii1li1l +Ill1li11l1 +lll1lIllll +lilIlil111 +I1llill1i1 +Iill1i1iII +IIIIi1i1ii +l11iiIIlii +Iili1IIIii +i11iIiiili +III1I1111l +liIIl1lIl1 +liIiiI1i1I +IiIIiilill +ii1lll1IlI +iIiIliiiiI +l1IiillI11 +iiIIl1l1li +l1i1lllIil +lIi1I1l1ii +ii1i1iIlII +ii11i1li1I +Il1i1IiiIl +llIiI11il1 +lIi1llI1lI +Ill1lIil1I +iIill1lIl1 +IlI1lIl11l +Il1III1II1 +lI111iIIlI +i11I1liI1i +l1Illil1ii +iii1ilIli1 +i1Il1lII1i +lIi1IIiill +i1iII1lI1i +Illl1Ii1ii +IlII1Il11i +Ili11I1lll +i1i1IiII1i +lIl1IIliIl +l11iIi1iil +lIliIIiil1 +I11llI11i1 +il11iiiill +lI1llIllii +I1iIlIil11 +IIll11ilI1 +Il1IIilI11 +lIIilil1il +i1iI11llI1 +ii1lIi1l1l +ll111I1Iii +li1I1l11II +i11I1iIil1 +Ii1IlI11l1 +l1i1IIiIIl +lllIIl1Ii1 +l11ilI1iil +l1lI1il1Ii +I1lIlIIi1I +Ii1liIl1i1 +IiI1Iii1il +Illi11iIii +lIlIIiIili +i11lI11Il1 +ll11IlilII +IlIlIliIl1 +lIIillIliI +Il1liiliil +IiiIIiiI1i +lI111Il1i1 +ii1ii1l1Ii +i1iiiIlllI +i1I1l1llIl +IIliI1Illi +IiI11i1lIl +IIlIlIi1i1 +ii1i11Ii1i +il11IllllI +lIi11lI111 +illlIiIii1 +iIlI1I11ll +iliI1lIil1 +iIil1i1I1I +l1Ii1l1lil +li1IIi1l1i +IIlIllIl1l +i1IilIlIli +lIiii111lI +iIlI1I1l1i +I1lii1liii +ilillIIIII +llllil11li +I1i1III11l +iIliilI1lI +I1iiIIiIIi +IllI11i11I +I1IllIiil1 +l1lillllii +l1Ii1iiilI +i1illiiIi1 +I1iIiilI1I +IilIilIiIl +IiiIliIil1 +lII1I11iIi +IlI11i1llI +l1l1Iilll1 +li1lIIi1il +ilIi1IIlIl +Il1Il1IiIi +iil1l11I1l +Ii1ii111Ii +i1l1liI1ll +Ii1iIIliII +lIl1lli1li +i1iIil1l1l +IiIllI11Il +Ii1i1iiIIl +i11IiIll1I +i1iII1IIII +lIIiilIi1i +I11IlIlIiI +illI11i1iI +i1IlIIl11l +li1i1il11I +iI1Iil1Il1 +Ii1iIIIili +lIllI11liI +i1IIil11il +IilIill1iI +l1ilIIiIl1 +l111i1lIiI +llili111I1 +ill1IIlll1 +II1IIiiIII +liI1IIlI11 +liiIil111i +IIllil11I1 +iIiIii11I1 +IlIiiiIilI +llI11lIl1I +liiIII1lll +i111ill1i1 +lIIiiiIiI1 +i11l1iIl1I +iii1I1liii +ili1III1II +i1lii1IlII +IlIl1ll1lI +iII1I11II1 +lI1ill1lII +I1llIIlIIi +li1illI111 +lI1IllIlll +il11IIIi1i +ilI1111111 +lIllIli1II +iI1IlilIi1 +IIIi11iilI +li11IiIlil +l1iilliiiI +Ii1ill1lII +iiIlii1Iil +II1l1i1lI1 +IIll1I1I1i +liIl111II1 +ll1iliIiIi +IIlII1IIiI +lI1illlI11 +illiI1iii1 +lilii111il +I1l1I1iI1l +I1illll111 +lli11I1Ii1 +liiII1ilIi +IlI1IiIi1I +IIilIIlIll +IliIi1IllI +IiI1ii1lli +ilI1li1iI1 +IiIiIlil1i +lIIlIIl111 +lil1iIIIl1 +lI1IlIiii1 +IIil1ilI1l +il111iiIli +IIIIiilill +lii1II1i1i +li1IiiIi1i +I1I1ii1iil +i11i11111I +li11IlIll1 +ilIll1iilI +i11IiIlIi1 +l111Iii1Ii +II1Il1iiI1 +lIllliilIi +I11lIiIl1i +iiiill11i1 +i11IiIilll +III1IiiiIi +II1Ii1l1iI +IIIIiilIl1 +llIIlI11II +II11iiII1l +lllliilIli +lll1i11Il1 +iIll1I111i +Ili111iiI1 +liIlll1lii +IIiiililiI +i1IiiiIlIl +i11IIli111 +iIiIil1lI1 +IIii1ii11I +lii1ilIlIi +i1I1IIlIlI +l1I11I1l1I +ii1lliI1II +li1l1111I1 +I1IIill1lI +i1liil11lI +IllIi1iI11 +lli11lIliI +IiiIlIlI1i +IIIliI1iiI +iiiIlII1il +lII1iIili1 +IillilliiI +lIl1iilill +ililllil1I +IliIl1IiiI +lIlII1i1i1 +II1liilil1 +ilil1II1lI +ii1iII11lI +lillIiiIll +l11IlIlIl1 +iliiIl1lI1 +i1lliII1l1 +IIli1li1I1 +lliIII1ili +llIliillIi +lII1ii1III +IIlIllllli +I11I111lii +liil1ii1II +iIIll1iliI +llIIl11Il1 +IlliliIlli +liiIiiliii +lli1I1IIIl +lii1iIilii +liiI1I1IlI +Illll11l1l +iliIiII1lI +lIlilIilii +llil1iIlI1 +IiiI1111lI +IiiiIiII1I +ilIliiIlii +li1iilllIl +iliiIlIlIl +l1i11lIiiI +I1IIli1Iil +IliIliIIll +IilI1ii11l +liilii1lil +Ii1Il1I1li +Il1Iiiilll +iIIiiil1li +iIiiIi1Ill +Iii1iI1l1I +iiiIllllIi +IiI1ill1iI +ilI11II1II +IiIiIliIlI +IlI1ll1l1i +lIiiii1iI1 +II1lIlII1i +Ii11lilil1 +I1i1IIlI1I +l1iliIlI11 +iilIIil1li +lIliI1iliI +Ii1IIIlll1 +iiii1IllIl +i111lli1l1 +IIIiIIiilI +I11i1l1lli +IIlI11IlI1 +ilI1llIIil +iii1ii1i1l +Iiil11l1il +iii1iIilI1 +IiIiiI1IlI +il1Iii1li1 +iIIillIi1i +Ii11I1Iii1 +IIllIIi1li +lli1IllI11 +il1I111I1i +Ii1ill11l1 +iiIiliiIlI +iIiI1ll1Il +I11iliIlil +Illli1lllI +IililI1I11 +I11lli1lII +I11il11Ii1 +iilIli1liI +llIIiliIiI +lIillIliI1 +IIlIiiIlI1 +iIl1Ili11i +lli1il11II +lIiIIi1Iii +I1ii1IiI1I +ilIil11l1I +IlIli1lIiI +IliIiIlIll +iiili1lIIl +lilIIIi1I1 +IIli1I1iii +Iiil1IIll1 +Ii1li1Ii1l +llII11llIl +IliIiiIlII +Iil11I11lI +ll1iI1i11i +ii111IiiI1 +llIiIiii1l +IiIIiII1II +I11ll1iiiI +iiI1li1lII +l1liil11l1 +liilll1l1I +IIIlIlIl1l +il11iiii1l +iI11lIilli +iIIIll1IIl +illllli1ll +l1l1II1IIi +iii1IIlIIl +IIi1I1iiIl +IiiIllilII +IlIIl1lIil +lliIi1Il1l +llillIl1i1 +i11li111I1 +i11IIl111l +ll111iII11 +lli1Ili1il +ii1ill1I1i +llIiIIIIil +iliIl1iIii +i11l11I1il +Ili1Ii111l +li11iIiiil +ilIilIiliI +Ii1i1lil1i +i1iiiiiill +i1lil1lili +I1lilli1i1 +IlI1lil1I1 +i1Ii1iI1i1 +iil1l1lli1 +iliil1lll1 +il1l1lI1II +i1Iiii111i +I11Il111i1 +llIiiiiIii +I11l1l111i +IliIii1ill +iIl1il1l11 +IiiI1ll1I1 +II1Ili1lll +li1illIl11 +lIiIi1Iil1 +iii1ilIii1 +IIlI1ii1i1 +ll1ililI1i +i1llli1lIi +il1IIlI11I +l1i1Ill11I +ii1lll1Ii1 +i1Il1illIl +ili1iIi1Il +IlIl1ilIil +liilIiiiI1 +l1i11l1iII +IIlliiIIIi +llil11i1il +lll1I1Iii1 +Iii1I1iiii +Ii1iilIi1l +III111lI1i +lill1IlIl1 +I11liI1I1I +II1IliiIii +Illii1l1l1 +Il11lil1il +l1I1lIl11i +Iili1lIi1i +IIliliIl11 +IIiii1i11i +Iiili1lll1 +l111lil1ll +liIIlI1liI +Iii1lIli11 +l1ilIlIi1l +IIll11IlIl +iIliI1ll1l +l1Ii1i1lil +i1IlilI1I1 +lIlllilllI +iIilIillI1 +ili1I1IIli +llIlIiIlII +Ill1IilII1 +l1IiI111i1 +I1IiI111ii +lI1I1il11l +ii1iI111il +Iili1I1iii +l1IIiIIl1i +II1li1iIll +ill1I11II1 +iilIi1lll1 +lIiII1ilii +iI1l1iiiIl +Il1II1l1i1 +I1ii1l1i1l +IliiIl1i1I +Iiili1Il1I +Ii11iIIllI +lliiii1I1i +IiiI1i1l11 +IllI1I1I1i +II1111IIIl +lIilliIl11 +l11Ililll1 +ilIiIIilii +llllIIliII +liiiIIll1l +IlIlil11ll +Il11IIi11I +ilIiiiIl1l +i11iiI1iII +lI1il1l1i1 +iillliIIi1 +IiII1l1ilI +i11lIl1I1I +i1Ili1Illi +IilIIiIlll +IlIIi11Il1 +l1il111l1i +IliIiiI1li +lI1lllli1I +l1lil11Ili +il1ll1li1i +IIIliIiliI +IIi1iII1Ii +IiilIiI1i1 +IliII1IiII +IiI11lIliI +I1li1Il1iI +lIill1l1Ii +i1l1Iiil1i +lI1l111liI +i11I1li11l +iI1ill1IiI +ill1l11Il1 +l1lli1iIiI +Il1lI11i1l +I1ilIiIl1i +ll1111iI1I +l1I1I111l1 +II1l1I1ii1 +li1l1Ii11l +iil1I1i11l +iiIilI1lIi +II1lillili +l11ll11i11 +II1il1Iiii +IIilIIi1Il +Il1lliiiI1 +iililil11I +iilIl1lIIl +liiII1Il1i +ll11iil1I1 +I11l1liIii +iiIIlIIII1 +iliiiiI1ll +IliiIIlIil +Ili1IliIii +lIlIlIilIi +I1i1ilIIii +Ii1ilIiii1 +l1IIiIilIl +l1llI1iI1I +II1llliIIl +IlIiIiIIlI +IlI1liII11 +iii1Il1lIi +Iil1iIiill +I111Il11I1 +IilllllilI +i11lIiill1 +llIlIIIiiI +iilI1lil1I +I11IlI11il +ll1iiiiliI +IliIliII1I +iiI1I11liI +iI11ll11lI +I1Ii1II1II +iiIiIl1IIl +iI11i11l1i +iil111llii +ilii11IIl1 +l1IlI1illl +lilIIIlI1i +IiI1ll11ll +liIli111II +IlllIililI +Il1li1IIiI +i1Ill1Illi +IlIiIli1Il +IliII11iIi +i11l1liIIi +llIIiiiiIl +IIii11lIlI +li1i1iIlIi +lIilil1il1 +lIl1Ii1ill +lliIIi1lil +III1li1I1l +IilI111iil +Iii1i1IIlI +iIIiIi11il +IiIiiiI1iI +llIIlIiill +iiIIl1IIii +Il11111Iil +ii1lIiII1I +IliIilI1lI +Il1liIlIi1 +i11llIlil1 +ii11ilill1 +l1ii1IIiIi +iIiIilII1I +llI1lI1lil +IliiIIilil +Iillll1ll1 +i11i1IlIli +iIiliil1II +Iiiilil1l1 +Iili11Il1I +iiIIi1liii +IllllI1l1l +iI11Il1l1i +IiIIIIll1l +IlIi1I1liI +ii1li1Ilii +I1Iilii1l1 +IiI1lilill +I1i1Ii1iII +ili1lilll1 +iii1l1lill +li1iiliIIi +ilIilIIlII +lii11ii1il +IIIiII11i1 +lIi1iIi11I +iIIIl1Il1l +II1ilIIii1 +I11l11lII1 +ilIlIIiii1 +illi1iiIil +lII1i1lIII +IllIIlIii1 +IiIlil1ill +iIIIiI11ll +ilI11I111l +Ililii11il +iili1Iliil +iil1ililI1 +iI1lIlIlIl +IlIli1llIi +iliiili1ll +iIiI1lllIi +IlIiIlI1Il +IiiIl1lIIl +II11I1il1l +I1li1lI1Il +li11l1iill +IlIII1IiIi +lI1iiIIlli +IiIiIiI1Ii +liiIiIIl1i +iII1lI1i1i +il1I11lIll +i1llI1l1l1 +i1IiIIi1II +i1111iiI1i +iIIIIIi11l +IIlIlI1iI1 +iIiilill1l +I1llIIlii1 +li1I11ilII +ll1lliii11 +IIlIlI1Ili +lillIIIilI +iII1Iliiii +I1IiIi11iI +I1liil1lil +IiiIIli1lI +l1ilill1il +lIll1llli1 +Illl1IliII +liIll1lll1 +llI1Ili1ii +liiIiIl1Il +ililIl1I1i +IIii1l1liI +I1i1liIi11 +IliiIlllli +i1l1li1I11 +Il1illli1l +liilillil1 +IiIlllIll1 +liil11i1lI +lIiIIllIi1 +lI1IIIIII1 +I1llillilI +ill1IiiIIi +i1I1lllIiI +lilll1iIIi +llIII111Il +i1lil1lIli +iIiiIii1I1 +lliIlIllIl +i1liilIIiI +i1IIlllIl1 +l1ii11llI1 +i1lI1Il1ii +iIli1I1lIl +iIiil1l1li +IlIil1iIiI +lIi1iIlIIl +I1IIiii1li +IIil1lI11i +liiIi11i1i +il1iIiIl11 +iililIiIli +lil1iI1iIi +l1li1IIiii +i1ll11ilIl +I1i1iiIlii +iI1I1IIliI +iI1li1lll1 +liIIIIilll +i11Iii1i1I +iil11i1Ill +l11i1iIiiI +i1i111lI1l +Il1IIIIlii +iII1111111 +IIillll1l1 +l11iIIllii +IiI1lI1I1I +llillI1iI1 +Ii1i11lili +I1lilIi1lI +l11III111l +IiIl111l11 diff --git a/dict/package_dict.txt b/dict/package_dict.txt new file mode 100644 index 0000000..b6f5855 --- /dev/null +++ b/dict/package_dict.txt @@ -0,0 +1,1000 @@ +uvvUUvvuVU +UuvvVVUuvU +uvuVVvVuvu +uVUVvVvvVv +vUVUuuUuvV +UvVVvvUUuV +VvvuuuUVVV +uuVUVUvVuU +VuvUUVVVvV +VuuUvUVvuU +UUUuuUuvUv +UUuUvvvuvV +vvUvuuvVuv +VUUUvUUuUV +uVvVuVUvUv +VvuVVvVVUV +vvVUuVVVvu +VVVuVUvvvV +uVVUvVuVVu +vuuVvUUVvu +uVVuUuUvvv +uvVVUuVvuV +vuvUUvvuuv +vvUuuUUvuu +vvVUuVVVvv +VUuUuvuvvu +uuUvVVVvuV +UVuuuuUUuv +VVVvVvUUVU +vUVvUUUvUV +VuVVVUvUUu +uvvvUvUUVV +vVVUUVUVvU +uVVuvUvVVu +vuVVUuvvuu +vuUVuUVVuu +uuVUVVUUUv +uuUuvuvvVV +vUuvUVVVVU +UvUVuvUUvu +vvvVUUUuVU +UVUUVuUVvu +uvuUvuvuvU +uVUVvvVUVu +uvVVuuUUuu +vvUVvvuVvU +uvvuvvvUVU +uVVuVuUvuV +vUuUUUvVVU +vvvVvVUuuU +uVVuuVUUvv +uUVVvUUvUU +uVuVUUvuuv +uvUUuUvvUU +vuVvUVuVuv +vuVVuUuuVv +vuvvUUUvuU +uuVVuVUuvU +UUuUuUuuVU +uVVvVuUVuU +UVuvUUVuvu +VuVvvUuuuV +uVvVUUVvvV +uuVUUuUvvU +vuUuuUVuVU +UVuVuvUVVu +uuVuvvVVUU +uVvUvVvvuU +UuVuvuUvuv +VUVUuVvUuV +vvUUvVvVuU +uvuUUVUUVu +uuUVvVUUUu +VUVvVUVvvV +vuVUVUVVUU +UuvVvuvvuV +UVUvVvUvvV +UUvUuVVUUu +UuVvUvuUUv +vvVVuvuuuU +vvVUvvuVVV +uVUvuVUvuu +vVuuVuVvuV +vVvVVuvUVV +UUVVVvvvuV +UvvvVvUvUv +vVuvUvUuuu +vVUvVvuVVv +UvVvuuVuUv +vvUvUuVvvU +vUuUUvuvUv +vuuuuuuVvv +uuUVVVUUvu +VuvVVuUvVU +UVVvVuUUvU +vVvVvvUuUu +VVUvuVVVvu +uvvVVVvVUu +vUvuVvVVvv +vuVuvvvvUV +vvvUvuUvvv +uVvUuVuvUu +VVuUVvvUvU +uuVUvuVVUV +VUUvuvuvUU +VUvvvUUVuu +uVvUUUVvUU +vVuVvuUUuv +uuVUuVUVuU +vUuuuUVUvv +VuVvVvuUvU +uuuUVUUUVU +vVVvUuvUvv +UvuvVuUvvu +uvuUUVUvVv +uVUuvVvUuV +VvUvUvuvuv +uvVUvuuvVU +VvvuVuUuVv +VVUUVUUVUV +VuuVuVVvuU +UVvuUVUVUV +uVVVUVVuvU +uUVUuuVvuU +vuvvvVVUuV +VuVvUuuUUv +vvvUuvvUUu +uvUVUuVVuu +UuVVUuuUVV +vUUUUuuvuV +vuuvVUuuVV +VuuvvuvvVu +UUVVVVuuUv +uvUuUvVuUu +uvvUuVVUUV +UUUuvUUvVU +vVvuvVvvvU +vvVUuUvUVV +uUVVVuvuvV +vUuVUUUUvu +VvVVUUuuUU +UuUUUUVuUu +uuvvUuVUVu +UVVuUuuuuu +uUUUUuVuuV +vUVUUVVUUU +UVUVUuVUVV +UUUvvvuvvv +UUUuUvUvvu +VVVuVVVuVU +VuUuVvUVVv +VuVVVVUuuU +uUUUVvvUuu +uvuvvUvUuV +UUuVUvUUVU +UuuUUuvUUU +vVUUvUUvUu +vvvVUvuVuu +UUvuvUvUvU +vvuVVuvvuv +vuvUVvVvUu +uVUvuVuuVU +UvuvuuvUuU +UuVUUVVVvu +UvUvUUuuvV +vUVVuuUuVU +UuUuUUvUvv +vvVUvuUuUu +UVUvUuVVvu +uUvVvVVVVV +uVUVUuvUvv +UVUVUUuuVu +VvvvvvvvvU +UUvVuvvuvV +VVuVuuUuUv +VUvVvuuuvU +VUUuVUVUvU +VuvuVVUUvV +VUVuVuVuVV +vUVvuVuuVU +vVVVVuuuuv +uvUuUvVUvU +UvVuuuUuuv +uVuuVuVuvv +vuuVVuvuvu +vVUvuuUvVV +uUUVuUUvuu +UVuVUuVvvv +UvUvvVvvUV +uUuUUuvuVU +vUuuVuUuvv +vUUUuVUuuu +UUuVvUuUvu +vUUuVVvuvv +uvuUVVUvUU +uvuUUuUvVV +uuvvuUUvuu +vUVVuUUVVV +VUvuUUVvvv +vuvVUuuvVu +uuvUUvvUuu +uUuvVUuUVv +UuVVUuUuvv +vUvuVuuVVV +UvVVuuVVUV +vuUvvvUVUU +uvVVuVvuvv +UvuUvuuUvU +uUVUVvUvUv +UUVUVUUVuU +vUVUUvUvuv +VvvvvvvUvV +VvuuUUVUuu +uuvvUvvvUV +VUuVUUUuvU +VVVvvVvUuU +uuuvUVvuvV +VVvuUVUvUu +vuuvUuuuUV +vVVVuVUUuU +UUVvVUUVVU +VUVuuVVUUU +vVuVVVUVUv +uuVVUuVVUU +VVuUVvuvUv +uvUuVVVVuv +UuUvUUvVVu +vVUuvVvuuV +uvuvuUuuUU +UUuvUVvUuu +uvVvUUuVvu +vuvuvUvVVu +VVUuuUUUVV +vvuvuUUUvU +VvUUUUvVUV +VuvvUuvvUv +vuVuVvVvuV +uVVVuuvvvV +UvVUUUuUVu +vUVUUvuUuV +vvuuuuvuvU +uvuVUuVUVv +uuuuVUVuVU +VUVUVUuUVU +vUUVuVVvuV +vuUvuVvvuv +uUuUuuUVVv +VUvuUuvuvU +VUuvUvuuVU +VvVvvVVUvU +UuVUuvvvvU +UUUuvUUUuu +vUVuuVuuVU +VVvUuVUuVU +UVuvuvVuuu +uvvuvVvvvv +vuvUUVVvVV +vvUuUVVuUV +vvvVUuVvUU +vVUVUvuuVu +UvVVVVvUuU +VuUVUUUVvU +UvuVvvuVVu +vVvuvUUvvU +VUuVVUvuuV +VUuvVvVuVV +uvuVvuVuuu +VUUvUVuvvV +UvVVVvVuuV +vVvvvvuUVv +uUuUvUUVvv +uvUUuUuVVV +vvVUUvvuuU +VVuvVvvvuv +UVVUVvUuUu +VUuuvUuUvv +UvvuUVvUvV +uvVuVvUUvv +UvvvUVuuUV +VVUUUUUVvV +vVVvUVuuuv +uUUvvvuVuV +uUUuVUUVvu +UUUVVVuuUv +UvUuuVvUvv +vuvUuvUUUV +uvVvvUuuvV +VvvVVuUuuU +vVvvuVVUvv +UvVVVvUVuu +UVuUvVUUUv +uvvuvvuVuU +uUuVuVVUVu +vuuVUVUUuv +vuVvuvuuUu +vVVuuVVvuU +vUvuvuUVVv +UVuUUvvVuv +uuVuUVUUVu +VuuvVvUvVu +uUVVuuUuVu +VVUuUvvuUV +uuuuvVVvVu +UUvvVUvuuu +uuUvvvuVvu +VuVVVvUuVV +UUUVuuUvVv +uuvUVvvVvv +vUuvvUvVVu +vVVVvVuVVu +UuvuUvuvvU +VUuUVVuVUV +uVuvuVVUuU +VuvUUvvVvU +VVVUuvvUUu +uvVvVvUUvU +uuVVUuVVuV +VUVuvUuVVV +VUvVUVvVvV +uvvVUVUuuv +VVVVuUvUUv +VuVvVUUuUu +uvvVVuvuvu +vuvvuUuUUU +UUvVVUuVVU +uUuUUvuUuv +UVVvuVvuvU +vVvUuvVuUv +VvVvuVuVuu +vUUuvvvvUv +UVvUuUVvvU +vvvVVuuuuv +UvUUUvUVvv +UuvUVvuVvU +UUUvVVvVuu +uVUvVVuuvU +VUUVuuUvvU +uvUvVVuVUv +vuUUVvVvUV +vvUUVuVUvU +uUvVVuuVUv +UvUUuuUvvV +vVvuUUUvVv +vVuvvuVvuV +uVuVvvvVuu +uUvvVvUuuu +UuUVVuUVvV +uuvuvvvuuU +VuUuUUvVVu +UUUuvvVVuU +uUUVvVuVUV +VuuuUUVVvU +vvVuVuuUUV +VvVUUUVuuv +vvvVvuuVuv +UUuuuvVuuv +VUvvuUVuVu +vvuvVuuvuU +uvvuuuvVuU +UvuUuvVvUV +UvvvUVuVVU +uvuuvVUvuv +vVUvUvVvVV +UUvVvvUUVv +UuUVUuuuUV +UuVUuvvUUV +vuuUUVVuVu +uuvuUUVVvv +vUvvVVVUVu +vVUuuUuuUv +UVvuVVvvuu +vVVuUuuuVU +VuVUuvuUvV +UvUvuvUVVu +uuuUUvVvVV +vUVuVUuuvv +vuVvuVVvVv +UUvvUuuVuv +UvuVVUUUUv +VVuUuvuvUV +vVuVvvVuUu +uUuvvVvVuV +UVvVuUvUUu +VuUUuUvvuv +uuVVUuUVUV +VUvuUVuUVv +vuvuuvVuUv +vuUuvvUuUU +uUVUvVvvvV +UvuuuuUUvv +VuuuUuUVUv +UuVVVvVuVv +uUvUUVuUUv +vVVUUVvvUv +UvuVUuUVVU +UVvuuuVUUv +vuVvuUvUUU +VUUuUvuVVv +vUUvuuvuvu +uuVVuUvuvv +uuuVvuVVuU +UuUUvUuVUv +vuUvUuVUuV +VuvUUuVUUu +vvuUvUUVvV +vVuVUVUUUV +VuVVvVVVvu +UUuUuVuvvU +vVVVuvUVUu +vUuVVvuuuU +UVUvvUvuuv +uVuuVUuuvv +uuuVUVVvvU +VVVuvVvVUv +VVVUUuUUUV +VUVUUUVVuv +VuuuVVvvUu +UVuvVuuuuV +vuuvvUvuVU +vUuvUUuvuV +VVVuuvUuuv +uvvUuvUvVV +uvvVuuuVVu +vUUVUuVUuV +UVuVvuvVUV +UVUVuuvuvU +vUVuvUuVUU +VUvuUvuuVv +UUUVUVvUuU +uvuvuVvvVv +VuUuvVUuUV +uUvuUUVvVu +UuVVvUvUuu +vVuUVUUvuU +VUvUuVVvvV +uuvVvVvUUU +UVvVvUUVvv +uVUvVvVUuU +UuuvVUvvuU +UUvVvUuuVU +VVuuUVvVUU +uvvuuVUVUV +uvvuUUVVVU +vvuUUuVuuv +vUvuVVVUvv +VUUUvvvUvv +VVVUVvUUVV +vvVvuuUvUv +vuVVvuvUVV +UVVVvVuUVv +uUUuUvuVvu +uUUUVuuUuv +VuVUvUvuuV +UuuuvvvvUV +UVUvVVvUuu +VUVUUVuvVV +vvUvvVvvvu +vUUvuuUVuu +VUvvUUUVuV +uvuvVvUVvV +VvUuvUuvUV +uvuVuvvUUv +UvuuUvvuvU +VVVuVUUvUv +vVvuVVvVVv +uUuuUUuVVu +UVVUUUVUuv +UUuvUVuvUv +uVVuvVVVVV +vVvvVUvuUv +uUVUVVUuvu +VUuvVuuUvu +UUVvuuvvVV +UUVvVvuVVV +vUvvUUvuVu +uUVvvuUVvu +vuUvVuUUUU +VVVUUUVUvv +VUVvVVuVuU +vUvuvUUUuu +UuVuVvvvvV +vuvVuUVVuv +VuVVuvVVUU +UuUuVVvuvV +VVVvvUuUVv +UvuVUvVuvu +uVUUVUVvvU +UuUUVVVuUu +vuvVuVvVUu +uUvvuuvVUV +VUuUUVvUUV +VUuUUUvuUU +VUuuvVuVUu +vUvVvVvVvv +VvUVUvuuvv +vvVuUUUVUv +uVUvvUVvuu +uvvvUuuvvU +UuUuUvuvuV +UvVvvUuuvv +VVvVvVvvuu +UUvUuUUvUV +uUvvUVvVUV +UVvuvUVVvu +VvVuuvuVvU +vvUuVuVVuv +vVUvVUUuVU +UVVUuVuvuV +vUVvUUUvuv +uVUVVvvvvu +VvuUuVvVVV +uVUvVVVvuu +vVuVUUuVvu +vuVvvVvVVv +UvUuuVvVVU +vuUVuuUvvu +VuuVUVUUUU +VuUvUVUuvV +UvUvVuuvUu +uuvUVuVuuV +uUUuvVuVuV +uVvuUuUuUv +vVvuvVvuVV +uVUVVuuvUU +UUvUuvUVvU +uUvVvUuvUV +UuuUVUuVuU +vuvuUvuVVu +VVuVUuUuuU +uVUUVUuvUU +vvuUvVuuUV +UvvVUVuuvU +UUVvUuVUUV +uuvvUuVUvv +VvUUUUUuuV +uUUUuVvuVV +uUUUuVuuuU +VuuuUvVvvV +VVVuVVvUVV +vvuVvUVvVU +uVvuuvvuuu +uuvuVuUuvU +UuvuvuvUuV +vVuVUuvuvU +vvVvuuvUuU +UUUvvvvUuU +UvUVvvVUvu +uuuvVuvvvU +uuvUuVvuvU +UUuVuuUuVU +uVvuUuvuuU +uVvVuvvuuv +UuUvVUuvuV +vVvUuUuUUV +UUVuvuvUVU +UuvVUvuuuv +vuUUUuUvuU +vUVUUuUVvv +VuUUVVvVVU +uUVuuuVVuv +UUUuvUUvVu +UUvVuvvuvU +VvVUvUuVVU +VUVvVvUvuu +UvvVuvVvUV +vUuuvvvUvv +vuuvuVVUVV +UUUuuuuVUU +UvuVvUvvVU +UuVVuuvVVV +UvuuuuVVVU +uUvVVuvVuu +vVuuUuVuuU +VVUuVVUUVu +UUVVUvUvvV +vvvvuUVVUu +VUUVvuVuvV +UvUvVVuuUv +UVvUVUvVuV +uVVuUVUUUU +uvVUvUUVuV +uuUUUuVVVU +UVVuVVuUvU +UvUVUvUvuU +vUVVVVVuVu +VVuvUVvUVV +VUuVvvvuuU +UuuvUVvuVu +vUUvVVuUVu +uVuVvvVvVV +vuUvUVuUVv +VVuVVVuUVu +UVVvVuVvvU +UUVvVVUvVV +uuUuuVUuUU +vVVvVVuvvv +uuvvuVVVUu +vVvUuuuuvV +vvVUVVUUuU +VuuuUVvUUu +uUvUuUvVuV +uVUvuvuUuV +UvuVvVVUuv +uVUVVuUVUu +UuuUuVvVVv +uVVuuUVvuv +VUUvVvUvvu +UUVuuUUUuV +uuUVuUUvuu +vUVuVVvuvU +VvVVVUvVUu +VvVVVvUuUv +uvUVuvuuvv +uUVuuUuUUU +vuuvVvUVvv +uuvvUVUVVv +vvVVUUvVVU +UvUvUuvvvu +uvvUvVvuuu +vuuUvUUuVv +VvVVUvUvUU +UvuVUvvvuU +VUuuUVVVVV +VVUvvuuVvU +UvvUvUUuvv +UuVUuUVUvv +UuvVvvVVvU +UvvuVUvVUV +UUvvUuvVVV +uVUvuVVuvU +UVvUuUVUUU +UuuuvuvUVV +uUuVVuuUVU +vVUUuvvUUU +VUVUVVuuUU +VUVvuvVuVV +VvUVUUvuVu +vUuuVUuvUU +VVuvUuUvVV +vuuUUUUvvu +UvVVUUuvVv +UuuUUVvvVU +uvUuVuvuuV +uuVVuUuvVU +VvUvUuuUvu +UvUVuVVuVv +VVuUuVvVUV +UvuuUvUUUV +VvuvuuVVvV +uVuVUuuuuv +vUVvuuUuUv +vVuVVuuUVV +VuvvUUUUVu +VuVuVVUVUV +VvUVVVUUVv +VUVVvuVvUv +vUVvvvvVUU +vvuVUvuvVU +UvUuUVvuvV +vvVVvvUuVU +vuUUuUuuUu +VuuvvVUuVU +VUVuUUuvUv +UUUuUVUVuV +uUUVUvuvuv +UUuVvVuUvV +VUUvVVUvvv +uvVVuvuVvV +VvvVUUvUvu +vuuUvvuvVU +UvvuUVUuVu +UuUvvUvuVU +VuuVuvvvvv +vVVUUUuUuU +UVUVUUUuUu +VUUVVuuUVV +VVuuvUUuvU +vUuVUuuUUV +uVvvVvvuUV +uvVVvuVUuv +UuVUuUvVvV +UuvUuuUvUV +VUvuuVuvvu +vvVuVuvuvu +uUUVuuUuuV +uVUvuuvvVU +UUUUUUUvUv +vVUUuVuVvU +UvuvvuUvVV +uvuUVuuUUU +VvUvUVUvVu +vUUVvvVUvu +vuVUVUUvUu +vvuVVUuUuV +VUVvuvvUvu +VUvuVuuuuV +UvVVUuUuVU +VUUuVvuvvu +VvuuvVvuuv +UuUUuUuVuv +UUvVuUuuVU +VUUUUVvVVU +VVUVvvuUVv +vVUvvuuuVu +uuvuVvvUUu +UUVvUVvvUV +uUuuuvvuUu +vUvVVVvuUU +vvUuvuuUUU +VVUvUUvUvV +UUvuvuuVUU +vUUuvUVVvV +VvUuvVUVVu +VUUuVUuUvV +UVVvuvVuUv +vVVuvUVvvu +vUuvUuvuUV +uVUUvVuvuu +vuVUvvUVVv +UVvvvUuuUu +vvVVuuVVVv +VuuUvvVvvV +vvuuVuUVUv +uvvUUuvvUU +vUUUUvvuuv +uUvuVuuVVV +VuuvVuvVuu +UUVUvuVVUV +VVUUuuVVUv +uvuVUuVvVV +VVVvVVUVVv +UVvuuVUuuv +uVVVuUUVuV +uvUuUVvvuV +VUUUUuUvUv +vVuvVuVUUu +UvUUvVUUuv +UvvuUuUVuu +UVvvVUVUvU +VvuuuVVvVv +VvUvvUUvVU +vvUVvVuvVU +uUvuvuVuvV +UvuUvVVuVU +VUVUVVUVUU +uUuvUVUuuU +VvuUUuUvUV +UuVuVUUVuv +vvuUuvVVVu +UvVuVVVuuU +UvUUVVUUUU +VvvvvuuuVV +uuVUUVUuvu +uvvvUVVVVU +VuvVuvvVuu +vVvuuVvuuU +vuuVVVUvUU +uuuVuuUUvV +UvuuuUVvuV +UUvVvvuuuU +vuVuuVuvVU +vuuuvUVVVU +UVuUUUUvUV +vUuVUuuvUv +vVuvUVVvuu +UuVVvUuUUv +uvUvVvUvVv +UVUVuvVVvU +uVvvUUVVvU +vUVVuuUuVV +vVUvvuUvUv +UUUVUVvVuv +UvUUuVUuVv +uUuuVuVvuu +VVuuvVUVvv +uuuVuUVUUU +vVuvvVUVvV +vUUVUVvuUU +uuvUvuVvuu +UVuuUvVvUU +UvUVUVuVUV +vUUvvVuvVU +vvUvuUUvuU +VuuuvVUUVv +uUVVuuuVUu +uuuvuvvVuv +uuvUVUvvVu +uuvUUVuuuu +vUUuUUuUVV +vVUVVuuVUV +uuvuuVVvvV +VUuUVuuVuv +VuUuUUvuvU +UuvVuUUVuV +vUUVvuUVvu +vUuUVvvuUu +uVUvvvUVVv +VVUvvuVvuu +vVVvVVuvvu +VUVVUuvUVv +VuvvvuuvVu +vUVuvVVvuu +VVUVVvVUVU +UUuuUUuvVV +VuVuuvVUVv +UuvuvvVUVU +VUVUvUvUvv +VUuVuUUVVv +VUUvVVVVuV +VVUUUVuVvv +UVuuVVVuuv +uuUUuuVUvv +UuvvuVVuUu +VuvuuUuUVV +UvUVVUVVVU +UUuUUvuVvV +UUvvuvUUuU +VVVUvUvVVv +UvUVuUVVvU +uuvuUUvVvu +VVVvvVUvvV +UUvVUuUUUU +UuVuuVvuuV +UVUUUUVUUV +vVVvuUvuUu +uUvuuUvVvv +vUuVvVVuUv +uUUUUUUuUu +vvUUuVuvuV +VUUuUVUUVu +UuVUvvVUuv +vvvvvVvvUv +uuuVuUUUVv +UvVVuvuVVU +vVuuvuvuUu +uuUVVuVvvv +uUVvvuuVVU +uvvVvVuVvu +vvvuvvUuuV +vvUVuuVUUu +vvVvVUVUvU +UvvvVVuvuU +vVuVUuvUuv +VvVUvuvVvU +VUvuuVUVvU +VvVVUvvVvU +vUvVvuUuuv +VUuvuvUVvU +UVUuVvuvuv +VvvUVuVuVu +VvuvvVvuUu +vUUVvvvvUv +VvVUUvuvUu +uuVuUuVUVV +vuVuvvuuVu +uvVuvVUuVv +uVuUuUuVvU +uUuVVUUVUu +UuVVvvVVvU +UVvVVUVvUu +vUvUuUvuVv +uuvuuVvVUU +VuVUVvUvVu +VVvuuuuUVU +UuuVVVvVuV +uuUUUVUUuV +VUvvVVuUvu +uUvUvuUUvu +uUVvVVvuUU +uuVuvvUvuV +uVuuuuUuUV +UvvvuuvvuU +VUuVuUuUUv +uvVvUVVuvu +uuUvvuUVVu +vUVUVvvUVu +uUUUVUUUVv +uuvvuvUUuU +vvVUuvVUVv +vVuUvvUVvv +UuvuVvuVvu +UuvVvUvVvv +vuUVvvUUvU +UVuvuVUuvU +vUVVVuVvuv +vvUvvVvUUV +uuvuVVUvVu +vuVVUVuVVU +VuvuuvUUuU +VvVvvVvvuU +uVvuuVVUuu +VVUvUuVVUv +vvvVvUuVuU +VUuvUuvuvV +uUVuUuvvvu +vuVVVuvUvv +uvUvVuVUvv +UVUUvvUUUv +vvVUVuVvuU +vUUVuvuVuU +vUVvvvUUVU +vVvvUVuvVU +VVuVvUUvuv +vvUuuVUUVU +uVuUvVVVVV +VVuuVuUuVv +VUVvUvuVVU +VVvvvvuvuv +uuVVvvvvUv +uuUVVUVUuu +UvuuvvUvUv +uuuUVuUuUu +VUuUvuvUUv +uUuUVuuvuv +VvUuuuVUVV +UVuuUuuUUv +vVvvvvVVVu +uvVVuVuVVv +vvUuvuvuuu +vVVuvUuuUu +vvuUUUvuvv +VUuuUUuuuu +vvuvuuvvuU +UuuuuUVVvu +UVVuUVVUUU +vUvvvvvUVV +UVUUUVuVUu +vuUVUvvUvV +uvVUvvvuuu +vUVUVvUvUv +UUvVvuvVVU +VvVvUVuVvu +vVVUuVUuvu +VuvvvVVVUV +uvvuvVVuUv +VuVUUUVvuu +UuuuUUUUvu +vUuuvVVvVV +vVVuVUVUvU +uuUuUuvVUV +uUuvvvvUUU +VUUvvuuUUv +vVVuuUvvVu +VvUVVuuuvv +VUUuVvvVVV +UUVvuvvUUU +uVVvUUVVUv +uVUuuVuuuu +UvUVuvvuuU +UvVvVVVvUV +vvvvVuUVVu +vVVuVUUUUU +UvVuuVvvuu +vVuUvvvUVv +vUUVuuVvuu +UvvVUVuvUV +vuvUVVuVUV +UuUuuvuuUU +UVuvuUVVVV +vUuVuUuuVV +vUVUvUuvvV +VvvvvUuVuv +vvUUUVuVvV +VVvVuuVUvu +uvVvvVUVuv +uUVuUuuuvV +UVVUvuVVVu +UVvVuVuUvU +UvUUVUVUUu +VUVuVUVUVV +uVUuuUVUVv +VUVUuVUUVv +vVUUUUvvuv +vvvVVVVvvV +vUuuVuuvuU +VuuVvvVuuV +vUvuUUvvUU +uVvUuVvUUU +UUuUuuVvvu +uvUVvuvVUU +vVUvUuVvvU +UUuVUvuvVU +uVUVvvVVUv +uVvuuuvuvU +VvvUuvVvuv +uUVvVVuVvv +uvUVVuUvvv +UuuUUuUuUu +UVuUvUuUVv +VUVUVVuuUV +UUvuUUUUuv +VUVUuUuvvV +vVUUVVvUVu +UuUvUUvuVV +UuvUUUVUvU +UUuvuuVVuu +uuvVvvvvVu +uUvUVUuvUv +uUvVVvvVVV +uvuVuvVvUU diff --git a/gitattributes b/gitattributes new file mode 100644 index 0000000..f811f6a --- /dev/null +++ b/gitattributes @@ -0,0 +1,5 @@ +# Disable autocrlf on generated files, they always generate with LF +# Add any extra files or paths here to make git stop saying they +# are changed when only line endings change. +src/generated/**/.cache/cache text eol=lf +src/generated/**/*.json text eol=lf diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..129dda1 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,64 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configuration-cache=false +neoForge.parchment.minecraftVersion=1.20.1 +neoForge.parchment.mappingsVersion=2023.09.03 + +# enable ProGuard +enableProguard=false +## Environment Properties + +# The Minecraft version must agree with the Forge version to get a valid artifact +minecraft_version=1.20.1 +# The Minecraft version range can use any release version of Minecraft as bounds. +# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly +# as they do not follow standard versioning conventions. +minecraft_version_range=[1.20.1,1.21) +# The Forge version must agree with the Minecraft version to get a valid artifact +forge_version=47.3.4 +# The Forge version range can use any version of Forge as bounds or match the loader version range +forge_version_range=[47,) +# The loader version range can only use the major version of Forge/FML as bounds +loader_version_range=[47,) +# The mapping channel to use for mappings. +# The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"]. +# Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin. +# +# | Channel | Version | | +# |-----------|----------------------|--------------------------------------------------------------------------------| +# | official | MCVersion | Official field/method names from Mojang mapping files | +# | parchment | YYYY.MM.DD-MCVersion | Open community-sourced parameter names and javadocs layered on top of official | +# +# You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. +# See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md +# +# Parchment is an unofficial project maintained by ParchmentMC, separate from Minecraft Forge. +# Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started +mapping_channel=parchment +# The mapping version to query from the mapping channel. +# This must match the format required by the mapping channel. +mapping_version=2023.09.03-1.20.1 +mapping_lasting_version=2023.09.03 +## Mod Properties + +# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} +# Must match the String constant located in the main mod class annotated with @Mod. +mod_id=superleadrope +# The human-readable display name for the mod. +mod_name=Super Lead Rope +# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. +mod_license=GPLv3 +# The mod version. See https://semver.org/ +mod_version=0.0.0.1 +# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. +# This should match the base package used for the mod sources. +# See https://maven.apache.org/guides/mini/guide-naming-conventions.html +mod_group_id=top.r3944realms.superleadrope +# The authors of the mod. This is a simple text string that is used for display purposes in the mod list. +mod_authors=R3944realms +# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. +mod_description= A Lead Rope which is better than Bugjump. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..f5172b8 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,10 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +guava = "33.4.5-jre" +junit-jupiter = "5.12.1" + +[libraries] +guava = { module = "com.google.guava:guava", version.ref = "guava" } +junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..1b33c55baabb587c669f562ae36f953de2481846 GIT binary patch literal 43764 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..db3a6ac --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/proguard.pro b/proguard.pro new file mode 100644 index 0000000..0f27c54 --- /dev/null +++ b/proguard.pro @@ -0,0 +1,78 @@ +######################################## +# Super Lead Rope ProGuard 配置 +# 作者: R3944Realms +# 适用于 Minecraft 1.20.1 + Forge +######################################## + +#--------------------------------------- +# 保留主类 (Forge @Mod 入口) +#--------------------------------------- +-keep public class top.r3944realms.superleadrope.SuperLeadRope { + public (); +} + +# 保留 Forge EventBus 订阅方法 +-keepclassmembers class ** { + @net.minecraftforge.eventbus.api.SubscribeEvent ; +} + +#--------------------------------------- +# 保留注解、调试信息 +#--------------------------------------- +-keepattributes *Annotation*,Exceptions,InnerClasses,Signature,SourceFile,LineNumberTable,StackMapTable + +#--------------------------------------- +# 保留 Minecraft / Forge / Mixin +#--------------------------------------- +-keep class net.minecraft.** +-keepclassmembers class net.minecraft.** { *; } +-dontwarn net.minecraft.** + +-keep class net.minecraftforge.** +-keepclassmembers class net.minecraftforge.** { *; } +-dontwarn net.minecraftforge.** + +-keep class cpw.mods.** +-keepclassmembers class cpw.mods.** { *; } +-dontwarn cpw.mods.** + +#--------------------------------------- +# 保留资源文件 (mods.toml / assets / data / pack.mcmeta) +#--------------------------------------- +-keepdirectories META-INF,assets/**,data/** + +#--------------------------------------- +# 混淆配置 +#--------------------------------------- +-renamesourcefileattribute SourceFile + +# 可选字典 (需手动提供 dict.txt) +-classobfuscationdictionary dict/class_dict.txt +-obfuscationdictionary dict/member_dict.txt +-packageobfuscationdictionary dict/package_dict.txt + +# 全局 repackage (避免 Forge 找不到入口) +-repackageclasses 'contents' + +#--------------------------------------- +# 构造器保留 +#--------------------------------------- +-keepclassmembernames class * { + (...); + void (); +} + +# 允许混淆内部类 +-keep,allowobfuscation class *$* { *; } + +#--------------------------------------- +# 稳定性配置 (避免奇怪验证错误) +#--------------------------------------- +-dontshrink +-dontoptimize +# -dontpreverify + +#--------------------------------------- +# 输出映射文件 +#--------------------------------------- +-printmapping build/libs/0xn-mapping.txt diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..497a012 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,11 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + maven { url = 'https://maven.neoforged.net/releases' } + maven { url = 'https://maven.parchmentmc.org' } // Add this line + } +} +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' +} \ No newline at end of file diff --git a/src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 b/src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 new file mode 100644 index 0000000..c5822cb --- /dev/null +++ b/src/generated/resources/.cache/1de3d2ee724999f84a11b20b51c37030049be277 @@ -0,0 +1,2 @@ +// 1.20.1 2025-08-02T18:29:50.5044172 Languages: zh_tw +d8984a2a501a148017582d1745d24136f24840a6 assets/superleadrope/lang/zh_tw.json diff --git a/src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac b/src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac new file mode 100644 index 0000000..81ccea2 --- /dev/null +++ b/src/generated/resources/.cache/2a65ee2815744be1ef1ffdae1c9a37f2a9cbe2ac @@ -0,0 +1,2 @@ +// 1.20.1 2025-08-02T18:29:50.4900479 Languages: zh_cn +1d742b4bdaf09cf0bb27b838c05b37d404f9d805 assets/superleadrope/lang/zh_cn.json diff --git a/src/generated/resources/.cache/31f65342fc4da49cb4df4f994bdb8a2aa9453b5d b/src/generated/resources/.cache/31f65342fc4da49cb4df4f994bdb8a2aa9453b5d new file mode 100644 index 0000000..bbd41ea --- /dev/null +++ b/src/generated/resources/.cache/31f65342fc4da49cb4df4f994bdb8a2aa9453b5d @@ -0,0 +1,3 @@ +// 1.20.1 2025-08-02T12:46:53.5980773 Item Models: superleadrope +c982e91b60c03a6460d1cc7b516628cf09a28417 assets/superleadrope/models/item/broken_super_lead_rope.json +4fb737a5f8f15642212aa581a02a81cf649fc36f assets/superleadrope/models/item/super_lead_rope.json diff --git a/src/generated/resources/.cache/735031f3addf80804addae5e3f53249900116f1e b/src/generated/resources/.cache/735031f3addf80804addae5e3f53249900116f1e new file mode 100644 index 0000000..affc392 --- /dev/null +++ b/src/generated/resources/.cache/735031f3addf80804addae5e3f53249900116f1e @@ -0,0 +1,2 @@ +// 1.20.1 2025-07-29T13:13:42.0738178 Sound Definitions +2c6cead888f42f1ca6fbc3081e43c73e26a4543e assets/superleadrope/sounds.json diff --git a/src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 b/src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 new file mode 100644 index 0000000..f74d9d2 --- /dev/null +++ b/src/generated/resources/.cache/82018c5420b46ddbb7071e62df09fdecd98133e6 @@ -0,0 +1,2 @@ +// 1.20.1 2025-08-02T18:29:50.5014197 Languages: lzh +b9129899dc35bdeb8acf2451acab08ce358dfd8d assets/superleadrope/lang/lzh.json diff --git a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e new file mode 100644 index 0000000..869f26c --- /dev/null +++ b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -0,0 +1 @@ +// 1.20.1 2025-08-02T18:29:50.496049 Recipes diff --git a/src/generated/resources/.cache/9fc560db70239f9631ea2b54518b8d5ada1a7b88 b/src/generated/resources/.cache/9fc560db70239f9631ea2b54518b8d5ada1a7b88 new file mode 100644 index 0000000..b84ae29 --- /dev/null +++ b/src/generated/resources/.cache/9fc560db70239f9631ea2b54518b8d5ada1a7b88 @@ -0,0 +1 @@ +// 1.20.1 2025-07-29T13:13:42.0601667 Tags for minecraft:item mod id superleadrope diff --git a/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 new file mode 100644 index 0000000..44f902e --- /dev/null +++ b/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -0,0 +1,2 @@ +// 1.20.1 2025-08-02T18:29:50.4980437 Languages: en_us +4cf775c9c9c637391296805dbd65edea025bf959 assets/superleadrope/lang/en_us.json diff --git a/src/generated/resources/.cache/d7cb74d6995b7cac24bbd97d180aabe19e79a2c1 b/src/generated/resources/.cache/d7cb74d6995b7cac24bbd97d180aabe19e79a2c1 new file mode 100644 index 0000000..bc96d32 --- /dev/null +++ b/src/generated/resources/.cache/d7cb74d6995b7cac24bbd97d180aabe19e79a2c1 @@ -0,0 +1 @@ +// 1.20.1 2025-07-29T13:13:42.0621667 Tags for minecraft:block mod id superleadrope diff --git a/src/generated/resources/assets/superleadrope/lang/en_us.json b/src/generated/resources/assets/superleadrope/lang/en_us.json new file mode 100644 index 0000000..611bbab --- /dev/null +++ b/src/generated/resources/assets/superleadrope/lang/en_us.json @@ -0,0 +1,8 @@ +{ + "entity.superleadrope.super_lead_knot": "Super Lead Knot", + "entity.superleadrope.super_leash": "Super Leash", + "item.superleadrope.super_lead_rope": "Super Lead Rope", + "sound.superleadrope.subtitle.lead_break": "Lead Break", + "sound.superleadrope.subtitle.lead_tied": "Lead Tied", + "sound.superleadrope.subtitle.lead_untied": "Lead Untie" +} \ No newline at end of file diff --git a/src/generated/resources/assets/superleadrope/lang/lzh.json b/src/generated/resources/assets/superleadrope/lang/lzh.json new file mode 100644 index 0000000..2dfddfa --- /dev/null +++ b/src/generated/resources/assets/superleadrope/lang/lzh.json @@ -0,0 +1,8 @@ +{ + "entity.superleadrope.super_lead_knot": "神駒羈縻索結", + "entity.superleadrope.super_leash": "神駒羈縻索", + "item.superleadrope.super_lead_rope": "神駒羈縻索", + "sound.superleadrope.subtitle.lead_break": "索絕", + "sound.superleadrope.subtitle.lead_tied": "繫索", + "sound.superleadrope.subtitle.lead_untied": "解索" +} \ No newline at end of file diff --git a/src/generated/resources/assets/superleadrope/lang/zh_cn.json b/src/generated/resources/assets/superleadrope/lang/zh_cn.json new file mode 100644 index 0000000..93e271c --- /dev/null +++ b/src/generated/resources/assets/superleadrope/lang/zh_cn.json @@ -0,0 +1,8 @@ +{ + "entity.superleadrope.super_lead_knot": "超级拴绳结", + "entity.superleadrope.super_leash": "超级拴绳", + "item.superleadrope.super_lead_rope": "超级拴绳", + "sound.superleadrope.subtitle.lead_break": "拴绳断裂", + "sound.superleadrope.subtitle.lead_tied": "拴绳系上", + "sound.superleadrope.subtitle.lead_untied": "拴绳解开" +} \ No newline at end of file diff --git a/src/generated/resources/assets/superleadrope/lang/zh_tw.json b/src/generated/resources/assets/superleadrope/lang/zh_tw.json new file mode 100644 index 0000000..c76a457 --- /dev/null +++ b/src/generated/resources/assets/superleadrope/lang/zh_tw.json @@ -0,0 +1,8 @@ +{ + "entity.superleadrope.super_lead_knot": "超級拴繩結", + "entity.superleadrope.super_leash": "超級拴繩", + "item.superleadrope.super_lead_rope": "超級拴繩", + "sound.superleadrope.subtitle.lead_break": "拴繩斷裂", + "sound.superleadrope.subtitle.lead_tied": "拴繩係上", + "sound.superleadrope.subtitle.lead_untied": "拴繩解開" +} \ No newline at end of file diff --git a/src/generated/resources/assets/superleadrope/models/item/broken_super_lead_rope.json b/src/generated/resources/assets/superleadrope/models/item/broken_super_lead_rope.json new file mode 100644 index 0000000..901ab28 --- /dev/null +++ b/src/generated/resources/assets/superleadrope/models/item/broken_super_lead_rope.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "superleadrope:item/broken_super_lead_rope" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/superleadrope/models/item/super_lead_rope.json b/src/generated/resources/assets/superleadrope/models/item/super_lead_rope.json new file mode 100644 index 0000000..38e9b8a --- /dev/null +++ b/src/generated/resources/assets/superleadrope/models/item/super_lead_rope.json @@ -0,0 +1,14 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "superleadrope:item/broken_super_lead_rope", + "predicate": { + "superleadrope:broken": 1.0 + } + } + ], + "textures": { + "layer0": "superleadrope:item/super_lead_rope" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/superleadrope/sounds.json b/src/generated/resources/assets/superleadrope/sounds.json new file mode 100644 index 0000000..ddb3691 --- /dev/null +++ b/src/generated/resources/assets/superleadrope/sounds.json @@ -0,0 +1,24 @@ +{ + "lead_break": { + "sounds": [ + "superleadrope:item/superlead/lead_break" + ], + "subtitle": "sound.superleadrope.subtitle.lead_break" + }, + "lead_tied": { + "sounds": [ + "superleadrope:item/superlead/lead_tied1", + "superleadrope:item/superlead/lead_tied2", + "superleadrope:item/superlead/lead_tied3" + ], + "subtitle": "sound.superleadrope.subtitle.lead_tied" + }, + "lead_untied": { + "sounds": [ + "superleadrope:item/superlead/lead_untied1", + "superleadrope:item/superlead/lead_untied2", + "superleadrope:item/superlead/lead_untied3" + ], + "subtitle": "sound.superleadrope.subtitle.lead_untied" + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/superleadrope/CommonEventHandler.java b/src/main/java/top/r3944realms/superleadrope/CommonEventHandler.java new file mode 100644 index 0000000..a4a0622 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/CommonEventHandler.java @@ -0,0 +1,112 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.entity.vehicle.Minecart; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.entity.EntityJoinLevelEvent; +import net.minecraftforge.event.entity.EntityLeaveLevelEvent; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; +import top.r3944realms.superleadrope.content.capability.CapabilityRemainder; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.content.entity.SuperLeashEntity; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; +import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem; +import top.r3944realms.superleadrope.core.leash.LeashInteractHandler; +import top.r3944realms.superleadrope.core.leash.LeashSyncManager; + +public class CommonEventHandler { + @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = SuperLeadRope.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE) + public static class Game { + @SubscribeEvent + public static void onEntityJoinWorld(EntityJoinLevelEvent event) { + Entity entity = event.getEntity(); + if (entity.level().isClientSide) return; + if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) { + entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(LeashSyncManager::track); + entity.level().addFreshEntity(new SuperLeashEntity(entity.level(), entity)); + } + } + + @SubscribeEvent + public static void onEntityLeaveWorld(EntityLeaveLevelEvent event) { + Entity entity = event.getEntity(); + if (entity.level().isClientSide) return; + if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) { + entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(LeashSyncManager::untrack); + } + } + @SubscribeEvent + public static void onPlayerHitOnBlock (PlayerInteractEvent.RightClickBlock event) { + Level level = event.getLevel(); + if (level.isClientSide) { + return ; + } + BlockPos blockPos = event.getHitVec().getBlockPos(); + BlockState blockState = level.getBlockState(blockPos); + if (SuperLeashKnotEntity.isSupportBlock(blockState)) { + SuperLeadRopeItem.bindToBlock(event.getEntity(), level, blockPos, event.getItemStack()); + } + } + + @SubscribeEvent + public static void onPlayerClone(PlayerEvent.Clone event) { + CapabilityRemainder.onPlayerClone(event); + } + + @SubscribeEvent + public static void onServerTick(TickEvent.ServerTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + LeashSyncManager.forEach((i -> ((LeashDataImpl) i).checkSync())); + } + } + + @SubscribeEvent + public static void onEntityInteract (PlayerInteractEvent.EntityInteract event) { + LeashInteractHandler.onEntityInteract(event); //处理实体互动 + } + + @SubscribeEvent + public static void attachCapability(AttachCapabilitiesEvent event) { + CapabilityHandler.attachCapability(event); + } + } + @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = SuperLeadRope.MOD_ID, bus= net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD) + public static class Mod { + @SubscribeEvent + public static void onCommonInit (FMLCommonSetupEvent event) { + event.enqueueWork(() -> { + }); + } + @SubscribeEvent + public static void registerCapability(RegisterCapabilitiesEvent event) { + CapabilityHandler.registerCapability(event); + } + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/SuperLeadRope.java b/src/main/java/top/r3944realms/superleadrope/SuperLeadRope.java new file mode 100644 index 0000000..126fc07 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/SuperLeadRope.java @@ -0,0 +1,40 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope; + +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import top.r3944realms.superleadrope.core.register.SLPEntityTypes; +import top.r3944realms.superleadrope.core.register.SLPItems; +import top.r3944realms.superleadrope.core.register.SLPSoundEvents; +import top.r3944realms.superleadrope.network.NetworkHandler; + + +@Mod(value = SuperLeadRope.MOD_ID) +public class SuperLeadRope { + public static final Logger logger = LoggerFactory.getLogger(SuperLeadRope.class); + public static final String MOD_ID = "superleadrope"; + public SuperLeadRope() { + IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus(); + SLPItems.register(eventBus); + SLPEntityTypes.register(eventBus); + SLPSoundEvents.register(eventBus); + NetworkHandler.register(); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/ClientEventHandler.java b/src/main/java/top/r3944realms/superleadrope/client/ClientEventHandler.java new file mode 100644 index 0000000..91d9c48 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/ClientEventHandler.java @@ -0,0 +1,65 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client; + + +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.EntityRenderersEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.client.model.SuperLeashKnotModel; +import top.r3944realms.superleadrope.client.model.geom.SLPModelLayers; +import top.r3944realms.superleadrope.client.renderer.entity.SuperLeashKnotRenderer; +import top.r3944realms.superleadrope.client.renderer.entity.SuperLeashRenderer; +import top.r3944realms.superleadrope.core.register.SLPEntityTypes; +import top.r3944realms.superleadrope.core.register.SLPItems; + +@OnlyIn(Dist.CLIENT) +public class ClientEventHandler { +// @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = SuperLeadRope.MOD_ID, value = Dist.CLIENT, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE) + public static class Game { + // 未使用-注释 + } + @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = SuperLeadRope.MOD_ID, value = Dist.CLIENT, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD) + public static class Mod { + @SubscribeEvent + public static void onClientInitializer (FMLClientSetupEvent event) { + event.enqueueWork(() -> { + ItemProperties.register( + SLPItems.SUPER_LEAD_ROPE.get(), new ResourceLocation(SuperLeadRope.MOD_ID, "broken"), + (itemStack, clientLevel, livingEntity, i) -> { + if (!itemStack.isDamageableItem()) return 0.0F; + + return itemStack.getDamageValue() > 1024 - 50 ? 1.0F : 0.0F; // 损坏 → 返回 1.0(触发 override) + } + ); + }); + } + @SubscribeEvent + public static void onRegisterModelLayer (EntityRenderersEvent.RegisterLayerDefinitions event) { + event.registerLayerDefinition(SLPModelLayers.SUPER_LEASH_KNOT, SuperLeashKnotModel::createBodyLayer); + } + @SubscribeEvent + public static void onRegisterRenderer (EntityRenderersEvent.RegisterRenderers event) { + event.registerEntityRenderer(SLPEntityTypes.SUPER_LEAD_KNOT.get(), SuperLeashKnotRenderer::new); + event.registerEntityRenderer(SLPEntityTypes.SUPER_LEASH.get(), SuperLeashRenderer::new); + } + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/model/SuperLeashKnotModel.java b/src/main/java/top/r3944realms/superleadrope/client/model/SuperLeashKnotModel.java new file mode 100644 index 0000000..7917a11 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/model/SuperLeashKnotModel.java @@ -0,0 +1,71 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.model; + + +import net.minecraft.client.model.HierarchicalModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.CubeListBuilder; +import net.minecraft.client.model.geom.builders.LayerDefinition; +import net.minecraft.client.model.geom.builders.MeshDefinition; +import net.minecraft.client.model.geom.builders.PartDefinition; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + +@OnlyIn(Dist.CLIENT) +public class SuperLeashKnotModel extends HierarchicalModel { + private static final String KNOT = "knot"; + private final ModelPart root; + private final ModelPart knot; + + public SuperLeashKnotModel(ModelPart root) { + this.root = root; + this.knot = root.getChild(KNOT); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + partdefinition.addOrReplaceChild(KNOT, + CubeListBuilder + .create() + .texOffs(0, 0) + .addBox(-3.0F, -8.0F, -3.0F, 6.0F, 8.0F, 6.0F), + PartPose.ZERO + ); + return LayerDefinition.create(meshdefinition, 32, 32); + } + + @Override + public void setupAnim ( + @NotNull Entity entity, + float limbSwing, + float limbSwingAmount, + float ageInTicks, + float netHeadYaw, + float headPitch + ) { + this.knot.yRot = netHeadYaw * 0.017453292F; + this.knot.xRot = headPitch * 0.017453292F; + } + @Override + public @NotNull ModelPart root() { + return root; + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/superleadrope/client/model/geom/SLPModelLayers.java b/src/main/java/top/r3944realms/superleadrope/client/model/geom/SLPModelLayers.java new file mode 100644 index 0000000..3c937d4 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/model/geom/SLPModelLayers.java @@ -0,0 +1,31 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.model.geom; + +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import top.r3944realms.superleadrope.SuperLeadRope; + +@OnlyIn(Dist.CLIENT) +public class SLPModelLayers { + public static final ModelLayerLocation SUPER_LEASH_KNOT = + new ModelLayerLocation( + new ResourceLocation(SuperLeadRope.MOD_ID, "super_leash_knot"), + "main" + ); +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/renderer/SLPRenderType.java b/src/main/java/top/r3944realms/superleadrope/client/renderer/SLPRenderType.java new file mode 100644 index 0000000..b27e1af --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/renderer/SLPRenderType.java @@ -0,0 +1,49 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.renderer; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.RenderType; + +import java.util.OptionalDouble; + +public class SLPRenderType extends RenderType { + public SLPRenderType(String name, VertexFormat format, VertexFormat.Mode mode, int bufferSize, boolean affectsCrumbling, boolean sortOnUpload, Runnable setupState, Runnable clearState) { + super(name, format, mode, bufferSize, affectsCrumbling, sortOnUpload, setupState, clearState); + } + static RenderType SUPER_LEASH; + public static RenderType leashType() { + return SUPER_LEASH; + } + static { + SUPER_LEASH = RenderType.create("super_leash", + DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, + VertexFormat.Mode.LINE_STRIP, + 256, + false, + false, + CompositeState.builder() + .setShaderState(RENDERTYPE_LINES_SHADER) + .setLineState(new LineStateShard(OptionalDouble.empty())) + .setLayeringState(VIEW_OFFSET_Z_LAYERING) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setOutputState(ITEM_ENTITY_TARGET) + .setWriteMaskState(COLOR_DEPTH_WRITE) + .setCullState(NO_CULL) + .createCompositeState(false)); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashKnotRenderer.java b/src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashKnotRenderer.java new file mode 100644 index 0000000..a66daa0 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashKnotRenderer.java @@ -0,0 +1,68 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.renderer.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.client.model.SuperLeashKnotModel; +import top.r3944realms.superleadrope.client.model.geom.SLPModelLayers; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; + +@OnlyIn(Dist.CLIENT) +public class SuperLeashKnotRenderer extends EntityRenderer { + private static final ResourceLocation KNOT_LOCATION = new ResourceLocation(SuperLeadRope.MOD_ID, "textures/entity/super_lead_knot.png"); + private final SuperLeashKnotModel model; + public SuperLeashKnotRenderer(EntityRendererProvider.Context context) { + super(context); + this.model = new SuperLeashKnotModel<>(context.bakeLayer(SLPModelLayers.SUPER_LEASH_KNOT)); + } + + @Override + public void render(@NotNull SuperLeashKnotEntity entity, float entityYaw, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight) { + // 根据实体的实际 hitbox 调整缩放 + float scaleX = entity.getBbWidth() / 0.5f; // 默认 0.5f,对应 scale=1 + float scaleY = entity.getBbHeight() / 0.5f; // 默认 0.5f,对应 scale=1 + float scaleZ = scaleX; // 宽度对称 + + poseStack.scale(-1.5F * scaleX, -1.5F * scaleY, 1.5F * scaleZ); + + // 位置微调(避免浮空) + poseStack.translate(0.0D, 0.15D * scaleY, 0.0D); + + this.model.setupAnim(entity, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F); + VertexConsumer vertexConsumer = buffer.getBuffer(this.model.renderType(KNOT_LOCATION)); + this.model.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY, + 1.0F, 1.0F, 1.0F, 1.0F); + + poseStack.popPose(); + super.render(entity, entityYaw, partialTick, poseStack, buffer, packedLight); + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull SuperLeashKnotEntity superLeashKnotEntity) { + return KNOT_LOCATION; + } + +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashRenderer.java b/src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashRenderer.java new file mode 100644 index 0000000..864ad87 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/renderer/entity/SuperLeashRenderer.java @@ -0,0 +1,153 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.renderer.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.client.renderer.SLPRenderType; +import top.r3944realms.superleadrope.client.renderer.resolver.SuperLeashStateResolver; +import top.r3944realms.superleadrope.client.renderer.state.SuperLeashRenderState; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.content.entity.SuperLeashEntity; + +import java.util.List; + +public class SuperLeashRenderer extends EntityRenderer { + // 渲染参数 + private static final int SEGMENTS = 24; // 绳子分段数 + private static final float BASE_THICKNESS = 0.08f; // 基础线宽 + private static final float CRITICAL_PULSE_SPEED = 0.2f; // 临界状态脉冲速度 + + public SuperLeashRenderer(EntityRendererProvider.Context context) { + super(context); + } + + @Override + public void render(@NotNull SuperLeashEntity entity, float entityYaw, float partialTick, + @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight) { + Entity controlled = entity.getControlled(); + if (!LeashDataImpl.isLeashable(controlled)) return; + + // 创建渲染状态 + List superLeashRenderStates = SuperLeashStateResolver.resolveAll( + controlled, + (LeashDataImpl) controlled.getCapability(CapabilityHandler.LEASH_DATA_CAP).orElseThrow(NullPointerException::new), + partialTick + ); + + // 渲染绳子 + superLeashRenderStates.forEach(s -> renderLeash(s, poseStack, buffer, packedLight, partialTick)); + } + + private void renderLeash(SuperLeashRenderState state, PoseStack poseStack, + MultiBufferSource buffer, int packedLight, float partialTicks) { + poseStack.pushPose(); + + VertexConsumer vertexBuilder = buffer.getBuffer(SLPRenderType.leashType()); + Vec3 start = state.startPos(); + Vec3 end = state.endPos(); + + // 计算绳子总长度和方向 + double length = start.distanceTo(end); + Vec3 direction = end.subtract(start).normalize(); + + // 临界状态闪烁效果 + float alpha = state.isCritical() ? + (Mth.sin(partialTicks * CRITICAL_PULSE_SPEED) * 0.5f + 0.5f) : + 1.0f; + + // 分段渲染绳子 + for (int i = 0; i <= SEGMENTS; i++) { + float progress = (float)i / SEGMENTS; + + // 计算当前段位置和摆动偏移 + Vec3 segmentPos = start.add(direction.scale(length * progress)); + Vec3 swingOffset = state.getSwingOffset(progress, partialTicks); + + // 应用张力拉伸效果 + if (state.stretchRatio() > 1.0f) { + float stretchFactor = (float)Math.sin(progress * Math.PI) * 0.2f * (state.stretchRatio() - 1.0f); + segmentPos = segmentPos.add(direction.scale(stretchFactor * length)); + } + + // 添加摆动偏移 + segmentPos = segmentPos.add(swingOffset); + + // 计算颜色渐变 (从正常色到紧张色) + int color = interpolateColor( + SuperLeashRenderState.COLOR_NORMAL, + state.isCritical() ? SuperLeashRenderState.COLOR_CRITICAL : SuperLeashRenderState.COLOR_TENSION, + state.tension()); + + // 添加顶点 + addVertex(vertexBuilder, poseStack, segmentPos, + state.thickness() * (1 - progress * 0.3f), // 末端稍细 + color, alpha, packedLight); + } + + poseStack.popPose(); + } + + private void addVertex(VertexConsumer builder, PoseStack poseStack, Vec3 pos, + float thickness, int color, float alpha, int packedLight) { + // 解包颜色 + float r = ((color >> 16) & 0xFF) / 255.0f; + float g = ((color >> 8) & 0xFF) / 255.0f; + float b = (color & 0xFF) / 255.0f; + + // 转换到相机空间 + Vec3 viewPos = pos.subtract(this.entityRenderDispatcher.camera.getPosition()); + + // 添加顶点 (使用LINE_STRIP渲染) + builder.vertex(poseStack.last().pose(), (float)viewPos.x, (float)viewPos.y, (float)viewPos.z) + .color(r, g, b, alpha) + .uv2(packedLight) + .overlayCoords(OverlayTexture.NO_OVERLAY) + .normal(poseStack.last().normal(), 0, 1, 0) + .endVertex(); + } + + private int interpolateColor(int color1, int color2, float ratio) { + int r1 = (color1 >> 16) & 0xFF; + int g1 = (color1 >> 8) & 0xFF; + int b1 = color1 & 0xFF; + + int r2 = (color2 >> 16) & 0xFF; + int g2 = (color2 >> 8) & 0xFF; + int b2 = color2 & 0xFF; + + int r = (int)(r1 + (r2 - r1) * ratio); + int g = (int)(g1 + (g2 - g1) * ratio); + int b = (int)(b1 + (b2 - b1) * ratio); + + return (r << 16) | (g << 8) | b; + } + + @Override + public ResourceLocation getTextureLocation(@NotNull SuperLeashEntity entity) { + return null; // 使用自定义渲染类型,不需要纹理 + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/renderer/resolver/SuperLeashStateResolver.java b/src/main/java/top/r3944realms/superleadrope/client/renderer/resolver/SuperLeashStateResolver.java new file mode 100644 index 0000000..505308c --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/renderer/resolver/SuperLeashStateResolver.java @@ -0,0 +1,201 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.renderer.resolver; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.client.renderer.state.SuperLeashRenderState; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; + +import java.util.*; + +public class SuperLeashStateResolver { + private static final float MAX_TENSION = 1.5f; + private static final float THICKNESS_BASE = 0.1f; + private static final float THICKNESS_TENSION = 0.15f; + + // 摆动计算缓存(存储上一帧数据) + private static final Map frameCacheMap = new HashMap<>(); + + private record FrameCache( + Vec3 lastStartPos, + Vec3 lastEndPos, + float lastSwingAngle, + float lastSwingSpeed + ) {} + + public static Optional resolve( + Entity holder, + Entity leashedEntity, + ILeashDataCapability.LeashInfo leashInfo, + float partialTicks) { + + if (holder == null || leashedEntity == null) { + return Optional.empty(); + } + + // 获取当前帧位置(带插值) + Vec3 currentHolderPos = getInterpolatedPosition(holder, partialTicks) + .add(0, holder.getBbHeight() * 0.7, 0); + Vec3 currentEntityPos = getInterpolatedPosition(leashedEntity, partialTicks) + .add(leashInfo.attachOffset()); + + // 获取上一帧数据 + FrameCache cache = frameCacheMap.get(leashedEntity.getUUID()); + Vec3 lastHolderPos = cache != null ? cache.lastStartPos() : currentHolderPos; + Vec3 lastEntityPos = cache != null ? cache.lastEndPos() : currentEntityPos; + float lastAngle = cache != null ? cache.lastSwingAngle() : 0f; + float lastSpeed = cache != null ? cache.lastSwingSpeed() : 0f; + + // 计算物理参数 + double distance = currentHolderPos.distanceTo(currentEntityPos); + double maxDistance = leashInfo.maxDistance(); + double elasticDistance = leashInfo.elasticDistance(); + float tension = calculateTension(distance, maxDistance, elasticDistance); + float stretchRatio = (float) (distance / maxDistance); + boolean isCritical = distance > maxDistance * 1.5; + + // 计算摆动动态 + SwingDynamics swing = calculateSwingDynamics( + currentHolderPos, currentEntityPos, + lastHolderPos, lastEntityPos, + lastAngle, lastSpeed, + tension, partialTicks); + + // 更新缓存 + frameCacheMap.put(leashedEntity.getUUID(), + new FrameCache(currentHolderPos, currentEntityPos, + swing.angle(), swing.speed())); + + return Optional.of(new SuperLeashRenderState( + currentHolderPos, + currentEntityPos, + leashInfo.attachOffset(), + lastHolderPos, + lastEntityPos, + tension, + stretchRatio, + isCritical, + leashInfo.keepLeashTicks(), + selectColor(tension, isCritical), + THICKNESS_BASE + (tension * THICKNESS_TENSION), + swing.angle(), + swing.speed() + )); + } + + private record SwingDynamics(float angle, float speed) {} + + private static SwingDynamics calculateSwingDynamics( + Vec3 currentStart, Vec3 currentEnd, + Vec3 lastStart, Vec3 lastEnd, + float lastAngle, float lastSpeed, + float tension, float partialTicks) { + + // 计算当前方向向量 + Vec3 currentDir = currentEnd.subtract(currentStart).normalize(); + Vec3 lastDir = lastEnd.subtract(lastStart).normalize(); + + // 计算方向变化角度(使用叉积确定变化方向) + Vec3 cross = lastDir.cross(currentDir); + float angleChange = (float) Math.acos(Math.min(1.0, lastDir.dot(currentDir))); + angleChange *= (float) Math.signum(cross.y); // 使用y分量确定摆动方向 + + // 模拟物理摆动(简谐运动) + float newSpeed = lastSpeed * 0.9f + angleChange * 0.5f * tension; + float newAngle = lastAngle + newSpeed; + + // 添加随机扰动(模拟风等外力) + if (tension > 0.3f) { + newSpeed += (float) ((Math.random() - 0.5) * 0.05 * tension); + } + + return new SwingDynamics(newAngle, newSpeed); + } + + private static Vec3 getInterpolatedPosition(Entity entity, float partialTicks) { + // 实体位置插值(使移动更平滑) + return new Vec3( + lerp(partialTicks, (float) entity.xo, (float) entity.getX()), + lerp(partialTicks, (float) entity.yo, (float) entity.getY()), + lerp(partialTicks, (float) entity.zo, (float) entity.getZ()) + ); + } + + private static float lerp(float delta, float start, float end) { + return start + delta * (end - start); + } + + private static float calculateTension(double distance, double maxDistance, double elasticDistance) { + if (distance <= elasticDistance) { + return 0f; // 完全松弛 + } + + // 非线性张力计算 + double excess = distance - elasticDistance; + double range = maxDistance - elasticDistance; + float ratio = (float) (excess / range); + + // 应用缓动函数使变化更自然 + return easeOutQuad(Math.min(ratio, MAX_TENSION)); + } + + private static float easeOutQuad(float x) { + return 1 - (1 - x) * (1 - x); + } + + private static int selectColor(float tension, boolean isCritical) { + if (isCritical) { + return SuperLeashRenderState.COLOR_CRITICAL; + } + return tension > 0.7f ? + SuperLeashRenderState.COLOR_TENSION : + SuperLeashRenderState.COLOR_NORMAL; + } + + /** + * 获取实体所有拴绳的渲染状态 + */ + @SuppressWarnings("unchecked") + public static List resolveAll( + Entity leashedEntity, + LeashDataImpl leashData, + float partialTicks) { + + List states = new ArrayList<>(); + Level level = leashedEntity.level(); + + for (ILeashDataCapability.LeashInfo leashInfo : leashData.getAllLeashes()) { + Entity holder = null; + if (leashInfo.blockPosOpt().isEmpty() && leashInfo.holderIdOpt().isPresent()){ + holder = level.getEntity(leashInfo.holderIdOpt().get()); + } else if (leashInfo.blockPosOpt().isPresent()) { + holder = SuperLeashKnotEntity.getOrCreateKnot(level, leashInfo.blockPosOpt().get()); + } + if (holder != null) { + resolve(holder, leashedEntity, leashInfo, partialTicks) + .ifPresent(states::add); + } + else SuperLeadRope.logger.error("Holder is not found"); + } + + return states; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/client/renderer/state/SuperLeashRenderState.java b/src/main/java/top/r3944realms/superleadrope/client/renderer/state/SuperLeashRenderState.java new file mode 100644 index 0000000..8365ee3 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/client/renderer/state/SuperLeashRenderState.java @@ -0,0 +1,57 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.client.renderer.state; + +import net.minecraft.world.phys.Vec3; + +public record SuperLeashRenderState( + Vec3 startPos, // 当前帧起点位置 + Vec3 endPos, // 当前帧终点位置 + Vec3 attachOffset, // 拴绳附着点偏移 + Vec3 lastStartPos, // 上一帧起点位置(用于摆动计算) + Vec3 lastEndPos, // 上一帧终点位置(用于摆动计算) + float tension, // 张力强度(0.0-1.0) + float stretchRatio, // 拉伸比例(1.0=正常长度) + boolean isCritical, // 是否处于临界断裂状态 + int keepLeashTicks, // 剩余缓冲Tick + int color, // 颜色(根据状态变化) + float thickness, // 线宽(根据张力变化) + float swingAngle, // 当前摆动角度(弧度) + float swingSpeed // 摆动速度(弧度/tick) +) { + // 预定义颜色常量 + public static final int COLOR_NORMAL = 0xFF8B4513; // 棕色(正常) + public static final int COLOR_TENSION = 0xFFFFA500; // 橙色(紧张) + public static final int COLOR_CRITICAL = 0xFFFF0000; // 红色(临界) + + /** + * 计算当前帧的摆动偏移量(用于波浪效果) + * @param progress 沿绳子的进度(0.0-1.0) + * @param partialTicks 部分tick时间 + * @return 垂直于绳子方向的偏移向量 + */ + public Vec3 getSwingOffset(float progress, float partialTicks) { + // 基于正弦波的摆动效果 + float angle = swingAngle + swingSpeed * partialTicks; + float offsetMagnitude = (float) (Math.sin(angle + progress * Math.PI * 2) * + thickness * 2.0 * tension); + + // 计算垂直于绳子方向的向量 + Vec3 ropeDir = endPos.subtract(startPos).normalize(); + Vec3 perpendicular = new Vec3(-ropeDir.z, 0, ropeDir.x).normalize(); + return perpendicular.scale(offsetMagnitude); + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/superleadrope/config/CommonConfig.java b/src/main/java/top/r3944realms/superleadrope/config/CommonConfig.java new file mode 100644 index 0000000..c3e398a --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/config/CommonConfig.java @@ -0,0 +1,19 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.config; + +public class CommonConfig { +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityHandler.java b/src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityHandler.java new file mode 100644 index 0000000..eb5615e --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityHandler.java @@ -0,0 +1,41 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.capability; + +import net.minecraft.world.entity.Entity; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.common.capabilities.CapabilityToken; +import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; + +public class CapabilityHandler { + public static final Capability LEASH_DATA_CAP = CapabilityManager.get(new CapabilityToken<>(){}); + + public static void registerCapability(RegisterCapabilitiesEvent event) { + event.register(ILeashDataCapability.class); + } + + public static void attachCapability(AttachCapabilitiesEvent event) { + Object object = event.getObject(); + if(object instanceof Entity entity && + (LeashDataImpl.isLeashable(entity))//只对活体 船 矿车添加CAP + ) { + event.addCapability(LeashDataProvider.LEASH_DATA_REL, new LeashDataProvider(entity)); + } + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityRemainder.java b/src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityRemainder.java new file mode 100644 index 0000000..99d966b --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/capability/CapabilityRemainder.java @@ -0,0 +1,26 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.capability; + +import net.minecraftforge.event.entity.player.PlayerEvent; + +public class CapabilityRemainder { + public static void onPlayerClone(PlayerEvent.Clone event) { + if (event.isWasDeath()) { + // + } + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataImpl.java b/src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataImpl.java new file mode 100644 index 0000000..341b22b --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataImpl.java @@ -0,0 +1,752 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.capability; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.entity.vehicle.Minecart; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.network.PacketDistributor; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; +import top.r3944realms.superleadrope.network.NetworkHandler; +import top.r3944realms.superleadrope.network.toClient.LeashDataSyncPacket; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; + +/** + * 预期行为 + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
场景行为
距离 ≤ maxDistance正常弹性拉力,重置 keepLeashTicks 为最大值
maxDistance < distance ≤ 2*maxDistance增强拉力,并减少 keepLeashTicks(每Tick减1)
distance > 2*maxDistance && keepLeashTicks > 0施加更强拉力并减少Tick
distance > 2*maxDistance && keepLeashTicks == 0立即断裂
+ */ +public class LeashDataImpl implements ILeashDataCapability { + private static final double LEASH_ELASTIC_DIST = 6.0; // 弹性距离 + private static final double LEASH_EXTREME_SNAP_DIST_FACTOR = 2.0; // 断裂距离 = 最大距离 * 2 //TODO:未来可配置 + private static final float SPRING_DAMPENING = 0.7f; // 阻尼系数 + private static final Vec3 AXIS_SPECIFIC_ELASTICITY = new Vec3(0.8, 0.2, 0.8); // 轴向弹性系数(Y轴较弱) + private static final int MAX_LEASHES_PER_ENTITY = 3;//一个实体最多链接多少个拴绳 //TODO:未来可配置 + private final Entity entity; + private boolean needsSync = false; + private long lastSyncTime; + private final Map leashHolders = new ConcurrentHashMap<>(); + // 引入解决 绳结不保存导致第二进入持有者不存在的问题 + private final Map leashKnots = new ConcurrentHashMap<>(); + private CompoundTag lastSyncedData = new CompoundTag(); + public LeashDataImpl(Entity entity) { + this.entity = entity; + } + private void markForSync() { + if (!entity.level().isClientSide) { + needsSync = true; + immediateSync(); + } + } + private void immediateSync() { + NetworkHandler.INSTANCE.send( + PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), + new LeashDataSyncPacket(entity.getId(), serializeNBT()) + ); + lastSyncTime = System.currentTimeMillis(); + needsSync = false; + } + public void sync() { + if (!needsSync || entity.level().isClientSide) return; + + CompoundTag currentData = serializeNBT(); + if (!currentData.equals(lastSyncedData)) { + NetworkHandler.INSTANCE.send( + PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), + new LeashDataSyncPacket(entity.getId(), currentData) + ); + lastSyncTime = System.currentTimeMillis(); + lastSyncedData = currentData; + needsSync = false; + } + } + // 定期同步检查 + public void checkSync() { + if (!needsSync) return; + + // 距离上次同步超过0.1秒才同步 + if (System.currentTimeMillis() - lastSyncTime > 100) { + sync(); + } + } + + // 添加拴绳(支持自定义最大长度和弹性距离) + @Override + public boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance) { + boolean result = addLeash(holder, leashStack, maxDistance, LEASH_ELASTIC_DIST, 0); + if (result) markForSync(); + return result; + } + @Override + public boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance, double elasticDistance, int maxKeepLeashTicks) { + boolean isSuperKnot = holder instanceof SuperLeashKnotEntity; + if (!canBeLeashed() || (!isSuperKnot && leashHolders.containsKey(holder.getUUID()) || (isSuperKnot && leashKnots.containsKey(((SuperLeashKnotEntity) holder).getPos())))) { + return false; + } + LeashInfo info = LeashInfo.CreateLeashInfo( + holder, + leashStack.getItem().getDescription().toString(), + calculateAttachOffset(entity), + maxDistance, + elasticDistance, + maxKeepLeashTicks, + maxKeepLeashTicks + ); + if (holder instanceof SuperLeashKnotEntity s) { + leashKnots.put(s.getPos(), info); + } + else leashHolders.put(holder.getUUID(), info); + markForSync(); + return true; + } + + @Override + public boolean setMaxDistance(Entity holder, double newMaxDistance) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + setMaxDistance(superLeashKnotEntity.getPos(), newMaxDistance) : + setMaxDistance(holder.getUUID(), newMaxDistance); + } + + @Override + public boolean setMaxDistance(Entity holder, double newMaxDistance, int newMaxKeepLeashTicks) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + setMaxDistance(superLeashKnotEntity.getPos(), newMaxDistance, newMaxKeepLeashTicks) : + setMaxDistance(holder.getUUID(), newMaxDistance, newMaxKeepLeashTicks); + } + + // 动态修改最大拴绳长度 + @Override + public boolean setMaxDistance(UUID holderUUID, double newMaxDistance) { + LeashInfo info = leashHolders.get(holderUUID); + if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + leashHolders.put(holderUUID, new LeashInfo( + info.holderUUIDOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + newMaxDistance, + info.elasticDistance(), // 保持原有弹性距离 + info.keepLeashTicks(), + info.maxKeepLeashTicks() + )); + markForSync(); + return true; + } + @Override + public boolean setMaxDistance(UUID holderUUID, double newMaxDistance, int newMaxKeepLeashTicks) { + LeashInfo info = leashHolders.get(holderUUID); + if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + leashHolders.put(holderUUID, new LeashInfo( + info.holderUUIDOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + newMaxDistance, + info.elasticDistance(), // 保持原有弹性距离 + newMaxKeepLeashTicks, + info.maxKeepLeashTicks() + )); + markForSync(); + return true; + } + + @Override + public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance) { + LeashInfo info = leashKnots.get(knotPos); + if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + leashKnots.put(knotPos, new LeashInfo( + info.blockPosOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + newMaxDistance, + info.elasticDistance(), // 保持原有弹性距离 + info.keepLeashTicks(), + info.maxKeepLeashTicks() + )); + markForSync(); + return true; + } + + @Override + public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance, int newMaxKeepLeashTicks) { + LeashInfo info = leashKnots.get(knotPos); + if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + leashKnots.put(knotPos, new LeashInfo( + info.blockPosOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + newMaxDistance, + info.elasticDistance(), // 保持原有弹性距离 + info.keepLeashTicks(), + newMaxKeepLeashTicks + )); + markForSync(); + return true; + } + + @Override + public boolean setElasticDistance(Entity holder, double newElasticDistance) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + setElasticDistance(superLeashKnotEntity.getPos(), newElasticDistance) : + setElasticDistance(holder.getUUID(), newElasticDistance); + } + + // 动态修改弹性距离 + @Override + public boolean setElasticDistance(UUID holderUUID, double newElasticDistance) { + LeashInfo info = leashHolders.get(holderUUID); + if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + + leashHolders.put(holderUUID, new LeashInfo( + info.holderUUIDOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + info.maxDistance(), + newElasticDistance, + info.keepLeashTicks(), + info.maxKeepLeashTicks() + )); + markForSync(); + return true; + } + + @Override + public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance) { + LeashInfo info = leashKnots.get(knotPos); + if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + + leashKnots.put(knotPos, new LeashInfo( + info.blockPosOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + info.maxDistance(), + newElasticDistance, + info.keepLeashTicks(), + info.maxKeepLeashTicks() + )); + markForSync(); + return true; + } + + @Override + public boolean setElasticDistance(Entity holder, double newElasticDistance, int newMaxKeepLeashTicks) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + setElasticDistance(superLeashKnotEntity.getPos(), newElasticDistance, newMaxKeepLeashTicks) : + setElasticDistance(holder.getUUID(), newElasticDistance, newMaxKeepLeashTicks); + } + + // 动态修改弹性距离 + @Override + public boolean setElasticDistance(UUID holderUUID, double newElasticDistance, int newMaxKeepLeashTicks) { + LeashInfo info = leashHolders.get(holderUUID); + if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + + leashHolders.put(holderUUID, new LeashInfo( + info.holderUUIDOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + info.maxDistance(), + newElasticDistance, + Math.min(info.keepLeashTicks(), newMaxKeepLeashTicks), // 限制剩余Tick不超过新最大值 + newMaxKeepLeashTicks + )); + return true; + } + + @Override + public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks) { + LeashInfo info = leashKnots.get(knotPos); + if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false; + + leashKnots.put(knotPos, new LeashInfo( + info.blockPosOpt().get(), + info.holderIdOpt().get(), + info.reserved(), + info.attachOffset(), + info.maxDistance(), + newElasticDistance, + Math.min(info.keepLeashTicks(), newMaxKeepLeashTicks), // 限制剩余Tick不超过新最大值 + newMaxKeepLeashTicks + )); + return true; + } + + // 计算拴绳拉力(防抖动逻辑) + @Override + public void applyLeashForces() { + for (Map.Entry uuidLeashInfoEntry : leashHolders.entrySet()) { + internalUUIDApplyLeashForces(uuidLeashInfoEntry); + } + for (Map.Entry blockPosLeashInfoEntry : leashKnots.entrySet()) { + internalBlockPosApplyLeashForce(blockPosLeashInfoEntry); + } + } + + private void internalUUIDApplyLeashForces(Map.Entry entry) { + UUID uuid = entry.getKey(); + Entity uuidHolder = ((ServerLevel) entity.level()).getEntity(uuid); + if (uuidHolder != null) { + internalApplyLeashForces(uuidHolder, entry); + } else { + SuperLeadRope.logger.error("Could not apply leash forces for {}, because it is not found.", uuid); + } + } + + private void internalBlockPosApplyLeashForce(Map.Entry entry) { + SuperLeashKnotEntity orCreateKnot = SuperLeashKnotEntity.getOrCreateKnot(entity.level(), entry.getKey()); + internalApplyLeashForces(orCreateKnot, entry); + } + private void internalApplyLeashForces(Entity holder, Map.Entry entry) { + Vec3 holderPos = holder.position().add(0, holder.getBbHeight() * 0.7, 0); + LeashInfo info = entry.getValue(); + Vec3 entityPos = entity.position().add(info.attachOffset()); + double distance = holderPos.distanceTo(entityPos); + double extremeSnapDist = info.maxDistance() * LEASH_EXTREME_SNAP_DIST_FACTOR; + + // 1. 检查是否超出断裂距离 + if (distance > extremeSnapDist) { + // 如果还有剩余缓冲Tick,施加更强拉力并减少计数 + if (info.keepLeashTicks() > 0) { + // 计算临界拉力(距离越远,拉力越强) + Vec3 pullForce = calculateCriticalPullForce(holderPos, entityPos, distance, info); + entity.setDeltaMovement(entity.getDeltaMovement().add(pullForce)); + entity.hurtMarked = true; + entry.setValue(info.decrementKeepLeashTicks()); + return; + } + // 否则立即断裂 + removeLeash(holder); + return; + } + + // 2. 正常弹性拉力逻辑(保持不变) + if (distance > info.elasticDistance()) { + Vec3 pullForce = calculatePullForce(holderPos, entityPos, distance, info); + entity.setDeltaMovement(entity.getDeltaMovement().add(pullForce)); + entity.hurtMarked = true; + } + + // 3. 重置缓冲Tick(如果回到安全距离) + if (distance <= info.maxDistance() && info.keepLeashTicks() < info.maxKeepLeashTicks()) { + entry.setValue(info.resetKeepLeashTicks()); + } + } + @Contract("_, _, _, _ -> new") + private @NotNull Vec3 calculatePullForce(@NotNull Vec3 holderPos, Vec3 entityPos, double distance, @NotNull LeashInfo info) { + Vec3 pullDirection = holderPos.subtract(entityPos).normalize(); + double pullStrength = 0.2; + + // 增强拉力(如果超出maxDistance但未达断裂距离) + if (distance > info.maxDistance()) { + double excessRatio = (distance - info.maxDistance()) / (info.maxDistance()); + pullStrength += excessRatio * 0.8; // 最高1.0倍基础拉力 + } + + Vec3 pullForce = pullDirection.scale( + (distance - info.elasticDistance()) * pullStrength * SPRING_DAMPENING + ); + + return new Vec3( + pullForce.x * AXIS_SPECIFIC_ELASTICITY.x, + pullForce.y * AXIS_SPECIFIC_ELASTICITY.y, + pullForce.z * AXIS_SPECIFIC_ELASTICITY.z + ); + } + private @NotNull Vec3 calculateCriticalPullForce(@NotNull Vec3 holderPos, Vec3 entityPos, double distance, @NotNull LeashInfo info) { + Vec3 pullDirection = holderPos.subtract(entityPos).normalize(); + + // 非线性增强拉力(距离越远,拉力越强) + double excessRatio = (distance - info.maxDistance()) / (info.maxDistance()); + double pullStrength = 1.0 + excessRatio * 2.0; // 基础1.0 + 额外增强(最高3.0倍) + + Vec3 pullForce = pullDirection.scale( + (distance - info.elasticDistance()) * pullStrength * SPRING_DAMPENING + ); + + // 应用轴向弹性系数(减少Y轴抖动) + return new Vec3( + pullForce.x * AXIS_SPECIFIC_ELASTICITY.x, + pullForce.y * AXIS_SPECIFIC_ELASTICITY.y, + pullForce.z * AXIS_SPECIFIC_ELASTICITY.z + ); + } + + // 移除拴绳绑定 + @Override + public boolean removeLeash(Entity holder) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + removeLeash(superLeashKnotEntity.getPos()) : + removeLeash(holder.getUUID()); + } + @Override + public boolean removeLeash(UUID holderUUID) { + boolean removed = leashHolders.remove(holderUUID) != null; + if (removed) + markForSync(); + return removed; + } + + @Override + public boolean removeLeash(BlockPos knotPos) { + boolean removed = leashKnots.remove(knotPos) != null; + if (removed) + markForSync(); + return removed; + } + + @Override + public boolean transferLeash(Entity holder, Entity newHolder) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + transferLeash(superLeashKnotEntity.getPos(), newHolder) : + transferLeash(holder.getUUID(), newHolder); + } + + @Override + public boolean transferLeash(Entity holder, Entity newHolder, ItemStack stack) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + transferLeash(superLeashKnotEntity.getPos(), newHolder, stack) : + transferLeash(holder.getUUID(), newHolder, stack); + } + + // 将拴绳持有者转移到新实体(非拴绳结 -> 任意) + @Override + public boolean transferLeash(UUID oldHolderUUID, Entity newHolder) { + LeashInfo info = leashHolders.remove(oldHolderUUID); + if (info == null || newHolder == null) return false; + if(newHolder instanceof SuperLeashKnotEntity superLeashKnotEntity) { + LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity); + leashKnots.put(superLeashKnotEntity.getPos(), leashInfo); + } else { + LeashInfo leashInfo = info.transferHolder(newHolder); + leashHolders.put(newHolder.getUUID(), leashInfo); + } + markForSync(); + return true; + } + @Override + public boolean transferLeash(UUID oldHolderUUID, Entity newHolder, ItemStack stack) { + LeashInfo info = leashHolders.remove(oldHolderUUID); + if (info == null || newHolder == null) return false; + if(newHolder instanceof SuperLeashKnotEntity superLeashKnotEntity) { + LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity, stack.getDescriptionId()); + leashKnots.put(superLeashKnotEntity.getPos(), leashInfo); + } else { + LeashInfo leashInfo = info.transferHolder(newHolder, stack.getDescriptionId()); + leashHolders.put(newHolder.getUUID(), leashInfo); + } + markForSync(); + return true; + } + + @Override + public boolean transferLeash(BlockPos knotPos, Entity newHolder) { + LeashInfo info = leashKnots.remove(knotPos); + if (info == null || newHolder == null) return false; + if(newHolder instanceof SuperLeashKnotEntity superLeashKnotEntity) { + LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity); + leashKnots.put(superLeashKnotEntity.getPos(), leashInfo); + } else { + LeashInfo leashInfo = info.transferHolder(newHolder); + leashHolders.put(newHolder.getUUID(), leashInfo); + } + markForSync(); + return true; + } + + @Override + public boolean transferLeash(BlockPos knotPos, Entity newHolder, ItemStack stack) { + LeashInfo info = leashKnots.remove(knotPos); + if (info == null || newHolder == null) return false; + if(newHolder instanceof SuperLeashKnotEntity superLeashKnotEntity) { + LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity, stack.getDescriptionId()); + leashKnots.put(superLeashKnotEntity.getPos(), leashInfo); + } else { + LeashInfo leashInfo = info.transferHolder(newHolder, stack.getDescriptionId()); + leashHolders.put(newHolder.getUUID(), leashInfo); + } + markForSync(); + return true; + } + + //只能系在这些实体上,在这里,其它情况一律忽略 + //TODO: 标签支持控制 + public static boolean isLeashable(Entity entity) { + return entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart; + } + + + // 获取所有拴绳信息 + @Override + public Collection getAllLeashes() { + Collection values = leashHolders.values(); + values.addAll(leashKnots.values()); + return values; + } + + @Override + public boolean isLeashedBy(Entity holder) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + isLeashedBy(superLeashKnotEntity.getPos()) : + isLeashedBy(holder.getUUID()); + } + + // 检查是否被特定实体拴住 + @Override + public boolean isLeashedBy(UUID holderUUID) { + return leashHolders.containsKey(holderUUID); + } + + @Override + public boolean isLeashedBy(BlockPos knotPos) { + return leashKnots.containsKey(knotPos); + } + + @Override + public Optional getLeashInfo(Entity holder) { + return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + getLeashInfo(superLeashKnotEntity.getPos()) : + getLeashInfo(holder.getUUID()); + } + + @Override + public Optional getLeashInfo(UUID holderUUID) { + return Optional.ofNullable(leashHolders.get(holderUUID)); + } + + @Override + public Optional getLeashInfo(BlockPos knotPos) { + return Optional.ofNullable(leashKnots.get(knotPos)); + } + + @Override + public CompoundTag serializeNBT() { + CompoundTag tag = new CompoundTag(); + ListTag holdersList = new ListTag(); + + for (LeashInfo info : leashHolders.values()) { + CompoundTag infoTag = generateCompoundTagFromUUIDLeashInfo(info); + holdersList.add(infoTag); + } + for (LeashInfo info : leashKnots.values()) { + CompoundTag infoTag = generateCompoundTagFromBlockPosLeashInfo(info); + holdersList.add(infoTag); + } + tag.put("LeashHolders", holdersList); + return tag; + } + + private static @NotNull CompoundTag generateCompoundTagFromUUIDLeashInfo(@NotNull LeashInfo info) { + CompoundTag infoTag = new CompoundTag(); + if (info.holderUUIDOpt().isEmpty()) { + throw new IllegalArgumentException("LeashInfo.holderUUIDOpt is empty"); + } + infoTag.putUUID("HolderUUID", info.holderUUIDOpt().get()); + return getCommonCompoundTag(info, infoTag); + } + private static @NotNull CompoundTag generateCompoundTagFromBlockPosLeashInfo(@NotNull LeashInfo info) { + CompoundTag infoTag = new CompoundTag(); + if (info.blockPosOpt().isEmpty()) { + throw new IllegalArgumentException("LeashInfo.blockPos is empty"); + } + BlockPos blockPos = info.blockPosOpt().get(); + infoTag.putInt("HolderX", blockPos.getX()); + infoTag.putInt("HolderY", blockPos.getY()); + infoTag.putInt("HolderZ", blockPos.getZ()); + return getCommonCompoundTag(info, infoTag); + } + + private static @NotNull CompoundTag getCommonCompoundTag(@NotNull LeashInfo info, CompoundTag infoTag) { + if(info.holderIdOpt().isEmpty()) { + throw new IllegalArgumentException("LeashInfo.intId is empty"); + } + infoTag.putInt("HolderID", info.holderIdOpt().get()); + infoTag.putString("LeashItem", info.reserved()); + infoTag.putDouble("OffsetX", info.attachOffset().x); + infoTag.putDouble("OffsetY", info.attachOffset().y); + infoTag.putDouble("OffsetZ", info.attachOffset().z); + infoTag.putDouble("MaxDistance", info.maxDistance()); + infoTag.putDouble("ElasticDistance", info.elasticDistance()); + infoTag.putInt("KeepLeashTicks", info.keepLeashTicks()); + infoTag.putInt("MaxKeepLeashTicks", info.maxKeepLeashTicks()); + return infoTag; + } + + @Override + public void deserializeNBT(@NotNull CompoundTag nbt) { + leashHolders.clear(); + leashKnots.clear(); + if (nbt.contains("LeashHolders", ListTag.TAG_LIST)) { + ListTag holdersList = nbt.getList("LeashHolders", ListTag.TAG_COMPOUND); + + for (int i = 0; i < holdersList.size(); i++) { + CompoundTag infoTag = holdersList.getCompound(i); + if (infoTag.contains("HolderUUID")) { + LeashInfo uuidLeashDataFormListTag = getUUIDLeashDataFormListTag(infoTag); + leashHolders.put(uuidLeashDataFormListTag.holderUUIDOpt().orElseThrow(), uuidLeashDataFormListTag); + } else { + LeashInfo blockPosLeashDataFormListTag = getBlockPosLeashDataFormListTag(infoTag); + leashKnots.put(blockPosLeashDataFormListTag.blockPosOpt().orElseThrow(), blockPosLeashDataFormListTag); + } + } + } + } + + @Override + public boolean canBeLeashed() { + return leashHolders.size() <= MAX_LEASHES_PER_ENTITY; + } + + @Contract("_ -> new") + private static @NotNull LeashInfo getUUIDLeashDataFormListTag(@NotNull CompoundTag infoTag) { + if (infoTag.contains("HolderUUID")){ + return new LeashInfo( + infoTag.getUUID("HolderUUID"), + infoTag.getInt("HolderID"), + infoTag.getString("LeashItem"), + new Vec3(infoTag.getDouble("OffsetX"), infoTag.getDouble("OffsetY"), infoTag.getDouble("OffsetZ")), + infoTag.getDouble("MaxDistance"), + infoTag.contains("ElasticDistance") ? infoTag.getDouble("ElasticDistance") : 6.0, + infoTag.getInt("KeepLeashTicks"), + infoTag.contains("MaxKeepLeashTicks") ? infoTag.getInt("MaxKeepLeashTicks") : 20 + ); + } else + throw new IllegalArgumentException("Unknown LeashInfo"); + } + @Contract("_ -> new") + private static @NotNull LeashInfo getBlockPosLeashDataFormListTag(@NotNull CompoundTag infoTag) { + if (infoTag.contains("HolderX")) { + return new LeashInfo( + new BlockPos(infoTag.getInt("HolderX"), infoTag.getInt("HolderY"), infoTag.getInt("HolderZ")), + infoTag.getInt("HolderID"), + infoTag.getString("LeashItem"), + new Vec3(infoTag.getDouble("OffsetX"), infoTag.getDouble("OffsetY"), infoTag.getDouble("OffsetZ")), + infoTag.getDouble("MaxDistance"), + infoTag.contains("ElasticDistance") ? infoTag.getDouble("ElasticDistance") : 6.0, + infoTag.getInt("KeepLeashTicks"), + infoTag.contains("MaxKeepLeashTicks") ? infoTag.getInt("MaxKeepLeashTicks") : 20 + ); + } else + throw new IllegalArgumentException("Unknown LeashInfo"); + } + + public static @NotNull List leashableInArea(Level pLevel, Vec3 pPos, Predicate filter) { + return leashableInArea(pLevel, pPos, filter, 1024D); + } + public static @NotNull List leashableInArea(@NotNull Level pLevel, Vec3 pPos, Predicate filter, double fetchDistance) { + AABB box = AABB.ofSize(pPos, fetchDistance, fetchDistance, fetchDistance); + return pLevel.getEntitiesOfClass(Entity.class, box, e -> LeashDataImpl.isLeashable(e) && filter.test(e)); + } + public static @NotNull List leashableInArea(@NotNull Entity entity, Predicate filter, double fetchDistance) { + return leashableInArea(entity.level(), entity.getBoundingBox().getCenter(), filter, fetchDistance); + } + public static @NotNull List leashableInArea(Entity entity, Predicate filter) { + return leashableInArea(entity, filter, 1024D); + } + public boolean canBeAttachedTo(Entity pEntity) { + if(pEntity == entity) { + return false; + } else { + Optional leashInfo = getLeashInfo(pEntity.getUUID()); + return leashInfo.isEmpty() && (entity.distanceTo(pEntity) <= LEASH_ELASTIC_DIST * LEASH_EXTREME_SNAP_DIST_FACTOR) && canBeLeashed();//距离最大,则不可以被固定或转移 + } + } + public static boolean isLeashHolder(@NotNull Entity pEntity, UUID pHolderUUID) { + AtomicBoolean isTarget = new AtomicBoolean(false); + pEntity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> { + if (i instanceof LeashDataImpl li) { + isTarget.set(li.isLeashedBy(pHolderUUID)); + } + }); + return isTarget.get(); + } + public static boolean isLeashHolder(@NotNull Entity pEntity, BlockPos pKnotPos) { + AtomicBoolean isTarget = new AtomicBoolean(false); + pEntity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> { + if (i instanceof LeashDataImpl li) { + isTarget.set(li.isLeashedBy(pKnotPos)); + } + }); + return isTarget.get(); + } + public static boolean isLeashHolder(@NotNull Entity pEntity, Entity pTestHolder) { + return pTestHolder instanceof SuperLeashKnotEntity superLeashKnotEntity ? + isLeashHolder(pEntity, superLeashKnotEntity.getPos()) : + isLeashHolder(pEntity, pTestHolder.getUUID()); + } + + + // 计算拴绳附着点 + @Contract("_ -> new") + private @NotNull Vec3 calculateAttachOffset(@NotNull Entity entity) { + EntityType type = entity.getType(); + if (type == EntityType.HORSE || type == EntityType.DONKEY) { + return new Vec3(0, 1.4, 0.3); + } else if (type == EntityType.IRON_GOLEM) { + return new Vec3(0, 1.8, 0); + } + //TODO: 未来自定义配置 + return new Vec3(0, entity.getBbHeight() * 0.8, 0); + } + + +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataProvider.java b/src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataProvider.java new file mode 100644 index 0000000..5e2a7c4 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/capability/LeashDataProvider.java @@ -0,0 +1,52 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.capability; + +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; +import net.minecraftforge.common.util.LazyOptional; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; + +public class LeashDataProvider implements ICapabilitySerializable { + public static final ResourceLocation LEASH_DATA_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_data"); + private final ILeashDataCapability instance; + private final LazyOptional optional; + public LeashDataProvider(Entity entity) { + this.instance = new LeashDataImpl(entity); + this.optional = LazyOptional.of(() -> instance); + } + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + return CapabilityHandler.LEASH_DATA_CAP.orEmpty(cap, optional); + } + + @Override + public CompoundTag serializeNBT() { + return instance.serializeNBT(); + } + + @Override + public void deserializeNBT(CompoundTag nbt) { + instance.deserializeNBT(nbt); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/capability/inter/ILeashDataCapability.java b/src/main/java/top/r3944realms/superleadrope/content/capability/inter/ILeashDataCapability.java new file mode 100644 index 0000000..4391d52 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/capability/inter/ILeashDataCapability.java @@ -0,0 +1,162 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.capability.inter; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.util.INBTSerializable; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; + +public interface ILeashDataCapability extends INBTSerializable { + // 原LeashData的方法接口 + boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance); + boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance, double elasticDistance, int maxKeepLeashTicks); + + boolean setMaxDistance(Entity holder, double newMaxDistance); + boolean setMaxDistance(Entity holder,double newMaxDistance, int newMaxKeepLeashTicks); + boolean setMaxDistance(UUID holderUUID, double newMaxDistance); + boolean setMaxDistance(UUID holderUUID, double newMaxDistance, int newMaxKeepLeashTicks); + boolean setMaxDistance(BlockPos knotPos, double newMaxDistance); + boolean setMaxDistance(BlockPos knotPos, double newMaxDistance, int newMaxKeepLeashTicks); + boolean setElasticDistance(Entity holder, double newElasticDistance); + boolean setElasticDistance(UUID holderUUID, double newElasticDistance); + boolean setElasticDistance(BlockPos knotPos, double newElasticDistance); + // 动态修改弹性距离 + boolean setElasticDistance(Entity holder, double newElasticDistance, int newMaxKeepLeashTicks); + boolean setElasticDistance(UUID holderUUID, double newElasticDistance, int newMaxKeepLeashTicks); + boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks); + + void applyLeashForces(); + boolean removeLeash(Entity holder); + boolean removeLeash(UUID holderUUID); + boolean removeLeash(BlockPos knotPos); + + boolean transferLeash(Entity holder, Entity newHolder); + boolean transferLeash(Entity holder, Entity newHolder, ItemStack stack); + boolean transferLeash(UUID holderUUID, Entity newHolder); + boolean transferLeash(UUID holderUUID, Entity newHolder, ItemStack stack); + boolean transferLeash(BlockPos knotPos, Entity newHolder); + boolean transferLeash(BlockPos knotPos, Entity newHolder, ItemStack stack); + + // 查询方法 + Collection getAllLeashes(); + boolean isLeashedBy(Entity holder); + boolean isLeashedBy(UUID holderUUID); + boolean isLeashedBy(BlockPos knotPos); + Optional getLeashInfo(Entity holder); + Optional getLeashInfo(UUID holderUUID); + Optional getLeashInfo(BlockPos knotPos); + + boolean canBeLeashed(); + boolean canBeAttachedTo(Entity pEntity); + + + record LeashInfo( + Optional blockPosOpt, + Optional holderUUIDOpt, + Optional holderIdOpt,//Only for client side use + String reserved, //保留字段 + Vec3 attachOffset, + double maxDistance, + double elasticDistance, + int keepLeashTicks, // 新增:保持拴绳的剩余Tick数 + int maxKeepLeashTicks // 新增:最大保持Tick数(可配置) + ) { + public static LeashInfo CreateLeashInfo( + Entity entity, + String reserved, + Vec3 attachOffset, + double maxDistance, + double elasticDistance, + int keepLeashTicks, + int maxKeepLeashTicks + ) { + return entity instanceof SuperLeashKnotEntity superLeashKnot ? + new LeashInfo(superLeashKnot.getPos(), entity.getId(), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks) : + new LeashInfo(entity.getUUID(), entity.getId(), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks); + } + public LeashInfo( + UUID holderUUID, + int holderId, + String reserved, + Vec3 attachOffset, + double maxDistance, + double elasticDistance, + int keepLeashTicks, + int maxKeepLeashTicks + ) { + this(Optional.empty() ,Optional.of(holderUUID), Optional.of(holderId), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks); + } + public LeashInfo( + BlockPos knotPos, + int holderId, + String reserved, + Vec3 attachOffset, + double maxDistance, + double elasticDistance, + int keepLeashTicks, + int maxKeepLeashTicks + ) { + this(Optional.of(knotPos), Optional.empty(), Optional.of(holderId), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks); + } + + // 返回一个减少剩余Tick的新实例 + public LeashInfo decrementKeepLeashTicks() { + return new LeashInfo( + blockPosOpt, holderUUIDOpt, holderIdOpt, reserved, attachOffset, + maxDistance, elasticDistance, + Math.max(0, keepLeashTicks - 1), + maxKeepLeashTicks + ); + } + + // 重置Tick为最大值 + public LeashInfo resetKeepLeashTicks() { + return new LeashInfo( + blockPosOpt, holderUUIDOpt, holderIdOpt, reserved, attachOffset, + maxDistance, elasticDistance, + maxKeepLeashTicks, + maxKeepLeashTicks + ); + } + public LeashInfo transferHolder (Entity entity) { + boolean isSuperKnot = entity instanceof SuperLeashKnotEntity; + return new LeashInfo( + isSuperKnot ? Optional.of(((SuperLeashKnotEntity) entity).getPos()) : Optional.empty(), + !isSuperKnot ? Optional.of(entity.getUUID()) : Optional.empty(), + Optional.of(entity.getId()), + reserved, attachOffset, maxDistance,elasticDistance, keepLeashTicks, maxKeepLeashTicks + ); + } + public LeashInfo transferHolder (Entity entity, String reserved) { + boolean isSuperKnot = entity instanceof SuperLeashKnotEntity; + return new LeashInfo( + isSuperKnot ? Optional.of(((SuperLeashKnotEntity) entity).getPos()) : Optional.empty(), + !isSuperKnot ? Optional.of(entity.getUUID()) : Optional.empty(), + Optional.of(entity.getId()), + reserved, attachOffset, maxDistance,elasticDistance, keepLeashTicks, maxKeepLeashTicks + ); + } + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashEntity.java b/src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashEntity.java new file mode 100644 index 0000000..074fb4c --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashEntity.java @@ -0,0 +1,69 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.entity; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; +import top.r3944realms.superleadrope.core.register.SLPEntityTypes; + +public class SuperLeashEntity extends Entity { + private Entity controlled; + public SuperLeashEntity(EntityType entityType, Level level) { + super(entityType, level); + } + public SuperLeashEntity(Level level, Entity controlled) { + super(SLPEntityTypes.SUPER_LEASH.get(), level); + if (!LeashDataImpl.isLeashable(controlled)) { + throw new IllegalArgumentException("Controlled entity " + controlled.getClass().getName() + "is not a leashable entity"); + } + this.controlled = controlled; + } + + public Entity getControlled() { + return controlled; + } + + @Override + public void tick() { + super.tick(); + if (controlled == null || !controlled.isAlive()) { + this.discard(); + } + this.setPos(controlled.getX(), controlled.getY(), controlled.getZ()); + if(!level().isClientSide) controlled.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(ILeashDataCapability::applyLeashForces); + } + + @Override + protected void defineSynchedData() { + + } + + @Override + protected void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { + + } + + @Override + protected void addAdditionalSaveData(@NotNull CompoundTag compoundTag) { + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashKnotEntity.java b/src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashKnotEntity.java new file mode 100644 index 0000000..8c5af5f --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/entity/SuperLeashKnotEntity.java @@ -0,0 +1,154 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.LeashFenceKnotEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.phys.AABB; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.core.register.SLPEntityTypes; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class SuperLeashKnotEntity extends LeashFenceKnotEntity { + // 默认尺寸 + private static final float DEFAULT_WIDTH = 0.5f; + private static final float DEFAULT_HEIGHT = 0.5f; + + // 当前计算出的尺寸 + private float currentWidth = DEFAULT_WIDTH; + private float currentHeight = DEFAULT_HEIGHT; + + // 支持的方块标签 //TODO:未来可配置化 + private static final List> SUPPORTED_BLOCK = Arrays.asList( + BlockTags.FENCES, + BlockTags.WALLS + ); + + public SuperLeashKnotEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public SuperLeashKnotEntity(Level pLevel, BlockPos pPos) { + this(SLPEntityTypes.SUPER_LEAD_KNOT.get(), pLevel); + this.setPos(pPos.getX(), pPos.getY(), pPos.getZ()); + } + + + @Override + public boolean survives() { + return SuperLeashKnotEntity.isSupportBlock(this.level().getBlockState(this.pos)); + } + + public static @NotNull SuperLeashKnotEntity getOrCreateKnot(@NotNull Level pLevel, @NotNull BlockPos pPos) { + int i = pPos.getX(); + int j = pPos.getY(); + int k = pPos.getZ(); + + for(SuperLeashKnotEntity superLeashKnotEntity : pLevel.getEntitiesOfClass(SuperLeashKnotEntity.class, new AABB((double)i - 1.0D, (double)j - 1.0D, (double)k - 1.0D, (double)i + 1.0D, (double)j + 1.0D, (double)k + 1.0D))) { + if (superLeashKnotEntity.getPos().equals(pPos)) { + return superLeashKnotEntity; + } + } + + SuperLeashKnotEntity superLeashKnotEntity1 = new SuperLeashKnotEntity(pLevel, pPos); + pLevel.addFreshEntity(superLeashKnotEntity1); + return superLeashKnotEntity1; + } + + @Override + protected void recalculateBoundingBox() { + updateDimensionsBasedOnBlock(); + double halfWidth = currentWidth / 2.0f; + this.setBoundingBox(new AABB( + this.getX() - halfWidth, + this.getY(), + this.getZ() - halfWidth, + this.getX() + halfWidth, + this.getY() + currentHeight, + this.getZ() + halfWidth + )); + } + + private void updateDimensionsBasedOnBlock() { + BlockState state = this.level().getBlockState(this.pos); + + // 根据方块类型调整尺寸 + if (state.is(BlockTags.WALLS)) { + // 墙类方块 - 更窄更高 + currentWidth = 0.25f; + currentHeight = 0.75f; + } else { + // 默认栅栏尺寸 + currentWidth = DEFAULT_WIDTH; + currentHeight = DEFAULT_HEIGHT; + } + //TODO: 未来扩展可配置化大小 + } + @Override + public void setPos(double x, double y, double z) { + super.setPos(x, y, z); + // 确保位置与方块中心对齐 + BlockPos pos = this.getPos(); + this.setPosRaw(pos.getX() + 0.5, pos.getY() + 0.375, pos.getZ() + 0.5); + } + + public static boolean isSupportBlock(BlockState state) { + for(TagKey tagKey : SUPPORTED_BLOCK) { + if(state.is(tagKey)) { + return true; + } + } + return false; + } + @Override + public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand) { + if (this.level().isClientSide) { + return InteractionResult.SUCCESS; + } + AtomicBoolean isTransferLeash = new AtomicBoolean(false); + List entities = LeashDataImpl.leashableInArea(player, ing -> true); + for(Entity entity : entities) { + if (LeashDataImpl.isLeashHolder(entity, player.getUUID())) + entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> { + i.transferLeash(player.getUUID(), this); + isTransferLeash.set(true); + }); + + } + + + if (isTransferLeash.get() ) { + this.gameEvent(GameEvent.BLOCK_ATTACH, player); + } + return InteractionResult.CONSUME; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/content/item/SuperLeadRopeItem.java b/src/main/java/top/r3944realms/superleadrope/content/item/SuperLeadRopeItem.java new file mode 100644 index 0000000..b95499f --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/content/item/SuperLeadRopeItem.java @@ -0,0 +1,182 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.content.item; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.LeadItem; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraftforge.common.extensions.IForgeItem; +import net.minecraftforge.common.util.LazyOptional; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; +import top.r3944realms.superleadrope.core.register.SLPSoundEvents; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +//TODO: +// 1. 可抛掷使用 ***(下个版本实现) +// - 可转移拴绳 +// 2. 多绑定(一个生物可以被多个加强拴绳绑定,产生共同作用效果) +// 3. 支持更多支撑方块 +// 4. 可配置的生物栓效果(通过标签系统可配置哪些额外实体可被拴住) +// 5. 可自定义拴绳渲染位置(以匹配不同的生物模型) +// 6. 不可消耗的(但是有耐久,需要修复, 通过消耗原版拴绳恢复,每次多重绑定就会消耗1点耐久) +// 实现拴生物,在生物的interact方法里去写相关逻辑 +// (尝试0 mixin 实现 加强拴绳逻辑) +public class SuperLeadRopeItem extends LeadItem implements IForgeItem { + + // 配置常量 + // 【手动调节,可以通过附魔获取更远抛掷和抛掷距离 - x1.3】//TODO:将可抛掷实现留到下次编写 + // 可以做个大于一定距离时远距离使用时抛出拴绳的实体,击中生物才栓中的 + private static final double SHORT_RANGE = 5.0D; + private static final float THROW_SPEED = 1.5F; + + + public SuperLeadRopeItem(@NotNull Properties pProperties) { + super( + pProperties + .durability(1024) + .setNoRepair() + ); + } + //通过按键 可抛掷启用/关闭实现(不会影响use逻辑) + @Override + public @NotNull InteractionResultHolder use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) { + ItemStack lead = pPlayer.getItemInHand(pUsedHand); + if(!pLevel.isClientSide) { + if (canUse(lead)) return InteractionResultHolder.pass(lead); + return super.use(pLevel, pPlayer, pUsedHand); + + } + return InteractionResultHolder.pass(lead); + } + + public static boolean canUse(ItemStack itemStack) { + return itemStack.getDamageValue() < 974; + } + + @Override + public @NotNull InteractionResult useOn(@NotNull UseOnContext context) { + Level level = context.getLevel(); + BlockPos pos = context.getClickedPos(); + BlockState state = level.getBlockState(pos); + ItemStack itemStack = context.getItemInHand(); + if (canUse(itemStack)) return InteractionResult.PASS; + if(SuperLeashKnotEntity.isSupportBlock(state)) { + Player player = context.getPlayer(); + if(!level.isClientSide && player != null) { + return bindToBlock(player, level, pos, itemStack); + } + } + return InteractionResult.PASS; + } + public static InteractionResult bindToEntity (Entity newHolder, Player player, Level level, BlockPos pos, ItemStack leashStack) { + AtomicBoolean isSuccess = new AtomicBoolean(false); + List list = LeashDataImpl.leashableInArea(level, pos.getCenter(), entity -> LeashDataImpl.isLeashHolder(entity, player.getUUID())); + for(Entity e : list) { + AtomicBoolean canBeAttachedTo = new AtomicBoolean(false); + LazyOptional iLeashDataCapability = e.getCapability(CapabilityHandler.LEASH_DATA_CAP); + iLeashDataCapability.ifPresent(i -> { + if (i instanceof LeashDataImpl li) { + canBeAttachedTo.set(li.canBeAttachedTo(newHolder)); + } + }); + if(canBeAttachedTo.get()) {//canBeAttachedTo + iLeashDataCapability.ifPresent(i -> { + if(i instanceof LeashDataImpl li) { + li.transferLeash(player.getUUID(), newHolder, leashStack); + isSuccess.set(true); + } + }); + } + } + if(!isSuccess.get()) { + return InteractionResult.PASS; + } + else { + level.gameEvent(GameEvent.ENTITY_INTERACT, pos, GameEvent.Context.of(player)); + newHolder.playSound(SLPSoundEvents.LEAD_TIED.get()); + return InteractionResult.CONSUME; + } + } + public static InteractionResult bindToBlock(Player player, Level level, BlockPos pos, ItemStack leashStack) { + //实现个加强绳结实体 + SuperLeashKnotEntity knot = null; + AtomicBoolean isSuccess = new AtomicBoolean(false); + UUID uuid = player.getUUID(); + List list = LeashDataImpl.leashableInArea(level, pos.getCenter(), entity -> LeashDataImpl.isLeashHolder(entity, uuid)); + if(list.isEmpty()) {//拴自己 to new knot + if (leashStack.isEmpty() || !canUse(leashStack)) return InteractionResult.PASS; + knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);; + knot.playPlacementSound(); + + SuperLeashKnotEntity finalKnot1 = knot; + player.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> { + if(i instanceof LeashDataImpl li) { + li.addLeash(finalKnot1, leashStack, 8D); + isSuccess.set(true); + } + }); + + } + else { + for(Entity e : list) { + if(knot == null) { + knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);; + knot.playPlacementSound(); + } + AtomicBoolean canBeAttachedTo = new AtomicBoolean(false); + SuperLeashKnotEntity finalKnot = knot; + LazyOptional iLeashDataCapability = e.getCapability(CapabilityHandler.LEASH_DATA_CAP); + iLeashDataCapability.ifPresent(i -> { + if (i instanceof LeashDataImpl li) { + canBeAttachedTo.set(li.canBeAttachedTo(finalKnot)); + } + }); + if(canBeAttachedTo.get()) {//canBeAttachedTo + iLeashDataCapability.ifPresent(i -> { + if(i instanceof LeashDataImpl li) { + li.transferLeash(uuid, finalKnot); + isSuccess.set(true); + } + }); + } + } + } + if (isSuccess.get()) { + if(!player.isCreative()) { + leashStack.hurtAndBreak(50, player, e->{}); + } + level.gameEvent(GameEvent.BLOCK_ATTACH, pos, GameEvent.Context.of(player)); + return InteractionResult.SUCCESS; + } else + return InteractionResult.PASS; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/core/leash/LeashInteractHandler.java b/src/main/java/top/r3944realms/superleadrope/core/leash/LeashInteractHandler.java new file mode 100644 index 0000000..4d4b042 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/core/leash/LeashInteractHandler.java @@ -0,0 +1,103 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.core.leash; + + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; +import top.r3944realms.superleadrope.content.capability.LeashDataImpl; +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; +import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem; +import top.r3944realms.superleadrope.core.register.SLPItems; +import top.r3944realms.superleadrope.core.register.SLPSoundEvents; + +public class LeashInteractHandler { + //只有玩家可以互动触发(其它的暂不支持(考虑到0 Mixin) + public static void onEntityInteract (PlayerInteractEvent.EntityInteract event) { + //WARNING: 主手和副手都会触发一次该事件 + + // ===== 卫语句 ===== + if (event.getLevel().isClientSide) { + return; + } + InteractionHand hand = event.getHand(); + if (hand == InteractionHand.OFF_HAND) { + return; + } + Entity target = event.getTarget(); + + if (!LeashDataImpl.isLeashable(target)) { + return; + } + LazyOptional LeashCap = target.getCapability(CapabilityHandler.LEASH_DATA_CAP); + if (!LeashCap.isPresent()) { + return; + } + Player player = event.getEntity(); + + ItemStack mainHandItem = player.getItemInHand(InteractionHand.MAIN_HAND); + ItemStack offHandItem = player.getItemInHand(InteractionHand.OFF_HAND); + //shift 按下 && 主副手无物品 attach拴绳 && 互动实体是Alive的 && 实体可被拴(保留改方法,未来使用) + if ( + mainHandItem.isEmpty() && offHandItem.isEmpty() && + target.isAlive() && player.isSecondaryUseActive() && + LeashCap.map(ILeashDataCapability::canBeLeashed).orElse(false) + + ) { + + SuperLeadRopeItem.bindToEntity(target, player, player.level(), target.getOnPos(), ItemStack.EMPTY); + } else { + if(LeashDataImpl.isLeashHolder(target, player)) { + LeashCap.ifPresent( + iLeashDataCapability -> iLeashDataCapability.removeLeash(player.getUUID()) + ); + target.gameEvent(GameEvent.ENTITY_INTERACT, player); + target.playSound(SLPSoundEvents.LEAD_UNTIED.get()); + return; + } + ItemStack itemStack; + if (mainHandItem.is(SLPItems.SUPER_LEAD_ROPE.get()) && SuperLeadRopeItem.canUse(mainHandItem)) { + itemStack = mainHandItem; + } else if (offHandItem.is(SLPItems.SUPER_LEAD_ROPE.get()) && SuperLeadRopeItem.canUse(offHandItem)) { + itemStack = offHandItem; + } else { + itemStack = ItemStack.EMPTY; + } + if (!itemStack.isEmpty()) { + if (itemStack.getItem() == SLPItems.SUPER_LEAD_ROPE.get()) {} + LeashCap.ifPresent(iLeashDataCapability -> { + if (iLeashDataCapability.canBeAttachedTo(player)) { + boolean success = iLeashDataCapability.addLeash(player, itemStack, 12); + if (success) { + if(!player.isCreative()) + itemStack.hurtAndBreak(50, player, e->{}); + target.playSound(SLPSoundEvents.LEAD_TIED.get()); + } + } + }); + + } + } + + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/core/leash/LeashSyncManager.java b/src/main/java/top/r3944realms/superleadrope/core/leash/LeashSyncManager.java new file mode 100644 index 0000000..2b4e1ad --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/core/leash/LeashSyncManager.java @@ -0,0 +1,39 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.core.leash; + +import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability; + +import java.util.Collections; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.function.Consumer; + +// 全局LeashData同步管理器 +public class LeashSyncManager { + static final Set INSTANCES = Collections.newSetFromMap(new WeakHashMap<>()); + + public static void track(ILeashDataCapability instance) { + INSTANCES.add(instance); + } + public static void untrack(ILeashDataCapability instance) { + INSTANCES.remove(instance); + } + public static void forEach(Consumer consumer) { + INSTANCES.forEach(consumer); + } + +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/superleadrope/core/register/SLPEntityTypes.java b/src/main/java/top/r3944realms/superleadrope/core/register/SLPEntityTypes.java new file mode 100644 index 0000000..5cb0fad --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/core/register/SLPEntityTypes.java @@ -0,0 +1,58 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.core.register; + +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.content.entity.SuperLeashEntity; +import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity; + +public class SLPEntityTypes { + public static DeferredRegister> ENTITY_TYPES = + DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, SuperLeadRope.MOD_ID); + public static RegistryObject> SUPER_LEAD_KNOT = ENTITY_TYPES.register( + "super_lead_knot", + () -> EntityType.Builder.of(SuperLeashKnotEntity::new, MobCategory.MISC) + .sized(1.0F, 1.0F) + .clientTrackingRange(4) + .updateInterval(20) + .noSave() + .build("super_lead_knot") + ); + public static RegistryObject> SUPER_LEASH = ENTITY_TYPES.register( + "super_leash", + () -> EntityType.Builder.of(SuperLeashEntity::new, MobCategory.MISC) + .sized(0.01f, 0.01f) + .noSummon() + .noSave() + .clientTrackingRange(0) + .updateInterval(1) + .fireImmune() + .canSpawnFarFromPlayer() + .build("super_leash") + ); + public static String getEntityNameKey(String entityName) { + return "entity." + SuperLeadRope.MOD_ID + "." + entityName; + } + public static void register(IEventBus bus) { + ENTITY_TYPES.register(bus); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/core/register/SLPItems.java b/src/main/java/top/r3944realms/superleadrope/core/register/SLPItems.java new file mode 100644 index 0000000..f875a24 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/core/register/SLPItems.java @@ -0,0 +1,35 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.core.register; + +import net.minecraft.world.item.Item; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem; + +public class SLPItems { + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, SuperLeadRope.MOD_ID); + public static final RegistryObject SUPER_LEAD_ROPE = ITEMS.register( + "super_lead_rope", + () -> new SuperLeadRopeItem(new Item.Properties()) + ); + public static void register(IEventBus bus) { + ITEMS.register(bus); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/core/register/SLPSoundEvents.java b/src/main/java/top/r3944realms/superleadrope/core/register/SLPSoundEvents.java new file mode 100644 index 0000000..6a5f1c9 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/core/register/SLPSoundEvents.java @@ -0,0 +1,44 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.core.register; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import top.r3944realms.superleadrope.SuperLeadRope; + +public class SLPSoundEvents { + public static final DeferredRegister SOUND_EVENTS = DeferredRegister.create(ForgeRegistries.SOUND_EVENTS, SuperLeadRope.MOD_ID); + public static final ResourceLocation RL_LEAD_UNTIED = new ResourceLocation(SuperLeadRope.MOD_ID,"item/superlead/lead_untied"); + public static final ResourceLocation RL_LEAD_TIED = new ResourceLocation(SuperLeadRope.MOD_ID,"item/superlead/lead_tied"); + public static final ResourceLocation RL_LEAD_BREAK = new ResourceLocation(SuperLeadRope.MOD_ID,"item/superlead/lead_break"); + public static final RegistryObject LEAD_UNTIED = registerSound("lead_untied"); + public static final RegistryObject LEAD_TIED = registerSound("lead_tied"); + public static final RegistryObject LEAD_BREAK = registerSound("lead_break"); + private static RegistryObject registerSound(String name) { + ResourceLocation location = new ResourceLocation(SuperLeadRope.MOD_ID, name); + return SOUND_EVENTS.register(name, () -> SoundEvent.createVariableRangeEvent(location)); + } + public static void register(IEventBus bus) { + SOUND_EVENTS.register(bus); + } + public static String getSubTitleTranslateKey(String name) { + return "sound." + SuperLeadRope.MOD_ID + ".subtitle." + name; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/SLPDataGenEvent.java b/src/main/java/top/r3944realms/superleadrope/datagen/SLPDataGenEvent.java new file mode 100644 index 0000000..97ce933 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/SLPDataGenEvent.java @@ -0,0 +1,89 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen; + +import net.minecraft.core.HolderLookup; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.datagen.provider.*; +import top.r3944realms.superleadrope.utils.lang.LanguageEnum; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +@Mod.EventBusSubscriber(modid = SuperLeadRope.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class SLPDataGenEvent { + static Logger logger = LoggerFactory.getLogger(SLPDataGenEvent.class); + @SubscribeEvent + public static void gatherData(GatherDataEvent event) throws IOException { + logger.info("GatherDataEvent thread: {}", Thread.currentThread().getName()); + CompletableFuture lookupProvider = event.getLookupProvider(); + LanguageGenerator(event, LanguageEnum.English); + LanguageGenerator(event, LanguageEnum.SimpleChinese); + LanguageGenerator(event, LanguageEnum.TraditionalChinese); + LanguageGenerator(event, LanguageEnum.LiteraryChinese); + RecipeGenerator(event); + ModelDataGenerate(event); + TagsProvider(event, lookupProvider); + SoundProvider(event); + } + private static void LanguageGenerator(GatherDataEvent event, LanguageEnum language) { + event.getGenerator().addProvider( + event.includeClient(), + (DataProvider.Factory) pOutput -> new SLPLanguageProvider(pOutput, language) + ); + } + + private static void RecipeGenerator(GatherDataEvent event) { + PackOutput packOutput = event.getGenerator().getPackOutput(); + event.getGenerator().addProvider( + true, + new SLPItemRecipeProvider(packOutput) + ); + } + private static void TagsProvider(GatherDataEvent event, CompletableFuture completableFuture) { + event.getGenerator().addProvider( + event.includeServer(), + (DataProvider.Factory) pOutput -> new SLPBlockTagProvider(pOutput, completableFuture, event.getExistingFileHelper()) + + ); + event.getGenerator().addProvider( + event.includeServer(), + (DataProvider.Factory) pOutput -> + new SLPItemTagProvider(pOutput, completableFuture, event.getExistingFileHelper()) + ); + } + private static void SoundProvider(GatherDataEvent event) { + event.getGenerator().addProvider( + event.includeClient(), + (DataProvider.Factory) pOutput -> + new SLPSoundDefinitionsProvider(pOutput,event.getExistingFileHelper()) + ); + } + + private static void ModelDataGenerate(GatherDataEvent event) { + event.getGenerator().addProvider( + event.includeClient(), + (DataProvider.Factory) pOutput -> new SLPItemModelProvider(pOutput, event.getExistingFileHelper()) + ); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPAdvancementKey.java b/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPAdvancementKey.java new file mode 100644 index 0000000..66139b6 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPAdvancementKey.java @@ -0,0 +1,44 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.data; +import top.r3944realms.superleadrope.SuperLeadRope; + +import javax.annotation.Nullable; + +public enum SLPAdvancementKey { + ; + private final String Name; + @Nullable + private final SLPAdvancementKey Parent; + SLPAdvancementKey(String name, @Nullable SLPAdvancementKey parent) { + this.Name = name; + this.Parent = parent; + } + + public @Nullable SLPAdvancementKey getParent() { + return Parent; + } + public String getNameKey() { + return "advancement." + SuperLeadRope.MOD_ID + "." + Name; + } + + public String getDescKey() { + return this.getNameKey() + ".desc"; + } + public String getNameWithNameSpace() { + return SuperLeadRope.MOD_ID + ":" + this.Name; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPItemTags.java b/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPItemTags.java new file mode 100644 index 0000000..3444beb --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPItemTags.java @@ -0,0 +1,36 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.data; + +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; + +public final class SLPItemTags { + + + private SLPItemTags() { + } + + private static TagKey bind(String name) { + return TagKey.create(Registries.ITEM, new ResourceLocation(name)); + } + + public static TagKey create(final ResourceLocation name) { + return TagKey.create(Registries.ITEM, name); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPLangKeyValue.java b/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPLangKeyValue.java new file mode 100644 index 0000000..b1dc790 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/data/SLPLangKeyValue.java @@ -0,0 +1,171 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.data; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.superleadrope.core.register.SLPEntityTypes; +import top.r3944realms.superleadrope.core.register.SLPItems; +import top.r3944realms.superleadrope.core.register.SLPSoundEvents; +import top.r3944realms.superleadrope.utils.lang.LanguageEnum; +import top.r3944realms.superleadrope.utils.lang.ModPartEnum; + +import javax.annotation.Nullable; +import java.util.function.Supplier; + + +public enum SLPLangKeyValue { + ITEM_SUPER_LEAD_ROPE( + SLPItems.SUPER_LEAD_ROPE, ModPartEnum.ITEM, + "Super Lead Rope", "超级拴绳", "超級拴繩","神駒羈縻索" + ), + + SOUND_SUBTITLE_SUPER_LEAD_BREAK( + SLPSoundEvents.getSubTitleTranslateKey("lead_break"), ModPartEnum.SOUND, + "Lead Break", "拴绳断裂", "拴繩斷裂", "索絕" + ), + + SOUND_SUBTITLE_SUPER_LEAD_TIED( + SLPSoundEvents.getSubTitleTranslateKey("lead_tied"), ModPartEnum.SOUND, + "Lead Tied", "拴绳系上", "拴繩係上", "繫索" + ), + + SOUND_SUBTITLE_SUPER_LEAD_UNTIED( + SLPSoundEvents.getSubTitleTranslateKey("lead_untied"), ModPartEnum.SOUND, + "Lead Untie", "拴绳解开", "拴繩解開", "解索" + ), + + ENTITY_SUPER_LEAD_KNOT( + SLPEntityTypes.getEntityNameKey("super_lead_knot"), ModPartEnum.ENTITY, + "Super Lead Knot", "超级拴绳结", "超級拴繩結", "神駒羈縻索結" + ), + + ENTITY_SUPER_LEASH( + SLPEntityTypes.getEntityNameKey("super_leash"), ModPartEnum.ENTITY, + "Super Leash", "超级拴绳", "超級拴繩","神駒羈縻索" + ), + + + + ; + private final Supplier supplier; + private String key; + private final String US_EN; + private final String SIM_CN; + private final String TRA_CN; + private final String LZH; + private final Boolean Default; + private final ModPartEnum MPE; + + SLPLangKeyValue(Supplier Supplier, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, String LZH, Boolean isDefault) { + this.supplier = Supplier; + this.MPE = MPE; + this.US_EN = US_EN; + this.SIM_CN = SIM_CN; + this.TRA_CN = TRA_CN; + this.LZH = LZH; + this.Default = isDefault; + } + SLPLangKeyValue(@NotNull String ResourceKey, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, String LZH, Boolean isDefault) { + this.supplier = null; + this.key = ResourceKey; + this.MPE = MPE; + this.US_EN = US_EN; + this.SIM_CN = SIM_CN; + this.TRA_CN = TRA_CN; + this.LZH = LZH; + this.Default = isDefault; + } + SLPLangKeyValue(Supplier Supplier, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, String LZH) { + this(Supplier, MPE, US_EN, SIM_CN, TRA_CN, LZH, false); + } + SLPLangKeyValue(Supplier Supplier, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, Boolean isDefault) { + this(Supplier, MPE, US_EN, SIM_CN, TRA_CN, null, isDefault); + } + SLPLangKeyValue(@NotNull String ResourceKey, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, Boolean isDefault) { + this(ResourceKey, MPE, US_EN, SIM_CN, TRA_CN, null, isDefault); + } + SLPLangKeyValue(@NotNull String ResourceKey, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, String LZH) { + this(ResourceKey, MPE, US_EN, SIM_CN, TRA_CN, LZH, false); + } + SLPLangKeyValue(Supplier Supplier, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN) { + this(Supplier, MPE, US_EN, SIM_CN, TRA_CN, null, false); + } + SLPLangKeyValue(@NotNull String ResourceKey, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN) { + this(ResourceKey, MPE, US_EN, SIM_CN, TRA_CN, null, false); + } + public static String getLan(LanguageEnum lan, SLPLangKeyValue key) { + if (lan == null || lan == LanguageEnum.English) return getEnglish(key); + else { + switch (lan) { + case SimpleChinese -> { + return getSimpleChinese(key); + } + case TraditionalChinese -> { + return getTraditionalChinese(key); + } + case LiteraryChinese -> { + return getLiteraryChinese(key); + } + default -> { + return getEnglish(key); + } + } + } + } + private static String getEnglish(SLPLangKeyValue key) { + return key.US_EN; + } + private static String getSimpleChinese(SLPLangKeyValue key) { + return key.SIM_CN; + } + private static String getTraditionalChinese(SLPLangKeyValue key) { + return key.TRA_CN; + } + @Nullable + public static String getLiteraryChinese(SLPLangKeyValue key) { + return key.LZH; + } + public String getKey() { + if(key == null){ + switch (MPE) {//Don't need to use "break;"[Java feature]; + case CREATIVE_TAB, MESSAGE, INFO, DEFAULT, COMMAND, CONFIG -> throw new UnsupportedOperationException("The Key value is NULL! Please use the correct constructor and write the parameters correctly"); + case ITEM -> key = (getItem()).getDescriptionId(); + case BLOCK -> key =(getBlock()).getDescriptionId(); + + } + //需要完善 + } + return key; + } + @SuppressWarnings("null") + public Item getItem() { + assert supplier != null; + return (Item)supplier.get(); + } + @SuppressWarnings("null") + public Block getBlock() { + assert supplier != null; + return (Block)supplier.get(); + } + public boolean isDefaultItem(){ + return MPE == ModPartEnum.ITEM && Default; + } + public boolean isDefaultBlock() { + return MPE == ModPartEnum.BLOCK && Default; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPBlockTagProvider.java b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPBlockTagProvider.java new file mode 100644 index 0000000..0f1c16b --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPBlockTagProvider.java @@ -0,0 +1,40 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.provider; + +import net.minecraft.core.HolderLookup; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.BlockTagsProvider; +import net.minecraftforge.common.data.ExistingFileHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import top.r3944realms.superleadrope.SuperLeadRope; + +import java.util.concurrent.CompletableFuture; + +public class SLPBlockTagProvider extends BlockTagsProvider { + public SLPBlockTagProvider( + PackOutput output, + CompletableFuture lookupProvider, + @Nullable ExistingFileHelper existingFileHelper) { + super(output, lookupProvider, SuperLeadRope.MOD_ID, existingFileHelper); + } + + @Override + protected void addTags(HolderLookup.@NotNull Provider provider) { + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemModelProvider.java b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemModelProvider.java new file mode 100644 index 0000000..35902bd --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemModelProvider.java @@ -0,0 +1,93 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.provider; + +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraftforge.client.model.generators.ItemModelBuilder; +import net.minecraftforge.client.model.generators.ItemModelProvider; +import net.minecraftforge.client.model.generators.ModelFile; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.registries.ForgeRegistries; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class SLPItemModelProvider extends ItemModelProvider { + private static List objectList; + public static final String GENERATED = "item/generated"; + public static final String HANDHELD = "item/handheld"; + + public SLPItemModelProvider(PackOutput output, ExistingFileHelper existingFileHelper) { + super(output, SuperLeadRope.MOD_ID, existingFileHelper); + objectList = new ArrayList<>(); + init(); + } + + @Override + protected void registerModels() { + DefaultModItemModelRegister(); + superLeadRopeModel(); + } + private void init() { + for(SLPLangKeyValue obj : SLPLangKeyValue.values()) { + if(!obj.isDefaultItem()) continue; + objectList.add(obj.getItem()); + } + } + /** + * @implNote
 先有纹理才会成功构建 + */ + private void DefaultModItemModelRegister() { + objectList.forEach(this::basicItem); + } + + public void itemGenerateModel(Item item, ResourceLocation location){ + withExistingParent(itemName(item), GENERATED).texture("layer0", location); + } + public void itemHandHeldModel(Item item, ResourceLocation location){ + withExistingParent(itemName(item), HANDHELD).texture("layer0", location); + } + public void superLeadRopeModel() { + // 生成主模型,支持根据 predicate 切换模型 + ItemModelBuilder builder = getBuilder(SuperLeadRope.MOD_ID + ":super_lead_rope"); + + builder.parent(new ModelFile.UncheckedModelFile(GENERATED)) + .texture("layer0", resourceItem("super_lead_rope")) + .override() + .predicate(new ResourceLocation(SuperLeadRope.MOD_ID, "broken"), 1.0f) + .model(new ModelFile.UncheckedModelFile(resourceItem("broken_super_lead_rope"))) + .end(); + + // 生成损坏模型 + ItemModelBuilder brokenBuilder = getBuilder(SuperLeadRope.MOD_ID + ":broken_super_lead_rope"); + + brokenBuilder.parent(new ModelFile.UncheckedModelFile(GENERATED)) + .texture("layer0", resourceItem("broken_super_lead_rope")); + } + + public String itemName(Item item){ + return Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item)).getPath(); + } + + public ResourceLocation resourceItem(String path){ + return modLoc("item/" + path); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemRecipeProvider.java b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemRecipeProvider.java new file mode 100644 index 0000000..a8c9ad9 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemRecipeProvider.java @@ -0,0 +1,34 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.provider; + +import net.minecraft.data.PackOutput; +import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.data.recipes.RecipeProvider; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +public class SLPItemRecipeProvider extends RecipeProvider { + public SLPItemRecipeProvider(PackOutput output) { + super(output); + } + + @Override + protected void buildRecipes(@NotNull Consumer consumer) { + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemTagProvider.java b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemTagProvider.java new file mode 100644 index 0000000..01cb025 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPItemTagProvider.java @@ -0,0 +1,41 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.provider; + +import net.minecraft.core.HolderLookup; +import net.minecraft.data.PackOutput; +import net.minecraft.data.tags.ItemTagsProvider; +import net.minecraftforge.common.data.ExistingFileHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import top.r3944realms.superleadrope.SuperLeadRope; + +import java.util.concurrent.CompletableFuture; + +public class SLPItemTagProvider extends ItemTagsProvider { + public SLPItemTagProvider( + PackOutput packOutput, + CompletableFuture holderProvider, + @Nullable ExistingFileHelper existingFileHelper) { + super(packOutput, holderProvider, CompletableFuture.completedFuture(TagLookup.empty()), SuperLeadRope.MOD_ID, existingFileHelper); + } + + @Override + protected void addTags(HolderLookup.@NotNull Provider provider) { + + + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPLanguageProvider.java b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPLanguageProvider.java new file mode 100644 index 0000000..2338574 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPLanguageProvider.java @@ -0,0 +1,56 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.provider; + +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.LanguageProvider; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue; +import top.r3944realms.superleadrope.utils.lang.LanguageEnum; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static top.r3944realms.superleadrope.datagen.data.SLPLangKeyValue.getLan; + + +public class SLPLanguageProvider extends LanguageProvider { + private final LanguageEnum Language; + private final Map LanKeyMap; + private static final List objects = new ArrayList<>(); + public SLPLanguageProvider(PackOutput output, LanguageEnum Lan) { + super(output, SuperLeadRope.MOD_ID, Lan.local); + this.Language = Lan; + LanKeyMap = new HashMap<>(); + init(); + } + private void init() { + for (SLPLangKeyValue key : SLPLangKeyValue.values()) { + addLang(key.getKey(), getLan(Language, key)); + } + } + private void addLang(String Key, String value) { + if(!objects.contains(Key)) objects.add(Key); + LanKeyMap.put(Key, value); + } + + @Override + protected void addTranslations() { + objects.forEach(key -> add(key,LanKeyMap.get(key))); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPSoundDefinitionsProvider.java b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPSoundDefinitionsProvider.java new file mode 100644 index 0000000..8213154 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/datagen/provider/SLPSoundDefinitionsProvider.java @@ -0,0 +1,62 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.datagen.provider; + +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.SoundDefinition; +import net.minecraftforge.common.data.SoundDefinitionsProvider; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.core.register.SLPSoundEvents; + +public class SLPSoundDefinitionsProvider extends SoundDefinitionsProvider { + public SLPSoundDefinitionsProvider(PackOutput output, ExistingFileHelper helper) { + super(output, SuperLeadRope.MOD_ID, helper); + } + public SoundDefinition getSoundDefinition(String subTitle, SoundDefinition.Sound... sounds) { + return SoundDefinition.definition().subtitle(subTitle).with(sounds); + } + + @Override + public void registerSounds() { + add( + SLPSoundEvents.LEAD_UNTIED, + getSoundDefinition( + SLPSoundEvents.getSubTitleTranslateKey("lead_untied"), + sound(SLPSoundEvents.RL_LEAD_UNTIED.withSuffix("1"), SoundDefinition.SoundType.SOUND), + sound(SLPSoundEvents.RL_LEAD_UNTIED.withSuffix("2"), SoundDefinition.SoundType.SOUND), + sound(SLPSoundEvents.RL_LEAD_UNTIED.withSuffix("3"), SoundDefinition.SoundType.SOUND) + ) + ); + add( + SLPSoundEvents.LEAD_TIED, + getSoundDefinition( + SLPSoundEvents.getSubTitleTranslateKey("lead_tied"), + sound(SLPSoundEvents.RL_LEAD_TIED.withSuffix("1"), SoundDefinition.SoundType.SOUND), + sound(SLPSoundEvents.RL_LEAD_TIED.withSuffix("2"), SoundDefinition.SoundType.SOUND), + sound(SLPSoundEvents.RL_LEAD_TIED.withSuffix("3"), SoundDefinition.SoundType.SOUND) + + ) + ); + add( + SLPSoundEvents.LEAD_BREAK, + getSoundDefinition( + SLPSoundEvents.getSubTitleTranslateKey("lead_break"), + sound(SLPSoundEvents.RL_LEAD_BREAK, SoundDefinition.SoundType.SOUND) + ) + ); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/network/NetworkHandler.java b/src/main/java/top/r3944realms/superleadrope/network/NetworkHandler.java new file mode 100644 index 0000000..1bec9ed --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/network/NetworkHandler.java @@ -0,0 +1,50 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.network; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkRegistry; +import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.network.simple.SimpleChannel; +import top.r3944realms.superleadrope.SuperLeadRope; +import top.r3944realms.superleadrope.network.toClient.LeashDataSyncPacket; + +public class NetworkHandler { + private static final String PROTOCOL_VERSION = "1"; + private static int cid = 0; + public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( + new ResourceLocation(SuperLeadRope.MOD_ID, "main"), + () -> PROTOCOL_VERSION, + PROTOCOL_VERSION::equals, + PROTOCOL_VERSION::equals + ); + public static void register() { + INSTANCE.messageBuilder(LeashDataSyncPacket.class, cid++, NetworkDirection.PLAY_TO_CLIENT) + .decoder(LeashDataSyncPacket::decode) + .encoder(LeashDataSyncPacket::encode) + .consumerNetworkThread(LeashDataSyncPacket::handle) + .add(); + } + public static void sendAllPlayer(MSG message){ + INSTANCE.send(PacketDistributor.ALL.noArg(), message); + } + + public static void sendToPlayer(MSG message, ServerPlayer player){ + INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/network/toClient/LeashDataSyncPacket.java b/src/main/java/top/r3944realms/superleadrope/network/toClient/LeashDataSyncPacket.java new file mode 100644 index 0000000..db2f505 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/network/toClient/LeashDataSyncPacket.java @@ -0,0 +1,64 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.network.toClient; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.network.NetworkEvent; +import top.r3944realms.superleadrope.content.capability.CapabilityHandler; + +import java.util.function.Supplier; + +public class LeashDataSyncPacket { + private final int entityId; + private final CompoundTag leashData; + + public LeashDataSyncPacket(int entityId, CompoundTag leashData) { + this.entityId = entityId; + this.leashData = leashData; + } + + public static void encode(LeashDataSyncPacket msg, FriendlyByteBuf buffer) { + buffer.writeInt(msg.entityId); + buffer.writeNbt(msg.leashData); + } + + public static LeashDataSyncPacket decode(FriendlyByteBuf buffer) { + return new LeashDataSyncPacket(buffer.readInt(), buffer.readNbt()); + } + + public static void handle(LeashDataSyncPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> { + ClientLevel level = Minecraft.getInstance().level; + if (level != null) { + Entity entity = level.getEntity(msg.entityId); + if (entity != null) { + entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(cap -> { + // 只在数据确实变化时更新 + CompoundTag current = cap.serializeNBT(); + if (!current.equals(msg.leashData)) { + cap.deserializeNBT(msg.leashData);//更新 + } + }); + } + } + }); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/utils/coremods/InvokerMethod.java b/src/main/java/top/r3944realms/superleadrope/utils/coremods/InvokerMethod.java new file mode 100644 index 0000000..a978a78 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/utils/coremods/InvokerMethod.java @@ -0,0 +1,24 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.utils.coremods; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public class InvokerMethod { + +} diff --git a/src/main/java/top/r3944realms/superleadrope/utils/lang/LanguageEnum.java b/src/main/java/top/r3944realms/superleadrope/utils/lang/LanguageEnum.java new file mode 100644 index 0000000..1c0866a --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/utils/lang/LanguageEnum.java @@ -0,0 +1,28 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.utils.lang; + +public enum LanguageEnum { + English("en_us"), + SimpleChinese("zh_cn"), + TraditionalChinese("zh_tw"), + LiteraryChinese("lzh"), + ; + public final String local; + LanguageEnum(String local) { + this.local = local; + } +} diff --git a/src/main/java/top/r3944realms/superleadrope/utils/lang/ModPartEnum.java b/src/main/java/top/r3944realms/superleadrope/utils/lang/ModPartEnum.java new file mode 100644 index 0000000..e41a367 --- /dev/null +++ b/src/main/java/top/r3944realms/superleadrope/utils/lang/ModPartEnum.java @@ -0,0 +1,37 @@ +/* + * Super Lead rope mod + * Copyright (C) 2025 R3944Realms + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package top.r3944realms.superleadrope.utils.lang; + +public enum ModPartEnum { + DEFAULT, + ITEM, + BLOCK, + ENCHANTMENT, + ADVANCEMENT, + CREATIVE_TAB, + CONFIG, + ENTITY, + GUI, + AUTHOR, + TITLE, + NAME, + DESCRIPTION, + INFO, + MESSAGE, + COMMAND, + SOUND + +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/src/main/resources/META-INF/coremods.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..779a22e --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,64 @@ +# This is an example mods.toml file. It contains the data relating to the loading mods. +# There are several mandatory fields (#mandatory), and many more that are optional (#optional). +# The overall format is standard TOML format, v0.5.0. +# Note that there are a couple of TOML lists in this file. +# Find more information on toml format here: https://github.com/toml-lang/toml +# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml +modLoader="javafml" #mandatory +# A version range to match for said mod loader - for regular FML @Mod it will be the forge version +loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. +# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. +license="${mod_license}" +# A URL to refer people to when problems occur with this mod +#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional +# A list of mods - how many allowed here is determined by the individual mod loader +[[mods]] #mandatory +# The modid of the mod +modId="${mod_id}" #mandatory +# The version number of the mod +version="${mod_version}" #mandatory +# A display name for the mod +displayName="${mod_name}" #mandatory +# A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/ +#updateJSONURL="https://change.me.example.invalid/updates.json" #optional +# A URL for the "homepage" for this mod, displayed in the mod UI +#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional +# A file name (in the root of the mod JAR) containing a logo for display +logoFile="superleadrope_logo.png" #optional +# A text field displayed in the mod UI +#credits="" #optional +# A text field displayed in the mod UI +authors="${mod_authors}" #optional +# Display Test controls the display for your mod in the server connection screen +# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. +# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. +# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. +# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. +# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. +#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) +# The description text for the mod (multi line!) (#mandatory) +description='''${mod_description}''' +# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. + +[[dependencies.${mod_id}]] #optional +# the modid of the dependency +modId="forge" #mandatory +# Does this dependency have to exist - if not, ordering below must be specified +mandatory=true #mandatory +# The version range of the dependency +versionRange="${forge_version_range}" #mandatory +# An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory +# BEFORE - This mod is loaded BEFORE the dependency +# AFTER - This mod is loaded AFTER the dependency +ordering="NONE" +# Side this dependency is applied on - BOTH, CLIENT, or SERVER +side="BOTH" +# Here's another dependency +[[dependencies.${mod_id}]] +modId="minecraft" +mandatory=true +# This version range declares a minimum of the current minecraft version up to but not including the next major version +versionRange="${minecraft_version_range}" +ordering="NONE" +side="BOTH" diff --git a/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_break.ogg b/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_break.ogg new file mode 100644 index 0000000000000000000000000000000000000000..901da7e3448c9fa46d9738509cbfd148d9cd4342 GIT binary patch literal 12113 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 JfD#cA{U4oLy(|C# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied1.ogg b/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..26e4e243634fb13b6c281b595b8c54fe2315dd86 GIT binary patch literal 6604 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied2.ogg b/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..73a1a496e6d3ef0cee70db484da2b919efe44eda GIT binary patch literal 6364 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 LjpNSKqQL(E2Tm^R literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied3.ogg b/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_tied3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..09ee64c3825b2fcff9f227f2ec98979fa4f9eb3c GIT binary patch literal 6687 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_untied3.ogg b/src/main/resources/assets/superleadrope/sounds/item/superlead/lead_untied3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f62772052b91ae253d464f6e5d1a2eff0f21f198 GIT binary patch literal 8069 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 literal 0 HcmV?d00001