From ebd24f870fd515e67cc2f8d35867f1b5439bdf54 Mon Sep 17 00:00:00 2001
From: modmuss50 <modmuss50@gmail.com>
Date: Wed, 23 Feb 2022 16:17:26 +0000
Subject: [PATCH] Misc FabricTagProvider fixes and improvements. (#2019)

* Misc tag data gen fixes.

* Fix backwards compat issue.
---
 .../v1/provider/FabricTagProvider.java        | 43 +++++++++++++++----
 .../fabric/impl/datagen/ForcedTagEntry.java   | 43 +++++++++++++++++++
 .../datagen/AbstractTagProviderMixin.java     | 38 ++++++++++++++++
 ...abric-data-generation-api-v1.accesswidener |  2 +
 .../fabric-data-generation-api-v1.mixins.json |  1 +
 .../datagen/DataGeneratorTestEntrypoint.java  |  8 ++--
 .../template.accesswidener                    |  2 +
 7 files changed, 124 insertions(+), 13 deletions(-)
 create mode 100644 fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/ForcedTagEntry.java
 create mode 100644 fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/AbstractTagProviderMixin.java

diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricTagProvider.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricTagProvider.java
index fb9b7d581..a189f0d81 100644
--- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricTagProvider.java
+++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricTagProvider.java
@@ -45,6 +45,7 @@ import net.minecraft.world.event.GameEvent;
 
 import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
 import net.fabricmc.fabric.impl.datagen.FabricDataGenHelper;
+import net.fabricmc.fabric.impl.datagen.ForcedTagEntry;
 import net.fabricmc.fabric.mixin.datagen.DynamicRegistryManagerAccessor;
 
 /**
@@ -62,6 +63,7 @@ import net.fabricmc.fabric.mixin.datagen.DynamicRegistryManagerAccessor;
  * @see DynamicRegistryTagProvider
  */
 public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
+	private final FabricDataGenerator fabricDataGenerator;
 	private final String path;
 	private final String name;
 
@@ -91,7 +93,8 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 	@SuppressWarnings({"unchecked", "rawtypes"})
 	protected FabricTagProvider(FabricDataGenerator dataGenerator, Registry<T> registry, String path, String name) {
 		super(dataGenerator, registry);
-		this.path = path;
+		this.fabricDataGenerator = dataGenerator;
+		this.path = path.startsWith("tags/") ? path : "tags/" + path;
 		this.name = name;
 
 		if (!(this instanceof DynamicRegistryTagProvider) && BuiltinRegistries.REGISTRIES.contains((RegistryKey) registry.getKey())) {
@@ -117,7 +120,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 
 	@Override
 	protected Path getOutput(Identifier id) {
-		return this.root.getOutput().resolve("data/%s/tags/%s/%s.json".formatted(id.getNamespace(), path, id.getPath()));
+		return this.root.getOutput().resolve("data/%s/%s/%s.json".formatted(id.getNamespace(), path, id.getPath()));
 	}
 
 	@Override
@@ -135,7 +138,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 	 */
 	public abstract static class BlockTagProvider extends FabricTagProvider<Block> {
 		public BlockTagProvider(FabricDataGenerator dataGenerator) {
-			super(dataGenerator, Registry.BLOCK, "blocks", "Block Tags");
+			super(dataGenerator, Registry.BLOCK, "Block Tags");
 		}
 	}
 
@@ -152,7 +155,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 		 * @param dataGenerator a {@link ItemTagProvider} tag provider
 		 */
 		public ItemTagProvider(FabricDataGenerator dataGenerator, @Nullable FabricTagProvider.BlockTagProvider blockTagProvider) {
-			super(dataGenerator, Registry.ITEM, "items", "Item Tags");
+			super(dataGenerator, Registry.ITEM, "Item Tags");
 
 			this.blockTagBuilderProvider = blockTagProvider == null ? null : blockTagProvider::getTagBuilder;
 		}
@@ -188,7 +191,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 	 */
 	public abstract static class FluidTagProvider extends FabricTagProvider<Fluid> {
 		public FluidTagProvider(FabricDataGenerator dataGenerator) {
-			super(dataGenerator, Registry.FLUID, "fluids", "Fluid Tags");
+			super(dataGenerator, Registry.FLUID, "Fluid Tags");
 		}
 	}
 
@@ -197,7 +200,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 	 */
 	public abstract static class EntityTypeTagProvider extends FabricTagProvider<EntityType<?>> {
 		public EntityTypeTagProvider(FabricDataGenerator dataGenerator) {
-			super(dataGenerator, Registry.ENTITY_TYPE, "entity_types", "Entity Type Tags");
+			super(dataGenerator, Registry.ENTITY_TYPE, "Entity Type Tags");
 		}
 	}
 
@@ -206,7 +209,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 	 */
 	public abstract static class GameEventTagProvider extends FabricTagProvider<GameEvent> {
 		public GameEventTagProvider(FabricDataGenerator dataGenerator) {
-			super(dataGenerator, Registry.GAME_EVENT, "game_events", "Game Event Tags");
+			super(dataGenerator, Registry.GAME_EVENT, "Game Event Tags");
 		}
 	}
 
@@ -296,6 +299,15 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 			return this;
 		}
 
+		/**
+		 * Add an optional {@link RegistryKey} to the tag.
+		 *
+		 * @return the {@link FabricTagBuilder} instance
+		 */
+		public FabricTagBuilder<T> addOptional(RegistryKey<? extends T> registryKey) {
+			return addOptional(registryKey.getValue());
+		}
+
 		/**
 		 * Add another tag to this tag.
 		 *
@@ -313,7 +325,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 		 */
 		@Override
 		public FabricTagBuilder<T> addTag(TagKey<T> tag) {
-			builder.add(tag.id(), source);
+			builder.addTag(tag.id(), source);
 			return this;
 		}
 
@@ -328,6 +340,15 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 			return this;
 		}
 
+		/**
+		 * Add another optional tag to this tag.
+		 *
+		 * @return the {@link FabricTagBuilder} instance
+		 */
+		public FabricTagBuilder<T> addOptionalTag(TagKey<T> tag) {
+			return addOptional(tag.id());
+		}
+
 		/**
 		 * Add another tag to this tag, ignoring any warning.
 		 *
@@ -337,7 +358,7 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 		 * @return the {@link FabricTagBuilder} instance
 		 */
 		public FabricTagBuilder<T> forceAddTag(TagKey<T> tag) {
-			builder.add(tag.id(), source);
+			builder.add(new ForcedTagEntry(new Tag.TagEntry(tag.id())), source);
 			return this;
 		}
 
@@ -392,4 +413,8 @@ public abstract class FabricTagProvider<T> extends AbstractTagProvider<T> {
 			}
 		}
 	}
