Skip to content

Commit 01b91a1

Browse files
committed
dynamically load and remap the AnvilGUI library to support both reobf and remapped server
1 parent da1b519 commit 01b91a1

4 files changed

Lines changed: 248 additions & 2 deletions

File tree

pom.xml

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,78 @@
1818
<description>Get inputs in a fancy way</description>
1919

2020
<properties>
21+
<anvilgui.version>1.10.4-SNAPSHOT</anvilgui.version>
2122
<project.mainClass>me.hsgamer.bettergui.anvilgui.Main</project.mainClass>
2223
</properties>
2324

25+
<build>
26+
<plugins>
27+
<plugin>
28+
<groupId>org.apache.maven.plugins</groupId>
29+
<artifactId>maven-shade-plugin</artifactId>
30+
<executions>
31+
<execution>
32+
<phase>package</phase>
33+
<goals>
34+
<goal>shade</goal>
35+
</goals>
36+
<configuration>
37+
<shadedArtifactAttached>true</shadedArtifactAttached>
38+
<createDependencyReducedPom>false</createDependencyReducedPom>
39+
<relocations>
40+
<!-- HSCore -->
41+
<relocation>
42+
<pattern>me.hsgamer.hscore</pattern>
43+
<shadedPattern>me.hsgamer.bettergui.lib.core</shadedPattern>
44+
</relocation>
45+
46+
<!-- MineLib -->
47+
<relocation>
48+
<pattern>io.github.projectunified.minelib</pattern>
49+
<shadedPattern>me.hsgamer.bettergui.lib.minelib</shadedPattern>
50+
</relocation>
51+
52+
<!-- bStats -->
53+
<relocation>
54+
<pattern>org.bstats</pattern>
55+
<shadedPattern>me.hsgamer.bettergui.lib.bstats</shadedPattern>
56+
</relocation>
57+
58+
<!-- Libby -->
59+
<relocation>
60+
<pattern>net.byteflux.libby</pattern>
61+
<shadedPattern>me.hsgamer.bettergui.anvilgui.lib.libby</shadedPattern>
62+
</relocation>
63+
</relocations>
64+
</configuration>
65+
</execution>
66+
</executions>
67+
</plugin>
68+
</plugins>
69+
</build>
70+
2471
<repositories>
2572
<repository>
2673
<id>codemc-public</id>
2774
<url>https://repo.codemc.io/repository/maven-public/</url>
2875
</repository>
76+
<repository>
77+
<id>AlessioDP</id>
78+
<url>https://repo.alessiodp.com/releases/</url>
79+
</repository>
2980
</repositories>
3081

