├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_cn.md ├── build.gradle ├── common.gradle ├── fabricWrapper ├── build.gradle └── src │ └── main │ └── resources │ └── fabric.mod.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── icon.png ├── settings.gradle ├── src └── main │ ├── java │ └── top │ │ └── leavesmc │ │ └── Bladeren │ │ ├── BladerenMod.java │ │ ├── ModInfo.java │ │ ├── clientcommands │ │ └── RandomManager.java │ │ ├── compat │ │ └── modmenu │ │ │ ├── ModMenuApiImpl.java │ │ │ └── WrapperModMenuApiImpl.java │ │ ├── config │ │ └── Configs.java │ │ ├── event │ │ └── DisconnectEvent.java │ │ ├── gui │ │ └── GuiConfigs.java │ │ ├── leaves │ │ ├── LeavesPayload.java │ │ └── LeavesProtocol.java │ │ ├── minihud │ │ └── msptSyncProtocol │ │ │ └── MsptSyncProtocol.java │ │ └── mixin │ │ ├── accessor │ │ └── AccessorDataStorage.java │ │ ├── clientcommands │ │ ├── MixinClientsCommands.java │ │ ├── disableNotVanillaWarn │ │ │ └── MixinServerBrandManager.java │ │ └── fishCommand │ │ │ ├── MixinConfigs.java │ │ │ ├── MixinFishCommand.java │ │ │ ├── MixinFishingCracker.java │ │ │ └── MixinLootContext.java │ │ ├── event │ │ └── disconnect │ │ │ └── MixinMinecraftClient.java │ │ ├── leaves │ │ ├── MixinClientPacketListener.java │ │ └── MixinClientboundCustomPayloadPacket.java │ │ ├── minecraft │ │ └── lavaRiptide │ │ │ └── MixinTridentItem.java │ │ └── minihud │ │ └── msptSyncProtocol │ │ └── MixinDataStorage.java │ └── resources │ ├── assets │ └── bladeren │ │ └── lang │ │ ├── en_us.json │ │ └── zh_cn.json │ ├── bladeren.mixins.json │ └── fabric.mod.json └── versions ├── 1.20.4 └── gradle.properties └── mainProject /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [ pull_request, push ] 3 | 4 | jobs: 5 | build: 6 | strategy: 7 | matrix: 8 | # Use these Java versions 9 | java: [ 17 ] 10 | # and run on both Linux and Windows 11 | os: [ ubuntu-20.04 ] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: checkout repository 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | - name: validate gradle wrapper 19 | uses: gradle/wrapper-validation-action@v1 20 | - name: setup jdk ${{ matrix.java }} 21 | uses: actions/setup-java@v3 22 | with: 23 | distribution: 'adopt' 24 | java-version: ${{ matrix.java }} 25 | - name: make gradle wrapper executable 26 | if: ${{ runner.os != 'Windows' }} 27 | run: chmod +x ./gradlew 28 | - name: preprocessResources 29 | env: 30 | BUILD_TYPE: "BETA" 31 | run: ./gradlew processResources 32 | - name: build 33 | env: 34 | BUILD_TYPE: "BETA" 35 | run: ./gradlew build 36 | - name: Find correct JAR 37 | id: findjar 38 | if: ${{ runner.os == 'Linux' && matrix.java == '17' }} 39 | run: | 40 | output="$(find fabricWrapper/build/libs/ ! -name "*-dev.jar" ! -name "*-sources.jar" -type f -printf "%f\n")" 41 | echo "jarname=$output" >> $GITHUB_OUTPUT 42 | - name: capture build artifacts 43 | if: ${{ runner.os == 'Linux' && matrix.java == '17' }} 44 | uses: actions/upload-artifact@v3 45 | with: 46 | name: ${{ steps.findjar.outputs.jarname }} 47 | path: | 48 | fabricWrapper/build/libs/*.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | publish/ 6 | out/ 7 | classes/ 8 | 9 | # eclipse 10 | 11 | *.launch 12 | 13 | # idea 14 | 15 | .idea/ 16 | *.iml 17 | *.ipr 18 | *.iws 19 | 20 | # vscode 21 | 22 | .settings/ 23 | .vscode/ 24 | bin/ 25 | .classpath 26 | .project 27 | 28 | # fabric 29 | 30 | run/ 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bladeren 2 | 3 | [![License](https://img.shields.io/github/license/LeavesMC/Bladeren?style=flat-square)](https://github.com/LeavesMC/Bladeren/blob/master/LICENSE) 4 | [![CI](https://img.shields.io/github/actions/workflow/status/LeavesMC/Bladeren/build.yml?label=Build&style=flat-square)](https://github.com/LeavesMC/Bladeren/actions/workflows/build.yml) 5 | 6 | **English** | [中文](./README_cn.md) 7 | 8 | ❗Before reporting a problem, be sure to try the latest [beta version](https://github.com/LeavesMC/Bladeren/actions) of Bladeren to check if the problem still exists. 9 | 10 | Adds some features and supports Leaves extra protocol. 11 | 12 | The default hotkey to open the in-game config GUI is **N + C**. 13 | 14 | ## Dependencies 15 | 16 | | Dependency | Type | Download | 17 | |------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------| 18 | | Fabric-API | Required | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/fabric-api) | [Github](https://github.com/FabricMC/fabric) | 19 | | Magiclib | Required | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/magiclib) | [Github](https://github.com/Hendrix-Shen/Magiclib) | 20 | | MaliLib | Required | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/malilib) | [Masa WebSite](https://masa.dy.fi/mcmods/client_mods/?mod=malilib) | 21 | | MiniHUD | Optional | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/minihud) | [Masa WebSite](https://masa.dy.fi/mcmods/client_mods/?mod=minihud) | 22 | 23 | 24 | ## Thanks 25 | 26 | Thanks [Magiclib](https://github.com/Hendrix-Shen/Magiclib). 27 | -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # Bladeren 2 | 3 | [![License](https://img.shields.io/github/license/LeavesMC/Bladeren?style=flat-square)](https://github.com/LeavesMC/Bladeren/blob/master/LICENSE) 4 | [![CI](https://img.shields.io/github/actions/workflow/status/LeavesMC/Bladeren/build.yml?label=Build&style=flat-square)](https://github.com/LeavesMC/Bladeren/actions/workflows/build.yml) 5 | 6 | [English](./README.md) | **中文** 7 | 8 | ❗在报告问题前请务必尝试最新 [测试版](https://github.com/LeavesMC/Bladeren/actions) ,在确定问题依然存在后再进行报告。 9 | 10 | 添加了一些特效和对Leaves的额外协议支持。 11 | 12 | 默认使用 **N + C** 来打开设置界面。 13 | 14 | ## 依赖项 15 | 16 | | 依赖 | 类型 | 下载 | 17 | |------------|----|----------------------------------------------------------------------------------------------------------------------------------------------| 18 | | Fabric-API | 必须 | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/fabric-api) | [Github](https://github.com/FabricMC/fabric) | 19 | | Magiclib | 必须 | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/magiclib) | [Github](https://github.com/Hendrix-Shen/Magiclib) | 20 | | MaliLib | 必须 | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/malilib) | [Masa WebSite](https://masa.dy.fi/mcmods/client_mods/?mod=malilib) | 21 | | MiniHUD | 可选 | [CurseForge](https://www.curseforge.com/minecraft/mc-mods/minihud) | [Masa WebSite](https://masa.dy.fi/mcmods/client_mods/?mod=minihud) | 22 | 23 | 24 | ## 感谢 25 | 26 | 感谢 [Magiclib](https://github.com/Hendrix-Shen/Magiclib) 提供的前置支持。 27 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("fabric-loom").version("1.3-SNAPSHOT").apply(false) 3 | id("io.github.juuxel.loom-vineflower").version("1.11.0").apply(false) 4 | id("net.kyori.blossom").version("1.3.1").apply(false) 5 | id("org.ajoberstar.grgit").version("5.2.0") 6 | id("maven-publish") 7 | id("com.replaymod.preprocess").version("SNAPSHOT") 8 | } 9 | 10 | preprocess { 11 | def mc1204 = createNode("1.20.4", 1_20_04, "mojang") // root 12 | } 13 | 14 | ext { 15 | def environmentMap = System.getenv() 16 | 17 | getVersionGit = { List paths -> 18 | if (grgit == null) { 19 | return "nogit" 20 | } 21 | 22 | List latestCommits = paths.isEmpty() ? grgit.log(maxCommits: 1) : grgit.log(paths: paths, maxCommits: 1) 23 | return latestCommits.isEmpty() ? "uncommited" : "${latestCommits.get(0).id.substring(0, 7)}" 24 | } 25 | 26 | getBuildNumber = { 27 | return environmentMap.GITHUB_RUN_NUMBER ? environmentMap.GITHUB_RUN_NUMBER : Integer.MAX_VALUE 28 | } 29 | 30 | getVersionType = { 31 | switch (environmentMap.BUILD_TYPE) { 32 | case "RELEASE": 33 | return "stable" 34 | case "BETA": 35 | return "beta" 36 | default: 37 | return "dev" 38 | } 39 | } 40 | 41 | getVersionPatch = { List paths -> 42 | if (grgit == null) { 43 | return 0 44 | } 45 | 46 | List latestCommits = paths.isEmpty() ? grgit.log() : grgit.log(paths: paths) 47 | return latestCommits.size() 48 | } 49 | 50 | getMavenArtifactVersion = { 51 | return ext.getVersionType() == "stable" ? "${project.mod_version}.${ext.getVersionPatch([])}" : project.version 52 | } 53 | } 54 | 55 | setVersion("${project.mod_version}.${project.getVersionPatch([])}+${project.getVersionGit([])}-${project.getVersionType()}") 56 | 57 | tasks.register("cleanPreprocessSources") { 58 | it.group("${project.mod_id}") 59 | 60 | doFirst { 61 | subprojects { 62 | def path = project.projectDir.toPath().resolve("build/preprocessed") 63 | path.toFile().deleteDir() 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /common.gradle: -------------------------------------------------------------------------------- 1 | apply(plugin: "fabric-loom") 2 | apply(plugin: "io.github.juuxel.loom-vineflower") 3 | apply(plugin: "maven-publish") 4 | apply(plugin: "net.kyori.blossom") 5 | apply(plugin: "com.replaymod.preprocess") 6 | 7 | repositories { 8 | mavenLocal() 9 | 10 | maven { 11 | name("Curse Maven") 12 | url("https://www.cursemaven.com") 13 | 14 | content { 15 | includeGroup("curse.maven") 16 | } 17 | } 18 | 19 | maven { 20 | name("Modrinth Maven") 21 | url("https://api.modrinth.com/maven") 22 | 23 | content { 24 | includeGroup("maven.modrinth") 25 | } 26 | } 27 | 28 | maven { 29 | name("Jitpack Maven") 30 | url("https://jitpack.io") 31 | 32 | content { 33 | includeGroup("com.github.Nyan-Work") 34 | } 35 | } 36 | 37 | mavenCentral() 38 | } 39 | 40 | int mcVersion = 1 41 | 42 | preprocess { 43 | mcVersion = vars.get().get("MC") 44 | tabIndentation.set(false) 45 | } 46 | 47 | // Module, Property prefix, Resolve condition, Transitive dependencies. 48 | def apiDependencies = [ 49 | ["curse.maven:minihud-244260", "minihud", true, false], 50 | ["curse.maven:litematica-308892", "litematica", true, false], 51 | ["maven.modrinth:client-commands", "clientcommands", true, true], 52 | ] 53 | 54 | // Module, Property prefix, Resolve condition, Transitive dependencies. 55 | def compileOnlyDependencies = [ 56 | ["curse.maven:minihud-244260", "minihud", true, false], 57 | ["curse.maven:litematica-308892", "litematica", true, false], 58 | ["maven.modrinth:client-commands", "clientcommands", true, true], 59 | ] 60 | 61 | dependencies { 62 | // Development environment 63 | minecraft("com.mojang:minecraft:${project.minecraft_version}") 64 | mappings(loom.officialMojangMappings()) 65 | 66 | // Annotation processor 67 | modCompileOnly("org.projectlombok:lombok:${project.lombok_version}") 68 | annotationProcessor("org.projectlombok:lombok:${project.lombok_version}") 69 | 70 | // Dependency 71 | modImplementation("top.hendrixshen.magiclib:magiclib-${project.minecraft_version.replace(".", "_")}:${project.magiclib_version}") { 72 | exclude(group: "carpet", module: "fabric-carpet") 73 | } 74 | 75 | // API 76 | apiDependencies.forEach { item -> 77 | String dependencyNotation = item[0] 78 | String propertyPrefix = item[1] 79 | boolean shouldResolve = item[2] 80 | boolean shouldTransitive = item[3] 81 | 82 | if (shouldResolve) { 83 | modApi("${dependencyNotation}:${project.property("${propertyPrefix}_version")}") { 84 | transitive(shouldTransitive) 85 | } 86 | } 87 | } 88 | 89 | // Compile only library. 90 | compileOnlyDependencies.forEach { item -> 91 | String dependencyNotation = item[0] 92 | String propertyPrefix = item[1] 93 | boolean shouldResolve = item[2] 94 | boolean shouldTransitive = item[3] 95 | 96 | if (shouldResolve) { 97 | modCompileOnly("${dependencyNotation}:${project.property("${propertyPrefix}_version")}") { 98 | transitive(shouldTransitive) 99 | } 100 | } 101 | } 102 | 103 | // Misc 104 | runtimeOnly(project(path: ":fabricWrapper")) 105 | } 106 | 107 | group(project.mod_maven_group) 108 | version(project.parent.version) 109 | 110 | base { 111 | archivesBaseName("${project.mod_archives_base_name}-${project.minecraft_version}") 112 | } 113 | 114 | loom { 115 | interfaceInjection { 116 | enableDependencyInterfaceInjection.set(true) 117 | } 118 | 119 | runConfigs.configureEach { 120 | // Dump modified classes automatically. 121 | property("mixin.debug.export", "true") 122 | } 123 | 124 | runConfigs.named("client") { 125 | runDir("run/client") 126 | } 127 | 128 | runConfigs.named("server") { 129 | runDir("run/server") 130 | } 131 | 132 | runs { 133 | mixinAuditClient { 134 | inherit(client) 135 | vmArgs("-Dmagiclib.mixin_audit=true") 136 | ideConfigGenerated(false) 137 | runDir("run/client") 138 | } 139 | 140 | mixinAuditServer { 141 | inherit(server) 142 | vmArgs("-Dmagiclib.mixin_audit=true") 143 | ideConfigGenerated(false) 144 | runDir("run/server") 145 | } 146 | } 147 | 148 | // Setup client default settings. 149 | runClient { 150 | defaultCharacterEncoding("UTF-8") 151 | 152 | if (!new File("${projectDir}/run/client/options.txt").exists()) { 153 | new File("${projectDir}/run/client").mkdirs() 154 | BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("${projectDir}/run/client/options.txt")) 155 | bufferedWriter.writeLine("autoJump:false") 156 | bufferedWriter.writeLine("enableVsync:false") 157 | bufferedWriter.writeLine("forceUnicodeFont:true") 158 | bufferedWriter.writeLine("fov:1.0") 159 | bufferedWriter.writeLine("gamma:16.0") 160 | bufferedWriter.writeLine("guiScale:3") 161 | bufferedWriter.writeLine("lang:${Locale.getDefault().toString()}") 162 | bufferedWriter.writeLine("maxFps:260") 163 | bufferedWriter.writeLine("renderDistance:10") 164 | bufferedWriter.writeLine("soundCategory_master:0.0") 165 | bufferedWriter.close() 166 | } 167 | } 168 | 169 | // Setup server default settings. 170 | runServer { 171 | defaultCharacterEncoding("UTF-8") 172 | 173 | // Agree eula before server init. 174 | if (!new File("${projectDir}/run/server/eula.txt").exists()) { 175 | new File("${projectDir}/run/server").mkdirs() 176 | BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("${projectDir}/run/server/eula.txt")) 177 | bufferedWriter.writeLine("eula=true") 178 | bufferedWriter.close() 179 | } 180 | } 181 | } 182 | 183 | tasks.findAll { 184 | it.name in [ 185 | "runClient", "runServer", 186 | "runMixinAuditClient", "runMixinAuditServer", 187 | "preprocessCode", "preprocessResources", 188 | "preprocessTestCode", "preprocessTestResources"] 189 | }.forEach { 190 | it.group("${project.mod_id}") 191 | } 192 | 193 | tasks.withType(JavaCompile).configureEach { 194 | options.setEncoding("UTF-8") 195 | } 196 | 197 | remapJar { 198 | remapperIsolation.set(false) 199 | } 200 | 201 | processResources { 202 | outputs.upToDateWhen { false } 203 | 204 | from("${rootDir}/icon.png") { 205 | into("assets/${project.mod_id}") 206 | } 207 | 208 | filesMatching("fabric.mod.json") { 209 | filter { line -> 210 | line.trim().startsWith("//") ? "" : line 211 | } 212 | 213 | expand([ 214 | "magiclib_dependency" : project.magiclib_dependency, 215 | "minecraft_dependency": project.minecraft_dependency, 216 | "minecraft_version_id": project.minecraft_version.replace(".", "_"), 217 | "minecraft_version" : project.minecraft_version, 218 | "mod_description" : project.mod_description, 219 | "mod_homepage" : project.mod_homepage, 220 | "mod_id" : project.mod_id, 221 | "mod_license" : project.mod_license, 222 | "mod_name" : project.mod_name, 223 | "mod_sources" : project.mod_sources, 224 | "mod_version" : project.version 225 | ]) 226 | } 227 | } 228 | 229 | blossom { 230 | replaceToken("@MOD_IDENTIFIER@", project.mod_id) 231 | replaceToken("@MOD_NAME@", project.mod_name) 232 | replaceToken("@MINECRAFT_VERSION_IDENTIFY@", project.minecraft_version.replace(".", "_")) 233 | } 234 | 235 | java { 236 | sourceCompatibility(JavaVersion.VERSION_17) 237 | targetCompatibility(JavaVersion.VERSION_17) 238 | withSourcesJar() 239 | } 240 | 241 | jar { 242 | from("${rootDir}/LICENSE") 243 | } 244 | 245 | publishing { 246 | publications { 247 | create("mavenJava", MavenPublication) { 248 | artifactId("${project.mod_id}-${project.minecraft_version.replace(".", "_")}") 249 | version("${rootProject.getMavenArtifactVersion()}") 250 | from(components.java) 251 | } 252 | } 253 | 254 | repositories { 255 | mavenLocal() 256 | 257 | maven { 258 | url("$rootDir/publish") 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /fabricWrapper/build.gradle: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonBuilder 2 | 3 | plugins { 4 | id("java-library") 5 | id("maven-publish") 6 | } 7 | 8 | group(project.mod_maven_group) 9 | version(project.parent.version) 10 | 11 | base { 12 | archivesBaseName("${project.mod_archives_base_name}-all") 13 | } 14 | 15 | def fabric_subprojects = project.parent.subprojects.findAll({ 16 | it.name != "fabricWrapper" 17 | }) 18 | 19 | fabric_subprojects.collect { 20 | evaluationDependsOn(":${it.name}") 21 | } 22 | 23 | jar { 24 | // disable cache 25 | outputs.upToDateWhen { false } 26 | 27 | dependsOn(fabric_subprojects.collect { 28 | it.tasks.remapJar 29 | }) 30 | 31 | doFirst { 32 | delete fileTree("build/tmp/submods/META-INF/jars") 33 | 34 | copy { 35 | from { 36 | fabric_subprojects.collect { 37 | it.remapJar.outputs.files 38 | } 39 | } 40 | 41 | into("build/tmp/submods/META-INF/jars") 42 | } 43 | } 44 | 45 | from("../LICENSE") 46 | from("build/tmp/submods") 47 | } 48 | 49 | processResources { 50 | // disable cache 51 | outputs.upToDateWhen { false } 52 | ArrayList mc_condition = [] 53 | ArrayList jars = [] 54 | 55 | fabric_subprojects.each({ 56 | mc_condition.add("${it.minecraft_dependency}") 57 | jars.add(["file": "META-INF/jars/${project.mod_archives_base_name}-${it.minecraft_version}-${project.version}.jar"]) 58 | }) 59 | 60 | from("${rootDir}/icon.png") { 61 | into("assets/${project.mod_id}") 62 | } 63 | 64 | filesMatching("fabric.mod.json") { 65 | expand([ 66 | "minecraft_dependency": new JsonBuilder(mc_condition), 67 | "magiclib_dependency" : project.magiclib_dependency, 68 | "mod_description" : project.mod_description, 69 | "mod_homepage" : project.mod_homepage, 70 | "mod_id" : project.mod_id, 71 | "mod_license" : project.mod_license, 72 | "mod_name" : project.mod_name, 73 | "mod_version" : project.version, 74 | "mod_sources" : project.mod_sources, 75 | "sub_jars" : new JsonBuilder(jars).toPrettyString(), 76 | ]) 77 | } 78 | } 79 | 80 | java { 81 | sourceCompatibility(JavaVersion.VERSION_1_8) 82 | targetCompatibility(JavaVersion.VERSION_1_8) 83 | } 84 | 85 | publishing { 86 | publications { 87 | register("mavenJava", MavenPublication) { 88 | artifactId("${project.mod_id}") 89 | version("${rootProject.getMavenArtifactVersion()}") 90 | from(components.java) 91 | } 92 | } 93 | 94 | repositories { 95 | mavenLocal() 96 | 97 | maven { 98 | url("$rootDir/publish") 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /fabricWrapper/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}", 4 | "version": "${mod_version}", 5 | "icon": "assets/${mod_id}/icon.png", 6 | "name": "${mod_name}", 7 | "description": "${mod_description}", 8 | "authors": [ 9 | { 10 | "name": "LeavesMC", 11 | "contact": { 12 | "homepage": "https://github.com/LeavesMC" 13 | } 14 | } 15 | ], 16 | "contact": { 17 | "homepage": "${mod_homepage}", 18 | "issues": "${mod_sources}/issues", 19 | "sources": "${mod_sources}" 20 | }, 21 | "license": "${mod_license}", 22 | "environment": "client", 23 | "entrypoints": { 24 | "modmenu": [ 25 | "top.leavesmc.Bladeren.compat.modmenu.WrapperModMenuApiImpl" 26 | ] 27 | }, 28 | "depends": { 29 | "magiclib": ">=${magiclib_dependency}", 30 | "minecraft": ${minecraft_dependency}, 31 | "malilib": "*" 32 | }, 33 | "custom": { 34 | "modmenu:clientsideOnly": true 35 | }, 36 | "jars": ${sub_jars} 37 | } 38 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Gradle properties 2 | org.gradle.cache.cleanup=false 3 | org.gradle.jvmargs=-Xmx6G 4 | org.gradle.parallel=true 5 | 6 | # Mod Properties 7 | mod_archives_base_name=Bladeren 8 | mod_id=bladeren 9 | mod_description=Leaves client additions. 10 | mod_maven_group=top.leavesmc 11 | mod_name=Bladeren 12 | mod_homepage=https://github.com/LeavesMC/Bladeren 13 | mod_sources=https://github.com/LeavesMC/Bladeren 14 | mod_version=1.1 15 | mod_license=LGPL-3.0 16 | 17 | # Required Libraries 18 | # MagicLib - 0.7.345 19 | magiclib_dependency=0.7.398 20 | magiclib_version=0.7.398 21 | 22 | # Annotation processor 23 | lombok_version=1.18.30 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeavesMC/Bladeren/65d18040d23dfc8c0d2f7663ceca88ad4e0e583a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeavesMC/Bladeren/65d18040d23dfc8c0d2f7663ceca88ad4e0e583a/icon.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | 5 | maven { 6 | name("Fabric") 7 | url("https://maven.fabricmc.net") 8 | } 9 | 10 | maven { 11 | name("Jitpack") 12 | url("https://jitpack.io") 13 | } 14 | 15 | maven { 16 | name("Nyan Maven") 17 | url("https://maven.hendrixshen.top") 18 | } 19 | 20 | maven { 21 | name("Cotton") 22 | url("https://server.bbkr.space/artifactory/libs-release") 23 | } 24 | 25 | mavenCentral() 26 | gradlePluginPortal() 27 | } 28 | } 29 | 30 | def versions = Arrays.asList( 31 | "1.20.4" 32 | ) 33 | 34 | for (String version : versions) { 35 | include(":$version") 36 | def proj = project(":$version") 37 | proj.projectDir = file("versions/$version") 38 | proj.buildFileName = "../../common.gradle" 39 | } 40 | 41 | include(":fabricWrapper") 42 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/BladerenMod.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren; 2 | 3 | import net.fabricmc.api.ClientModInitializer; 4 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 5 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 6 | import top.hendrixshen.magiclib.malilib.impl.ConfigHandler; 7 | import top.hendrixshen.magiclib.malilib.impl.ConfigManager; 8 | import top.leavesmc.Bladeren.config.Configs; 9 | import top.leavesmc.Bladeren.leaves.LeavesProtocol; 10 | 11 | public class BladerenMod implements ClientModInitializer { 12 | private static final int CONFIG_VERSION = 1; 13 | 14 | @Dependencies(and = { 15 | @Dependency(value = ModInfo.MINIHUD_MOD_ID, versionPredicate = ">=0.22.0", optional = true), 16 | @Dependency(value = ModInfo.CLIENTCOMMANDS_MOD_ID, versionPredicate = ">=2.8.2", optional = true), 17 | }) 18 | @Override 19 | public void onInitializeClient() { 20 | ConfigManager cm = ConfigManager.get(ModInfo.MOD_ID); 21 | cm.parseConfigClass(Configs.class); 22 | ModInfo.configHandler = new ConfigHandler(ModInfo.MOD_ID, cm, CONFIG_VERSION); 23 | ConfigHandler.register(ModInfo.configHandler); 24 | Configs.init(cm); 25 | 26 | LeavesProtocol.init(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/ModInfo.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren; 2 | 3 | import net.fabricmc.loader.api.FabricLoader; 4 | import net.minecraft.resources.ResourceLocation; 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | import org.jetbrains.annotations.Contract; 8 | import org.jetbrains.annotations.NotNull; 9 | import top.hendrixshen.magiclib.compat.minecraft.api.network.chat.ComponentCompatApi; 10 | import top.hendrixshen.magiclib.malilib.impl.ConfigHandler; 11 | import top.hendrixshen.magiclib.language.api.I18n; 12 | 13 | import net.minecraft.network.chat.MutableComponent; 14 | 15 | public class ModInfo { 16 | public static final String MINIHUD_MOD_ID = "minihud"; 17 | public static final String CLIENTCOMMANDS_MOD_ID = "clientcommands"; 18 | public static String MOD_ID = "@MOD_IDENTIFIER@"; 19 | public static final String CURRENT_MOD_ID = "@MOD_IDENTIFIER@-@MINECRAFT_VERSION_IDENTIFY@"; 20 | public static final String MOD_NAME = FabricLoader.getInstance().getModContainer(CURRENT_MOD_ID).orElseThrow(RuntimeException::new).getMetadata().getName(); 21 | public static final String MOD_VERSION = FabricLoader.getInstance().getModContainer(CURRENT_MOD_ID).orElseThrow(RuntimeException::new).getMetadata().getVersion().getFriendlyString(); 22 | public static final Logger LOGGER = LogManager.getLogger(MOD_ID); 23 | public static ConfigHandler configHandler; 24 | 25 | public static String translate(String key, Object... objects) { 26 | return I18n.get(ModInfo.MOD_ID + "." + key, objects); 27 | } 28 | 29 | public static @NotNull MutableComponent translatable(String key, Object... objects) { 30 | return ComponentCompatApi.translatable(ModInfo.MOD_ID + "." + key, objects); 31 | } 32 | 33 | @Contract("_ -> new") 34 | public static @NotNull ResourceLocation id(String path) { 35 | return new ResourceLocation(MOD_ID, path); 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/clientcommands/RandomManager.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.clientcommands; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import lombok.Setter; 5 | import net.earthcomputer.clientcommands.command.FishCommand; 6 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; 7 | import net.minecraft.client.player.LocalPlayer; 8 | import net.minecraft.commands.CommandBuildContext; 9 | import net.minecraft.nbt.CompoundTag; 10 | import net.minecraft.resources.ResourceLocation; 11 | import top.leavesmc.Bladeren.ModInfo; 12 | import top.leavesmc.Bladeren.config.Configs; 13 | import top.leavesmc.Bladeren.leaves.LeavesProtocol; 14 | 15 | public class RandomManager { 16 | 17 | @Setter 18 | private static CommandDispatcher savedDispatcher; 19 | @Setter 20 | private static CommandBuildContext savedRegistryAccess; 21 | 22 | private static final String RNG_FISHING = "rng_fishing"; 23 | private static final String VANILLA_RANDOM = "use_vanilla_random"; 24 | 25 | public static final ResourceLocation RNG_FISHING_ID = ModInfo.id("fishing_loot_seed"); 26 | 27 | public static long fishingLootSeed = 0L; 28 | 29 | public static void init() { 30 | LeavesProtocol.registerHelloEndTask(RandomManager::onHelloEnd); 31 | LeavesProtocol.registerFeatureHandler(RNG_FISHING, RandomManager::enableRNGFishing); 32 | } 33 | 34 | private static void enableRNGFishing(LocalPlayer player, CompoundTag tag) { 35 | if (tag.getString("Value").equals("true")) { 36 | CompoundTag data = new CompoundTag(); 37 | data.putString("Value", Boolean.toString(Configs.fishCommand)); 38 | LeavesProtocol.addFeatureBackData(RNG_FISHING, data); 39 | } 40 | } 41 | 42 | private static void onHelloEnd() { 43 | if (Configs.fishCommand) { 44 | FishCommand.register(savedDispatcher, savedRegistryAccess); 45 | } 46 | } 47 | 48 | public static boolean isVanillaRandom() { 49 | return LeavesProtocol.isFeatureEnable(VANILLA_RANDOM); 50 | } 51 | 52 | public static boolean isFishCommand() { 53 | return isVanillaRandom() && LeavesProtocol.isFeatureEnable(RNG_FISHING); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/compat/modmenu/ModMenuApiImpl.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.compat.modmenu; 2 | 3 | import top.leavesmc.Bladeren.ModInfo; 4 | import top.leavesmc.Bladeren.gui.GuiConfigs; 5 | import top.hendrixshen.magiclib.compat.modmenu.ModMenuCompatApi; 6 | 7 | public class ModMenuApiImpl implements ModMenuCompatApi { 8 | @Override 9 | public ConfigScreenFactoryCompat getConfigScreenFactoryCompat() { 10 | return (screen) -> { 11 | GuiConfigs gui = GuiConfigs.getInstance(); 12 | gui.setParent(screen); 13 | return gui; 14 | }; 15 | } 16 | 17 | @Override 18 | public String getModIdCompat() { 19 | return ModInfo.CURRENT_MOD_ID; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/compat/modmenu/WrapperModMenuApiImpl.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.compat.modmenu; 2 | 3 | import top.leavesmc.Bladeren.ModInfo; 4 | 5 | public class WrapperModMenuApiImpl extends ModMenuApiImpl { 6 | @Override 7 | public String getModIdCompat() { 8 | return ModInfo.MOD_ID; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/config/Configs.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.config; 2 | 3 | import fi.dy.masa.malilib.config.options.ConfigHotkey; 4 | import net.minecraft.client.Minecraft; 5 | import org.apache.logging.log4j.Level; 6 | import org.apache.logging.log4j.core.config.Configurator; 7 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 8 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 9 | import top.hendrixshen.magiclib.malilib.api.annotation.Config; 10 | import top.hendrixshen.magiclib.malilib.api.annotation.Hotkey; 11 | import top.hendrixshen.magiclib.malilib.impl.ConfigManager; 12 | import top.leavesmc.Bladeren.ModInfo; 13 | import top.leavesmc.Bladeren.gui.GuiConfigs; 14 | import top.leavesmc.Bladeren.minihud.msptSyncProtocol.MsptSyncProtocol; 15 | 16 | public class Configs { 17 | // GENERIC 18 | @Config(category = ConfigCategory.GENERIC) 19 | public static boolean debug = false; 20 | 21 | @Hotkey(hotkey = "N,C") 22 | @Config(category = ConfigCategory.GENERIC) 23 | public static ConfigHotkey openConfigGui; 24 | 25 | // MINECRAFT 26 | @Config(category = ConfigCategory.MINECRAFT) 27 | public static boolean lavaRiptide = false; 28 | 29 | // MINIHUD 30 | @Config(category = ConfigCategory.MINIHUD, dependencies = @Dependencies(and = @Dependency(ModInfo.MINIHUD_MOD_ID))) 31 | public static boolean msptSyncProtocol = true; 32 | 33 | @Config(category = ConfigCategory.CLIENTCOMMANDS, dependencies = @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID))) 34 | public static boolean fishCommand = true; 35 | @Config(category = ConfigCategory.CLIENTCOMMANDS, dependencies = @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID))) 36 | public static boolean disableNotVanillaWarn = true; 37 | 38 | public static void init(ConfigManager cm) { 39 | // GENERIC 40 | cm.setValueChangeCallback("debug", option -> { 41 | if (debug) { 42 | Configurator.setLevel(ModInfo.MOD_ID, Level.toLevel("DEBUG")); 43 | } else { 44 | Configurator.setLevel(ModInfo.MOD_ID, Level.toLevel("INFO")); 45 | } 46 | GuiConfigs.getInstance().reDraw(); 47 | }); 48 | if (debug) { 49 | Configurator.setLevel(ModInfo.MOD_ID, Level.toLevel("DEBUG")); 50 | } 51 | 52 | openConfigGui.getKeybind().setCallback((keyAction, iKeybind) -> { 53 | GuiConfigs screen = GuiConfigs.getInstance(); 54 | screen.setParent(Minecraft.getInstance().screen); 55 | Minecraft.getInstance().setScreen(screen); 56 | return true; 57 | }); 58 | 59 | // MINIHUD 60 | cm.setValueChangeCallback("msptSyncProtocol", option -> { 61 | MsptSyncProtocol.modifyStatus(); 62 | }); 63 | } 64 | 65 | public static class ConfigCategory { 66 | public static final String GENERIC = "generic"; 67 | public static final String MINECRAFT = "minecraft"; 68 | public static final String MINIHUD = "minihud"; 69 | public static final String CLIENTCOMMANDS = "clientcommands"; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/event/DisconnectEvent.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DisconnectEvent { 7 | 8 | private static final List funList = new ArrayList<>(); 9 | 10 | public static void register(Disconnect fun) { 11 | funList.add(fun); 12 | } 13 | 14 | public static void onDisconnect() { 15 | for (Disconnect fun : funList) { 16 | fun.onPlayDisconnect(); 17 | } 18 | } 19 | 20 | @FunctionalInterface 21 | public interface Disconnect { 22 | void onPlayDisconnect(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/gui/GuiConfigs.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.gui; 2 | 3 | import top.leavesmc.Bladeren.ModInfo; 4 | import top.leavesmc.Bladeren.config.Configs; 5 | import lombok.Getter; 6 | import top.hendrixshen.magiclib.malilib.impl.ConfigManager; 7 | import top.hendrixshen.magiclib.malilib.impl.gui.ConfigGui; 8 | 9 | public class GuiConfigs extends ConfigGui { 10 | 11 | @Getter(lazy = true) 12 | private static final GuiConfigs instance = new GuiConfigs(ModInfo.MOD_ID, Configs.ConfigCategory.GENERIC, ConfigManager.get(ModInfo.MOD_ID)); 13 | 14 | private GuiConfigs(String identifier, String defaultTab, ConfigManager configManager) { 15 | super(identifier, defaultTab, configManager, () -> ModInfo.translate("gui.title.configs", ModInfo.MOD_VERSION)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/leaves/LeavesPayload.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.leaves; 2 | 3 | import net.minecraft.network.FriendlyByteBuf; 4 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | public record LeavesPayload(FriendlyByteBuf byteBuf, ResourceLocation id) implements CustomPacketPayload { 8 | public LeavesPayload(ResourceLocation identifier, FriendlyByteBuf input) { 9 | this(new FriendlyByteBuf(input.readBytes(input.readableBytes())), identifier); 10 | } 11 | 12 | @Override 13 | public void write(FriendlyByteBuf buf) { 14 | buf.writeBytes(byteBuf); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/leaves/LeavesProtocol.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.leaves; 2 | 3 | import io.netty.buffer.Unpooled; 4 | import lombok.Getter; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.client.player.LocalPlayer; 7 | import net.minecraft.nbt.CompoundTag; 8 | import net.minecraft.network.FriendlyByteBuf; 9 | import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; 10 | import net.minecraft.resources.ResourceLocation; 11 | import top.leavesmc.Bladeren.ModInfo; 12 | import top.leavesmc.Bladeren.event.DisconnectEvent; 13 | 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.function.BiConsumer; 19 | 20 | public class LeavesProtocol { 21 | 22 | public static final ResourceLocation HELLO_ID = ModInfo.id("hello"); 23 | public static final ResourceLocation FEATURE_MODIFY_ID = ModInfo.id("feature_modify"); 24 | 25 | private static final Map> dataHandlers = new HashMap<>(); 26 | private static final Map> featureHandlers = new HashMap<>(); 27 | private static final Map featureBackData = new HashMap<>(); 28 | private static final Map featureData = new HashMap<>(); 29 | private static final List helloEndTasks = new ArrayList<>(); 30 | 31 | private static LocalPlayer localPlayer = null; 32 | @Getter 33 | private static boolean isLeavesServer = false; 34 | 35 | public static void init() { 36 | DisconnectEvent.register(LeavesProtocol::onDisconnect); 37 | dataHandlers.put(HELLO_ID, LeavesProtocol::handleHello); 38 | } 39 | 40 | public static void handleHello(LocalPlayer player, FriendlyByteBuf data) { 41 | String serverVersion = data.readUtf(64); 42 | CompoundTag tag = data.readNbt(); 43 | 44 | isLeavesServer = true; 45 | 46 | if (tag != null) { 47 | CompoundTag featureNbt = tag.getCompound("Features"); 48 | for (String name : featureNbt.getAllKeys()) { 49 | if (featureHandlers.containsKey(name)) { 50 | featureHandlers.get(name).accept(localPlayer, featureNbt.getCompound(name)); 51 | } 52 | featureData.put(name, featureNbt.getCompound(name).getString("Value")); 53 | } 54 | } 55 | 56 | FriendlyByteBuf backData = new FriendlyByteBuf(Unpooled.buffer()); 57 | backData.writeUtf(ModInfo.MOD_VERSION); 58 | 59 | CompoundTag backTag = new CompoundTag(); 60 | 61 | CompoundTag backFeatureNbt = new CompoundTag(); 62 | for (String name : featureBackData.keySet()) { 63 | backFeatureNbt.put(name, featureBackData.get(name)); 64 | } 65 | featureBackData.clear(); 66 | backTag.put("Features", backFeatureNbt); 67 | 68 | backData.writeNbt(backTag); 69 | 70 | helloEndTasks.forEach(Runnable::run); 71 | 72 | sendPacket(HELLO_ID, backData); 73 | } 74 | 75 | public static void onPayload(LeavesPayload payload) { 76 | if (dataHandlers.containsKey(payload.id())) { 77 | dataHandlers.get(payload.id()).accept(localPlayer, payload.byteBuf()); 78 | } 79 | } 80 | 81 | public static String getFeatureData(String name) { 82 | return featureData.getOrDefault(name, "null"); 83 | } 84 | 85 | public static boolean isFeatureEnableOrLocal(String name) { 86 | return Minecraft.getInstance().isLocalServer() || isFeatureEnable(name); 87 | } 88 | 89 | public static boolean isFeatureEnable(String name) { 90 | return isLeavesServer && featureData.getOrDefault(name, "false").equals("true"); 91 | } 92 | 93 | public static void registerDataHandler(ResourceLocation id, BiConsumer handler) { 94 | dataHandlers.put(id, handler); 95 | } 96 | 97 | public static void registerFeatureHandler(String id, BiConsumer handler) { 98 | featureHandlers.put(id, handler); 99 | } 100 | 101 | public static void registerHelloEndTask(Runnable task) { 102 | helloEndTasks.add(task); 103 | } 104 | 105 | public static void addFeatureBackData(String id, CompoundTag tag) { 106 | featureBackData.put(id, tag); 107 | } 108 | 109 | public static LocalPlayer getPlayer() { 110 | return localPlayer; 111 | } 112 | 113 | public static void sendPacket(ResourceLocation id, FriendlyByteBuf data) { 114 | localPlayer.connection.send(new ServerboundCustomPayloadPacket(new LeavesPayload(id, data))); 115 | } 116 | 117 | public static void sendFeatureModify(String name, CompoundTag tag) { 118 | sendPacket(FEATURE_MODIFY_ID, new FriendlyByteBuf(Unpooled.buffer()).writeUtf(name).writeNbt(tag)); 119 | } 120 | 121 | public static void gameJoined(LocalPlayer player) { 122 | localPlayer = player; 123 | } 124 | 125 | private static void onDisconnect() { 126 | localPlayer = null; 127 | isLeavesServer = false; 128 | featureData.clear(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/minihud/msptSyncProtocol/MsptSyncProtocol.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.minihud.msptSyncProtocol; 2 | 3 | import fi.dy.masa.minihud.util.DataStorage; 4 | import net.minecraft.client.player.LocalPlayer; 5 | import net.minecraft.nbt.CompoundTag; 6 | import net.minecraft.network.FriendlyByteBuf; 7 | import net.minecraft.resources.ResourceLocation; 8 | import top.leavesmc.Bladeren.ModInfo; 9 | import top.leavesmc.Bladeren.config.Configs; 10 | import top.leavesmc.Bladeren.leaves.LeavesProtocol; 11 | import top.leavesmc.Bladeren.mixin.accessor.AccessorDataStorage; 12 | 13 | public class MsptSyncProtocol { 14 | 15 | private static final String MSPT_SYNC_NAME = "mspt_sync"; 16 | private static final ResourceLocation MSPT_SYNC = ModInfo.id(MSPT_SYNC_NAME); 17 | 18 | private static AccessorDataStorage dataStorage; 19 | 20 | public static void init() { 21 | LeavesProtocol.registerDataHandler(MSPT_SYNC, MsptSyncProtocol::updateMspt); 22 | LeavesProtocol.registerFeatureHandler(MSPT_SYNC_NAME, MsptSyncProtocol::enableSync); 23 | } 24 | 25 | private static void enableSync(LocalPlayer player, CompoundTag tag) { 26 | if (tag.getString("Value").equals("true")) { 27 | dataStorage = (AccessorDataStorage) DataStorage.getInstance(); 28 | CompoundTag data = new CompoundTag(); 29 | data.putString("Value", Boolean.toString(Configs.msptSyncProtocol)); 30 | LeavesProtocol.addFeatureBackData(MSPT_SYNC_NAME, data); 31 | } 32 | } 33 | 34 | public static void modifyStatus() { 35 | CompoundTag data = new CompoundTag(); 36 | data.putString("Value", Boolean.toString(Configs.msptSyncProtocol)); 37 | LeavesProtocol.sendFeatureModify(MSPT_SYNC_NAME, data); 38 | 39 | if (!Configs.msptSyncProtocol) { 40 | dataStorage.setServerTPSValid(false); 41 | dataStorage.setCarpetServer(false); 42 | } else { 43 | dataStorage = (AccessorDataStorage) DataStorage.getInstance(); 44 | } 45 | } 46 | 47 | private static void updateMspt(LocalPlayer player, FriendlyByteBuf buf) { 48 | if (Configs.msptSyncProtocol) { 49 | dataStorage.setServerMSPT(buf.readDouble()); 50 | dataStorage.setServerTPS(buf.readDouble()); 51 | dataStorage.setServerTPSValid(true); 52 | dataStorage.setCarpetServer(true); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/accessor/AccessorDataStorage.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.accessor; 2 | 3 | import fi.dy.masa.minihud.util.DataStorage; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 7 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 8 | import top.leavesmc.Bladeren.ModInfo; 9 | 10 | @Dependencies(and = @Dependency(ModInfo.MINIHUD_MOD_ID)) 11 | @Mixin(value = DataStorage.class, remap = false) 12 | public interface AccessorDataStorage { 13 | 14 | @Accessor 15 | void setCarpetServer(boolean isCarpetServer); 16 | 17 | @Accessor 18 | void setServerTPSValid(boolean isServerTPSValid); 19 | 20 | @Accessor 21 | void setServerTPS(double tps); 22 | 23 | @Accessor 24 | void setServerMSPT(double mspt); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/clientcommands/MixinClientsCommands.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.clientcommands; 2 | 3 | import net.earthcomputer.clientcommands.ClientCommands; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 9 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 10 | import top.leavesmc.Bladeren.ModInfo; 11 | import top.leavesmc.Bladeren.clientcommands.RandomManager; 12 | 13 | @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID)) 14 | @Mixin(ClientCommands.class) 15 | public class MixinClientsCommands { 16 | @Inject(method = "onInitializeClient", at = @At("HEAD"), remap = false) 17 | private void onInit(CallbackInfo ci) { 18 | RandomManager.init(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/clientcommands/disableNotVanillaWarn/MixinServerBrandManager.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.clientcommands.disableNotVanillaWarn; 2 | 3 | import net.earthcomputer.clientcommands.ServerBrandManager; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 9 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 10 | import top.leavesmc.Bladeren.ModInfo; 11 | import top.leavesmc.Bladeren.clientcommands.RandomManager; 12 | import top.leavesmc.Bladeren.config.Configs; 13 | 14 | @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID)) 15 | @Mixin(ServerBrandManager.class) 16 | public abstract class MixinServerBrandManager { 17 | 18 | @Shadow(remap = false) 19 | public static boolean isVanilla() { 20 | return false; 21 | } 22 | 23 | @Redirect( 24 | method = "rngWarning", 25 | at = @At(value = "INVOKE", target = "Lnet/earthcomputer/clientcommands/ServerBrandManager;isVanilla()Z"), 26 | remap = false 27 | ) 28 | private static boolean isVanillaOrLeaves() { 29 | return isVanilla() || (Configs.disableNotVanillaWarn && RandomManager.isVanillaRandom()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/clientcommands/fishCommand/MixinConfigs.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.clientcommands.fishCommand; 2 | 3 | import net.earthcomputer.clientcommands.Configs; 4 | import net.earthcomputer.clientcommands.MultiVersionCompat; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 9 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 10 | import top.leavesmc.Bladeren.ModInfo; 11 | import top.leavesmc.Bladeren.clientcommands.RandomManager; 12 | 13 | @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID)) 14 | @Mixin(Configs.class) 15 | public class MixinConfigs { 16 | 17 | @Redirect( 18 | method = "conditionLessThan1_20", 19 | at = @At(value = "INVOKE", target = "Lnet/earthcomputer/clientcommands/MultiVersionCompat;getProtocolVersion()I"), 20 | remap = false 21 | ) 22 | private static int getProtocolVersion(MultiVersionCompat instance) { 23 | if (top.leavesmc.Bladeren.config.Configs.fishCommand && RandomManager.isFishCommand()) { 24 | return 762; 25 | } else { 26 | return instance.getProtocolVersion(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/clientcommands/fishCommand/MixinFishCommand.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.clientcommands.fishCommand; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import net.earthcomputer.clientcommands.MultiVersionCompat; 5 | import net.earthcomputer.clientcommands.command.FishCommand; 6 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; 7 | import net.minecraft.commands.CommandBuildContext; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 14 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 15 | import top.leavesmc.Bladeren.ModInfo; 16 | import top.leavesmc.Bladeren.clientcommands.RandomManager; 17 | import top.leavesmc.Bladeren.config.Configs; 18 | 19 | @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID)) 20 | @Mixin(FishCommand.class) 21 | public class MixinFishCommand { 22 | 23 | @Inject(method = "register", at = @At("HEAD"), remap = false) 24 | private static void onRegister(CommandDispatcher dispatcher, CommandBuildContext registryAccess, CallbackInfo ci) { 25 | RandomManager.setSavedDispatcher(dispatcher); 26 | RandomManager.setSavedRegistryAccess(registryAccess); 27 | } 28 | 29 | @Redirect( 30 | method = "register", 31 | at = @At(value = "INVOKE", target = "Lnet/earthcomputer/clientcommands/MultiVersionCompat;getProtocolVersion()I"), 32 | remap = false 33 | ) 34 | private static int getProtocolVersion(MultiVersionCompat instance) { 35 | if (Configs.fishCommand && RandomManager.isFishCommand()) { 36 | return 762; 37 | } else { 38 | return instance.getProtocolVersion(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/clientcommands/fishCommand/MixinFishingCracker.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.clientcommands.fishCommand; 2 | 3 | import io.netty.buffer.Unpooled; 4 | import net.earthcomputer.clientcommands.Configs; 5 | import net.earthcomputer.clientcommands.features.FishingCracker; 6 | import net.earthcomputer.clientcommands.mixin.CheckedRandomAccessor; 7 | import net.minecraft.network.FriendlyByteBuf; 8 | import net.minecraft.util.Mth; 9 | import net.minecraft.util.RandomSource; 10 | import net.minecraft.world.phys.Vec3; 11 | import org.spongepowered.asm.mixin.Final; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Shadow; 14 | import org.spongepowered.asm.mixin.Unique; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 19 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 20 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 21 | import top.leavesmc.Bladeren.ModInfo; 22 | import top.leavesmc.Bladeren.clientcommands.RandomManager; 23 | import top.leavesmc.Bladeren.leaves.LeavesProtocol; 24 | 25 | import java.util.OptionalLong; 26 | import java.util.UUID; 27 | import java.util.concurrent.ScheduledExecutorService; 28 | import java.util.concurrent.TimeUnit; 29 | 30 | @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID)) 31 | @Mixin(FishingCracker.class) 32 | public abstract class MixinFishingCracker { 33 | 34 | @Shadow(remap = false) 35 | @Final 36 | private static ScheduledExecutorService DELAY_EXECUTOR; 37 | 38 | @Unique 39 | private static long realSeed = 0L; 40 | 41 | @Inject(method = "getSeed", at = @At("RETURN"), remap = false) 42 | private static void onGetSeed(UUID uuid, CallbackInfoReturnable cir) { 43 | if (cir.getReturnValue().isPresent() && RandomManager.isFishCommand()) { 44 | RandomSource random = RandomSource.create(cir.getReturnValue().getAsLong() ^ 25214903917L); 45 | Mth.createInsecureUUID(random); 46 | realSeed = ((CheckedRandomAccessor) random).getSeed().get(); 47 | } 48 | } 49 | 50 | @Inject(method = "processBobberSpawn", at = @At(value = "INVOKE", target = "Ljava/util/List;size()I", ordinal = 2), remap = false) 51 | private static void onGetGoodFishing(UUID fishingBobberUUID, Vec3 pos, Vec3 velocity, CallbackInfo ci) { 52 | long lootSeed = RandomManager.fishingLootSeed; 53 | DELAY_EXECUTOR.schedule(() -> { 54 | if (Configs.getFishingManipulation().isEnabled()) { 55 | if (realSeed != 0L && RandomManager.fishingLootSeed != 0L) { 56 | FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 57 | buf.writeLong(realSeed); 58 | buf.writeLong(lootSeed); 59 | buf.writeInt(0); 60 | LeavesProtocol.sendPacket(RandomManager.RNG_FISHING_ID, buf); 61 | } 62 | } 63 | }, 200, TimeUnit.MILLISECONDS); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/clientcommands/fishCommand/MixinLootContext.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.clientcommands.fishCommand; 2 | 3 | import com.seedfinding.mccore.version.MCVersion; 4 | import com.seedfinding.mcfeature.loot.LootContext; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 10 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 11 | import top.leavesmc.Bladeren.ModInfo; 12 | import top.leavesmc.Bladeren.clientcommands.RandomManager; 13 | 14 | @Dependencies(and = @Dependency(ModInfo.CLIENTCOMMANDS_MOD_ID)) 15 | @Mixin(LootContext.class) 16 | public class MixinLootContext { 17 | @Inject(method = "(JLcom/seedfinding/mccore/version/MCVersion;)V", at = @At("RETURN"), remap = false) 18 | private void onInit(long lootTableSeed, MCVersion version, CallbackInfo ci) { 19 | RandomManager.fishingLootSeed = lootTableSeed; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/event/disconnect/MixinMinecraftClient.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.event.disconnect; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | import top.leavesmc.Bladeren.event.DisconnectEvent; 9 | 10 | @Mixin(Minecraft.class) 11 | public abstract class MixinMinecraftClient { 12 | 13 | @Inject(method = "clearClientLevel", at = @At(value = "HEAD")) 14 | private void onDisconnect(CallbackInfo ci) { 15 | if (!Minecraft.getInstance().hasSingleplayerServer()) { 16 | DisconnectEvent.onDisconnect(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/leaves/MixinClientPacketListener.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.leaves; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl; 5 | import net.minecraft.client.multiplayer.ClientPacketListener; 6 | import net.minecraft.client.multiplayer.CommonListenerCookie; 7 | import net.minecraft.network.Connection; 8 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 9 | import net.minecraft.network.protocol.game.ClientboundLoginPacket; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | import top.leavesmc.Bladeren.leaves.LeavesPayload; 15 | import top.leavesmc.Bladeren.leaves.LeavesProtocol; 16 | 17 | @Mixin(ClientPacketListener.class) 18 | public abstract class MixinClientPacketListener extends ClientCommonPacketListenerImpl { 19 | 20 | protected MixinClientPacketListener(Minecraft minecraft, Connection connection, CommonListenerCookie commonListenerCookie) { 21 | super(minecraft, connection, commonListenerCookie); 22 | } 23 | 24 | @Inject(method = "handleLogin", at = @At("RETURN")) 25 | private void onGameJoined(ClientboundLoginPacket clientboundLoginPacket, CallbackInfo ci) { 26 | LeavesProtocol.gameJoined(minecraft.player); 27 | } 28 | 29 | @Inject(method = "handleUnknownCustomPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V"), cancellable = true) 30 | private void onOnCustomPayload(CustomPacketPayload packetPayload, CallbackInfo ci) { 31 | if (packetPayload instanceof LeavesPayload payload) { 32 | LeavesProtocol.onPayload(payload); 33 | ci.cancel(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/leaves/MixinClientboundCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.leaves; 2 | 3 | import net.minecraft.network.FriendlyByteBuf; 4 | import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; 5 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 6 | import net.minecraft.resources.ResourceLocation; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 11 | import top.leavesmc.Bladeren.ModInfo; 12 | import top.leavesmc.Bladeren.leaves.LeavesPayload; 13 | 14 | @Mixin(ClientboundCustomPayloadPacket.class) 15 | public class MixinClientboundCustomPayloadPacket { 16 | @Inject(method = "readPayload", at = @At(value = "HEAD"), cancellable = true) 17 | private static void readPayload(ResourceLocation id, FriendlyByteBuf buf, CallbackInfoReturnable cir) { 18 | if (id.getNamespace().equals(ModInfo.MOD_ID)) { 19 | cir.setReturnValue(new LeavesPayload(id, buf)); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/minecraft/lavaRiptide/MixinTridentItem.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.minecraft.lavaRiptide; 2 | 3 | import net.minecraft.world.entity.player.Player; 4 | import net.minecraft.world.item.TridentItem; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | import top.leavesmc.Bladeren.config.Configs; 9 | import top.leavesmc.Bladeren.leaves.LeavesProtocol; 10 | 11 | @Mixin(TridentItem.class) 12 | public class MixinTridentItem { 13 | 14 | @Redirect(method = "releaseUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isInWaterOrRain()Z")) 15 | private boolean isInWaterOrLave(Player player) { 16 | return player.isInWaterOrRain() || (Configs.lavaRiptide && LeavesProtocol.isFeatureEnableOrLocal("lava_riptide") && player.isInLava()); 17 | } 18 | 19 | @Redirect(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isInWaterOrRain()Z")) 20 | private boolean checkInWaterOrLave(Player player) { 21 | return player.isInWaterOrRain() || (Configs.lavaRiptide && LeavesProtocol.isFeatureEnableOrLocal("lava_riptide") && player.isInLava()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/top/leavesmc/Bladeren/mixin/minihud/msptSyncProtocol/MixinDataStorage.java: -------------------------------------------------------------------------------- 1 | package top.leavesmc.Bladeren.mixin.minihud.msptSyncProtocol; 2 | 3 | import fi.dy.masa.minihud.util.DataStorage; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependencies; 9 | import top.hendrixshen.magiclib.dependency.api.annotation.Dependency; 10 | import top.leavesmc.Bladeren.ModInfo; 11 | import top.leavesmc.Bladeren.minihud.msptSyncProtocol.MsptSyncProtocol; 12 | 13 | @Dependencies(and = @Dependency(ModInfo.MINIHUD_MOD_ID)) 14 | @Mixin(value = DataStorage.class, remap = false) 15 | public class MixinDataStorage { 16 | @Inject(method = "", at = @At(value = "RETURN")) 17 | private void onInit(CallbackInfo ci) { 18 | MsptSyncProtocol.init(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/assets/bladeren/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "bladeren.gui.title.configs": "Bladeren Config - Version: %s", 3 | "bladeren.gui.button.tab.generic": "Generic", 4 | "bladeren.gui.button.tab.minecraft": "Minecraft", 5 | "bladeren.gui.button.tab.minihud": "Minihud", 6 | "bladeren.gui.button.tab.clientcommands": "clientcommands", 7 | "bladeren.config.generic.debug.name": "debug", 8 | "bladeren.config.generic.debug.comment": "Display debug message", 9 | "bladeren.config.generic.openConfigGui.name": "openConfigGui", 10 | "bladeren.config.generic.openConfigGui.comment": "A hotkey to open the in-game Config GUI", 11 | "bladeren.config.minihud.msptSyncProtocol.name": "msptSyncProtocol", 12 | "bladeren.config.minihud.msptSyncProtocol.comment": "Use Bladeren to sync mspt data from Leaves", 13 | "bladeren.config.minecraft.lavaRiptide.name": "lavaRiptide", 14 | "bladeren.config.minecraft.lavaRiptide.comment": "Make riptide can use on lava,\nin server maybe is hacker" 15 | } -------------------------------------------------------------------------------- /src/main/resources/assets/bladeren/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "bladeren.gui.title.configs": "Bladeren 设置 - 版本: %s", 3 | "bladeren.gui.button.tab.generic": "通用", 4 | "bladeren.gui.button.tab.minecraft": "Minecraft", 5 | "bladeren.gui.button.tab.minihud": "Minihud", 6 | "bladeren.gui.button.tab.clientcommands": "clientcommands", 7 | "bladeren.config.generic.debug.name": "调试模式", 8 | "bladeren.config.generic.debug.comment": "开启后将会打印调试日志", 9 | "bladeren.config.generic.openConfigGui.name": "打开设置界面", 10 | "bladeren.config.generic.openConfigGui.comment": "打开设置界面的快捷键", 11 | "bladeren.config.minihud.msptSyncProtocol.name": "MSPT数据同步", 12 | "bladeren.config.minihud.msptSyncProtocol.comment": "使用 Bladeren 协议和 Leaves 服务器同步MSPT数据", 13 | "bladeren.config.minecraft.lavaRiptide.name": "熔岩激流", 14 | "bladeren.config.minecraft.lavaRiptide.comment": "使得激流可以在岩浆中使用,\n这会被大多数服务器视为作弊且服务器可禁用此功能" 15 | } -------------------------------------------------------------------------------- /src/main/resources/bladeren.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "top.leavesmc.Bladeren.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "plugin": "top.hendrixshen.magiclib.dependency.impl.MagicMixinPlugin", 7 | "client": [ 8 | "accessor.AccessorDataStorage", 9 | "clientcommands.MixinClientsCommands", 10 | "clientcommands.disableNotVanillaWarn.MixinServerBrandManager", 11 | "clientcommands.fishCommand.MixinConfigs", 12 | "clientcommands.fishCommand.MixinFishCommand", 13 | "event.disconnect.MixinMinecraftClient", 14 | "leaves.MixinClientPacketListener", 15 | "minecraft.lavaRiptide.MixinTridentItem", 16 | "minihud.msptSyncProtocol.MixinDataStorage" 17 | ], 18 | "injectors": { 19 | "defaultRequire": 1 20 | }, 21 | "mixins": [ 22 | "leaves.MixinClientboundCustomPayloadPacket" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}-${minecraft_version_id}", 4 | "version": "${mod_version}", 5 | "icon": "assets/${mod_id}/icon.png", 6 | "name": "${mod_name} for ${minecraft_version}", 7 | "description": "${mod_description}", 8 | "authors": [ 9 | { 10 | "name": "LeavesMC", 11 | "contact": { 12 | "homepage": "https://github.com/LeavesMC" 13 | } 14 | } 15 | ], 16 | "contact": { 17 | "homepage": "${mod_homepage}", 18 | "issues": "${mod_sources}/issues", 19 | "sources": "${mod_sources}" 20 | }, 21 | "license": "${mod_license}", 22 | "environment": "client", 23 | "entrypoints": { 24 | "client": [ 25 | "top.leavesmc.Bladeren.BladerenMod" 26 | ], 27 | "modmenu": [ 28 | "top.leavesmc.Bladeren.compat.modmenu.ModMenuApiImpl" 29 | ] 30 | }, 31 | "mixins": [ 32 | "${mod_id}.mixins.json" 33 | ], 34 | "depends": { 35 | "magiclib-${minecraft_version_id}": ">=${magiclib_dependency}", 36 | "malilib": "*", 37 | "minecraft": "${minecraft_dependency}" 38 | }, 39 | "custom": { 40 | "modmenu:clientsideOnly": true, 41 | "modmenu:parent": "${mod_id}", 42 | "modmenu": { 43 | "parent": "${mod_id}" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /versions/1.20.4/gradle.properties: -------------------------------------------------------------------------------- 1 | # Development Environment 2 | minecraft_version=1.20.4 3 | minecraft_dependency=1.20.x 4 | 5 | # Compatible Libraries 6 | minihud_version=4946335 7 | litematica_version=4946471 8 | clientcommands_version=2.8.9 -------------------------------------------------------------------------------- /versions/mainProject: -------------------------------------------------------------------------------- 1 | 1.20.4 --------------------------------------------------------------------------------