Skip to content

Commit

Permalink
Coremods
Browse files Browse the repository at this point in the history
  • Loading branch information
shartte committed Apr 5, 2024
1 parent c100c42 commit 65419b5
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 51 deletions.
20 changes: 20 additions & 0 deletions coremods/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
id 'java-library'
}

repositories {
mavenLocal()
maven { url = 'https://maven.neoforged.net/releases' }
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(project.java_version))
}
}

dependencies {
compileOnly "org.jetbrains:annotations:${project.jetbrains_annotations_version}"
implementation "net.neoforged.fancymodloader:spi:${project.fancy_mod_loader_version}"
implementation "cpw.mods:modlauncher:${project.modlauncher_version}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package net.neoforged.neoforge.coremods;

import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.ITransformerVotingContext;
import cpw.mods.modlauncher.api.TransformerVoteResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;

import java.lang.reflect.Modifier;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class FieldToMethod implements ITransformer<ClassNode> {
private final Map<String, String> fieldToMethod;
private final Set<Target> targets;

public FieldToMethod(String className, Map<String, String> fieldToMethod) {
this.targets = Set.of(Target.targetClass(className));
this.fieldToMethod = fieldToMethod;
}

@Override
public @NotNull ClassNode transform(ClassNode input, ITransformerVotingContext context) {
for (var entry : fieldToMethod.entrySet()) {
redirectFieldToMethod(input, entry.getKey(), entry.getValue());
}

return input;
}

@Override
public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) {
return TransformerVoteResult.YES;
}

@Override
public @NotNull Set<Target> targets() {
return targets;
}

/**
* Rewrites accesses to a specific field in the given class to a method-call.
* <p>
* The field specified by fieldName must be private and non-static.
* The method-call the field-access is redirected to does not take any parameters and returns an object of the
* same type as the field.
* If no methodName is passed, any method matching the described signature will be used as callable method.
*
* @param classNode the class to rewrite the accesses in
* @param fieldName the field accesses should be redirected to
* @param methodName the name of the method to redirect accesses through,
* or null if any method with matching signature should be applicable
*/
private static void redirectFieldToMethod(final ClassNode classNode, final String fieldName, @Nullable final String methodName) {
MethodNode foundMethod = null;
FieldNode foundField = null;
for (FieldNode fieldNode : classNode.fields) {
if (Objects.equals(fieldNode.name, fieldName)) {
if (foundField == null) {
foundField = fieldNode;
} else {
throw new IllegalStateException("Found multiple fields with name " + fieldName);
}
}
}

if (foundField == null) {
throw new IllegalStateException("No field with name " + fieldName + " found");
}
if (!Modifier.isPrivate(foundField.access) || Modifier.isStatic(foundField.access)) {
throw new IllegalStateException("Field " + fieldName + " is not private and an instance field");
}

final String methodSignature = "()" + foundField.desc;

for (MethodNode methodNode : classNode.methods) {
if (Objects.equals(methodNode.desc, methodSignature)) {
if (foundMethod == null && Objects.equals(methodNode.name, methodName)) {
foundMethod = methodNode;
} else if (foundMethod == null && methodName == null) {
foundMethod = methodNode;
} else if (foundMethod != null && (methodName == null || Objects.equals(methodNode.name, methodName))) {
throw new IllegalStateException("Found duplicate method with signature " + methodSignature);
}
}
}

if (foundMethod == null) {
throw new IllegalStateException("Unable to find method " + methodSignature);
}

for (MethodNode methodNode : classNode.methods) {
// skip the found getter method
if (methodNode == foundMethod) continue;
if (!Objects.equals(methodNode.desc, methodSignature)) {
final ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode insnNode = iterator.next();
if (insnNode.getOpcode() == Opcodes.GETFIELD) {
FieldInsnNode fieldInsnNode = (FieldInsnNode) insnNode;
if (Objects.equals(fieldInsnNode.name, fieldName)) {
iterator.remove();
MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKEVIRTUAL, classNode.name, foundMethod.name, foundMethod.desc, false);
iterator.add(replace);
}
}
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.neoforged.neoforge.coremods;

import cpw.mods.modlauncher.api.ITransformer;
import net.neoforged.neoforgespi.coremod.ICoreMod;

import java.util.List;
import java.util.Map;

public class NeoForgeCoreMod implements ICoreMod {
@Override
public Iterable<? extends ITransformer<?>> getTransformers() {
return List.of(
new FieldToMethod("net.minecraft.world.level.biome.Biome", Map.of(
"climateSettings", "getModifiedClimateSettings",
"specialEffects", "getModifiedSpecialEffects"
)),
new FieldToMethod("net.minecraft.world.level.levelgen.structure.Structure", Map.of(
"settings", "getModifiedStructureSettings"
)),
new FieldToMethod("net.minecraft.world.level.block.LiquidBlock", Map.of(
"fluid", "getFluid"
)),
new FieldToMethod("net.minecraft.world.item.BucketItem", Map.of(
"content", "getFluid"
)),
new FieldToMethod("net.minecraft.world.level.block.StairBlock", Map.of(
"base", "getModelBlock"
)),
new FieldToMethod("net.minecraft.world.level.block.FlowerPotBlock", Map.of(
"potted", "getPotted"
))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
net.neoforged.neoforge.coremods.NeoForgeCoreMod
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jetbrains_annotations_version=24.0.1
slf4j_api_version=2.0.7
apache_maven_artifact_version=3.8.5
jarjar_version=0.4.0
fancy_mod_loader_version=2.0.17
fancy_mod_loader_version=2.0.31-jcm
mojang_logging_version=1.1.1
log4j_version=2.19.0
guava_version=31.1.2-jre
Expand Down
4 changes: 4 additions & 0 deletions projects/neoforge/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ dependencies {
userdevCompileOnly jarJar("io.github.llamalad7:mixinextras-neoforge:${project.mixin_extras_version}"), {
jarJar.ranged(it, "[${project.mixin_extras_version},)")
}

userdevCompileOnly jarJar(project(":coremods")), {
jarJar.ranged(it, project.version)
}
}

runTypes {
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ include ':tests'
project(":tests").projectDir = file("tests")

include ':testframework'
include ':coremods'
6 changes: 0 additions & 6 deletions src/main/resources/META-INF/coremods.json

This file was deleted.

44 changes: 0 additions & 44 deletions src/main/resources/coremods/add_bouncer_method.js

This file was deleted.

0 comments on commit 65419b5

Please sign in to comment.