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 1f66ee9
Show file tree
Hide file tree
Showing 21 changed files with 200 additions and 72 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'
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import net.neoforged.neoforgespi.language.IModInfo;

public class ConfigScreenHandler {
public record ConfigScreenFactory(BiFunction<Minecraft, Screen, Screen> screenFunction) implements IExtensionPoint<ConfigScreenFactory> {}
public record ConfigScreenFactory(BiFunction<Minecraft, Screen, Screen> screenFunction) implements IExtensionPoint {}

public static Optional<BiFunction<Minecraft, Screen, Screen>> getScreenFactoryFor(IModInfo selectedMod) {
return ModList.get().getModContainerById(selectedMod.getModId()).flatMap(mc -> mc.getCustomExtension(ConfigScreenFactory.class).map(ConfigScreenFactory::screenFunction));
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.CrashReportCallables;
import net.neoforged.fml.IExtensionPoint;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.ModLoader;
import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.ModLoadingStage;
import net.neoforged.fml.ModLoadingWarning;
import net.neoforged.fml.StartupMessageManager;
Expand Down Expand Up @@ -617,13 +615,12 @@ public NeoForgeMod(IEventBus modEventBus, Dist dist, ModContainer container) {
CONDITION_CODECS.register(modEventBus);
GLOBAL_LOOT_MODIFIER_SERIALIZERS.register(modEventBus);
NeoForge.EVENT_BUS.addListener(this::serverStopping);
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, NeoForgeConfig.clientSpec);
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, NeoForgeConfig.serverSpec);
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, NeoForgeConfig.commonSpec);
container.registerConfig(ModConfig.Type.CLIENT, NeoForgeConfig.clientSpec);
container.registerConfig(ModConfig.Type.SERVER, NeoForgeConfig.serverSpec);
container.registerConfig(ModConfig.Type.COMMON, NeoForgeConfig.commonSpec);
modEventBus.register(NeoForgeConfig.class);
NeoForgeRegistriesSetup.setup(modEventBus);
// Forge does not display problems when the remote is not matching.
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> "ANY", (remote, isServer) -> true));
StartupMessageManager.addModMessage("NeoForge version " + NeoForgeVersion.getVersion());

