From 9aba3cf1dccf43a0b000413c7544196bfb643e25 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Mon, 20 Nov 2023 21:00:36 +0800 Subject: [PATCH] Update to 20.2.59-beta & Adapt to Registry Changes --- .../impl/RegistrySupplierImpl.java | 98 ++++ .../registry/registries/DeferredRegister.java | 13 +- .../registry/registries/Registrar.java | 9 + .../registry/registries/RegistrySupplier.java | 3 +- .../fabric/RegistrarManagerImpl.java | 20 +- .../hooks/forgelike/ForgeLikeHooks.java | 36 ++ .../biome/forge/BiomeModificationsImpl.java | 14 +- gradle.properties | 2 +- .../forgelike/forge/ForgeLikeHooksImpl.java | 42 ++ .../forge/RegistrarManagerImpl.java | 68 ++- .../forgelike/forge/ForgeLikeHooksImpl.java | 42 ++ .../forge/RegistrarManagerImpl.java | 426 ++++++++++++++++++ .../src/main/resources/META-INF/mods.toml | 2 +- 13 files changed, 755 insertions(+), 20 deletions(-) create mode 100644 common/src/main/java/dev/architectury/impl/RegistrySupplierImpl.java create mode 100644 forge/src/main/java/dev/architectury/hooks/forgelike/ForgeLikeHooks.java create mode 100644 minecraftforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java rename {forge => minecraftforge}/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java (93%) create mode 100644 neoforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java create mode 100644 neoforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java diff --git a/common/src/main/java/dev/architectury/impl/RegistrySupplierImpl.java b/common/src/main/java/dev/architectury/impl/RegistrySupplierImpl.java new file mode 100644 index 000000000..dd11c205c --- /dev/null +++ b/common/src/main/java/dev/architectury/impl/RegistrySupplierImpl.java @@ -0,0 +1,98 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.impl; + +import com.mojang.datafixers.util.Either; +import dev.architectury.registry.registries.RegistrySupplier; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderOwner; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@ApiStatus.Internal +public interface RegistrySupplierImpl extends RegistrySupplier { + @Nullable + Holder getHolder(); + + @Override + default T value() { + return get(); + } + + @Override + default boolean isBound() { + return isPresent(); + } + + @Override + default boolean is(ResourceLocation resourceLocation) { + return getId().equals(resourceLocation); + } + + @Override + default boolean is(ResourceKey resourceKey) { + return getKey().equals(resourceKey); + } + + @Override + default boolean is(Predicate> predicate) { + return predicate.test(getKey()); + } + + @Override + default boolean is(TagKey tagKey) { + Holder holder = getHolder(); + return holder != null && holder.is(tagKey); + } + + @Override + default Stream> tags() { + Holder holder = getHolder(); + return holder != null ? holder.tags() : Stream.empty(); + } + + @Override + default Either, T> unwrap() { + return Either.left(getKey()); + } + + @Override + default Optional> unwrapKey() { + return Optional.of(getKey()); + } + + @Override + default Kind kind() { + return Kind.REFERENCE; + } + + @Override + default boolean canSerializeIn(HolderOwner holderOwner) { + Holder holder = getHolder(); + return holder != null && holder.canSerializeIn(holderOwner); + } +} diff --git a/common/src/main/java/dev/architectury/registry/registries/DeferredRegister.java b/common/src/main/java/dev/architectury/registry/registries/DeferredRegister.java index af6607385..e96e1b8ce 100644 --- a/common/src/main/java/dev/architectury/registry/registries/DeferredRegister.java +++ b/common/src/main/java/dev/architectury/registry/registries/DeferredRegister.java @@ -20,6 +20,8 @@ package dev.architectury.registry.registries; import com.google.common.base.Suppliers; +import dev.architectury.impl.RegistrySupplierImpl; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -90,16 +92,25 @@ public Registrar getRegistrar() { return registriesSupplier.get().get(key); } - private class Entry implements RegistrySupplier { + private class Entry implements RegistrySupplierImpl { private final ResourceLocation id; private final Supplier supplier; private RegistrySupplier value; + @Nullable + private Holder holder = null; public Entry(ResourceLocation id, Supplier supplier) { this.id = id; this.supplier = supplier; } + @Nullable + @Override + public Holder getHolder() { + if (holder != null) return holder; + return holder = getRegistrar().getHolder(getId()); + } + @Override public RegistrarManager getRegistrarManager() { return DeferredRegister.this.getRegistrarManager(); diff --git a/common/src/main/java/dev/architectury/registry/registries/Registrar.java b/common/src/main/java/dev/architectury/registry/registries/Registrar.java index 775c7e293..27865b73d 100644 --- a/common/src/main/java/dev/architectury/registry/registries/Registrar.java +++ b/common/src/main/java/dev/architectury/registry/registries/Registrar.java @@ -19,6 +19,7 @@ package dev.architectury.registry.registries; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -68,6 +69,14 @@ default RegistrySupplier wrap(R obj) { ResourceKey> key(); + @Nullable + Holder getHolder(ResourceKey key); + + @Nullable + default Holder getHolder(ResourceLocation id) { + return getHolder(ResourceKey.create(key(), id)); + } + /** * Listens to when the registry entry is registered, and calls the given action. * Evaluates immediately if the entry is already registered. diff --git a/common/src/main/java/dev/architectury/registry/registries/RegistrySupplier.java b/common/src/main/java/dev/architectury/registry/registries/RegistrySupplier.java index ba82555b2..dfa8c0a84 100644 --- a/common/src/main/java/dev/architectury/registry/registries/RegistrySupplier.java +++ b/common/src/main/java/dev/architectury/registry/registries/RegistrySupplier.java @@ -19,12 +19,13 @@ package dev.architectury.registry.registries; +import net.minecraft.core.Holder; import org.jetbrains.annotations.ApiStatus; import java.util.function.Consumer; @ApiStatus.NonExtendable -public interface RegistrySupplier extends DeferredSupplier { +public interface RegistrySupplier extends DeferredSupplier, Holder { RegistrarManager getRegistrarManager(); Registrar getRegistrar(); 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 4a42c09b3..35d768071 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 dev.architectury.impl.RegistrySupplierImpl; import dev.architectury.registry.registries.Registrar; import dev.architectury.registry.registries.RegistrarBuilder; import dev.architectury.registry.registries.RegistrarManager; @@ -32,6 +33,7 @@ import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; import net.fabricmc.fabric.api.event.registry.RegistryAttribute; import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; +import net.minecraft.core.Holder; import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; @@ -153,7 +155,17 @@ public RegistrarImpl(String modId, Registry delegate) { public RegistrySupplier delegate(ResourceLocation id) { Supplier value = Suppliers.memoize(() -> get(id)); RegistrarImpl registrar = this; - return new RegistrySupplier<>() { + return new RegistrySupplierImpl() { + @Nullable + Holder holder = null; + + @Nullable + @Override + public Holder getHolder() { + if (holder != null) return holder; + return holder = registrar.getHolder(getId()); + } + @Override public RegistrarManager getRegistrarManager() { return RegistrarManager.get(modId); @@ -259,6 +271,12 @@ public ResourceKey> key() { return delegate.key(); } + @Override + @Nullable + public Holder getHolder(ResourceKey key) { + return delegate.getHolder(key).orElse(null); + } + @Override public Iterator iterator() { return delegate.iterator(); diff --git a/forge/src/main/java/dev/architectury/hooks/forgelike/ForgeLikeHooks.java b/forge/src/main/java/dev/architectury/hooks/forgelike/ForgeLikeHooks.java new file mode 100644 index 000000000..0c743a924 --- /dev/null +++ b/forge/src/main/java/dev/architectury/hooks/forgelike/ForgeLikeHooks.java @@ -0,0 +1,36 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.hooks.forgelike; + +import com.mojang.serialization.Codec; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.common.world.BiomeModifier; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Supplier; + +@ApiStatus.Internal +public class ForgeLikeHooks { + @ExpectPlatform + public static void registerBiomeModifier(ResourceLocation id, Supplier> codecSupplier) { + throw new AssertionError(); + } +} diff --git a/forge/src/main/java/dev/architectury/registry/level/biome/forge/BiomeModificationsImpl.java b/forge/src/main/java/dev/architectury/registry/level/biome/forge/BiomeModificationsImpl.java index a845e2347..efc5233a4 100644 --- a/forge/src/main/java/dev/architectury/registry/level/biome/forge/BiomeModificationsImpl.java +++ b/forge/src/main/java/dev/architectury/registry/level/biome/forge/BiomeModificationsImpl.java @@ -21,8 +21,8 @@ import com.google.common.collect.Lists; import com.mojang.serialization.Codec; +import dev.architectury.hooks.forgelike.ForgeLikeHooks; import dev.architectury.hooks.level.biome.*; -import dev.architectury.platform.hooks.EventBusesHooks; import dev.architectury.registry.level.biome.BiomeModifications.BiomeContext; import dev.architectury.utils.ArchitecturyConstants; import dev.architectury.utils.GameInstance; @@ -42,8 +42,6 @@ import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraftforge.common.world.*; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegisterEvent; import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.Nullable; @@ -64,14 +62,8 @@ public class BiomeModificationsImpl { private static Codec noneBiomeModCodec = null; public static void init() { - EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID,bus -> { - bus.addListener(event -> { - event.register(ForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, registry -> { - registry.register(new ResourceLocation(ArchitecturyConstants.MOD_ID, "none_biome_mod_codec"), - noneBiomeModCodec = Codec.unit(BiomeModifierImpl.INSTANCE)); - }); - }); - }); + ForgeLikeHooks.registerBiomeModifier(new ResourceLocation(ArchitecturyConstants.MOD_ID, "none_biome_mod_codec"), + () -> noneBiomeModCodec = Codec.unit(BiomeModifierImpl.INSTANCE)); } public static void addProperties(Predicate predicate, BiConsumer modifier) { diff --git a/gradle.properties b/gradle.properties index ce575a5a4..c181fac57 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ fabric_api_version=0.89.1+1.20.2 mod_menu_version=7.0.0 forge_version=48.0.38 -neoforge_version=20.2.52-beta +neoforge_version=20.2.59-beta curseforge_id=419699 modrinth_id=lhGA9TYQ diff --git a/minecraftforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java b/minecraftforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java new file mode 100644 index 000000000..fbb4b4fb7 --- /dev/null +++ b/minecraftforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java @@ -0,0 +1,42 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.hooks.forgelike.forge; + +import com.mojang.serialization.Codec; +import dev.architectury.platform.hooks.EventBusesHooks; +import dev.architectury.utils.ArchitecturyConstants; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.common.world.BiomeModifier; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegisterEvent; + +import java.util.function.Supplier; + +public class ForgeLikeHooksImpl { + public static void registerBiomeModifier(ResourceLocation id, Supplier> codecSupplier) { + EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> { + bus.addListener(event -> { + event.register(ForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, registry -> { + registry.register(id, codecSupplier.get()); + }); + }); + }); + } +} diff --git a/forge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java b/minecraftforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java similarity index 93% rename from forge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java rename to minecraftforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java index 4aad3bfc0..a688b5b8f 100644 --- a/forge/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 dev.architectury.impl.RegistrySupplierImpl; import dev.architectury.platform.hooks.EventBusesHooks; 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.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; @@ -322,7 +324,17 @@ public VanillaBackedRegistryImpl(String modId, Map delegate(ResourceLocation id) { Supplier value = Suppliers.memoize(() -> get(id)); Registrar registrar = this; - return new RegistrySupplier<>() { + return new RegistrySupplierImpl() { + @Nullable + Holder holder = null; + + @Nullable + @Override + public Holder getHolder() { + if (holder != null) return holder; + return holder = registrar.getHolder(getId()); + } + @Override public RegistrarManager getRegistrarManager() { return RegistrarManager.get(modId); @@ -432,6 +444,12 @@ public ResourceKey> key() { return delegate.key(); } + @Override + @Nullable + public Holder getHolder(ResourceKey key) { + return delegate.getHolder(key).orElse(null); + } + @Override public Iterator iterator() { return delegate.iterator(); @@ -462,7 +480,17 @@ public ForgeBackedRegistryImpl(String modId, Map delegate(ResourceLocation id) { Supplier value = Suppliers.memoize(() -> get(id)); Registrar registrar = this; - return new RegistrySupplier<>() { + return new RegistrySupplierImpl() { + @Nullable + Holder holder = null; + + @Nullable + @Override + public Holder getHolder() { + if (holder != null) return holder; + return holder = registrar.getHolder(getId()); + } + @Override public RegistrarManager getRegistrarManager() { return RegistrarManager.get(modId); @@ -519,7 +547,17 @@ public RegistrySupplier register(ResourceLocation id, Supplier< Data data = (Data) registry.computeIfAbsent(key(), type -> new Data<>()); data.registerForForge(delegate, id, objectArr, supplier); Registrar registrar = this; - return new RegistrySupplier<>() { + return new RegistrySupplierImpl() { + @Nullable + Holder holder = null; + + @Nullable + @Override + public Holder getHolder() { + if (holder != null) return holder; + return holder = getRegistrar().getHolder(getId()); + } + @Override public RegistrarManager getRegistrarManager() { return RegistrarManager.get(modId); @@ -625,6 +663,12 @@ public ResourceKey> key() { return ResourceKey.createRegistryKey(delegate.getRegistryName()); } + @Override + @Nullable + public Holder getHolder(ResourceKey key) { + return delegate.getHolder(key).orElse(null); + } + @Override public Iterator iterator() { return delegate.iterator(); @@ -668,7 +712,17 @@ public boolean isReady() { @Override public RegistrySupplier delegate(ResourceLocation id) { if (isReady()) return delegate.get().delegate(id); - return new RegistrySupplier<>() { + return new RegistrySupplierImpl() { + @Nullable + Holder holder = null; + + @Nullable + @Override + public Holder getHolder() { + if (holder != null || !isReady()) return holder; + return holder = delegate.get().getHolder(getId()); + } + @Override public RegistrarManager getRegistrarManager() { return RegistrarManager.get(modId); @@ -761,6 +815,12 @@ public ResourceKey> key() { return isReady() ? delegate.get().key() : ResourceKey.createRegistryKey(registryId); } + @Override + @Nullable + public Holder getHolder(ResourceKey key) { + return isReady() ? delegate.get().getHolder(key) : null; + } + @Override public void listen(ResourceLocation id, Consumer callback) { if (isReady()) { diff --git a/neoforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java b/neoforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java new file mode 100644 index 000000000..8d6560072 --- /dev/null +++ b/neoforge/src/main/java/dev/architectury/hooks/forgelike/forge/ForgeLikeHooksImpl.java @@ -0,0 +1,42 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.hooks.forgelike.forge; + +import com.mojang.serialization.Codec; +import dev.architectury.platform.hooks.forge.EventBusesHooksImpl; +import dev.architectury.utils.ArchitecturyConstants; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.common.world.BiomeModifier; +import net.neoforged.neoforge.registries.NeoForgeRegistries; +import net.neoforged.neoforge.registries.RegisterEvent; + +import java.util.function.Supplier; + +public class ForgeLikeHooksImpl { + public static void registerBiomeModifier(ResourceLocation id, Supplier> codecSupplier) { + EventBusesHooksImpl.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> { + bus.addListener(event -> { + event.register(NeoForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, registry -> { + registry.register(id, codecSupplier.get()); + }); + }); + }); + } +} 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 new file mode 100644 index 000000000..e51de44ac --- /dev/null +++ b/neoforge/src/main/java/dev/architectury/registry/registries/forge/RegistrarManagerImpl.java @@ -0,0 +1,426 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021, 2022 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package dev.architectury.registry.registries.forge; + +import com.google.common.base.Objects; +import com.google.common.base.Suppliers; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import dev.architectury.impl.RegistrySupplierImpl; +import dev.architectury.platform.hooks.forge.EventBusesHooksImpl; +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.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.registries.NewRegistryEvent; +import net.neoforged.neoforge.registries.RegisterEvent; +import net.neoforged.neoforge.registries.RegistryBuilder; +import org.apache.commons.lang3.mutable.Mutable; +import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class RegistrarManagerImpl { + private static final Logger LOGGER = LogManager.getLogger(RegistrarManagerImpl.class); + private static final Multimap, Consumer> LISTENERS = HashMultimap.create(); + + private static void listen(ResourceKey resourceKey, ResourceLocation id, Consumer listener) { + LISTENERS.put(new RegistryEntryId<>(resourceKey, id), listener); + } + + public static RegistrarManager.RegistryProvider _get(String modId) { + return new RegistryProviderImpl(modId); + } + + public static class Data { + private boolean registered = false; + private final Map> objects = new LinkedHashMap<>(); + + public void register(Registry registry, ResourceLocation location, Mutable object, Supplier reference) { + if (!registered) { + objects.put(location, () -> { + T value = reference.get(); + object.setValue(value); + return value; + }); + } else { + ResourceKey> resourceKey = registry.key(); + T value = reference.get(); + Registry.register(registry, location, value); + object.setValue(value); + + RegistryEntryId registryEntryId = new RegistryEntryId<>(resourceKey, location); + for (Consumer consumer : LISTENERS.get(registryEntryId)) { + ((Consumer) consumer).accept(value); + } + LISTENERS.removeAll(registryEntryId); + } + } + } + + public record RegistryEntryId(ResourceKey registryKey, ResourceLocation id) { + @Override + public String toString() { + return "Registry Entry [%s / %s]".formatted(registryKey.location(), id); + } + } + + public static class RegistryProviderImpl implements RegistrarManager.RegistryProvider { + private static final Map>, Registrar> CUSTOM_REGS = new HashMap<>(); + private final String modId; + private final Supplier eventBus; + private final Map>, Data> registry = new HashMap<>(); + private final Multimap>, Consumer>> listeners = HashMultimap.create(); + + @Nullable + private List> newRegistries = new ArrayList<>(); + + public RegistryProviderImpl(String modId) { + this.modId = modId; + this.eventBus = Suppliers.memoize(() -> { + IEventBus eventBus = EventBusesHooksImpl.getModEventBus(modId).orElseThrow(() -> new IllegalStateException("Can't get event bus for mod '" + modId + "' because it was not registered!")); + eventBus.register(new EventListener()); + return eventBus; + }); + } + + private void updateEventBus() { + synchronized (eventBus) { + // Make sure that the eventbus is setup + this.eventBus.get(); + } + } + + @Override + public Registrar get(ResourceKey> registryKey) { + updateEventBus(); + Registry registry = (Registry) BuiltInRegistries.REGISTRY.get(registryKey.location()); + if (registry != null) { + return get(registry); + } + Registrar customReg = RegistryProviderImpl.CUSTOM_REGS.get(registryKey); + if (customReg != null) return (Registrar) customReg; + throw new IllegalArgumentException("Registry " + registryKey + " does not exist!"); + } + + @Override + public Registrar get(Registry registry) { + updateEventBus(); + return new RegistrarImpl<>(modId, this.registry, registry); + } + + @Override + public void forRegistry(ResourceKey> key, Consumer> consumer) { + this.listeners.put((ResourceKey>) (ResourceKey>) key, + (Consumer>) (Consumer>) consumer); + } + + @Override + public RegistrarBuilder builder(Class type, ResourceLocation registryId) { + return new RegistryBuilderWrapper<>(this, new RegistryBuilder<>(ResourceKey.createRegistryKey(registryId))); + } + + public class EventListener { + @SubscribeEvent + public void handleEvent(RegisterEvent event) { + for (Map.Entry>, Data> typeDataEntry : RegistryProviderImpl.this.registry.entrySet()) { + if (typeDataEntry.getKey().equals(event.getRegistryKey())) { + //noinspection rawtypes + registerFor(event, (ResourceKey) typeDataEntry.getKey(), typeDataEntry.getValue()); + } + } + } + + public void registerFor(RegisterEvent event, ResourceKey> resourceKey, Data data) { + event.register(resourceKey, registry -> { + data.registered = true; + + for (Map.Entry> entry : data.objects.entrySet()) { + ResourceLocation location = entry.getKey(); + T value = entry.getValue().get(); + registry.register(location, value); + + RegistryEntryId registryEntryId = new RegistryEntryId<>(resourceKey, location); + for (Consumer consumer : LISTENERS.get(registryEntryId)) { + ((Consumer) consumer).accept(value); + } + LISTENERS.removeAll(registryEntryId); + } + + data.objects.clear(); + Registrar archRegistry = get(event.getRegistry()); + + for (Map.Entry>, Consumer>> entry : listeners.entries()) { + if (entry.getKey().location().equals(resourceKey.location())) { + entry.getValue().accept(archRegistry); + } + } + }); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void handleEventPost(RegisterEvent event) { + Registrar archRegistry = get(event.getRegistry()); + + List> toRemove = new ArrayList<>(); + + for (Map.Entry, Collection>> entry : LISTENERS.asMap().entrySet()) { + if (entry.getKey().registryKey.equals(event.getRegistryKey())) { + if (archRegistry.contains(entry.getKey().id)) { + Object value = archRegistry.get(entry.getKey().id); + for (Consumer consumer : entry.getValue()) { + ((Consumer) consumer).accept(value); + } + toRemove.add(entry.getKey()); + } else { + LOGGER.warn("Registry entry listened {} was not realized!", entry.getKey()); + } + } + } + + for (RegistryEntryId id : toRemove) { + LISTENERS.removeAll(id); + } + } + + @SubscribeEvent + public void handleEvent(NewRegistryEvent event) { + if (newRegistries != null) { + for (Registry registry : newRegistries) { + event.register(registry); + } + newRegistries = null; + } + } + } + } + + public static class RegistryBuilderWrapper implements RegistrarBuilder { + private final RegistryProviderImpl provider; + private final RegistryBuilder builder; + private boolean syncToClients = false; + + public RegistryBuilderWrapper(RegistryProviderImpl provider, RegistryBuilder builder) { + this.provider = provider; + this.builder = builder; + } + + @Override + public Registrar build() { + builder.sync(syncToClients); + if (provider.newRegistries == null) { + throw new IllegalStateException("Cannot create registries when registries are already aggregated!"); + } + var registry = builder.create(); + var registrar = provider.get(registry); + provider.newRegistries.add(registry); + //noinspection rawtypes + RegistryProviderImpl.CUSTOM_REGS.put((ResourceKey) registrar.key(), registrar); + return registrar; + } + + @Override + public RegistrarBuilder option(RegistrarOption option) { + if (option == StandardRegistrarOption.SYNC_TO_CLIENTS) { + this.syncToClients = true; + } + return this; + } + } + + public static class RegistrarImpl implements Registrar { + private final String modId; + private final Registry delegate; + private final Map>, Data> registry; + + public RegistrarImpl(String modId, Map>, Data> registry, Registry delegate) { + this.modId = modId; + this.registry = registry; + this.delegate = delegate; + } + + @Override + public RegistrySupplier delegate(ResourceLocation id) { + Supplier value = Suppliers.memoize(() -> get(id)); + return asSupplier(id, this, () -> contains(id), value); + } + + @Override + public RegistrySupplier register(ResourceLocation id, Supplier supplier) { + Data data = (Data) registry.computeIfAbsent(key(), type -> new Data<>()); + Mutable object = new MutableObject<>(); + data.register(delegate, id, object, supplier); + return asSupplier(id, (Registrar) this, () -> object.getValue() != null, object::getValue); + } + + private RegistrySupplier asSupplier(ResourceLocation id, Registrar registrar, BooleanSupplier isPresent, Supplier object) { + return new RegistrySupplierImpl() { + @Nullable + Holder holder = null; + + @Nullable + @Override + public Holder getHolder() { + if (holder != null) return holder; + return holder = registrar.getHolder(getId()); + } + + @Override + public RegistrarManager getRegistrarManager() { + return RegistrarManager.get(modId); + } + + @Override + public Registrar getRegistrar() { + return registrar; + } + + @Override + public ResourceLocation getRegistryId() { + return delegate.key().location(); + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public boolean isPresent() { + return isPresent.getAsBoolean(); + } + + @Override + public E get() { + E value = (E) object.get(); + if (value == null) { + throw new NullPointerException("Value missing: " + this.getId() + "@" + getRegistryId()); + } + return value; + } + + @Override + public int hashCode() { + return Objects.hashCode(getRegistryId(), getId()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof RegistrySupplier other)) return false; + return other.getRegistryId().equals(getRegistryId()) && other.getId().equals(getId()); + } + + @Override + public String toString() { + return getRegistryId() + "@" + id.toString(); + } + }; + } + + @Override + @Nullable + public ResourceLocation getId(T obj) { + return delegate.getKey(obj); + } + + @Override + public int getRawId(T obj) { + return delegate.getId(obj); + } + + @Override + public Optional> getKey(T t) { + return delegate.getResourceKey(t); + } + + @Override + @Nullable + public T get(ResourceLocation id) { + return delegate.get(id); + } + + @Override + public T byRawId(int rawId) { + return delegate.byId(rawId); + } + + @Override + public boolean contains(ResourceLocation resourceLocation) { + return delegate.keySet().contains(resourceLocation); + } + + @Override + public boolean containsValue(T t) { + return delegate.getResourceKey(t).isPresent(); + } + + @Override + public Set getIds() { + return delegate.keySet(); + } + + @Override + public Set, T>> entrySet() { + return delegate.entrySet(); + } + + @Override + public ResourceKey> key() { + return delegate.key(); + } + + @Override + @Nullable + public Holder getHolder(ResourceKey key) { + return delegate.getHolder(key).orElse(null); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public void listen(ResourceLocation id, Consumer callback) { + if (contains(id)) { + callback.accept(get(id)); + } else { + RegistrarManagerImpl.listen(key(), id, callback); + } + } + } +} diff --git a/neoforge/src/main/resources/META-INF/mods.toml b/neoforge/src/main/resources/META-INF/mods.toml index a4094b9a0..f620b277d 100644 --- a/neoforge/src/main/resources/META-INF/mods.toml +++ b/neoforge/src/main/resources/META-INF/mods.toml @@ -24,7 +24,7 @@ side = "BOTH" [[dependencies.architectury]] modId = "neoforge" mandatory = true -versionRange = "[20.2,)" +versionRange = "[20.2.58,)" ordering = "NONE" side = "BOTH"