From 3bae05ca102792d4f65894da5c7417e4aae7d7d4 Mon Sep 17 00:00:00 2001 From: Sergey Shatunov Date: Sun, 24 Dec 2023 18:51:32 +0800 Subject: [PATCH] Add Dynamic (DataPack, WorldGen) registries support Signed-off-by: Sergey Shatunov --- .../registry/registries/RegistrarManager.java | 59 +++++++++++++++++++ .../fabric/RegistrarManagerImpl.java | 12 ++++ .../forge/RegistrarManagerImpl.java | 44 ++++++++++++++ .../forge/RegistrarManagerImpl.java | 44 ++++++++++++++ 4 files changed, 159 insertions(+) diff --git a/common/src/main/java/dev/architectury/registry/registries/RegistrarManager.java b/common/src/main/java/dev/architectury/registry/registries/RegistrarManager.java index 4d8697838..cf5a8aa63 100644 --- a/common/src/main/java/dev/architectury/registry/registries/RegistrarManager.java +++ b/common/src/main/java/dev/architectury/registry/registries/RegistrarManager.java @@ -19,12 +19,14 @@ package dev.architectury.registry.registries; +import com.mojang.serialization.Codec; import dev.architectury.injectables.annotations.ExpectPlatform; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -76,6 +78,59 @@ public final RegistrarBuilder builder(ResourceLocation registryId, T... t return this.provider.builder((Class) typeGetter.getClass().getComponentType(), registryId); } + /** + * Registers a non-synced dynamic registry. + * + *

The entries of the registry will be loaded from data packs at the file path + * {@code data////.json}. + * + * @param key the key of the registry + * @param codec the codec used to load registry entries from data packs + * @param the type of registry entry + */ + public void dynamicRegistry(ResourceKey> key, @NotNull Codec codec) { + this.provider.registerDynamicRegistry(key, codec); + } + + /** + * Registers a synced dynamic registry. + * + *

The entries of the registry will be loaded from data packs at the file path + * {@code data////.json}. + * + *

The registry will be synced from the server to players' clients using the same codec + * that is used to load the registry. + * + *

If the object contained in the registry is complex and contains a lot of data + * that is not relevant on the client, another codec for networking can be specified with + * {@link #dynamicRegistrySynced(ResourceKey, Codec, Codec)}. + * + * @param key the key of the registry + * @param codec the codec used to load registry entries from data packs and the network + * @param the type of registry entry + */ + public void dynamicRegistrySynced(ResourceKey> key, @NotNull Codec codec) { + this.provider.registerDynamicRegistrySynced(key, codec, codec); + } + + + /** + * Registers a synced dynamic registry. + * + *

The entries of the registry will be loaded from data packs at the file path + * {@code data////.json} + * + *

The registry will be synced from the server to players' clients using the given network codec. + * + * @param key the key of the registry + * @param dataCodec the codec used to load registry entries from data packs + * @param networkCodec the codec used to load registry entries from the network + * @param the type of registry entry + */ + public void dynamicRegistrySynced(ResourceKey> key, @NotNull Codec dataCodec, @NotNull Codec networkCodec) { + this.provider.registerDynamicRegistrySynced(key, dataCodec, networkCodec); + } + /** * Forge: If the object is {@code IForgeRegistryEntry}, use `getRegistryName`, else null * Fabric: Use registry @@ -118,5 +173,9 @@ public interface RegistryProvider { void forRegistry(ResourceKey> key, Consumer> consumer); RegistrarBuilder builder(Class type, ResourceLocation registryId); + + void registerDynamicRegistry(ResourceKey> key, Codec dataCodec); + + void registerDynamicRegistrySynced(ResourceKey> key, Codec dataCodec, Codec networkCodec); } } diff --git a/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistrarManagerImpl.java b/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistrarManagerImpl.java index 35d768071..177ad7a29 100644 --- a/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistrarManagerImpl.java +++ b/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistrarManagerImpl.java @@ -23,6 +23,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.mojang.serialization.Codec; import dev.architectury.impl.RegistrySupplierImpl; import dev.architectury.registry.registries.Registrar; import dev.architectury.registry.registries.RegistrarBuilder; @@ -30,6 +31,7 @@ import dev.architectury.registry.registries.RegistrySupplier; import dev.architectury.registry.registries.options.RegistrarOption; import dev.architectury.registry.registries.options.StandardRegistrarOption; +import net.fabricmc.fabric.api.event.registry.DynamicRegistries; import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; import net.fabricmc.fabric.api.event.registry.RegistryAttribute; import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; @@ -94,6 +96,16 @@ public void forRegistry(ResourceKey> key, Consumer> public RegistrarBuilder builder(Class type, ResourceLocation registryId) { return new RegistrarBuilderWrapper<>(modId, FabricRegistryBuilder.createSimple(type, registryId)); } + + @Override + public void registerDynamicRegistry(ResourceKey> key, Codec dataCodec) { + DynamicRegistries.register(key, dataCodec); + } + + @Override + public void registerDynamicRegistrySynced(ResourceKey> key, Codec dataCodec, Codec networkCodec) { + DynamicRegistries.registerSynced(key, dataCodec, networkCodec); + } } public static class RegistryEntryId { diff --git a/minecraftforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java b/minecraftforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java index a688b5b8f..ace409f57 100644 --- a/minecraftforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java +++ b/minecraftforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java @@ -23,6 +23,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.mojang.serialization.Codec; import dev.architectury.impl.RegistrySupplierImpl; import dev.architectury.platform.hooks.EventBusesHooks; import dev.architectury.registry.registries.Registrar; @@ -122,6 +123,9 @@ record RegistryBuilderEntry(RegistryBuilder builder, Consumer builders = new ArrayList<>(); + @Nullable + private List> newDynamicRegistries = new ArrayList<>(); + public RegistryProviderImpl(String modId) { this.modId = modId; this.eventBus = Suppliers.memoize(() -> { @@ -177,6 +181,36 @@ public RegistrarBuilder builder(Class type, ResourceLocation registryI .setName(registryId), registryId); } + @Override + public void registerDynamicRegistry(ResourceKey> key, Codec dataCodec) { + if (newDynamicRegistries == null) { + throw new IllegalStateException("Cannot create registries when registries are already aggregated!"); + } + newDynamicRegistries.add(new DynamicRegistryData<>(key, dataCodec, null)); + } + + @Override + public void registerDynamicRegistrySynced(ResourceKey> key, Codec dataCodec, Codec networkCodec) { + if (newDynamicRegistries == null) { + throw new IllegalStateException("Cannot create registries when registries are already aggregated!"); + } + newDynamicRegistries.add(new DynamicRegistryData<>(key, dataCodec, networkCodec)); + } + + private record DynamicRegistryData( + ResourceKey> key, + Codec dataCodec, + @Nullable Codec networkCodec) { + public void register(DataPackRegistryEvent.NewRegistry event) { + if (networkCodec != null) { + event.dataPackRegistry(key, dataCodec, networkCodec); + } else { + event.dataPackRegistry(key, dataCodec); + } + } + } + + public class EventListener { @SubscribeEvent public void handleEvent(RegisterEvent event) { @@ -266,6 +300,16 @@ public void handleEvent(NewRegistryEvent event) { builders = null; } } + + @SubscribeEvent + public void handleEvent(DataPackRegistryEvent.NewRegistry event) { + if (newDynamicRegistries != null) { + for (DynamicRegistryData data : newDynamicRegistries) { + data.register(event); + } + newDynamicRegistries = null; + } + } } } diff --git a/neoforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java b/neoforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java index e51de44ac..1afa0af68 100644 --- a/neoforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java +++ b/neoforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java @@ -23,6 +23,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.mojang.serialization.Codec; import dev.architectury.impl.RegistrySupplierImpl; import dev.architectury.platform.hooks.forge.EventBusesHooksImpl; import dev.architectury.registry.registries.Registrar; @@ -39,6 +40,7 @@ import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.registries.DataPackRegistryEvent; import net.neoforged.neoforge.registries.NewRegistryEvent; import net.neoforged.neoforge.registries.RegisterEvent; import net.neoforged.neoforge.registries.RegistryBuilder; @@ -108,6 +110,9 @@ public static class RegistryProviderImpl implements RegistrarManager.RegistryPro @Nullable private List> newRegistries = new ArrayList<>(); + @Nullable + private List> newDynamicRegistries = new ArrayList<>(); + public RegistryProviderImpl(String modId) { this.modId = modId; this.eventBus = Suppliers.memoize(() -> { @@ -153,6 +158,35 @@ public RegistrarBuilder builder(Class type, ResourceLocation registryI return new RegistryBuilderWrapper<>(this, new RegistryBuilder<>(ResourceKey.createRegistryKey(registryId))); } + @Override + public void registerDynamicRegistry(ResourceKey> key, Codec dataCodec) { + if (newDynamicRegistries == null) { + throw new IllegalStateException("Cannot create registries when registries are already aggregated!"); + } + newDynamicRegistries.add(new DynamicRegistryData<>(key, dataCodec, null)); + } + + @Override + public void registerDynamicRegistrySynced(ResourceKey> key, Codec dataCodec, Codec networkCodec) { + if (newDynamicRegistries == null) { + throw new IllegalStateException("Cannot create registries when registries are already aggregated!"); + } + newDynamicRegistries.add(new DynamicRegistryData<>(key, dataCodec, networkCodec)); + } + + private record DynamicRegistryData( + ResourceKey> key, + Codec dataCodec, + @Nullable Codec networkCodec) { + public void register(DataPackRegistryEvent.NewRegistry event) { + if (networkCodec != null) { + event.dataPackRegistry(key, dataCodec, networkCodec); + } else { + event.dataPackRegistry(key, dataCodec); + } + } + } + public class EventListener { @SubscribeEvent public void handleEvent(RegisterEvent event) { @@ -225,6 +259,16 @@ public void handleEvent(NewRegistryEvent event) { newRegistries = null; } } + + @SubscribeEvent + public void handleEvent(DataPackRegistryEvent.NewRegistry event) { + if (newDynamicRegistries != null) { + for (DynamicRegistryData data : newDynamicRegistries) { + data.register(event); + } + newDynamicRegistries = null; + } + } } }