mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 08:17:35 +00:00
[1.18.2] Fix tags for custom forge registries. (#8495)
Tag-enabled registries must now be registered to vanilla's root registry. See RegistryBuilder#hasTags. Modded tag-enabled registries have to use the format `data/<namespace>/tags/<registrynamespace>/<registryname>/<tag>.json` This format is to prevent conflicts for registries with the same path but different namespaces EX: Registry name `examplemod:shoe`, tag name `blue_shoes` would be `data/<namespace>/tags/examplemod/shoe/blue_shoes.json` RegistryEvent.NewRegistry has been moved and renamed to NewRegistryEvent. RegistryBuilder#create has been made private. See NewRegistryEvent#create Created new ITagManager system for looking up Forge tags. See IForgeRegistry#tags. Add lookup methods for Holders from forge registries. See IForgeRegistry#getHolder.
This commit is contained in:
1 parent
30f3a7dbba
commit
ad75cb8644
51 files changed
+1621
-531
No files matched your search
@@ -65,7 +65,7 @@ public class ForgeWorldPresetScreens
|
||||
|
||||
static void registerPresets()
|
||||
{
|
||||
ForgeRegistries.WORLD_TYPES.forEach(wt -> {
|
||||
ForgeRegistries.WORLD_TYPES.get().forEach(wt -> {
|
||||
GeneratorPreset gen = new GeneratorPreset(wt);
|
||||
GENERATORS.put(wt, gen);
|
||||
WorldPreset.registerGenerator(gen);
|
||||
|
||||
@@ -1096,7 +1096,7 @@ public class ForgeHooks
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<EntityDataSerializer<?>, DataSerializerEntry> serializerEntries = GameData.getSerializerMap();
|
||||
private static Map<EntityDataSerializer<?>, DataSerializerEntry> serializerEntries = GameData.getSerializerMap();
|
||||
//private static final ForgeRegistry<DataSerializerEntry> serializerRegistry = (ForgeRegistry<DataSerializerEntry>) ForgeRegistries.DATA_SERIALIZERS;
|
||||
// Do not reimplement this ^ it introduces a chicken-egg scenario by classloading registries during bootstrap
|
||||
|
||||
@@ -1106,7 +1106,7 @@ public class ForgeHooks
|
||||
EntityDataSerializer<?> serializer = vanilla.byId(id);
|
||||
if (serializer == null)
|
||||
{
|
||||
DataSerializerEntry entry = ((ForgeRegistry<DataSerializerEntry>)ForgeRegistries.DATA_SERIALIZERS).getValue(id);
|
||||
DataSerializerEntry entry = ((ForgeRegistry<DataSerializerEntry>)ForgeRegistries.DATA_SERIALIZERS.get()).getValue(id);
|
||||
if (entry != null) serializer = entry.getSerializer();
|
||||
}
|
||||
return serializer;
|
||||
@@ -1117,8 +1117,16 @@ public class ForgeHooks
|
||||
int id = vanilla.getId(serializer);
|
||||
if (id < 0)
|
||||
{
|
||||
DataSerializerEntry entry = serializerEntries.get(serializer);
|
||||
if (entry != null) id = ((ForgeRegistry<DataSerializerEntry>)ForgeRegistries.DATA_SERIALIZERS).getID(entry);
|
||||
// ForgeRegistries.DATA_SERIALIZERS is a deferred register now, so if this method is called too early, the serializer map will be null
|
||||
// This should keep checking until it's not null
|
||||
if (serializerEntries == null)
|
||||
serializerEntries = GameData.getSerializerMap();
|
||||
if (serializerEntries != null)
|
||||
{
|
||||
DataSerializerEntry entry = serializerEntries.get(serializer);
|
||||
if (entry != null)
|
||||
id = ((ForgeRegistry<DataSerializerEntry>) ForgeRegistries.DATA_SERIALIZERS.get()).getID(entry);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public class ForgeMod
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker FORGEMOD = MarkerManager.getMarker("FORGEMOD");
|
||||
|
||||
private static final DeferredRegister<Attribute> ATTRIBUTES = DeferredRegister.create(Attribute.class, "forge");
|
||||
private static final DeferredRegister<Attribute> ATTRIBUTES = DeferredRegister.create(ForgeRegistries.Keys.ATTRIBUTES, "forge");
|
||||
|
||||
public static final RegistryObject<Attribute> SWIM_SPEED = ATTRIBUTES.register("swim_speed", () -> new RangedAttribute("forge.swimSpeed", 1.0D, 0.0D, 1024.0D).setSyncable(true));
|
||||
public static final RegistryObject<Attribute> NAMETAG_DISTANCE = ATTRIBUTES.register("nametag_distance", () -> new RangedAttribute("forge.nameTagDistance", 64.0D, 0.0D, 64.0).setSyncable(true));
|
||||
@@ -144,6 +144,7 @@ public class ForgeMod
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ForgeConfig.serverSpec);
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ForgeConfig.commonSpec);
|
||||
modEventBus.register(ForgeConfig.class);
|
||||
ForgeDeferredRegistriesSetup.setup(modEventBus);
|
||||
// Forge does not display problems when the remote is not matching.
|
||||
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, ()->new IExtensionPoint.DisplayTest(()->"ANY", (remote, isServer)-> true));
|
||||
StartupMessageManager.addModMessage("Forge version "+ForgeVersion.getVersion());
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import net.minecraftforge.registries.ObjectHolderRegistry;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -24,7 +25,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ForgeStatesProvider implements IModStateProvider {
|
||||
final ModLoadingState CREATE_REGISTRIES = ModLoadingState.withTransition("CREATE_REGISTRIES", "CONSTRUCT", ModLoadingPhase.GATHER, SerialTransition.of(()-> Stream.of(IModStateTransition.EventGenerator.fromFunction(RegistryEvent.NewRegistry::new))));
|
||||
final ModLoadingState CREATE_REGISTRIES = ModLoadingState.withTransition("CREATE_REGISTRIES", "CONSTRUCT", ModLoadingPhase.GATHER, new SerialTransition<>(() -> Stream.of(IModStateTransition.EventGenerator.fromFunction(RegistryManager.newRegistryEventGenerator())), RegistryManager::preNewRegistryEvent, RegistryManager::postNewRegistryEvent, (e, prev) -> prev.thenApplyAsync(Function.identity(), e)));
|
||||
final ModLoadingState OBJECT_HOLDERS = ModLoadingState.withInline("OBJECT_HOLDERS", "CREATE_REGISTRIES", ModLoadingPhase.GATHER, ml-> ObjectHolderRegistry.findObjectHolders());
|
||||
final ModLoadingState INJECT_CAPABILITIES = ModLoadingState.withInline("INJECT_CAPABILITIES", "OBJECT_HOLDERS", ModLoadingPhase.GATHER, ml-> CapabilityManager.INSTANCE.injectCapabilities(ml.getAllScanData()));
|
||||
final ModLoadingState UNFREEZE = ModLoadingState.withInline("UNFREEZE_DATA", "INJECT_CAPABILITIES", ModLoadingPhase.GATHER, ml->GameData.unfreezeData());
|
||||
@@ -36,6 +37,7 @@ public class ForgeStatesProvider implements IModStateProvider {
|
||||
return List.of(CREATE_REGISTRIES, OBJECT_HOLDERS, INJECT_CAPABILITIES, UNFREEZE, LOAD_REGISTRIES, FREEZE, NETLOCK);
|
||||
}
|
||||
|
||||
// TODO 1.19: Pass the event instances to the pre and post hooks rather than the event generators
|
||||
static record SerialTransition<T extends Event & IModBusEvent>(Supplier<Stream<EventGenerator<?>>> eventStream, BiFunction<Executor, ? extends EventGenerator<T>, CompletableFuture<List<Throwable>>> preDispatchHook, BiFunction<Executor, ? extends EventGenerator<T>, CompletableFuture<List<Throwable>>> postDispatchHook, BiFunction<Executor, CompletableFuture<List<Throwable>>, CompletableFuture<List<Throwable>>> finalActivityGenerator) implements IModStateTransition {
|
||||
public static <T extends Event & IModBusEvent> SerialTransition<T> of(Supplier<Stream<EventGenerator<?>>> eventStream) {
|
||||
return new SerialTransition<T>(eventStream, (t, f)->CompletableFuture.completedFuture(Collections.emptyList()), (t, f)->CompletableFuture.completedFuture(Collections.emptyList()), (e, prev) ->prev.thenApplyAsync(Function.identity(), e));
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagLoader;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class ForgeTagHandler
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static Set<ResourceLocation> customTagTypeNames = Collections.emptySet();
|
||||
private static boolean tagTypesSet = false;
|
||||
|
||||
// TODO-PATCHING: remove the custom registry tags stuff (1.18.2 has universal tags) and rework how optional tags could work
|
||||
// @Nullable
|
||||
// private static <T extends IForgeRegistryEntry<T>> StaticTagHelper<T> getTagHelper(IForgeRegistry<T> registry)
|
||||
// {
|
||||
// return (StaticTagHelper<T>) StaticTags.get(registry.getRegistryName());
|
||||
// }
|
||||
//
|
||||
// private static void validateRegistrySupportsTags(IForgeRegistry<?> registry)
|
||||
// {
|
||||
// //Note: We also check against getTagHelper in case someone decides to use the helpers for tag creation for types supported by vanilla
|
||||
// if (getTagHelper(registry) == null && (!(registry instanceof ForgeRegistry) || ((ForgeRegistry<?>) registry).getTagFolder() == null))
|
||||
// {
|
||||
// throw new IllegalArgumentException("Registry " + registry.getRegistryName() + " does not support tag types.");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper method that creates a named tag for a forge registry, erroring if the registry doesn't support custom tag types. If the custom tag types
|
||||
// * have not been set yet, this method falls back and creates the tag reference delaying adding it to the tag registry to allow for statically
|
||||
// * initializing and referencing the tag.
|
||||
// * @param registry Registry the tag is for
|
||||
// * @param name Name of the tag
|
||||
// * @param <T> Type of the registry
|
||||
// * @return A named tag
|
||||
// */
|
||||
// public static <T extends IForgeRegistryEntry<T>> Named<T> makeWrapperTag(IForgeRegistry<T> registry, ResourceLocation name)
|
||||
// {
|
||||
// validateRegistrySupportsTags(registry);
|
||||
// if (tagTypesSet)
|
||||
// {
|
||||
// StaticTagHelper<T> tagRegistry = getTagHelper(registry);
|
||||
// if (tagRegistry == null) throw new IllegalArgumentException("Registry " + registry.getRegistryName() + " does not support tag types.");
|
||||
// return tagRegistry.bind(name.toString());
|
||||
// }
|
||||
// return StaticTagHelper.createDelayedTag(registry.getRegistryName(), name);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper method that creates an optional tag for a forge registry, erroring if the registry doesn't support custom tag types. If the custom tag types
|
||||
// * have not been set yet, this method falls back and creates the tag reference delaying adding it to the tag registry to allow for statically
|
||||
// * initializing and referencing the tag.
|
||||
// * @param registry Registry the tag is for
|
||||
// * @param name Name of the tag
|
||||
// * @param <T> Type of the registry
|
||||
// * @return An optional tag
|
||||
// */
|
||||
// public static <T extends IForgeRegistryEntry<T>> IOptionalNamedTag<T> createOptionalTag(IForgeRegistry<T> registry, ResourceLocation name)
|
||||
// {
|
||||
// return createOptionalTag(registry, name, null);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper method that creates an optional tag for a forge registry, erroring if the registry doesn't support custom tag types. If the custom tag types
|
||||
// * have not been set yet, this method falls back and creates the tag reference delaying adding it to the tag registry to allow for statically
|
||||
// * initializing and referencing the tag.
|
||||
// * @param registry Registry the tag is for
|
||||
// * @param name Name of the tag
|
||||
// * @param defaults Default values for the optional tag
|
||||
// * @param <T> Type of the registry
|
||||
// * @return An optional tag
|
||||
// */
|
||||
// public static <T extends IForgeRegistryEntry<T>> IOptionalNamedTag<T> createOptionalTag(IForgeRegistry<T> registry, ResourceLocation name, @Nullable Set<Supplier<T>> defaults)
|
||||
// {
|
||||
// validateRegistrySupportsTags(registry);
|
||||
// if (tagTypesSet)
|
||||
// {
|
||||
// StaticTagHelper<T> tagRegistry = getTagHelper(registry);
|
||||
// if (tagRegistry == null) throw new IllegalArgumentException("Registry " + registry.getRegistryName() + " does not support tag types.");
|
||||
// return tagRegistry.createOptional(name, defaults);
|
||||
// }
|
||||
// return StaticTagHelper.createDelayedOptional(registry.getRegistryName(), name, defaults);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper method for creating named tags for custom forge registries. If the custom tag types have not been set yet, this method falls back and creates
|
||||
// * the tag reference delaying adding it to the tag registry to allow for statically initializing and referencing the tag.
|
||||
// * @param registryName Name of the registry the tag is for
|
||||
// * @param name Name of the tag
|
||||
// * @param <T> Type of the registry
|
||||
// * @return A named tag
|
||||
// * @implNote This method only errors instantly if tag types have already been set, otherwise the error is delayed until after registries finish initializing
|
||||
// * and we can validate if the custom registry really does support custom tags.
|
||||
// */
|
||||
// public static <T extends IForgeRegistryEntry<T>> Named<T> makeWrapperTag(ResourceLocation registryName, ResourceLocation name)
|
||||
// {
|
||||
// if (tagTypesSet)
|
||||
// {
|
||||
// IForgeRegistry<T> registry = RegistryManager.ACTIVE.getRegistry(registryName);
|
||||
// if (registry == null) throw new IllegalArgumentException("Could not find registry named: " + registryName);
|
||||
// return makeWrapperTag(registry, name);
|
||||
// }
|
||||
// return StaticTagHelper.createDelayedTag(registryName, name);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper method for creating optional tags for custom forge registries. If the custom tag types have not been set yet, this method falls back and creates
|
||||
// * the tag reference delaying adding it to the tag registry to allow for statically initializing and referencing the tag.
|
||||
// * @param registryName Name of the registry the tag is for
|
||||
// * @param name Name of the tag
|
||||
// * @param <T> Type of the registry
|
||||
// * @return An optional tag
|
||||
// * @implNote This method only errors instantly if tag types have already been set, otherwise the error is delayed until after registries finish initializing
|
||||
// * and we can validate if the custom registry really does support custom tags.
|
||||
// */
|
||||
// public static <T extends IForgeRegistryEntry<T>> IOptionalNamedTag<T> createOptionalTag(ResourceLocation registryName, ResourceLocation name)
|
||||
// {
|
||||
// return createOptionalTag(registryName, name, null);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper method for creating optional tags for custom forge registries. If the custom tag types have not been set yet, this method falls back and creates
|
||||
// * the tag reference delaying adding it to the tag registry to allow for statically initializing and referencing the tag.
|
||||
// * @param registryName Name of the registry the tag is for
|
||||
// * @param name Name of the tag
|
||||
// * @param defaults Default values for the optional tag
|
||||
// * @param <T> Type of the registry
|
||||
// * @return An optional tag
|
||||
// * @implNote This method only errors instantly if tag types have already been set, otherwise the error is delayed until after registries finish initializing
|
||||
// * and we can validate if the custom registry really does support custom tags.
|
||||
// */
|
||||
// public static <T extends IForgeRegistryEntry<T>> IOptionalNamedTag<T> createOptionalTag(ResourceLocation registryName, ResourceLocation name, @Nullable Set<Supplier<T>> defaults)
|
||||
// {
|
||||
// if (tagTypesSet)
|
||||
// {
|
||||
// IForgeRegistry<T> registry = RegistryManager.ACTIVE.getRegistry(registryName);
|
||||
// if (registry == null) throw new IllegalArgumentException("Could not find registry named: " + registryName);
|
||||
// return createOptionalTag(registry, name, defaults);
|
||||
// }
|
||||
// return StaticTagHelper.createDelayedOptional(registryName, name, defaults);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Gets the all the registry names of registries that support custom tag types.
|
||||
*/
|
||||
public static Set<ResourceLocation> getCustomTagTypeNames()
|
||||
{
|
||||
return customTagTypeNames;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the set containing the resource locations representing the registry name of each forge registry that supports custom tag types.
|
||||
// *
|
||||
// * @apiNote Internal: Calling this manually <strong>WILL</strong> cause a crash to occur as it can only be called once, and is done so by
|
||||
// * forge after all registries have been initialized.
|
||||
// */
|
||||
// public static void setCustomTagTypes(Set<ResourceLocation> customTagTypesNames)
|
||||
// {
|
||||
// if (tagTypesSet) throw new RuntimeException("Custom tag types have already been set, this method should only be called by forge, and after registries are initialized");
|
||||
// tagTypesSet = true;
|
||||
// customTagTypeNames = ImmutableSet.copyOf(customTagTypesNames);
|
||||
// //Add the static references for custom tag types to the proper tag registries
|
||||
// // Note: If this ends up being a hotspot due to lots of mods having lots of statically registered tags
|
||||
// // that get loaded/registered before the new registry event is fired/processed everywhere then this
|
||||
// // potentially should end up being moved into an async processor.
|
||||
// StaticTagHelper.performDelayedAdd();
|
||||
// }
|
||||
|
||||
/**
|
||||
* Creates a map for custom tag type to tag reader
|
||||
*
|
||||
* @apiNote Internal: For use by TagManager
|
||||
*/
|
||||
public static Map<ResourceLocation, TagLoader<?>> createCustomTagTypeReaders()
|
||||
{
|
||||
LOGGER.debug("Gathering custom tag collection reader from types.");
|
||||
ImmutableMap.Builder<ResourceLocation, TagLoader<?>> builder = ImmutableMap.builder();
|
||||
for (ResourceLocation registryName : customTagTypeNames)
|
||||
{
|
||||
ForgeRegistry<?> registry = RegistryManager.ACTIVE.getRegistry(registryName);
|
||||
if (registry != null && registry.getTagFolder() != null)
|
||||
{
|
||||
builder.put(registryName, new TagLoader<>(rl -> Optional.ofNullable(registry.getValue(rl)), "tags/" + registry.getTagFolder()));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Wraps the forge registry if it supports tags into the internal registry for use in serialization
|
||||
// *
|
||||
// * @apiNote Internal: For use in TagContainer
|
||||
// */
|
||||
// @SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "unchecked"})
|
||||
// public static <T> Optional<? extends Registry<T>> getWrapperRegistry(ResourceKey<? extends Registry<T>> key, Optional<? extends Registry<T>> vanillaReg)
|
||||
// {
|
||||
// if (vanillaReg.isPresent())
|
||||
// return vanillaReg;
|
||||
//
|
||||
// ForgeRegistry<?> reg = RegistryManager.ACTIVE.getRegistry(key.location());
|
||||
// if (reg == null || reg.getTagFolder() == null)
|
||||
// return Optional.empty();
|
||||
//
|
||||
// if (reg.getDefaultKey() == null)
|
||||
// return Optional.of((Registry<T>) GameData.getWrapper(reg.getRegistryKey(), Lifecycle.stable()));
|
||||
// return Optional.of((Registry<T>) GameData.getWrapper(reg.getRegistryKey(), Lifecycle.stable(), "ignored"));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Helper to reinject missing optional tags.
|
||||
// *
|
||||
// * @apiNote Internal
|
||||
// */
|
||||
// public static TagContainer reinjectOptionalTags(TagContainer tagCollectionSupplier)
|
||||
// {
|
||||
// TagContainer.Builder builder = new TagContainer.Builder();
|
||||
// //noinspection unchecked,rawtypes
|
||||
// StaticTags.visitHelpers(h -> builder.add(h.getKey(), h.reinjectOptionalTags(tagCollectionSupplier.getOrEmpty((ResourceKey) h.getKey()))));
|
||||
// return builder.build();
|
||||
// }
|
||||
}
|
||||
@@ -5,59 +5,28 @@
|
||||
|
||||
package net.minecraftforge.common.data;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.tags.TagsProvider;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class ForgeRegistryTagsProvider<T extends IForgeRegistryEntry<T>> extends TagsProvider<T>
|
||||
{
|
||||
//TODO add game event tags here when they become a forge registry
|
||||
//Special handling for vanilla tag types in case someone decides to use the ForgeRegistryTagsProvider instead of one of the vanilla subtypes
|
||||
private static final Map<IForgeRegistry<?>, String> vanillaTypes = ImmutableMap.<IForgeRegistry<?>, String>builder()
|
||||
.put(ForgeRegistries.BLOCKS, "blocks")
|
||||
.put(ForgeRegistries.ENTITIES, "entity_types")
|
||||
.put(ForgeRegistries.FLUIDS, "fluids")
|
||||
.put(ForgeRegistries.ITEMS, "items")
|
||||
.build();
|
||||
|
||||
private static <T extends IForgeRegistryEntry<T>> Registry<T> wrapRegistry(IForgeRegistry<T> registryIn)
|
||||
private static <T extends IForgeRegistryEntry<T>> Registry<T> wrapRegistry(IForgeRegistry<T> forgeRegistry)
|
||||
{
|
||||
if (!(registryIn instanceof ForgeRegistry))
|
||||
throw new IllegalArgumentException("Forge registry " + registryIn.getRegistryName() + " is not an instance of a ForgeRegistry");
|
||||
ForgeRegistry<T> forgeRegistry = (ForgeRegistry<T>) registryIn;
|
||||
if (forgeRegistry.getTagFolder() == null && !vanillaTypes.containsKey(registryIn))
|
||||
throw new IllegalArgumentException("Forge registry " + registryIn.getRegistryName() + " does not have support for tags");
|
||||
if (forgeRegistry.tags() == null)
|
||||
throw new IllegalArgumentException("Forge registry " + forgeRegistry.getRegistryName() + " does not have support for tags");
|
||||
if (forgeRegistry.getDefaultKey() == null)
|
||||
return GameData.getWrapper(forgeRegistry.getRegistryKey(), Lifecycle.experimental());
|
||||
return GameData.getWrapper(forgeRegistry.getRegistryKey(), Lifecycle.experimental(), "default");
|
||||
}
|
||||
|
||||
private static <T extends IForgeRegistryEntry<T>> String getTagFolder(IForgeRegistry<T> registryIn)
|
||||
public ForgeRegistryTagsProvider(DataGenerator generator, IForgeRegistry<T> forgeRegistry, String modId, @Nullable ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
String tagFolder = ((ForgeRegistry<T>) registryIn).getTagFolder();
|
||||
return tagFolder == null ? vanillaTypes.get(registryIn) : tagFolder;
|
||||
}
|
||||
|
||||
public ForgeRegistryTagsProvider(DataGenerator generatorIn, IForgeRegistry<T> registryIn, String modId, @Nullable ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(generatorIn, wrapRegistry(registryIn), modId, existingFileHelper, getTagFolder(registryIn));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path getPath(ResourceLocation id)
|
||||
{
|
||||
//TODO-PATCHING: Mojang has introduced logic here to determine where the tags go, we need to replicate that logic possibly.
|
||||
return generator.getOutputFolder().resolve("data/" + id.getNamespace() + "/tags/" + folder + "/" + id.getPath() + ".json");
|
||||
super(generator, wrapRegistry(forgeRegistry), modId, existingFileHelper);
|
||||
}
|
||||
}
|
||||
@@ -116,11 +116,11 @@ public class LootModifierManager extends SimpleJsonResourceReloadListener {
|
||||
|
||||
ResourceLocation serializer = new ResourceLocation(GsonHelper.getAsString(object, "type"));
|
||||
|
||||
return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.getValue(serializer).read(location, object, lootConditions);
|
||||
return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getValue(serializer).read(location, object, lootConditions);
|
||||
}
|
||||
|
||||
public static GlobalLootModifierSerializer<?> getSerializerForName(ResourceLocation resourcelocation) {
|
||||
return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.getValue(resourcelocation);
|
||||
return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.get().getValue(resourcelocation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ public class ForgeWorldPreset extends ForgeRegistryEntry<ForgeWorldPreset>
|
||||
if (StringUtil.isNullOrEmpty(defaultWorldType) || "default".equals(defaultWorldType))
|
||||
return null; // use vanilla
|
||||
|
||||
ForgeWorldPreset def = ForgeRegistries.WORLD_TYPES.getValue(new ResourceLocation(defaultWorldType));
|
||||
ForgeWorldPreset def = ForgeRegistries.WORLD_TYPES.get().getValue(new ResourceLocation(defaultWorldType));
|
||||
if (def == null)
|
||||
{
|
||||
LOGGER.error("The defaultWorldType '{}' specified in the forge config has not been registered. The vanilla default generator will be used.", defaultWorldType);
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import net.minecraftforge.registries.RegistryBuilder;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -27,7 +26,6 @@ import net.minecraftforge.eventbus.api.GenericEvent;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
|
||||
/**
|
||||
* RegistryEvent supertype.
|
||||
*/
|
||||
@@ -36,17 +34,6 @@ public class RegistryEvent<T extends IForgeRegistryEntry<T>> extends GenericEven
|
||||
RegistryEvent(Class<T> clazz) {
|
||||
super(clazz);
|
||||
}
|
||||
/**
|
||||
* Register new registries when you receive this event, through the {@link RegistryBuilder}
|
||||
*/
|
||||
public static class NewRegistry extends net.minecraftforge.eventbus.api.Event implements IModBusEvent
|
||||
{
|
||||
public NewRegistry(ModContainer mc) {}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegistryEvent.NewRegistry";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register your objects for the appropriate registry type when you receive this event.
|
||||
|
||||
+15
-6
@@ -8,8 +8,10 @@ package net.minecraftforge.network.filters;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -17,6 +19,7 @@ import io.netty.channel.ChannelHandler;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypes;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.game.ClientboundCommandsPacket;
|
||||
@@ -25,15 +28,15 @@ import net.minecraft.network.protocol.game.ClientboundUpdateTagsPacket;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagNetworkSerialization;
|
||||
import net.minecraftforge.common.ForgeTagHandler;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
import com.mojang.logging.LogUtils;
|
||||
|
||||
/**
|
||||
* A filter for impl packets, used to filter/modify parts of vanilla impl messages that
|
||||
@@ -42,8 +45,7 @@ import com.mojang.brigadier.tree.RootCommandNode;
|
||||
@ChannelHandler.Sharable
|
||||
public class VanillaConnectionNetworkFilter extends VanillaPacketFilter
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public VanillaConnectionNetworkFilter()
|
||||
{
|
||||
@@ -100,8 +102,15 @@ public class VanillaConnectionNetworkFilter extends VanillaPacketFilter
|
||||
*/
|
||||
private static ClientboundUpdateTagsPacket filterCustomTagTypes(ClientboundUpdateTagsPacket packet) {
|
||||
Map<ResourceKey<? extends Registry<?>>, TagNetworkSerialization.NetworkPayload> tags = packet.getTags()
|
||||
.entrySet().stream().filter(e -> !ForgeTagHandler.getCustomTagTypeNames().contains(e.getKey().location()))
|
||||
.entrySet().stream().filter(e -> isVanillaRegistry(e.getKey().location()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
return new ClientboundUpdateTagsPacket(tags);
|
||||
}
|
||||
|
||||
private static boolean isVanillaRegistry(ResourceLocation location)
|
||||
{
|
||||
// Checks if the registry name is contained within the static view of vanilla registries both in Registry and builtin registries
|
||||
return RegistryManager.getVanillaRegistryKeys().contains(location)
|
||||
|| RegistryAccess.REGISTRIES.keySet().stream().anyMatch(k -> k.location().equals(location));
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,23 @@
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.registries.tags.ITagManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -47,35 +57,66 @@ public class DeferredRegister<T extends IForgeRegistryEntry<T>>
|
||||
*/
|
||||
public static <B extends IForgeRegistryEntry<B>> DeferredRegister<B> create(IForgeRegistry<B> reg, String modid)
|
||||
{
|
||||
return new DeferredRegister<B>(reg, modid);
|
||||
return new DeferredRegister<>(reg, modid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use for custom registries that are made during the NewRegistry event.
|
||||
* Use for custom registries that are made during the NewRegistry event.
|
||||
*
|
||||
* @deprecated Use {@link #create(ResourceLocation, String)} and {@link #makeRegistry(Class, Supplier)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
public static <B extends IForgeRegistryEntry<B>> DeferredRegister<B> create(Class<B> base, String modid)
|
||||
{
|
||||
return new DeferredRegister<B>(base, modid);
|
||||
return new DeferredRegister<>(null, base, modid);
|
||||
}
|
||||
|
||||
/**
|
||||
* DeferredRegister factory for custom registries that are made during the {@link NewRegistryEvent} event
|
||||
* or with {@link #makeRegistry(Class, Supplier)}.
|
||||
*
|
||||
* @param key The key of the registry to reference
|
||||
* @param modid The namespace for all objects registered to this DeferredRegister
|
||||
*/
|
||||
public static <B extends IForgeRegistryEntry<B>> DeferredRegister<B> create(ResourceKey<? extends Registry<B>> key, String modid)
|
||||
{
|
||||
return new DeferredRegister<>(key.location(), null, modid);
|
||||
}
|
||||
|
||||
/**
|
||||
* DeferredRegister factory for custom registries that are made during the {@link NewRegistryEvent} event
|
||||
* or with {@link #makeRegistry(Class, Supplier)}.
|
||||
*
|
||||
* @param registryName The name of the registry, should include namespace. May come from another DeferredRegister through {@link #getRegistryName()}.
|
||||
* @param modid The namespace for all objects registered to this DeferredRegister
|
||||
*/
|
||||
public static <B extends IForgeRegistryEntry<B>> DeferredRegister<B> create(ResourceLocation registryName, String modid)
|
||||
{
|
||||
return new DeferredRegister<>(registryName, null, modid);
|
||||
}
|
||||
|
||||
private final ResourceLocation registryName;
|
||||
private final Class<T> superType;
|
||||
private final String modid;
|
||||
private final Map<RegistryObject<T>, Supplier<? extends T>> entries = new LinkedHashMap<>();
|
||||
private final Set<RegistryObject<T>> entriesView = Collections.unmodifiableSet(entries.keySet());
|
||||
|
||||
private IForgeRegistry<T> type;
|
||||
private Supplier<IForgeRegistry<T>> typeSupplier;
|
||||
private Supplier<RegistryBuilder<T>> registryFactory;
|
||||
private SetMultimap<TagKey<T>, Supplier<T>> optionalTags;
|
||||
private boolean seenRegisterEvent = false;
|
||||
|
||||
private DeferredRegister(Class<T> base, String modid)
|
||||
private DeferredRegister(@Nullable ResourceLocation registryName, @Nullable Class<T> base, String modid)
|
||||
{
|
||||
this.registryName = registryName;
|
||||
this.superType = base;
|
||||
this.modid = modid;
|
||||
}
|
||||
|
||||
private DeferredRegister(IForgeRegistry<T> reg, String modid)
|
||||
{
|
||||
this(reg.getRegistrySuperType(), modid);
|
||||
this(reg.getRegistryName(), reg.getRegistrySuperType(), modid);
|
||||
this.type = reg;
|
||||
}
|
||||
|
||||
@@ -96,8 +137,11 @@ public class DeferredRegister<T extends IForgeRegistryEntry<T>>
|
||||
final ResourceLocation key = new ResourceLocation(modid, name);
|
||||
|
||||
RegistryObject<I> ret;
|
||||
if (this.type != null)
|
||||
ret = RegistryObject.of(key, this.type);
|
||||
IForgeRegistry<T> reg = getForgeRegistry();
|
||||
if (reg != null)
|
||||
ret = RegistryObject.of(key, reg);
|
||||
else if (this.registryName != null)
|
||||
ret = RegistryObject.of(key, this.registryName, this.modid);
|
||||
else if (this.superType != null)
|
||||
ret = RegistryObject.of(key, this.superType, this.modid);
|
||||
else
|
||||
@@ -118,15 +162,122 @@ public class DeferredRegister<T extends IForgeRegistryEntry<T>>
|
||||
* @param name Path of the registry's {@link ResourceLocation}
|
||||
* @param sup Supplier of the RegistryBuilder that is called to fill {@link #type} during the NewRegistry event
|
||||
* @return A supplier of the {@link IForgeRegistry} created by the builder.
|
||||
*
|
||||
* @deprecated Use {@link #create(ResourceLocation, String)} and {@link #makeRegistry(Class, Supplier)} instead
|
||||
*/
|
||||
public Supplier<IForgeRegistry<T>> makeRegistry(final String name, final Supplier<RegistryBuilder<T>> sup) {
|
||||
if (this.superType == null)
|
||||
throw new IllegalStateException("Cannot create a registry without specifying a base type");
|
||||
if (this.type != null || this.registryFactory != null)
|
||||
throw new IllegalStateException("Cannot create a registry for a type that already exists");
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
public Supplier<IForgeRegistry<T>> makeRegistry(final String name, final Supplier<RegistryBuilder<T>> sup)
|
||||
{
|
||||
return makeRegistry(new ResourceLocation(modid, name), this.superType, sup);
|
||||
}
|
||||
|
||||
this.registryFactory = () -> sup.get().setName(new ResourceLocation(modid, name)).setType(this.superType);
|
||||
return () -> this.type;
|
||||
/**
|
||||
* Only used for custom registries to fill the forge registry held in this DeferredRegister.
|
||||
*
|
||||
* Calls {@link RegistryBuilder#setName} and {@link RegistryBuilder#setType} automatically.
|
||||
*
|
||||
* @param base The base type to use in the created {@link IForgeRegistry}
|
||||
* @param sup Supplier of a RegistryBuilder that initializes a {@link IForgeRegistry} during the {@link NewRegistryEvent} event
|
||||
* @return A supplier of the {@link IForgeRegistry} created by the builder.
|
||||
* Will always return null until after the {@link NewRegistryEvent} event fires.
|
||||
*/
|
||||
public Supplier<IForgeRegistry<T>> makeRegistry(final Class<T> base, final Supplier<RegistryBuilder<T>> sup)
|
||||
{
|
||||
return makeRegistry(this.registryName, base, sup);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<T> createTagKey(@NotNull String path)
|
||||
{
|
||||
Objects.requireNonNull(path);
|
||||
return createTagKey(new ResourceLocation(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)}.
|
||||
*
|
||||
* @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<T> createTagKey(@NotNull ResourceLocation location)
|
||||
{
|
||||
if (this.registryName == null)
|
||||
throw new IllegalStateException("The registry name was not set, cannot create a tag key");
|
||||
Objects.requireNonNull(location);
|
||||
return TagKey.create(ResourceKey.createRegistryKey(this.registryName), location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tag key with the current modid and provided path that will use the set of defaults if the tag is not loaded from any datapacks.
|
||||
* 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)
|
||||
* @see #addOptionalTagDefaults(TagKey, Set)
|
||||
*/
|
||||
@NotNull
|
||||
public TagKey<T> createOptionalTagKey(@NotNull String path, @NotNull Set<? extends Supplier<T>> defaults)
|
||||
{
|
||||
Objects.requireNonNull(path);
|
||||
return createOptionalTagKey(new ResourceLocation(this.modid, path), defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tag key with the provided location that will use the set of defaults if the tag is not loaded from any datapacks.
|
||||
* 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)
|
||||
* @see #addOptionalTagDefaults(TagKey, Set)
|
||||
*/
|
||||
@NotNull
|
||||
public TagKey<T> createOptionalTagKey(@NotNull ResourceLocation location, @NotNull Set<? extends Supplier<T>> defaults)
|
||||
{
|
||||
TagKey<T> tagKey = createTagKey(location);
|
||||
|
||||
addOptionalTagDefaults(tagKey, defaults);
|
||||
|
||||
return tagKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds defaults to an existing tag key.
|
||||
* 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<T> name, @NotNull Set<? extends Supplier<T>> defaults)
|
||||
{
|
||||
Objects.requireNonNull(defaults);
|
||||
if (optionalTags == null)
|
||||
optionalTags = Multimaps.newSetMultimap(new IdentityHashMap<>(), HashSet::new);
|
||||
|
||||
optionalTags.putAll(name, defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,17 +313,60 @@ public class DeferredRegister<T extends IForgeRegistryEntry<T>>
|
||||
return entriesView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The registry name stored in this deferred register. Useful for creating new deferred registers based on an existing one.
|
||||
*/
|
||||
@Nullable
|
||||
public ResourceLocation getRegistryName()
|
||||
{
|
||||
return this.registryName;
|
||||
}
|
||||
|
||||
private Supplier<IForgeRegistry<T>> makeRegistry(final ResourceLocation registryName, final Class<T> superType, final Supplier<RegistryBuilder<T>> sup) {
|
||||
if (registryName == null)
|
||||
throw new IllegalStateException("Cannot create a registry without specifying a registry name");
|
||||
if (superType == null)
|
||||
throw new IllegalStateException("Cannot create a registry without specifying a base type");
|
||||
if (this.type != null || this.registryFactory != null)
|
||||
throw new IllegalStateException("Cannot create a registry for a type that already exists");
|
||||
|
||||
this.registryFactory = () -> sup.get().setName(registryName).setType(superType);
|
||||
return this::getForgeRegistry;
|
||||
}
|
||||
|
||||
private IForgeRegistry<T> getForgeRegistry()
|
||||
{
|
||||
if (this.type == null && this.typeSupplier != null)
|
||||
this.type = this.typeSupplier.get();
|
||||
|
||||
return this.type;
|
||||
}
|
||||
|
||||
private void onFill(IForgeRegistry<T> registry)
|
||||
{
|
||||
if (this.optionalTags == null)
|
||||
return;
|
||||
|
||||
ITagManager<T> tagManager = registry.tags();
|
||||
if (tagManager == null)
|
||||
throw new IllegalStateException("The forge registry " + registry.getRegistryName() + " does not support tags, but optional tags were registered!");
|
||||
|
||||
Multimaps.asMap(this.optionalTags).forEach(tagManager::addOptionalTagDefaults);
|
||||
}
|
||||
|
||||
private void addEntries(RegistryEvent.Register<?> event)
|
||||
{
|
||||
if (this.type == null && this.registryFactory == null)
|
||||
IForgeRegistry<T> storedType = this.getForgeRegistry();
|
||||
if (storedType == null && this.registryFactory == null)
|
||||
{
|
||||
//If there is no type yet and we don't have a registry factory, attempt to capture the registry
|
||||
//Note: This will only ever get run on the first registry event, as after that time,
|
||||
// the type will no longer be null. This is needed here rather than during the NewRegistry event
|
||||
// to ensure that mods can properly use deferred registers for custom registries added by other mods
|
||||
captureRegistry();
|
||||
storedType = this.type;
|
||||
}
|
||||
if (this.type != null && event.getGenericType() == this.type.getRegistrySuperType())
|
||||
if (storedType != null && event.getGenericType() == storedType.getRegistrySuperType())
|
||||
{
|
||||
this.seenRegisterEvent = true;
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -185,14 +379,20 @@ public class DeferredRegister<T extends IForgeRegistryEntry<T>>
|
||||
}
|
||||
}
|
||||
|
||||
private void createRegistry(RegistryEvent.NewRegistry event)
|
||||
private void createRegistry(NewRegistryEvent event)
|
||||
{
|
||||
this.type = this.registryFactory.get().create();
|
||||
this.typeSupplier = event.create(this.registryFactory.get(), this::onFill);
|
||||
}
|
||||
|
||||
private void captureRegistry()
|
||||
{
|
||||
if (this.superType != null)
|
||||
if (this.registryName != null)
|
||||
{
|
||||
this.type = RegistryManager.ACTIVE.getRegistry(this.registryName);
|
||||
if (this.type == null)
|
||||
throw new IllegalStateException("Unable to find registry with key " + this.registryName + " for modid \"" + modid + "\" after NewRegistry event");
|
||||
}
|
||||
else if (this.superType != null)
|
||||
{
|
||||
this.type = RegistryManager.ACTIVE.getRegistry(this.superType);
|
||||
if (this.type == null)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
|
||||
public class ForgeDeferredRegistriesSetup
|
||||
{
|
||||
private static boolean setup = false;
|
||||
|
||||
/**
|
||||
* Internal forge method. Modders do not call.
|
||||
*/
|
||||
public static void setup(IEventBus modEventBus)
|
||||
{
|
||||
if (setup)
|
||||
throw new IllegalStateException("Setup has already been called!");
|
||||
|
||||
ForgeRegistries.DEFERRED_DATA_SERIALIZERS.register(modEventBus);
|
||||
ForgeRegistries.DEFERRED_LOOT_MODIFIER_SERIALIZERS.register(modEventBus);
|
||||
ForgeRegistries.DEFERRED_WORLD_TYPES.register(modEventBus);
|
||||
|
||||
setup = true;
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ import net.minecraftforge.common.Tags;
|
||||
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
|
||||
import net.minecraftforge.common.world.ForgeWorldPreset;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A class that exposes static references to all vanilla and Forge registries.
|
||||
* Created to have a central place to access the registries directly if modders need.
|
||||
@@ -52,46 +54,49 @@ public class ForgeRegistries
|
||||
static { init(); } // This must be above the fields so we guarantee it's run before getRegistry is called. Yay static inializers
|
||||
|
||||
// Game objects
|
||||
public static final IForgeRegistry<Block> BLOCKS = RegistryManager.ACTIVE.getRegistry(Block.class);
|
||||
public static final IForgeRegistry<Fluid> FLUIDS = RegistryManager.ACTIVE.getRegistry(Fluid.class);
|
||||
public static final IForgeRegistry<Item> ITEMS = RegistryManager.ACTIVE.getRegistry(Item.class);
|
||||
public static final IForgeRegistry<MobEffect> MOB_EFFECTS = RegistryManager.ACTIVE.getRegistry(MobEffect.class);
|
||||
public static final IForgeRegistry<SoundEvent> SOUND_EVENTS = RegistryManager.ACTIVE.getRegistry(SoundEvent.class);
|
||||
public static final IForgeRegistry<Potion> POTIONS = RegistryManager.ACTIVE.getRegistry(Potion.class);
|
||||
public static final IForgeRegistry<Enchantment> ENCHANTMENTS = RegistryManager.ACTIVE.getRegistry(Enchantment.class);
|
||||
public static final IForgeRegistry<EntityType<?>> ENTITIES = RegistryManager.ACTIVE.getRegistry(EntityType.class);
|
||||
public static final IForgeRegistry<BlockEntityType<?>> BLOCK_ENTITIES = RegistryManager.ACTIVE.getRegistry(BlockEntityType.class);
|
||||
public static final IForgeRegistry<ParticleType<?>> PARTICLE_TYPES = RegistryManager.ACTIVE.getRegistry(ParticleType.class);
|
||||
public static final IForgeRegistry<MenuType<?>> CONTAINERS = RegistryManager.ACTIVE.getRegistry(MenuType.class);
|
||||
public static final IForgeRegistry<Motive> PAINTING_TYPES = RegistryManager.ACTIVE.getRegistry(Motive.class);
|
||||
public static final IForgeRegistry<RecipeSerializer<?>> RECIPE_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(RecipeSerializer.class);
|
||||
public static final IForgeRegistry<Attribute> ATTRIBUTES = RegistryManager.ACTIVE.getRegistry(Attribute.class);
|
||||
public static final IForgeRegistry<StatType<?>> STAT_TYPES = RegistryManager.ACTIVE.getRegistry(StatType.class);
|
||||
public static final IForgeRegistry<Block> BLOCKS = RegistryManager.ACTIVE.getRegistry(Keys.BLOCKS);
|
||||
public static final IForgeRegistry<Fluid> FLUIDS = RegistryManager.ACTIVE.getRegistry(Keys.FLUIDS);
|
||||
public static final IForgeRegistry<Item> ITEMS = RegistryManager.ACTIVE.getRegistry(Keys.ITEMS);
|
||||
public static final IForgeRegistry<MobEffect> MOB_EFFECTS = RegistryManager.ACTIVE.getRegistry(Keys.MOB_EFFECTS);
|
||||
public static final IForgeRegistry<SoundEvent> SOUND_EVENTS = RegistryManager.ACTIVE.getRegistry(Keys.SOUND_EVENTS);
|
||||
public static final IForgeRegistry<Potion> POTIONS = RegistryManager.ACTIVE.getRegistry(Keys.POTIONS);
|
||||
public static final IForgeRegistry<Enchantment> ENCHANTMENTS = RegistryManager.ACTIVE.getRegistry(Keys.ENCHANTMENTS);
|
||||
public static final IForgeRegistry<EntityType<?>> ENTITIES = RegistryManager.ACTIVE.getRegistry(Keys.ENTITY_TYPES);
|
||||
public static final IForgeRegistry<BlockEntityType<?>> BLOCK_ENTITIES = RegistryManager.ACTIVE.getRegistry(Keys.BLOCK_ENTITY_TYPES);
|
||||
public static final IForgeRegistry<ParticleType<?>> PARTICLE_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.PARTICLE_TYPES);
|
||||
public static final IForgeRegistry<MenuType<?>> CONTAINERS = RegistryManager.ACTIVE.getRegistry(Keys.CONTAINER_TYPES);
|
||||
public static final IForgeRegistry<Motive> PAINTING_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.PAINTING_TYPES);
|
||||
public static final IForgeRegistry<RecipeSerializer<?>> RECIPE_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(Keys.RECIPE_SERIALIZERS);
|
||||
public static final IForgeRegistry<Attribute> ATTRIBUTES = RegistryManager.ACTIVE.getRegistry(Keys.ATTRIBUTES);
|
||||
public static final IForgeRegistry<StatType<?>> STAT_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.STAT_TYPES);
|
||||
|
||||
// Villages
|
||||
public static final IForgeRegistry<VillagerProfession> PROFESSIONS = RegistryManager.ACTIVE.getRegistry(VillagerProfession.class);
|
||||
public static final IForgeRegistry<PoiType> POI_TYPES = RegistryManager.ACTIVE.getRegistry(PoiType.class);
|
||||
public static final IForgeRegistry<MemoryModuleType<?>> MEMORY_MODULE_TYPES = RegistryManager.ACTIVE.getRegistry(MemoryModuleType.class);
|
||||
public static final IForgeRegistry<SensorType<?>> SENSOR_TYPES = RegistryManager.ACTIVE.getRegistry(SensorType.class);
|
||||
public static final IForgeRegistry<Schedule> SCHEDULES = RegistryManager.ACTIVE.getRegistry(Schedule.class);
|
||||
public static final IForgeRegistry<Activity> ACTIVITIES = RegistryManager.ACTIVE.getRegistry(Activity.class);
|
||||
public static final IForgeRegistry<VillagerProfession> PROFESSIONS = RegistryManager.ACTIVE.getRegistry(Keys.VILLAGER_PROFESSIONS);
|
||||
public static final IForgeRegistry<PoiType> POI_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.POI_TYPES);
|
||||
public static final IForgeRegistry<MemoryModuleType<?>> MEMORY_MODULE_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.MEMORY_MODULE_TYPES);
|
||||
public static final IForgeRegistry<SensorType<?>> SENSOR_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.SENSOR_TYPES);
|
||||
public static final IForgeRegistry<Schedule> SCHEDULES = RegistryManager.ACTIVE.getRegistry(Keys.SCHEDULES);
|
||||
public static final IForgeRegistry<Activity> ACTIVITIES = RegistryManager.ACTIVE.getRegistry(Keys.ACTIVITIES);
|
||||
|
||||
// Worldgen
|
||||
public static final IForgeRegistry<WorldCarver<?>> WORLD_CARVERS = RegistryManager.ACTIVE.getRegistry(WorldCarver.class);
|
||||
public static final IForgeRegistry<Feature<?>> FEATURES = RegistryManager.ACTIVE.getRegistry(Feature.class);
|
||||
public static final IForgeRegistry<ChunkStatus> CHUNK_STATUS = RegistryManager.ACTIVE.getRegistry(ChunkStatus.class);
|
||||
public static final IForgeRegistry<StructureFeature<?>> STRUCTURE_FEATURES = RegistryManager.ACTIVE.getRegistry(StructureFeature.class);
|
||||
public static final IForgeRegistry<BlockStateProviderType<?>> BLOCK_STATE_PROVIDER_TYPES = RegistryManager.ACTIVE.getRegistry(BlockStateProviderType.class);
|
||||
public static final IForgeRegistry<FoliagePlacerType<?>> FOLIAGE_PLACER_TYPES = RegistryManager.ACTIVE.getRegistry(FoliagePlacerType.class);
|
||||
public static final IForgeRegistry<TreeDecoratorType<?>> TREE_DECORATOR_TYPES = RegistryManager.ACTIVE.getRegistry(TreeDecoratorType.class);
|
||||
public static final IForgeRegistry<WorldCarver<?>> WORLD_CARVERS = RegistryManager.ACTIVE.getRegistry(Keys.WORLD_CARVERS);
|
||||
public static final IForgeRegistry<Feature<?>> FEATURES = RegistryManager.ACTIVE.getRegistry(Keys.FEATURES);
|
||||
public static final IForgeRegistry<ChunkStatus> CHUNK_STATUS = RegistryManager.ACTIVE.getRegistry(Keys.CHUNK_STATUS);
|
||||
public static final IForgeRegistry<StructureFeature<?>> STRUCTURE_FEATURES = RegistryManager.ACTIVE.getRegistry(Keys.STRUCTURE_FEATURES);
|
||||
public static final IForgeRegistry<BlockStateProviderType<?>> BLOCK_STATE_PROVIDER_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.BLOCK_STATE_PROVIDER_TYPES);
|
||||
public static final IForgeRegistry<FoliagePlacerType<?>> FOLIAGE_PLACER_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.FOLIAGE_PLACER_TYPES);
|
||||
public static final IForgeRegistry<TreeDecoratorType<?>> TREE_DECORATOR_TYPES = RegistryManager.ACTIVE.getRegistry(Keys.TREE_DECORATOR_TYPES);
|
||||
|
||||
// Dynamic/Data driven.
|
||||
public static final IForgeRegistry<Biome> BIOMES = RegistryManager.ACTIVE.getRegistry(Keys.BIOMES);
|
||||
|
||||
// Custom forge registries
|
||||
public static final IForgeRegistry<DataSerializerEntry> DATA_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(DataSerializerEntry.class);
|
||||
public static final IForgeRegistry<GlobalLootModifierSerializer<?>> LOOT_MODIFIER_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(GlobalLootModifierSerializer.class);
|
||||
public static final IForgeRegistry<ForgeWorldPreset> WORLD_TYPES = RegistryManager.ACTIVE.getRegistry(ForgeWorldPreset.class);
|
||||
static final DeferredRegister<DataSerializerEntry> DEFERRED_DATA_SERIALIZERS = DeferredRegister.create(Keys.DATA_SERIALIZERS, Keys.DATA_SERIALIZERS.location().getNamespace());
|
||||
public static final Supplier<IForgeRegistry<DataSerializerEntry>> DATA_SERIALIZERS = DEFERRED_DATA_SERIALIZERS.makeRegistry(DataSerializerEntry.class, GameData::getDataSerializersRegistryBuilder);
|
||||
static final DeferredRegister<GlobalLootModifierSerializer<?>> DEFERRED_LOOT_MODIFIER_SERIALIZERS = DeferredRegister.create(Keys.LOOT_MODIFIER_SERIALIZERS, Keys.LOOT_MODIFIER_SERIALIZERS.location().getNamespace());
|
||||
public static final Supplier<IForgeRegistry<GlobalLootModifierSerializer<?>>> LOOT_MODIFIER_SERIALIZERS = DEFERRED_LOOT_MODIFIER_SERIALIZERS.makeRegistry(GameData.c(GlobalLootModifierSerializer.class), GameData::getGLMSerializersRegistryBuilder);
|
||||
static final DeferredRegister<ForgeWorldPreset> DEFERRED_WORLD_TYPES = DeferredRegister.create(Keys.WORLD_TYPES, Keys.WORLD_TYPES.location().getNamespace());
|
||||
public static final Supplier<IForgeRegistry<ForgeWorldPreset>> WORLD_TYPES = DEFERRED_WORLD_TYPES.makeRegistry(ForgeWorldPreset.class, GameData::getWorldTypesRegistryBuilder);
|
||||
|
||||
public static final class Keys {
|
||||
//Vanilla
|
||||
@@ -127,7 +132,7 @@ public class ForgeRegistries
|
||||
// Vanilla Dynamic
|
||||
public static final ResourceKey<Registry<Biome>> BIOMES = key("worldgen/biome");
|
||||
|
||||
//Forge
|
||||
// Forge
|
||||
public static final ResourceKey<Registry<DataSerializerEntry>> DATA_SERIALIZERS = key("data_serializers");
|
||||
public static final ResourceKey<Registry<GlobalLootModifierSerializer<?>>> LOOT_MODIFIER_SERIALIZERS = key("forge:loot_modifier_serializers");
|
||||
public static final ResourceKey<Registry<ForgeWorldPreset>> WORLD_TYPES = key("forge:world_types");
|
||||
|
||||
@@ -8,16 +8,17 @@ package net.minecraftforge.registries;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraftforge.common.util.LogMessageAdapter;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.registries.tags.ITagManager;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
@@ -44,6 +45,8 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRegistryInternal<V>, IForgeRegistryModifiable<V>
|
||||
{
|
||||
@@ -70,14 +73,14 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
||||
private final Set<Integer> blocked = Sets.newHashSet();
|
||||
private final Multimap<ResourceLocation, V> overrides = ArrayListMultimap.create();
|
||||
private final BiMap<OverrideOwner<V>, V> owners = HashBiMap.create();
|
||||
private final ForgeRegistryTagManager<V> tagManager;
|
||||
private final DummyFactory<V> dummyFactory;
|
||||
private final boolean isDelegated;
|
||||
private final int min;
|
||||
private final int max;
|
||||
private final boolean allowOverrides;
|
||||
private final boolean isModifiable;
|
||||
@Nullable
|
||||
private final String tagFolder;
|
||||
private final boolean hasWrapper;
|
||||
|
||||
private V defaultValue = null;
|
||||
boolean isFrozen = false;
|
||||
@@ -111,7 +114,8 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
||||
this.isDelegated = ForgeRegistryEntry.class.isAssignableFrom(superType); //TODO: Make this IDelegatedRegistryEntry?
|
||||
this.allowOverrides = builder.getAllowOverrides();
|
||||
this.isModifiable = builder.getAllowModifications();
|
||||
this.tagFolder = builder.getTagFolder();
|
||||
this.hasWrapper = builder.getHasWrapper();
|
||||
this.tagManager = this.hasWrapper ? new ForgeRegistryTagManager<>(this) : null;
|
||||
if (this.create != null)
|
||||
this.create.onCreate(this, stage);
|
||||
}
|
||||
@@ -156,6 +160,7 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceKey<Registry<V>> getRegistryKey()
|
||||
{
|
||||
return this.key;
|
||||
@@ -167,12 +172,7 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
||||
return superType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTagFolder()
|
||||
{
|
||||
return tagFolder;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Codec<V> getCodec()
|
||||
{
|
||||
return this.codec;
|
||||
@@ -234,6 +234,7 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
||||
return getResourceKey(value).map(ResourceKey::location).orElse(this.defaultKey);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<ResourceKey<V>> getResourceKey(V value)
|
||||
{
|
||||
@@ -241,19 +242,79 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
||||
return Optional.ofNullable(this.owners.inverse().get(value)).map(OverrideOwner::key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
Registry<V> getWrapper()
|
||||
{
|
||||
if (!this.hasWrapper)
|
||||
return null;
|
||||
|
||||
return this.defaultKey != null
|
||||
? this.getSlaveMap(NamespacedDefaultedWrapper.Factory.ID, NamespacedDefaultedWrapper.class)
|
||||
: this.getSlaveMap(NamespacedWrapper.Factory.ID, NamespacedWrapper.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
Optional<NamespacedHolderHelper<V>> getHolderHelper()
|
||||
{
|
||||
Registry<V> wrapper = getWrapper();
|
||||
if (!(wrapper instanceof IHolderHelperHolder))
|
||||
return Optional.empty();
|
||||
|
||||
// Unsafe cast means we can't use pattern matching here
|
||||
return Optional.of(((IHolderHelperHolder<V>) wrapper).getHolderHelper());
|
||||
}
|
||||
|
||||
void onBindTags(Map<TagKey<V>, HolderSet.Named<V>> tags, Set<TagKey<V>> defaultedTags)
|
||||
{
|
||||
if (this.tagManager != null)
|
||||
this.tagManager.bind(tags, defaultedTags);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<Holder<V>> getHolder(ResourceKey<V> key)
|
||||
{
|
||||
return getHolderHelper().flatMap(h -> h.getHolder(key));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<Holder<V>> getHolder(ResourceLocation location)
|
||||
{
|
||||
return getHolderHelper().flatMap(h -> h.getHolder(location));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<Holder<V>> getHolder(V value)
|
||||
{
|
||||
return getHolderHelper().flatMap(h -> h.getHolder(value));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ITagManager<V> tags()
|
||||
{
|
||||
return this.tagManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<ResourceLocation> getKeys()
|
||||
{
|
||||
return Collections.unmodifiableSet(this.names.keySet());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<V> getValues()
|
||||
{
|
||||
return Collections.unmodifiableSet(this.names.values());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<ResourceKey<V>, V>> getEntries()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraftforge.registries.tags.ITag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.Spliterator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class ForgeRegistryTag<V extends IForgeRegistryEntry<V>> implements ITag<V>
|
||||
{
|
||||
private final TagKey<V> key;
|
||||
@Nullable
|
||||
private HolderSet<V> holderSet;
|
||||
@Nullable
|
||||
private List<V> contents;
|
||||
|
||||
ForgeRegistryTag(TagKey<V> key)
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagKey<V> getKey()
|
||||
{
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<V> iterator()
|
||||
{
|
||||
return this.getContents().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<V> spliterator()
|
||||
{
|
||||
return this.getContents().spliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return this.getContents().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return this.getContents().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<V> stream()
|
||||
{
|
||||
return this.getContents().stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(V value)
|
||||
{
|
||||
return this.getContents().contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<V> getRandomElement(Random random)
|
||||
{
|
||||
return Util.getRandomSafe(this.getContents(), random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound()
|
||||
{
|
||||
return this.holderSet != null;
|
||||
}
|
||||
|
||||
List<V> getContents()
|
||||
{
|
||||
if (this.contents == null && this.holderSet != null)
|
||||
this.contents = this.holderSet.stream().map(Holder::value).toList();
|
||||
|
||||
return this.contents == null ? List.of() : this.contents;
|
||||
}
|
||||
|
||||
void bind(@Nullable HolderSet<V> holderSet)
|
||||
{
|
||||
this.holderSet = holderSet;
|
||||
this.contents = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Tag[" +
|
||||
"key=" + this.key + ", " +
|
||||
"contents=" + getContents() + ']';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraftforge.registries.tags.IReverseTag;
|
||||
import net.minecraftforge.registries.tags.ITag;
|
||||
import net.minecraftforge.registries.tags.ITagManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class ForgeRegistryTagManager<V extends IForgeRegistryEntry<V>> implements ITagManager<V>
|
||||
{
|
||||
private final ForgeRegistry<V> owner;
|
||||
private volatile Map<TagKey<V>, ITag<V>> tags = new IdentityHashMap<>();
|
||||
|
||||
ForgeRegistryTagManager(ForgeRegistry<V> owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
void bind(Map<TagKey<V>, HolderSet.Named<V>> holderTags, Set<TagKey<V>> defaultedTags)
|
||||
{
|
||||
IdentityHashMap<TagKey<V>, ITag<V>> newTags = new IdentityHashMap<>(this.tags);
|
||||
|
||||
// Forcefully unbind all pre-existing tags
|
||||
newTags.values().forEach(tag -> ((ForgeRegistryTag<V>) tag).bind(null));
|
||||
|
||||
// Bind all tags that were loaded
|
||||
holderTags.forEach((key, holderSet) ->
|
||||
((ForgeRegistryTag<V>) newTags.computeIfAbsent(key, ForgeRegistryTag::new)).bind(holderSet));
|
||||
|
||||
this.tags = newTags;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ITag<V> getTag(@NotNull TagKey<V> name)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
ITag<V> tag = this.tags.get(name);
|
||||
|
||||
if (tag == null)
|
||||
{
|
||||
// Create empty tag
|
||||
tag = new ForgeRegistryTag<>(name);
|
||||
|
||||
// Mojang uses volatile and sets the tag map this way to not have the performance penalties of synced read access.
|
||||
// However, this can generate a lot of new maps. We should look into performance alternatives.
|
||||
IdentityHashMap<TagKey<V>, ITag<V>> map = new IdentityHashMap<>(this.tags);
|
||||
map.put(name, tag);
|
||||
this.tags = map;
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<IReverseTag<V>> getReverseTag(@NotNull V value)
|
||||
{
|
||||
Objects.requireNonNull(value);
|
||||
// All Holders are implementors of IReverseTag
|
||||
return (Optional<IReverseTag<V>>) (Optional) this.owner.getHolder(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKnownTagName(@NotNull TagKey<V> name)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
ITag<V> tag = this.tags.get(name);
|
||||
return tag != null && tag.isBound();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<ITag<V>> iterator()
|
||||
{
|
||||
return Iterators.unmodifiableIterator(this.tags.values().iterator());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Stream<ITag<V>> stream()
|
||||
{
|
||||
return this.tags.values().stream();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Stream<TagKey<V>> getTagNames()
|
||||
{
|
||||
return this.tags.keySet().stream();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TagKey<V> createTagKey(@NotNull ResourceLocation location)
|
||||
{
|
||||
Objects.requireNonNull(location);
|
||||
return TagKey.create(this.owner.getRegistryKey(), location);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TagKey<V> createOptionalTagKey(@NotNull ResourceLocation location, @NotNull Set<? extends Supplier<V>> defaults)
|
||||
{
|
||||
TagKey<V> tagKey = createTagKey(location);
|
||||
|
||||
addOptionalTagDefaults(tagKey, defaults);
|
||||
|
||||
return tagKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOptionalTagDefaults(@NotNull TagKey<V> name, @NotNull Set<? extends Supplier<V>> defaults)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(defaults);
|
||||
|
||||
this.owner.getHolderHelper().ifPresent(h -> h.addOptionalTag(name, defaults));
|
||||
}
|
||||
}
|
||||
@@ -121,13 +121,13 @@ public class GameData
|
||||
makeRegistry(BLOCKS, Block.class, "air").addCallback(BlockCallbacks.INSTANCE).legacyName("blocks").vanillaHolder(Block::builtInRegistryHolder).create();
|
||||
makeRegistry(FLUIDS, Fluid.class, "empty").vanillaHolder(Fluid::builtInRegistryHolder).create();
|
||||
makeRegistry(ITEMS, Item.class, "air").addCallback(ItemCallbacks.INSTANCE).legacyName("items").vanillaHolder(Item::builtInRegistryHolder).create();
|
||||
makeRegistry(MOB_EFFECTS, MobEffect.class).legacyName("potions").tagFolder("mob_effects").create();
|
||||
makeRegistry(MOB_EFFECTS, MobEffect.class).legacyName("potions").create();
|
||||
//makeRegistry(BIOMES, Biome.class).legacyName("biomes").create();
|
||||
makeRegistry(SOUND_EVENTS, SoundEvent.class).legacyName("soundevents").create();
|
||||
makeRegistry(POTIONS, Potion.class, "empty").legacyName("potiontypes").tagFolder("potions").create();
|
||||
makeRegistry(ENCHANTMENTS, Enchantment.class).legacyName("enchantments").tagFolder("enchantments").create();
|
||||
makeRegistry(POTIONS, Potion.class, "empty").legacyName("potiontypes").create();
|
||||
makeRegistry(ENCHANTMENTS, Enchantment.class).legacyName("enchantments").create();
|
||||
makeRegistry(ENTITY_TYPES, c(EntityType.class), "pig").legacyName("entities").vanillaHolder(EntityType::builtInRegistryHolder).create();
|
||||
makeRegistry(BLOCK_ENTITY_TYPES, c(BlockEntityType.class)).disableSaving().legacyName("blockentities").tagFolder("block_entity_types").create();
|
||||
makeRegistry(BLOCK_ENTITY_TYPES, c(BlockEntityType.class)).disableSaving().legacyName("blockentities").create();
|
||||
makeRegistry(PARTICLE_TYPES, c(ParticleType.class)).disableSaving().create();
|
||||
makeRegistry(CONTAINER_TYPES, c(MenuType.class)).disableSaving().create();
|
||||
makeRegistry(PAINTING_TYPES, Motive.class, "kebab").create();
|
||||
@@ -147,25 +147,37 @@ public class GameData
|
||||
makeRegistry(WORLD_CARVERS, c(WorldCarver.class)).disableSaving().disableSync().create();
|
||||
makeRegistry(FEATURES, c(Feature.class)).addCallback(FeatureCallbacks.INSTANCE).disableSaving().disableSync().create();
|
||||
makeRegistry(CHUNK_STATUS, ChunkStatus.class, "empty").disableSaving().disableSync().create();
|
||||
makeRegistry(STRUCTURE_FEATURES, c(StructureFeature.class)).disableSaving().disableSync().tagFolder("structure_features").create();
|
||||
makeRegistry(STRUCTURE_FEATURES, c(StructureFeature.class)).disableSaving().disableSync().create();
|
||||
makeRegistry(BLOCK_STATE_PROVIDER_TYPES, c(BlockStateProviderType.class)).disableSaving().disableSync().create();
|
||||
makeRegistry(FOLIAGE_PLACER_TYPES, c(FoliagePlacerType.class)).disableSaving().disableSync().create();
|
||||
makeRegistry(TREE_DECORATOR_TYPES, c(TreeDecoratorType.class)).disableSaving().disableSync().create();
|
||||
|
||||
// Dynamic Worldgen
|
||||
makeRegistry(BIOMES, Biome.class).disableSync().create();
|
||||
|
||||
// Custom forge registries
|
||||
makeRegistry(DATA_SERIALIZERS, DataSerializerEntry.class, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides().addCallback(SerializerCallbacks.INSTANCE).create();
|
||||
makeRegistry(LOOT_MODIFIER_SERIALIZERS, c(GlobalLootModifierSerializer.class)).disableSaving().disableSync().create();
|
||||
makeRegistry(WORLD_TYPES, ForgeWorldPreset.class).disableSaving().disableSync().create();
|
||||
}
|
||||
|
||||
static RegistryBuilder<DataSerializerEntry> getDataSerializersRegistryBuilder()
|
||||
{
|
||||
return makeRegistry(DATA_SERIALIZERS, DataSerializerEntry.class, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides()
|
||||
.addCallback(SerializerCallbacks.INSTANCE);
|
||||
}
|
||||
|
||||
static RegistryBuilder<GlobalLootModifierSerializer<?>> getGLMSerializersRegistryBuilder()
|
||||
{
|
||||
return makeRegistry(LOOT_MODIFIER_SERIALIZERS, c(GlobalLootModifierSerializer.class)).disableSaving().disableSync();
|
||||
}
|
||||
|
||||
static RegistryBuilder<ForgeWorldPreset> getWorldTypesRegistryBuilder()
|
||||
{
|
||||
return makeRegistry(WORLD_TYPES, ForgeWorldPreset.class).disableSaving().disableSync();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") //Ugly hack to let us pass in a typed Class object. Remove when we remove type specific references.
|
||||
private static <T> Class<T> c(Class<?> cls) { return (Class<T>)cls; }
|
||||
static <T> Class<T> c(Class<?> cls) { return (Class<T>)cls; }
|
||||
|
||||
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key, Class<T> type)
|
||||
{
|
||||
return new RegistryBuilder<T>().setName(key.location()).setType(type).setMaxID(MAX_VARINT).addCallback(new NamespacedWrapper.Factory<T>());
|
||||
return new RegistryBuilder<T>().setName(key.location()).setType(type).setMaxID(MAX_VARINT).hasWrapper();
|
||||
}
|
||||
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key, Class<T> type, int min, int max)
|
||||
{
|
||||
@@ -199,31 +211,32 @@ public class GameData
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<Block,Item> getBlockItemMap()
|
||||
{
|
||||
return RegistryManager.ACTIVE.getRegistry(Item.class).getSlaveMap(BLOCK_TO_ITEM, Map.class);
|
||||
return RegistryManager.ACTIVE.getRegistry(ITEMS).getSlaveMap(BLOCK_TO_ITEM, Map.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static IdMapper<BlockState> getBlockStateIDMap()
|
||||
{
|
||||
return RegistryManager.ACTIVE.getRegistry(Block.class).getSlaveMap(BLOCKSTATE_TO_ID, IdMapper.class);
|
||||
return RegistryManager.ACTIVE.getRegistry(BLOCKS).getSlaveMap(BLOCKSTATE_TO_ID, IdMapper.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<BlockState, PoiType> getBlockStatePointOfInterestTypeMap()
|
||||
{
|
||||
return RegistryManager.ACTIVE.getRegistry(PoiType.class).getSlaveMap(BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE, Map.class);
|
||||
return RegistryManager.ACTIVE.getRegistry(POI_TYPES).getSlaveMap(BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE, Map.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<EntityDataSerializer<?>, DataSerializerEntry> getSerializerMap()
|
||||
{
|
||||
return RegistryManager.ACTIVE.getRegistry(DataSerializerEntry.class).getSlaveMap(SERIALIZER_TO_ENTRY, Map.class);
|
||||
ForgeRegistry<DataSerializerEntry> registry = RegistryManager.ACTIVE.getRegistry(DATA_SERIALIZERS);
|
||||
return registry == null ? null : registry.getSlaveMap(SERIALIZER_TO_ENTRY, Map.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static BiMap<String, StructureFeature<?>> getStructureMap()
|
||||
{
|
||||
return (BiMap<String, StructureFeature<?>>) RegistryManager.ACTIVE.getRegistry(Feature.class).getSlaveMap(STRUCTURES, BiMap.class);
|
||||
return (BiMap<String, StructureFeature<?>>) RegistryManager.ACTIVE.getRegistry(FEATURES).getSlaveMap(STRUCTURES, BiMap.class);
|
||||
}
|
||||
|
||||
public static <K extends IForgeRegistryEntry<K>> K register_impl(K value)
|
||||
|
||||
@@ -5,16 +5,19 @@
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.registries.tags.ITagManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Main interface for the registry system. Use this to query the registry system.
|
||||
@@ -23,6 +26,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||
*/
|
||||
public interface IForgeRegistry<V extends IForgeRegistryEntry<V>> extends Iterable<V>
|
||||
{
|
||||
ResourceKey<Registry<V>> getRegistryKey();
|
||||
ResourceLocation getRegistryName();
|
||||
Class<V> getRegistrySuperType();
|
||||
|
||||
@@ -38,13 +42,39 @@ public interface IForgeRegistry<V extends IForgeRegistryEntry<V>> extends Iterab
|
||||
@Nullable V getValue(ResourceLocation key);
|
||||
@Nullable ResourceLocation getKey(V value);
|
||||
@Nullable ResourceLocation getDefaultKey();
|
||||
@Nullable Optional<ResourceKey<V>> getResourceKey(V value);
|
||||
@NotNull Optional<ResourceKey<V>> getResourceKey(V value);
|
||||
|
||||
@Nonnull Set<ResourceLocation> getKeys();
|
||||
@Nonnull Collection<V> getValues();
|
||||
@Nonnull Set<Entry<ResourceKey<V>, V>> getEntries();
|
||||
@NotNull Set<ResourceLocation> getKeys();
|
||||
@NotNull Collection<V> getValues();
|
||||
@NotNull Set<Entry<ResourceKey<V>, V>> getEntries();
|
||||
|
||||
@Nonnull Codec<V> getCodec();
|
||||
/**
|
||||
* @see Registry#byNameCodec()
|
||||
*/
|
||||
@NotNull Codec<V> getCodec();
|
||||
|
||||
/**
|
||||
* This method exists purely as a stopgap for vanilla compatibility.
|
||||
* For anything tag related, use {@link #tags()}.
|
||||
*
|
||||
* @see Registry#getHolder(ResourceKey)
|
||||
*/
|
||||
@NotNull Optional<Holder<V>> getHolder(ResourceKey<V> key);
|
||||
/**
|
||||
* This method exists purely as a stopgap for vanilla compatibility.
|
||||
* For anything tag related, use {@link #tags()}.
|
||||
*/
|
||||
@NotNull Optional<Holder<V>> getHolder(ResourceLocation location);
|
||||
/**
|
||||
* This method exists purely as a stopgap for vanilla compatibility.
|
||||
* For anything tag related, use {@link #tags()}.
|
||||
*/
|
||||
@NotNull Optional<Holder<V>> getHolder(V value);
|
||||
|
||||
/**
|
||||
* @return an instance of {@link ITagManager} if this registry supports tags and/or has a wrapper registry, null otherwise
|
||||
*/
|
||||
@Nullable ITagManager<V> tags();
|
||||
|
||||
/**
|
||||
* Retrieve the slave map of type T from the registry.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
interface IHolderHelperHolder<T extends IForgeRegistryEntry<T>>
|
||||
{
|
||||
NamespacedHolderHelper<T> getHolderHelper();
|
||||
}
|
||||
@@ -30,7 +30,7 @@ import net.minecraft.core.DefaultedRegistry;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
|
||||
class NamespacedDefaultedWrapper<T extends IForgeRegistryEntry<T>> extends DefaultedRegistry<T> implements ILockableRegistry
|
||||
class NamespacedDefaultedWrapper<T extends IForgeRegistryEntry<T>> extends DefaultedRegistry<T> implements ILockableRegistry, IHolderHelperHolder<T>
|
||||
{
|
||||
private final ForgeRegistry<T> delegate;
|
||||
private final NamespacedHolderHelper<T> holders;
|
||||
@@ -42,7 +42,7 @@ class NamespacedDefaultedWrapper<T extends IForgeRegistryEntry<T>> extends Defau
|
||||
{
|
||||
super("empty", owner.getRegistryKey(), Lifecycle.experimental(), holderLookup);
|
||||
this.delegate = owner;
|
||||
this.holders = new NamespacedHolderHelper<>(this, this.delegate.getDefaultKey(), holderLookup);
|
||||
this.holders = new NamespacedHolderHelper<>(owner, this, this.delegate.getDefaultKey(), holderLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -186,6 +186,12 @@ class NamespacedDefaultedWrapper<T extends IForgeRegistryEntry<T>> extends Defau
|
||||
return this.delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespacedHolderHelper<T> getHolderHelper()
|
||||
{
|
||||
return this.holders;
|
||||
}
|
||||
|
||||
@Override public Optional<Holder<T>> getHolder(int id) { return this.holders.getHolder(id); }
|
||||
@Override public Optional<Holder<T>> getHolder(ResourceKey<T> key) { return this.holders.getHolder(key); }
|
||||
@Override public Holder<T> getOrCreateHolder(ResourceKey<T> key) { return this.holders.getOrCreateHolder(key); }
|
||||
@@ -202,7 +208,7 @@ class NamespacedDefaultedWrapper<T extends IForgeRegistryEntry<T>> extends Defau
|
||||
@Override public void resetTags() { this.holders.resetTags(); }
|
||||
@Deprecated @Override public void unfreeze() { this.holders.unfreeze(); }
|
||||
|
||||
/** @Depreciated Forge: For internal use only. Use the Register events when registering values. */
|
||||
/** @deprecated Forge: For internal use only. Use the Register events when registering values. */
|
||||
@Deprecated @Override public void lock(){ this.locked = true; }
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package net.minecraftforge.registries;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -15,11 +16,14 @@ import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -34,15 +38,18 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class NamespacedHolderHelper<T extends IForgeRegistryEntry<T>>
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ForgeRegistry<T> owner;
|
||||
private final Registry<T> self;
|
||||
@Nullable
|
||||
private final ResourceLocation defaultKey;
|
||||
@Nullable
|
||||
private final Function<T, Holder.Reference<T>> holderLookup;
|
||||
private final Multimap<TagKey<T>, Supplier<T>> optionalTags = Multimaps.newSetMultimap(new IdentityHashMap<>(), HashSet::new);
|
||||
|
||||
private boolean frozen = false; // Frozen is vanilla's variant of locked, but it can be unfrozen
|
||||
private List<Holder.Reference<T>> holdersSorted;
|
||||
@@ -52,8 +59,9 @@ class NamespacedHolderHelper<T extends IForgeRegistryEntry<T>>
|
||||
private volatile Map<TagKey<T>, HolderSet.Named<T>> tags = new IdentityHashMap<>();
|
||||
private Holder.Reference<T> defaultHolder;
|
||||
|
||||
NamespacedHolderHelper(Registry<T> self, @Nullable ResourceLocation defaultKey, @Nullable Function<T, Holder.Reference<T>> holderLookup)
|
||||
NamespacedHolderHelper(ForgeRegistry<T> owner, Registry<T> self, @Nullable ResourceLocation defaultKey, @Nullable Function<T, Holder.Reference<T>> holderLookup)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.self = self;
|
||||
this.defaultKey = defaultKey;
|
||||
this.holderLookup = holderLookup;
|
||||
@@ -70,6 +78,16 @@ class NamespacedHolderHelper<T extends IForgeRegistryEntry<T>>
|
||||
return Optional.ofNullable(this.holdersByName.get(key.location()));
|
||||
}
|
||||
|
||||
Optional<Holder<T>> getHolder(ResourceLocation location)
|
||||
{
|
||||
return Optional.ofNullable(this.holdersByName.get(location));
|
||||
}
|
||||
|
||||
Optional<Holder<T>> getHolder(T value)
|
||||
{
|
||||
return Optional.ofNullable(this.holders.get(value));
|
||||
}
|
||||
|
||||
Holder<T> getOrCreateHolder(ResourceKey<T> key)
|
||||
{
|
||||
return this.holdersByName.computeIfAbsent(key.location(), k ->
|
||||
@@ -120,6 +138,11 @@ class NamespacedHolderHelper<T extends IForgeRegistryEntry<T>>
|
||||
return named;
|
||||
}
|
||||
|
||||
void addOptionalTag(TagKey<T> name, @NotNull Set<? extends Supplier<T>> defaults)
|
||||
{
|
||||
this.optionalTags.putAll(name, defaults);
|
||||
}
|
||||
|
||||
Stream<TagKey<T>> getTagNames()
|
||||
{
|
||||
return this.tags.keySet().stream();
|
||||
@@ -165,18 +188,7 @@ class NamespacedHolderHelper<T extends IForgeRegistryEntry<T>>
|
||||
{
|
||||
Map<Holder.Reference<T>, List<TagKey<T>>> holderToTag = new IdentityHashMap<>();
|
||||
this.holdersByName.values().forEach(v -> holderToTag.put(v, new ArrayList<>()));
|
||||
newTags.forEach((k, v) ->
|
||||
{
|
||||
for(Holder<T> holder : v)
|
||||
{
|
||||
if (!holder.isValidInRegistry(this.self))
|
||||
throw new IllegalStateException("Can't create named set " + k + " containing value " + holder + " from outside registry " + this);
|
||||
|
||||
if (!(holder instanceof Holder.Reference<T>))
|
||||
throw new IllegalStateException("Found direct holder " + holder + " value in tag " + k);
|
||||
holderToTag.get((Holder.Reference<T>)holder).add(k);
|
||||
}
|
||||
});
|
||||
newTags.forEach((name, values) -> values.forEach(holder -> addTagToHolder(holderToTag, name, holder)));
|
||||
|
||||
Set<TagKey<T>> set = Sets.difference(this.tags.keySet(), newTags.keySet());
|
||||
if (!set.isEmpty())
|
||||
@@ -184,8 +196,33 @@ class NamespacedHolderHelper<T extends IForgeRegistryEntry<T>>
|
||||
|
||||
Map<TagKey<T>, HolderSet.Named<T>> tmpTags = new IdentityHashMap<>(this.tags);
|
||||
newTags.forEach((k, v) -> tmpTags.computeIfAbsent(k, this::createTag).bind(v));
|
||||
|
||||
Set<TagKey<T>> defaultedTags = Sets.difference(this.optionalTags.keySet(), newTags.keySet());
|
||||
defaultedTags.forEach(name -> {
|
||||
List<Holder<T>> defaults = this.optionalTags.get(name).stream()
|
||||
.map(valueSupplier -> getHolder(valueSupplier.get()).orElse(null))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
defaults.forEach(holder -> addTagToHolder(holderToTag, name, holder));
|
||||
tmpTags.computeIfAbsent(name, this::createTag).bind(defaults);
|
||||
});
|
||||
|
||||
holderToTag.forEach(Holder.Reference::bindTags);
|
||||
this.tags = tmpTags;
|
||||
|
||||
this.owner.onBindTags(this.tags, defaultedTags);
|
||||
}
|
||||
|
||||
private void addTagToHolder(Map<Holder.Reference<T>, List<TagKey<T>>> holderToTag, TagKey<T> name, Holder<T> holder)
|
||||
{
|
||||
if (!holder.isValidInRegistry(this.self))
|
||||
throw new IllegalStateException("Can't create named set " + name + " containing value " + holder + " from outside registry " + this);
|
||||
|
||||
if (!(holder instanceof Holder.Reference<T>))
|
||||
throw new IllegalStateException("Found direct holder " + holder + " value in tag " + name);
|
||||
|
||||
holderToTag.get((Holder.Reference<T>) holder).add(name);
|
||||
}
|
||||
|
||||
void resetTags()
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
|
||||
class NamespacedWrapper<T extends IForgeRegistryEntry<T>> extends MappedRegistry<T> implements ILockableRegistry
|
||||
class NamespacedWrapper<T extends IForgeRegistryEntry<T>> extends MappedRegistry<T> implements ILockableRegistry, IHolderHelperHolder<T>
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ForgeRegistry<T> delegate;
|
||||
@@ -45,7 +45,7 @@ class NamespacedWrapper<T extends IForgeRegistryEntry<T>> extends MappedRegistry
|
||||
{
|
||||
super(owner.getRegistryKey(), Lifecycle.experimental(), holderLookup);
|
||||
this.delegate = owner;
|
||||
this.holders = new NamespacedHolderHelper<>(this, null, holderLookup);
|
||||
this.holders = new NamespacedHolderHelper<>(owner, this, null, holderLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,6 +184,12 @@ class NamespacedWrapper<T extends IForgeRegistryEntry<T>> extends MappedRegistry
|
||||
return this.delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespacedHolderHelper<T> getHolderHelper()
|
||||
{
|
||||
return this.holders;
|
||||
}
|
||||
|
||||
@Override public Optional<Holder<T>> getHolder(int id) { return this.holders.getHolder(id); }
|
||||
@Override public Optional<Holder<T>> getHolder(ResourceKey<T> key) { return this.holders.getHolder(key); }
|
||||
@Override public Holder<T> getOrCreateHolder(ResourceKey<T> key) { return this.holders.getOrCreateHolder(key); }
|
||||
@@ -200,7 +206,7 @@ class NamespacedWrapper<T extends IForgeRegistryEntry<T>> extends MappedRegistry
|
||||
@Override public void resetTags() { this.holders.resetTags(); }
|
||||
@Deprecated @Override public void unfreeze() { this.holders.unfreeze(); }
|
||||
|
||||
/** @Depreciated Forge: For internal use only. Use the Register events when registering values. */
|
||||
/** @deprecated Forge: For internal use only. Use the Register events when registering values. */
|
||||
@Deprecated @Override public void lock(){ this.locked = true; }
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Register new registries when you receive this event through {@link RegistryBuilder} and {@link #create(RegistryBuilder)}.
|
||||
*/
|
||||
public class NewRegistryEvent extends Event implements IModBusEvent
|
||||
{
|
||||
private final List<RegistryData<?>> registries = new ArrayList<>();
|
||||
|
||||
public NewRegistryEvent() {}
|
||||
|
||||
/**
|
||||
* Adds a registry builder to be created.
|
||||
*
|
||||
* @param builder The builder to turn into a {@link IForgeRegistry}
|
||||
* @return A supplier of the {@link IForgeRegistry} created by the builder. Resolving too early will return null.
|
||||
*/
|
||||
public <V extends IForgeRegistryEntry<V>> Supplier<IForgeRegistry<V>> create(RegistryBuilder<V> builder)
|
||||
{
|
||||
return create(builder, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a registry builder to be created.
|
||||
*
|
||||
* @param builder The builder to turn into a {@link IForgeRegistry}
|
||||
* @param onFill Called when the returned supplier is filled with the registry
|
||||
* @return a supplier of the {@link IForgeRegistry} created by the builder. Resolving too early will return null.
|
||||
*/
|
||||
public <V extends IForgeRegistryEntry<V>> Supplier<IForgeRegistry<V>> create(RegistryBuilder<V> builder, @Nullable Consumer<IForgeRegistry<V>> onFill)
|
||||
{
|
||||
RegistryHolder<V> registryHolder = new RegistryHolder<>();
|
||||
|
||||
registries.add(new RegistryData<>(builder, registryHolder, onFill));
|
||||
|
||||
return registryHolder;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
void fill()
|
||||
{
|
||||
Map<RegistryBuilder<?>, IForgeRegistry<?>> builtRegistries = this.registries
|
||||
.stream()
|
||||
.collect(Collectors.toMap(RegistryData::builder, d -> d.builder().create(), (a, b) -> a, IdentityHashMap::new));
|
||||
|
||||
builtRegistries.forEach((builder, reg) -> {
|
||||
if (builder.getHasWrapper() && !Registry.REGISTRY.containsKey(reg.getRegistryName()))
|
||||
RegistryManager.registerToRootRegistry((ForgeRegistry<?>) reg);
|
||||
});
|
||||
|
||||
for (RegistryData data : this.registries)
|
||||
{
|
||||
IForgeRegistry<?> registry = builtRegistries.get(data.builder);
|
||||
if (registry != null)
|
||||
{
|
||||
data.registryHolder.registry = registry;
|
||||
if (data.onFill != null)
|
||||
data.onFill.accept(registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record RegistryData<V extends IForgeRegistryEntry<V>>(
|
||||
RegistryBuilder<V> builder,
|
||||
RegistryHolder<V> registryHolder,
|
||||
Consumer<IForgeRegistry<V>> onFill
|
||||
) {}
|
||||
|
||||
private static class RegistryHolder<V extends IForgeRegistryEntry<V>> implements Supplier<IForgeRegistry<V>>
|
||||
{
|
||||
IForgeRegistry<V> registry = null;
|
||||
|
||||
@Override
|
||||
public IForgeRegistry<V> get()
|
||||
{
|
||||
return this.registry;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "RegistryEvent.NewRegistry";
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,6 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
|
||||
private boolean allowOverrides = true;
|
||||
private boolean allowModifications = false;
|
||||
private boolean hasWrapper = false;
|
||||
@Nullable
|
||||
private String tagFolder;
|
||||
private DummyFactory<T> dummyFactory;
|
||||
private MissingFactory<T> missingFactory;
|
||||
private Set<ResourceLocation> legacyNames = new HashSet<>();
|
||||
@@ -201,15 +199,6 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
|
||||
return this;
|
||||
}
|
||||
|
||||
public RegistryBuilder<T> tagFolder(String tagFolder)
|
||||
{
|
||||
if (tagFolder == null || !tagFolder.matches("[a-z_/]+")) throw new IllegalArgumentException("Non [a-z_/] character in tag folder " + tagFolder);
|
||||
this.tagFolder = tagFolder;
|
||||
//Also mark this registry as having a wrapper to a vanilla registry so that it can be used in data generators properly
|
||||
hasWrapper();
|
||||
return this;
|
||||
}
|
||||
|
||||
public RegistryBuilder<T> legacyName(String name)
|
||||
{
|
||||
return legacyName(new ResourceLocation(name));
|
||||
@@ -227,7 +216,24 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
|
||||
return this;
|
||||
}
|
||||
|
||||
public IForgeRegistry<T> create()
|
||||
/**
|
||||
* Enables tags for this registry if not already.
|
||||
* All forge registries with wrappers inherently support tags.
|
||||
*
|
||||
* @return this builder
|
||||
* @see RegistryBuilder#hasWrapper()
|
||||
*/
|
||||
public RegistryBuilder<T> hasTags()
|
||||
{
|
||||
// Tag system heavily relies on Registry<?> objects, so we need a wrapper for this registry to take advantage
|
||||
this.hasWrapper();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modders: Use {@link NewRegistryEvent#create(RegistryBuilder)} instead
|
||||
*/
|
||||
IForgeRegistry<T> create()
|
||||
{
|
||||
if (hasWrapper)
|
||||
{
|
||||
@@ -345,12 +351,6 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
|
||||
return allowModifications;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTagFolder()
|
||||
{
|
||||
return tagFolder;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DummyFactory<T> getDummyFactory()
|
||||
{
|
||||
|
||||
@@ -7,9 +7,13 @@ package net.minecraftforge.registries;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
@@ -18,9 +22,13 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Sets.SetView;
|
||||
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.core.WritableRegistry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraftforge.fml.IModStateTransition;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.network.HandshakeMessages;
|
||||
import net.minecraftforge.registries.ForgeRegistry.Snapshot;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -33,6 +41,7 @@ public class RegistryManager
|
||||
public static final RegistryManager ACTIVE = new RegistryManager("ACTIVE");
|
||||
public static final RegistryManager VANILLA = new RegistryManager("VANILLA");
|
||||
public static final RegistryManager FROZEN = new RegistryManager("FROZEN");
|
||||
private static Set<ResourceLocation> vanillaRegistryKeys = Set.of();
|
||||
|
||||
BiMap<ResourceLocation, ForgeRegistry<? extends IForgeRegistryEntry<?>>> registries = HashBiMap.create();
|
||||
private BiMap<Class<? extends IForgeRegistryEntry<?>>, ResourceLocation> superTypes = HashBiMap.create();
|
||||
@@ -68,6 +77,12 @@ public class RegistryManager
|
||||
return getRegistry(key.location());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getRegistry(ResourceLocation)
|
||||
* @see #getRegistry(ResourceKey)
|
||||
* @deprecated The uniqueness of registry super types will not be guaranteed starting in 1.19.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
public <V extends IForgeRegistryEntry<V>> IForgeRegistry<V> getRegistry(Class<? super V> cls)
|
||||
{
|
||||
return getRegistry(superTypes.get(cls));
|
||||
@@ -124,6 +139,9 @@ public class RegistryManager
|
||||
foundType, superTypes.get(foundType), name, builder.getType(), builder.getType());
|
||||
throw new IllegalArgumentException("Duplicate registry parent type found - you can only have one registry for a particular super type");
|
||||
}
|
||||
if (registries.containsKey(name))
|
||||
throw new IllegalArgumentException("Attempted to register a registry for " + name + " with type "
|
||||
+ builder.getType().getName() + " but it already exists as " + registries.get(name).getRegistrySuperType().getName());
|
||||
ForgeRegistry<V> reg = new ForgeRegistry<V>(this, name, builder);
|
||||
registries.put(name, reg);
|
||||
superTypes.put(builder.getType(), name);
|
||||
@@ -136,6 +154,36 @@ public class RegistryManager
|
||||
return getRegistry(name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <V extends IForgeRegistryEntry<V>> void registerToRootRegistry(ForgeRegistry<V> forgeReg)
|
||||
{
|
||||
WritableRegistry<Registry<V>> registry = (WritableRegistry<Registry<V>>) Registry.REGISTRY;
|
||||
Registry<V> wrapper = forgeReg.getWrapper();
|
||||
if (wrapper != null)
|
||||
registry.register(forgeReg.getRegistryKey(), wrapper, Lifecycle.experimental());
|
||||
}
|
||||
|
||||
public static IModStateTransition.EventGenerator<NewRegistryEvent> newRegistryEventGenerator()
|
||||
{
|
||||
NewRegistryEvent event = new NewRegistryEvent();
|
||||
return mc -> event;
|
||||
}
|
||||
|
||||
|
||||
public static CompletableFuture<List<Throwable>> preNewRegistryEvent(final Executor executor,
|
||||
final IModStateTransition.EventGenerator<? extends NewRegistryEvent> eventGenerator)
|
||||
{
|
||||
return CompletableFuture.runAsync(() -> vanillaRegistryKeys = Set.copyOf(Registry.REGISTRY.keySet()), executor)
|
||||
.handle((v, t) -> t != null ? Collections.singletonList(t) : Collections.emptyList());
|
||||
}
|
||||
|
||||
public static CompletableFuture<List<Throwable>> postNewRegistryEvent(final Executor executor,
|
||||
final IModStateTransition.EventGenerator<? extends NewRegistryEvent> eventGenerator)
|
||||
{
|
||||
return CompletableFuture.runAsync(() -> eventGenerator.apply(null).fill(), executor)
|
||||
.handle((v, t) -> t != null ? Collections.singletonList(t) : Collections.emptyList());
|
||||
}
|
||||
|
||||
private void addLegacyName(ResourceLocation legacyName, ResourceLocation name)
|
||||
{
|
||||
if (this.legacyNames.containsKey(legacyName))
|
||||
@@ -189,4 +237,9 @@ public class RegistryManager
|
||||
filter(resloc -> ACTIVE.synced.contains(resloc)).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Set<ResourceLocation> getVanillaRegistryKeys()
|
||||
{
|
||||
return vanillaRegistryKeys;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -24,6 +26,10 @@ public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> impl
|
||||
@Nullable
|
||||
private T value;
|
||||
|
||||
/**
|
||||
* @deprecated The uniqueness of registry super types will not be guaranteed starting in 1.19. Use {@link #of(ResourceLocation, ResourceLocation, String)}.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final ResourceLocation name, Supplier<Class<? super T>> registryType) {
|
||||
return new RegistryObject<>(name, registryType);
|
||||
}
|
||||
@@ -32,10 +38,38 @@ public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> impl
|
||||
return new RegistryObject<>(name, registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated The uniqueness of registry super types will not be guaranteed starting in 1.19. Use {@link #of(ResourceLocation, ResourceLocation, String)}.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final ResourceLocation name, final Class<T> baseType, String modid) {
|
||||
return new RegistryObject<>(name, baseType, modid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for a {@link RegistryObject} that stores the value of an object in a registry once it is ready.
|
||||
*
|
||||
* @param name The name of the object to look up in a forge registry
|
||||
* @param key The key of the forge registry to grab from {@link RegistryManager#ACTIVE}
|
||||
* @param modid The mod id calling context
|
||||
* @return A {@link RegistryObject} that stores the value of an object in a registry once it is ready
|
||||
*/
|
||||
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final ResourceLocation name, final ResourceKey<? extends Registry<T>> key, String modid) {
|
||||
return new RegistryObject<>(name, key.location(), modid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for a {@link RegistryObject} that stores the value of an object in a registry once it is ready.
|
||||
*
|
||||
* @param name The name of the object to look up in a forge registry
|
||||
* @param registryName The name of the forge registry to grab from {@link RegistryManager#ACTIVE}
|
||||
* @param modid The mod id calling context
|
||||
* @return A {@link RegistryObject} that stores the value of an object in a registry once it is ready
|
||||
*/
|
||||
public static <T extends IForgeRegistryEntry<T>, U extends T> RegistryObject<U> of(final ResourceLocation name, final ResourceLocation registryName, String modid) {
|
||||
return new RegistryObject<>(name, registryName, modid);
|
||||
}
|
||||
|
||||
private static RegistryObject<?> EMPTY = new RegistryObject<>();
|
||||
|
||||
private static <T extends IForgeRegistryEntry<? super T>> RegistryObject<T> empty() {
|
||||
@@ -48,6 +82,7 @@ public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> impl
|
||||
this.name = null;
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
private <V extends IForgeRegistryEntry<V>> RegistryObject(ResourceLocation name, Supplier<Class<? super V>> registryType)
|
||||
{
|
||||
this(name, RegistryManager.ACTIVE.<V>getRegistry(registryType.get()));
|
||||
@@ -68,6 +103,7 @@ public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> impl
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
private <V extends IForgeRegistryEntry<V>> RegistryObject(final ResourceLocation name, final Class<V> baseType, final String modid)
|
||||
{
|
||||
this.name = name;
|
||||
@@ -83,7 +119,7 @@ public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> impl
|
||||
{
|
||||
this.registry = RegistryManager.ACTIVE.getRegistry(baseType);
|
||||
if (registry == null)
|
||||
throw new IllegalStateException("Unable to find registry for type " + baseType.getName() + " for mod \"" + modid + "\". Check the 'caused by' to see futher stack.", callerStack);
|
||||
throw new IllegalStateException("Unable to find registry for type " + baseType.getName() + " for mod \"" + modid + "\". Check the 'caused by' to see further stack.", callerStack);
|
||||
}
|
||||
if (pred.test(registry.getRegistryName()))
|
||||
RegistryObject.this.updateReference((IForgeRegistry<? extends T>) registry);
|
||||
@@ -97,6 +133,36 @@ public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> impl
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V extends IForgeRegistryEntry<V>> RegistryObject(final ResourceLocation name, final ResourceLocation registryName, final String modid)
|
||||
{
|
||||
this.name = name;
|
||||
final Throwable callerStack = new Throwable("Calling Site from mod: " + modid);
|
||||
ObjectHolderRegistry.addHandler(new Consumer<>()
|
||||
{
|
||||
private IForgeRegistry<V> registry;
|
||||
|
||||
@Override
|
||||
public void accept(Predicate<ResourceLocation> pred)
|
||||
{
|
||||
if (registry == null)
|
||||
{
|
||||
this.registry = RegistryManager.ACTIVE.getRegistry(registryName);
|
||||
if (registry == null)
|
||||
throw new IllegalStateException("Unable to find registry with key " + registryName + " for mod \"" + modid + "\". Check the 'caused by' to see further stack.", callerStack);
|
||||
}
|
||||
if (pred.test(registry.getRegistryName()))
|
||||
RegistryObject.this.updateReference((IForgeRegistry<? extends T>) registry);
|
||||
}
|
||||
});
|
||||
IForgeRegistry<V> registry = RegistryManager.ACTIVE.getRegistry(registryName);
|
||||
// allow registry to be null, this might be for a custom registry that does not exist yet
|
||||
if (registry != null)
|
||||
{
|
||||
this.updateReference(((IForgeRegistry<? extends T>) registry));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly retrieves the wrapped Registry Object. This value will automatically be updated when the backing registry is updated.
|
||||
* Will throw NPE if the value is null, use isPresent to check first. Or use any of the other guarded functions.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries.tags;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.tags.TagKey;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A reverse tag is an object aware of what tags it is contained in.
|
||||
* {@link Holder}s implement this interface.
|
||||
* A reverse tag makes no guarantees about its persistence relative to a registry value.
|
||||
* Modders should look up a reverse tag every time they need it from a {@link ITagManager} rather than storing it somewhere.
|
||||
*/
|
||||
public interface IReverseTag<V>
|
||||
{
|
||||
Stream<TagKey<V>> getTagKeys();
|
||||
|
||||
boolean containsTag(TagKey<V> key);
|
||||
|
||||
default boolean containsTag(ITag<V> tag)
|
||||
{
|
||||
return containsTag(tag.getKey());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries.tags;
|
||||
|
||||
import net.minecraft.tags.TagKey;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A tag is a collection of elements with an identifying {@link TagKey tag key}.
|
||||
* For Forge, these are bound on world load.
|
||||
* Tags will always be empty until they are bound.
|
||||
* A tag instance provided for a given {@link TagKey} from a given {@link ITagManager} will always return the same instance on future invocations.
|
||||
* This means that the same tag instance will be rebound across reloads assuming the same registry instance is in use.
|
||||
* It is safe to store instances of this class for long periods of time.
|
||||
*/
|
||||
public interface ITag<V> extends Iterable<V>
|
||||
{
|
||||
TagKey<V> getKey();
|
||||
|
||||
Stream<V> stream();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
int size();
|
||||
|
||||
boolean contains(V value);
|
||||
|
||||
Optional<V> getRandomElement(Random random);
|
||||
|
||||
/**
|
||||
* @return {@code true} if this tag was loaded with a value (including empty),
|
||||
* otherwise the tag is always empty and this returns {@code false}
|
||||
*/
|
||||
boolean isBound();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.registries.tags;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
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<V extends IForgeRegistryEntry<V>> extends Iterable<ITag<V>>
|
||||
{
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @apiNote This method guarantees that all future calls to this method on the same tag manager instance with the same tag key will return the same tag.
|
||||
* @see #isKnownTagName(TagKey)
|
||||
*/
|
||||
@NotNull ITag<V> getTag(@NotNull TagKey<V> name);
|
||||
|
||||
/**
|
||||
* Queries a reverse tag for a given value from the forge registry linked to this tag manager.
|
||||
* A reverse tag stores all tags that the given {@code value} is contained in.
|
||||
*
|
||||
* @param value A value currently registered to the forge registry linked to this tag manager
|
||||
* @return A reverse tag for the given value, or an empty optional if the value is not registered
|
||||
*/
|
||||
@NotNull Optional<IReverseTag<V>> getReverseTag(@NotNull V value);
|
||||
|
||||
/**
|
||||
* Checks whether the given tag key exists in this tag manager and is bound.
|
||||
* Unlike {@link #getTag(TagKey)}, this method will <b>not</b> create the tag if it does not exist.
|
||||
*
|
||||
* @see ITag#isBound()
|
||||
*/
|
||||
boolean isKnownTagName(@NotNull TagKey<V> name);
|
||||
|
||||
/**
|
||||
* @return A stream of all tags stored in this tag manager, bound or unbound.
|
||||
*/
|
||||
@NotNull Stream<ITag<V>> stream();
|
||||
|
||||
/**
|
||||
* @return A stream of all tag keys stored in this tag manager, bound or unbound.
|
||||
*/
|
||||
@NotNull Stream<TagKey<V>> getTagNames();
|
||||
|
||||
/**
|
||||
* Creates a tag key based on the location and the forge registry linked to this tag manager.
|
||||
* Custom registries can use {@link DeferredRegister#createTagKey(ResourceLocation)} to create tag keys before the tag manager is created.
|
||||
*
|
||||
* @see #createOptionalTagKey(ResourceLocation, Set)
|
||||
* @see DeferredRegister#createTagKey(ResourceLocation)
|
||||
*/
|
||||
@NotNull TagKey<V> createTagKey(@NotNull ResourceLocation location);
|
||||
|
||||
/**
|
||||
* Creates a tag key that will use the set of defaults if the tag is not loaded from any datapacks.
|
||||
* Useful on the client side when a server may not provide a specific tag.
|
||||
* Custom registries can use {@link DeferredRegister#addOptionalTagDefaults(TagKey, Set)} to create tag keys before the tag manager is created.
|
||||
*
|
||||
* @see #createTagKey(ResourceLocation)
|
||||
* @see #addOptionalTagDefaults(TagKey, Set)
|
||||
* @see DeferredRegister#createOptionalTagKey(ResourceLocation, Set)
|
||||
*/
|
||||
@NotNull TagKey<V> createOptionalTagKey(@NotNull ResourceLocation location, @NotNull Set<? extends Supplier<V>> defaults);
|
||||
|
||||
/**
|
||||
* Adds defaults to an existing tag key.
|
||||
* 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.
|
||||
* Custom registries can use {@link DeferredRegister#addOptionalTagDefaults(TagKey, Set)} to add defaults before the tag manager is created.
|
||||
*
|
||||
* @see #createOptionalTagKey(ResourceLocation, Set)
|
||||
* @see DeferredRegister#addOptionalTagDefaults(TagKey, Set)
|
||||
*/
|
||||
void addOptionalTagDefaults(@NotNull TagKey<V> name, @NotNull Set<? extends Supplier<V>> defaults);
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public class ForgeCommand
|
||||
.then(GenerateCommand.register())
|
||||
.then(DimensionsCommand.register())
|
||||
.then(ModListCommand.register())
|
||||
.then(TagsCommand.register())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.server.command;
|
||||
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
|
||||
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.ResourceKeyArgument;
|
||||
import net.minecraft.commands.arguments.ResourceLocationArgument;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.ComponentUtils;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The {@code /forge tags} command for listing a registry's tags, getting the elements of tags, and querying the tags of a
|
||||
* registry object.
|
||||
*
|
||||
* <p>Each command is paginated, showing {@value PAGE_SIZE} entries at a time. When there are more than 0 entries,
|
||||
* the text indicating the amount of entries is highlighted and can be clicked to copy the list of all entries (across
|
||||
* all pages) to the clipboard. (This is reflected by the use of green text in brackets, mimicking the clickable
|
||||
* coordinates in the {@code /locate} command's message)</p>
|
||||
*
|
||||
* <p>The command has three subcommands:</p>
|
||||
* <ul>
|
||||
* <li>{@code /forge tags <registry> list [page]} - Lists all available tags in the given registry.</li>
|
||||
* <li>{@code /forge tags <registry> get <tag> [page]} - Gets all elements of the given tag in the given registry.</li>
|
||||
* <li>{@code /forge tags <registry> query <element> [page]} - Queries for all tags in the given registry which
|
||||
* contain the given registry object.</li>
|
||||
* </ul>
|
||||
*/
|
||||
class TagsCommand
|
||||
{
|
||||
private static final long PAGE_SIZE = 8;
|
||||
private static final ResourceKey<Registry<Registry<?>>> ROOT_REGISTRY_KEY =
|
||||
ResourceKey.createRegistryKey(new ResourceLocation("root"));
|
||||
|
||||
private static final DynamicCommandExceptionType UNKNOWN_REGISTRY = new DynamicCommandExceptionType(key ->
|
||||
new TranslatableComponent("commands.forge.tags.error.unknown_registry", key));
|
||||
private static final Dynamic2CommandExceptionType UNKNOWN_TAG = new Dynamic2CommandExceptionType((tag, registry) ->
|
||||
new TranslatableComponent("commands.forge.tags.error.unknown_tag", tag, registry));
|
||||
private static final Dynamic2CommandExceptionType UNKNOWN_ELEMENT = new Dynamic2CommandExceptionType((tag, registry) ->
|
||||
new TranslatableComponent("commands.forge.tags.error.unknown_element", tag, registry));
|
||||
|
||||
public static ArgumentBuilder<CommandSourceStack, ?> register()
|
||||
{
|
||||
/*
|
||||
* /forge tags <registry> list [page]
|
||||
* /forge tags <registry> get <tag> [page]
|
||||
* /forge tags <registry> query <element> [page]
|
||||
*/
|
||||
return Commands.literal("tags")
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("registry", ResourceKeyArgument.key(ROOT_REGISTRY_KEY))
|
||||
.suggests(TagsCommand::suggestRegistries)
|
||||
.then(Commands.literal("list")
|
||||
.executes(ctx -> listTags(ctx, 1))
|
||||
.then(Commands.argument("page", IntegerArgumentType.integer(1))
|
||||
.executes(ctx -> listTags(ctx, IntegerArgumentType.getInteger(ctx, "page")))
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("get")
|
||||
.then(Commands.argument("tag", ResourceLocationArgument.id())
|
||||
.suggests(suggestFromRegistry(r -> r.getTagNames().map(TagKey::location)::iterator))
|
||||
.executes(ctx -> listTagElements(ctx, 1))
|
||||
.then(Commands.argument("page", IntegerArgumentType.integer(1))
|
||||
.executes(ctx -> listTagElements(ctx, IntegerArgumentType.getInteger(ctx, "page")))
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("query")
|
||||
.then(Commands.argument("element", ResourceLocationArgument.id())
|
||||
.suggests(suggestFromRegistry(Registry::keySet))
|
||||
.executes(ctx -> queryElementTags(ctx, 1))
|
||||
.then(Commands.argument("page", IntegerArgumentType.integer(1))
|
||||
.executes(ctx -> queryElementTags(ctx, IntegerArgumentType.getInteger(ctx, "page")))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int listTags(final CommandContext<CommandSourceStack> ctx, final int page) throws CommandSyntaxException
|
||||
{
|
||||
final ResourceKey<? extends Registry<?>> registryKey = getResourceKey(ctx, "registry", ROOT_REGISTRY_KEY)
|
||||
.orElseThrow(); // Expect to be always retrieve a resource key for the root registry (registry key)
|
||||
final Registry<?> registry = ctx.getSource().getServer().registryAccess().registry(registryKey)
|
||||
.orElseThrow(() -> UNKNOWN_REGISTRY.create(registryKey.location()));
|
||||
|
||||
final long tagCount = registry.getTags().count();
|
||||
|
||||
ctx.getSource().sendSuccess(createMessage(
|
||||
new TranslatableComponent("commands.forge.tags.registry_key", new TextComponent(registryKey.location().toString()).withStyle(ChatFormatting.GOLD)),
|
||||
"commands.forge.tags.tag_count",
|
||||
"commands.forge.tags.copy_tag_names",
|
||||
tagCount,
|
||||
page,
|
||||
ChatFormatting.DARK_GREEN,
|
||||
() -> registry.getTags()
|
||||
.map(Pair::getSecond)
|
||||
.map(s -> s.unwrap().map(k -> k.location().toString(), Object::toString))
|
||||
), false);
|
||||
|
||||
return (int) tagCount;
|
||||
}
|
||||
|
||||
private static int listTagElements(final CommandContext<CommandSourceStack> ctx, final int page) throws CommandSyntaxException
|
||||
{
|
||||
final ResourceKey<? extends Registry<?>> registryKey = getResourceKey(ctx, "registry", ROOT_REGISTRY_KEY)
|
||||
.orElseThrow(); // Expect to be always retrieve a resource key for the root registry (registry key)
|
||||
final Registry<?> registry = ctx.getSource().getServer().registryAccess().registry(registryKey)
|
||||
.orElseThrow(() -> UNKNOWN_REGISTRY.create(registryKey.location()));
|
||||
|
||||
final ResourceLocation tagLocation = ResourceLocationArgument.getId(ctx, "tag");
|
||||
final TagKey<?> tagKey = TagKey.create(cast(registryKey), tagLocation);
|
||||
|
||||
final HolderSet.Named<?> tag = registry.getTag(cast(tagKey))
|
||||
.orElseThrow(() -> UNKNOWN_TAG.create(tagKey.location(), registryKey.location()));
|
||||
|
||||
ctx.getSource().sendSuccess(createMessage(
|
||||
new TranslatableComponent("commands.forge.tags.tag_key",
|
||||
new TextComponent(tagKey.registry().location().toString()).withStyle(ChatFormatting.GOLD),
|
||||
new TextComponent(tagKey.location().toString()).withStyle(ChatFormatting.DARK_GREEN)),
|
||||
"commands.forge.tags.element_count",
|
||||
"commands.forge.tags.copy_element_names",
|
||||
tag.size(),
|
||||
page,
|
||||
ChatFormatting.YELLOW,
|
||||
() -> tag.stream().map(s -> s.unwrap().map(k -> k.location().toString(), Object::toString))
|
||||
), false);
|
||||
|
||||
return tag.size();
|
||||
}
|
||||
|
||||
private static int queryElementTags(final CommandContext<CommandSourceStack> ctx, final int page) throws CommandSyntaxException
|
||||
{
|
||||
final ResourceKey<? extends Registry<?>> registryKey = getResourceKey(ctx, "registry", ROOT_REGISTRY_KEY)
|
||||
.orElseThrow(); // Expect to be always retrieve a resource key for the root registry (registry key)
|
||||
final Registry<?> registry = ctx.getSource().getServer().registryAccess().registry(registryKey)
|
||||
.orElseThrow(() -> UNKNOWN_REGISTRY.create(registryKey.location()));
|
||||
|
||||
final ResourceLocation elementLocation = ResourceLocationArgument.getId(ctx, "element");
|
||||
final ResourceKey<?> elementKey = ResourceKey.create(cast(registryKey), elementLocation);
|
||||
|
||||
final Holder<?> elementHolder = registry.getHolder(cast(elementKey))
|
||||
.orElseThrow(() -> UNKNOWN_ELEMENT.create(elementLocation, registryKey.location()));
|
||||
|
||||
final long containingTagsCount = elementHolder.tags().count();
|
||||
|
||||
ctx.getSource().sendSuccess(createMessage(
|
||||
new TranslatableComponent("commands.forge.tags.element",
|
||||
new TextComponent(registryKey.location().toString()).withStyle(ChatFormatting.GOLD),
|
||||
new TextComponent(elementLocation.toString()).withStyle(ChatFormatting.YELLOW)),
|
||||
"commands.forge.tags.containing_tag_count",
|
||||
"commands.forge.tags.copy_tag_names",
|
||||
containingTagsCount,
|
||||
page,
|
||||
ChatFormatting.DARK_GREEN,
|
||||
() -> elementHolder.tags().map(k -> k.location().toString())
|
||||
), false);
|
||||
|
||||
return (int) containingTagsCount;
|
||||
}
|
||||
|
||||
private static MutableComponent createMessage(final TranslatableComponent header,
|
||||
final String containsText,
|
||||
final String copyHoverText,
|
||||
final long count,
|
||||
final long currentPage,
|
||||
final ChatFormatting elementColor,
|
||||
final Supplier<Stream<String>> names)
|
||||
{
|
||||
final String allElementNames = names.get().sorted().collect(Collectors.joining("\n"));
|
||||
final long totalPages = (count - 1) / PAGE_SIZE + 1;
|
||||
final long actualPage = Mth.clamp(currentPage, 1, totalPages);
|
||||
|
||||
MutableComponent containsComponent = new TranslatableComponent(containsText, count);
|
||||
if (count > 0) // Highlight the count text, make it clickable, and append page counters
|
||||
{
|
||||
containsComponent = ComponentUtils.wrapInSquareBrackets(containsComponent.withStyle(s -> s
|
||||
.withColor(ChatFormatting.GREEN)
|
||||
.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, allElementNames))
|
||||
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
new TranslatableComponent(copyHoverText)))));
|
||||
containsComponent = new TranslatableComponent("commands.forge.tags.page_info",
|
||||
containsComponent, actualPage, totalPages);
|
||||
}
|
||||
|
||||
final MutableComponent tagElements = new TextComponent("").append(containsComponent);
|
||||
names.get()
|
||||
.sorted()
|
||||
.skip(PAGE_SIZE * (actualPage - 1))
|
||||
.limit(PAGE_SIZE)
|
||||
.map(TextComponent::new)
|
||||
.map(t -> t.withStyle(elementColor))
|
||||
.map(t -> new TextComponent("\n - ").append(t))
|
||||
.forEach(tagElements::append);
|
||||
|
||||
return header.append("\n").append(tagElements);
|
||||
}
|
||||
|
||||
private static CompletableFuture<Suggestions> suggestRegistries(final CommandContext<CommandSourceStack> ctx,
|
||||
final SuggestionsBuilder builder)
|
||||
{
|
||||
ctx.getSource().suggestRegistryElements(Registry.REGISTRY,
|
||||
SharedSuggestionProvider.ElementSuggestionType.ELEMENTS, builder);
|
||||
return builder.buildFuture();
|
||||
}
|
||||
|
||||
private static SuggestionProvider<CommandSourceStack> suggestFromRegistry(
|
||||
final Function<Registry<?>, Iterable<ResourceLocation>> namesFunction)
|
||||
{
|
||||
return (ctx, builder) -> getResourceKey(ctx, "registry", ROOT_REGISTRY_KEY)
|
||||
.flatMap(key -> ctx.getSource().registryAccess().registry(key).map(registry -> {
|
||||
SharedSuggestionProvider.suggestResource(namesFunction.apply(registry), builder);
|
||||
return builder.buildFuture();
|
||||
}))
|
||||
.orElseGet(builder::buildFuture);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static <T> Optional<ResourceKey<T>> getResourceKey(final CommandContext<CommandSourceStack> ctx,
|
||||
final String name,
|
||||
final ResourceKey<Registry<T>> registryKey)
|
||||
{
|
||||
// Don't inline to avoid an unchecked cast warning due to raw types
|
||||
final ResourceKey<?> key = ctx.getArgument(name, ResourceKey.class);
|
||||
return key.cast(registryKey);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <O> O cast(final Object input)
|
||||
{
|
||||
return (O) input;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user