From 02cdf8266f7c6a97b6a30c43be319baf0484de43 Mon Sep 17 00:00:00 2001
From: thedarkcolour <30441001+thedarkcolour@users.noreply.github.com>
Date: Fri, 15 May 2026 18:25:24 -0700
Subject: [PATCH] Fixed coremods, removed obsolete end portal patch
---
coremod/build.gradle | 5 +-
.../exdeorum/coremod/ASMTransformer.java | 162 ------------------
.../DedicatedServerPropertiesTransformer.java | 49 ++++++
.../coremod/EndCityStructureTransformer.java | 51 ++++++
.../exdeorum/coremod/ExDeorumASM.java | 35 ++++
...net.neoforged.neoforgespi.coremod.ICoreMod | 1 -
....neoforgespi.transformation.ClassProcessor | 2 +
.../thedarkcolour/exdeorum/asm/ASMHooks.java | 16 +-
8 files changed, 141 insertions(+), 180 deletions(-)
delete mode 100644 coremod/src/main/java/thedarkcolour/exdeorum/coremod/ASMTransformer.java
create mode 100644 coremod/src/main/java/thedarkcolour/exdeorum/coremod/DedicatedServerPropertiesTransformer.java
create mode 100644 coremod/src/main/java/thedarkcolour/exdeorum/coremod/EndCityStructureTransformer.java
create mode 100644 coremod/src/main/java/thedarkcolour/exdeorum/coremod/ExDeorumASM.java
delete mode 100644 coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod
create mode 100644 coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.transformation.ClassProcessor
diff --git a/coremod/build.gradle b/coremod/build.gradle
index 8c68115b..e14e729e 100644
--- a/coremod/build.gradle
+++ b/coremod/build.gradle
@@ -2,7 +2,7 @@ plugins {
id 'java'
}
-java.toolchain.languageVersion = JavaLanguageVersion.of(21)
+java.toolchain.languageVersion = JavaLanguageVersion.of(25)
java.toolchain.vendor = JvmVendorSpec.JETBRAINS
jar {
@@ -27,6 +27,5 @@ repositories {
}
dependencies {
- compileOnly 'net.neoforged.fancymodloader:loader:4.0.15'
- compileOnly 'org.jetbrains:annotations:24.1.0'
+ compileOnly 'net.neoforged.fancymodloader:loader:11.0.13'
}
\ No newline at end of file
diff --git a/coremod/src/main/java/thedarkcolour/exdeorum/coremod/ASMTransformer.java b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/ASMTransformer.java
deleted file mode 100644
index 0e16f73e..00000000
--- a/coremod/src/main/java/thedarkcolour/exdeorum/coremod/ASMTransformer.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Ex Deorum
- * Copyright (c) 2024 thedarkcolour
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package thedarkcolour.exdeorum.coremod;
-
-import cpw.mods.modlauncher.api.ITransformer;
-import cpw.mods.modlauncher.api.ITransformerVotingContext;
-import cpw.mods.modlauncher.api.TargetType;
-import cpw.mods.modlauncher.api.TransformerVoteResult;
-import net.neoforged.coremod.api.ASMAPI;
-import net.neoforged.neoforgespi.coremod.ICoreMod;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.VarInsnNode;
-
-import java.util.List;
-import java.util.Set;
-
-public class ASMTransformer implements ICoreMod {
- @Override
- public Iterable extends ITransformer>> getTransformers() {
- return List.of(
- new EndCityStructureTransformer(),
- new DedicatedServerPropertiesTransformer(),
- new EndDragonFightTransformer()
- );
- }
-
- private interface MethodTransformer extends ITransformer {
- @Override
- default TransformerVoteResult castVote(ITransformerVotingContext context) {
- return TransformerVoteResult.YES;
- }
-
- @Override
- default TargetType getTargetType() {
- return TargetType.METHOD;
- }
- }
-
- // inserts a hook into EndCityStructure#findGenerationPoint to fix the position of the city if it is in a void world
- private static class EndCityStructureTransformer implements MethodTransformer {
- @Override
- public Set> targets() {
- return Set.of(ITransformer.Target.targetMethod(
- "net.minecraft.world.level.levelgen.structure.structures.EndCityStructure",
- "findGenerationPoint",
- "(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;)Ljava/util/Optional;"
- ));
- }
-
- //
- @Override
- public MethodNode transform(MethodNode input, ITransformerVotingContext context) {
- var insnList = input.instructions;
-
- for (var i = 0; i < insnList.size(); ++i) {
- var insn = insnList.get(i);
-
- // patch before ASTORE 3
- if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == 3) {
- insnList.insertBefore(insn, ASMAPI.listOf(
- new VarInsnNode(Opcodes.ALOAD, 1),
- new MethodInsnNode(Opcodes.INVOKESTATIC, "thedarkcolour/exdeorum/asm/ASMHooks", "adjustPos", "(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;)Lnet/minecraft/core/BlockPos;", false)
- ));
- ASMAPI.log("INFO", "Successfully patched End City generation for void worlds");
- return input;
- }
- }
-
- ASMAPI.log("ERROR", "Unable to patch End City generation, void worlds will have no end cities!!!");
- return input;
- }
- }
-
- // Redirects a field access in the constructor of DedicatedServerProperties from WorldPresets.NORMAL to ASMHooks.overrideDefaultWorldPreset()
- private static class DedicatedServerPropertiesTransformer implements MethodTransformer {
- @Override
- public Set> targets() {
- return Set.of(ITransformer.Target.targetMethod(
- "net.minecraft.server.dedicated.DedicatedServerProperties",
- "",
- "(Ljava/util/Properties;)V"
- ));
- }
-
- @Override
- public MethodNode transform(MethodNode input, ITransformerVotingContext context) {
- var insnList = input.instructions;
-
- for (var i = 0; i < insnList.size(); ++i) {
- var insn = insnList.get(i);
-
- if (insn.getOpcode() == Opcodes.GETSTATIC && (((FieldInsnNode) insn).name.equals("f_226437_") || ((FieldInsnNode) insn).name.equals("NORMAL"))) {
- var newInsn = new MethodInsnNode(Opcodes.INVOKESTATIC, "thedarkcolour/exdeorum/asm/ASMHooks", "overrideDefaultWorldPreset", "()Lnet/minecraft/resources/ResourceKey;", false);
- insnList.set(insn, newInsn);
-
- ASMAPI.log("INFO", "Successfully patched server.properties to use void world type by default");
- return input;
- }
- }
-
- ASMAPI.log("ERROR", "Unable to patch server.properties, you will have to set \"level-type\" to \"exdeorum:void_world\" manually.");
- return input;
- }
- }
-
- // Fixes heightmap issues when placing the end portal podium that would only spawn half of the portal
- // What this patch looks like in code: EndIslandPodium.place(..., this.portalLocation = ASMHooks.prePlaceEndPodium(this.portalLocation))
- private static class EndDragonFightTransformer implements MethodTransformer {
- @Override
- public Set> targets() {
- return Set.of(ITransformer.Target.targetMethod(
- "net.minecraft.world.level.dimension.end.EndDragonFight",
- "spawnExitPortal",
- "(Z)V"
- ));
- }
-
- @Override
- public MethodNode transform(MethodNode input, ITransformerVotingContext context) {
- var insnList = input.instructions;
-
- // Start at 2 to avoid null getPrevious().getPrevious()
- for (var i = 2; i < insnList.size(); ++i) {
- var insn = insnList.get(i);
-
- if (insn.getOpcode() == Opcodes.ALOAD && ((VarInsnNode) insn).var == 2) {
- insnList.insertBefore(insn, ASMAPI.listOf(
- new VarInsnNode(Opcodes.ALOAD, 0),
- new VarInsnNode(Opcodes.ALOAD, 0),
- new FieldInsnNode(Opcodes.GETFIELD, "net/minecraft/world/level/dimension/end/EndDragonFight", "portalLocation", "Lnet/minecraft/core/BlockPos;"),
- new MethodInsnNode(Opcodes.INVOKESTATIC, "thedarkcolour/exdeorum/asm/ASMHooks", "prePlaceEndPodium", "(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/core/BlockPos;", false),
- new FieldInsnNode(Opcodes.PUTFIELD, "net/minecraft/world/level/dimension/end/EndDragonFight", "portalLocation", "Lnet/minecraft/core/BlockPos;")
- ));
- ASMAPI.log("INFO", "Successfully patched end portal.");
- return input;
- }
- }
-
- ASMAPI.log("ERROR", "Unable to patch End Portal, it will not spawn properly and you will be unable to return to the overworld without cheats.");
- return input;
- }
- }
-}
diff --git a/coremod/src/main/java/thedarkcolour/exdeorum/coremod/DedicatedServerPropertiesTransformer.java b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/DedicatedServerPropertiesTransformer.java
new file mode 100644
index 00000000..ca5c9f25
--- /dev/null
+++ b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/DedicatedServerPropertiesTransformer.java
@@ -0,0 +1,49 @@
+package thedarkcolour.exdeorum.coremod;
+
+import net.neoforged.neoforgespi.transformation.ProcessorName;
+import net.neoforged.neoforgespi.transformation.SimpleMethodProcessor;
+import net.neoforged.neoforgespi.transformation.SimpleTransformationContext;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.Set;
+
+// Redirects a field access in the constructor of DedicatedServerProperties from WorldPresets.NORMAL to ASMHooks.overrideDefaultWorldPreset()
+public class DedicatedServerPropertiesTransformer extends SimpleMethodProcessor {
+ private static final ProcessorName NAME = new ProcessorName("exdeorum", "dedicated_server_properties_transformer");
+
+ @Override
+ public ProcessorName name() {
+ return NAME;
+ }
+
+ @Override
+ public Set targets() {
+ return Set.of(new Target(
+ "net.minecraft.server.dedicated.DedicatedServerProperties",
+ "",
+ "(Ljava/util/Properties;)V"
+ ));
+ }
+
+ @Override
+ public void transform(MethodNode input, SimpleTransformationContext context) {
+ var insnList = input.instructions;
+
+ for (var i = 0; i < insnList.size(); ++i) {
+ var insn = insnList.get(i);
+
+ if (insn.getOpcode() == Opcodes.GETSTATIC && (((FieldInsnNode) insn).name.equals("f_226437_") || ((FieldInsnNode) insn).name.equals("NORMAL"))) {
+ var newInsn = new MethodInsnNode(Opcodes.INVOKESTATIC, "thedarkcolour/exdeorum/asm/ASMHooks", "overrideDefaultWorldPreset", "()Lnet/minecraft/resources/ResourceKey;", false);
+ insnList.set(insn, newInsn);
+
+ ExDeorumASM.LOGGER.info("Successfully patched server.properties to use void world type by default");
+ return;
+ }
+ }
+
+ ExDeorumASM.LOGGER.error("Unable to patch server.properties, you will have to set \"level-type\" to \"exdeorum:void_world\" manually.");
+ }
+}
diff --git a/coremod/src/main/java/thedarkcolour/exdeorum/coremod/EndCityStructureTransformer.java b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/EndCityStructureTransformer.java
new file mode 100644
index 00000000..9a7353f6
--- /dev/null
+++ b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/EndCityStructureTransformer.java
@@ -0,0 +1,51 @@
+package thedarkcolour.exdeorum.coremod;
+
+import net.neoforged.neoforgespi.transformation.ProcessorName;
+import net.neoforged.neoforgespi.transformation.SimpleMethodProcessor;
+import net.neoforged.neoforgespi.transformation.SimpleTransformationContext;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.VarInsnNode;
+
+import java.util.Set;
+
+// inserts a hook into EndCityStructure#findGenerationPoint to fix the position of the city if it is in a void world
+public class EndCityStructureTransformer extends SimpleMethodProcessor {
+ private static final ProcessorName NAME = new ProcessorName("exdeorum", "end_city_structure_void_transformer");
+
+ @Override
+ public ProcessorName name() {
+ return NAME;
+ }
+
+ @Override
+ public Set targets() {
+ return Set.of(new Target(
+ "net.minecraft.world.level.levelgen.structure.structures.EndCityStructure",
+ "findGenerationPoint",
+ "(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;)Ljava/util/Optional;"
+ ));
+ }
+
+ @Override
+ public void transform(MethodNode input, SimpleTransformationContext context) {
+ var insnList = input.instructions;
+
+ for (var i = 0; i < insnList.size(); ++i) {
+ var insn = insnList.get(i);
+
+ // patch before ASTORE 3
+ if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == 3) {
+ insnList.insertBefore(insn, ExDeorumASM.insnList(
+ new VarInsnNode(Opcodes.ALOAD, 1),
+ new MethodInsnNode(Opcodes.INVOKESTATIC, "thedarkcolour/exdeorum/asm/ASMHooks", "adjustPos", "(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;)Lnet/minecraft/core/BlockPos;", false)
+ ));
+ ExDeorumASM.LOGGER.info("Successfully patched End City generation for void worlds");
+ return;
+ }
+ }
+
+ ExDeorumASM.LOGGER.error("Unable to patch End City generation, void worlds will have no end cities!!!");
+ }
+}
diff --git a/coremod/src/main/java/thedarkcolour/exdeorum/coremod/ExDeorumASM.java b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/ExDeorumASM.java
new file mode 100644
index 00000000..b88208d7
--- /dev/null
+++ b/coremod/src/main/java/thedarkcolour/exdeorum/coremod/ExDeorumASM.java
@@ -0,0 +1,35 @@
+/*
+ * Ex Deorum
+ * Copyright (c) 2024 thedarkcolour
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package thedarkcolour.exdeorum.coremod;
+
+import org.objectweb.asm.tree.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class ExDeorumASM {
+ static final Logger LOGGER = LoggerFactory.getLogger(ExDeorumASM.class);
+
+ public static InsnList insnList(AbstractInsnNode... nodes) {
+ InsnList list = new InsnList();
+ for (var node : nodes) {
+ list.add(node);
+ }
+ return list;
+ }
+}
diff --git a/coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod b/coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod
deleted file mode 100644
index 8951e244..00000000
--- a/coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod
+++ /dev/null
@@ -1 +0,0 @@
-thedarkcolour.exdeorum.coremod.ASMTransformer
\ No newline at end of file
diff --git a/coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.transformation.ClassProcessor b/coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.transformation.ClassProcessor
new file mode 100644
index 00000000..124c1630
--- /dev/null
+++ b/coremod/src/main/resources/META-INF/services/net.neoforged.neoforgespi.transformation.ClassProcessor
@@ -0,0 +1,2 @@
+thedarkcolour.exdeorum.coremod.DedicatedServerPropertiesTransformer
+thedarkcolour.exdeorum.coremod.EndCityStructureTransformer
diff --git a/src/main/java/thedarkcolour/exdeorum/asm/ASMHooks.java b/src/main/java/thedarkcolour/exdeorum/asm/ASMHooks.java
index 3e977720..2a28c45e 100644
--- a/src/main/java/thedarkcolour/exdeorum/asm/ASMHooks.java
+++ b/src/main/java/thedarkcolour/exdeorum/asm/ASMHooks.java
@@ -33,11 +33,11 @@ import thedarkcolour.exdeorum.voidworld.VoidChunkGenerator;
import java.util.Properties;
-// todo test that all of these patches still work properly
@SuppressWarnings("unused")
public final class ASMHooks {
/**
* Called in {@link net.minecraft.world.level.levelgen.structure.structures.EndCityStructure#findGenerationPoint(Structure.GenerationContext)}
+ * by {@link thedarkcolour.exdeorum.coremod.EndCityStructureTransformer}
* to fix End Cities not generating in void worlds.
*/
public static BlockPos adjustPos(BlockPos pos, Structure.GenerationContext context) {
@@ -48,21 +48,9 @@ public final class ASMHooks {
}
}
- /**
- * Called in {@link net.minecraft.world.level.dimension.end.EndDragonFight#spawnExitPortal(boolean)}
- * right before {@code EndPodiumFeature.place} is called to fix End Portal not spawning fully,
- * with part of it being generated outside the world in the void.
- */
- public static BlockPos prePlaceEndPodium(BlockPos pos) {
- if (pos.getY() < 4) {
- return pos.above(32);
- } else {
- return pos.immutable();
- }
- }
-
/**
* Called in {@link net.minecraft.server.dedicated.DedicatedServerProperties#DedicatedServerProperties(Properties)}
+ * by {@link thedarkcolour.exdeorum.coremod.DedicatedServerPropertiesTransformer}
* where {@code WorldPresets.NORMAL} is used in the line that looks like {@code WorldPresets.NORMAL.location().toString()}
*/
public static ResourceKey overrideDefaultWorldPreset() {