diff --git a/src/main/java/net/minecraftforge/registries/DeferredRegister.java b/src/main/java/net/minecraftforge/registries/DeferredRegister.java index dcb6b1ab9a..bd274749de 100644 --- a/src/main/java/net/minecraftforge/registries/DeferredRegister.java +++ b/src/main/java/net/minecraftforge/registries/DeferredRegister.java @@ -25,7 +25,6 @@ import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.function.Supplier; @@ -161,6 +160,7 @@ public class DeferredRegister { private boolean seenRegisterEvent = false; private DeferredRegister(ResourceKey> registryKey, String modid, boolean optionalRegistry) { + requireNonNull("registryKey", registryKey); this.registryKey = registryKey; this.modid = modid; this.optionalRegistry = optionalRegistry; @@ -174,28 +174,25 @@ public class DeferredRegister { * Adds a new supplier to the list of entries to be registered, and returns a RegistryObject that will be populated with the created entry automatically. * * @param name The new entry's name, it will automatically have the modid prefixed. - * @param sup A factory for the new entry, it should return a new instance every time it is called. + * @param factory A factory for the new entry, it should return a new instance every time it is called. * @return A RegistryObject that will be updated with when the entries in the registry change. */ @SuppressWarnings("unchecked") - public RegistryObject register(final String name, final Supplier sup) { + public RegistryObject register(final String name, final Supplier factory) { if (seenRegisterEvent) throw new IllegalStateException("Cannot register new entries to DeferredRegister after RegisterEvent has been fired."); - Objects.requireNonNull(name); - Objects.requireNonNull(sup); + requireNonNull("name", name); + requireNonNull("factory", factory); var key = ResourceLocation.fromNamespaceAndPath(modid, name); RegistryObject ret; - if (this.registryKey != null) { - if (this.optionalRegistry) - ret = RegistryObject.createOptional(key, this.registryKey, this.modid); - else - ret = RegistryObject.create(key, this.registryKey, this.modid); - } else - throw new IllegalStateException("Could not create RegistryObject in DeferredRegister"); + if (this.optionalRegistry) + ret = RegistryObject.createOptional(key, this.registryKey, this.modid); + else + ret = RegistryObject.create(key, this.registryKey, this.modid); - if (entries.putIfAbsent((RegistryObject) ret, sup) != null) + if (entries.putIfAbsent((RegistryObject) ret, factory) != null) throw new IllegalArgumentException("Duplicate registration " + name); return ret; @@ -214,18 +211,40 @@ public class DeferredRegister { return makeRegistry(this.registryKey.location(), sup); } + /** + * Creates a ResourceKey based on the current modid and provided path as the location and the registry name linked to this DeferredRegister. + * To control the namespace, use {@link #key(ResourceLocation)}. + * + * @see #key(ResourceLocation) + */ + @NotNull + public ResourceKey key(@NotNull String path) { + requireNonNull("path", path); + return key(ResourceLocation.fromNamespaceAndPath(this.modid, path)); + } + + /** + * Creates a tag key based on the provided resource location and the registry name linked to this DeferredRegister. + * To use the current modid as the namespace, use {@link #createTagKey(String)}. + * + * @see #key(String) + */ + @NotNull + public ResourceKey key(@NotNull ResourceLocation location) { + requireNonNull("location", location); + return ResourceKey.create(getRegistryKey(), location); + } + /** * Creates a tag key based on the current modid and provided path as the location and the registry name linked to this DeferredRegister. * To control the namespace, use {@link #createTagKey(ResourceLocation)}. * - * @throws IllegalStateException If the registry name was not set. - * Use the factories that take {@link #create(ResourceLocation, String) a registry name} or {@link #create(IForgeRegistry, String) forge registry}. * @see #createTagKey(ResourceLocation) * @see #createOptionalTagKey(String, Set) */ @NotNull public TagKey createTagKey(@NotNull String path) { - Objects.requireNonNull(path); + requireNonNull("path", path); return createTagKey(ResourceLocation.fromNamespaceAndPath(this.modid, path)); } @@ -233,16 +252,12 @@ public class DeferredRegister { * Creates a tag key based on the provided resource location and the registry name linked to this DeferredRegister. * To use the current modid as the namespace, use {@link #createTagKey(String)}. * - * @throws IllegalStateException If the registry name was not set. - * Use the factories that take {@link #create(ResourceLocation, String) a registry name} or {@link #create(IForgeRegistry, String) forge registry}. * @see #createTagKey(String) * @see #createOptionalTagKey(ResourceLocation, Set) */ @NotNull public TagKey createTagKey(@NotNull ResourceLocation location) { - if (this.registryKey == null) - throw new IllegalStateException("The registry name was not set, cannot create a tag key"); - Objects.requireNonNull(location); + requireNonNull("location", location); return TagKey.create(this.registryKey, location); } @@ -251,8 +266,6 @@ public class DeferredRegister { * Useful on the client side when a server may not provide a specific tag. * To control the namespace, use {@link #createOptionalTagKey(ResourceLocation, Set)}. * - * @throws IllegalStateException If the registry name was not set. - * Use the factories that take {@link #create(ResourceLocation, String) a registry name} or {@link #create(IForgeRegistry, String) forge registry}. * @see #createTagKey(String) * @see #createTagKey(ResourceLocation) * @see #createOptionalTagKey(ResourceLocation, Set) @@ -260,7 +273,7 @@ public class DeferredRegister { */ @NotNull public TagKey createOptionalTagKey(@NotNull String path, @NotNull Set> defaults) { - Objects.requireNonNull(path); + requireNonNull("path", path); return createOptionalTagKey(ResourceLocation.fromNamespaceAndPath(this.modid, path), defaults); } @@ -269,8 +282,6 @@ public class DeferredRegister { * Useful on the client side when a server may not provide a specific tag. * To use the current modid as the namespace, use {@link #createOptionalTagKey(String, Set)}. * - * @throws IllegalStateException If the registry name was not set. - * Use the factories that take {@link #create(ResourceLocation, String) a registry name} or {@link #create(IForgeRegistry, String) forge registry}. * @see #createTagKey(String) * @see #createTagKey(ResourceLocation) * @see #createOptionalTagKey(String, Set) @@ -290,13 +301,11 @@ public class DeferredRegister { * The set of defaults will be bound to the tag if the tag is not loaded from any datapacks. * Useful on the client side when a server may not provide a specific tag. * - * @throws IllegalStateException If the registry name was not set. - * Use the factories that take {@link #create(ResourceLocation, String) a registry name} or {@link #create(IForgeRegistry, String) forge registry}. * @see #createOptionalTagKey(String, Set) * @see #createOptionalTagKey(ResourceLocation, Set) */ public void addOptionalTagDefaults(@NotNull TagKey name, @NotNull Set> defaults) { - Objects.requireNonNull(defaults); + requireNonNull("defaults", defaults); if (optionalTags == null) optionalTags = Multimaps.newSetMultimap(new IdentityHashMap<>(), HashSet::new); @@ -332,7 +341,7 @@ public class DeferredRegister { */ @NotNull public ResourceLocation getRegistryName() { - return Objects.requireNonNull(this.registryKey).location(); + return this.registryKey.location(); } private RegistryHolder makeRegistry(final ResourceLocation registryName, final Supplier> sup) { @@ -357,6 +366,12 @@ public class DeferredRegister { Multimaps.asMap(this.optionalTags).forEach(tagManager::addOptionalTagDefaults); } + private static T requireNonNull(String name, T value) { + if (value == null) + throw new IllegalArgumentException(name + " can not be null"); + return value; + } + private class EventDispatcher { @SubscribeEvent public void handleEvent(RegisterEvent event) { @@ -366,6 +381,9 @@ public class DeferredRegister { event.register(registryKey, e.getKey().getId(), () -> e.getValue().get()); e.getKey().updateReference(event); } + + if (registryFactory == null && event.getForgeRegistry() != null) + onFill(event.getForgeRegistry()); } } diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java index fe3e1cdcc4..74e672ee8c 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java @@ -244,9 +244,9 @@ public class ForgeRegistry implements IForgeRegistryInternal, IForgeRegist return wrapper; } - void onBindTags(Map, HolderSet.Named> tags, Set> defaultedTags) { + void onBindTags(Map, HolderSet.Named> tags) { if (this.tagManager != null) - this.tagManager.bind(tags, defaultedTags); + this.tagManager.bind(tags); } @NotNull diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistryTagManager.java b/src/main/java/net/minecraftforge/registries/ForgeRegistryTagManager.java index dabc20f37c..80b2a7103b 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistryTagManager.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistryTagManager.java @@ -23,18 +23,15 @@ import java.util.Set; import java.util.function.Supplier; import java.util.stream.Stream; -class ForgeRegistryTagManager implements ITagManager -{ +class ForgeRegistryTagManager implements ITagManager { private final ForgeRegistry owner; private volatile Map, ITag> tags = new IdentityHashMap<>(); - ForgeRegistryTagManager(ForgeRegistry owner) - { + ForgeRegistryTagManager(ForgeRegistry owner) { this.owner = owner; } - void bind(Map, HolderSet.Named> holderTags, Set> defaultedTags) - { + void bind(Map, HolderSet.Named> holderTags) { IdentityHashMap, ITag> newTags = new IdentityHashMap<>(this.tags); // Forcefully unbind all pre-existing tags @@ -49,13 +46,11 @@ class ForgeRegistryTagManager implements ITagManager @NotNull @Override - public ITag getTag(@NotNull TagKey name) - { + public ITag getTag(@NotNull TagKey name) { Objects.requireNonNull(name); ITag tag = this.tags.get(name); - if (tag == null) - { + if (tag == null) { // Create empty tag tag = new ForgeRegistryTag<>(name); @@ -72,16 +67,14 @@ class ForgeRegistryTagManager implements ITagManager @SuppressWarnings({ "unchecked", "rawtypes" }) @NotNull @Override - public Optional> getReverseTag(@NotNull V value) - { + public Optional> getReverseTag(@NotNull V value) { Objects.requireNonNull(value); // All Holders are implementors of IReverseTag return (Optional>) (Optional) this.owner.getHolder(value); } @Override - public boolean isKnownTagName(@NotNull TagKey name) - { + public boolean isKnownTagName(@NotNull TagKey name) { Objects.requireNonNull(name); ITag tag = this.tags.get(name); return tag != null && tag.isBound(); @@ -89,37 +82,32 @@ class ForgeRegistryTagManager implements ITagManager @NotNull @Override - public Iterator> iterator() - { + public Iterator> iterator() { return Iterators.unmodifiableIterator(this.tags.values().iterator()); } @NotNull @Override - public Stream> stream() - { + public Stream> stream() { return this.tags.values().stream(); } @NotNull @Override - public Stream> getTagNames() - { + public Stream> getTagNames() { return this.tags.keySet().stream(); } @NotNull @Override - public TagKey createTagKey(@NotNull ResourceLocation location) - { + public TagKey createTagKey(@NotNull ResourceLocation location) { Objects.requireNonNull(location); return TagKey.create(this.owner.getRegistryKey(), location); } @NotNull @Override - public TagKey createOptionalTagKey(@NotNull ResourceLocation location, @NotNull Set> defaults) - { + public TagKey createOptionalTagKey(@NotNull ResourceLocation location, @NotNull Set> defaults) { TagKey tagKey = createTagKey(location); addOptionalTagDefaults(tagKey, defaults); @@ -128,8 +116,7 @@ class ForgeRegistryTagManager implements ITagManager } @Override - public void addOptionalTagDefaults(@NotNull TagKey name, @NotNull Set> defaults) - { + public void addOptionalTagDefaults(@NotNull TagKey name, @NotNull Set> defaults) { Objects.requireNonNull(name); Objects.requireNonNull(defaults); diff --git a/src/main/java/net/minecraftforge/registries/GameData.java b/src/main/java/net/minecraftforge/registries/GameData.java index 3a0ccc56e5..ee67bb60ba 100644 --- a/src/main/java/net/minecraftforge/registries/GameData.java +++ b/src/main/java/net/minecraftforge/registries/GameData.java @@ -247,26 +247,32 @@ public class GameData { } @SuppressWarnings("deprecation") - public static void unfreezeData() - { + public static void unfreezeData() { LOGGER.debug(REGISTRIES, "Unfreezing vanilla registries"); BuiltInRegistries.REGISTRY.stream().filter(r -> r instanceof MappedRegistry).forEach(r -> ((MappedRegistry)r).unfreeze()); } - public static void freezeData() - { + public static void freezeData() { LOGGER.debug(REGISTRIES, "Freezing registries"); - BuiltInRegistries.REGISTRY.stream().filter(r -> r instanceof MappedRegistry).forEach(r -> ((MappedRegistry)r).freeze()); - - for (Map.Entry> r : RegistryManager.ACTIVE.registries.entrySet()) - { - loadRegistry(r.getKey(), RegistryManager.ACTIVE, RegistryManager.FROZEN, true); + for (var reg : BuiltInRegistries.REGISTRY) { + if (reg instanceof NamespacedWrapper named) { + // This is called after we fire our register events, but before doesn't load any tags. + // So lets skip the validation for this pass and just make every unbound tag empty + // Tags will be bound later when tag data is reloaded/synced + named.bindAllUnboundTagsToEmpty(); + named.freeze(); + } else if (reg instanceof MappedRegistry maped) + maped.freeze(); } - RegistryManager.FROZEN.registries.forEach((name, reg) -> - { + + for (var r : RegistryManager.ACTIVE.registries.entrySet()) + loadRegistry(r.getKey(), RegistryManager.ACTIVE, RegistryManager.FROZEN, true); + + RegistryManager.FROZEN.registries.forEach((name, reg) -> { reg.validateContent(name); reg.freeze(); }); + RegistryManager.ACTIVE.registries.forEach((name, reg) -> { reg.freeze(); reg.bake(); @@ -764,6 +770,7 @@ public class GameData { int index = name.lastIndexOf(':'); String oldPrefix = index == -1 ? "" : name.substring(0, index).toLowerCase(Locale.ROOT); name = index == -1 ? name : name.substring(index + 1); + @SuppressWarnings("removal") String prefix = ModLoadingContext.get().getActiveNamespace(); if (warnOverrides && !oldPrefix.equals(prefix) && !oldPrefix.isEmpty()) { diff --git a/src/main/java/net/minecraftforge/registries/NamespacedWrapper.java b/src/main/java/net/minecraftforge/registries/NamespacedWrapper.java index e64330caf6..ee7afcfaad 100644 --- a/src/main/java/net/minecraftforge/registries/NamespacedWrapper.java +++ b/src/main/java/net/minecraftforge/registries/NamespacedWrapper.java @@ -318,6 +318,7 @@ class NamespacedWrapper extends MappedRegistry implements ILockableRegistr throw new IllegalStateException("Unbound tags in registry " + this.key() + ": " + unbound); this.frozenTags = MappedRegistry.TagSet.fromMap(this.tags); + this.delegate.onBindTags(this.tags); this.refreshTagsInHoldersForge(); return this; } @@ -378,6 +379,14 @@ class NamespacedWrapper extends MappedRegistry implements ILockableRegistr tag.bind(List.of()); } + void bindAllUnboundTagsToEmpty() { + this.validateWrite(); + for (var tag : this.tags.values()) { + if (!tag.isBound()) + tag.bind(List.of()); + } + } + @Override public Registry.PendingTags prepareTagReload(TagLoader.LoadResult data) { if (!this.frozen) @@ -395,6 +404,23 @@ class NamespacedWrapper extends MappedRegistry implements ILockableRegistr _new.put(key, List.copyOf(entry.getValue())); } + for (var entry : this.optionalTags.entries()) { + var key = entry.getKey(); + if (data.tags().containsKey(key)) + continue; + + var value = entry.getValue().get(); + var holder = this.getHolder(value).orElse(null); + if (holder == null) + continue; + + var existing = this.tags.get(key); + if (existing == null) + existing = this.createTag(key); + _old.put(key, existing); + _new.put(key, List.of(holder)); + } + var oldBindings = _old.build(); var newBindings = _new.build(); @@ -444,6 +470,7 @@ class NamespacedWrapper extends MappedRegistry implements ILockableRegistr } NamespacedWrapper.this.frozenTags = MappedRegistry.TagSet.fromMap(oldBindings); + NamespacedWrapper.this.delegate.onBindTags(NamespacedWrapper.this.tags); NamespacedWrapper.this.refreshTagsInHoldersForge(); } }; diff --git a/src/main/java/net/minecraftforge/registries/RegisterEvent.java b/src/main/java/net/minecraftforge/registries/RegisterEvent.java index 120f26a648..1b6c79a1c6 100644 --- a/src/main/java/net/minecraftforge/registries/RegisterEvent.java +++ b/src/main/java/net/minecraftforge/registries/RegisterEvent.java @@ -25,17 +25,15 @@ import java.util.function.Supplier; * @see #register(ResourceKey, ResourceLocation, Supplier) * @see #register(ResourceKey, Consumer) */ -public class RegisterEvent extends Event implements IModBusEvent -{ +public class RegisterEvent extends Event implements IModBusEvent { @NotNull private final ResourceKey> registryKey; @Nullable - final ForgeRegistry forgeRegistry; + private final ForgeRegistry forgeRegistry; @Nullable private final Registry vanillaRegistry; - RegisterEvent(@NotNull ResourceKey> registryKey, @Nullable ForgeRegistry forgeRegistry, @Nullable Registry vanillaRegistry) - { + RegisterEvent(@NotNull ResourceKey> registryKey, @Nullable ForgeRegistry forgeRegistry, @Nullable Registry vanillaRegistry) { this.registryKey = registryKey; this.forgeRegistry = forgeRegistry; this.vanillaRegistry = vanillaRegistry; @@ -51,10 +49,8 @@ public class RegisterEvent extends Event implements IModBusEvent * @see #register(ResourceKey, Consumer) a register variant making registration of multiple objects less redundant */ @SuppressWarnings({ "unchecked", "rawtypes" }) - public void register(ResourceKey> registryKey, ResourceLocation name, Supplier valueSupplier) - { - if (this.registryKey.equals(registryKey)) - { + public void register(ResourceKey> registryKey, ResourceLocation name, Supplier valueSupplier) { + if (this.registryKey.equals(registryKey)) { if (this.forgeRegistry != null) ((IForgeRegistry) this.forgeRegistry).register(name, valueSupplier.get()); else if (this.vanillaRegistry != null) @@ -69,20 +65,16 @@ public class RegisterEvent extends Event implements IModBusEvent * @param the type of the registry * @see #register(ResourceKey, ResourceLocation, Supplier) a register variant targeted towards registering one or two objects */ - public void register(ResourceKey> registryKey, Consumer> consumer) - { + public void register(ResourceKey> registryKey, Consumer> consumer) { if (this.registryKey.equals(registryKey)) - { consumer.accept((name, value) -> register(registryKey, name, () -> value)); - } } /** * @return The registry key linked to this event */ @NotNull - public ResourceKey> getRegistryKey() - { + public ResourceKey> getRegistryKey() { return registryKey; } @@ -91,8 +83,7 @@ public class RegisterEvent extends Event implements IModBusEvent */ @Nullable @SuppressWarnings("unchecked") - public IForgeRegistry getForgeRegistry() - { + public IForgeRegistry getForgeRegistry() { return (IForgeRegistry) forgeRegistry; } @@ -101,20 +92,17 @@ public class RegisterEvent extends Event implements IModBusEvent */ @Nullable @SuppressWarnings("unchecked") - public Registry getVanillaRegistry() - { + public Registry getVanillaRegistry() { return (Registry) vanillaRegistry; } @Override - public String toString() - { + public String toString() { return "RegisterEvent"; } @FunctionalInterface - public interface RegisterHelper - { + public interface RegisterHelper { /** * Registers the given value with the given name to the registry. * The namespace is inferred based on the active mod container. @@ -123,8 +111,8 @@ public class RegisterEvent extends Event implements IModBusEvent * @param name the name of the object to register as its key with the namespaced inferred from the active mod container * @param value the object value */ - default void register(String name, T value) - { + @SuppressWarnings("removal") + default void register(String name, T value) { register(ResourceLocation.fromNamespaceAndPath(ModLoadingContext.get().getActiveNamespace(), name), value); } @@ -134,8 +122,7 @@ public class RegisterEvent extends Event implements IModBusEvent * @param key the resource key of the object to register * @param value the object value */ - default void register(ResourceKey key, T value) - { + default void register(ResourceKey key, T value) { register(key.location(), value); } diff --git a/src/main/java/net/minecraftforge/registries/tags/ITagManager.java b/src/main/java/net/minecraftforge/registries/tags/ITagManager.java index 1d9a9a9b1b..7f72b58254 100644 --- a/src/main/java/net/minecraftforge/registries/tags/ITagManager.java +++ b/src/main/java/net/minecraftforge/registries/tags/ITagManager.java @@ -20,8 +20,7 @@ import java.util.stream.Stream; * A tag manager holds information about all tags currently bound to a forge registry. * This should be preferred to any {@link Holder}-related methods. */ -public interface ITagManager extends Iterable> -{ +public interface ITagManager extends Iterable> { /** * Queries this tag manager for a tag with the given tag key. * If it does not exist, this will create an empty tag and return it.