Process the main modloading work on the async thread, but still
do deferred work on the main thread by passing in the executor. Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
parent
359be1a880
commit
9067dbf6a0
|
@ -31,6 +31,7 @@ import java.util.concurrent.Executor;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
@ -187,21 +188,25 @@ public class DeferredWorkQueue
|
|||
taskQueue.clear();
|
||||
}
|
||||
|
||||
static void runTasks(ModLoadingStage fromStage, Consumer<List<ModLoadingException>> errorHandler) {
|
||||
static void runTasks(ModLoadingStage fromStage, Consumer<List<ModLoadingException>> errorHandler, final Executor executor) {
|
||||
raisedExceptions.clear();
|
||||
if (taskQueue.isEmpty()) return; // Don't log unnecessarily
|
||||
LOGGER.info(LOADING, "Dispatching synchronous work after {}: {} jobs", fromStage, taskQueue.size());
|
||||
StopWatch globalTimer = StopWatch.createStarted();
|
||||
while (!taskQueue.isEmpty()) {
|
||||
TaskInfo taskinfo = taskQueue.poll();
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
taskinfo.task.run();
|
||||
timer.stop();
|
||||
if (timer.elapsed(TimeUnit.SECONDS) >= 1) {
|
||||
LOGGER.warn(LOADING, "Mod '{}' took {} to run a deferred task.", taskinfo.owner.getModId(), timer);
|
||||
}
|
||||
}
|
||||
final CompletableFuture<Void> tasks = CompletableFuture.allOf(taskQueue.stream().map(ti -> makeRunnable(ti, executor)).toArray(CompletableFuture[]::new));
|
||||
tasks.join();
|
||||
LOGGER.info(LOADING, "Synchronous work queue completed in {}", globalTimer);
|
||||
errorHandler.accept(raisedExceptions);
|
||||
}
|
||||
|
||||
private static CompletableFuture<?> makeRunnable(TaskInfo ti, Executor executor) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
ti.task.run();
|
||||
timer.stop();
|
||||
if (timer.elapsed(TimeUnit.SECONDS) >= 1) {
|
||||
LOGGER.warn(LOADING, "Mod '{}' took {} to run a deferred task.", ti.owner.getModId(), timer);
|
||||
}
|
||||
}, executor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import net.minecraftforge.eventbus.api.Event;
|
|||
import net.minecraftforge.forgespi.language.ILifecycleEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -41,7 +41,7 @@ public enum LifecycleEventProvider
|
|||
GATHERDATA(()->new GatherDataLifecycleEvent(ModLoadingStage.GATHERDATA), ModList.inlineDispatcher);
|
||||
|
||||
private final Supplier<? extends LifecycleEvent> event;
|
||||
private final BiConsumer<LifecycleEvent, Consumer<List<ModLoadingException>>> eventDispatcher;
|
||||
private final EventHandler<LifecycleEvent, Consumer<List<ModLoadingException>>,Executor> eventDispatcher;
|
||||
private Supplier<Event> customEventSupplier;
|
||||
private LifecycleEvent.Progression progression = LifecycleEvent.Progression.NEXT;
|
||||
|
||||
|
@ -50,7 +50,7 @@ public enum LifecycleEventProvider
|
|||
this(e, ModList.parallelDispatcher);
|
||||
}
|
||||
|
||||
LifecycleEventProvider(Supplier<? extends LifecycleEvent> e, BiConsumer<LifecycleEvent, Consumer<List<ModLoadingException>>> eventDispatcher)
|
||||
LifecycleEventProvider(Supplier<? extends LifecycleEvent> e, EventHandler<LifecycleEvent, Consumer<List<ModLoadingException>>,Executor> eventDispatcher)
|
||||
{
|
||||
this.event = e;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
|
@ -64,11 +64,11 @@ public enum LifecycleEventProvider
|
|||
this.progression = progression;
|
||||
}
|
||||
|
||||
public void dispatch(Consumer<List<ModLoadingException>> errorHandler) {
|
||||
public void dispatch(Consumer<List<ModLoadingException>> errorHandler, final Executor executor) {
|
||||
final LifecycleEvent lifecycleEvent = this.event.get();
|
||||
lifecycleEvent.setCustomEventSupplier(this.customEventSupplier);
|
||||
lifecycleEvent.changeProgression(this.progression);
|
||||
this.eventDispatcher.accept(lifecycleEvent, errorHandler);
|
||||
this.eventDispatcher.dispatchEvent(lifecycleEvent, errorHandler, executor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,4 +147,8 @@ public enum LifecycleEventProvider
|
|||
return ModLoadingStage.DONE;
|
||||
}
|
||||
}
|
||||
|
||||
public interface EventHandler<T extends LifecycleEvent, U extends Consumer<? extends List<? super ModLoadingException>>, V extends Executor> {
|
||||
void dispatchEvent(T event, U exceptionHandler, V executor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinWorkerThread;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -80,9 +81,9 @@ public class ModList
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
static BiConsumer<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>> inlineDispatcher = (event, errors) -> ModList.get().dispatchSynchronousEvent(event, errors);
|
||||
static LifecycleEventProvider.EventHandler<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>, Executor> inlineDispatcher = (event, errors, executor) -> ModList.get().dispatchSynchronousEvent(event, errors, executor);
|
||||
|
||||
static BiConsumer<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>> parallelDispatcher = (event, errors) -> ModList.get().dispatchParallelEvent(event, errors);
|
||||
static LifecycleEventProvider.EventHandler<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>, Executor> parallelDispatcher = (event, errors, executor) -> ModList.get().dispatchParallelEvent(event, errors, executor);
|
||||
|
||||
public static ModList get() {
|
||||
return INSTANCE;
|
||||
|
@ -106,13 +107,13 @@ public class ModList
|
|||
return this.fileById.get(modid);
|
||||
}
|
||||
|
||||
private void dispatchSynchronousEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler) {
|
||||
private void dispatchSynchronousEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler, final Executor executor) {
|
||||
LOGGER.debug(LOADING, "Dispatching synchronous event {}", lifecycleEvent);
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
this.mods.forEach(m->m.transitionState(lifecycleEvent, errorHandler));
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
}
|
||||
private void dispatchParallelEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler) {
|
||||
private void dispatchParallelEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler, final Executor executor) {
|
||||
LOGGER.debug(LOADING, "Dispatching parallel event {}", lifecycleEvent);
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
DeferredWorkQueue.clear();
|
||||
|
@ -124,7 +125,7 @@ public class ModList
|
|||
{
|
||||
LOGGER.error(LOADING, "Encountered an exception during parallel processing", e);
|
||||
}
|
||||
DeferredWorkQueue.runTasks(lifecycleEvent.fromStage(), errorHandler);
|
||||
DeferredWorkQueue.runTasks(lifecycleEvent.fromStage(), errorHandler, executor);
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.apache.logging.log4j.Logger;
|
|||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -126,15 +127,15 @@ public class ModLoader
|
|||
return ()->postEvent(new ModelRegistryEvent());
|
||||
}
|
||||
|
||||
public void loadMods() {
|
||||
public void loadMods(Executor mainThreadExecutor) {
|
||||
statusConsumer.ifPresent(c->c.accept("Loading mod config"));
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, ()->()-> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
|
||||
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: SETUP"));
|
||||
dispatchAndHandleError(LifecycleEventProvider.SETUP);
|
||||
dispatchAndHandleError(LifecycleEventProvider.SETUP, mainThreadExecutor);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: SIDED SETUP"));
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, this::fireClientEvents);
|
||||
dispatchAndHandleError(LifecycleEventProvider.SIDED_SETUP);
|
||||
dispatchAndHandleError(LifecycleEventProvider.SIDED_SETUP, mainThreadExecutor);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup complete"));
|
||||
}
|
||||
|
||||
|
@ -156,21 +157,21 @@ public class ModLoader
|
|||
}
|
||||
modList.setLoadedMods(modContainers);
|
||||
statusConsumer.ifPresent(c->c.accept("Constructing mods"));
|
||||
dispatchAndHandleError(LifecycleEventProvider.CONSTRUCT);
|
||||
dispatchAndHandleError(LifecycleEventProvider.CONSTRUCT, Runnable::run);
|
||||
statusConsumer.ifPresent(c->c.accept("Creating registries"));
|
||||
GameData.fireCreateRegistryEvents(LifecycleEventProvider.CREATE_REGISTRIES, this::dispatchAndHandleError);
|
||||
GameData.fireCreateRegistryEvents(LifecycleEventProvider.CREATE_REGISTRIES, event -> dispatchAndHandleError(event, Runnable::run));
|
||||
ObjectHolderRegistry.findObjectHolders();
|
||||
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
|
||||
statusConsumer.ifPresent(c->c.accept("Populating registries"));
|
||||
GameData.fireRegistryEvents(rl->true, LifecycleEventProvider.LOAD_REGISTRIES, this::dispatchAndHandleError);
|
||||
GameData.fireRegistryEvents(rl->true, LifecycleEventProvider.LOAD_REGISTRIES, event -> dispatchAndHandleError(event, Runnable::run));
|
||||
statusConsumer.ifPresent(c->c.accept("Early mod loading complete"));
|
||||
}
|
||||
|
||||
private void dispatchAndHandleError(LifecycleEventProvider event) {
|
||||
private void dispatchAndHandleError(LifecycleEventProvider event, Executor executor) {
|
||||
if (!loadingExceptions.isEmpty()) {
|
||||
LOGGER.error(LOADING,"Skipping lifecycle event {}, {} errors found.", event, loadingExceptions.size());
|
||||
} else {
|
||||
event.dispatch(this::accumulateErrors);
|
||||
event.dispatch(this::accumulateErrors, executor);
|
||||
}
|
||||
if (!loadingExceptions.isEmpty()) {
|
||||
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", event, loadingExceptions.size());
|
||||
|
@ -217,14 +218,14 @@ public class ModLoader
|
|||
ModList.get().forEachModContainer((id, mc) -> mc.acceptEvent(e));
|
||||
}
|
||||
|
||||
public void finishMods()
|
||||
public void finishMods(Executor mainThreadExecutor)
|
||||
{
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: ENQUEUE IMC"));
|
||||
dispatchAndHandleError(LifecycleEventProvider.ENQUEUE_IMC);
|
||||
dispatchAndHandleError(LifecycleEventProvider.ENQUEUE_IMC, mainThreadExecutor);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: PROCESS IMC"));
|
||||
dispatchAndHandleError(LifecycleEventProvider.PROCESS_IMC);
|
||||
dispatchAndHandleError(LifecycleEventProvider.PROCESS_IMC, mainThreadExecutor);
|
||||
statusConsumer.ifPresent(c->c.accept("Mod setup: Final completion"));
|
||||
dispatchAndHandleError(LifecycleEventProvider.COMPLETE);
|
||||
dispatchAndHandleError(LifecycleEventProvider.COMPLETE, mainThreadExecutor);
|
||||
statusConsumer.ifPresent(c->c.accept("Freezing data"));
|
||||
GameData.freezeData();
|
||||
NetworkRegistry.lock();
|
||||
|
@ -247,7 +248,7 @@ public class ModLoader
|
|||
Bootstrap.register();
|
||||
dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, inputs, serverGenerators, clientGenerators, devToolGenerators, reportsGenerator, structureValidator);
|
||||
gatherAndInitializeMods();
|
||||
dispatchAndHandleError(LifecycleEventProvider.GATHERDATA);
|
||||
dispatchAndHandleError(LifecycleEventProvider.GATHERDATA, Runnable::run);
|
||||
dataGeneratorConfig.runAll();
|
||||
}
|
||||
|
||||
|
|
|
@ -67,9 +67,9 @@ public class ClientModLoader
|
|||
}
|
||||
|
||||
private static CompletableFuture<Void> onreload(final IFutureReloadListener.IStage stage, final IResourceManager resourceManager, final IProfiler prepareProfiler, final IProfiler executeProfiler, final Executor asyncExecutor, final Executor syncExecutor) {
|
||||
return CompletableFuture.runAsync(createRunnableWithCatch(ClientModLoader::startModLoading), syncExecutor).
|
||||
return CompletableFuture.runAsync(createRunnableWithCatch(() -> startModLoading(syncExecutor)), asyncExecutor).
|
||||
thenCompose(stage::markCompleteAwaitingOthers).
|
||||
thenRunAsync(ClientModLoader::finishModLoading, syncExecutor);
|
||||
thenRunAsync(() -> finishModLoading(syncExecutor), asyncExecutor);
|
||||
}
|
||||
|
||||
private static Runnable createRunnableWithCatch(Runnable r) {
|
||||
|
@ -83,15 +83,16 @@ public class ClientModLoader
|
|||
};
|
||||
}
|
||||
|
||||
private static void startModLoading() {
|
||||
private static void startModLoading(Executor executor) {
|
||||
earlyLoaderGUI.handleElsewhere();
|
||||
createRunnableWithCatch(ModLoader.get()::loadMods).run();
|
||||
createRunnableWithCatch(() -> ModLoader.get().loadMods(executor)).run();
|
||||
}
|
||||
private static void finishModLoading()
|
||||
private static void finishModLoading(Executor executor)
|
||||
{
|
||||
createRunnableWithCatch(ModLoader.get()::finishMods).run();
|
||||
createRunnableWithCatch(() -> ModLoader.get().finishMods(executor)).run();
|
||||
loading = false;
|
||||
mc.gameSettings.loadOptions();
|
||||
// reload game settings on main thread
|
||||
executor.execute(()->mc.gameSettings.loadOptions());
|
||||
}
|
||||
|
||||
public static VersionChecker.Status checkForUpdates()
|
||||
|
|
|
@ -43,11 +43,11 @@ public class ServerModLoader
|
|||
LogicalSidedProvider.setServer(()->dedicatedServer);
|
||||
LanguageHook.loadForgeAndMCLangs();
|
||||
ModLoader.get().gatherAndInitializeMods();
|
||||
ModLoader.get().loadMods();
|
||||
ModLoader.get().loadMods(Runnable::run);
|
||||
}
|
||||
|
||||
public static void end() {
|
||||
ModLoader.get().finishMods();
|
||||
ModLoader.get().finishMods(Runnable::run);
|
||||
List<ModLoadingWarning> warnings = ModLoader.get().getWarnings();
|
||||
if (!warnings.isEmpty()) {
|
||||
LOGGER.warn(LOADING, "Mods loaded with {} warnings", warnings.size());
|
||||
|
|
Loading…
Reference in New Issue