Skip to content

Commit 399831e

Browse files
Bring back the utils module(previously named common)
Support reading MCP mappings Refactor `MappingProcessor`s and introduce `ContentList` New component: `SideSpecific` Make `PropertiesTrait` also a `Component`
1 parent 87c6a55 commit 399831e

69 files changed

Lines changed: 1024 additions & 913 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

decompiler/decompiler.properties

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
# Example of creating the user-defined decompiler. This is the config file. In this example we use Spigot FernFlower
22

3-
# Required, your decompiler executable file(.jar, .exe, etc.). Absolute path and relative path are both OK.
3+
# Required. The decompiler executable file(.jar, .exe, etc.). Absolute path and relative path are both OK.
44
decompiler-file=fernflower.jar
55

6-
# Required, sets the input to the decompiler should be file or directory. Options are "FILE" and "DIRECTORY"(case-insensitive).
7-
# "FILE" will input the full Minecraft jar, so you need to set your decompiler to skip lib classes.
8-
source-type=DIRECTORY
6+
# Required. Controls whether the decompiler input should be a file or a directory. Options are "FILE" and "DIRECTORY"(case-insensitive).
7+
# "FILE" will input the full Minecraft jar, so you may need to set your decompiler to skip lib classes.
8+
source-type=DIrECToRy
99

10-
# Required, args passed to the decompiler, has 4 variables:
11-
# %lib_all%: All libs separated by path.separator(default is ';')
12-
# %lib_repeat%: List all the libs by repeating the arg. In this example will repeat the -e arg(results -e=first-lib.jar -e=second-lib.jar).
13-
# If there are no characters on both sides of this variable, it will repeat the previous arg and this arg(e.g. "-e %lib_repeat%" results "-e first-lib.jar -e second-lib.jar")
10+
# Required. The args passed to the decompiler, which have the following variables:
11+
# %lib_all%: All libs separated by path.separator(defaults to ';')
12+
# %lib_repeat%: List all the libs by repeating the arg. In this example it will result in '-e=first-lib.jar -e=second-lib.jar'.
13+
# %lib_repeat_with_previous%: Similar to %lib_repeat%, but it will repeat the previous arg and this arg(e.g. '-e "%lib_repeat%"' results in '-e "first-lib.jar" -e "second-lib.jar"')
1414
# %source%: The input file/directory(specified by source-type).
1515
# %target%: The output directory
1616
# %abstract_params%: The input file of abstract parameter names generated by MinecraftDecompiler if -r option is provided. Used by ForgeFlower and its forks
17-
# NOTE: %lib_all% and %lib_repeat% only works when "lib-recommended" option is set to true
1817
args=-log=TRACE -dgs=1 -asc=1 -udv=0 -ump=0 -rsy=1 -aoa=1 -e=%lib_repeat% %source% %target%

extensions/parchment/src/main/java/cn/maxpixel/mcdecompiler/mapping/parchment/FormatVersion.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
package cn.maxpixel.mcdecompiler.mapping.parchment;
2020

21-
import cn.maxpixel.mcdecompiler.mapping.util.MappingUtil;
21+
import cn.maxpixel.mcdecompiler.mapping.util.MappingUtils;
2222

