From 281ef5a1526a807d497be354211b4e27b5653671 Mon Sep 17 00:00:00 2001 From: LexManos Date: Tue, 10 Sep 2019 16:02:07 -0700 Subject: [PATCH] Add new DeferredRegistry helper, and change RegistryObject to update when overrides are registered. --- .../event/ClientPlayerNetworkEvent.java | 19 ++++ .../event/ParticleFactoryRegisterEvent.java | 19 ++++ .../net/minecraftforge/common/ForgeMod.java | 14 +-- .../minecraftforge/fml/RegistryObject.java | 92 +++++++++-------- .../network/FMLMCRegisterPacketHandler.java | 19 ++++ .../registries/DeferredRegister.java | 98 +++++++++++++++++++ .../registries/RegistryManager.java | 5 +- .../server/command/ForgeArguments.java | 15 --- 8 files changed, 214 insertions(+), 67 deletions(-) create mode 100644 src/main/java/net/minecraftforge/registries/DeferredRegister.java delete mode 100644 src/main/java/net/minecraftforge/server/command/ForgeArguments.java diff --git a/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java b/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java index da847dd5c..04b042afb 100644 --- a/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.client.event; import net.minecraft.client.entity.player.ClientPlayerEntity; diff --git a/src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java b/src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java index 4ca71d76d..30e5f1848 100644 --- a/src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.client.event; import net.minecraftforge.eventbus.api.Event; diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 8804bd3ac..4050224b2 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -29,10 +29,7 @@ import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.server.command.ConfigCommand; -import net.minecraftforge.server.command.EnumArgument; -import net.minecraftforge.server.command.ForgeArguments; import net.minecraftforge.server.command.ForgeCommand; -import net.minecraftforge.server.command.ModIdArgument; import net.minecraftforge.versions.forge.ForgeVersion; import net.minecraftforge.versions.mcp.MCPVersion; @@ -40,8 +37,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import net.minecraft.command.arguments.ArgumentSerializer; -import net.minecraft.command.arguments.ArgumentTypes; import net.minecraft.data.DataGenerator; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeSerializer; @@ -68,7 +63,6 @@ import net.minecraftforge.common.data.ForgeRecipeProvider; import net.minecraftforge.common.model.animation.CapabilityAnimation; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.items.CapabilityItemHandler; @@ -134,7 +128,13 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook VersionChecker.startVersionCheck(); } - ForgeArguments.register(); + /* + * We can't actually add any of these, because vanilla clients will choke on unknown argument types + * So our custom arguments will not validate client-side, but they do still work + ArgumentTypes.register("forge:enum", EnumArgument.class, new EnumArgument.Serializer()); + ArgumentTypes.register("forge:modid", ModIdArgument.class, new ArgumentSerializer<>(ModIdArgument::modIdArgument)); + ArgumentTypes.register("forge:structure_type", StructureArgument.class, new ArgumentSerializer<>(StructureArgument::structure)); + */ } public void serverStarting(FMLServerStartingEvent evt) diff --git a/src/main/java/net/minecraftforge/fml/RegistryObject.java b/src/main/java/net/minecraftforge/fml/RegistryObject.java index 3a2f31475..5f13b76b1 100644 --- a/src/main/java/net/minecraftforge/fml/RegistryObject.java +++ b/src/main/java/net/minecraftforge/fml/RegistryObject.java @@ -21,7 +21,8 @@ package net.minecraftforge.fml; import net.minecraft.util.ResourceLocation; import net.minecraftforge.registries.IForgeRegistry; -import net.minecraftforge.registries.ForgeRegistryEntry; +import net.minecraftforge.registries.IForgeRegistryEntry; +import net.minecraftforge.registries.ObjectHolderRegistry; import net.minecraftforge.registries.RegistryManager; import java.util.Objects; @@ -32,69 +33,76 @@ import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; -public final class RegistryObject> -{ - private final String name; - private final IForgeRegistry owningRegistry; - private T value; - private boolean searched; +import javax.annotation.Nullable; - public static , U extends T> RegistryObject of(final String name, Supplier> registryType) { +public final class RegistryObject> +{ + private final ResourceLocation name; + @Nullable + private T value; + + public static , U extends T> RegistryObject of(final String name, Supplier> registryType) { return new RegistryObject<>(name, registryType); } + public static , U extends T> RegistryObject of(final String name, IForgeRegistry registry) { + return new RegistryObject<>(name, registry); + } + private static RegistryObject EMPTY = new RegistryObject<>(); - private static > RegistryObject empty() { + private static > RegistryObject empty() { @SuppressWarnings("unchecked") RegistryObject t = (RegistryObject) EMPTY; return t; } private RegistryObject() { - this.searched = true; - this.name = ""; - this.owningRegistry = null; + this.name = null; } - private > RegistryObject(String name, Supplier> registryType) + private > RegistryObject(String name, Supplier> registryType) { - this.name = name; - IForgeRegistry registry; - try { - registry = RegistryManager.ACTIVE.getRegistry(registryType.get()); - } catch (Throwable t) { - registry = null; - } - this.owningRegistry = registry; + this(name, RegistryManager.ACTIVE.getRegistry(registryType.get())); } - private T getValue() + @SuppressWarnings("unchecked") + private > RegistryObject(String name, IForgeRegistry registry) + { + if (registry == null) + throw new IllegalArgumentException("Invalid registry argument, must not be null"); + this.name = new ResourceLocation(name); + ObjectHolderRegistry.addHandler(pred -> + { + if (pred.test(registry.getRegistryName())) + this.value = registry.containsKey(this.name) ? (T)registry.getValue(this.name) : null; + }); + } + + /** + * Directly retrieves the wrapped Registry Object. This value will automatically be updated when the backing registry is updated. + */ + @Nullable + public T get() { - if (!searched) { - if (this.owningRegistry != null) { - //noinspection unchecked - this.value = (T)this.owningRegistry.getValue(new ResourceLocation(this.name)); - } - searched = true; - } return this.value; } public String getName() { - return this.name; + return this.name.toString(); } public Stream stream() { - return isPresent() ? Stream.of(getValue()) : Stream.of(); + return isPresent() ? Stream.of(get()) : Stream.of(); } + /** * Return {@code true} if there is a mod object present, otherwise {@code false}. * * @return {@code true} if there is a mod object present, otherwise {@code false} */ public boolean isPresent() { - return getValue() != null; + return get() != null; } /** @@ -106,8 +114,8 @@ public final class RegistryObject> * null */ public void ifPresent(Consumer consumer) { - if (getValue() != null) - consumer.accept(getValue()); + if (get() != null) + consumer.accept(get()); } /** @@ -126,7 +134,7 @@ public final class RegistryObject> if (!isPresent()) return this; else - return predicate.test(getValue()) ? this : empty(); + return predicate.test(get()) ? this : empty(); } /** @@ -149,7 +157,7 @@ public final class RegistryObject> if (!isPresent()) return Optional.empty(); else { - return Optional.ofNullable(mapper.apply(getValue())); + return Optional.ofNullable(mapper.apply(get())); } } @@ -175,7 +183,7 @@ public final class RegistryObject> if (!isPresent()) return Optional.empty(); else { - return Objects.requireNonNull(mapper.apply(getValue())); + return Objects.requireNonNull(mapper.apply(get())); } } @@ -187,7 +195,7 @@ public final class RegistryObject> * @return the mod object, if present, otherwise {@code other} */ public T orElse(T other) { - return getValue() != null ? getValue() : other; + return get() != null ? get() : other; } /** @@ -201,7 +209,7 @@ public final class RegistryObject> * null */ public T orElseGet(Supplier other) { - return getValue() != null ? getValue() : other.get(); + return get() != null ? get() : other.get(); } /** @@ -221,8 +229,8 @@ public final class RegistryObject> * {@code exceptionSupplier} is null */ public T orElseThrow(Supplier exceptionSupplier) throws X { - if (getValue() != null) { - return getValue(); + if (get() != null) { + return get(); } else { throw exceptionSupplier.get(); } @@ -233,7 +241,7 @@ public final class RegistryObject> { if (this == obj) return true; if (obj instanceof RegistryObject) { - return Objects.equals(((RegistryObject)obj).name, name); + return Objects.equals(((RegistryObject)obj).name, name); } return false; } diff --git a/src/main/java/net/minecraftforge/fml/network/FMLMCRegisterPacketHandler.java b/src/main/java/net/minecraftforge/fml/network/FMLMCRegisterPacketHandler.java index 5cbdadfb0..16f2cdb1a 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLMCRegisterPacketHandler.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLMCRegisterPacketHandler.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.fml.network; import io.netty.buffer.Unpooled; diff --git a/src/main/java/net/minecraftforge/registries/DeferredRegister.java b/src/main/java/net/minecraftforge/registries/DeferredRegister.java new file mode 100644 index 000000000..eae15e452 --- /dev/null +++ b/src/main/java/net/minecraftforge/registries/DeferredRegister.java @@ -0,0 +1,98 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.registries; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.RegistryObject; + +/** + * Utility class to help with managing registry entries. + * Maintains a list of all suppliers for entries and registers them during the proper Register event. + * Suppliers should return NEW instances every time. + * + *Example Usage: + *
+ *   private static final DeferredRegister ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID);
+ *   private static final DeferredRegister BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID);
+ *
+ *   public static final RegistryObject ROCK_BLOCK = BLOCKS.register("rock", () -> new Block(Block.Properties.create(Material.ROCK)));
+ *   public static final RegistryObject ROCK_ITEM = ITEMS.register("rock", () -> new BlockItem(ROCK_BLOCK.get(), new Item.Properties().group(ItemGroup.MISC)));
+ *
+ *   public ExampleMod() {
+ *       ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus());
+ *       BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus());
+ *   }
+ *
+ * + * @param The base registry type, must be a concrete base class, do not use subclasses or wild cards. + */ +public class DeferredRegister> +{ + private final IForgeRegistry type; + private final String modid; + private List> entries = new ArrayList<>(); + + public DeferredRegister(IForgeRegistry reg, String modid) + { + this.type = reg; + this.modid = modid; + } + + /** + * 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. + * @return A RegistryObject that will be updated with when the entries in the registry change. + */ + public RegistryObject register(final String name, final Supplier sup) + { + final ResourceLocation key = new ResourceLocation(modid, name); + entries.add(() -> sup.get().setRegistryName(key)); + return RegistryObject.of(key.toString(), this.type); + } + + /** + * Adds our event handler to the specified event bus, this MUST be called in order for this class to function. + * See the example usage. + * + * @param bus The Mod Specific event bus. + */ + public void register(IEventBus bus) + { + bus.addListener(this::addEntries); + } + + private void addEntries(RegistryEvent.Register event) + { + if (event.getGenericType() == this.type.getRegistrySuperType()) + { + @SuppressWarnings("unchecked") + IForgeRegistry reg = (IForgeRegistry)event.getRegistry(); + entries.stream().map(Supplier::get).forEach(reg::register); + } + } +} diff --git a/src/main/java/net/minecraftforge/registries/RegistryManager.java b/src/main/java/net/minecraftforge/registries/RegistryManager.java index 118b81db9..45203a700 100644 --- a/src/main/java/net/minecraftforge/registries/RegistryManager.java +++ b/src/main/java/net/minecraftforge/registries/RegistryManager.java @@ -19,7 +19,6 @@ package net.minecraftforge.registries; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -85,7 +84,7 @@ public class RegistryManager { return this.registries.inverse().get(reg); } - + public > ResourceLocation updateLegacyName(ResourceLocation legacyName) { while (getRegistry(legacyName) == null) @@ -142,7 +141,7 @@ public class RegistryManager addLegacyName(legacyName, name); return getRegistry(name); } - + private void addLegacyName(ResourceLocation legacyName, ResourceLocation name) { if (this.legacyNames.containsKey(legacyName)) diff --git a/src/main/java/net/minecraftforge/server/command/ForgeArguments.java b/src/main/java/net/minecraftforge/server/command/ForgeArguments.java deleted file mode 100644 index d37e58321..000000000 --- a/src/main/java/net/minecraftforge/server/command/ForgeArguments.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.minecraftforge.server.command; - -public class ForgeArguments -{ - public static void register() - { - /* - * We can't actually add any of these, because vanilla clients will choke on unknown argument types - * So our custom arguments will not validate client-side, but they do still work - ArgumentTypes.register("forge:enum", EnumArgument.class, new EnumArgument.Serializer()); - ArgumentTypes.register("forge:modid", ModIdArgument.class, new ArgumentSerializer<>(ModIdArgument::modIdArgument)); - ArgumentTypes.register("forge:structure_type", StructureArgument.class, new ArgumentSerializer<>(StructureArgument::structure)); - */ - } -}