From 2c3e78a35756fe334dd9d4f45ab8ca32afc61bb5 Mon Sep 17 00:00:00 2001
From: asie <kontakt@asie.pl>
Date: Fri, 25 Jan 2019 23:45:12 +0100
Subject: [PATCH] (#72) Resource reloading hooks

---
 .../IdentifiableResourceReloadListener.java   |  65 ++++++++
 .../api/resource/ResourceManagerHelper.java   |  41 +++++
 .../resource/ResourceReloadListenerKeys.java  |  44 ++++++
 .../resources/ResourceManagerHelperImpl.java  |  88 +++++++++++
 .../MixinKeyedResourceReloadListener.java     | 142 ++++++++++++++++++
 .../MixinReloadableResourceManagerImpl.java   |  40 +++++
 .../net.fabricmc.fabric.mixins.client.json    |   1 +
 .../net.fabricmc.fabric.mixins.common.json    |   2 +
 .../resources/ResourceReloadModClient.java    |  77 ++++++++++
 9 files changed, 500 insertions(+)
 create mode 100644 src/main/java/net/fabricmc/fabric/api/resource/IdentifiableResourceReloadListener.java
 create mode 100644 src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java
 create mode 100644 src/main/java/net/fabricmc/fabric/api/resource/ResourceReloadListenerKeys.java
 create mode 100644 src/main/java/net/fabricmc/fabric/impl/resources/ResourceManagerHelperImpl.java
 create mode 100644 src/main/java/net/fabricmc/fabric/mixin/resources/MixinKeyedResourceReloadListener.java
 create mode 100644 src/main/java/net/fabricmc/fabric/mixin/resources/MixinReloadableResourceManagerImpl.java
 create mode 100644 src/test/java/net/fabricmc/fabric/resources/ResourceReloadModClient.java

diff --git a/src/main/java/net/fabricmc/fabric/api/resource/IdentifiableResourceReloadListener.java b/src/main/java/net/fabricmc/fabric/api/resource/IdentifiableResourceReloadListener.java
new file mode 100644
index 000000000..fc17fc7bb
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/api/resource/IdentifiableResourceReloadListener.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.resource;
+
+import net.minecraft.resource.ResourceReloadListener;
+import net.minecraft.util.Identifier;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Interface for "identifiable" resource reload listeners.
+ *
+ * "Identifiable" listeners have an unique identifier, which can be depended on,
+ * and can provide dependencies that they would like to see executed before
+ * themselves.
+ *
+ * {@link ResourceReloadListenerKeys}
+ */
+public interface IdentifiableResourceReloadListener extends ResourceReloadListener {
+	/**
+	 * @return The unique identifier of this listener.
+	 */
+	Identifier getFabricId();
+
+	/**
+	 * @return The identifiers of listeners this listener expects to have been
+	 * executed before itself.
+	 */
+	default Collection<Identifier> getFabricDependencies() {
+		return Collections.emptyList();
+	}
+
+	/**
+	 * By default, resource reload listeners in Minecraft are all executed on
+	 * the game's main thread while the game is paused. This means they do not
+	 * need to provide any guarantees regarding their thread safety, or usage
+	 * of resources potentially modified by other reload listeners.
+	 *
+	 * "Thread safety", in this context, refers simply to independence; namely
+	 * whether or not, under the condition that all of its dependencies have
+	 * already been processed, this resource reload listener can run without
+	 * accessing or modifying areas it does not control in a non-thread-safe
+	 * manner.
+	 *
+	 * @return Whether or not the listener can be executed in a thread-safe way.
+	 */
+	default boolean isListenerThreadSafe() {
+		return false;
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java b/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java
new file mode 100644
index 000000000..917436840
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.resource;
+
+import net.fabricmc.fabric.impl.resources.ResourceManagerHelperImpl;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.resource.ResourceType;
+
+/**
+ * Helper for working with {@link ResourceManager} instances.
+ */
+public interface ResourceManagerHelper {
+	/**
+	 * Add a resource reload listener for a given registry.
+	 * @param listener The resource reload listener.
+	 */
+	void addReloadListener(IdentifiableResourceReloadListener listener);
+
+	/**
+	 * Get the ResourceManagerHelper instance for a given resource type.
+	 * @param type The given resource type.
+	 * @return The ResourceManagerHelper instance.
+	 */
+	static ResourceManagerHelper get(ResourceType type) {
+		return ResourceManagerHelperImpl.get(type);
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/api/resource/ResourceReloadListenerKeys.java b/src/main/java/net/fabricmc/fabric/api/resource/ResourceReloadListenerKeys.java
new file mode 100644
index 000000000..bac69bbcf
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/api/resource/ResourceReloadListenerKeys.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.resource;
+
+import net.minecraft.util.Identifier;
+
+/**
+ * This class contains default keys for various Minecraft resource reload listeners.
+ *
+ * {@link IdentifiableResourceReloadListener}
+ */
+public final class ResourceReloadListenerKeys {
+	// client
+	public static final Identifier SOUNDS = new Identifier("minecraft:sounds");
+	public static final Identifier FONTS = new Identifier("minecraft:fonts");
+	public static final Identifier MODELS = new Identifier("minecraft:models");
+	public static final Identifier LANGUAGES = new Identifier("minecraft:languages");
+	public static final Identifier TEXTURES = new Identifier("minecraft:textures");
+
+	// server
+	public static final Identifier TAGS = new Identifier("minecraft:tags");
+	public static final Identifier RECIPES = new Identifier("minecraft:recipes");
+	public static final Identifier ADVANCEMENTS = new Identifier("minecraft:advancements");
+	public static final Identifier FUNCTIONS = new Identifier("minecraft:functions");
+	public static final Identifier LOOT_TABLES = new Identifier("minecraft:loot_tables");
+
+	private ResourceReloadListenerKeys() {
+
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/impl/resources/ResourceManagerHelperImpl.java b/src/main/java/net/fabricmc/fabric/impl/resources/ResourceManagerHelperImpl.java
new file mode 100644
index 000000000..61f984af4
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/impl/resources/ResourceManagerHelperImpl.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.resources;
+
+import com.google.common.collect.Lists;
+import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
+import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
+import net.minecraft.resource.ResourceReloadListener;
+import net.minecraft.resource.ResourceType;
+import net.minecraft.util.Identifier;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.*;
+
+public class ResourceManagerHelperImpl implements ResourceManagerHelper {
+	private static final Map<ResourceType, ResourceManagerHelperImpl> registryMap = new HashMap<>();
+	private static final Logger LOGGER = LogManager.getLogger();
+
+	private final List<IdentifiableResourceReloadListener> addedListeners = new ArrayList<>();
+
+	public static ResourceManagerHelper get(ResourceType type) {
+		return registryMap.computeIfAbsent(type, (t) -> new ResourceManagerHelperImpl());
+	}
+
+	public static void sort(ResourceType type, List<ResourceReloadListener> listeners) {
+		ResourceManagerHelperImpl instance = registryMap.get(type);
+		if (instance != null) {
+			instance.sort(listeners);
+		}
+	}
+
+	protected void sort(List<ResourceReloadListener> listeners) {
+		listeners.removeAll(addedListeners);
+
+		// General rules:
+		// - We *do not* touch the ordering of vanilla listeners. Ever.
+		//   While dependency values are provided where possible, we cannot
+		//   trust them 100%. Only code doesn't lie.
+		// - We addReloadListener all custom listeners after vanilla listeners. Same reasons.
+
+		List<IdentifiableResourceReloadListener> listenersToAdd = Lists.newArrayList(addedListeners);
+		Set<Identifier> resolvedIds = new HashSet<>();
+		for (ResourceReloadListener listener : listeners) {
+			if (listener instanceof IdentifiableResourceReloadListener) {
+				resolvedIds.add(((IdentifiableResourceReloadListener) listener).getFabricId());
+			}
+		}
+
+		int lastSize = -1;
+		while (listeners.size() != lastSize) {
+			lastSize = listeners.size();
+
+			Iterator<IdentifiableResourceReloadListener> it = listenersToAdd.iterator();
+			while (it.hasNext()) {
+				IdentifiableResourceReloadListener listener = it.next();
+				if (resolvedIds.containsAll(listener.getFabricDependencies())) {
+					resolvedIds.add(listener.getFabricId());
+					listeners.add(listener);
+					it.remove();
+				}
+			}
+		}
+
+		for (IdentifiableResourceReloadListener listener : listenersToAdd) {
+			LOGGER.warn("Could not resolve dependencies for listener: " + listener.getFabricId() + "!");
+		}
+	}
+
+	@Override
+	public void addReloadListener(IdentifiableResourceReloadListener listener) {
+		addedListeners.add(listener);
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/mixin/resources/MixinKeyedResourceReloadListener.java b/src/main/java/net/fabricmc/fabric/mixin/resources/MixinKeyedResourceReloadListener.java
new file mode 100644
index 000000000..fa2163e01
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/mixin/resources/MixinKeyedResourceReloadListener.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.resources;
+
+import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
+import net.fabricmc.fabric.api.resource.ResourceReloadListenerKeys;
+import net.minecraft.client.audio.SoundLoader;
+import net.minecraft.client.font.FontRendererManager;
+import net.minecraft.client.render.WorldRenderer;
+import net.minecraft.client.render.block.BlockRenderManager;
+import net.minecraft.client.render.item.ItemRenderer;
+import net.minecraft.client.render.model.BakedModelManager;
+import net.minecraft.client.resource.language.LanguageManager;
+import net.minecraft.client.texture.TextureManager;
+import net.minecraft.recipe.RecipeManager;
+import net.minecraft.server.ServerAdvancementLoader;
+import net.minecraft.server.function.CommandFunctionManager;
+import net.minecraft.tag.TagManager;
+import net.minecraft.util.Identifier;
+import net.minecraft.world.loot.LootManager;
+import org.spongepowered.asm.mixin.Mixin;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class MixinKeyedResourceReloadListener {
+	@Mixin({
+		/* public */
+		SoundLoader.class, FontRendererManager.class, BakedModelManager.class, LanguageManager.class, TextureManager.class,
+		/* private */
+		WorldRenderer.class, BlockRenderManager.class, ItemRenderer.class
+	})
+	public static abstract class Client implements IdentifiableResourceReloadListener {
+		private Collection<Identifier> fabric_idDeps;
+		private Identifier fabric_id;
+
+		@Override
+		@SuppressWarnings({ "ConstantConditions", "RedundantCast" })
+		public Collection<Identifier> getFabricDependencies() {
+			if (fabric_idDeps == null) {
+				Object self = (Object) this;
+				if (self instanceof BakedModelManager || self instanceof WorldRenderer) {
+					fabric_idDeps = Collections.singletonList(ResourceReloadListenerKeys.TEXTURES);
+				} else if (self instanceof ItemRenderer || self instanceof BlockRenderManager) {
+					fabric_idDeps = Collections.singletonList(ResourceReloadListenerKeys.MODELS);
+				} else {
+					fabric_idDeps = Collections.emptyList();
+				}
+			}
+
+			return fabric_idDeps;
+		}
+
+		@Override
+		@SuppressWarnings({ "ConstantConditions", "RedundantCast" })
+		public Identifier getFabricId() {
+			if (fabric_id == null) {
+				Object self = (Object) this;
+
+				if (self instanceof SoundLoader) {
+					fabric_id = ResourceReloadListenerKeys.SOUNDS;
+				} else if (self instanceof FontRendererManager) {
+					fabric_id = ResourceReloadListenerKeys.FONTS;
+				} else if (self instanceof BakedModelManager) {
+					fabric_id = ResourceReloadListenerKeys.MODELS;
+				} else if (self instanceof LanguageManager) {
+					fabric_id = ResourceReloadListenerKeys.LANGUAGES;
+				} else if (self instanceof TextureManager) {
+					fabric_id = ResourceReloadListenerKeys.TEXTURES;
+				} else {
+					fabric_id = new Identifier("minecraft", "private/" + self.getClass().getSimpleName());
+				}
+			}
+
+			return fabric_id;
+		}
+	}
+
+	@Mixin({
+		/* public */
+		RecipeManager.class, ServerAdvancementLoader.class, CommandFunctionManager.class, LootManager.class, TagManager.class
+		/* private */
+	})
+	public static abstract class Server implements IdentifiableResourceReloadListener {
+		private Collection<Identifier> fabric_idDeps;
+		private Identifier fabric_id;
+
+		@Override
+		@SuppressWarnings({ "ConstantConditions", "RedundantCast" })
+		public Collection<Identifier> getFabricDependencies() {
+			if (fabric_idDeps == null) {
+				Object self = (Object) this;
+
+				if (self instanceof TagManager) {
+					fabric_idDeps = Collections.emptyList();
+				} else {
+					fabric_idDeps = Collections.singletonList(ResourceReloadListenerKeys.TAGS);
+				}
+			}
+
+			return fabric_idDeps;
+		}
+
+		@Override
+		@SuppressWarnings({ "ConstantConditions", "RedundantCast" })
+		public Identifier getFabricId() {
+			if (fabric_id == null) {
+				Object self = (Object) this;
+;
+				if (self instanceof RecipeManager) {
+					fabric_id = ResourceReloadListenerKeys.RECIPES;
+				} else if (self instanceof ServerAdvancementLoader) {
+					fabric_id = ResourceReloadListenerKeys.ADVANCEMENTS;
+				} else if (self instanceof CommandFunctionManager) {
+					fabric_id = ResourceReloadListenerKeys.FUNCTIONS;
+				} else if (self instanceof LootManager) {
+					fabric_id = ResourceReloadListenerKeys.LOOT_TABLES;
+				} else if (self instanceof TagManager) {
+					fabric_id = ResourceReloadListenerKeys.TAGS;
+				} else {
+					fabric_id = new Identifier("minecraft", "private/" + self.getClass().getSimpleName());
+				}
+			}
+
+			return fabric_id;
+		}
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/mixin/resources/MixinReloadableResourceManagerImpl.java b/src/main/java/net/fabricmc/fabric/mixin/resources/MixinReloadableResourceManagerImpl.java
new file mode 100644
index 000000000..c3b864b18
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/mixin/resources/MixinReloadableResourceManagerImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.resources;
+
+import net.fabricmc.fabric.impl.resources.ResourceManagerHelperImpl;
+import net.minecraft.resource.*;
+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.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.util.List;
+
+@Mixin(ReloadableResourceManagerImpl.class)
+public class MixinReloadableResourceManagerImpl {
+	@Shadow
+	private List<ResourceReloadListener> listeners;
+	@Shadow
+	private ResourceType type;
+
+	@Inject(at = @At("HEAD"), method = "reload")
+	public void reload(List<ResourcePack> packs, CallbackInfo info) {
+		ResourceManagerHelperImpl.sort(type, listeners);
+	}
+}
diff --git a/src/main/resources/net.fabricmc.fabric.mixins.client.json b/src/main/resources/net.fabricmc.fabric.mixins.client.json
index 9e3227ff0..20abc037a 100644
--- a/src/main/resources/net.fabricmc.fabric.mixins.client.json
+++ b/src/main/resources/net.fabricmc.fabric.mixins.client.json
@@ -21,6 +21,7 @@
     "registry.client.MixinBlockColorMap",
     "registry.client.MixinItemColorMap",
     "registry.client.MixinItemModelMap",
+    "resources.MixinKeyedResourceReloadListener$Client",
     "resources.MixinMinecraftGame"
   ],
   "injectors": {
diff --git a/src/main/resources/net.fabricmc.fabric.mixins.common.json b/src/main/resources/net.fabricmc.fabric.mixins.common.json
index a3f34a861..137fd6dfa 100644
--- a/src/main/resources/net.fabricmc.fabric.mixins.common.json
+++ b/src/main/resources/net.fabricmc.fabric.mixins.common.json
@@ -27,7 +27,9 @@
     "registry.MixinIdRegistry",
     "registry.MixinServerPlayNetworkHandler",
     "registry.MixinWorldSaveHandler",
+    "resources.MixinKeyedResourceReloadListener$Server",
     "resources.MixinMinecraftServer",
+    "resources.MixinReloadableResourceManagerImpl",
     "tools.MixinItemStack",
     "tools.MixinMiningToolItem"
   ],
diff --git a/src/test/java/net/fabricmc/fabric/resources/ResourceReloadModClient.java b/src/test/java/net/fabricmc/fabric/resources/ResourceReloadModClient.java
new file mode 100644
index 000000000..f81db2fa0
--- /dev/null
+++ b/src/test/java/net/fabricmc/fabric/resources/ResourceReloadModClient.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.resources;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
+import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.resource.ResourceType;
+import net.minecraft.util.Identifier;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class ResourceReloadModClient implements ClientModInitializer {
+	@Override
+	public void onInitializeClient() {
+		ResourceManagerHelper.get(ResourceType.ASSETS).addReloadListener(new IdentifiableResourceReloadListener() {
+			@Override
+			public Identifier getFabricId() {
+				return new Identifier("fabric:rrmc2");
+			}
+
+			@Override
+			public Collection<Identifier> getFabricDependencies() {
+				return Collections.singletonList(new Identifier("fabric:rrmc1"));
+			}
+
+			@Override
+			public void onResourceReload(ResourceManager var1) {
+				System.out.println("Reloading (should run as #2)");
+			}
+		});
+
+		ResourceManagerHelper.get(ResourceType.ASSETS).addReloadListener(new IdentifiableResourceReloadListener() {
+			@Override
+			public Identifier getFabricId() {
+				return new Identifier("fabric:rrmc1");
+			}
+
+			@Override
+			public void onResourceReload(ResourceManager var1) {
+				System.out.println("Reloading (should run as #1)");
+			}
+		});
+
+		ResourceManagerHelper.get(ResourceType.ASSETS).addReloadListener(new IdentifiableResourceReloadListener() {
+			@Override
+			public Identifier getFabricId() {
+				return new Identifier("fabric:rrmc_should_not_resolve");
+			}
+
+			@Override
+			public Collection<Identifier> getFabricDependencies() {
+				return Collections.singletonList(new Identifier("fabric:rrmc_nonexistent"));
+			}
+
+			@Override
+			public void onResourceReload(ResourceManager var1) {
+			}
+		});
+	}
+}