Skip to content

Commit

Permalink
Allow only one public mod constructor. Add Dist as injected parameter. (
Browse files Browse the repository at this point in the history
  • Loading branch information
Technici4n authored Nov 2, 2023
1 parent e29afa5 commit c299bf4
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 35 deletions.
Empty file modified gradlew
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package net.neoforged.fml.javafmlmod;

import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.EventBusErrorMessage;
import net.neoforged.bus.api.BusBuilder;
import net.neoforged.bus.api.Event;
Expand All @@ -14,6 +15,7 @@
import net.neoforged.fml.ModLoadingException;
import net.neoforged.fml.ModLoadingStage;
import net.neoforged.fml.event.IModBusEvent;
import net.neoforged.fml.loading.FMLLoader;
import net.neoforged.neoforgespi.language.IModInfo;
import net.neoforged.neoforgespi.language.ModFileScanData;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -70,45 +72,42 @@ private void constructMod()
try
{
LOGGER.trace(LOADING, "Loading mod instance {} of type {}", getModId(), modClass.getName());
try {
// Try noargs constructor first
this.modInstance = modClass.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException ignored) {
// Otherwise look for constructor that can accept more arguments
Map<Class<?>, Object> allowedConstructorArgs = Map.of(
IEventBus.class, eventBus,
ModContainer.class, this,
FMLModContainer.class, this);

constructorsLoop: for (var constructor : modClass.getDeclaredConstructors()) {
var parameterTypes = constructor.getParameterTypes();
Object[] constructorArgs = new Object[parameterTypes.length];
Set<Class<?>> foundArgs = new HashSet<>();

for (int i = 0; i < parameterTypes.length; i++) {
Object argInstance = allowedConstructorArgs.get(parameterTypes[i]);
if (argInstance == null) {
// Unknown argument, try next constructor method...
continue constructorsLoop;
}

if (foundArgs.contains(parameterTypes[i])) {
throw new RuntimeException("Duplicate constructor argument type: " + parameterTypes[i]);
}

foundArgs.add(parameterTypes[i]);
constructorArgs[i] = argInstance;
}

// All arguments are found
this.modInstance = constructor.newInstance(constructorArgs);
}

if (this.modInstance == null) {
throw new RuntimeException("Could not find mod constructor. Allowed optional argument classes: " +
var constructors = modClass.getConstructors();
if (constructors.length != 1) {
throw new RuntimeException("Mod class must have exactly 1 public constructor, found " + constructors.length);
}
var constructor = constructors[0];

// Allowed arguments for injection via constructor
Map<Class<?>, Object> allowedConstructorArgs = Map.of(
IEventBus.class, eventBus,
ModContainer.class, this,
FMLModContainer.class, this,
Dist.class, FMLLoader.getDist());

var parameterTypes = constructor.getParameterTypes();
Object[] constructorArgs = new Object[parameterTypes.length];
Set<Class<?>> foundArgs = new HashSet<>();

for (int i = 0; i < parameterTypes.length; i++) {
Object argInstance = allowedConstructorArgs.get(parameterTypes[i]);
if (argInstance == null) {
throw new RuntimeException("Mod constructor has unsupported argument " + parameterTypes[i] + ". Allowed optional argument classes: " +
allowedConstructorArgs.keySet().stream().map(Class::getSimpleName).collect(Collectors.joining(", ")));
}

if (foundArgs.contains(parameterTypes[i])) {
throw new RuntimeException("Duplicate mod constructor argument type: " + parameterTypes[i]);
}

foundArgs.add(parameterTypes[i]);
constructorArgs[i] = argInstance;
}

// All arguments are found
this.modInstance = constructor.newInstance(constructorArgs);

LOGGER.trace(LOADING, "Loaded mod instance {} of type {}", getModId(), modClass.getName());
}
catch (Throwable e)
Expand Down

0 comments on commit c299bf4

Please sign in to comment.