+
+	public FabricDataGenerator getFabricDataGenerator() {
+		return fabricDataGenerator;
+	}
 }
diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/ForcedTagEntry.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/ForcedTagEntry.java
new file mode 100644
index 000000000..bbfd21e1b
--- /dev/null
+++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/ForcedTagEntry.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.datagen;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import com.google.gson.JsonArray;
+
+import net.minecraft.tag.Tag;
+import net.minecraft.util.Identifier;
+
+public record ForcedTagEntry(Tag.Entry delegate) implements Tag.Entry {
+	@Override
+	public <T> boolean resolve(Function<Identifier, Tag<T>> tagGetter, Function<Identifier, T> objectGetter, Consumer<T> collector) {
+		return delegate.resolve(tagGetter, objectGetter, collector);
+	}
+
+	@Override
+	public void addToJson(JsonArray json) {
+		delegate.addToJson(json);
+	}
+
+	@Override
+	public boolean canAdd(Predicate<Identifier> objectExistsTest, Predicate<Identifier> tagExistsTest) {
+		return true;
+	}
+}
diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/AbstractTagProviderMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/AbstractTagProviderMixin.java
new file mode 100644
index 000000000..a600a9724
--- /dev/null
+++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/AbstractTagProviderMixin.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.datagen;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+
+import net.minecraft.data.server.AbstractTagProvider;
+
+import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
+
+@Mixin(AbstractTagProvider.class)
+public class AbstractTagProviderMixin {
+	@ModifyArg(method = "getOrCreateTagBuilder", index = 2, at = @At(value = "INVOKE", target = "Lnet/minecraft/data/server/AbstractTagProvider$ObjectBuilder;<init>(Lnet/minecraft/tag/Tag$Builder;Lnet/minecraft/util/registry/Registry;Ljava/lang/String;)V"))
+	private String injectModId(String str) {
+		//noinspection ConstantConditions
+		if ((Object) (this) instanceof FabricTagProvider fabricTagProvider) {
+			return fabricTagProvider.getFabricDataGenerator().getModId();
+		}
+
+		return str;
+	}
+}
diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener
index fce8746dd..9790a62c0 100644
--- a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener
+++ b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener
@@ -12,6 +12,8 @@ accessible  field   net/minecraft/data/server/AbstractTagProvider   tagBuilders
 
 accessible  field   net/minecraft/data/server/BlockLootTableGenerator   lootTables  Ljava/util/Map;
 
