mirror of
https://github.com/FabricMC/fabric.git
synced 2025-03-25 22:39:50 -04:00
Add API to create reload listeners with a registry lookup. (#3927)
* Add API to create reload listeners with a registry lookup. * Document this is only for server data * Review feedback
This commit is contained in:
parent
8cfd8554f6
commit
7e687b320e
4 changed files with 127 additions and 7 deletions
fabric-resource-loader-v0/src
main
java/net/fabricmc/fabric
resources
testmod/java/net/fabricmc/fabric/test/resource/loader
|
@ -16,8 +16,11 @@
|
|||
|
||||
package net.fabricmc.fabric.api.resource;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.registry.RegistryWrapper;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
import net.minecraft.text.Text;
|
||||
|
@ -49,6 +52,16 @@ public interface ResourceManagerHelper {
|
|||
*/
|
||||
void registerReloadListener(IdentifiableResourceReloadListener listener);
|
||||
|
||||
/**
|
||||
* Register a resource reload listener for a given resource manager type.
|
||||
*
|
||||
* <p>Note: This is only supported for server data reload listeners.
|
||||
*
|
||||
* @param identifier The identifier of the listener.
|
||||
* @param listenerFactory A function that creates a new instance of the listener with a given registry lookup.
|
||||
*/
|
||||
void registerReloadListener(Identifier identifier, Function<RegistryWrapper.WrapperLookup, IdentifiableResourceReloadListener> listenerFactory);
|
||||
|
||||
/**
|
||||
* Get the ResourceManagerHelper instance for a given resource type.
|
||||
*
|
||||
|
|
|
@ -25,13 +25,18 @@ import java.util.Iterator;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.recipe.RecipeManager;
|
||||
import net.minecraft.registry.RegistryWrapper;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackInfo;
|
||||
import net.minecraft.resource.ResourcePackPosition;
|
||||
|
@ -53,10 +58,16 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
|||
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceManagerHelperImpl.class);
|
||||
|
||||
private final Set<Identifier> addedListenerIds = new HashSet<>();
|
||||
private final Set<ListenerFactory> listenerFactories = new LinkedHashSet<>();
|
||||
private final Set<IdentifiableResourceReloadListener> addedListeners = new LinkedHashSet<>();
|
||||
private final ResourceType type;
|
||||
|
||||
private ResourceManagerHelperImpl(ResourceType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static ResourceManagerHelperImpl get(ResourceType type) {
|
||||
return registryMap.computeIfAbsent(type, (t) -> new ResourceManagerHelperImpl());
|
||||
return registryMap.computeIfAbsent(type, ResourceManagerHelperImpl::new);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,7 +85,7 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
|||
public static boolean registerBuiltinResourcePack(Identifier id, String subPath, ModContainer container, Text displayName, ResourcePackActivationType activationType) {
|
||||
// Assuming the mod has multiple paths, we simply "hope" that the file separator is *not* different across them
|
||||
List<Path> paths = container.getRootPaths();
|
||||
String separator = paths.get(0).getFileSystem().getSeparator();
|
||||
String separator = paths.getFirst().getFileSystem().getSeparator();
|
||||
subPath = subPath.replace("/", separator);
|
||||
ModNioResourcePack resourcePack = ModNioResourcePack.create(id.toString(), container, subPath, ResourceType.CLIENT_RESOURCES, activationType, false);
|
||||
ModNioResourcePack dataPack = ModNioResourcePack.create(id.toString(), container, subPath, ResourceType.SERVER_DATA, activationType, false);
|
||||
|
@ -168,7 +179,16 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
|||
// trust them 100%. Only code doesn't lie.
|
||||
// - We addReloadListener all custom listeners after vanilla listeners. Same reasons.
|
||||
|
||||
List<IdentifiableResourceReloadListener> listenersToAdd = Lists.newArrayList(addedListeners);
|
||||
final RegistryWrapper.WrapperLookup wrapperLookup = getWrapperLookup(listeners);
|
||||
List<IdentifiableResourceReloadListener> listenersToAdd = Lists.newArrayList();
|
||||
|
||||
for (ListenerFactory addedListener : listenerFactories) {
|
||||
listenersToAdd.add(addedListener.get(wrapperLookup));
|
||||
}
|
||||
|
||||
addedListeners.clear();
|
||||
addedListeners.addAll(listenersToAdd);
|
||||
|
||||
Set<Identifier> resolvedIds = new HashSet<>();
|
||||
|
||||
for (ResourceReloader listener : listeners) {
|
||||
|
@ -200,15 +220,80 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
|||
}
|
||||
}
|
||||
|
||||
// A bit of a hack to get the registry, but it works.
|
||||
@Nullable
|
||||
private RegistryWrapper.WrapperLookup getWrapperLookup(List<ResourceReloader> listeners) {
|
||||
if (type == ResourceType.CLIENT_RESOURCES) {
|
||||
// We don't need the registry for client resources.
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ResourceReloader resourceReloader : listeners) {
|
||||
if (resourceReloader instanceof RecipeManager recipeManager) {
|
||||
return recipeManager.registryLookup;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No RecipeManager found in listeners!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReloadListener(IdentifiableResourceReloadListener listener) {
|
||||
if (!addedListenerIds.add(listener.getFabricId())) {
|
||||
LOGGER.warn("Tried to register resource reload listener " + listener.getFabricId() + " twice!");
|
||||
registerReloadListener(new SimpleResourceReloaderFactory(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReloadListener(Identifier identifier, Function<RegistryWrapper.WrapperLookup, IdentifiableResourceReloadListener> listenerFactory) {
|
||||
if (type == ResourceType.CLIENT_RESOURCES) {
|
||||
throw new IllegalArgumentException("Cannot register a registry listener for the client resource type!");
|
||||
}
|
||||
|
||||
registerReloadListener(new RegistryResourceReloaderFactory(identifier, listenerFactory));
|
||||
}
|
||||
|
||||
private void registerReloadListener(ListenerFactory factory) {
|
||||
if (!addedListenerIds.add(factory.id())) {
|
||||
LOGGER.warn("Tried to register resource reload listener " + factory.id() + " twice!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!addedListeners.add(listener)) {
|
||||
throw new RuntimeException("Listener with previously unknown ID " + listener.getFabricId() + " already in listener set!");
|
||||
if (!listenerFactories.add(factory)) {
|
||||
throw new RuntimeException("Listener with previously unknown ID " + factory.id() + " already in listener set!");
|
||||
}
|
||||
}
|
||||
|
||||
private sealed interface ListenerFactory permits SimpleResourceReloaderFactory, RegistryResourceReloaderFactory {
|
||||
Identifier id();
|
||||
|
||||
IdentifiableResourceReloadListener get(RegistryWrapper.WrapperLookup registry);
|
||||
}
|
||||
|
||||
private record SimpleResourceReloaderFactory(IdentifiableResourceReloadListener listener) implements ListenerFactory {
|
||||
@Override
|
||||
public Identifier id() {
|
||||
return listener.getFabricId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifiableResourceReloadListener get(RegistryWrapper.WrapperLookup registry) {
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
|
||||
private record RegistryResourceReloaderFactory(Identifier id, Function<RegistryWrapper.WrapperLookup, IdentifiableResourceReloadListener> listenerFactory) implements ListenerFactory {
|
||||
private RegistryResourceReloaderFactory {
|
||||
Objects.requireNonNull(listenerFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifiableResourceReloadListener get(RegistryWrapper.WrapperLookup registry) {
|
||||
final IdentifiableResourceReloadListener listener = listenerFactory.apply(registry);
|
||||
|
||||
if (!id.equals(listener.getFabricId())) {
|
||||
throw new IllegalStateException("Listener factory for " + id + " created a listener with ID " + listener.getFabricId());
|
||||
}
|
||||
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,3 +4,4 @@ accessible method net/minecraft/resource/NamespaceResourceManager getMetadataPat
|
|||
accessible method net/minecraft/resource/NamespaceResourceManager loadMetadata (Lnet/minecraft/resource/InputSupplier;)Lnet/minecraft/resource/metadata/ResourceMetadata;
|
||||
accessible field net/minecraft/resource/FileResourcePackProvider source Lnet/minecraft/resource/ResourcePackSource;
|
||||
accessible field net/minecraft/resource/ResourcePackManager providers Ljava/util/Set;
|
||||
accessible field net/minecraft/recipe/RecipeManager registryLookup Lnet/minecraft/registry/RegistryWrapper$WrapperLookup;
|
||||
|
|
|
@ -18,7 +18,11 @@ package net.fabricmc.fabric.test.resource.loader;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.enchantment.Enchantments;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.RegistryWrapper;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -116,5 +120,22 @@ public class ResourceReloadListenerTestMod implements ModInitializer {
|
|||
serverResources = true;
|
||||
}
|
||||
});
|
||||
|
||||
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(RegistryReloader.ID, RegistryReloader::new);
|
||||
}
|
||||
|
||||
private record RegistryReloader(RegistryWrapper.WrapperLookup wrapperLookup) implements SimpleSynchronousResourceReloadListener {
|
||||
private static final Identifier ID = Identifier.of(MODID, "registry_reloader");
|
||||
|
||||
@Override
|
||||
public Identifier getFabricId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(ResourceManager manager) {
|
||||
Objects.requireNonNull(wrapperLookup);
|
||||
wrapperLookup.getWrapperOrThrow(RegistryKeys.ENCHANTMENT).getOrThrow(Enchantments.FORTUNE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue