aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/moe/nea/firmament
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/moe/nea/firmament')
-rw-r--r--src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java173
-rw-r--r--src/main/java/moe/nea/firmament/init/MixinPlugin.java5
-rw-r--r--src/main/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java14
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java29
4 files changed, 177 insertions, 44 deletions
diff --git a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java
new file mode 100644
index 0000000..e3644c0
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java
@@ -0,0 +1,173 @@
+package moe.nea.firmament.init;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class AutoDiscoveryPlugin {
+ private static final List<AutoDiscoveryPlugin> mixinPlugins = new ArrayList<>();
+
+ public static List<AutoDiscoveryPlugin> getMixinPlugins() {
+ return mixinPlugins;
+ }
+
+ private String mixinPackage;
+
+ public void setMixinPackage(String mixinPackage) {
+ this.mixinPackage = mixinPackage;
+ mixinPlugins.add(this);
+ }
+
+ /**
+ * Resolves the base class root for a given class URL. This resolves either the JAR root, or the class file root.
+ * In either case the return value of this + the class name will resolve back to the original class url, or to other
+ * class urls for other classes.
+ */
+ public URL getBaseUrlForClassUrl(URL classUrl) {
+ String string = classUrl.toString();
+ if (classUrl.getProtocol().equals("jar")) {
+ try {
+ return new URL(string.substring(4).split("!")[0]);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ if (string.endsWith(".class")) {
+ try {
+ return new URL(string.replace("\\", "/")
+ .replace(getClass().getCanonicalName()
+ .replace(".", "/") + ".class", ""));
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return classUrl;
+ }
+
+ /**
+ * Get the package that contains all the mixins. This value is set using {@link #setMixinPackage}.
+ */
+ public String getMixinPackage() {
+ return mixinPackage;
+ }
+
+ /**
+ * Get the path inside the class root to the mixin package
+ */
+ public String getMixinBaseDir() {
+ return mixinPackage.replace(".", "/");
+ }
+
+ /**
+ * A list of all discovered mixins.
+ */
+ private List<String> mixins = null;
+
+ /**
+ * Try to add mixin class ot the mixins based on the filepath inside of the class root.
+ * Removes the {@code .class} file suffix, as well as the base mixin package.
+ * <p><b>This method cannot be called after mixin initialization.</p>
+ *
+ * @param className the name or path of a class to be registered as a mixin.
+ */
+ public void tryAddMixinClass(String className) {
+ if (!className.endsWith(".class")) return;
+ String norm = (className.substring(0, className.length() - ".class".length()))
+ .replace("\\", "/")
+ .replace("/", ".");
+ if (norm.startsWith(getMixinPackage() + ".") && !norm.endsWith(".")) {
+ mixins.add(norm.substring(getMixinPackage().length() + 1));
+ }
+ }
+
+ private void tryDiscoverFromContentFile(URL url) {
+ Path file;
+ try {
+ file = Paths.get(getBaseUrlForClassUrl(url).toURI());
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("Base directory found at " + file);
+ if (!Files.exists(file)) {
+ System.out.println("Skipping non-existing mixin root: " + file);
+ return;
+ }
+ if (Files.isDirectory(file)) {
+ walkDir(file);
+ } else {
+ walkJar(file);
+ }
+ System.out.println("Found mixins: " + mixins);
+
+ }
+
+ /**
+ * Search through the JAR or class directory to find mixins contained in {@link #getMixinPackage()}
+ */
+ public List<String> getMixins() {
+ if (mixins != null) return mixins;
+ System.out.println("Trying to discover mixins");
+ mixins = new ArrayList<>();
+ URL classUrl = getClass().getProtectionDomain().getCodeSource().getLocation();
+ System.out.println("Found classes at " + classUrl);
+ tryDiscoverFromContentFile(classUrl);
+ var classRoots = System.getProperty("firmament.classroots");
+ if (classRoots != null && !classRoots.isBlank()) {
+ System.out.println("Found firmament class roots: " + classRoots);
+ for (String s : classRoots.split(File.pathSeparator)) {
+ if (s.isBlank()) {
+ continue;
+ }
+ try {
+ tryDiscoverFromContentFile(new File(s).toURI().toURL());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return mixins;
+ }
+
+ /**
+ * Search through directory for mixin classes based on {@link #getMixinBaseDir}.
+ *
+ * @param classRoot The root directory in which classes are stored for the default package.
+ */
+ private void walkDir(Path classRoot) {
+ System.out.println("Trying to find mixins from directory");
+ try (Stream<Path> classes = Files.walk(classRoot.resolve(getMixinBaseDir()))) {
+ classes.map(it -> classRoot.relativize(it).toString())
+ .forEach(this::tryAddMixinClass);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Read through a JAR file, trying to find all mixins inside.
+ */
+ private void walkJar(Path file) {
+ System.out.println("Trying to find mixins from jar file");
+ try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(file))) {
+ ZipEntry next;
+ while ((next = zis.getNextEntry()) != null) {
+ tryAddMixinClass(next.getName());
+ zis.closeEntry();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/moe/nea/firmament/init/MixinPlugin.java b/src/main/java/moe/nea/firmament/init/MixinPlugin.java
index ea8709b..e7a02b5 100644
--- a/src/main/java/moe/nea/firmament/init/MixinPlugin.java
+++ b/src/main/java/moe/nea/firmament/init/MixinPlugin.java
@@ -12,9 +12,12 @@ import java.util.Set;
public class MixinPlugin implements IMixinConfigPlugin {
+ AutoDiscoveryPlugin autoDiscoveryPlugin = new AutoDiscoveryPlugin();
+
@Override
public void onLoad(String mixinPackage) {
MixinExtrasBootstrap.init();
+ autoDiscoveryPlugin.setMixinPackage(mixinPackage);
}
@Override
@@ -37,7 +40,7 @@ public class MixinPlugin implements IMixinConfigPlugin {
@Override
public List<String> getMixins() {
- return null;
+ return autoDiscoveryPlugin.getMixins();
}
@Override
diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java b/src/main/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java
deleted file mode 100644
index b759204..0000000
--- a/src/main/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package moe.nea.firmament.mixins.accessor.sodium;
-
-import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
-import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Pseudo;
-import org.spongepowered.asm.mixin.gen.Accessor;
-
-@Mixin(SodiumWorldRenderer.class)
-@Pseudo
-public interface AccessorSodiumWorldRenderer {
- @Accessor("renderSectionManager")
- RenderSectionManager getRenderSectionManager_firmament();
-}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java
deleted file mode 100644
index 90f20bc..0000000
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package moe.nea.firmament.mixins.custommodels;
-
-import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
-import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
-import com.llamalad7.mixinextras.sugar.Local;
-import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;
-import moe.nea.firmament.features.texturepack.CustomBlockTextures;
-import net.minecraft.block.BlockState;
-import net.minecraft.client.render.block.BlockModels;
-import net.minecraft.client.render.model.BakedModel;
-import net.minecraft.util.math.BlockPos;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-
-@Mixin(ChunkBuilderMeshingTask.class)
-public class PatchBlockModelInSodiumChunkGenerator {
- @WrapOperation(
- method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;"))
- private BakedModel replaceBlockModel(BlockModels instance, BlockState state, Operation<BakedModel> original,
- @Local(name = "blockPos") BlockPos.Mutable pos) {
- var replacement = CustomBlockTextures.getReplacementModel(state, pos);
- if (replacement != null) return replacement;
- CustomBlockTextures.enterFallbackCall();
- var fallback = original.call(instance, state);
- CustomBlockTextures.exitFallbackCall();
- return fallback;
- }
-}