Skip to content

Commit

Permalink
Add Dynamic (DataPack, WorldGen) registries support
Browse files Browse the repository at this point in the history
Signed-off-by: Sergey Shatunov <[email protected]>
  • Loading branch information
Prototik committed Dec 24, 2023
1 parent 7d771c2 commit 3bae05c
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -76,6 +78,59 @@ public final <T> RegistrarBuilder<T> builder(ResourceLocation registryId, T... t
return this.provider.builder((Class<T>) typeGetter.getClass().getComponentType(), registryId);
}

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

/**
* Registers a synced dynamic registry.
*
* <p>The entries of the registry will be loaded from data packs at the file path
* {@code data/<entry namespace>/<registry namespace>/<registry path>/<entry path>.json}.
*
* <p>The registry will be synced from the server to players' clients using the same codec
* that is used to load the registry.
*
* <p>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 <T> the type of registry entry
*/
public <T> void dynamicRegistrySynced(ResourceKey<Registry<T>> key, @NotNull Codec<T> codec) {
this.provider.registerDynamicRegistrySynced(key, codec, codec);
}


/**
* Registers a synced dynamic registry.
*
* <p>The entries of the registry will be loaded from data packs at the file path
* {@code data/<entry namespace>/<registry namespace>/<registry path>/<entry path>.json}
*
* <p>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 <T> the type of registry entry
*/
public <T> void dynamicRegistrySynced(ResourceKey<Registry<T>> key, @NotNull Codec<T> dataCodec, @NotNull Codec<T> networkCodec) {
this.provider.registerDynamicRegistrySynced(key, dataCodec, networkCodec);
}

/**
* Forge: If the object is {@code IForgeRegistryEntry}, use `getRegistryName`, else null
* Fabric: Use registry
Expand Down Expand Up @@ -118,5 +173,9 @@ public interface RegistryProvider {
<T> void forRegistry(ResourceKey<Registry<T>> key, Consumer<Registrar<T>> consumer);

<T> RegistrarBuilder<T> builder(Class<T> type, ResourceLocation registryId);

<T> void registerDynamicRegistry(ResourceKey<Registry<T>> key, Codec<T> dataCodec);

<T> void registerDynamicRegistrySynced(ResourceKey<Registry<T>> key, Codec<T> dataCodec, Codec<T> networkCodec);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
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;
import dev.architectury.registry.registries.RegistrarManager;
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;
Expand Down Expand Up @@ -94,6 +96,16 @@ public <T> void forRegistry(ResourceKey<Registry<T>> key, Consumer<Registrar<T>>
public <T> RegistrarBuilder<T> builder(Class<T> type, ResourceLocation registryId) {
return new RegistrarBuilderWrapper<>(modId, FabricRegistryBuilder.createSimple(type, registryId));
}

@Override
public <T> void registerDynamicRegistry(ResourceKey<Registry<T>> key, Codec<T> dataCodec) {
DynamicRegistries.register(key, dataCodec);
}

@Override
public <T> void registerDynamicRegistrySynced(ResourceKey<Registry<T>> key, Codec<T> dataCodec, Codec<T> networkCodec) {
DynamicRegistries.registerSynced(key, dataCodec, networkCodec);
}
}

public static class RegistryEntryId<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -122,6 +123,9 @@ record RegistryBuilderEntry(RegistryBuilder<?> builder, Consumer<IForgeRegistry<
@Nullable
private List<RegistryBuilderEntry> builders = new ArrayList<>();

@Nullable
private List<DynamicRegistryData<?>> newDynamicRegistries = new ArrayList<>();

public RegistryProviderImpl(String modId) {
this.modId = modId;
this.eventBus = Suppliers.memoize(() -> {
Expand Down Expand Up @@ -177,6 +181,36 @@ public <T> RegistrarBuilder<T> builder(Class<T> type, ResourceLocation registryI
.setName(registryId), registryId);
}

@Override
public <T> void registerDynamicRegistry(ResourceKey<Registry<T>> key, Codec<T> dataCodec) {
if (newDynamicRegistries == null) {
throw new IllegalStateException("Cannot create registries when registries are already aggregated!");
}
newDynamicRegistries.add(new DynamicRegistryData<>(key, dataCodec, null));
}

@Override
public <T> void registerDynamicRegistrySynced(ResourceKey<Registry<T>> key, Codec<T> dataCodec, Codec<T> 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<T>(
ResourceKey<Registry<T>> key,
Codec<T> dataCodec,
@Nullable Codec<T> 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) {
Expand Down Expand Up @@ -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;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -108,6 +110,9 @@ public static class RegistryProviderImpl implements RegistrarManager.RegistryPro
@Nullable
private List<Registry<?>> newRegistries = new ArrayList<>();

@Nullable
private List<DynamicRegistryData<?>> newDynamicRegistries = new ArrayList<>();

public RegistryProviderImpl(String modId) {
this.modId = modId;
this.eventBus = Suppliers.memoize(() -> {
Expand Down Expand Up @@ -153,6 +158,35 @@ public <T> RegistrarBuilder<T> builder(Class<T> type, ResourceLocation registryI
return new RegistryBuilderWrapper<>(this, new RegistryBuilder<>(ResourceKey.createRegistryKey(registryId)));
}

@Override
public <T> void registerDynamicRegistry(ResourceKey<Registry<T>> key, Codec<T> dataCodec) {
if (newDynamicRegistries == null) {
throw new IllegalStateException("Cannot create registries when registries are already aggregated!");
}
newDynamicRegistries.add(new DynamicRegistryData<>(key, dataCodec, null));
}

@Override
public <T> void registerDynamicRegistrySynced(ResourceKey<Registry<T>> key, Codec<T> dataCodec, Codec<T> 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<T>(
ResourceKey<Registry<T>> key,
Codec<T> dataCodec,
@Nullable Codec<T> 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) {
Expand Down Expand Up @@ -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;
}
}
}
}

Expand Down

0 comments on commit 3bae05c

Please sign in to comment.