add ability for mods to provide further mod providers
This commit is contained in:
parent
6dd1bf04ed
commit
565e4df74e
|
@ -0,0 +1,10 @@
|
||||||
|
package dev.frogmc.frogloader.example;
|
||||||
|
|
||||||
|
import dev.frogmc.frogloader.api.plugin.ModProvider;
|
||||||
|
|
||||||
|
public class ExampleModProvider implements ModProvider {
|
||||||
|
@Override
|
||||||
|
public String id() {
|
||||||
|
return "example_mod:example";
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,4 +14,4 @@ credits = [
|
||||||
prelaunch = "dev.frogmc.frogloader.example.ExamplePreLaunchExtension"
|
prelaunch = "dev.frogmc.frogloader.example.ExamplePreLaunchExtension"
|
||||||
mixin = "example_mod.mixins.json"
|
mixin = "example_mod.mixins.json"
|
||||||
accesswidener = "example_mod.accesswidener"
|
accesswidener = "example_mod.accesswidener"
|
||||||
|
modprovider = "dev.frogmc.frogloader.example.ExampleModProvider"
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package dev.frogmc.frogloader.impl;
|
package dev.frogmc.frogloader.impl;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.ServiceLoader;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import dev.frogmc.frogloader.api.FrogLoader;
|
import dev.frogmc.frogloader.api.FrogLoader;
|
||||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||||
|
@ -26,37 +23,50 @@ public class PluginLoader {
|
||||||
public static void discoverModProviders(Path gameDir, Map<String, Map<String, ModProperties>> mods, Collection<String> modIds, Collection<ModProvider> 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...");
|
LOGGER.info("Discovering mod providers...");
|
||||||
|
|
||||||
for (ModProvider plugin : ServiceLoader.load(ModProvider.class)) {
|
List<ModProvider> providers = new ArrayList<>(ServiceLoader.load(ModProvider.class).stream().map(ServiceLoader.Provider::get).toList()); // we need mutability & random access
|
||||||
|
Map<String, Collection<ModProperties>> properties = new HashMap<>();
|
||||||
|
AtomicInteger size = new AtomicInteger(providers.size()); // use a separate size variable to not have to iterate over the list over and over again
|
||||||
|
for (int i = 0; i < size.get(); i++) {
|
||||||
|
ModProvider plugin = providers.get(i); // use random access to work around concurrent access (through modifications during iteration)
|
||||||
LOGGER.debug("Found mod provider: {}", plugin.getClass().getName());
|
LOGGER.debug("Found mod provider: {}", plugin.getClass().getName());
|
||||||
if (!plugin.isApplicable()) {
|
if (!plugin.isApplicable()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LOGGER.debug("Initialising mod provider: {}", plugin.id());
|
LOGGER.debug("Initialising mod provider: {}", plugin.id());
|
||||||
Map<String, ModProperties> modsFromProvider = new HashMap<>();
|
Collection<ModProperties> loadedMods = plugin.loadMods(Discovery.find(gameDir.resolve(plugin.loadDirectory()),
|
||||||
Collection<ModProperties> loadedMods = plugin.loadMods(Discovery.find(gameDir.resolve(plugin.loadDirectory()), plugin::isDirectoryApplicable, plugin::isFileApplicable), FrogLoaderImpl.getInstance().getClassloader()::addURL);
|
plugin::isDirectoryApplicable,
|
||||||
|
plugin::isFileApplicable),
|
||||||
|
FrogLoaderImpl.getInstance().getClassloader()::addURL);
|
||||||
initializeModMixins(loadedMods);
|
initializeModMixins(loadedMods);
|
||||||
AWProcessor.load(loadedMods);
|
AWProcessor.load(loadedMods);
|
||||||
|
|
||||||
loadedMods.forEach(m -> modsFromProvider.put(m.id(), m));
|
properties.put(plugin.id(), loadedMods);
|
||||||
|
|
||||||
LOGGER.debug("Loaded {} mod(s) from provider: {}", modsFromProvider.size(), plugin.id());
|
LOGGER.debug("Loaded {} mod(s) from provider: {}", loadedMods.size(), plugin.id());
|
||||||
mods.put(plugin.id(), modsFromProvider);
|
loadedMods.forEach(p -> p.extensions().runIfPresent(BuiltinExtensions.MOD_PROVIDER, ModProvider.class, provider -> {
|
||||||
modIds.addAll(modsFromProvider.keySet());
|
providers.add(provider);
|
||||||
modProviders.add(plugin);
|
size.getAndIncrement();
|
||||||
|
}));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Error during plugin initialisation: ", e);
|
LOGGER.error("Error during plugin initialisation: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<ModProperties> properties = mods.values().stream().map(Map::values).flatMap(Collection::stream).collect(Collectors.toUnmodifiableSet());
|
Collection<ModProperties> flattened = properties.values().stream().flatMap(Collection::stream).toList();
|
||||||
try {
|
try {
|
||||||
Collection<ModProperties> solved = new ModDependencyResolver(properties).solve();
|
Collection<ModProperties> solved = new ModDependencyResolver(flattened).solve();
|
||||||
mods.forEach((s, map) -> map.values().retainAll(solved));
|
properties.forEach((s, c) -> c.retainAll(solved));
|
||||||
|
properties.forEach((s, c) -> {
|
||||||
|
Map<String, ModProperties> map = mods.computeIfAbsent(s, u -> new HashMap<>());
|
||||||
|
c.forEach(p -> map.put(p.id(), p));
|
||||||
|
});
|
||||||
|
modIds.addAll(solved.stream().map(ModProperties::id).toList());
|
||||||
|
modProviders.addAll(providers);
|
||||||
} catch (ModDependencyResolver.UnfulfilledDependencyException e) {
|
} catch (ModDependencyResolver.UnfulfilledDependencyException e) {
|
||||||
LoaderGui.execUnfulfilledDep(CrashReportGenerator.writeReport(e, properties), e, false);
|
LoaderGui.execUnfulfilledDep(CrashReportGenerator.writeReport(e, flattened), e, false);
|
||||||
} catch (ModDependencyResolver.BreakingModException e) {
|
} catch (ModDependencyResolver.BreakingModException e) {
|
||||||
LoaderGui.execBreakingDep(CrashReportGenerator.writeReport(e, properties), e, false);
|
LoaderGui.execBreakingDep(CrashReportGenerator.writeReport(e, flattened), e, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,5 @@ public class BuiltinExtensions {
|
||||||
public final String PRE_LAUNCH = "prelaunch";
|
public final String PRE_LAUNCH = "prelaunch";
|
||||||
public final String ACCESSWIDENER = "accesswidener";
|
public final String ACCESSWIDENER = "accesswidener";
|
||||||
public final String LOADING_TYPE = "loading_type";
|
public final String LOADING_TYPE = "loading_type";
|
||||||
|
public final String MOD_PROVIDER = "modprovider";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue