Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.21.x] Topologically sort reload listeners based on dependency ordering #1915

Open
wants to merge 14 commits into
base: 1.21.x
Choose a base branch
from
Open
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 @@ -134,6 +134,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 @@ -151,7 +152,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 @@ -975,7 +975,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.RegisterRenderers());
ModLoader.postEvent(new RegisterRenderStateModifiersEvent());
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 @@ -63,12 +62,15 @@ public static void begin(final Minecraft minecraft, final PackRepository default
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