Skip to content

Commit

Permalink
Add task to generate finalizeSpawn MethodRedirector coremod targets (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Technici4n authored Dec 12, 2024
1 parent 368e69f commit 4d3958a
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check-local-changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
run: ./gradlew generatePackageInfos

- name: Gen patches and ATs
run: ./gradlew :neoforge:genPatches :neoforge:generateAccessTransformers
run: ./gradlew :neoforge:genPatches :neoforge:generateAccessTransformers :neoforge:generateFinalizeSpawnTargets

- name: Run datagen with Gradle
run: ./gradlew :neoforge:runData :tests:runData
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package net.neoforged.neodev;

import com.google.gson.GsonBuilder;
import net.neoforged.neodev.utils.AsmUtils;
import net.neoforged.neodev.utils.FileUtils;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
* This task is used to generate targets for the finalizeSpawn MethodRedirector coremod.
*/
public abstract class GenerateFinalizeSpawnTargets extends DefaultTask {
@InputFile
public abstract RegularFileProperty getInput();

@OutputFile
public abstract RegularFileProperty getOutput();

@TaskAction
public void exec() throws IOException {
var visitor = new Visitor();
AsmUtils.visitAllClasses(
getInput().getAsFile().get(),
visitor,
ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);

var classList = List.copyOf(visitor.matchedClasses);

FileUtils.writeStringSafe(
getOutput().getAsFile().get().toPath(),
new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create().toJson(classList),
StandardCharsets.UTF_8);
}

static class Visitor extends ClassVisitor {
final Set<String> matchedClasses = new TreeSet<>();
String currentClass = null;

protected Visitor() {
super(Opcodes.ASM9);
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
currentClass = name;
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
// Ignore these classes as we special case them
if (currentClass.equals("net/minecraft/world/level/BaseSpawner")
|| currentClass.equals("net/minecraft/world/level/block/entity/trialspawner/TrialSpawner")) {
return null;
}

return new MethodVisitor(api) {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
if (opcode == Opcodes.INVOKEVIRTUAL
&& name.equals("finalizeSpawn")
&& descriptor.equals("(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;")) {
matchedClasses.add(currentClass);
}
}
};
}
}
}
27 changes: 27 additions & 0 deletions buildSrc/src/main/java/net/neoforged/neodev/utils/AsmUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.neoforged.neodev.utils;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;

import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;