3182
<dependencies>
3283
<dependency>
3384
<groupId>net.wesjd</groupId>
3485
<artifactId>anvilgui</artifactId>
35-
<version>1.10.0-SNAPSHOT</version>
86+
<version>${anvilgui.version}</version>
3687
<scope>provided</scope>
3788
</dependency>
89+
<dependency>
90+
<groupId>net.byteflux</groupId>
91+
<artifactId>libby-core</artifactId> <!-- Replace bukkit if you're using another platform -->
92+
<version>1.3.1</version>
93+
</dependency>
3894
</dependencies>
3995
</project>
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package me.hsgamer.bettergui.anvilgui;
2+
3+
import me.hsgamer.hscore.logger.common.Logger;
4+
import net.byteflux.libby.Library;
5+
import net.byteflux.libby.LibraryManager;
6+
import net.byteflux.libby.classloader.URLClassLoaderHelper;
7+
import net.byteflux.libby.logging.LogLevel;
8+
import net.byteflux.libby.logging.adapters.LogAdapter;
9+
10+
import java.io.BufferedReader;
11+
import java.io.IOException;
12+
import java.io.InputStream;
13+
import java.io.InputStreamReader;
14+
import java.lang.reflect.Field;
15+
import java.nio.file.Files;
16+
import java.nio.file.Path;
17+
import java.nio.file.StandardCopyOption;
18+
import java.util.Collections;
19+
import java.util.Enumeration;
20+
import java.util.List;
21+
import java.util.Objects;
22+
import java.util.function.Function;
23+
import java.util.jar.JarEntry;
24+
import java.util.jar.JarFile;
25+
import java.util.jar.JarOutputStream;
26+
import java.util.jar.Manifest;
27+
28+
public class LibLoader extends LibraryManager {
29+
private final Function<List<Path>, List<Path>> REMAPPER;
30+
private final URLClassLoaderHelper classLoader;
31+
private final Main main;
32+
33+
public LibLoader(Main main) {
34+
super(new LogAdapter() {
35+
@Override
36+
public void log(LogLevel level, String message) {
37+
Logger logger = main.getLogger();
38+
switch (level) {
39+
case DEBUG:
40+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.DEBUG, message);
41+
break;
42+
case INFO:
43+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.INFO, message);
44+
break;
45+
case WARN:
46+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.WARN, message);
47+
break;
48+
case ERROR:
49+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.ERROR, message);
50+
break;
51+
}
52+
}
53+
54+
@Override
55+
public void log(LogLevel level, String message, Throwable throwable) {
56+
Logger logger = main.getLogger();
57+
switch (level) {
58+
case DEBUG:
59+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.DEBUG, message, throwable);
60+
break;
61+
case INFO:
62+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.INFO, message, throwable);
63+
break;
64+
case WARN:
65+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.WARN, message, throwable);
66+
break;
67+
case ERROR:
68+
logger.log(me.hsgamer.hscore.logger.common.LogLevel.ERROR, message, throwable);
69+
break;
70+
}
71+
}
72+
}, main.getDataFolder().toPath(), "lib");
73+
this.classLoader = new URLClassLoaderHelper(main.getExpansionClassLoader(), this);
74+
this.main = main;
75+
76+
Function<List<Path>, List<Path>> remapper;
77+
try {
78+
Class<?> clazz = Class.forName("org.bukkit.plugin.java.LibraryLoader");
79+
Field remapperField = clazz.getDeclaredField("REMAPPER");
80+
81+
//noinspection unchecked
82+
remapper = (Function<List<Path>, List<Path>>) remapperField.get(null);
83+
} catch (Exception e) {
84+
remapper = null;
85+
}
86+
REMAPPER = remapper;
87+
}
88+
89+
@Override
90+
protected void addToClasspath(Path file) {
91+
classLoader.addToClasspath(file);
92+
}
93+
94+
private Path remap(Path file) {
95+
return REMAPPER != null ? REMAPPER.apply(Collections.singletonList(file)).get(0) : file;
96+
}
97+
98+
// This method's only purpose is to add the "paperweight-mappings-namespace" attribute to the MANIFEST.MF file of the library
99+
// So that it can be remapped by Paper's PluginRemapper
100+
// Thanks Copilot for this monstrosity of a method that solves the problem
101+
private void modifyManifest(Path file, Path modifiedFile) throws IOException {
102+
Path tempJarPath = Files.createTempFile("temp-", ".jar");
103+
104+
try (JarFile jarFile = new JarFile(file.toFile());
105+
JarOutputStream tempJarOutputStream = new JarOutputStream(Files.newOutputStream(tempJarPath))) {
106+
107+
// Copy existing entries
108+
Enumeration<JarEntry> entries = jarFile.entries();
109+
while (entries.hasMoreElements()) {
110+
JarEntry entry = entries.nextElement();
111+
if (JarFile.MANIFEST_NAME.equals(entry.getName())) {
112+
continue; // Skip the existing MANIFEST.MF
113+
}
114+
try (InputStream entryInputStream = jarFile.getInputStream(entry)) {
115+
tempJarOutputStream.putNextEntry(new JarEntry(entry.getName()));
116+
byte[] buffer = new byte[1024];
117+
int bytesRead;
118+
while ((bytesRead = entryInputStream.read(buffer)) != -1) {
119+
tempJarOutputStream.write(buffer, 0, bytesRead);
120+
}
121+
tempJarOutputStream.closeEntry();
122+
}
123+
}
124+
125+
// Modify the MANIFEST.MF
126+
Manifest manifest = jarFile.getManifest();
127+
if (manifest == null) {
128+
manifest = new Manifest();
129+
}
130+
manifest.getMainAttributes().putValue("paperweight-mappings-namespace", "spigot");
131+
132+
// Write the modified MANIFEST.MF
133+
tempJarOutputStream.putNextEntry(new JarEntry(JarFile.MANIFEST_NAME));
134+
manifest.write(tempJarOutputStream);
135+
tempJarOutputStream.closeEntry();
136+
}
137+
138+
Files.move(tempJarPath, modifiedFile, StandardCopyOption.REPLACE_EXISTING);
139+
}
140+
141+
public void loadLibrary() throws Exception {
142+
try (
143+
InputStream inputStream = Objects.requireNonNull(main.getExpansionClassLoader().getResourceAsStream("LIB_VERSION"));
144+
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))
145+
) {
146+
String version = reader.readLine();
147+
Library lib = Library.builder()
148+
.groupId("net{}wesjd")
149+
.artifactId("anvilgui")
150+
.version(version)
151+
.repository("https://repo.codemc.io/repository/maven-public/")
152+
.build();
153+
154+
155+
Path path = saveDirectory.resolve(lib.getPath());
156+
Path parent = path.getParent();
157+
String name = path.getFileName().toString();
158+
name = name.substring(0, name.lastIndexOf('.'));
159+
160+
boolean downloaded = false;
161+
if (!Files.exists(path)) {
162+
downloadLibrary(lib);
163+
downloaded = true;
164+
}
165+
166+
Path modifiedPath = parent.resolve(name + "-modified.jar");
167+
if (downloaded || !Files.exists(modifiedPath)) {
168+
modifyManifest(path, modifiedPath);
169+
}
170+
171+
Path remappedPath = remap(modifiedPath);
172+
addToClasspath(remappedPath);
173+
}
174+
}
175+
}

src/main/java/me/hsgamer/bettergui/anvilgui/Main.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
package me.hsgamer.bettergui.anvilgui;
22

3+
import me.hsgamer.bettergui.api.addon.GetLogger;
34
import me.hsgamer.bettergui.builder.MenuBuilder;
45
import me.hsgamer.hscore.expansion.common.Expansion;
6+
import me.hsgamer.hscore.expansion.extra.expansion.DataFolder;
7+
import me.hsgamer.hscore.expansion.extra.expansion.GetClassLoader;
8+
import me.hsgamer.hscore.logger.common.LogLevel;
59

6-
public final class Main implements Expansion {
10+
public final class Main implements Expansion, GetLogger, GetClassLoader, DataFolder {
11+
@Override
12+
public boolean onLoad() {
13+
try {
14+
new LibLoader(this).loadLibrary();
15+
return true;
16+
} catch (Exception e) {
17+
getLogger().log(LogLevel.ERROR, "An error occurred while loading the library", e);
18+
return false;
19+
}
20+
}
721

822
@Override
923
public void onEnable() {

src/main/resources/LIB_VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
${anvilgui.version}

0 commit comments

Comments
 (0)