package io.gitlab.jfronny.libjf.unsafe; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.impl.ModContainerImpl; import net.fabricmc.loader.impl.metadata.EntrypointMetadata; import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.function.Consumer; public class DynamicEntry { /** * Execute an entrypoint. * * @param name the name of the entrypoint to execute. * @param entrypointType the entrypoint type. * @param onExecute entrypoint execution callback with an instance of the entrypoint type. * @param the entrypoint type. */ public static void execute(final String name, final Class entrypointType, final Consumer> onExecute) { final List> targets = new ArrayList<>(); for (final EntrypointContainer entrypoint : getEntrypointTargets(name)) { try { targets.add(new ConsumableEntrypoint<>( entrypointType.cast(Class.forName(entrypoint.entrypoint).getConstructor().newInstance()), entrypoint.mod )); } catch (final ClassNotFoundException exception) { throw new IllegalArgumentException(String.format("class %s specified in the %s entrypoint of mod %s does not exist", entrypoint.entrypoint, name, entrypoint.mod), exception); } catch (final IllegalAccessException | InstantiationException | NoSuchMethodException exception) { throw new IllegalStateException(String.format("class %s specified in the %s entrypoint of mod %s cannot be instantiated", entrypoint.entrypoint, name, entrypoint.mod), exception); } catch (final InvocationTargetException exception) { throw new RuntimeException(String.format("an error was encountered during the instantiation of the %s entrypoint class %s", name, entrypoint.entrypoint), exception); } } for (ConsumableEntrypoint target : targets) { onExecute.accept(target); } } private static Collection getEntrypointTargets(final String entrypoint) { final List entrypoints = new LinkedList<>(); for (final ModContainer mod : FabricLoader.getInstance().getAllMods()) { final List modEntrypoints = ((ModContainerImpl)mod).getMetadata().getEntrypoints(entrypoint); if (modEntrypoints != null) { for (final EntrypointMetadata metadata : modEntrypoints) { entrypoints.add(new EntrypointContainer(metadata.getValue(), mod.getMetadata().getId())); } } } return entrypoints; } record EntrypointContainer(String entrypoint, String mod) { } public record ConsumableEntrypoint(T instance, String modId) { } }