+accessible    class    net/minecraft/tag/Tag$TagEntry
+
 transitive-accessible   method  net/minecraft/data/family/BlockFamilies register    (Lnet/minecraft/block/Block;)Lnet/minecraft/data/family/BlockFamily$Builder;
 
 transitive-accessible    method    net/minecraft/data/client/ItemModelGenerator    register    (Lnet/minecraft/item/Item;Lnet/minecraft/data/client/Model;)V
diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json
index f58a88a30..01b878025 100644
--- a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json
+++ b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.mixins.json
@@ -3,6 +3,7 @@
   "package": "net.fabricmc.fabric.mixin.datagen",
   "compatibilityLevel": "JAVA_16",
   "mixins": [
+    "AbstractTagProviderMixin",
     "ModelProviderMixin",
     "DynamicRegistryManagerAccessor",
     "TagBuilderMixin"
diff --git a/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java b/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java
index 09a79216b..afa2165c7 100644
--- a/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java
+++ b/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java
@@ -27,10 +27,9 @@ import net.minecraft.advancement.Advancement;
 import net.minecraft.advancement.AdvancementFrame;
 import net.minecraft.advancement.criterion.OnKilledCriterion;
 import net.minecraft.data.client.BlockStateModelGenerator;
-import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
-import net.minecraft.tag.TagKey;
 import net.minecraft.data.client.ItemModelGenerator;
 import net.minecraft.data.server.recipe.RecipeJsonProvider;
+import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
 import net.minecraft.item.Items;
 import net.minecraft.loot.LootPool;
 import net.minecraft.loot.LootTable;
@@ -40,6 +39,7 @@ import net.minecraft.loot.entry.ItemEntry;
 import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
 import net.minecraft.tag.BlockTags;
 import net.minecraft.tag.ItemTags;
+import net.minecraft.tag.TagKey;
 import net.minecraft.text.TranslatableText;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.registry.BuiltinRegistries;
@@ -76,7 +76,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
 		dataGenerator.addProvider(TestBiomeTagProvider::new);
 
 		try {
-			new FabricTagProvider<>(dataGenerator, BuiltinRegistries.BIOME, "biomes", "Biome Tags") {
+			new FabricTagProvider<>(dataGenerator, BuiltinRegistries.BIOME, "Biome Tags") {
 				@Override
 				protected void generateTags() {
 				}
@@ -147,7 +147,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
 		protected void generateTags() {
 			getOrCreateTagBuilder(BlockTags.FIRE).add(SIMPLE_BLOCK);
 			getOrCreateTagBuilder(BlockTags.ANVIL).setReplace(true).add(SIMPLE_BLOCK, BLOCK_WITHOUT_ITEM);
-			getOrCreateTagBuilder(BlockTags.ACACIA_LOGS).addTag(BlockTags.ANIMALS_SPAWNABLE_ON);
+			getOrCreateTagBuilder(BlockTags.ACACIA_LOGS).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON);
 		}
 	}
 
diff --git a/fabric-data-generation-api-v1/template.accesswidener b/fabric-data-generation-api-v1/template.accesswidener
index e0f496f95..4d5054b4e 100644
--- a/fabric-data-generation-api-v1/template.accesswidener
+++ b/fabric-data-generation-api-v1/template.accesswidener
@@ -12,6 +12,8 @@ accessible  field   net/minecraft/data/server/AbstractTagProvider   tagBuilders
 
 accessible  field   net/minecraft/data/server/BlockLootTableGenerator   lootTables  Ljava/util/Map;
 
+accessible    class    net/minecraft/tag/Tag$TagEntry
+
 transitive-accessible   method  net/minecraft/data/family/BlockFamilies register    (Lnet/minecraft/block/Block;)Lnet/minecraft/data/family/BlockFamily$Builder;
 
 transitive-accessible    method    net/minecraft/data/client/ItemModelGenerator    register    (Lnet/minecraft/item/Item;Lnet/minecraft/data/client/Model;)V