Add support for custom tag types (#7289)

This commit is contained in:
Richard Freimer 2020-09-08 22:10:36 -04:00 committed by GitHub
parent 43391c009c
commit 45f8dc5245
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1059 additions and 24 deletions

View file

@ -352,6 +352,7 @@ project(':forge') {
'--mod', 'piston_event_test',
'--mod', 'global_loot_test',
'--mod', 'scaffolding_test',
'--mod', 'custom_tag_types_test',
'--output', rootProject.file('src/generated_test/resources/'),
'--existing', sourceSets.main.resources.srcDirs[0]
}

View file

@ -77,7 +77,21 @@
if (effect != null) {
EffectInstance effectinstance = new EffectInstance(effect, p_147260_1_.func_180755_e(), p_147260_1_.func_149428_f(), p_147260_1_.func_186984_g(), p_147260_1_.func_179707_f(), p_147260_1_.func_205527_h());
effectinstance.func_100012_b(p_147260_1_.func_149429_c());
@@ -1883,10 +1896,12 @@
@@ -1388,11 +1401,12 @@
public void func_199723_a(STagsListPacket p_199723_1_) {
PacketThreadUtil.func_218797_a(p_199723_1_, this, this.field_147299_f);
ITagCollectionSupplier itagcollectionsupplier = p_199723_1_.func_199858_a();
- Multimap<ResourceLocation, ResourceLocation> multimap = TagRegistryManager.func_242198_b(itagcollectionsupplier);
+ Multimap<ResourceLocation, ResourceLocation> multimap = TagRegistryManager.validateVanillaTags(itagcollectionsupplier);
if (!multimap.isEmpty()) {
field_147301_d.warn("Incomplete server tags, disconnecting. Missing: {}", (Object)multimap);
this.field_147302_e.func_150718_a(new TranslationTextComponent("multiplayer.disconnect.missing_tags"));
} else {
+ net.minecraftforge.common.ForgeTagHandler.resetCachedTagCollections();
this.field_199725_m = itagcollectionsupplier;
if (!this.field_147302_e.func_150731_c()) {
itagcollectionsupplier.func_242212_e();
@@ -1883,10 +1897,12 @@
int l5 = packetbuffer.readInt();
this.field_147299_f.field_184132_p.field_229018_q_.func_229022_a_(blockpos8, l3, s10, l5);
} else {

View file

@ -16,7 +16,15 @@
GameRules gamerules = serverworld1.func_82736_K();
boolean flag = gamerules.func_223586_b(GameRules.field_226683_z_);
boolean flag1 = gamerules.func_223586_b(GameRules.field_223612_o);
@@ -170,7 +172,7 @@
@@ -156,6 +158,7 @@
serverplaynethandler.func_147359_a(new SHeldItemChangePacket(p_72355_2_.field_71071_by.field_70461_c));
serverplaynethandler.func_147359_a(new SUpdateRecipesPacket(this.field_72400_f.func_199529_aN().func_199510_b()));
serverplaynethandler.func_147359_a(new STagsListPacket(this.field_72400_f.func_244266_aF()));
+ net.minecraftforge.fml.network.NetworkHooks.syncCustomTagTypes(p_72355_2_, this.field_72400_f.func_244266_aF());
this.func_187243_f(p_72355_2_);
p_72355_2_.func_147099_x().func_150877_d();
p_72355_2_.func_192037_E().func_192826_c(p_72355_2_);
@@ -170,7 +173,7 @@
this.func_232641_a_(iformattabletextcomponent.func_240699_a_(TextFormatting.YELLOW), ChatType.SYSTEM, Util.field_240973_b_);
serverplaynethandler.func_147364_a(p_72355_2_.func_226277_ct_(), p_72355_2_.func_226278_cu_(), p_72355_2_.func_226281_cx_(), p_72355_2_.field_70177_z, p_72355_2_.field_70125_A);
@ -25,7 +33,7 @@
this.field_177454_f.put(p_72355_2_.func_110124_au(), p_72355_2_);
this.func_148540_a(new SPlayerListItemPacket(SPlayerListItemPacket.Action.ADD_PLAYER, p_72355_2_));
@@ -225,6 +227,7 @@
@@ -225,6 +228,7 @@
}
p_72355_2_.func_71116_b();
@ -33,7 +41,7 @@
}
protected void func_96456_a(ServerScoreboard p_96456_1_, ServerPlayerEntity p_96456_2_) {
@@ -285,6 +288,7 @@
@@ -285,6 +289,7 @@
compoundnbt1 = compoundnbt;
p_72380_1_.func_70020_e(compoundnbt);
field_148546_d.debug("loading single player");
@ -41,7 +49,7 @@
} else {
compoundnbt1 = this.field_72412_k.func_237336_b_(p_72380_1_);
}
@@ -293,6 +297,7 @@
@@ -293,6 +298,7 @@
}
protected void func_72391_b(ServerPlayerEntity p_72391_1_) {
@ -49,7 +57,7 @@
this.field_72412_k.func_237335_a_(p_72391_1_);
ServerStatisticsManager serverstatisticsmanager = this.field_148547_k.get(p_72391_1_.func_110124_au());
if (serverstatisticsmanager != null) {
@@ -307,6 +312,7 @@
@@ -307,6 +313,7 @@
}
public void func_72367_e(ServerPlayerEntity p_72367_1_) {
@ -57,7 +65,7 @@
ServerWorld serverworld = p_72367_1_.func_71121_q();
p_72367_1_.func_195066_a(Stats.field_75947_j);
this.func_72391_b(p_72367_1_);
@@ -330,7 +336,7 @@
@@ -330,7 +337,7 @@
p_72367_1_.func_213319_R();
serverworld.func_217434_e(p_72367_1_);
p_72367_1_.func_192039_O().func_192745_a();
@ -66,7 +74,7 @@
this.field_72400_f.func_201300_aS().func_201382_b(p_72367_1_);
UUID uuid = p_72367_1_.func_110124_au();
ServerPlayerEntity serverplayerentity = this.field_177454_f.get(uuid);
@@ -400,8 +406,8 @@
@@ -400,8 +407,8 @@
}
public ServerPlayerEntity func_232644_a_(ServerPlayerEntity p_232644_1_, boolean p_232644_2_) {
@ -77,7 +85,7 @@
BlockPos blockpos = p_232644_1_.func_241140_K_();
float f = p_232644_1_.func_242109_L();
boolean flag = p_232644_1_.func_241142_M_();
@@ -424,6 +430,7 @@
@@ -424,6 +431,7 @@
ServerPlayerEntity serverplayerentity = new ServerPlayerEntity(this.field_72400_f, serverworld1, p_232644_1_.func_146103_bH(), playerinteractionmanager);
serverplayerentity.field_71135_a = p_232644_1_.field_71135_a;
serverplayerentity.func_193104_a(p_232644_1_, p_232644_2_);
@ -85,7 +93,7 @@
serverplayerentity.func_145769_d(p_232644_1_.func_145782_y());
serverplayerentity.func_184819_a(p_232644_1_.func_184591_cq());
@@ -465,10 +472,11 @@
@@ -465,10 +473,11 @@
this.func_72354_b(serverplayerentity, serverworld1);
this.func_187243_f(serverplayerentity);
serverworld1.func_217433_d(serverplayerentity);
@ -98,7 +106,7 @@
if (flag2) {
serverplayerentity.field_71135_a.func_147359_a(new SPlaySoundEffectPacket(SoundEvents.field_232818_ms_, SoundCategory.BLOCKS, (double)blockpos.func_177958_n(), (double)blockpos.func_177956_o(), (double)blockpos.func_177952_p(), 1.0F, 1.0F));
}
@@ -786,7 +794,7 @@
@@ -786,7 +795,7 @@
}
public List<ServerPlayerEntity> func_181057_v() {
@ -107,7 +115,15 @@
}
@Nullable
@@ -816,4 +824,12 @@
@@ -804,6 +813,7 @@
}
this.func_148540_a(new STagsListPacket(this.field_72400_f.func_244266_aF()));
+ net.minecraftforge.fml.network.NetworkHooks.syncCustomTagTypes(this.field_72400_f.func_244266_aF());
SUpdateRecipesPacket supdaterecipespacket = new SUpdateRecipesPacket(this.field_72400_f.func_199529_aN().func_199510_b());
for(ServerPlayerEntity serverplayerentity : this.field_72404_b) {
@@ -816,4 +826,12 @@
public boolean func_206257_x() {
return this.field_72407_n;
}

View file

@ -1,10 +1,19 @@
--- a/net/minecraft/tags/ITagCollectionSupplier.java
+++ b/net/minecraft/tags/ITagCollectionSupplier.java
@@ -8,7 +8,7 @@
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.registry.Registry;
-public interface ITagCollectionSupplier {
+public interface ITagCollectionSupplier extends net.minecraftforge.common.extensions.IForgeTagCollectionSupplier {
ITagCollectionSupplier field_242208_a = func_242209_a(ITagCollection.func_242205_c(), ITagCollection.func_242205_c(), ITagCollection.func_242205_c(), ITagCollection.func_242205_c());
ITagCollection<Block> func_241835_a();
@@ -22,6 +22,7 @@
default void func_242212_e() {
TagRegistryManager.func_242193_a(this);
Blocks.func_235419_a_();
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.TagsUpdatedEvent(this));
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.TagsUpdatedEvent.VanillaTagTypes(this));
}
default void func_242210_a(PacketBuffer p_242210_1_) {

View file

@ -0,0 +1,25 @@
--- a/net/minecraft/tags/NetworkTagManager.java
+++ b/net/minecraft/tags/NetworkTagManager.java
@@ -20,6 +20,7 @@
protected TagCollectionReader<Item> field_199720_b = new TagCollectionReader<>(Registry.field_212630_s::func_241873_b, "tags/items", "item");
protected TagCollectionReader<Fluid> field_205705_c = new TagCollectionReader<>(Registry.field_212619_h::func_241873_b, "tags/fluids", "fluid");
protected TagCollectionReader<EntityType<?>> field_215299_d = new TagCollectionReader<>(Registry.field_212629_r::func_241873_b, "tags/entity_types", "entity_type");
+ protected Map<ResourceLocation, TagCollectionReader<?>> customTagTypeReaders = net.minecraftforge.common.ForgeTagHandler.createCustomTagTypeReaders();
private ITagCollectionSupplier field_242230_e = ITagCollectionSupplier.field_242208_a;
public ITagCollectionSupplier func_242231_a() {
@@ -31,11 +32,13 @@
CompletableFuture<Map<ResourceLocation, ITag.Builder>> completablefuture1 = this.field_199720_b.func_242224_a(p_215226_2_, p_215226_5_);
CompletableFuture<Map<ResourceLocation, ITag.Builder>> completablefuture2 = this.field_205705_c.func_242224_a(p_215226_2_, p_215226_5_);
CompletableFuture<Map<ResourceLocation, ITag.Builder>> completablefuture3 = this.field_215299_d.func_242224_a(p_215226_2_, p_215226_5_);
- return CompletableFuture.allOf(completablefuture, completablefuture1, completablefuture2, completablefuture3).thenCompose(p_215226_1_::func_216872_a).thenAcceptAsync((p_232979_5_) -> {
+ CompletableFuture<java.util.List<net.minecraftforge.common.ForgeTagHandler.TagCollectionReaderInfo>> customTagTypeResults = net.minecraftforge.common.ForgeTagHandler.getCustomTagTypeReloadResults(p_215226_2_, p_215226_5_, customTagTypeReaders);
+ return CompletableFuture.allOf(completablefuture, completablefuture1, completablefuture2, completablefuture3, customTagTypeResults).thenCompose(p_215226_1_::func_216872_a).thenAcceptAsync((p_232979_5_) -> {
ITagCollection<Block> itagcollection = this.field_199719_a.func_242226_a(completablefuture.join());
ITagCollection<Item> itagcollection1 = this.field_199720_b.func_242226_a(completablefuture1.join());
ITagCollection<Fluid> itagcollection2 = this.field_205705_c.func_242226_a(completablefuture2.join());
ITagCollection<EntityType<?>> itagcollection3 = this.field_215299_d.func_242226_a(completablefuture3.join());
+ net.minecraftforge.common.ForgeTagHandler.updateCustomTagTypes(customTagTypeResults.join());
ITagCollectionSupplier itagcollectionsupplier = ITagCollectionSupplier.func_242209_a(itagcollection, itagcollection1, itagcollection2, itagcollection3);
Multimap<ResourceLocation, ResourceLocation> multimap = TagRegistryManager.func_242198_b(itagcollectionsupplier);
if (!multimap.isEmpty()) {

View file

@ -5,7 +5,7 @@
public class TagCollectionManager {
- private static volatile ITagCollectionSupplier field_232918_a_ = ITagCollectionSupplier.func_242209_a(ITagCollection.func_242202_a(BlockTags.func_242174_b().stream().collect(Collectors.toMap(ITag.INamedTag::func_230234_a_, (p_242183_0_) -> {
+ private static volatile ITagCollectionSupplier field_232918_a_ = ITagCollectionSupplier.func_242209_a(ITagCollection.func_242202_a(BlockTags.func_242174_b().stream().distinct().collect(Collectors.toMap(ITag.INamedTag::func_230234_a_, (p_242183_0_) -> {
+ private static volatile ITagCollectionSupplier field_232918_a_ = net.minecraftforge.common.ForgeTagHandler.populateTagCollectionManager(ITagCollection.func_242202_a(BlockTags.func_242174_b().stream().distinct().collect(Collectors.toMap(ITag.INamedTag::func_230234_a_, (p_242183_0_) -> {
return p_242183_0_;
- }))), ITagCollection.func_242202_a(ItemTags.func_242177_b().stream().collect(Collectors.toMap(ITag.INamedTag::func_230234_a_, (p_242182_0_) -> {
+ }))), ITagCollection.func_242202_a(ItemTags.func_242177_b().stream().distinct().collect(Collectors.toMap(ITag.INamedTag::func_230234_a_, (p_242182_0_) -> {

View file

@ -1,6 +1,13 @@
--- a/net/minecraft/tags/TagRegistry.java
+++ b/net/minecraft/tags/TagRegistry.java
@@ -22,7 +22,15 @@
@@ -16,13 +16,51 @@
private ITagCollection<T> field_232930_b_ = ITagCollection.func_242205_c();
private final List<TagRegistry.NamedTag<T>> field_232931_c_ = Lists.newArrayList();
private final Function<ITagCollectionSupplier, ITagCollection<T>> field_242184_c;
+ private static java.util.Map<ResourceLocation, List<TagRegistry.NamedTag<?>>> toAdd = com.google.common.collect.Maps.newHashMap();
public TagRegistry(Function<ITagCollectionSupplier, ITagCollection<T>> p_i241894_1_) {
this.field_242184_c = p_i241894_1_;
}
public ITag.INamedTag<T> func_232937_a_(String p_232937_1_) {
@ -12,12 +19,41 @@
+ return add(new TagRegistry.OptionalNamedTag<>(key, defaults));
+ }
+
+ /** Call via ForgeTagHandler#makeWrapperTag to avoid any exceptions due to calling this after it is safe to call {@link #func_232937_a_(String)} */
+ public static <T> ITag.INamedTag<T> createDelayedTag(ResourceLocation tagRegistry, ResourceLocation name) {
+ return delayedAdd(tagRegistry, new TagRegistry.NamedTag<>(name));
+ }
+
+ /** Call via ForgeTagHandler#createOptionalTag to avoid any exceptions due to calling this after it is safe to call {@link #createOptional(ResourceLocation, java.util.function.Supplier)} */
+ public static <T> net.minecraftforge.common.Tags.IOptionalNamedTag<T> createDelayedOptional(ResourceLocation tagRegistry, ResourceLocation key, @Nullable java.util.function.Supplier<Set<T>> defaults) {
+ return delayedAdd(tagRegistry, new TagRegistry.OptionalNamedTag<>(key, defaults));
+ }
+
+ private static synchronized <T, R extends TagRegistry.NamedTag<T>> R delayedAdd(ResourceLocation tagRegistry, R tag) {
+ if (toAdd == null) throw new RuntimeException("Creating delayed tags or optional tags, is only supported before custom tag types have been added.");
+ toAdd.computeIfAbsent(tagRegistry, registry -> Lists.newArrayList()).add(tag);
+ return tag;
+ }
+
+ public static void performDelayedAdd() {
+ if (toAdd != null) {
+ for (java.util.Map.Entry<ResourceLocation, List<TagRegistry.NamedTag<?>>> entry : toAdd.entrySet()) {
+ TagRegistry<?> tagRegistry = TagRegistryManager.get(entry.getKey());
+ if (tagRegistry == null) throw new RuntimeException("A mod attempted to add a delayed tag for a registry that doesn't have custom tag support.");
+ for (TagRegistry.NamedTag<?> tag : entry.getValue()) {
+ tagRegistry.add((TagRegistry.NamedTag) tag);
+ }
+ }
+ toAdd = null;
+ }
+ }
+
+ private <R extends TagRegistry.NamedTag<T>> R add(R namedtag) {
+ namedtag.func_232943_a_(field_232930_b_::func_199910_a);
this.field_232931_c_.add(namedtag);
return namedtag;
}
@@ -56,7 +64,7 @@
@@ -56,7 +94,7 @@
public Set<ResourceLocation> func_242189_b(ITagCollectionSupplier p_242189_1_) {
ITagCollection<T> itagcollection = this.field_242184_c.apply(p_242189_1_);
@ -26,7 +62,7 @@
ImmutableSet<ResourceLocation> immutableset = ImmutableSet.copyOf(itagcollection.func_199908_a());
return Sets.difference(set, immutableset);
}
@@ -93,5 +101,45 @@
@@ -93,5 +131,45 @@
public List<T> func_230236_b_() {
return this.func_232944_c_().func_230236_b_();
}

View file

@ -0,0 +1,26 @@
--- a/net/minecraft/tags/TagRegistryManager.java
+++ b/net/minecraft/tags/TagRegistryManager.java
@@ -51,4 +51,23 @@
throw new IllegalStateException("Missing helper registrations");
}
}
+
+ @javax.annotation.Nullable
+ public static TagRegistry<?> get(ResourceLocation rl) {
+ return field_242190_a.get(rl);
+ }
+
+ public static Multimap<ResourceLocation, ResourceLocation> validateVanillaTags(ITagCollectionSupplier tagCollectionSupplier) {
+ Multimap<ResourceLocation, ResourceLocation> missingTags = HashMultimap.create();
+ for (java.util.Map.Entry<ResourceLocation, TagRegistry<?>> entry : field_242190_a.entrySet()) {
+ if (!net.minecraftforge.common.ForgeTagHandler.getCustomTagTypeNames().contains(entry.getKey())) {
+ missingTags.putAll(entry.getKey(), entry.getValue().func_242189_b(tagCollectionSupplier));
+ }
+ }
+ return missingTags;
+ }
+
+ public static void fetchCustomTagTypes(ITagCollectionSupplier tagCollectionSupplier) {
+ net.minecraftforge.common.ForgeTagHandler.getCustomTagTypeNames().forEach(tagRegistry -> field_242190_a.get(tagRegistry).func_242188_a(tagCollectionSupplier));
+ }
}

View file

@ -67,6 +67,8 @@ a012d6d92bab1c91913bd0f2dc0492a0fce916f2 assets/minecraft/blockstates/wall_torch
d2c8e860521c5e738ed0798337f5728d610825ff assets/piston_event_test/models/block/shiftonmove.json
f51f026a75e27a0a53a76771d553c0e3385a2966 assets/piston_event_test/models/item/shiftonmove.json
cf16f861eaf5815238c2278eb48bde0688cb73b7 assets/scaffolding_test/blockstates/scaffolding_method_test.json
42d3ce7d941eb8b80c3d541b937d0f93c9cf7c3c data/custom_tag_types_test/tags/biomes/oceans.json
862196702dcd5538c5ceb4ac6202e57eb5c8a97f data/custom_tag_types_test/tags/custom_tag_types_test/custom_types/tests.json
4fbaf6f4a3ea05cc071076e27f44ac81f9cc50e3 data/data_gen_test/advancements/conditional.json
ed4cbf1a3a2f5d8969f6346fdc9acdbe81d0c919 data/data_gen_test/recipes/conditional.json
40208299608468b044f64317995f9182ec219d90 data/data_gen_test/tags/blocks/test.json
@ -74,3 +76,6 @@ d65c425e740dc833f29d16606a1171825876be0d data/data_gen_test/tags/blocks/thing/on
1f70ed4ddc878bada5e43d3c44a34157806beda8 data/data_gen_test/tags/blocks/thing/three.json
2c648bca262caaa826ddbbde796d35bb2ee5f03a data/data_gen_test/tags/blocks/thing/two.json
b0565ce75fc7880be7517e86a218d1ed9d9e346f data/data_gen_test/tags/blocks/things.json
7572ecfdcedc05dfcabf8a4c69c75e007023256f data/forge/loot_modifiers/global_loot_modifiers.json
f65e40b06ce7ad18e053ec88058b951f98ae5f40 data/global_loot_test/loot_modifiers/smelting.json
f991cfd612acf5ce98a43f4771ee04727219ae53 data/global_loot_test/loot_modifiers/wheat_harvest.json

View file

@ -0,0 +1,15 @@
{
"replace": false,
"values": [
"minecraft:ocean",
"minecraft:frozen_ocean",
"minecraft:deep_ocean",
"minecraft:warm_ocean",
"minecraft:lukewarm_ocean",
"minecraft:cold_ocean",
"minecraft:deep_warm_ocean",
"minecraft:deep_lukewarm_ocean",
"minecraft:deep_cold_ocean",
"minecraft:deep_frozen_ocean"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"custom_tag_types_test:custom"
]
}

View file

@ -110,7 +110,7 @@ public class ForgeInternalHandler
}
@SubscribeEvent
public synchronized void tagsUpdated(TagsUpdatedEvent event)
public synchronized void tagsUpdated(TagsUpdatedEvent.VanillaTagTypes event)
{
ForgeHooks.updateBurns();
}

View file

@ -0,0 +1,343 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityType;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.Item;
import net.minecraft.resources.IResourceManager;
import net.minecraft.tags.ITag;
import net.minecraft.tags.ITag.INamedTag;
import net.minecraft.tags.ITagCollection;
import net.minecraft.tags.ITagCollectionSupplier;
import net.minecraft.tags.TagCollectionReader;
import net.minecraft.tags.TagRegistry;
import net.minecraft.tags.TagRegistryManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.Tags.IOptionalNamedTag;
import net.minecraftforge.fml.network.FMLPlayMessages.SyncCustomTagTypes;
import net.minecraftforge.registries.ForgeRegistry;
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 Map<ResourceLocation, ITagCollection<?>> customTagTypes = Collections.emptyMap();
private static Set<ResourceLocation> customTagTypeNames = Collections.emptySet();
private static boolean tagTypesSet = false;
@Nullable
private static <T extends IForgeRegistryEntry<T>> TagRegistry<T> getTagRegistry(IForgeRegistry<T> registry)
{
return (TagRegistry<T>) TagRegistryManager.get(registry.getRegistryName());
}
private static void validateRegistrySupportsTags(IForgeRegistry<?> registry)
{
//Note: We also check against getTagRegistry in case someone decides to use the helpers for tag creation for types supported by vanilla
if (getTagRegistry(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>> ITag.INamedTag<T> makeWrapperTag(IForgeRegistry<T> registry, ResourceLocation name)
{
validateRegistrySupportsTags(registry);
if (tagTypesSet)
{
TagRegistry<T> tagRegistry = getTagRegistry(registry);
if (tagRegistry == null) throw new IllegalArgumentException("Registry " + registry.getRegistryName() + " does not support tag types.");
return tagRegistry.func_232937_a_(name.toString());
}
return TagRegistry.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 Supplier<Set<T>> defaults)
{
validateRegistrySupportsTags(registry);
if (tagTypesSet)
{
TagRegistry<T> tagRegistry = getTagRegistry(registry);
if (tagRegistry == null) throw new IllegalArgumentException("Registry " + registry.getRegistryName() + " does not support tag types.");
return tagRegistry.createOptional(name, defaults);
}
return TagRegistry.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>> ITag.INamedTag<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 TagRegistry.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 Supplier<Set<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 TagRegistry.createDelayedOptional(registryName, name, defaults);
}
/**
* Gets the all the registry names of registries that support custom tag types.
*/
public static Set<ResourceLocation> getCustomTagTypeNames()
{
return customTagTypeNames;
}
/**
* Gets a map of registry name to tag collection for all custom tag types.
*
* @apiNote Prefer interacting with this via the current {@link ITagCollectionSupplier} and using one of the forge extension getCustomTypeCollection methods
*/
public static Map<ResourceLocation, ITagCollection<?>> getCustomTagTypes()
{
return customTagTypes;
}
/**
* 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> customTagTypes)
{
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(customTagTypes);
TagRegistry.performDelayedAdd();
}
/**
* Creates a map for custom tag type to tag reader
*
* @apiNote Internal: For use by NetworkTagManager
*/
public static Map<ResourceLocation, TagCollectionReader<?>> createCustomTagTypeReaders()
{
LOGGER.debug("Gathering custom tag collection reader from types.");
ImmutableMap.Builder<ResourceLocation, TagCollectionReader<?>> builder = ImmutableMap.builder();
for (ResourceLocation registryName : customTagTypeNames)
{
ForgeRegistry<?> registry = RegistryManager.ACTIVE.getRegistry(registryName);
if (registry != null && registry.getTagFolder() != null)
{
builder.put(registryName, new TagCollectionReader<>(rl -> Optional.ofNullable(registry.getValue(rl)), "tags/" + registry.getTagFolder(), registryName.getPath()));
}
}
return builder.build();
}
/**
* Resets the cached collections for the various custom tag types.
*
* @apiNote Internal
*/
public static void resetCachedTagCollections()
{
ImmutableMap.Builder<ResourceLocation, ITagCollection<?>> builder = ImmutableMap.builder();
for (ResourceLocation registryName : customTagTypeNames)
{
TagRegistry<?> tagRegistry = TagRegistryManager.get(registryName);
if (tagRegistry != null)
{
builder.put(registryName, ITagCollection.func_242202_a(tagRegistry.func_241288_c_().stream().distinct().collect(Collectors.toMap(INamedTag::func_230234_a_, namedTag -> namedTag))));
}
}
customTagTypes = builder.build();
}
/**
* Used to ensure that all custom tag types have a defaulted collection when vanilla is initializing a defaulted TagCollectionManager
*
* @apiNote Internal: For use by TagCollectionManager
*/
public static ITagCollectionSupplier populateTagCollectionManager(ITagCollection<Block> blockTags, ITagCollection<Item> itemTags, ITagCollection<Fluid> fluidTags, ITagCollection<EntityType<?>> entityTypeTags)
{
//Default the tag collections
resetCachedTagCollections();
if (!customTagTypes.isEmpty())
{
LOGGER.debug("Populated the TagCollectionManager with {} extra types", customTagTypes.size());
}
return ITagCollectionSupplier.func_242209_a(blockTags, itemTags, fluidTags, entityTypeTags);
}
/**
* Updates the custom tag types' tags from reloading via NetworkTagManager
*
* @apiNote Internal: For use by NetworkTagManager
*/
public static void updateCustomTagTypes(List<TagCollectionReaderInfo> tagCollectionReaders)
{
ImmutableMap.Builder<ResourceLocation, ITagCollection<?>> builder = ImmutableMap.builder();
for (TagCollectionReaderInfo info : tagCollectionReaders)
{
builder.put(info.tagType, info.reader.func_242226_a(info.tagBuilders));
}
customTagTypes = builder.build();
}
/**
* Updates the custom tag types' tags from packet
*
* @apiNote Internal
*/
public static void updateCustomTagTypes(SyncCustomTagTypes packet)
{
customTagTypes = packet.getCustomTagTypes();
}
/**
* Gets the completable future containing the reload results for all custom tag types.
*
* @apiNote Internal: For use by NetworkTagManager
*/
public static CompletableFuture<List<TagCollectionReaderInfo>> getCustomTagTypeReloadResults(IResourceManager resourceManager, Executor backgroundExecutor, Map<ResourceLocation, TagCollectionReader<?>> readers)
{
CompletableFuture<List<TagCollectionReaderInfo>> customResults = CompletableFuture.completedFuture(new ArrayList<>());
for (Map.Entry<ResourceLocation, TagCollectionReader<?>> entry : readers.entrySet())
{
customResults = customResults.thenCombine(entry.getValue().func_242224_a(resourceManager, backgroundExecutor), (results, result) -> {
results.add(new TagCollectionReaderInfo(entry.getKey(), entry.getValue(), result));
return results;
});
}
return customResults;
}
/**
* Helper storage class for keeping track of various data for all custom tag types in the NetworkTagReader to make the code easier to read.
*
* @apiNote Internal: For use by NetworkTagManager
*/
public static class TagCollectionReaderInfo
{
private final ResourceLocation tagType;
private final TagCollectionReader<?> reader;
private final Map<ResourceLocation, ITag.Builder> tagBuilders;
private TagCollectionReaderInfo(ResourceLocation tagType, TagCollectionReader<?> reader, Map<ResourceLocation, ITag.Builder> tagBuilders)
{
this.tagType = tagType;
this.reader = reader;
this.tagBuilders = tagBuilders;
}
}
}

View file

@ -0,0 +1,73 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.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.data.DataGenerator;
import net.minecraft.data.TagsProvider;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.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;
public abstract class ForgeRegistryTagsProvider<T extends IForgeRegistryEntry<T>> extends TagsProvider<T>
{
//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)
{
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.getDefaultKey() == null)
return GameData.getWrapper(forgeRegistry.getRegistryKey(), Lifecycle.experimental());
return GameData.getWrapper(forgeRegistry.getRegistryKey(), Lifecycle.experimental(), "default");
}
private final String folder;
public ForgeRegistryTagsProvider(DataGenerator generatorIn, IForgeRegistry<T> registryIn, String modId, @Nullable ExistingFileHelper existingFileHelper)
{
super(generatorIn, wrapRegistry(registryIn), modId, existingFileHelper);
String tagFolder = ((ForgeRegistry<T>) registryIn).getTagFolder();
folder = tagFolder == null ? vanillaTypes.get(registryIn) : tagFolder;
}
@Override
protected Path makePath(ResourceLocation id)
{
return generator.getOutputFolder().resolve("data/" + id.getNamespace() + "/tags/" + folder + "/" + id.getPath() + ".json");
}
}

View file

@ -21,6 +21,7 @@ package net.minecraftforge.common.extensions;
import net.minecraft.data.TagsProvider;
import net.minecraft.tags.ITag;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
//TODO, Tag removal support.
@ -40,6 +41,14 @@ public interface IForgeTagBuilder<T>
return builder;
}
default TagsProvider.Builder<T> add(RegistryKey<T>... keys) {
TagsProvider.Builder<T> builder = getBuilder();
for (RegistryKey<T> key : keys) {
builder.getInternalBuilder().func_232961_a_(key.func_240901_a_(), getBuilder().getModID());
}
return builder;
}
default TagsProvider.Builder<T> replace() {
return replace(true);
}

View file

@ -0,0 +1,61 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.extensions;
import java.util.Map;
import net.minecraft.tags.ITagCollection;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.ForgeTagHandler;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;
public interface IForgeTagCollectionSupplier
{
/**
* Gets the tag map of registry names to tag collections for the various custom tag types.
*
* @apiNote Prefer using one of the getCustomTypeCollection methods
*/
default Map<ResourceLocation, ITagCollection<?>> getCustomTagTypes()
{
return ForgeTagHandler.getCustomTagTypes();
}
/**
* Gets the {@link ITagCollection} for a forge registry with the given name, or throws an exception if the registry doesn't support custom tag types.
* @param regName Name of the forge registry
* @return The tag collection
*/
default ITagCollection<?> getCustomTypeCollection(ResourceLocation regName)
{
if (!ForgeTagHandler.getCustomTagTypeNames().contains(regName)) throw new IllegalArgumentException("Registry " + regName + ", does not support custom tag types");
return getCustomTagTypes().get(regName);
}
/**
* Gets the {@link ITagCollection} for a forge registry, or throws an exception if the registry doesn't support custom tag types.
* @param reg Forge registry
* @return The tag collection
*/
default <T extends IForgeRegistryEntry<T>> ITagCollection<T> getCustomTypeCollection(IForgeRegistry<T> reg)
{
return (ITagCollection<T>) getCustomTypeCollection(reg.getRegistryName());
}
}

View file

@ -45,4 +45,26 @@ public class TagsUpdatedEvent extends Event
{
return manager;
}
/**
* Fired after the Vanilla Tag types have been processed
*/
public static class VanillaTagTypes extends TagsUpdatedEvent
{
public VanillaTagTypes(ITagCollectionSupplier manager)
{
super(manager);
}
}
/**
* Fired after any custom tag types have been processed
*/
public static class CustomTagTypes extends TagsUpdatedEvent
{
public CustomTagTypes(ITagCollectionSupplier manager)
{
super(manager);
}
}
}

View file

@ -198,6 +198,8 @@ public class ModLoader
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
statusConsumer.ifPresent(c->c.accept("Populating registries"));
dispatchAndHandleError(ModLoadingStage.LOAD_REGISTRIES, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Adding custom tag types"));
GameData.setCustomTagTypesFromRegistries();
statusConsumer.ifPresent(c->c.accept("Early mod loading complete"));
}

View file

@ -19,7 +19,14 @@
package net.minecraftforge.fml.network;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import io.netty.buffer.Unpooled;
import java.util.List;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.IHasContainer;
import net.minecraft.client.gui.ScreenManager;
@ -27,23 +34,36 @@ import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.fluid.Fluid;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.Item;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tags.ITag;
import net.minecraft.tags.ITagCollection;
import net.minecraft.tags.ITagCollectionSupplier;
import net.minecraft.tags.TagRegistryManager;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
import net.minecraft.world.biome.FuzzedBiomeMagnifier;
import net.minecraftforge.common.ForgeTagHandler;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TagsUpdatedEvent;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Supplier;
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 FMLPlayMessages
{
@ -308,4 +328,144 @@ public class FMLPlayMessages
return additionalData;
}
}
public static class SyncCustomTagTypes
{
private static final Logger LOGGER = LogManager.getLogger();
private final Map<ResourceLocation, ITagCollection<?>> customTagTypeCollections;
SyncCustomTagTypes(Map<ResourceLocation, ITagCollection<?>> customTagTypeCollections)
{
this.customTagTypeCollections = customTagTypeCollections;
}
public Map<ResourceLocation, ITagCollection<?>> getCustomTagTypes()
{
return customTagTypeCollections;
}
public static void encode(SyncCustomTagTypes msg, PacketBuffer buf)
{
buf.writeVarInt(msg.customTagTypeCollections.size());
msg.customTagTypeCollections.forEach((registryName, modded) -> forgeTagCollectionWrite(buf, registryName, modded.func_241833_a()));
}
private static <T> void forgeTagCollectionWrite(PacketBuffer buf, ResourceLocation registryName, Map<ResourceLocation, ITag<T>> tags)
{
buf.writeResourceLocation(registryName);
buf.writeVarInt(tags.size());
tags.forEach((name, tag) -> {
buf.writeResourceLocation(name);
List<T> elements = tag.func_230236_b_();
buf.writeVarInt(elements.size());
for (T element : elements)
{
buf.writeResourceLocation(((IForgeRegistryEntry<?>) element).getRegistryName());
}
});
}
public static SyncCustomTagTypes decode(PacketBuffer buf)
{
ImmutableMap.Builder<ResourceLocation, ITagCollection<?>> builder = ImmutableMap.builder();
int size = buf.readVarInt();
for (int i = 0; i < size; i++)
{
ResourceLocation regName = buf.readResourceLocation();
IForgeRegistry<?> registry = RegistryManager.ACTIVE.getRegistry(regName);
if (registry != null)
{
builder.put(regName, readTagCollection(buf, registry));
}
}
return new SyncCustomTagTypes(builder.build());
}
private static <T extends IForgeRegistryEntry<T>> ITagCollection<T> readTagCollection(PacketBuffer buf, IForgeRegistry<T> registry)
{
Map<ResourceLocation, ITag<T>> tags = Maps.newHashMap();
int totalTags = buf.readVarInt();
for (int i = 0; i < totalTags; i++)
{
ImmutableSet.Builder<T> elementBuilder = ImmutableSet.builder();
ResourceLocation name = buf.readResourceLocation();
int totalElements = buf.readVarInt();
for (int j = 0; j < totalElements; j++)
{
T element = registry.getValue(buf.readResourceLocation());
if (element != null)
{
elementBuilder.add(element);
}
}
tags.put(name, ITag.func_232946_a_(elementBuilder.build()));
}
return ITagCollection.func_242202_a(tags);
}
public static void handle(SyncCustomTagTypes msg, Supplier<NetworkEvent.Context> ctx)
{
ctx.get().enqueueWork(() -> {
if (Minecraft.getInstance().world != null)
{
ITagCollectionSupplier tagCollectionSupplier = Minecraft.getInstance().world.getTags();
//Validate that all the tags exist using the tag type collections from the packet
// We mimic vanilla in that we validate before updating the actual stored tags so that it can gracefully fallback
// to the last working set of tags
//Note: We gracefully ignore any tag types the server may have that we don't as they won't be in our tag registry
// so they won't be validated
Multimap<ResourceLocation, ResourceLocation> missingTags = TagRegistryManager.func_242198_b(new ITagCollectionSupplier()
{
@Override
public ITagCollection<Block> func_241835_a()
{
return tagCollectionSupplier.func_241835_a();
}
@Override
public ITagCollection<Item> func_241836_b()
{
return tagCollectionSupplier.func_241836_b();
}
@Override
public ITagCollection<Fluid> func_241837_c()
{
return tagCollectionSupplier.func_241837_c();
}
@Override
public ITagCollection<EntityType<?>> func_241838_d()
{
return tagCollectionSupplier.func_241838_d();
}
@Override
public Map<ResourceLocation, ITagCollection<?>> getCustomTagTypes()
{
//Override and use the tags from the packet to test for validation before we actually set them
return msg.customTagTypeCollections;
}
});
if (missingTags.isEmpty())
{
//If we have no missing tags, update the custom tag types
ForgeTagHandler.updateCustomTagTypes(msg);
if (!ctx.get().getNetworkManager().isLocalChannel())
{
//And if everything hasn't already been set due to being in single player
// Fetch and update the custom tag types. We skip vanilla tag types as they have already been fetched
// And fire an event that the custom tag types have been updated
TagRegistryManager.fetchCustomTagTypes(tagCollectionSupplier);
MinecraftForge.EVENT_BUS.post(new TagsUpdatedEvent.CustomTagTypes(tagCollectionSupplier));
}
} else {
LOGGER.warn("Incomplete server tags, disconnecting. Missing: {}", missingTags);
ctx.get().getNetworkManager().closeChannel(new TranslationTextComponent("multiplayer.disconnect.missing_tags"));
}
}
});
ctx.get().setPacketHandled(true);
}
}
}

View file

@ -19,6 +19,7 @@
package net.minecraftforge.fml.network;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@ -26,6 +27,8 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import net.minecraft.tags.ITagCollection;
import net.minecraft.tags.ITagCollectionSupplier;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.fml.common.thread.EffectiveSide;
import org.apache.logging.log4j.LogManager;
@ -208,4 +211,31 @@ public class NetworkHooks
player.openContainer.addListener(player);
MinecraftForge.EVENT_BUS.post(new PlayerContainerEvent.Open(player, c));
}
/**
* Syncs the custom tag types attached to a {@link ITagCollectionSupplier} to all connected players.
* @param tagCollectionSupplier The tag collection supplier containing the custom tags
*/
public static void syncCustomTagTypes(ITagCollectionSupplier tagCollectionSupplier)
{
Map<ResourceLocation, ITagCollection<?>> customTagTypes = tagCollectionSupplier.getCustomTagTypes();
if (!customTagTypes.isEmpty())
{
FMLNetworkConstants.playChannel.send(PacketDistributor.ALL.noArg(), new FMLPlayMessages.SyncCustomTagTypes(customTagTypes));
}
}
/**
* Syncs the custom tag types attached to a {@link ITagCollectionSupplier} to the given player.
* @param player The player to sync the custom tags to.
* @param tagCollectionSupplier The tag collection supplier containing the custom tags
*/
public static void syncCustomTagTypes(ServerPlayerEntity player, ITagCollectionSupplier tagCollectionSupplier)
{
Map<ResourceLocation, ITagCollection<?>> customTagTypes = tagCollectionSupplier.getCustomTagTypes();
if (!customTagTypes.isEmpty())
{
FMLNetworkConstants.playChannel.sendTo(new FMLPlayMessages.SyncCustomTagTypes(customTagTypes), player.connection.getNetworkManager(), NetworkDirection.PLAY_TO_CLIENT);
}
}
}

View file

@ -105,6 +105,12 @@ class NetworkInitialization {
// .consumer(FMLPlayMessages.DimensionInfoMessage::handle)
// .add();
playChannel.messageBuilder(FMLPlayMessages.SyncCustomTagTypes.class, 3).
decoder(FMLPlayMessages.SyncCustomTagTypes::decode).
encoder(FMLPlayMessages.SyncCustomTagTypes::encode).
consumer(FMLPlayMessages.SyncCustomTagTypes::handle).
add();
return playChannel;
}

View file

@ -91,6 +91,8 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
private final int max;
private final boolean allowOverrides;
private final boolean isModifiable;
@Nullable
private final String tagFolder;
private V defaultValue = null;
boolean isFrozen = false;
@ -120,6 +122,7 @@ 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();
if (this.create != null)
this.create.onCreate(this, stage);
}
@ -175,6 +178,12 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
return superType;
}
@Nullable
public String getTagFolder()
{
return tagFolder;
}
@Override
public void registerAll(@SuppressWarnings("unchecked") V... values)
{

View file

@ -22,6 +22,8 @@ package net.minecraftforge.registries;
import com.google.common.collect.*;
import com.mojang.serialization.Lifecycle;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.block.AirBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -47,6 +49,7 @@ import net.minecraft.potion.Effect;
import net.minecraft.potion.Potion;
import net.minecraft.state.StateContainer;
import net.minecraft.stats.StatType;
import net.minecraft.tags.TagRegistryManager;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ObjectIntIdentityMap;
import net.minecraft.util.RegistryKey;
@ -68,6 +71,7 @@ import net.minecraft.world.gen.foliageplacer.FoliagePlacerType;
import net.minecraft.world.gen.placement.Placement;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
import net.minecraft.world.gen.treedecorator.TreeDecoratorType;
import net.minecraftforge.common.ForgeTagHandler;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
import net.minecraftforge.event.RegistryEvent;
@ -175,7 +179,7 @@ public class GameData
makeRegistry(TREE_DECORATOR_TYPES, c(TreeDecoratorType.class)).disableSaving().disableSync().create();
// Dynamic Worldgen
makeRegistry(BIOMES, Biome.class).create();
makeRegistry(BIOMES, Biome.class).tagFolder("biomes").create();
// Custom forge registries
makeRegistry(DATA_SERIALIZERS, DataSerializerEntry.class, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides().addCallback(SerializerCallbacks.INSTANCE).create();
@ -190,11 +194,11 @@ public class GameData
}
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(RegistryKey<? extends Registry<T>> key, Class<T> type, int min, int max)
{
return new RegistryBuilder<T>().setName(key.func_240901_a_()).setType(type).setIDRange(min, max).addCallback(new NamespacedWrapper.Factory<T>());
return new RegistryBuilder<T>().setName(key.func_240901_a_()).setType(type).setIDRange(min, max).hasWrapper();
}
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(RegistryKey<? extends Registry<T>> key, Class<T> type, String _default)
{
return new RegistryBuilder<T>().setName(key.func_240901_a_()).setType(type).setMaxID(MAX_VARINT).addCallback(new NamespacedDefaultedWrapper.Factory<T>()).setDefaultKey(new ResourceLocation(_default));
return new RegistryBuilder<T>().setName(key.func_240901_a_()).setType(type).setMaxID(MAX_VARINT).hasWrapper().setDefaultKey(new ResourceLocation(_default));
}
public static <T extends IForgeRegistryEntry<T>> SimpleRegistry<T> getWrapper(RegistryKey<? extends Registry<T>> key, Lifecycle lifecycle)
@ -360,6 +364,22 @@ public class GameData
};
}
public static void setCustomTagTypesFromRegistries()
{
Set<ResourceLocation> customTagTypes = new HashSet<>();
for (Map.Entry<ResourceLocation, ForgeRegistry<? extends IForgeRegistryEntry<?>>> entry : RegistryManager.ACTIVE.registries.entrySet())
{
ResourceLocation registryName = entry.getKey();
if (entry.getValue().getTagFolder() != null && TagRegistryManager.get(registryName) == null)
{
LOGGER.debug(REGISTRIES, "Registering custom tag type for: {}", registryName);
customTagTypes.add(registryName);
TagRegistryManager.func_242196_a(registryName, tagCollectionSupplier -> tagCollectionSupplier.getCustomTypeCollection(registryName));
}
}
ForgeTagHandler.setCustomTagTypes(customTagTypes);
}
//Lets us clear the map so we can rebuild it.
private static class ClearableObjectIntIdentityMap<I> extends ObjectIntIdentityMap<I>
{

View file

@ -48,6 +48,9 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
private boolean sync = true;
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<>();
@ -203,6 +206,21 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
return this;
}
RegistryBuilder<T> hasWrapper()
{
this.hasWrapper = true;
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));
@ -216,6 +234,13 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
public IForgeRegistry<T> create()
{
if (hasWrapper)
{
if (getDefault() == null)
addCallback(new NamespacedWrapper.Factory<T>());
else
addCallback(new NamespacedDefaultedWrapper.Factory<T>());
}
return RegistryManager.ACTIVE.createRegistry(registryName, this);
}
@ -325,6 +350,12 @@ public class RegistryBuilder<T extends IForgeRegistryEntry<T>>
return allowModifications;
}
@Nullable
public String getTagFolder()
{
return tagFolder;
}
@Nullable
public DummyFactory<T> getDummyFactory()
{

View file

@ -66,7 +66,7 @@ import java.util.List;
@Mod(GlobalLootModifiersTest.MODID)
public class GlobalLootModifiersTest {
public static final String MODID = "global_loot_test";
public static final boolean ENABLE = false;
public static final boolean ENABLE = true;
public GlobalLootModifiersTest()
{

View file

@ -0,0 +1,114 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.debug.misc;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import net.minecraft.data.DataGenerator;
import net.minecraft.tags.ITag;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraftforge.common.ForgeTagHandler;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.common.data.ForgeRegistryTagsProvider;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistryEntry;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.RegistryBuilder;
@Mod(CustomTagTypesTest.MODID)
public class CustomTagTypesTest
{
public static final String MODID = "custom_tag_types_test";
private static final ResourceLocation customRegistryName = new ResourceLocation(MODID, "custom_type_registry");
private static final DeferredRegister<Custom> CUSTOMS = DeferredRegister.create(Custom.class, MODID);
private static final RegistryObject<Custom> CUSTOM = CUSTOMS.register("custom", Custom::new);
private static final Supplier<IForgeRegistry<Custom>> CUSTOM_REG = CUSTOMS.makeRegistry(customRegistryName.getPath(),
() -> new RegistryBuilder<Custom>().tagFolder(MODID + "/custom_types"));
private static final ITag.INamedTag<Biome> OCEANS = ForgeTagHandler.makeWrapperTag(ForgeRegistries.BIOMES, new ResourceLocation(MODID, "oceans"));
private static final ITag.INamedTag<Custom> TESTS = ForgeTagHandler.makeWrapperTag(customRegistryName, new ResourceLocation(MODID, "tests"));
public CustomTagTypesTest()
{
IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus();
CUSTOMS.register(modBus);
modBus.addListener(this::gatherData);
}
private void gatherData(GatherDataEvent event)
{
if (event.includeServer())
{
DataGenerator gen = event.getGenerator();
ExistingFileHelper existingFileHelper = event.getExistingFileHelper();
gen.addProvider(new BiomeTags(gen, existingFileHelper));
gen.addProvider(new CustomRegistryTags(gen, existingFileHelper));
}
}
public static class Custom extends ForgeRegistryEntry<Custom> {
}
public static class BiomeTags extends ForgeRegistryTagsProvider<Biome>
{
public BiomeTags(DataGenerator gen, @Nullable ExistingFileHelper existingFileHelper)
{
super(gen, ForgeRegistries.BIOMES, MODID, existingFileHelper);
}
@Override
protected void registerTags()
{
func_240522_a_(OCEANS).add(Biomes.OCEAN, Biomes.FROZEN_OCEAN, Biomes.DEEP_OCEAN, Biomes.WARM_OCEAN, Biomes.LUKEWARM_OCEAN,
Biomes.COLD_OCEAN, Biomes.DEEP_WARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN, Biomes.DEEP_COLD_OCEAN, Biomes.DEEP_FROZEN_OCEAN);
}
@Override
public String getName() {
return "Biome Tags";
}
}
public static class CustomRegistryTags extends ForgeRegistryTagsProvider<Custom>
{
public CustomRegistryTags(DataGenerator gen, @Nullable ExistingFileHelper existingFileHelper)
{
super(gen, CUSTOM_REG.get(), MODID, existingFileHelper);
}
@Override
protected void registerTags()
{
func_240522_a_(TESTS).func_240532_a_(CUSTOM.get());
}
@Override
public String getName() {
return "Custom Registry Tags";
}
}
}

View file

@ -82,3 +82,5 @@ license="LGPL v2.1"
modId="finite_water_test"
[[mods]]
modId="scaffolding_test"
[[mods]]
modId="custom_tag_types_test"