Skip to content

Commit 22c85cb

Browse files
support multiple mods
1 parent a026191 commit 22c85cb

6 files changed

Lines changed: 99 additions & 51 deletions

File tree

README.md

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,36 +47,58 @@ export IDEA_JDK="/usr/lib/jvm/java-21-jetbrains"
4747
## Structure
4848

4949
```
50-
├── jars/ # vanilla jars
51-
├── libs/ # decompiler linking libs
52-
├── patches/ # decompiler fixes
53-
├── mods/ # your modifications (.patch and .zip)
54-
├── server/src/ # server source
55-
├── client/src/ # client source
56-
└── prism-instance/ # PrismLauncher instance template
50+
├── jars/ # vanilla jars
51+
├── libs/ # decompiler linking libs
52+
├── patches/ # decompiler fixes
53+
├── mods/
54+
│ ├── client/ # client patches (mymod.patch)
55+
│ └── server/ # server patches (mymod.patch)
56+
├── server/src/ # server source
57+
├── client/src/ # client source
58+
└── prism-instance/ # PrismLauncher instance template
5759
```
5860

5961
## Modding
6062

6163
Two-layer patch system:
6264
1. `patches/` - fixes for decompiler output (don't touch)
63-
2. `mods/` - your changes
65+
2. `mods/client/` and `mods/server/` - your named patches
6466

65-
Edit source, test, then generate patches:
67+
Edit source, test, then generate a named patch:
6668
```bash
67-
./gradlew genClientMods
68-
./gradlew genServerMods
69+
./gradlew modGen -Pargs=client,mymod
70+
./gradlew modGen -Pargs=server,mymod
71+
```
72+
73+
This saves to `mods/client/mymod.patch` or `mods/server/mymod.patch`.
74+
75+
### Applying Mods
76+
77+
Apply named patches to the source:
78+
```bash
79+
./gradlew modApply -Pargs=client,mod1,mod2,mod3
80+
./gradlew modApply -Pargs=server,mod1,mod2,mod3
81+
```
82+
83+
Patches are applied in order. If a patch fails, it likely depends on another.
84+
85+
### Reverting Mods
86+
87+
Reverse patches (in reverse order):
88+
```bash
89+
./gradlew modRevert -Pargs=client,mod1,mod2,mod3
90+
./gradlew modRevert -Pargs=server,mod1,mod2,mod3
6991
```
7092

7193
### Packing Mods
7294

7395
Pack changed classes into a zip for distribution:
7496
```bash
75-
./gradlew packClient
76-
./gradlew packServer
97+
./gradlew modPack -Pargs=client,mod1,mod2,mod3
98+
./gradlew modPack -Pargs=server,mod1,mod2,mod3
7799
```
78100

79-
This compares your source against the base, finds modified files, and outputs them to `mods/client.zip` or `mods/server.zip`.
101+
This applies the patches first, then compares against the base and outputs to `mods/client.zip` or `mods/server.zip`.
80102

81103
### Using with PrismLauncher
82104

build.gradle

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -111,63 +111,46 @@ task snapClient {
111111
}
112112
}
113113

