Skip to content

Commit

Permalink
[1.21.x] Topologically sort reload listeners based on dependency orde…
Browse files Browse the repository at this point in the history
…ring (#1915)

Co-authored-by: Brennan Ward <[email protected]>
  • Loading branch information
Shadows-of-Fire and Shadows-of-Fire authored Feb 6, 2025
1 parent 2a445ac commit 0aa1993
Show file tree
Hide file tree
Showing 22 changed files with 785 additions and 192 deletions.
20 changes: 13 additions & 7 deletions patches/net/minecraft/server/ReloadableServerResources.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,28 @@
public static CompletableFuture<ReloadableServerResources> loadResources(
ResourceManager p_248588_,
LayeredRegistryAccess<RegistryLayer> p_335667_,
@@ -83,10 +_,24 @@
@@ -83,10 +_,30 @@
ReloadableServerResources reloadableserverresources = new ReloadableServerResources(
p_359514_.layers(), p_359514_.lookupWithUpdatedTags(), p_250212_, p_249301_, p_363739_, p_251126_
);
+ List<PreparableReloadListener> listeners = new java.util.ArrayList<>(reloadableserverresources.listeners());
+ listeners.addAll(net.neoforged.neoforge.event.EventHooks.onResourceReload(reloadableserverresources, p_359514_.layers().compositeAccess()));
+ listeners.forEach(rl -> {
+ if (rl instanceof net.neoforged.neoforge.resource.ContextAwareReloadListener srl) srl.injectContext(reloadableserverresources.context, reloadableserverresources.registryLookup);
+ });
+
+ // Neo: Fire the AddServerReloadListenersEvent and use the resulting listeners instead of the vanilla listener list.
+ List<PreparableReloadListener> listeners = net.neoforged.neoforge.event.EventHooks.onResourceReload(reloadableserverresources, p_359514_.layers().compositeAccess());
+
+ // Neo: Inject the ConditionContext and RegistryLookup to any resource listener that requests it.
+ for (PreparableReloadListener rl : listeners) {
+ if (rl instanceof net.neoforged.neoforge.resource.ContextAwareReloadListener carl) {
+ carl.injectContext(reloadableserverresources.context, reloadableserverresources.registryLookup);
+ }
+ }
+
return SimpleReloadInstance.create(
- p_248588_, reloadableserverresources.listeners(), p_249136_, p_249601_, DATA_RELOAD_INITIAL_TASK, LOGGER.isDebugEnabled()
+ p_248588_, listeners, p_249136_, p_249601_, DATA_RELOAD_INITIAL_TASK, LOGGER.isDebugEnabled()
)
.done()
+ .thenRun(() -> {
+ // Clear context after reload completes
+ // Neo: Clear context after reload completes
+ reloadableserverresources.context.clear();
+ listeners.forEach(rl -> {
+ if (rl instanceof net.neoforged.neoforge.resource.ContextAwareReloadListener srl) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
--- a/net/minecraft/server/packs/resources/ReloadableResourceManager.java
+++ b/net/minecraft/server/packs/resources/ReloadableResourceManager.java
@@ -73,4 +_,10 @@
@@ -33,6 +_,12 @@
this.resources.close();
}

+ /**
+ * @deprecated Neo: Use {@link net.neoforged.neoforge.client.event.AddClientReloadListenerEvent}.
+ *
+ * @throws UnsupportedOperationException if called after the event has been fired.
+ */
+ @Deprecated
public void registerReloadListener(PreparableReloadListener p_10714_) {
this.listeners.add(p_10714_);
}
@@ -72,5 +_,24 @@
@Override
public Stream<PackResources> listPacks() {
return this.resources.listPacks();
}
+ }
+
+ public void registerReloadListenerIfNotPresent(PreparableReloadListener listener) {
+ if (!this.listeners.contains(listener)) {
+ this.registerReloadListener(listener);
+ }
+ /**
+ * Neo: Expose the reload listeners so they can be passed to the event.
+ *
+ * @return The (immutable) list of reload listeners.
+ */
+ public List<PreparableReloadListener> getListeners() {
+ return this.listeners;
+ }
+
+ /**
+ * Neo: Updates the {@link #listeners} with the sorted list from the event.
+ *
+ * @implNote The returned list is immutable, so after this method is called, {@link #registerReloadListener(PreparableReloadListener)} will throw.
+ */
+ @org.jetbrains.annotations.ApiStatus.Internal
+ public void updateListenersFrom(net.neoforged.neoforge.event.SortedReloadListenerEvent event) {
+ this.listeners = net.neoforged.neoforge.resource.ReloadListenerSort.sort(event);
}
}
8 changes: 6 additions & 2 deletions src/main/java/net/neoforged/neoforge/client/ClientHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.asm.enumextension.ExtensionInfo;
import net.neoforged.neoforge.client.entity.animation.json.AnimationTypeManager;
import net.neoforged.neoforge.client.event.AddClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.AddSectionGeometryEvent;
import net.neoforged.neoforge.client.event.CalculateDetachedCameraDistanceEvent;
import net.neoforged.neoforge.client.event.CalculatePlayerTurnEvent;
Expand All @@ -157,7 +158,6 @@
import net.neoforged.neoforge.client.event.InputEvent;
import net.neoforged.neoforge.client.event.ModelEvent;
import net.neoforged.neoforge.client.event.MovementInputUpdateEvent;
import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.RegisterColorHandlersEvent;
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
import net.neoforged.neoforge.client.event.RegisterMaterialAtlasesEvent;
Expand Down Expand Up @@ -990,7 +990,11 @@ public static void initClientHooks(Minecraft mc, ReloadableResourceManager resou
GameTestHooks.registerGametests();
registerSpriteSourceTypes();
MenuScreens.init();
ModLoader.postEvent(new RegisterClientReloadListenersEvent(resourceManager));

var rlEvent = new AddClientReloadListenersEvent(resourceManager);
ModLoader.postEvent(rlEvent);
resourceManager.updateListenersFrom(rlEvent);

ModLoader.postEvent(new EntityRenderersEvent.RegisterLayerDefinitions());
ModLoader.postEvent(new EntityRenderersEvent.CreateSkullModels(skullModelsByType));
ModLoader.postEvent(new EntityRenderersEvent.RegisterRenderers());
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/net/neoforged/neoforge/client/ClientNeoForgeMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
import net.neoforged.fml.config.ModConfigs;
import net.neoforged.neoforge.client.color.item.FluidContentsTint;
import net.neoforged.neoforge.client.entity.animation.json.AnimationLoader;
import net.neoforged.neoforge.client.event.AddClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent;
import net.neoforged.neoforge.client.event.ModelEvent;
import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.RegisterColorHandlersEvent;
import net.neoforged.neoforge.client.event.RegisterItemModelsEvent;
import net.neoforged.neoforge.client.event.RegisterNamedRenderTypesEvent;
Expand All @@ -38,10 +38,12 @@
import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent;
import net.neoforged.neoforge.client.gui.ConfigurationScreen;
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
import net.neoforged.neoforge.client.loading.ClientModLoader;
import net.neoforged.neoforge.client.model.EmptyModel;
import net.neoforged.neoforge.client.model.UnbakedCompositeModel;
import net.neoforged.neoforge.client.model.item.DynamicFluidContainerModel;
import net.neoforged.neoforge.client.model.obj.ObjLoader;
import net.neoforged.neoforge.client.resources.VanillaClientListeners;
import net.neoforged.neoforge.client.textures.NamespacedDirectoryLister;
import net.neoforged.neoforge.common.ModConfigSpec;
import net.neoforged.neoforge.common.NeoForge;
Expand All @@ -64,7 +66,9 @@
import net.neoforged.neoforge.common.data.internal.VanillaSoundDefinitionsProvider;
import net.neoforged.neoforge.common.util.SelfTest;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import net.neoforged.neoforge.internal.BrandingControl;
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
import net.neoforged.neoforge.resource.NeoForgeReloadListeners;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
Expand Down Expand Up @@ -131,9 +135,16 @@ static void onRegisterModelLoaders(ModelEvent.RegisterLoaders event) {
}

@SubscribeEvent
static void onRegisterReloadListeners(RegisterClientReloadListenersEvent event) {
event.registerReloadListener(ObjLoader.INSTANCE);
event.registerReloadListener(AnimationLoader.INSTANCE);
static void onRegisterReloadListeners(AddClientReloadListenersEvent event) {
event.addListener(NeoForgeReloadListeners.CLIENT_MOD_LOADING, ClientModLoader::onResourceReload);
event.addListener(NeoForgeReloadListeners.BRANDING, BrandingControl.resourceManagerReloadListener());

// These run before vanilla reload listeners.
event.addDependency(NeoForgeReloadListeners.CLIENT_MOD_LOADING, NeoForgeReloadListeners.BRANDING);
event.addDependency(NeoForgeReloadListeners.BRANDING, VanillaClientListeners.FIRST);

event.addListener(NeoForgeReloadListeners.OBJ_LOADER, ObjLoader.INSTANCE);
event.addListener(NeoForgeReloadListeners.ENTITY_ANIMATIONS, AnimationLoader.INSTANCE);
}

@SubscribeEvent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.client.event;

import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.neoforged.fml.LogicalSide;
import net.neoforged.fml.event.IModBusEvent;
import net.neoforged.neoforge.client.resources.VanillaClientListeners;
import net.neoforged.neoforge.event.SortedReloadListenerEvent;
import org.jetbrains.annotations.ApiStatus;

/**
* This event allows mods to register client-side reload listeners to the resource manager.
* This event is fired once during the construction of the {@link Minecraft} instance.
* <p>
* This event is only fired on the {@linkplain LogicalSide#CLIENT logical client}.
*
* @see {@link AddServerReloadListenersEvent} for registering server-side reload listeners.
*/
public class AddClientReloadListenersEvent extends SortedReloadListenerEvent implements IModBusEvent {
@ApiStatus.Internal
public AddClientReloadListenersEvent(ReloadableResourceManager resourceManager) {
super(resourceManager.getListeners(), AddClientReloadListenersEvent::lookupName);
}

private static ResourceLocation lookupName(PreparableReloadListener listener) {
ResourceLocation key = VanillaClientListeners.getNameForClass(listener.getClass());
if (key == null) {
if (listener.getClass().getPackageName().startsWith("net.minecraft")) {
throw new IllegalArgumentException("A key for the reload listener " + listener + " was not provided in VanillaClientListeners!");
} else {
throw new IllegalArgumentException("A non-vanilla reload listener " + listener + " was added via mixin before the AddClientReloadListenerEvent! Mod-added listeners must go through the event.");
}
}
return key;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.common.NeoForgeConfig;
import net.neoforged.neoforge.common.util.LogicalSidedProvider;
import net.neoforged.neoforge.internal.BrandingControl;
import net.neoforged.neoforge.internal.CommonModLoader;
import net.neoforged.neoforge.logging.CrashReportExtender;
import net.neoforged.neoforge.resource.ResourcePackLoader;
Expand Down Expand Up @@ -66,12 +65,15 @@ public static void finish(final PackRepository defaultResourcePacks, final Reloa
if (error == null) {
ResourcePackLoader.populatePackRepository(defaultResourcePacks, PackType.CLIENT_RESOURCES, false);
DataPackConfig.DEFAULT.addModPacks(ResourcePackLoader.getPackNames(PackType.SERVER_DATA));
mcResourceManager.registerReloadListener(ClientModLoader::onResourceReload);
mcResourceManager.registerReloadListener(BrandingControl.resourceManagerReloadListener());
}
}

private static CompletableFuture<Void> onResourceReload(final PreparableReloadListener.PreparationBarrier stage, final ResourceManager resourceManager, final Executor asyncExecutor, final Executor syncExecutor) {
/**
* This method can be bound as a method reference to {@link PreparableReloadListener}.
* <p>
* It is used as the entrypoint for client mod loading, which starts when {@link Minecraft} triggers the first resource reload.
*/
public static CompletableFuture<Void> onResourceReload(final PreparableReloadListener.PreparationBarrier stage, final ResourceManager resourceManager, final Executor asyncExecutor, final Executor syncExecutor) {
return CompletableFuture.runAsync(() -> startModLoading(syncExecutor, asyncExecutor), ModWorkManager.parallelExecutor())
.thenCompose(stage::wait)
.thenRunAsync(() -> finishModLoading(syncExecutor, asyncExecutor), ModWorkManager.parallelExecutor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
import net.neoforged.neoforge.client.event.AddClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.ModelEvent;
import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent;

/**
* A loader for custom {@linkplain UnbakedModel unbaked models}.
* <p>
* If you do any caching, you should implement {@link ResourceManagerReloadListener} and register it with
* {@link RegisterClientReloadListenersEvent}.
* {@link AddClientReloadListenersEvent}.
*
* @see ModelEvent.RegisterLoaders
* @see RegisterClientReloadListenersEvent
* @see AddClientReloadListenersEvent
*/
public interface UnbakedModelLoader<T extends UnbakedModel> {
/**
Expand Down
Loading

0 comments on commit 0aa1993

Please sign in to comment.