NeoForge.EVENT_BUS.addListener(VillagerTradingManager::loadTrades);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import cpw.mods.modlauncher.api.LambdaExceptionUtils;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -69,7 +69,7 @@ public CompletableFuture<?> run(CachedOutput cache) {

ImmutableList.Builder<CompletableFuture<?>> futuresBuilder = new ImmutableList.Builder<>();

toSerialize.forEach(LamdbaExceptionUtils.rethrowBiConsumer((name, json) -> {
toSerialize.forEach(LambdaExceptionUtils.rethrowBiConsumer((name, json) -> {
entries.add(new ResourceLocation(modid, name));
Path modifierPath = modifierFolderPath.resolve(name + ".json");
futuresBuilder.add(DataProvider.saveStable(cache, json, modifierPath));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

package net.neoforged.neoforge.data.event;

import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import cpw.mods.modlauncher.api.LambdaExceptionUtils;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -126,7 +126,7 @@ public DataGenerator makeGenerator(final Function<Path, Path> pathEnhancer, fina
public void runAll() {
Map<Path, List<DataGenerator>> paths = generators.stream().collect(Collectors.groupingBy(gen -> gen.getPackOutput().getOutputFolder(), LinkedHashMap::new, Collectors.toList()));

paths.values().forEach(LamdbaExceptionUtils.rethrowConsumer(lst -> {
paths.values().forEach(LambdaExceptionUtils.rethrowConsumer(lst -> {
DataGenerator parent = lst.get(0);
for (int x = 1; x < lst.size(); x++)
lst.get(x).getProvidersView().forEach((name, provider) -> parent.addProvider(true, provider));
Expand Down
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.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.mojang.logging.LogUtils;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import cpw.mods.modlauncher.api.LambdaExceptionUtils;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.invoke.MethodHandle;
Expand Down Expand Up @@ -64,7 +64,7 @@ public static List<Test> forClassesWithAnnotation(ModContainer container, Class<
final Type annType = Type.getType(annotation);
return container.getModInfo().getOwningFile().getFile().getScanResult()
.getAnnotations().stream().filter(it -> annType.equals(it.annotationType()) && it.targetType() == ElementType.TYPE && SIDE_FILTER.test(it))
.map(LamdbaExceptionUtils.rethrowFunction(annotationData -> {
.map(LambdaExceptionUtils.rethrowFunction(annotationData -> {
final Class<?> clazz = Class.forName(annotationData.clazz().getClassName());
return (Test) clazz.getDeclaredConstructor().newInstance();
})).toList();
Expand Down Expand Up @@ -119,7 +119,7 @@ public static SetMultimap<OnInit.Stage, Consumer<MutableTestFramework>> onInitMe
final SetMultimap<OnInit.Stage, Consumer<MutableTestFramework>> set = Multimaps.newSetMultimap(new EnumMap<>(OnInit.Stage.class), HashSet::new);
findMethodsWithAnnotation(container, d -> true, OnInit.class)
.filter(method -> Modifier.isStatic(method.getModifiers()) && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(TestFrameworkImpl.class))
.forEach(LamdbaExceptionUtils.rethrowConsumer(method -> {
.forEach(LambdaExceptionUtils.rethrowConsumer(method -> {
final MethodHandle handle = ReflectionUtils.handle(method);
set.put(method.getAnnotation(OnInit.class).value(), framework -> {
try {
Expand All @@ -142,7 +142,7 @@ public static void templatesWithAnnotation(final ModContainer container, BiConsu
container.getModInfo().getOwningFile().getFile().getScanResult()
.getAnnotations().stream()
.filter(it -> it.targetType() == ElementType.FIELD && it.annotationType().equals(regStrTemplate))
.map(LamdbaExceptionUtils.rethrowFunction(data -> Class.forName(data.clazz().getClassName()).getDeclaredField(data.memberName())))
.map(LambdaExceptionUtils.rethrowFunction(data -> Class.forName(data.clazz().getClassName()).getDeclaredField(data.memberName())))
.filter(it -> Modifier.isStatic(it.getModifiers()) && (StructureTemplate.class.isAssignableFrom(it.getType()) || Supplier.class.isAssignableFrom(it.getType())))
.forEach(field -> {
try {
Expand Down Expand Up @@ -170,7 +170,7 @@ public static void groupsWithAnnotation(ModContainer container, Consumer<GroupDa
final Type asmType = Type.getType(TestGroup.class);
container.getModInfo().getOwningFile().getFile().getScanResult()
.getAnnotations().stream().filter(it -> asmType.equals(it.annotationType()))
.forEach(LamdbaExceptionUtils.rethrowConsumer(annotationData -> {
.forEach(LambdaExceptionUtils.rethrowConsumer(annotationData -> {
final Class<?> clazz = Class.forName(annotationData.clazz().getClassName());
final Field field = clazz.getDeclaredField(annotationData.memberName());
final String groupId = (String) field.get(null);
Expand All @@ -195,7 +195,7 @@ public static Stream<Method> findMethodsWithAnnotation(ModContainer container, P
return container.getModInfo().getOwningFile().getFile().getScanResult()
.getAnnotations().stream().filter(it -> annType.equals(it.annotationType()) && it.targetType() == ElementType.METHOD && annotationPredicate.test(it))
.filter(it -> !excludedSides.contains(it.clazz().getClassName()))
.map(LamdbaExceptionUtils.rethrowFunction(annotationData -> {
.map(LambdaExceptionUtils.rethrowFunction(annotationData -> {
final Class<?> clazz = Class.forName(annotationData.clazz().getClassName());
final String methodName = annotationData.memberName().substring(0, annotationData.memberName().indexOf("("));
return ReflectionUtils.methodMatching(clazz, it -> it.getName().equals(methodName) && it.getAnnotation(annotation) != null);
Expand Down
Loading

0 comments on commit 1f66ee9

Please sign in to comment.