2323
public record FormatVersion(int major, int minor, int patch) {
2424
public static FormatVersion CURRENT = new FormatVersion(1, 1, 0);
@@ -30,7 +30,7 @@ public record FormatVersion(int major, int minor, int patch) {
3030
}
3131

3232
public static FormatVersion from(String version) {
33-
String[] parts = MappingUtil.split(version, '.');
33+
String[] parts = MappingUtils.split(version, '.');
3434
if (parts.length < 2) throw new IllegalArgumentException("Expected at least 2 tokens for version " + version);
3535
if (parts.length > 3) throw new IllegalArgumentException("Expected at most 3 tokens for version " + version);
3636
return new FormatVersion(

extensions/parchment/src/main/java/cn/maxpixel/mcdecompiler/mapping/parchment/ParchmentMappingFormat.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,9 @@
1919
package cn.maxpixel.mcdecompiler.mapping.parchment;
2020

2121
import cn.maxpixel.mcdecompiler.mapping.PairedMapping;
22-
import cn.maxpixel.mcdecompiler.mapping.collection.ClassifiedMapping;
2322
import cn.maxpixel.mcdecompiler.mapping.format.MappingFormat;
2423
import org.jetbrains.annotations.NotNull;
2524

26-
import java.io.BufferedReader;
27-
import java.util.Objects;
28-
2925
public enum ParchmentMappingFormat implements MappingFormat.Classified<PairedMapping> {
3026
INSTANCE;
3127
public static final String NAME = "parchment";
@@ -45,11 +41,6 @@ public enum ParchmentMappingFormat implements MappingFormat.Classified<PairedMap
4541
return NAME;
4642
}
4743

48-
@Override
49-
public char getCommentChar() {
50-
return '\0';
51-
}
52-
5344
@Override
5445
public @NotNull ParchmentMappingProcessor getProcessor() {
5546
return ParchmentMappingProcessor.INSTANCE;
@@ -59,9 +50,4 @@ public char getCommentChar() {
5950
public @NotNull ParchmentMappingGenerator getGenerator() {
6051
return ParchmentMappingGenerator.INSTANCE;
6152
}
62-
63-
@Override
64-
public @NotNull ClassifiedMapping<PairedMapping> read(@NotNull BufferedReader reader) {
65-
return getProcessor().process(Objects.requireNonNull(reader));
66-
}
6753
}

extensions/parchment/src/main/java/cn/maxpixel/mcdecompiler/mapping/parchment/ParchmentMappingGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import cn.maxpixel.mcdecompiler.mapping.format.MappingFormat;
2828
import cn.maxpixel.mcdecompiler.mapping.generator.MappingGenerator;
2929
import cn.maxpixel.mcdecompiler.mapping.remapper.ClassifiedMappingRemapper;
30-
import cn.maxpixel.mcdecompiler.mapping.util.Utils;
30+
import cn.maxpixel.mcdecompiler.utils.Utils;
3131
import com.google.gson.stream.JsonWriter;
3232
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
3333
import it.unimi.dsi.fastutil.objects.ObjectList;

extensions/parchment/src/main/java/cn/maxpixel/mcdecompiler/mapping/parchment/ParchmentMappingProcessor.java

Lines changed: 22 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,13 @@
2626
import cn.maxpixel.mcdecompiler.mapping.component.LocalVariableTable;
2727
import cn.maxpixel.mcdecompiler.mapping.format.MappingFormat;
2828
import cn.maxpixel.mcdecompiler.mapping.processor.MappingProcessor;
29-
import cn.maxpixel.mcdecompiler.mapping.util.Utils;
29+
import cn.maxpixel.mcdecompiler.mapping.util.ContentList;
30+
import cn.maxpixel.mcdecompiler.utils.Utils;
3031
import com.google.gson.stream.JsonReader;
3132
import com.google.gson.stream.JsonToken;
3233
import org.jetbrains.annotations.NotNull;
3334

3435
import java.io.IOException;
35-
import java.io.Reader;
36-
import java.util.List;
3736

3837
import static cn.maxpixel.mcdecompiler.mapping.parchment.ParchmentMappingFormat.*;
3938

@@ -46,32 +45,30 @@ public MappingFormat<PairedMapping, ClassifiedMapping<PairedMapping>> getFormat(
4645
}
4746

4847
@Override
49-
public ClassifiedMapping<PairedMapping> process(List<String> content) {
50-
return process(new StringListReader(content));
51-
}
52-
53-
public ClassifiedMapping<PairedMapping> process(Reader rd) {
54-
try (JsonReader reader = new JsonReader(rd)) {
55-
reader.beginObject();
56-
57-
ClassifiedMapping<PairedMapping> mappings = new ClassifiedMapping<>();
58-
while (reader.peek() == JsonToken.NAME) switch (reader.nextName()) {
59-
case KEY_VERSION -> {
60-
FormatVersion version = FormatVersion.from(reader.nextString());
61-
if (!FormatVersion.CURRENT.compatibleWith(version)) {
62-
throw new UnsupportedOperationException("Version " + version + " is incompatible with " +
63-
"current version " + FormatVersion.CURRENT);
48+
public ClassifiedMapping<PairedMapping> process(ContentList contents) {
49+
ClassifiedMapping<PairedMapping> mappings = new ClassifiedMapping<>();
50+
for (var content : contents) {
51+
try (JsonReader reader = new JsonReader(content.reader())) {
52+
reader.beginObject();
53+
54+
while (reader.peek() == JsonToken.NAME) switch (reader.nextName()) {
55+
case KEY_VERSION -> {
56+
FormatVersion version = FormatVersion.from(reader.nextString());
57+
if (!FormatVersion.CURRENT.compatibleWith(version)) {
58+
throw new UnsupportedOperationException("Version " + version + " is incompatible with " +
59+
"current version " + FormatVersion.CURRENT);
60+
}
6461
}
62+
case KEY_PACKAGES -> handlePackages(reader, mappings);
63+
case KEY_CLASSES -> handleClasses(reader, mappings);
64+
default -> reader.skipValue();
6565
}
66-
case KEY_PACKAGES -> handlePackages(reader, mappings);
67-
case KEY_CLASSES -> handleClasses(reader, mappings);
68-
default -> reader.skipValue();
66+
reader.endObject();
67+
} catch (IOException e) {
68+
throw Utils.wrapInRuntime(e);
6969
}
70-
reader.endObject();
71-
return mappings;
72-
} catch (IOException e) {
73-
throw Utils.wrapInRuntime(e);
7470
}
71+
return mappings;
7572
}
7673

7774
private static @NotNull Documented handleDocs(JsonReader reader) throws IOException {
@@ -204,59 +201,4 @@ private static void handlePackages(JsonReader reader, ClassifiedMapping<PairedMa
204201
}
205202
reader.endArray();
206203
}
207-
208-
private static class StringListReader extends Reader {
209-
private final List<String> l;
210-
private int listIndex = 0;
211-
private final int listSize;
212-
private String s;
213-
private int stringIndex = 0;
214-
private int stringSize = 0;
215-
private boolean closed;
216-
217-
public StringListReader(List<String> l) {
218-
this.l = l;
219-
if ((this.listSize = l.size()) > 0) {
220-
this.s = l.get(0);
221-
this.stringSize = s.length();
222-
}
223-
}
224-
225-
@Override
226-
public int read(char @NotNull [] cbuf, int off, int len) throws IOException {
227-
if (closed) throw new IOException("Reader closed");
228-
if (listIndex >= listSize) return -1;
229-
int read = 0;
230-
while (listIndex < listSize && len > 0) {
231-
int remaining = stringSize - stringIndex;
232-
if (remaining >= len) {
233-
s.getChars(stringIndex, stringIndex + len, cbuf, off);
234-
stringIndex += len;
235-
read += len;
236-
return read;
237-
} else {// remaining <= len - 1
238-
s.getChars(stringIndex, stringSize, cbuf, off);
239-
cbuf[off + remaining] = '\n';
240-
read += remaining + 1;
241-
off += remaining + 1;
242-
len -= remaining + 1;
243-
updateString();
244-
}
245-
}
246-
return read;
247-
}
248-
249-
private void updateString() {
250-
if (++listIndex < listSize) {
251-
s = l.get(listIndex);
252-
stringIndex = 0;
253-
stringSize = s.length();
254-
}
255-
}
256-
257-
@Override
258-
public void close() {
259-
closed = true;
260-
}
261-
}
262204
}

extensions/parchment/src/test/java/cn/maxpixel/mcdecompiler/test/mapping/parchment/ParchmentFormatTest.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@
2222
import cn.maxpixel.mcdecompiler.mapping.format.MappingFormats;
2323
import cn.maxpixel.mcdecompiler.mapping.parchment.FormatVersion;
2424
import cn.maxpixel.mcdecompiler.mapping.parchment.ParchmentMappingFormat;
25-
import cn.maxpixel.mcdecompiler.mapping.parchment.ParchmentMappingProcessor;
26-
import cn.maxpixel.mcdecompiler.mapping.util.Utils;
27-
import cn.maxpixel.rewh.logging.LogManager;
28-
import cn.maxpixel.rewh.logging.Logger;
29-
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
3025
import org.junit.jupiter.api.Test;
3126
import org.junit.jupiter.api.io.CleanupMode;
3227
import org.junit.jupiter.api.io.TempDir;
@@ -38,7 +33,6 @@
3833
import static org.junit.jupiter.api.Assertions.*;
3934

4035
class ParchmentFormatTest {
41-
private static final Logger LOGGER = LogManager.getLogger();
4236

4337
@Test
4438
void testFormatVersion() {
@@ -67,12 +61,5 @@ void testProcessorAndGenerator(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path t
6761
var c2 = ParchmentMappingFormat.INSTANCE.read(reader);
6862
assertEquals(c1, c2);
6963
}
70-
try (var reader = Files.newBufferedReader(path)) {
71-
ObjectArrayList<String> lines = reader.lines().collect(ObjectArrayList.toList());
72-
var c3 = ParchmentMappingProcessor.INSTANCE.process(lines);
73-
assertEquals(c1, c3);
74-
} catch (IOException e) {
75-
throw Utils.wrapInRuntime(e);
76-
}
7764
}
7865
}

modules/api/src/main/java/cn/maxpixel/mcdecompiler/api/MinecraftDecompiler.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@
3131
import cn.maxpixel.mcdecompiler.mapping.collection.ClassifiedMapping;
3232
import cn.maxpixel.mcdecompiler.mapping.collection.MappingCollection;
3333
import cn.maxpixel.mcdecompiler.mapping.trait.NamespacedTrait;
34-
import cn.maxpixel.mcdecompiler.mapping.util.Utils;
3534
import cn.maxpixel.mcdecompiler.remapper.ClassifiedDeobfuscator;
3635
import cn.maxpixel.mcdecompiler.remapper.DeobfuscationOptions;
3736
import cn.maxpixel.mcdecompiler.remapper.util.IOUtil;
37+
import cn.maxpixel.mcdecompiler.utils.LambdaUtil;
38+
import cn.maxpixel.mcdecompiler.utils.Utils;
3839
import cn.maxpixel.rewh.logging.LogManager;
3940
import cn.maxpixel.rewh.logging.Logger;
4041
import com.google.gson.JsonObject;
@@ -122,10 +123,10 @@ public void decompile(String decompilerName, @Nullable Path incrementalJar) {
122123
try {
123124
MessageDigest md = MessageDigest.getInstance("SHA-1");
124125
md.update(IOUtil.readAllBytes(p));
125-
StringBuilder hashA = MiscUtils.createHashString(md);
126+
StringBuilder hashA = AppUtils.createHashString(md);
126127

127128
md.update(IOUtil.readAllBytes(jarFs.getPath(path)));
128-
StringBuilder hashB = MiscUtils.createHashString(md);
129+
StringBuilder hashB = AppUtils.createHashString(md);
129130
if (hashA.compareTo(hashB) == 0) {
130131
maybeRemoved.add(path);
131132
} else if (fileName.lastIndexOf('$') > 0) {

modules/api/src/main/java/cn/maxpixel/mcdecompiler/api/extension/OptionRegistry.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
package cn.maxpixel.mcdecompiler.api.extension;
2020

21-
import cn.maxpixel.mcdecompiler.common.app.util.LambdaUtil;
22-
import cn.maxpixel.mcdecompiler.mapping.util.Utils;
21+
import cn.maxpixel.mcdecompiler.mapping.util.MappingUtils;
22+
import cn.maxpixel.mcdecompiler.utils.LambdaUtil;
2323
import it.unimi.dsi.fastutil.objects.*;
2424
import org.jetbrains.annotations.NotNull;
2525
import org.jetbrains.annotations.Nullable;
@@ -149,7 +149,7 @@ public Option register(@NotNull String option) {
149149
}
150150

151151
public Option register(@NotNull String option, @Nullable String description) {
152-
if (Utils.isStringNotBlank(option)) return OptionRegistry.this.register(new Option(List.of(prefix + '-' + option), description));
152+
if (MappingUtils.isStringNotBlank(option)) return OptionRegistry.this.register(new Option(List.of(prefix + '-' + option), description));
153153
else throw new IllegalArgumentException("Option cannot be null or empty");
154154
}
155155

@@ -161,7 +161,7 @@ public Option register(@NotNull List<@NotNull String> options, @Nullable String
161161
String[] sa = new String[Objects.requireNonNull(options).size()];
162162
for (int i = 0; i < sa.length; i++) {
163163
String o = options.get(i);
164-
if (Utils.isStringNotBlank(o)) sa[i] = prefix + '-' + o;
164+
if (MappingUtils.isStringNotBlank(o)) sa[i] = prefix + '-' + o;
165165
else throw new IllegalArgumentException("Option cannot be null or empty");
166166
}
167167
return OptionRegistry.this.register(new Option(new ObjectImmutableList<>(sa), description));

modules/app-common/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
<name>MinecraftDecompiler - Application Common</name>
1515

1616
<dependencies>
17+
<dependency>
18+
<groupId>cn.maxpixel.minecraft-decompiler</groupId>
19+
<artifactId>utils</artifactId>
20+
<version>${project.version}</version>
21+
</dependency>
1722
<dependency>
1823
<groupId>org.jetbrains</groupId>
1924
<artifactId>annotations</artifactId>

modules/app-common/src/main/java/cn/maxpixel/mcdecompiler/common/app/util/ProcessUtil.java renamed to modules/app-common/src/main/java/cn/maxpixel/mcdecompiler/common/app/util/AppUtils.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* MinecraftDecompiler. A tool/library to deobfuscate and decompile jars.
3-
* Copyright (C) 2019-2024 MaxPixelStudios(XiaoPangxie732)
3+
* Copyright (C) 2019-2025 MaxPixelStudios(XiaoPangxie732)
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Lesser General Public License as published by
@@ -20,32 +20,47 @@
2020

2121
import cn.maxpixel.rewh.logging.LogManager;
2222
import cn.maxpixel.rewh.logging.Logger;
23+
import org.jetbrains.annotations.NotNull;
2324

2425
import java.io.BufferedReader;
2526
import java.io.IOException;
26-
import java.io.InputStreamReader;
27+
import java.security.MessageDigest;
28+
29+
public class AppUtils {
30+
public static StringBuilder createHashString(MessageDigest md) {
31+
StringBuilder out = new StringBuilder();
32+
for (byte b : md.digest()) {
33+
String hex = Integer.toHexString(Byte.toUnsignedInt(b));
34+
if (hex.length() < 2) out.append('0');
35+
out.append(hex);
36+
}
37+
return out;
38+
}
39+
40+
public static String file2Native(@NotNull String fileName) {
41+
return fileName.replace('\\', '/').replace(".class", "");
42+
}
2743

28-
public class ProcessUtil {
2944
public static void waitFor(Process pro) {
3045
Logger logger = LogManager.getLogger("Process PID: " + pro.pid());
31-
try (BufferedReader in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
32-
BufferedReader err = new BufferedReader(new InputStreamReader(pro.getErrorStream()))) {
46+
try (BufferedReader in = pro.inputReader();
47+
BufferedReader err = pro.errorReader()) {
3348
Thread inT = new Thread(() -> {
3449
try {
3550
String ins;
3651
while ((ins = in.readLine()) != null) logger.debug("{}", ins);// avoid unexpected interpolation
3752
} catch (Throwable e) {
3853
logger.warn("Exception thrown", e);
3954
}
40-
});
55+
}, "Process-PID-" + pro.pid() + "-STDOUT-Reader");
4156
Thread errT = new Thread(() -> {
4257
try {
4358
String ins;
4459
while ((ins = err.readLine()) != null) logger.warn("{}", ins);
4560
} catch (Throwable e) {
4661
logger.warn("Exception thrown", e);
4762
}
48-
});
63+
}, "Process-PID-" + pro.pid() + "-STDERR-Reader");
4964
inT.setDaemon(true);
5065
errT.setDaemon(true);
5166
inT.start();

0 commit comments

Comments
 (0)