Separate plugin types #10
|
@ -6,16 +6,15 @@ import java.util.Optional;
|
|||
|
||||
import dev.frogmc.frogloader.api.env.Env;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogGamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogPlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.GamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.ModProvider;
|
||||
import dev.frogmc.frogloader.impl.FrogLoaderImpl;
|
||||
|
||||
/**
|
||||
* General API to interact with this loader.
|
||||
*
|
||||
* @see ModProperties
|
||||
* @see FrogPlugin
|
||||
* @see ModProvider
|
||||
* @see Env
|
||||
*/
|
||||
public interface FrogLoader {
|
||||
|
@ -34,14 +33,14 @@ public interface FrogLoader {
|
|||
*
|
||||
* @return The game plugin applicable to the current game
|
||||
*/
|
||||
FrogGamePlugin getGamePlugin();
|
||||
GamePlugin getGamePlugin();
|
||||
|
||||
/**
|
||||
* Get all loaded mod providers.
|
||||
*
|
||||
* @return A collection of all loaded mod providers
|
||||
*/
|
||||
Collection<FrogModProvider> getModProviders();
|
||||
Collection<ModProvider> getModProviders();
|
||||
|
||||
/**
|
||||
* Get the current (physical) environment.
|
||||
|
@ -103,12 +102,13 @@ public interface FrogLoader {
|
|||
*
|
||||
* @return A collection of all loaded mods
|
||||
* @see ModProperties
|
||||
* @see FrogPlugin
|
||||
* @see ModProvider
|
||||
*/
|
||||
Collection<ModProperties> getMods();
|
||||
|
||||
/**
|
||||
* Get the version of the currently loaded game
|
||||
*
|
||||
* @return The current game version
|
||||
*/
|
||||
String getGameVersion();
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package dev.frogmc.frogloader.api.plugin;
|
||||
|
||||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
|
||||
public interface FrogGamePlugin {
|
||||
default void run() {
|
||||
}
|
||||
|
||||
default boolean isApplicable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void init(FrogLoader loader) throws Exception {
|
||||
}
|
||||
|
||||
String queryVersion();
|
||||
|
||||
default ModProperties getGameMod() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package dev.frogmc.frogloader.api.plugin;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
|
||||
public interface FrogModProvider {
|
||||
String id();
|
||||
|
||||
default String loadDirectory() {
|
||||
return "mods";
|
||||
}
|
||||
|
||||
default boolean isApplicable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isFileApplicable(Path path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isDirectoryApplicable(Path path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void preLaunch(Collection<ModProperties> mods) {
|
||||
}
|
||||
|
||||
default Collection<ModProperties> loadMods(Collection<Path> modFiles) throws Exception {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package dev.frogmc.frogloader.api.plugin;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
|
||||
/**
|
||||
* A Plugin that may load mods for a specific game and environment
|
||||
*
|
||||
* @see FrogLoader
|
||||
*/
|
||||
public interface FrogPlugin {
|
||||
|
||||
/**
|
||||
* General run method of this plugin. This method is run after all plugins have been initialized.
|
||||
*
|
||||
* @see FrogPlugin#init(FrogLoader)
|
||||
* @see FrogPlugin#getMods()
|
||||
*/
|
||||
default void run() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this plugin is applicable for the current environment
|
||||
*
|
||||
* @return Whether this plugin is applicable to be loaded in the current environment
|
||||
*/
|
||||
default boolean isApplicable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization method for this plugin. This method will be called after <code>isApplicable()</code>
|
||||
* if it returns true to initialize is plugin.
|
||||
*
|
||||
* @param loader the loader loading this plugin
|
||||
* @throws Exception This method may throw any exception, it will be handled by the loader.
|
||||
* @see FrogPlugin#isApplicable()
|
||||
* @see FrogPlugin#getMods()
|
||||
*/
|
||||
default void init(FrogLoader loader) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should return all mods loaded by this plugin. It will be queried after <code>init(FrogLoader)</code>
|
||||
* and before <code>run()</code>.
|
||||
*
|
||||
* @return A collection of mods loaded by this plugin.
|
||||
* @see FrogPlugin#init(FrogLoader)
|
||||
* @see FrogPlugin#run()
|
||||
*/
|
||||
default Collection<ModProperties> getMods() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package dev.frogmc.frogloader.api.plugin;
|
||||
|
||||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A plugin responsible for loading a game.
|
||||
* Only one of these may be loaded at a time.
|
||||
* @see FrogLoader
|
||||
* @see ModProvider
|
||||
*/
|
||||
public interface GamePlugin {
|
||||
/**
|
||||
* Method to launch the game.
|
||||
* This method will be called after mods are located and loaded.
|
||||
*/
|
||||
default void run() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this plugin is applicable to be loaded in the current environment.
|
||||
* Only one plugin may be applicable at a time.
|
||||
* @return Whether this plugin is applicable to be loaded
|
||||
*/
|
||||
default boolean isApplicable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this plugin.
|
||||
* @param loader The loader currently loading this plugin
|
||||
* @throws Exception If an exception occurs during initialization. It will be handled by the loader.
|
||||
*/
|
||||
default void init(FrogLoader loader) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the version of the game of this plugin.
|
||||
* @return The version of the game loaded by this plugin
|
||||
*/
|
||||
@NotNull
|
||||
String queryVersion();
|
||||
|
||||
/**
|
||||
* Get the mod embodying the game loaded by this plugin.
|
||||
* @return A mod for the currently loaded game. May be null if no such mod shall be added.
|
||||
*/
|
||||
default ModProperties getGameMod() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package dev.frogmc.frogloader.api.plugin;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
|
||||
/**
|
||||
* A provider for mods to be loaded.
|
||||
* @see FrogLoader
|
||||
* @see GamePlugin
|
||||
* @see ModProperties
|
||||
*/
|
||||
public interface ModProvider {
|
||||
|
||||
/**
|
||||
* Get the ID of this provider. Mods will be stored separated by their provider ID.
|
||||
* @return The ID of this provider
|
||||
*/
|
||||
String id();
|
||||
Ecorous marked this conversation as resolved
|
||||
|
||||
/**
|
||||
* The directory to search in for mods. This will be resolved relative to the game directory.
|
||||
* @return The name of the mods directory, relative to the game directory
|
||||
*/
|
||||
default String loadDirectory() {
|
||||
return "mods";
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this provider is applicable to load in the current environment.
|
||||
* @return Whether this provider is applicable to load
|
||||
*/
|
||||
default boolean isApplicable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a mod file is valid to be loaded by this provider.
|
||||
* @param path The path to validate
|
||||
* @return Whether this path is valid to be loaded by this provider
|
||||
* @see #isDirectoryApplicable(Path)
|
||||
* @see #loadDirectory()
|
||||
*/
|
||||
default boolean isFileApplicable(Path path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a directory (inside the path declared by this provider's mod directory) is valid to be queried for mods
|
||||
* to be loaded by this provider.
|
||||
* @param path The directory to be validated
|
||||
* @return Whether this directory should be traversed further
|
||||
* @see #loadDirectory()
|
||||
* @see #isFileApplicable(Path)
|
||||
*/
|
||||
default boolean isDirectoryApplicable(Path path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be invoked just before the game is launched. It may be used for a pre-launch entrypoint for mods.
|
||||
* @param mods The mods loaded by this provider
|
||||
*/
|
||||
default void preLaunch(Collection<ModProperties> mods) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should load the mods found previously into their runtime representation.
|
||||
* This method should also load any nested mods
|
||||
* <p>Note: This method also needs to add mods to the classpath for them to be loaded correctly. For this, a parameter is provided.</p>
|
||||
*
|
||||
* @param modFiles The paths to be loaded by this provider
|
||||
* @param classpathAdder A consumer to easily add URLs to the classpath used to run the game on
|
||||
* @return Mods loaded by this provider
|
||||
* @throws Exception If an exception occurs during loading. It will be handled by the loader.
|
||||
*/
|
||||
default Collection<ModProperties> loadMods(Collection<Path> modFiles, Consumer<URL> classpathAdder) throws Exception {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
|
@ -14,8 +14,8 @@ import com.google.gson.Gson;
|
|||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
import dev.frogmc.frogloader.api.env.Env;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogGamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
|
||||
import dev.frogmc.frogloader.api.plugin.GamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.ModProvider;
|
||||
import dev.frogmc.frogloader.impl.gui.LoaderGui;
|
||||
import dev.frogmc.frogloader.impl.launch.MixinClassLoader;
|
||||
import dev.frogmc.frogloader.impl.mod.ModUtil;
|
||||
|
@ -37,7 +37,7 @@ public class FrogLoaderImpl implements FrogLoader {
|
|||
@Getter
|
||||
private final Env env;
|
||||
@Getter
|
||||
private final Collection<FrogModProvider> modProviders = new ArrayList<>();
|
||||
private final Collection<ModProvider> modProviders = new ArrayList<>();
|
||||
@Getter
|
||||
private final Path gameDir, configDir;
|
||||
@Getter
|
||||
|
@ -48,7 +48,7 @@ public class FrogLoaderImpl implements FrogLoader {
|
|||
private final Gson gson = new Gson();
|
||||
private final Map<String, Map<String, ModProperties>> mods = new HashMap<>();
|
||||
@Getter
|
||||
private FrogGamePlugin gamePlugin;
|
||||
private GamePlugin gamePlugin;
|
||||
@Getter
|
||||
private String gameVersion;
|
||||
private Collection<String> modIds = new ArrayList<>();
|
||||
|
@ -73,7 +73,7 @@ public class FrogLoaderImpl implements FrogLoader {
|
|||
try {
|
||||
loadGamePlugin();
|
||||
loadModProviders();
|
||||
modProviders.stream().map(FrogModProvider::loadDirectory).map(gameDir::resolve).forEach(modsDirs::add);
|
||||
modProviders.stream().map(ModProvider::loadDirectory).map(gameDir::resolve).forEach(modsDirs::add);
|
||||
advanceMixinState();
|
||||
modIds = collectModIds();
|
||||
LOGGER.info(ModUtil.getModList(getMods()));
|
||||
|
@ -105,7 +105,7 @@ public class FrogLoaderImpl implements FrogLoader {
|
|||
}
|
||||
|
||||
private void loadGamePlugin() {
|
||||
FrogGamePlugin plugin = PluginLoader.discoverGamePlugins();
|
||||
GamePlugin plugin = PluginLoader.discoverGamePlugins();
|
||||
gameVersion = plugin.queryVersion();
|
||||
ModProperties gameMod = plugin.getGameMod();
|
||||
if (gameMod != null) {
|
||||
|
|
|
@ -9,8 +9,8 @@ import java.util.stream.Collectors;
|
|||
|
||||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogGamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
|
||||
import dev.frogmc.frogloader.api.plugin.GamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.ModProvider;
|
||||
import dev.frogmc.frogloader.impl.gui.LoaderGui;
|
||||
import dev.frogmc.frogloader.impl.mixin.AWProcessor;
|
||||
import dev.frogmc.frogloader.impl.mod.BuiltinExtensions;
|
||||
|
@ -23,10 +23,10 @@ import org.spongepowered.asm.mixin.Mixins;
|
|||
public class PluginLoader {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("FrogLoader/Plugins");
|
||||
|
||||
public static void discoverModProviders(Path gameDir, Map<String, Map<String, ModProperties>> mods, Collection<String> modIds, Collection<FrogModProvider> modProviders) throws ModDependencyResolver.ResolverException {
|
||||
public static void discoverModProviders(Path gameDir, Map<String, Map<String, ModProperties>> mods, Collection<String> modIds, Collection<ModProvider> modProviders) throws ModDependencyResolver.ResolverException {
|
||||
LOGGER.info("Discovering mod providers...");
|
||||
|
||||
for (FrogModProvider plugin : ServiceLoader.load(FrogModProvider.class)) {
|
||||
for (ModProvider plugin : ServiceLoader.load(ModProvider.class)) {
|
||||
LOGGER.debug("Found mod provider: {}", plugin.getClass().getName());
|
||||
if (!plugin.isApplicable()) {
|
||||
continue;
|
||||
|
@ -34,7 +34,7 @@ public class PluginLoader {
|
|||
try {
|
||||
LOGGER.debug("Initialising mod provider: {}", plugin.id());
|
||||
Map<String, ModProperties> modsFromProvider = new HashMap<>();
|
||||
Collection<ModProperties> loadedMods = plugin.loadMods(Discovery.find(gameDir.resolve(plugin.loadDirectory()), plugin::isDirectoryApplicable, plugin::isFileApplicable));
|
||||
Collection<ModProperties> loadedMods = plugin.loadMods(Discovery.find(gameDir.resolve(plugin.loadDirectory()), plugin::isDirectoryApplicable, plugin::isFileApplicable), FrogLoaderImpl.getInstance().getClassloader()::addURL);
|
||||
initializeModMixins(loadedMods);
|
||||
AWProcessor.load(loadedMods);
|
||||
|
||||
|
@ -72,18 +72,18 @@ public class PluginLoader {
|
|||
});
|
||||
}
|
||||
|
||||
public static FrogGamePlugin discoverGamePlugins() {
|
||||
public static GamePlugin discoverGamePlugins() {
|
||||
LOGGER.info("Discovering game plugins...");
|
||||
ServiceLoader<FrogGamePlugin> loader = ServiceLoader.load(FrogGamePlugin.class);
|
||||
ServiceLoader<GamePlugin> loader = ServiceLoader.load(GamePlugin.class);
|
||||
loader.stream().map(ServiceLoader.Provider::get).forEach(p -> LOGGER.info("Found game plugin: {}", p.getClass().getName()));
|
||||
FrogGamePlugin[] applicablePlugins = ServiceLoader.load(FrogGamePlugin.class).stream().map(ServiceLoader.Provider::get).filter(FrogGamePlugin::isApplicable).toArray(FrogGamePlugin[]::new);
|
||||
GamePlugin[] applicablePlugins = ServiceLoader.load(GamePlugin.class).stream().map(ServiceLoader.Provider::get).filter(GamePlugin::isApplicable).toArray(GamePlugin[]::new);
|
||||
if (applicablePlugins.length > 1) {
|
||||
throw new IllegalStateException("Multiple applicable game plugins found!");
|
||||
} else if (applicablePlugins.length == 0) {
|
||||
throw new IllegalStateException("No applicable game plugin found!");
|
||||
}
|
||||
|
||||
FrogGamePlugin plugin = applicablePlugins[0]; // we can skip the loop as we always will only have one element
|
||||
GamePlugin plugin = applicablePlugins[0]; // we can skip the loop as we always will only have one element
|
||||
try {
|
||||
plugin.init(FrogLoader.getInstance());
|
||||
return plugin;
|
||||
|
|
|
@ -14,15 +14,16 @@ import dev.frogmc.frogloader.api.FrogLoader;
|
|||
import dev.frogmc.frogloader.api.mod.ModDependencies;
|
||||
import dev.frogmc.frogloader.api.mod.ModExtensions;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogGamePlugin;
|
||||
import dev.frogmc.frogloader.api.plugin.GamePlugin;
|
||||
import dev.frogmc.frogloader.impl.FrogLoaderImpl;
|
||||
import dev.frogmc.frogloader.impl.mod.ModPropertiesImpl;
|
||||
import dev.frogmc.frogloader.impl.util.SystemProperties;
|
||||
import dev.frogmc.thyroxine.Thyroxine;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class MinecraftGamePlugin implements FrogGamePlugin {
|
||||
public class MinecraftGamePlugin implements GamePlugin {
|
||||
|
||||
protected final String[] MINECRAFT_CLASSES = new String[]{
|
||||
"net/minecraft/client/main/Main.class",
|
||||
|
@ -126,7 +127,7 @@ public class MinecraftGamePlugin implements FrogGamePlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String queryVersion() {
|
||||
public @NotNull String queryVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,23 +2,24 @@ package dev.frogmc.frogloader.impl.plugin.mod;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import dev.frogmc.frogloader.api.FrogLoader;
|
||||
import dev.frogmc.frogloader.api.extensions.PreLaunchExtension;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
|
||||
import dev.frogmc.frogloader.impl.FrogLoaderImpl;
|
||||
import dev.frogmc.frogloader.api.plugin.ModProvider;
|
||||
import dev.frogmc.frogloader.impl.mod.BuiltinExtensions;
|
||||
import dev.frogmc.frogloader.impl.mod.ModPropertiesReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class FrogmodModProvider implements FrogModProvider {
|
||||
public class FrogModProvider implements ModProvider {
|
||||
|
||||
public static final String MOD_FILE_EXTENSION = ".frogmod";
|
||||
|
||||
|
@ -53,7 +54,7 @@ public class FrogmodModProvider implements FrogModProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModProperties> loadMods(Collection<Path> paths) throws Exception {
|
||||
public Collection<ModProperties> loadMods(Collection<Path> paths, Consumer<URL> classpathAdder) throws Exception {
|
||||
Path jijCache = getJijCacheDir();
|
||||
|
||||
Map<Path, ModProperties> mods = new HashMap<>();
|
||||
|
@ -74,7 +75,7 @@ public class FrogmodModProvider implements FrogModProvider {
|
|||
LOGGER.warn("Failed to resolve url for {}", path, e);
|
||||
return null;
|
||||
}
|
||||
}).filter(Objects::nonNull).forEach(FrogLoaderImpl.getInstance().getClassloader()::addURL);
|
||||
}).filter(Objects::nonNull).forEach(classpathAdder);
|
||||
|
||||
loadedMods.addAll(mods.values());
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
package dev.frogmc.frogloader.impl.plugin.mod;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
|
||||
import dev.frogmc.frogloader.api.plugin.ModProvider;
|
||||
import dev.frogmc.frogloader.impl.mod.JavaModProperties;
|
||||
|
||||
public class JavaModProvider implements FrogModProvider {
|
||||
public class JavaModProvider implements ModProvider {
|
||||
@Override
|
||||
public String id() {
|
||||
return "frogloader:integrated/java";
|
||||
|
@ -20,7 +22,7 @@ public class JavaModProvider implements FrogModProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModProperties> loadMods(Collection<Path> modFiles) throws Exception {
|
||||
public Collection<ModProperties> loadMods(Collection<Path> modFiles, Consumer<URL> classpathAdder) throws Exception {
|
||||
return Collections.singleton(JavaModProperties.get());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
dev.frogmc.frogloader.impl.plugin.mod.JavaModProvider
|
||||
dev.frogmc.frogloader.impl.plugin.mod.FrogmodModProvider
|
|
@ -0,0 +1,2 @@
|
|||
dev.frogmc.frogloader.impl.plugin.mod.JavaModProvider
|
||||
dev.frogmc.frogloader.impl.plugin.mod.FrogModProvider
|
Loading…
Reference in a new issue
Should/could this be changed to a ResourceLocation?
No, thought about it but ResourceLocation is a Minecraft class and therefore may not be available.
Should we make a similar wrapper class? It seems strange not to enforce the used format
I don't think so, it doesn't really matter. The only important thing is that the content is unique among all mod providers due to the constraints of java's HashMap. And as we aren't really doing anything with these IDs except for supplying each provider with its mods later on I don't think it's worth requiring any specific format.
It's something to consider if we ever want to parse it