├── .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 | [](https://github.com/LeavesMC/Bladeren/blob/master/LICENSE)
4 | [](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 | [](https://github.com/LeavesMC/Bladeren/blob/master/LICENSE)
4 | [](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
--------------------------------------------------------------------------------