Cleanup lifecycle transitions

Fix mod ordering for multi-mod jars
Make dependency resolution issues easier to debug/diagnose
This commit is contained in:
LexManos committed 2024-11-11 03:04:23 -08:00
1 parent d93b7db69a
commit 384286a453
22 files changed
+828 -569

No files matched your search

@@ -11,22 +11,39 @@ import net.minecraftforge.fml.IModLoadingState;
import net.minecraftforge.fml.IModStateProvider;
import net.minecraftforge.fml.ModLoadingPhase;
import net.minecraftforge.fml.ModLoadingState;
import net.minecraftforge.fml.core.ModStateProvider;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.registries.GameData;
import net.minecraftforge.registries.ObjectHolderRegistry;
import net.minecraftforge.registries.RegistryManager;
public class ForgeStatesProvider implements IModStateProvider {
final ModLoadingState CREATE_REGISTRIES = ModLoadingState.withInline("CREATE_REGISTRIES", "CONSTRUCT", ModLoadingPhase.GATHER, ml -> RegistryManager.postNewRegistryEvent());
final ModLoadingState OBJECT_HOLDERS = ModLoadingState.withInline("OBJECT_HOLDERS", "CREATE_REGISTRIES", ModLoadingPhase.GATHER, ml -> ObjectHolderRegistry.findObjectHolders());
final ModLoadingState INJECT_CAPABILITIES = ModLoadingState.withInline("INJECT_CAPABILITIES", "OBJECT_HOLDERS", ModLoadingPhase.GATHER, CapabilityManager::injectCapabilities);
final ModLoadingState UNFREEZE = ModLoadingState.withInline("UNFREEZE_DATA", "INJECT_CAPABILITIES", ModLoadingPhase.GATHER, ml -> GameData.unfreezeData());
final ModLoadingState LOAD_REGISTRIES = ModLoadingState.withInline("LOAD_REGISTRIES", "UNFREEZE_DATA", ModLoadingPhase.GATHER, ml -> GameData.postRegisterEvents());
final ModLoadingState FREEZE = ModLoadingState.withInline("FREEZE_DATA", "COMPLETE", ModLoadingPhase.COMPLETE, ml -> GameData.freezeData());
final ModLoadingState NETLOCK = ModLoadingState.withInline("NETWORK_LOCK", "FREEZE_DATA", ModLoadingPhase.COMPLETE, ml -> NetworkRegistry.lock());
public static final ModLoadingState CREATE_REGISTRIES = gather("CREATE_REGISTRIES", ModStateProvider.CONSTRUCT, RegistryManager::postNewRegistryEvent);
public static final ModLoadingState OBJECT_HOLDERS = gather("OBJECT_HOLDERS", CREATE_REGISTRIES, ObjectHolderRegistry::findObjectHolders);
public static final ModLoadingState INJECT_CAPABILITIES = gather("INJECT_CAPABILITIES", OBJECT_HOLDERS).withInline(CapabilityManager::injectCapabilities);
public static final ModLoadingState UNFREEZE_DATA = gather("UNFREEZE_DATA", INJECT_CAPABILITIES, GameData::unfreezeData);
public static final ModLoadingState LOAD_REGISTRIES = gather("LOAD_REGISTRIES", UNFREEZE_DATA, GameData::postRegisterEvents);
public static final ModLoadingState FREEZE_DATA = complete("FREEZE_DATA", ModStateProvider.COMPLETE, GameData::freezeData);
public static final ModLoadingState NETWORK_LOCK = complete("NETWORK_LOCK", FREEZE_DATA, NetworkRegistry::lock);
private static ModLoadingState.Builder gather(String name, ModLoadingState after) {
return ModLoadingState.of(name, ModLoadingPhase.GATHER).after(after);
}
private static ModLoadingState gather(String name, ModLoadingState after, Runnable inline) {
return gather(name, after).withInline(ml -> inline.run());
}
private static ModLoadingState.Builder complete(String name, ModLoadingState after) {
return ModLoadingState.of(name, ModLoadingPhase.COMPLETE).after(after);
}
private static ModLoadingState complete(String name, ModLoadingState after, Runnable inline) {
return complete(name, after).withInline(ml -> inline.run());
}
@Override
public List<IModLoadingState> getAllStates() {
return List.of(CREATE_REGISTRIES, OBJECT_HOLDERS, INJECT_CAPABILITIES, UNFREEZE, LOAD_REGISTRIES, FREEZE, NETLOCK);
return List.of(CREATE_REGISTRIES, OBJECT_HOLDERS, INJECT_CAPABILITIES, UNFREEZE_DATA, LOAD_REGISTRIES, FREEZE_DATA, NETWORK_LOCK);
}
}
@@ -34,15 +34,13 @@ public class ModStateProvider implements IModStateProvider {
*
* @see ModLoadingPhase#ERROR
*/
final ModLoadingState ERROR = ModLoadingState.empty("ERROR", "",
ModLoadingPhase.ERROR);
public static final ModLoadingState ERROR = ModLoadingState.of("ERROR", ModLoadingPhase.ERROR).empty();
/**
* First {@linkplain ModLoadingPhase#GATHER gathering state}, for the validation of the mod list.
* TODO: figure out where this is used and why this exists instead of CONSTRUCT being the first state
*/
private final ModLoadingState VALIDATE = ModLoadingState.empty("VALIDATE", "",
ModLoadingPhase.GATHER);
public static final ModLoadingState VALIDATE = ModLoadingState.of("VALIDATE", ModLoadingPhase.GATHER).empty();
/**
* {@linkplain ModLoadingPhase#GATHER Gathering state} after {@linkplain #VALIDATE validation}, for the construction
@@ -51,22 +49,20 @@ public class ModStateProvider implements IModStateProvider {
* @see FMLConstructModEvent
* @see ModLoadingStage#CONSTRUCT
*/
final ModLoadingState CONSTRUCT = ModLoadingState.withTransition("CONSTRUCT", "VALIDATE",
ml -> "Constructing %d mods".formatted(ml.size()),
ModLoadingPhase.GATHER,
new ParallelTransition(ModLoadingStage.CONSTRUCT, FMLConstructModEvent.class));
public static final ModLoadingState CONSTRUCT = ModLoadingState.of("CONSTRUCT", ModLoadingPhase.GATHER)
.after(VALIDATE)
.message(ml -> "Constructing %d mods".formatted(ml.size()))
.withTransition(new ParallelTransition(ModLoadingStage.CONSTRUCT, FMLConstructModEvent::new));
/**
* First {@linkplain ModLoadingPhase#LOAD loading state}, for loading of the common and (if applicable)
* {@linkplain Dist#CLIENT client-side} mod configurations.
*/
private final ModLoadingState CONFIG_LOAD = ModLoadingState.withInline("CONFIG_LOAD", "",
ModLoadingPhase.LOAD,
ml -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
() -> () -> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
});
public static final ModLoadingState CONFIG_LOAD = ModLoadingState.of("CONFIG_LOAD", ModLoadingPhase.LOAD)
.withInline(ml -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
});
/**
* {@linkplain ModLoadingPhase#LOAD Loading state} after {@linkplain #CONFIG_LOAD configuration loading}, for
@@ -75,9 +71,9 @@ public class ModStateProvider implements IModStateProvider {
* @see FMLCommonSetupEvent
* @see ModLoadingStage#COMMON_SETUP
*/
private final ModLoadingState COMMON_SETUP = ModLoadingState.withTransition("COMMON_SETUP", "CONFIG_LOAD",
ModLoadingPhase.LOAD,
new ParallelTransition(ModLoadingStage.COMMON_SETUP, FMLCommonSetupEvent.class));
public static final ModLoadingState COMMON_SETUP = ModLoadingState.of("COMMON_SETUP", ModLoadingPhase.LOAD)
.after(CONFIG_LOAD)
.withTransition(new ParallelTransition(ModLoadingStage.COMMON_SETUP, FMLCommonSetupEvent::new));
/**
* {@linkplain ModLoadingPhase#LOAD Loading state} after {@linkplain #COMMON_SETUP common setup}, for side-specific
@@ -87,10 +83,14 @@ public class ModStateProvider implements IModStateProvider {
* @see FMLDedicatedServerSetupEvent
* @see ModLoadingStage#SIDED_SETUP
*/
private final ModLoadingState SIDED_SETUP = ModLoadingState.withTransition("SIDED_SETUP", "COMMON_SETUP",
ModLoadingPhase.LOAD,
new ParallelTransition(ModLoadingStage.SIDED_SETUP,
DistExecutor.unsafeRunForDist(()->()-> FMLClientSetupEvent.class, ()->()-> FMLDedicatedServerSetupEvent.class)));
public static final ModLoadingState SIDED_SETUP = ModLoadingState.of("SIDED_SETUP", ModLoadingPhase.LOAD)
.after(COMMON_SETUP)
.withTransition(new ParallelTransition(ModLoadingStage.SIDED_SETUP,
DistExecutor.unsafeRunForDist(
() -> () -> FMLClientSetupEvent::new,
() -> () -> FMLDedicatedServerSetupEvent::new
)
));
/**
* First {@linkplain ModLoadingPhase#COMPLETE completion state}, for enqueuing {@link net.minecraftforge.fml.InterModComms}
@@ -99,9 +99,8 @@ public class ModStateProvider implements IModStateProvider {
* @see InterModEnqueueEvent
* @see ModLoadingStage#ENQUEUE_IMC
*/
private final ModLoadingState ENQUEUE_IMC = ModLoadingState.withTransition("ENQUEUE_IMC", "",
ModLoadingPhase.COMPLETE,
new ParallelTransition(ModLoadingStage.ENQUEUE_IMC, InterModEnqueueEvent.class));
public static final ModLoadingState ENQUEUE_IMC = ModLoadingState.of("ENQUEUE_IMC", ModLoadingPhase.COMPLETE)
.withTransition(new ParallelTransition(ModLoadingStage.ENQUEUE_IMC, InterModEnqueueEvent::new));
/**
* {@linkplain ModLoadingPhase#COMPLETE Completion state} after {@linkplain #ENQUEUE_IMC}, for processing of messages
@@ -110,9 +109,9 @@ public class ModStateProvider implements IModStateProvider {
* @see InterModProcessEvent
* @see ModLoadingStage#PROCESS_IMC
*/
private final ModLoadingState PROCESS_IMC = ModLoadingState.withTransition("PROCESS_IMC", "ENQUEUE_IMC",
ModLoadingPhase.COMPLETE,
new ParallelTransition(ModLoadingStage.PROCESS_IMC, InterModProcessEvent.class));
public static final ModLoadingState PROCESS_IMC = ModLoadingState.of("PROCESS_IMC", ModLoadingPhase.COMPLETE)
.after(ENQUEUE_IMC)
.withTransition(new ParallelTransition(ModLoadingStage.PROCESS_IMC, InterModProcessEvent::new));
/**
* {@linkplain ModLoadingPhase#COMPLETE Completion state} after {@linkplain #PROCESS_IMC}, marking the completion
@@ -121,18 +120,17 @@ public class ModStateProvider implements IModStateProvider {
* @see FMLLoadCompleteEvent
* @see ModLoadingStage#COMPLETE
*/
private final ModLoadingState COMPLETE = ModLoadingState.withTransition("COMPLETE", "PROCESS_IMC",
ml -> "completing load of %d mods".formatted(ml.size()),
ModLoadingPhase.COMPLETE,
new ParallelTransition(ModLoadingStage.COMPLETE, FMLLoadCompleteEvent.class));
public static final ModLoadingState COMPLETE = ModLoadingState.of("COMPLETE", ModLoadingPhase.COMPLETE)
.after(PROCESS_IMC)
.message(ml -> "completing load of %d mods".formatted(ml.size()))
.withTransition(new ParallelTransition(ModLoadingStage.COMPLETE, FMLLoadCompleteEvent::new));
/**
* The marker state for the completion of the full mod loading process.
*
* @see ModLoadingStage#DONE
*/
private final ModLoadingState DONE = ModLoadingState.empty("DONE", "",
ModLoadingPhase.DONE);
public static final ModLoadingState DONE = ModLoadingState.of("DONE", ModLoadingPhase.DONE).empty();
@Override
public List<IModLoadingState> getAllStates() {
@@ -5,23 +5,23 @@
package net.minecraftforge.fml.core;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.IModStateTransition;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.ThreadSelector;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.event.lifecycle.ParallelDispatchEvent;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Stream;
record ParallelTransition(ModLoadingStage stage, Class<? extends ParallelDispatchEvent> event) implements IModStateTransition {
record ParallelTransition(ModLoadingStage stage, BiFunction<ModContainer, ModLoadingStage, ParallelDispatchEvent> event) implements IModStateTransition {
@SuppressWarnings("unchecked")
@Override
public Supplier<Stream<EventGenerator<?>>> eventFunctionStream() {
return () -> Stream.of(IModStateTransition.EventGenerator.fromFunction(LamdbaExceptionUtils.rethrowFunction((ModContainer mc) -> event.getConstructor(ModContainer.class, ModLoadingStage.class).newInstance(mc, stage))));
public <T extends Event & IModBusEvent> EventGenerator<T> eventFunction() {
return EventGenerator.fromFunction(mod -> (T)event.apply(mod, stage));
}
@Override
@@ -36,14 +36,4 @@ record ParallelTransition(ModLoadingStage stage, Class<? extends ParallelDispatc
return t;
}, e);
}
@Override
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> preDispatchHook() {
return (t, f) -> CompletableFuture.completedFuture(null);
}
@Override
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> postDispatchHook() {
return (t, f) -> CompletableFuture.completedFuture(null);
}
}
@@ -23,10 +23,8 @@ import net.minecraftforge.fml.ModLoadingStage;
*
* This is a parallel dispatch event.
*/
public class FMLClientSetupEvent extends ParallelDispatchEvent
{
public FMLClientSetupEvent(ModContainer container, ModLoadingStage stage)
{
public class FMLClientSetupEvent extends ParallelDispatchEvent {
public FMLClientSetupEvent(ModContainer container, ModLoadingStage stage) {
super(container, stage);
}
}