From 1d65ea904d43b0290d521e75f3c636897ddf72c3 Mon Sep 17 00:00:00 2001 From: chyzman Date: Tue, 30 Dec 2025 17:22:57 -0500 Subject: [PATCH 1/4] add RESOURCES_LOADED client lifecycle event --- .../lifecycle/v1/ClientLifecycleEvents.java | 15 +++++++++++++++ .../event/lifecycle/client/MinecraftMixin.java | 17 +++++++++++++++-- .../lifecycle/client/ClientLifecycleTests.java | 4 ++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java index b2e3fb82ade..db14f164912 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java @@ -48,6 +48,16 @@ private ClientLifecycleEvents() { } }); + /** + * Called after the client has finished reloading resources. + */ + public static final Event RESOURCES_LOADED = EventFactory.createArrayBacked( + ResourcesLoaded.class, callbacks -> (client, isFirst) -> { + for (ResourcesLoaded callback : callbacks) { + callback.onResourcesLoaded(client, isFirst); + } + }); + @FunctionalInterface public interface ClientStarted { void onClientStarted(Minecraft client); @@ -57,4 +67,9 @@ public interface ClientStarted { public interface ClientStopping { void onClientStopping(Minecraft client); } + + @FunctionalInterface + public interface ResourcesLoaded { + void onResourcesLoaded(Minecraft client, boolean isFirst); + } } diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java index 28179abe9df..f72cadaabb4 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java @@ -16,8 +16,12 @@ package net.fabricmc.fabric.mixin.event.lifecycle.client; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 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.Coerce; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -30,7 +34,9 @@ @Mixin(Minecraft.class) public abstract class MinecraftMixin { - @Inject(at = @At("HEAD"), method = "tick") + @Shadow private boolean gameLoadFinished; + + @Inject(at = @At("HEAD"), method = "tick") private void onStartTick(CallbackInfo info) { ClientTickEvents.START_CLIENT_TICK.invoker().onStartTick((Minecraft) (Object) this); } @@ -51,7 +57,14 @@ private void onStart(CallbackInfo ci) { ClientLifecycleEvents.CLIENT_STARTED.invoker().onClientStarted((Minecraft) (Object) this); } - @Inject(method = "updateLevelInEngines", at = @At("TAIL")) + @WrapMethod(method = "onResourceLoadFinished") + private void onResourceReload(@Coerce Object gameLoadCookie, Operation original) { + boolean first = !this.gameLoadFinished; + original.call(gameLoadCookie); + ClientLifecycleEvents.RESOURCES_LOADED.invoker().onResourcesLoaded((Minecraft) (Object) this, first); + } + + @Inject(method = "updateLevelInEngines", at = @At("TAIL")) private void afterClientWorldChange(ClientLevel world, CallbackInfo ci) { if (world != null) { Minecraft client = (Minecraft) (Object) this; diff --git a/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java b/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java index eab20bb1e75..9792b2c828a 100644 --- a/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java +++ b/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java @@ -50,6 +50,10 @@ public void onInitializeClient() { System.out.println("Client has started stopping!"); }); + ClientLifecycleEvents.RESOURCES_LOADED.register((client, first) -> { + LOGGER.info((first ? "First r" : "R") + "esource load completed"); + }); + ClientWorldEvents.AFTER_CLIENT_WORLD_CHANGE.register((client, world) -> { LOGGER.info("Client world changed to {}", world.dimension().identifier()); }); From 483ae24e7037227a86c811fb704c27de3ad3ca1d Mon Sep 17 00:00:00 2001 From: chyzman Date: Tue, 30 Dec 2025 17:40:54 -0500 Subject: [PATCH 2/4] fixed style? the test might be styled wrong, but I copied the style of the test right next to the one I added so idk --- .../lifecycle/v1/ClientLifecycleEvents.java | 26 +++++++++---------- .../lifecycle/client/MinecraftMixin.java | 18 ++++++------- .../client/ClientLifecycleTests.java | 6 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java index db14f164912..2f579d32fc6 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java @@ -48,15 +48,15 @@ private ClientLifecycleEvents() { } }); - /** - * Called after the client has finished reloading resources. - */ - public static final Event RESOURCES_LOADED = EventFactory.createArrayBacked( - ResourcesLoaded.class, callbacks -> (client, isFirst) -> { - for (ResourcesLoaded callback : callbacks) { - callback.onResourcesLoaded(client, isFirst); - } - }); + /** + * Called after the client has finished reloading resources. + */ + public static final Event RESOURCES_LOADED = EventFactory.createArrayBacked( + ResourcesLoaded.class, callbacks -> (client, isFirst) -> { + for (ResourcesLoaded callback : callbacks) { + callback.onResourcesLoaded(client, isFirst); + } + }); @FunctionalInterface public interface ClientStarted { @@ -68,8 +68,8 @@ public interface ClientStopping { void onClientStopping(Minecraft client); } - @FunctionalInterface - public interface ResourcesLoaded { - void onResourcesLoaded(Minecraft client, boolean isFirst); - } + @FunctionalInterface + public interface ResourcesLoaded { + void onResourcesLoaded(Minecraft client, boolean isFirst); + } } diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java index f72cadaabb4..ebba715ff25 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java @@ -34,9 +34,9 @@ @Mixin(Minecraft.class) public abstract class MinecraftMixin { - @Shadow private boolean gameLoadFinished; + @Shadow private boolean gameLoadFinished; - @Inject(at = @At("HEAD"), method = "tick") + @Inject(at = @At("HEAD"), method = "tick") private void onStartTick(CallbackInfo info) { ClientTickEvents.START_CLIENT_TICK.invoker().onStartTick((Minecraft) (Object) this); } @@ -57,14 +57,14 @@ private void onStart(CallbackInfo ci) { ClientLifecycleEvents.CLIENT_STARTED.invoker().onClientStarted((Minecraft) (Object) this); } - @WrapMethod(method = "onResourceLoadFinished") - private void onResourceReload(@Coerce Object gameLoadCookie, Operation original) { - boolean first = !this.gameLoadFinished; - original.call(gameLoadCookie); - ClientLifecycleEvents.RESOURCES_LOADED.invoker().onResourcesLoaded((Minecraft) (Object) this, first); - } + @WrapMethod(method = "onResourceLoadFinished") + private void onResourceReload(@Coerce Object gameLoadCookie, Operation original) { + boolean first = !this.gameLoadFinished; + original.call(gameLoadCookie); + ClientLifecycleEvents.RESOURCES_LOADED.invoker().onResourcesLoaded((Minecraft) (Object) this, first); + } - @Inject(method = "updateLevelInEngines", at = @At("TAIL")) + @Inject(method = "updateLevelInEngines", at = @At("TAIL")) private void afterClientWorldChange(ClientLevel world, CallbackInfo ci) { if (world != null) { Minecraft client = (Minecraft) (Object) this; diff --git a/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java b/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java index 9792b2c828a..9691289ca5a 100644 --- a/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java +++ b/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java @@ -50,9 +50,9 @@ public void onInitializeClient() { System.out.println("Client has started stopping!"); }); - ClientLifecycleEvents.RESOURCES_LOADED.register((client, first) -> { - LOGGER.info((first ? "First r" : "R") + "esource load completed"); - }); + ClientLifecycleEvents.RESOURCES_LOADED.register((client, first) -> { + LOGGER.info((first ? "First r" : "R") + "esource load completed"); + }); ClientWorldEvents.AFTER_CLIENT_WORLD_CHANGE.register((client, world) -> { LOGGER.info("Client world changed to {}", world.dimension().identifier()); From 9e9b23bf04b62a8c15d6eb5e99e9c79c0fcc7c84 Mon Sep 17 00:00:00 2001 From: chyzman Date: Tue, 30 Dec 2025 17:50:24 -0500 Subject: [PATCH 3/4] auto formatter moment --- .../api/client/event/lifecycle/v1/ClientLifecycleEvents.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java index 2f579d32fc6..5751c2b735b 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java @@ -51,8 +51,7 @@ private ClientLifecycleEvents() { /** * Called after the client has finished reloading resources. */ - public static final Event RESOURCES_LOADED = EventFactory.createArrayBacked( - ResourcesLoaded.class, callbacks -> (client, isFirst) -> { + public static final Event RESOURCES_LOADED = EventFactory.createArrayBacked(ResourcesLoaded.class, callbacks -> (client, isFirst) -> { for (ResourcesLoaded callback : callbacks) { callback.onResourcesLoaded(client, isFirst); } From 6d35198889fb24af9711b4b9c3ccfa2be16f1421 Mon Sep 17 00:00:00 2001 From: chyzman Date: Tue, 30 Dec 2025 18:39:03 -0500 Subject: [PATCH 4/4] start and end --- .../lifecycle/v1/ClientLifecycleEvents.java | 24 +++++++++++++++---- .../lifecycle/client/MinecraftMixin.java | 17 +++++++++++-- .../client/ClientLifecycleTests.java | 6 ++++- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java index 5751c2b735b..bad21420111 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java @@ -48,12 +48,21 @@ private ClientLifecycleEvents() { } }); + /** + * Called before the client begins loading resources. + */ + public static final Event START_RESOURCE_RELOAD = EventFactory.createArrayBacked(StartResourceReload.class, callbacks -> (client, isFirst) -> { + for (StartResourceReload callback : callbacks) { + callback.startResourceReload(client, isFirst); + } + }); + /** * Called after the client has finished reloading resources. */ - public static final Event RESOURCES_LOADED = EventFactory.createArrayBacked(ResourcesLoaded.class, callbacks -> (client, isFirst) -> { - for (ResourcesLoaded callback : callbacks) { - callback.onResourcesLoaded(client, isFirst); + public static final Event END_RESOURCE_RELOAD = EventFactory.createArrayBacked(EndResourceReload.class, callbacks -> (client, isFirst) -> { + for (EndResourceReload callback : callbacks) { + callback.endResourceReload(client, isFirst); } }); @@ -68,7 +77,12 @@ public interface ClientStopping { } @FunctionalInterface - public interface ResourcesLoaded { - void onResourcesLoaded(Minecraft client, boolean isFirst); + public interface StartResourceReload { + void startResourceReload(Minecraft client, boolean isFirst); + } + + @FunctionalInterface + public interface EndResourceReload { + void endResourceReload(Minecraft client, boolean isFirst); } } diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java index ebba715ff25..9d1b234e821 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/MinecraftMixin.java @@ -16,6 +16,8 @@ package net.fabricmc.fabric.mixin.event.lifecycle.client; +import java.util.concurrent.CompletableFuture; + import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import org.spongepowered.asm.mixin.Mixin; @@ -24,6 +26,7 @@ import org.spongepowered.asm.mixin.injection.Coerce; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -57,11 +60,21 @@ private void onStart(CallbackInfo ci) { ClientLifecycleEvents.CLIENT_STARTED.invoker().onClientStarted((Minecraft) (Object) this); } + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;createReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/server/packs/resources/ReloadInstance;"), method = "") + private void onStartResourceLoad(CallbackInfo ci) { + ClientLifecycleEvents.START_RESOURCE_RELOAD.invoker().startResourceReload((Minecraft) (Object) this, true); + } + + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/ResourceLoadStateTracker;startReload(Lnet/minecraft/client/ResourceLoadStateTracker$ReloadReason;Ljava/util/List;)V"), method = "reloadResourcePacks(ZLnet/minecraft/client/Minecraft$GameLoadCookie;)Ljava/util/concurrent/CompletableFuture;") + private void onStartResourceReload(CallbackInfoReturnable> cir) { + ClientLifecycleEvents.START_RESOURCE_RELOAD.invoker().startResourceReload((Minecraft) (Object) this, false); + } + @WrapMethod(method = "onResourceLoadFinished") - private void onResourceReload(@Coerce Object gameLoadCookie, Operation original) { + private void onResourceLoadFinished(@Coerce Object gameLoadCookie, Operation original) { boolean first = !this.gameLoadFinished; original.call(gameLoadCookie); - ClientLifecycleEvents.RESOURCES_LOADED.invoker().onResourcesLoaded((Minecraft) (Object) this, first); + ClientLifecycleEvents.END_RESOURCE_RELOAD.invoker().endResourceReload((Minecraft) (Object) this, first); } @Inject(method = "updateLevelInEngines", at = @At("TAIL")) diff --git a/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java b/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java index 9691289ca5a..59e7dd83aa5 100644 --- a/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java +++ b/fabric-lifecycle-events-v1/src/testmodClient/java/net/fabricmc/fabric/test/event/lifecycle/client/ClientLifecycleTests.java @@ -50,7 +50,11 @@ public void onInitializeClient() { System.out.println("Client has started stopping!"); }); - ClientLifecycleEvents.RESOURCES_LOADED.register((client, first) -> { + ClientLifecycleEvents.START_RESOURCE_RELOAD.register((client, first) -> { + LOGGER.info((first ? "First r" : "R") + "esource load starting"); + }); + + ClientLifecycleEvents.END_RESOURCE_RELOAD.register((client, first) -> { LOGGER.info((first ? "First r" : "R") + "esource load completed"); });