114-
task modsServer {
114+
task modApply {
115115
group = 'mods'
116-
dependsOn snapServer
117116
doLast {
118-
Patcher.apply(file('server/src/main/java'), file('mods/server.patch'))
117+
def p = project.hasProperty('args') ? project.args.split(',') : null
118+
if (!p || p.length < 2) throw new RuntimeException("Usage: -Pargs=side,mod1,mod2")
119+
Mod.apply(rootDir, p[0], p[1..-1] as String[])
119120
}
120121
}
121122

122-
task modsClient {
123+
task modRevert {
123124
group = 'mods'
124-
dependsOn snapClient
125125
doLast {
126-
Patcher.apply(file('client/src/main/java'), file('mods/client.patch'))
126+
def p = project.hasProperty('args') ? project.args.split(',') : null
127+
if (!p || p.length < 2) throw new RuntimeException("Usage: -Pargs=side,mod1,mod2")
128+
Mod.revert(rootDir, p[0], p[1..-1] as String[])
127129
}
128130
}
129131

130-
task setupServer { group = 'setup'; dependsOn modsServer }
131-
task setupClient { group = 'setup'; dependsOn modsClient }
132-
task setup { group = 'setup'; dependsOn setupServer, setupClient }
133-
134-
task genModsServer {
135-
group = 'mods'
136-
doLast {
137-
Patcher.diff(file('patchSrc/server-base.zip'), file('server/src/main/java'),
138-
file('mods/server.patch'), true)
139-
}
140-
}
141-
142-
task genModsClient {
132+
task modGen {
143133
group = 'mods'
144134
doLast {
145-
Patcher.diff(file('patchSrc/client-base.zip'), file('client/src/main/java'),
146-
file('mods/client.patch'), true)
135+
def p = project.hasProperty('args') ? project.args.split(',') : null
136+
if (!p || p.length != 2) throw new RuntimeException("Usage: -Pargs=side,name")
137+
Mod.gen(rootDir, p[0], p[1])
147138
}
148139
}
149140

150-
task genMods { group = 'mods'; dependsOn genModsServer, genModsClient }
151-
152-
task packServer {
141+
task modPack {
153142
group = 'mods'
154-
dependsOn ':server:compileJava'
143+
dependsOn ':client:compileJava', ':server:compileJava'
155144
doLast {
156-
Mod.pack(file('patchSrc/server-base.zip'), file('server/src/main/java'),
157-
file('server/build/classes/java/main'), file('mods/server.zip'))
145+
def p = project.hasProperty('args') ? project.args.split(',') : null
146+
if (!p || p.length < 2) throw new RuntimeException("Usage: -Pargs=side,mod1,mod2")
147+
Mod.pack(rootDir, p[0], p[1..-1] as String[])
158148
}
159149
}
160150

161-
task packClient {
162-
group = 'mods'
163-
dependsOn ':client:compileJava'
164-
doLast {
165-
Mod.pack(file('patchSrc/client-base.zip'), file('client/src/main/java'),
166-
file('client/build/classes/java/main'), file('mods/client.zip'))
167-
}
168-
}
169-
170-
task pack { group = 'mods'; dependsOn packServer, packClient }
151+
task setupServer { group = 'setup'; dependsOn snapServer }
152+
task setupClient { group = 'setup'; dependsOn snapClient }
153+
task setup { group = 'setup'; dependsOn setupServer, setupClient }
171154

172155
task genPatchServer {
173156
group = 'patches'

buildSrc/src/main/java/Mod.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,43 @@
55

66
public class Mod {
77

8+
public static void apply(File root, String side, String[] names) throws Exception {
9+
for (String name : names) {
10+
File patch = new File(root, "mods/" + side + "/" + name + ".patch");
11+
12+
if (!patch.exists()) throw new RuntimeException("Patch not found: " + patch);
13+
Patcher.apply(new File(root, side + "/src/main/java"), patch);
14+
}
15+
}
16+
17+
public static void revert(File root, String side, String[] names) throws Exception {
18+
for (int i = names.length - 1; i >= 0; i--) {
19+
File patch = new File(root, "mods/" + side + "/" + names[i] + ".patch");
20+
21+
if (!patch.exists()) throw new RuntimeException("Patch not found: " + patch);
22+
Patcher.unapply(new File(root, side + "/src/main/java"), patch);
23+
}
24+
}
25+
26+
public static void gen(File root, String side, String name) throws Exception {
27+
File base = new File(root, "patchSrc/" + side + "-base.zip");
28+
File src = new File(root, side + "/src/main/java");
29+
File out = new File(root, "mods/" + side + "/" + name + ".patch");
30+
31+
Patcher.diff(base, src, out, true);
32+
}
33+
34+
public static void pack(File root, String side, String[] names) throws Exception {
35+
apply(root, side, names);
36+
37+
File base = new File(root, "patchSrc/" + side + "-base.zip");
38+
File src = new File(root, side + "/src/main/java");
39+
File classes = new File(root, side + "/build/classes/java/main");
40+
File out = new File(root, "mods/" + side + ".zip");
41+
42+
pack(base, src, classes, out);
43+
}
44+
845
public static void pack(File base, File src, File classes, File out) throws Exception {
946
if (!base.exists()) throw new RuntimeException("Run setup first");
1047

buildSrc/src/main/java/Patcher.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ public static void apply(File dir, File patch) throws Exception {
1111
run(dir, "patch", "-p1", "-i", patch.getAbsolutePath());
1212
}
1313

14+
public static void unapply(File dir, File patch) throws Exception {
15+
if (!patch.exists()) return;
16+
17+
run(dir, "patch", "-R", "-p1", "-i", patch.getAbsolutePath());
18+
}
19+
1420
public static void snap(File src, File dest) throws IOException {
1521
dest.getParentFile().mkdirs();
1622

0 commit comments

Comments
 (0)