public final class AsmUtils {
private AsmUtils() {}

public static void visitAllClasses(File jarFile, ClassVisitor visitor, int parsingOptions) throws IOException {
try (var zip = new ZipFile(jarFile)) {
var entries = zip.entries();
while (entries.hasMoreElements()) {
var next = entries.nextElement();
if (next.isDirectory() || !next.getName().endsWith(".class")) continue;

try (var in = zip.getInputStream(next)) {
var reader = new ClassReader(in);
reader.accept(visitor, parsingOptions);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.neoforged.neodev.utils.structure;

import net.neoforged.neodev.utils.AsmUtils;
import org.apache.commons.lang3.mutable.MutableInt;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
Expand All @@ -13,7 +14,6 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipFile;

public final class ClassStructureVisitor extends ClassVisitor {
private final Map<String, ClassInfo> classes;
Expand All @@ -26,19 +26,10 @@ private ClassStructureVisitor(Map<String, ClassInfo> classes) {

public static Map<String, ClassInfo> readJar(File file) throws IOException {
var map = new HashMap<String, ClassInfo>();
var visitor = new ClassStructureVisitor(map);
try (var zip = new ZipFile(file)) {
var entries = zip.entries();
while (entries.hasMoreElements()) {
var next = entries.nextElement();
if (next.isDirectory() || !next.getName().endsWith(".class")) continue;

try (var in = zip.getInputStream(next)) {
var reader = new ClassReader(in);
reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
}
}
}
AsmUtils.visitAllClasses(
file,
new ClassStructureVisitor(map),
ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return map;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
[
"net/minecraft/server/commands/RaidCommand",
"net/minecraft/server/commands/SummonCommand",
"net/minecraft/world/entity/EntityType",
"net/minecraft/world/entity/ai/village/VillageSiege",
"net/minecraft/world/entity/animal/frog/Tadpole",
"net/minecraft/world/entity/animal/horse/SkeletonTrapGoal",
"net/minecraft/world/entity/monster/Evoker$EvokerSummonSpellGoal",
"net/minecraft/world/entity/monster/Spider",
"net/minecraft/world/entity/monster/Strider",
"net/minecraft/world/entity/monster/Zombie",
"net/minecraft/world/entity/monster/ZombieVillager",
"net/minecraft/world/entity/npc/CatSpawner",
"net/minecraft/world/entity/npc/Villager",
"net/minecraft/world/entity/raid/Raid",
"net/minecraft/world/level/NaturalSpawner",
"net/minecraft/world/level/levelgen/PatrolSpawner",
"net/minecraft/world/level/levelgen/PhantomSpawner",
"net/minecraft/world/level/levelgen/structure/structures/OceanMonumentPieces$OceanMonumentPiece",
"net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces$OceanRuinPiece",
"net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece",
"net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces$WoodlandMansionPiece",
"net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate"
"net/minecraft/server/commands/RaidCommand",
"net/minecraft/server/commands/SummonCommand",
"net/minecraft/world/entity/EntityType",
"net/minecraft/world/entity/ai/village/VillageSiege",
"net/minecraft/world/entity/animal/frog/Tadpole",
"net/minecraft/world/entity/animal/horse/SkeletonTrapGoal",
"net/minecraft/world/entity/monster/Evoker$EvokerSummonSpellGoal",
"net/minecraft/world/entity/monster/Spider",
"net/minecraft/world/entity/monster/Strider",
"net/minecraft/world/entity/monster/Zombie",
"net/minecraft/world/entity/monster/ZombieVillager",
"net/minecraft/world/entity/npc/CatSpawner",
"net/minecraft/world/entity/npc/Villager",
"net/minecraft/world/entity/raid/Raid",
"net/minecraft/world/level/NaturalSpawner",
"net/minecraft/world/level/levelgen/PatrolSpawner",
"net/minecraft/world/level/levelgen/PhantomSpawner",
"net/minecraft/world/level/levelgen/structure/structures/OceanMonumentPieces$OceanMonumentPiece",
"net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces$OceanRuinPiece",
"net/minecraft/world/level/levelgen/structure/structures/SwampHutPiece",
"net/minecraft/world/level/levelgen/structure/structures/WoodlandMansionPieces$WoodlandMansionPiece",
"net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate"
]
8 changes: 8 additions & 0 deletions projects/neoforge/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import net.neoforged.jarcompatibilitychecker.gradle.JCCPlugin
import net.neoforged.jarcompatibilitychecker.gradle.CompatibilityTask
import net.neoforged.jarcompatibilitychecker.gradle.ProvideNeoForgeJarTask
import net.neoforged.neodev.GenerateFinalizeSpawnTargets

plugins {
id 'java-library'
Expand Down Expand Up @@ -222,6 +223,13 @@ generateAccessTransformers {
)
}

tasks.register("generateFinalizeSpawnTargets", GenerateFinalizeSpawnTargets.class) {
group generateAccessTransformers.group
description "Generate the targets for the finalizeSpawn MethodRedirector coremod"
input = generateAccessTransformers.input
output = rootProject.file("coremods/src/main/resources/net/neoforged/neoforge/coremods/finalize_spawn_targets.json")
}

tasks.withType(JavaCompile.class).configureEach {
// Increase memory used during compilation, to avoid OutOfMemoryErrors
options.forkOptions.memoryMaximumSize = '2g'
Expand Down

0 comments on commit 4d3958a

Please sign in to comment.