diff --git a/patchwork-dispatcher/build.gradle b/patchwork-dispatcher/build.gradle index e42a016b..db3030b2 100644 --- a/patchwork-dispatcher/build.gradle +++ b/patchwork-dispatcher/build.gradle @@ -6,6 +6,5 @@ dependencies { implementation project(path: ':patchwork-fml', configuration: 'dev') implementation project(path: ':patchwork-registries', configuration: 'dev') implementation project(path: ':patchwork-events-lifecycle', configuration: 'dev') - implementation project(path: ':patchwork-events-rendering', configuration: 'dev') implementation project(path: ':patchwork-model-loader', configuration: 'dev') } diff --git a/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/Patchwork.java b/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/Patchwork.java index f6a0b20b..0c05c5eb 100644 --- a/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/Patchwork.java +++ b/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/Patchwork.java @@ -19,23 +19,23 @@ package net.patchworkmc.impl; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; @@ -45,40 +45,37 @@ import net.minecraftforge.fml.javafmlmod.FMLModContainer; import net.minecraftforge.registries.ForgeRegistries; -import net.minecraft.client.MinecraftClient; import net.minecraft.server.dedicated.DedicatedServer; -import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.patchworkmc.api.ForgeInitializer; -import net.patchworkmc.impl.event.lifecycle.LifecycleEvents; -import net.patchworkmc.impl.event.render.RenderEvents; -import net.patchworkmc.impl.modelloader.ModelEventDispatcher; import net.patchworkmc.impl.registries.RegistryEventDispatcher; -public class Patchwork implements ModInitializer { +public class Patchwork { private static final Logger LOGGER = LogManager.getLogger(Patchwork.class); - private static void dispatch(Map mods, Event event) { + private static void dispatch(Collection mods, Event event) { dispatch(mods, container -> event); } - private static void dispatch(Map mods, Function provider) { - for (FMLModContainer container : mods.values()) { + /** + * Fire the specific event for all ModContainers on the {@link Mod.EventBusSubscriber.Bus.MOD} Event bus. + */ + private static void dispatch(Collection mods, Function provider) { + for (FMLModContainer container : mods) { ModLoadingContext.get().setActiveContainer(container, new FMLJavaModLoadingContext(container)); Event event = provider.apply(container); LOGGER.debug("Firing event for modid {} : {}", container.getModId(), event.toString()); - container.getEventBus().post(event); + container.patchwork$acceptEvent(event); LOGGER.debug("Fired event for modid {} : {}", container.getModId(), event.toString()); ModLoadingContext.get().setActiveContainer(null, "minecraft"); } } - @Override - public void onInitialize() { + public static void gatherAndInitializeMods() { ForgeRegistries.init(); Map mods = new HashMap<>(); @@ -102,6 +99,7 @@ public void onInitialize() { ModLoadingContext.get().setActiveContainer(container, new FMLJavaModLoadingContext(container)); try { + // TODO: Supposed to call "container.setMod()" here, but this requires a WIP Patchwork-Patcher feature. initializer.onForgeInitialize(); } catch (Throwable t) { if (error == null) { @@ -150,27 +148,65 @@ public void onInitialize() { ModList.get().setLoadedMods(mods.values()); // Send initialization events - dispatch(mods, new RegistryEvent.NewRegistry()); - RegistryEventDispatcher.dispatchRegistryEvents(event -> dispatch(mods, event)); - dispatch(mods, FMLCommonSetupEvent::new); - - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - ModelEventDispatcher.fireModelRegistryEvent(); - dispatch(mods, container -> new FMLClientSetupEvent(MinecraftClient::getInstance, container)); - RenderEvents.registerEventDispatcher(event -> dispatch(mods, event)); - }); + dispatch(mods.values(), new RegistryEvent.NewRegistry()); + RegistryEventDispatcher.dispatchRegistryEvents(event -> dispatch(mods.values(), event)); + } - DistExecutor.runWhenOn(Dist.DEDICATED_SERVER, () -> () -> { - Object gameInstance = FabricLoader.getInstance().getGameInstance(); - Supplier supplier = () -> (DedicatedServer) gameInstance; + /** + * This is called on the ResourceLoader's thread when a resource loading happens, i.e. during client start-up or F3+T is pressed. + * Forge fires the FMLCommonSetupEvent and LifeCycleEvents(FMLClientSetupEvent and FMLDedicatedServerSetupEvent) on its own thread in parallel. Sequence cannot be guaranteed. + * IMPORTANT: In Patchwork, we fire all events on the main thread (Client Thread or Server Thread). + * @param lifeCycleEvent + * @param preSidedRunnable Fired before the LifeCycleEvent, on the main thread. Sequence cannot be guaranteed. + * @param postSidedRunnable Fired after the LifeCycleEvent, on the main thread. Sequence cannot be guaranteed. + */ + public static void loadMods(Function lifeCycleEvent, Consumer>> preSidedRunnable, Consumer>> postSidedRunnable) { + List mods = ModList.get().applyForEachModContainer(m -> (FMLModContainer) m).collect(Collectors.toList()); + + // Loading mod config + // TODO: Load client and common configs here + + // Mod setup: SETUP + dispatch(mods, FMLCommonSetupEvent::new); + // Mod setup: SIDED SETUP + preSidedRunnable.accept(c -> dispatch(mods, c.get())); + dispatch(mods, lifeCycleEvent); + postSidedRunnable.accept(c -> dispatch(mods, c.get())); + // Mod setup complete + } - dispatch(mods, container -> new FMLDedicatedServerSetupEvent(supplier, container)); - }); + /** + * In Patchwork, we fire all of following events on the main thread (Client Thread or Server Thread). + */ + public static void finishMods() { + List mods = ModList.get().applyForEachModContainer(m -> (FMLModContainer) m).collect(Collectors.toList()); + // Mod setup: ENQUEUE IMC dispatch(mods, InterModEnqueueEvent::new); + // Mod setup: PROCESS IMC dispatch(mods, InterModProcessEvent::new); - LifecycleEvents.setLoadCompleteCallback(() -> dispatch(mods, FMLLoadCompleteEvent::new)); + // Mod setup: Final completion + dispatch(mods, FMLLoadCompleteEvent::new); + // Freezing data, TODO: do we need freezing? + // GameData.freezeData(); + // NetworkRegistry.lock(); + } + + public static void beginServerModLoading() { + Object gameInstance = FabricLoader.getInstance().getGameInstance(); + Supplier supplier = () -> (DedicatedServer) gameInstance; + + LOGGER.debug("Patchwork Dedicated Server Mod Loader: Start mod loading."); + Patchwork.gatherAndInitializeMods(); + Patchwork.loadMods(container -> new FMLDedicatedServerSetupEvent(supplier, container), dummy -> { }, dummy -> { }); + } + + public static void endOfServerModLoading() { + LOGGER.debug("Patchwork Dedicated Server Mod Loader: Finish mod loading."); + Patchwork.finishMods(); + LOGGER.debug("Patchwork Dedicated Server Mod Loader: Complete mod loading"); + // Assume there's no error. MinecraftForge.EVENT_BUS.start(); } } diff --git a/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/PatchworkClientModLoader.java b/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/PatchworkClientModLoader.java new file mode 100644 index 00000000..6adb4ba3 --- /dev/null +++ b/patchwork-dispatcher/src/main/java/net/patchworkmc/impl/PatchworkClientModLoader.java @@ -0,0 +1,100 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.impl; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; + +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceReloadListener; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.resource.ClientBuiltinResourcePackProvider; +import net.minecraft.client.resource.ClientResourcePackProfile; +import net.minecraft.resource.ReloadableResourceManager; +import net.minecraft.resource.ResourcePackManager; + +public class PatchworkClientModLoader { + private static final Logger LOGGER = LogManager.getLogger(PatchworkClientModLoader.class); + private static boolean loading; + private static MinecraftClient mc; + + public static void begin(final MinecraftClient minecraft, final ResourcePackManager defaultResourcePacks, + final ReloadableResourceManager mcResourceManager, ClientBuiltinResourcePackProvider metadataSerializer) { + loading = true; + PatchworkClientModLoader.mc = minecraft; + Patchwork.gatherAndInitializeMods(); + mcResourceManager.registerListener(PatchworkClientModLoader::onReload); + } + + /** + * @param syncExecutor The main thread executor + */ + private static CompletableFuture onReload(final ResourceReloadListener.Synchronizer stage, final ResourceManager resourceManager, + final Profiler prepareProfiler, final Profiler executeProfiler, final Executor asyncExecutor, final Executor syncExecutor) { + return CompletableFuture.runAsync(() -> startModLoading(syncExecutor), asyncExecutor) + .thenCompose(stage::whenPrepared) + .thenRunAsync(() -> finishModLoading(syncExecutor), asyncExecutor); + } + + private static void startModLoading(Executor mainThreadExecutor) { + LOGGER.debug("Patchwork Client Mod Loader: Start mod loading."); + mainThreadExecutor.execute(() -> Patchwork.loadMods(container -> new FMLClientSetupEvent(() -> PatchworkClientModLoader.mc, container), + PatchworkClientModLoader::preSidedRunnable, PatchworkClientModLoader::postSidedRunnable)); + } + + private static void preSidedRunnable(Consumer> perModContainerEventProcessor) { + perModContainerEventProcessor.accept(ModelRegistryEvent::new); + } + + private static void postSidedRunnable(Consumer> perModContainerEventProcessor) { + } + + private static void finishModLoading(Executor executor) { + LOGGER.debug("Patchwork Client Mod Loader: Finish mod loading."); + Patchwork.finishMods(); + loading = false; + // reload game settings on main thread + executor.execute(() -> mc.options.load()); + } + + /** + * @return true if an error occurred so that we can cancel the normal title screen. + */ + public static boolean completeModLoading() { + LOGGER.debug("Patchwork Client Mod Loader: Complete mod loading"); + // Assume there's no error. + MinecraftForge.EVENT_BUS.start(); + return false; + } + + // TODO: Reserved for future use + public static void onResourceReloadComplete(boolean errorFree) { + } +} diff --git a/patchwork-dispatcher/src/main/java/net/patchworkmc/mixin/MixinMinecraftClient.java b/patchwork-dispatcher/src/main/java/net/patchworkmc/mixin/MixinMinecraftClient.java new file mode 100644 index 00000000..633c7532 --- /dev/null +++ b/patchwork-dispatcher/src/main/java/net/patchworkmc/mixin/MixinMinecraftClient.java @@ -0,0 +1,54 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.resource.ReloadableResourceManager; + +import net.patchworkmc.impl.PatchworkClientModLoader; + +@Mixin(MinecraftClient.class) +public abstract class MixinMinecraftClient { + @Shadow + private ReloadableResourceManager resourceManager; + + @Inject(method = "init", at = @At(value = "INVOKE", shift = Shift.BEFORE, ordinal = 0, target = "net/minecraft/resource/ResourcePackManager.scanPacks()V")) + private void initForgeModsOnClient(CallbackInfo ci) { + MinecraftClient me = (MinecraftClient) (Object) this; + PatchworkClientModLoader.begin(me, me.getResourcePackManager(), resourceManager, me.getResourcePackDownloader()); + } + + // this.setOverlay(new SplashScreen(this, this.resourceManager.beginInitialMonitoredReload(SystemUtil.getServerWorkerExecutor(), this, voidFuture), () -> { + // if (SharedConstants.isDevelopment) this.checkGameData(); + // + if (net.minecraftforge.fml.client.ClientModLoader.completeModLoading()) return; // Do not overwrite the error sceen + // + // Show either ConnectScreen or TitleScreen + // } + @Inject(method = "method_18504", at = @At("RETURN")) + private void onResourceReloadComplete(CallbackInfo ci) { + PatchworkClientModLoader.onResourceReloadComplete(!PatchworkClientModLoader.completeModLoading()); + } +} diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftServerSubclass.java b/patchwork-dispatcher/src/main/java/net/patchworkmc/mixin/MixinMinecraftDedicatedServer.java similarity index 52% rename from patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftServerSubclass.java rename to patchwork-dispatcher/src/main/java/net/patchworkmc/mixin/MixinMinecraftDedicatedServer.java index ec0edf93..f2f873cf 100644 --- a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftServerSubclass.java +++ b/patchwork-dispatcher/src/main/java/net/patchworkmc/mixin/MixinMinecraftDedicatedServer.java @@ -17,29 +17,27 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.patchworkmc.mixin.event.lifecycle; +package net.patchworkmc.mixin; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.MinecraftDedicatedServer; -import net.minecraft.server.integrated.IntegratedServer; -import net.patchworkmc.impl.event.lifecycle.LifecycleEvents; +import net.patchworkmc.impl.Patchwork; -/** - * Mixes into {@link IntegratedServer} and {@link MinecraftDedicatedServer} in order to implement - * {@link net.minecraftforge.fml.event.server.FMLServerStartingEvent}. This event fires right before the implementations - * return true from setupServer. Returning false from the callback cancels the - * server's startup, however, it's important to note that this event isn't actually cancellable in Forge! - */ -@Mixin({IntegratedServer.class, MinecraftDedicatedServer.class}) -public class MixinMinecraftServerSubclass { - @Inject(method = "setupServer", at = @At("RETURN")) - private void hookSetupEnd(CallbackInfoReturnable callback) { - LifecycleEvents.handleServerStarting((MinecraftServer) (Object) this); +@Mixin(MinecraftDedicatedServer.class) +public abstract class MixinMinecraftDedicatedServer { + @Inject(method = "setupServer", at = @At(value = "INVOKE", shift = Shift.AFTER, ordinal = 0, target = "org/apache/logging/log4j/Logger.info(Ljava/lang/String;)V")) + private void initForgeModsOnServer(CallbackInfoReturnable ci) { + Patchwork.beginServerModLoading(); + } + + @Inject(method = "setupServer", at = @At(value = "NEW", shift = Shift.BEFORE, ordinal = 0, target = "net/minecraft/server/dedicated/DedicatedPlayerManager")) + private void endOfModLoading(CallbackInfoReturnable ci) { + Patchwork.endOfServerModLoading(); } } diff --git a/patchwork-dispatcher/src/main/resources/fabric.mod.json b/patchwork-dispatcher/src/main/resources/fabric.mod.json index 5cd7f2a2..9fec4d55 100644 --- a/patchwork-dispatcher/src/main/resources/fabric.mod.json +++ b/patchwork-dispatcher/src/main/resources/fabric.mod.json @@ -10,17 +10,16 @@ "license": "LGPL-2.1-only", "icon": "assets/patchwork-dispatcher/icon.png", "environment": "*", - "entrypoints": { - "main": [ - "net.patchworkmc.impl.Patchwork" - ] - }, "depends": { "patchwork-api-base": "*", "patchwork-fml": "*", "patchwork-registries": "*", - "patchwork-events-lifecycle": "*" + "patchwork-events-lifecycle": "*", + "patchwork-model-loader": "*" }, + "mixins": [ + "patchwork-dispatcher.mixins.json" + ], "custom": { "modmenu:api": true, "modmenu:parent": "patchwork" diff --git a/patchwork-dispatcher/src/main/resources/patchwork-dispatcher.mixins.json b/patchwork-dispatcher/src/main/resources/patchwork-dispatcher.mixins.json new file mode 100644 index 00000000..90025d4b --- /dev/null +++ b/patchwork-dispatcher/src/main/resources/patchwork-dispatcher.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "package": "net.patchworkmc.mixin", + "compatibilityLevel": "JAVA_8", + "server": [ + "MixinMinecraftDedicatedServer" + ], + "client": [ + "MixinMinecraftClient" + ], + "injectors": { + "defaultRequire": 1, + "maxShiftBy": 2 + } +} diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java index 1e4646f4..b1bc0e4e 100644 --- a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java +++ b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java @@ -37,6 +37,8 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; +import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.world.World; import net.fabricmc.api.ModInitializer; @@ -45,8 +47,6 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; public class LifecycleEvents implements ModInitializer { - private static Runnable loadCompleteCallback; - public static void fireWorldTickEvent(TickEvent.Phase phase, World world) { LogicalSide side = world.isClient() ? LogicalSide.CLIENT : LogicalSide.SERVER; TickEvent.WorldTickEvent event = new TickEvent.WorldTickEvent(side, phase, world); @@ -71,12 +71,20 @@ public static void firePlayerTickEvent(TickEvent.Phase phase, PlayerEntity playe MinecraftForge.EVENT_BUS.post(new TickEvent.PlayerTickEvent(phase, player)); } - public static void handleServerStarting(final MinecraftServer server) { + /** + * Mixes into {@link IntegratedServer} and {@link MinecraftDedicatedServer} in order to implement + * {@link net.minecraftforge.fml.event.server.FMLServerStartingEvent}. This event fires right before the implementations + * return true from setupServer. Returning false from the callback cancels the + * server's startup, however, it's important to note that this event isn't actually cancellable in Forge! + */ + public static boolean handleServerStarting(final MinecraftServer server) { // TODO: Forge loads language data here. I haven't found any mods that use this behavior. if (MinecraftForge.EVENT_BUS.post(new FMLServerStartingEvent(server))) { throw new UnsupportedOperationException("FMLServerStartingEvent is not cancellable!"); } + + return true; } public static void handleServerStarted(final MinecraftServer server) { @@ -97,14 +105,6 @@ private static Path getServerConfigPath(final MinecraftServer server) { return serverConfig; } - public static void setLoadCompleteCallback(Runnable callback) { - loadCompleteCallback = callback; - } - - public static void handleLoadComplete() { - loadCompleteCallback.run(); - } - public static void handleServerStopped(final MinecraftServer server) { MinecraftForge.EVENT_BUS.post(new FMLServerStoppedEvent(server)); ServerLifecycleHooks.currentServer = null; diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinIntegratedServer.java b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinIntegratedServer.java index 7ad7fcd9..aee17cf2 100644 --- a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinIntegratedServer.java +++ b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinIntegratedServer.java @@ -22,6 +22,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.server.MinecraftServer; @@ -35,4 +36,10 @@ public class MixinIntegratedServer { private void onServerAboutToStart(CallbackInfoReturnable cir) { LifecycleEvents.handleServerAboutToStart((MinecraftServer) (Object) this); } + + @Inject(method = "setupServer", at = @At(value = "RETURN", ordinal = 0), cancellable = true, slice = + @Slice(from = @At(value = "INVOKE", target = "net/minecraft/server/MinecraftServer.setMotd(Ljava/lang/String;)V"))) + private void handleServerStarting(CallbackInfoReturnable cir) { + cir.setReturnValue(LifecycleEvents.handleServerStarting((MinecraftServer) (Object) this)); + } } diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftClient.java b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftClient.java index 8e51e2f6..88bd6bf4 100644 --- a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftClient.java +++ b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftClient.java @@ -51,11 +51,6 @@ private void hookClientTickEnd(CallbackInfo info) { LifecycleEvents.fireClientTickEvent(TickEvent.Phase.END); } - @Inject(method = "init", at = @At("RETURN")) - private void hookClientInit(CallbackInfo ci) { - LifecycleEvents.handleLoadComplete(); - } - @Shadow @Final private RenderTickCounter renderTickCounter; diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftDedicatedServer.java b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftDedicatedServer.java index 777948bc..b0b51ed3 100644 --- a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftDedicatedServer.java +++ b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftDedicatedServer.java @@ -22,6 +22,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.server.MinecraftServer; @@ -33,7 +34,12 @@ public class MixinMinecraftDedicatedServer { @Inject(method = "setupServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/UserCache;setUseRemote(Z)V", shift = At.Shift.AFTER)) private void onServerAboutToStart(CallbackInfoReturnable cir) { - LifecycleEvents.handleLoadComplete(); // This is a "multithreaded" event that would be called around this time. LifecycleEvents.handleServerAboutToStart((MinecraftServer) (Object) this); } + + @Inject(method = "setupServer", at = @At(value = "RETURN", ordinal = 0), cancellable = true, slice = + @Slice(from = @At(value = "INVOKE", target = "net/minecraft/item/Item.appendStacks(Lnet/minecraft/item/ItemGroup;Lnet/minecraft/util/DefaultedList;)V"))) + private void handleServerStarting(CallbackInfoReturnable cir) { + cir.setReturnValue(LifecycleEvents.handleServerStarting((MinecraftServer) (Object) this)); + } } diff --git a/patchwork-events-lifecycle/src/main/resources/patchwork-events-lifecycle.mixins.json b/patchwork-events-lifecycle/src/main/resources/patchwork-events-lifecycle.mixins.json index 3aeabb4d..91c77547 100644 --- a/patchwork-events-lifecycle/src/main/resources/patchwork-events-lifecycle.mixins.json +++ b/patchwork-events-lifecycle/src/main/resources/patchwork-events-lifecycle.mixins.json @@ -3,7 +3,6 @@ "package": "net.patchworkmc.mixin.event.lifecycle", "compatibilityLevel": "JAVA_8", "mixins": [ - "MixinMinecraftServerSubclass", "MixinPlayerEntity", "MixinServerWorld" ], diff --git a/patchwork-events-rendering/build.gradle b/patchwork-events-rendering/build.gradle index 68e8173b..16784a5e 100644 --- a/patchwork-events-rendering/build.gradle +++ b/patchwork-events-rendering/build.gradle @@ -3,4 +3,5 @@ version = getSubprojectVersion(project, "0.3.0") dependencies { implementation project(path: ':patchwork-api-base', configuration: 'dev') + implementation project(path: ':patchwork-fml', configuration: 'dev') } diff --git a/patchwork-events-rendering/src/main/java/net/patchworkmc/impl/event/render/RenderEvents.java b/patchwork-events-rendering/src/main/java/net/patchworkmc/impl/event/render/RenderEvents.java index e70e9b83..c00d6e3f 100644 --- a/patchwork-events-rendering/src/main/java/net/patchworkmc/impl/event/render/RenderEvents.java +++ b/patchwork-events-rendering/src/main/java/net/patchworkmc/impl/event/render/RenderEvents.java @@ -20,13 +20,12 @@ package net.patchworkmc.impl.event.render; import java.util.Set; -import java.util.function.Consumer; import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.DrawBlockHighlightEvent; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.ModLoader; import net.minecraft.client.color.block.BlockColors; import net.minecraft.client.color.item.ItemColors; @@ -39,26 +38,20 @@ import net.minecraft.util.hit.HitResult; public class RenderEvents { - private static Consumer eventDispatcher; - - public static void registerEventDispatcher(Consumer dispatcher) { - eventDispatcher = dispatcher; - } - public static void onBlockColorsInit(BlockColors blockColors) { - eventDispatcher.accept(new ColorHandlerEvent.Block(blockColors)); + ModLoader.get().postEvent(new ColorHandlerEvent.Block(blockColors)); } public static void onItemColorsInit(ItemColors itemColors, BlockColors blockColors) { - eventDispatcher.accept(new ColorHandlerEvent.Item(itemColors, blockColors)); + ModLoader.get().postEvent(new ColorHandlerEvent.Item(itemColors, blockColors)); } public static void onTextureStitchPre(SpriteAtlasTexture spriteAtlasTexture, Set set) { - eventDispatcher.accept(new TextureStitchEvent.Pre(spriteAtlasTexture, set)); + ModLoader.get().postEvent(new TextureStitchEvent.Pre(spriteAtlasTexture, set)); } public static void onTextureStitchPost(SpriteAtlasTexture spriteAtlasTexture) { - eventDispatcher.accept(new TextureStitchEvent.Post(spriteAtlasTexture)); + ModLoader.get().postEvent(new TextureStitchEvent.Post(spriteAtlasTexture)); } /** diff --git a/patchwork-events-rendering/src/main/resources/fabric.mod.json b/patchwork-events-rendering/src/main/resources/fabric.mod.json index 8ad3995c..d8f37a2d 100644 --- a/patchwork-events-rendering/src/main/resources/fabric.mod.json +++ b/patchwork-events-rendering/src/main/resources/fabric.mod.json @@ -13,7 +13,8 @@ "PatchworkMC" ], "depends": { - "patchwork-api-base": "*" + "patchwork-api-base": "*", + "patchwork-fml": "*" }, "mixins": [ "patchwork-events-rendering.mixins.json" diff --git a/patchwork-fml/src/main/java/net/minecraftforge/fml/ModContainer.java b/patchwork-fml/src/main/java/net/minecraftforge/fml/ModContainer.java index 2a4ad48f..447aed30 100644 --- a/patchwork-fml/src/main/java/net/minecraftforge/fml/ModContainer.java +++ b/patchwork-fml/src/main/java/net/minecraftforge/fml/ModContainer.java @@ -85,4 +85,8 @@ public final net.fabricmc.loader.api.ModContainer getParent() { protected void acceptEvent(Event e) { } + + public final void patchwork$acceptEvent(Event e) { + this.acceptEvent(e); + } } diff --git a/patchwork-model-loader/src/main/java/net/patchworkmc/impl/modelloader/ModelEventDispatcher.java b/patchwork-model-loader/src/main/java/net/patchworkmc/impl/modelloader/ModelEventDispatcher.java index 1924e55c..1afc38d1 100644 --- a/patchwork-model-loader/src/main/java/net/patchworkmc/impl/modelloader/ModelEventDispatcher.java +++ b/patchwork-model-loader/src/main/java/net/patchworkmc/impl/modelloader/ModelEventDispatcher.java @@ -22,7 +22,6 @@ import java.util.Map; import net.minecraftforge.client.event.ModelBakeEvent; -import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.fml.ModLoader; @@ -31,15 +30,6 @@ import net.minecraft.util.Identifier; public class ModelEventDispatcher { - /** - * In Forge, ModelRegistryEvent is fired in parallel with FMLClientSetupEvent. - * Here we fire ModelRegistryEvent before FMLClientSetupEvent. - * The official forge does not set the ModLoadingContext here, so this should be fine. - */ - public static void fireModelRegistryEvent() { - ModLoader.get().postEvent(new ModelRegistryEvent()); - } - public static void onModelBake(BakedModelManager modelManager, Map modelRegistry, ModelLoader modelLoader) { ModLoader.get().postEvent(new ModelBakeEvent(modelManager, modelRegistry, modelLoader)); modelLoader.onPostBakeEvent(modelRegistry);