Skip to content

Commit e0abc28

Browse files
Prism Launher support
1 parent bdb813f commit e0abc28

9 files changed

Lines changed: 204 additions & 3 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ server/src/
2222
client/src/
2323
server/bin/
2424
client/bin/
25+
*.zip
2526

2627
# Run directories
2728
run/

README.md

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Decompiled source from Mojang's unobfuscated JARs. No Loom, no Forge toolchains, just Vineflower and Gradle.
44

5+
Starting with 1.21.11, Mojang ships unobfuscated JARs.
6+
57
## Requirements
68

79
- JDK 21+
@@ -39,9 +41,10 @@ For client, grab assets first:
3941
├── jars/ # vanilla jars
4042
├── libs/ # decompiler linking libs
4143
├── patches/ # decompiler fixes
42-
├── mods/ # your modifications
44+
├── mods/ # your modifications (.patch and .zip)
4345
├── server/src/ # server source
44-
└── client/src/ # client source
46+
├── client/src/ # client source
47+
└── prism-instance/ # PrismLauncher instance template
4548
```
4649

4750
## Modding
@@ -52,8 +55,52 @@ Two-layer patch system:
5255

5356
Edit source, test, then generate patches:
5457
```bash
55-
./gradlew genServerMods
5658
./gradlew genClientMods
59+
./gradlew genServerMods
60+
```
61+
62+
### Packing Mods
63+
64+
Pack changed classes into a zip for distribution:
65+
```bash
66+
./gradlew packClient
67+
./gradlew packServer
68+
```
69+
70+
This compares your source against the base, finds modified files, and outputs them to `mods/client.zip` or `mods/server.zip`.
71+
72+
### Using with PrismLauncher
73+
74+
Old-school jar modding is back. To use your mods with PrismLauncher:
75+
76+
1. **Copy the instance template:**
77+
```bash
78+
cp -r prism-instance ~/.local/share/PrismLauncher/instances/my-modded-mc
79+
```
80+
81+
2. **Add your mod classes:**
82+
```bash
83+
cp mods/client.zip ~/.local/share/PrismLauncher/instances/my-modded-mc/jarmods/
84+
```
85+
86+
3. **Restart PrismLauncher:**
87+
1. There should be a new instance `1.21.11-rc2 Unobfuscated`
88+
2. You can edit it to toggle `Unobfuscated` component to disable unobfuscated client
89+
3. Or you can toggle `Mods` component to disable your mods
90+
91+
The jarMods system merges your classes on top of the base jar at runtime.
92+
93+
### Instance Structure
94+
95+
```
96+
prism-instance/
97+
├── instance.cfg # instance name/type
98+
├── mmc-pack.json # components list
99+
├── jarmods/
100+
│ └── client.zip # your compiled mod classes
101+
└── patches/
102+
├── custom.unobfuscated.json # unobfuscated jar override
103+
└── custom.mods.json # jarMods component
57104
```
58105

59106
## Decompiler

build.gradle

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,26 @@ task genModsClient {
149149

150150
task genMods { group = 'mods'; dependsOn genModsServer, genModsClient }
151151

152+
task packServer {
153+
group = 'mods'
154+
dependsOn ':server:compileJava'
155+
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'))
158+
}
159+
}
160+
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 }
171+
152172
task genPatchServer {
153173
group = 'patches'
154174
doLast {

buildSrc/src/main/java/Mod.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import java.io.*;
2+
import java.nio.file.*;
3+
import java.util.*;
4+
import java.util.zip.*;
5+
6+
public class Mod {
7+
8+
public static void pack(File base, File src, File classes, File out) throws Exception {
9+
if (!base.exists()) throw new RuntimeException("Run setup first");
10+
11+
Set<String> changed = changed(base, src);
12+
if (changed.isEmpty()) {
13+
System.out.println("No changes to pack");
14+
return;
15+
}
16+
17+
zip(classes, changed, out);
18+
System.out.println("Packed " + changed.size() + " classes to " + out.getName());
19+
}
20+
21+
private static Set<String> changed(File base, File src) throws IOException {
22+
Set<String> changed = new HashSet<>();
23+
Map<String, byte[]> orig = new HashMap<>();
24+
25+
try (ZipFile zf = new ZipFile(base)) {
26+
for (ZipEntry e : Collections.list(zf.entries())) {
27+
if (e.isDirectory() || !e.getName().endsWith(".java")) continue;
28+
29+
orig.put(e.getName(), zf.getInputStream(e).readAllBytes());
30+
}
31+
}
32+
33+
Path s = src.toPath();
34+
for (String pkg : new String[]{"com", "net"}) {
35+
Path p = s.resolve(pkg);
36+
if (!Files.exists(p)) continue;
37+
38+
Files.walk(p).filter(f -> f.toString().endsWith(".java")).forEach(f -> {
39+
String rel = s.relativize(f).toString();
40+
try {
41+
byte[] cur = Files.readAllBytes(f);
42+
byte[] o = orig.get(rel);
43+
if (o == null || !Arrays.equals(cur, o)) changed.add(rel);
44+
} catch (IOException e) {
45+
throw new UncheckedIOException(e);
46+
}
47+
});
48+
}
49+
50+
return changed;
51+
}
52+
53+
private static void zip(File classes, Set<String> srcs, File out) throws IOException {
54+
out.getParentFile().mkdirs();
55+
56+
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(out))) {
57+
Path base = classes.toPath();
58+
for (String s : srcs) {
59+
String name = s.replace(".java", "");
60+
Path dir = base.resolve(name).getParent();
61+
String prefix = base.resolve(name).getFileName().toString();
62+
if (!Files.exists(dir)) continue;
63+
64+
Files.list(dir).filter(p -> p.getFileName().toString().startsWith(prefix) && p.toString().endsWith(".class")).forEach(p -> {
65+
try {
66+
zos.putNextEntry(new ZipEntry(base.relativize(p).toString()));
67+
Files.copy(p, zos);
68+
zos.closeEntry();
69+
} catch (IOException e) {
70+
throw new UncheckedIOException(e);
71+
}
72+
});
73+
}
74+
}
75+
}
76+
}

prism-instance/instance.cfg

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[General]
2+
ConfigVersion=1.2
3+
InstanceType=OneSix
4+
iconKey=default
5+
name=My Modded Minecraft
6+
notes=1.21.11-rc2 with unobfuscated classes

prism-instance/jarmods/--place-your-client-zip-here

Whitespace-only changes.

prism-instance/mmc-pack.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"components": [
3+
{
4+
"uid": "org.lwjgl3",
5+
"version": "3.3.3",
6+
"dependencyOnly": true
7+
},
8+
{
9+
"uid": "net.minecraft",
10+
"version": "1.21.11-rc2",
11+
"important": true
12+
},
13+
{
14+
"uid": "custom.unobfuscated"
15+
},
16+
{
17+
"uid": "custom.mods"
18+
}
19+
],
20+
"formatVersion": 1
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"formatVersion": 1,
3+
"jarMods": [
4+
{
5+
"MMC-displayname": "Mods",
6+
"MMC-filename": "client.zip",
7+
"MMC-hint": "local",
8+
"name": "custom.jarmods:mods:1"
9+
}
10+
],
11+
"name": "Mods",
12+
"uid": "custom.mods",
13+
"version": "1.0"
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"formatVersion": 1,
3+
"mainJar": {
4+
"downloads": {
5+
"artifact": {
6+
"sha1": "8e75db09feb89eec8ed7f2a2ae779b3fb1fb7f18",
7+
"size": 36734143,
8+
"url": "https://piston-data.mojang.com/v1/objects/8e75db09feb89eec8ed7f2a2ae779b3fb1fb7f18/client.jar"
9+
}
10+
},
11+
"name": "com.mojang:minecraft:1.21.11-rc2-unobfuscated:client"
12+
},
13+
"name": "Unobfuscated",
14+
"uid": "custom.unobfuscated",
15+
"version": "1.21.11-rc2"
16+
}

0 commit comments

Comments
 (0)