Separate plugin types #10

Merged
owlsys merged 14 commits from ecorous/plugin-types into main 2024-06-16 17:13:54 -04:00
7 changed files with 89 additions and 51 deletions
Showing only changes of commit e352bb835f - Show all commits

View file

@ -6,6 +6,8 @@ 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.impl.FrogLoaderImpl;
@ -28,11 +30,20 @@ public interface FrogLoader {
}
/**
* Get all loaded plugins.
* Get all loaded game plugins.
*
* @return A collection of all loaded plugins
* @return A collection of all loaded game plugins
*/
Collection<FrogPlugin> getPlugins();
Collection<FrogGamePlugin> getGamePlugins();
/**
* Get all loaded mod providers.
*
* @return A collection of all loaded mod providers
*/
Collection<FrogModProvider> getModProviders();
//Collection<FrogPlugin> getPlugins();
/**
* Get the current (physical) environment.

View file

@ -2,10 +2,12 @@ package dev.frogmc.frogloader.api.plugin;
import dev.frogmc.frogloader.api.mod.ModProperties;
import java.io.File;
import java.nio.file.Path;
import java.util.Collection;
public interface FrogModProvider {
String id();
public interface FrogModPlugin {
default String loadDirectory() {
return "mods";
}
@ -18,6 +20,8 @@ public interface FrogModPlugin {
return false;
}
default void initMods(Collection<ModProperties> mods) {};
default ModProperties loadMod(Path path) {
return null;
}

View file

@ -5,7 +5,7 @@ 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.FrogModPlugin;
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
import dev.frogmc.frogloader.api.plugin.FrogPlugin;
import dev.frogmc.frogloader.impl.gui.LoaderGui;
import dev.frogmc.frogloader.impl.launch.MixinClassLoader;
@ -38,14 +38,14 @@ public class FrogLoaderImpl implements FrogLoader {
private final Env env;
private final Logger LOGGER = LoggerFactory.getLogger("FrogLoader");
@Getter
private final List<FrogPlugin> plugins = new ArrayList<>();
// @Getter
// private final List<FrogPlugin> plugins = new ArrayList<>();
@Getter
private final List<FrogGamePlugin> gamePlugins = new ArrayList<>();
private final Collection<FrogGamePlugin> gamePlugins = new ArrayList<>();
@Getter
private final List<FrogModPlugin> modPlugins = new ArrayList<>();
@Getter
private final Collection<FrogModProvider> modProviders = new ArrayList<>();
@Getter
private final Path gameDir, configDir, modsDir;
@ -56,8 +56,10 @@ public class FrogLoaderImpl implements FrogLoader {
@Getter
private final Gson gson = new Gson();
private Map<String, ModProperties> mods;
private Collection<String> modIds;
// Map<Provider ID, Map<Mod ID, ModProperties>>
private Map<String, Map<String, ModProperties>> mods = new HashMap<>();
// private Map<String, ModProperties> mods;
private Collection<String> modIds = new ArrayList<>();
private FrogLoaderImpl(String[] args, Env env) {
@ -79,15 +81,16 @@ public class FrogLoaderImpl implements FrogLoader {
}
try {
discoverPlugins();
discoverGamePlugins();
discoverModProviders();
advanceMixinState();
mods = collectMods();
modIds = collectModIds();
LOGGER.info(ModUtil.getModList(mods.values()));
LOGGER.info(ModUtil.getModList(getMods()));
LOGGER.info("Launching...");
plugins.forEach(FrogPlugin::run);
gamePlugins.forEach(FrogGamePlugin::run);
modProviders.forEach(m -> m.initMods(mods.get(m.id()).values()));
} catch (Throwable t) {
LoaderGui.execReport(CrashReportGenerator.writeReport(t, collectMods().values()), false);
LoaderGui.execReport(CrashReportGenerator.writeReport(t, getMods()), false);
}
}
@ -110,28 +113,31 @@ public class FrogLoaderImpl implements FrogLoader {
}
}
private void discoverModPlugins() {
FrogModPlugin[] applicablePlugins = ServiceLoader
.load(FrogModPlugin.class)
.stream()
.map(ServiceLoader.Provider::get)
.filter(FrogModPlugin::isApplicable)
.toArray(FrogModPlugin[]::new);
private void discoverModProviders() {
LOGGER.info("Discovering mod providers...");
ServiceLoader<FrogModProvider> loader = ServiceLoader.load(FrogModProvider.class);
loader.stream().map(ServiceLoader.Provider::get).forEach(p -> LOGGER.info("Found mod provider: " + p.getClass().getName()));
FrogModProvider[] applicableProviders = ServiceLoader.load(FrogModProvider.class).stream().map(ServiceLoader.Provider::get).filter(FrogModProvider::isApplicable).toArray(FrogModProvider[]::new);
for (FrogModPlugin plugin : applicablePlugins) {
for (FrogModProvider plugin : applicableProviders) {
try {
Collection<Path> paths = Discovery.find(gameDir.resolve(plugin.loadDirectory()), p->false, plugin::isFileApplicable);
LOGGER.info("Initialising mod provider: " + plugin.id());
Map<String, ModProperties> modsFromProvider = new HashMap<>();
Collection<Path> paths = Discovery.find(gameDir.resolve(plugin.loadDirectory()), p -> false, plugin::isFileApplicable);
paths.forEach(p -> {
LOGGER.info("Loading mod: " + p);
try {
ModProperties mod = plugin.loadMod(p);
mods.put(mod.id(), mod);
modIds.add(mod.id());
modsFromProvider.put(mod.id(), mod);
} catch (Throwable e) {
LOGGER.error("Error during mod initialisation: ", e);
throw new RuntimeException(e);
}
});
modPlugins.add(plugin);
LOGGER.info("Loaded " + modsFromProvider.size() + " mods from provider: " + plugin.id());
mods.put(plugin.id(), modsFromProvider);
modIds.addAll(modsFromProvider.keySet());
modProviders.add(plugin);
} catch (Throwable e) {
LOGGER.error("Error during plugin initialisation: ", e);
throw new RuntimeException(e);
@ -140,13 +146,10 @@ public class FrogLoaderImpl implements FrogLoader {
}
private void discoverGamePlugins() {
// this cast is safe
FrogGamePlugin[] applicablePlugins = ServiceLoader
.load(FrogGamePlugin.class)
.stream()
.map(ServiceLoader.Provider::get)
.filter(FrogGamePlugin::isApplicable)
.toArray(FrogGamePlugin[]::new);
LOGGER.info("Discovering game plugins...");
ServiceLoader<FrogGamePlugin> loader = ServiceLoader.load(FrogGamePlugin.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);
if (applicablePlugins.length > 1) {
throw new IllegalStateException("Multiple applicable game plugins found!");
} else if (applicablePlugins.length == 0) {
@ -165,7 +168,7 @@ public class FrogLoaderImpl implements FrogLoader {
}
private void discoverPlugins() {
/*private void discoverPlugins() {
ServiceLoader.load(FrogPlugin.class).forEach(plugin -> {
try {
if (plugin.isApplicable()) {
@ -181,7 +184,7 @@ public class FrogLoaderImpl implements FrogLoader {
if (plugins.isEmpty()) {
throw new IllegalStateException("No plugin applicable to the current state was found!");
}
}
}*/
public String getArgument(String name) {
for (int i = 0; i < args.length - 1; i += 2) {
@ -212,19 +215,19 @@ public class FrogLoaderImpl implements FrogLoader {
@Override
public Optional<ModProperties> getModProperties(String id) {
return Optional.ofNullable(mods.get(id));
return mods.values().stream().flatMap(m -> m.values().stream()).filter(m -> m.id().equals(id)).findFirst();
}
private Map<String, ModProperties> collectMods() {
/*private Map<String, ModProperties> collectMods() {
return plugins.stream().map(FrogPlugin::getMods).flatMap(Collection::stream).collect(Collectors.toMap(ModProperties::id, m -> m));
}
}*/
private Collection<String> collectModIds() {
return mods.keySet();
return mods.values().stream().flatMap(m -> m.keySet().stream()).collect(Collectors.toSet());
}
@Override
public Collection<ModProperties> getMods() {
return mods.values();
return mods.values().stream().map(Map::values).flatMap(Collection::stream).collect(Collectors.toSet());
}
}

View file

@ -1,18 +1,28 @@
package dev.frogmc.frogloader.impl.plugin.mod;
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.FrogModPlugin;
import dev.frogmc.frogloader.impl.mod.ModPropertiesImpl;
import dev.frogmc.frogloader.api.plugin.FrogModProvider;
import dev.frogmc.frogloader.impl.mod.ModPropertiesReader;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.Collection;
@SuppressWarnings("unused")
public class FrogmodModProvider implements FrogModProvider {
Logger LOGGER = org.slf4j.LoggerFactory.getLogger("FrogModProvider");
@Override
public String id() {
return "frogloader:frogmod";
}
public class FrogmodModPlugin implements FrogModPlugin {
@Override
public boolean isApplicable() {
return true;
@ -20,12 +30,14 @@ public class FrogmodModPlugin implements FrogModPlugin {
@Override
public boolean isFileApplicable(Path path) {
if (!path.endsWith(".frogmod")) {
if (!path.toString().endsWith(".frogmod")) {
LOGGER.info("File {} is not a frogmod file", path.toString());
return false;
}
try (FileSystem fs = FileSystems.newFileSystem(path)) {
return fs.getPath("frog.mod.toml").toFile().exists();
} catch (Exception e) {
LOGGER.error("Error while checking file {}", path, e);
return false;
}
}
@ -34,10 +46,17 @@ public class FrogmodModPlugin implements FrogModPlugin {
public ModProperties loadMod(Path path) {
try (FileSystem fs = FileSystems.newFileSystem(path)) {
ModProperties prop = ModPropertiesReader.readFile(fs.getPath("frog.mod.toml").toUri().toURL()).orElseThrow(IOException::new);
prop.extensions().runIfPresent(PreLaunchExtension.ID, PreLaunchExtension.class, PreLaunchExtension::onPreLaunch);
// prop.extensions().runIfPresent(PreLaunchExtension.ID, PreLaunchExtension.class, PreLaunchExtension::onPreLaunch);
return prop;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void initMods(Collection<ModProperties> mods) {
mods.forEach(mod -> {
mod.extensions().runIfPresent(PreLaunchExtension.ID, PreLaunchExtension.class, PreLaunchExtension::onPreLaunch);
});
}
}

View file

@ -0,0 +1 @@
dev.frogmc.frogloader.impl.plugin.game.minecraft.MinecraftGamePlugin

View file

@ -0,0 +1 @@
dev.frogmc.frogloader.impl.plugin.mod.FrogmodModProvider

View file

@ -1 +0,0 @@
dev.frogmc.frogloader.impl.plugin.game.minecraft.MinecraftOld