From 738bc5d4289614828610c69ed881159e6c99a8d4 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Fri, 1 Nov 2024 03:27:23 +0200 Subject: [PATCH 01/21] Add tag aliases --- fabric-data-generation-api-v1/build.gradle | 1 + .../v1/provider/FabricTagProvider.java | 82 +++++++++ .../impl/datagen/TagAliasGenerator.java | 49 ++++++ .../mixin/datagen/TagProviderMixin.java | 51 +++++- .../src/main/resources/fabric.mod.json | 3 +- fabric-tag-api-v1/build.gradle | 10 ++ .../fabric/api/tag/v1/TagAliasGroup.java | 56 +++++++ .../fabric/api/tag/v1/package-info.java | 22 +++ .../impl/tag/SimpleRegistryExtension.java | 21 +++ .../impl/tag/TagAliasEnabledRegistry.java | 26 +++ .../fabric/impl/tag/TagAliasLoader.java | 156 ++++++++++++++++++ .../net/fabricmc/fabric/impl/tag/TagInit.java | 29 ++++ .../mixin/tag/SimpleRegistry2Mixin.java | 40 +++++ .../mixin/tag/SimpleRegistry3Mixin.java | 40 +++++ .../fabric/mixin/tag/SimpleRegistryMixin.java | 97 +++++++++++ .../assets/fabric-tag-api-v1/icon.png | Bin 0 -> 1579 bytes .../resources/fabric-tag-api-v1.accesswidener | 3 + .../resources/fabric-tag-api-v1.mixins.json | 13 ++ .../src/main/resources/fabric.mod.json | 36 ++++ .../src/testmod/resources/fabric.mod.json | 15 ++ gradle.properties | 1 + settings.gradle | 1 + 22 files changed, 750 insertions(+), 2 deletions(-) create mode 100644 fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java create mode 100644 fabric-tag-api-v1/build.gradle create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagInit.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java create mode 100644 fabric-tag-api-v1/src/main/resources/assets/fabric-tag-api-v1/icon.png create mode 100644 fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.accesswidener create mode 100644 fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json create mode 100644 fabric-tag-api-v1/src/main/resources/fabric.mod.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/fabric.mod.json diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 60560e7edd..07d4bf621d 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -7,6 +7,7 @@ moduleDependencies(project, [ 'fabric-networking-api-v1', 'fabric-resource-conditions-api-v1', 'fabric-item-group-api-v1', + 'fabric-tag-api-v1', 'fabric-recipe-api-v1' ]) 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 cac205fc07..bf2b9bac76 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 @@ -16,6 +16,11 @@ package net.fabricmc.fabric.api.datagen.v1.provider; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -70,6 +75,9 @@ * @see EntityTypeTagProvider */ public abstract class FabricTagProvider extends TagProvider { + private final FabricDataOutput output; + private final Map aliasGroupBuilders = new HashMap<>(); + /** * Constructs a new {@link FabricTagProvider} with the default computed path. * @@ -80,6 +88,7 @@ public abstract class FabricTagProvider extends TagProvider { */ public FabricTagProvider(FabricDataOutput output, RegistryKey> registryKey, CompletableFuture registriesFuture) { super(output, registryKey, registriesFuture); + this.output = output; } /** @@ -116,6 +125,34 @@ protected FabricTagBuilder getOrCreateTagBuilder(TagKey tag) { return new FabricTagBuilder(super.getOrCreateTagBuilder(tag)); } + /** + * Gets an {@link AliasGroupBuilder} with the given ID. + * + * @param groupId the group ID + * @return the alias group builder + */ + protected AliasGroupBuilder getOrCreateAliasGroupBuilder(Identifier groupId) { + return aliasGroupBuilders.computeIfAbsent(groupId, key -> new AliasGroupBuilder()); + } + + /** + * Gets an {@link AliasGroupBuilder} with the given ID. + * + * @param group the group name + * @return the alias group builder + */ + protected AliasGroupBuilder getOrCreateAliasGroupBuilder(String group) { + Identifier groupId = Identifier.of(output.getModId(), group); + return aliasGroupBuilders.computeIfAbsent(groupId, key -> new AliasGroupBuilder()); + } + + /** + * {@return a read-only map of alias group builders by the alias group ID} + */ + public Map getAliasGroupBuilders() { + return Collections.unmodifiableMap(aliasGroupBuilders); + } + /** * Extend this class to create {@link Block} tags in the "/blocks" tag directory. */ @@ -396,4 +433,49 @@ public final FabricTagBuilder add(RegistryKey... registryKeys) { return this; } } + + /** + * A builder for tag alias groups. + */ + public final class AliasGroupBuilder { + private final List> tags = new ArrayList<>(); + + /** + * {@return a read-only list of the tags in this alias group} + */ + public List> getTags() { + return Collections.unmodifiableList(tags); + } + + public AliasGroupBuilder add(TagKey tag) { + if (tag.registryRef() != registryRef) { + throw new IllegalArgumentException("Tag " + tag + " isn't from the registry " + registryRef); + } + + this.tags.add(tag); + return this; + } + + @SafeVarargs + public final AliasGroupBuilder add(TagKey... tags) { + for (TagKey tag : tags) { + add(tag); + } + + return this; + } + + public AliasGroupBuilder add(Identifier tag) { + this.tags.add(TagKey.of(registryRef, tag)); + return this; + } + + public AliasGroupBuilder add(Identifier... tags) { + for (Identifier tag : tags) { + this.tags.add(TagKey.of(registryRef, tag)); + } + + return this; + } + } } diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java new file mode 100644 index 0000000000..6d9ce45902 --- /dev/null +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java @@ -0,0 +1,49 @@ +/* + * 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.nio.file.Path; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import net.minecraft.data.DataOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.DataWriter; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.tag.v1.TagAliasGroup; + +public final class TagAliasGenerator { + public static String getDirectory(RegistryKey> registryKey) { + String directory = "fabric/tag_aliases/"; + Identifier registryId = registryKey.getValue(); + + if (!Identifier.DEFAULT_NAMESPACE.equals(registryId.getNamespace())) { + directory += registryId.getNamespace() + '/'; + } + + return directory + registryId.getPath(); + } + + public static CompletableFuture writeTagAlias(DataWriter writer, DataOutput.PathResolver pathResolver, RegistryKey> registryRef, Identifier groupId, List> tags) { + Path path = pathResolver.resolveJson(groupId); + return DataProvider.writeCodecToPath(writer, TagAliasGroup.codec(registryRef), new TagAliasGroup<>(tags), path); + } +} diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/TagProviderMixin.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/TagProviderMixin.java index 3ae2955117..2a1fcd0074 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/TagProviderMixin.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/mixin/datagen/TagProviderMixin.java @@ -16,18 +16,48 @@ package net.fabricmc.fabric.mixin.datagen; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraft.data.DataOutput; +import net.minecraft.data.DataWriter; import net.minecraft.data.server.tag.TagProvider; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; import net.minecraft.registry.tag.TagBuilder; +import net.minecraft.util.Identifier; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.fabricmc.fabric.impl.datagen.FabricTagBuilder; +import net.fabricmc.fabric.impl.datagen.TagAliasGenerator; @Mixin(TagProvider.class) -public class TagProviderMixin { +public class TagProviderMixin { + @Shadow + @Final + protected RegistryKey> registryRef; + + @Unique + private DataOutput.PathResolver tagAliasPathResolver; + + @Inject(method = "(Lnet/minecraft/data/DataOutput;Lnet/minecraft/registry/RegistryKey;Ljava/util/concurrent/CompletableFuture;Ljava/util/concurrent/CompletableFuture;)V", at = @At("RETURN")) + private void initPathResolver(DataOutput output, RegistryKey> registryRef, CompletableFuture registriesFuture, CompletableFuture parentTagLookupFuture, CallbackInfo info) { + tagAliasPathResolver = output.getResolver(DataOutput.OutputType.DATA_PACK, TagAliasGenerator.getDirectory(registryRef)); + } + @ModifyArg(method = "method_27046", at = @At(value = "INVOKE", target = "Lnet/minecraft/registry/tag/TagFile;(Ljava/util/List;Z)V"), index = 1) private boolean addReplaced(boolean replaced, @Local TagBuilder tagBuilder) { if (tagBuilder instanceof FabricTagBuilder fabricTagBuilder) { @@ -36,4 +66,23 @@ private boolean addReplaced(boolean replaced, @Local TagBuilder tagBuilder) { return replaced; } + + @SuppressWarnings("unchecked") + @WrapOperation(method = "method_49659", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;allOf([Ljava/util/concurrent/CompletableFuture;)Ljava/util/concurrent/CompletableFuture;")) + private CompletableFuture addTagAliasGroupBuilders(CompletableFuture[] futures, Operation> original, @Local(argsOnly = true) DataWriter writer) { + if ((Object) this instanceof FabricTagProvider) { + // Note: no pattern matching instanceof so that we can cast directly to FabricTagProvider instead of a wildcard + Map.AliasGroupBuilder> builders = ((FabricTagProvider) (Object) this).getAliasGroupBuilders(); + CompletableFuture[] newFutures = Arrays.copyOf(futures, futures.length + builders.size()); + int index = futures.length; + + for (Map.Entry.AliasGroupBuilder> entry : builders.entrySet()) { + newFutures[index++] = TagAliasGenerator.writeTagAlias(writer, tagAliasPathResolver, registryRef, entry.getKey(), entry.getValue().getTags()); + } + + return original.call((Object) newFutures); + } else { + return original.call((Object) futures); + } + } } diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric.mod.json b/fabric-data-generation-api-v1/src/main/resources/fabric.mod.json index 8f1a7a6ed0..cff1a04de7 100644 --- a/fabric-data-generation-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-data-generation-api-v1/src/main/resources/fabric.mod.json @@ -16,7 +16,8 @@ "FabricMC" ], "depends": { - "fabricloader": ">=0.16.8" + "fabricloader": ">=0.16.8", + "fabric-tag-api-v1": "*" }, "description": "Allows for automatic data generation.", "mixins": [ diff --git a/fabric-tag-api-v1/build.gradle b/fabric-tag-api-v1/build.gradle new file mode 100644 index 0000000000..a9a380ad4a --- /dev/null +++ b/fabric-tag-api-v1/build.gradle @@ -0,0 +1,10 @@ +version = getSubprojectVersion(project) + +loom { + accessWidenerPath = file('src/main/resources/fabric-tag-api-v1.accesswidener') +} + +moduleDependencies(project, [ + 'fabric-api-base', + 'fabric-resource-loader-v0' +]) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java new file mode 100644 index 0000000000..25cfcdb9ff --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java @@ -0,0 +1,56 @@ +/* + * 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.api.tag.v1; + +import java.util.List; + +import com.mojang.serialization.Codec; + +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.tag.TagKey; + +/** + * A group of tags that refer to the same set of registry entries. + * + *

Tag alias groups can be defined in data packs in the {@code data//fabric/tag_aliases/} + * directory. {@code } is the path of the registry's ID, prefixed with {@code /} if it's + * not {@value net.minecraft.util.Identifier#DEFAULT_NAMESPACE}. + * + *

The JSON format of tag alias groups is an object with a {@code tags} list containing plain tag IDs. + * + *

If multiple tag alias groups include a tag, the groups will be combined and each tag will be an alias + * for the same contents. + * + * @param tags the tags in the group, must be from the same registry + * @param the type of registry entries in the tags + */ +public record TagAliasGroup(List> tags) { + /** + * {@return the codec for tag alias groups in the specified registry} + * + * @param registryKey the key of the registry where the tags are from + * @param the entry type + */ + public static Codec> codec(RegistryKey> registryKey) { + return TagKey.unprefixedCodec(registryKey) + .listOf() + .fieldOf("tags") + .xmap(TagAliasGroup::new, TagAliasGroup::tags) + .codec(); + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java new file mode 100644 index 0000000000..22d56f5be4 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * The Fabric Tag API for working with {@linkplain net.minecraft.registry.tag.TagKey tags}. + * + * @see net.fabricmc.fabric.api.tag.v1.TagAliasGroup + */ +package net.fabricmc.fabric.api.tag.v1; diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java new file mode 100644 index 0000000000..661beb0c9e --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java @@ -0,0 +1,21 @@ +/* + * 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.tag; + +public interface SimpleRegistryExtension extends TagAliasEnabledRegistry { + void fabric_applyPendingTagAliases(); +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java new file mode 100644 index 0000000000..50eb6f576c --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java @@ -0,0 +1,26 @@ +/* + * 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.tag; + +import java.util.Map; +import java.util.Set; + +import net.minecraft.registry.tag.TagKey; + +public interface TagAliasEnabledRegistry { + void fabric_applyTagAliases(Map, Set>> aliasGroups); +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java new file mode 100644 index 0000000000..65b46c8382 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -0,0 +1,156 @@ +/* + * 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.tag; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceFinder; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.SinglePreparationResourceReloader; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; + +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; +import net.fabricmc.fabric.api.tag.v1.TagAliasGroup; + +public final class TagAliasLoader extends SinglePreparationResourceReloader>, List>> implements IdentifiableResourceReloadListener { + public static final Identifier ID = Identifier.of("fabric-tag-api-v1", "tag_alias_groups"); + + private static final Logger LOGGER = LoggerFactory.getLogger(TagAliasLoader.class); + private final RegistryWrapper.WrapperLookup registries; + + public TagAliasLoader(RegistryWrapper.WrapperLookup registries) { + this.registries = registries; + } + + @Override + public Identifier getFabricId() { + return ID; + } + + @SuppressWarnings("unchecked") + @Override + protected Map>, List> prepare(ResourceManager manager, Profiler profiler) { + Map>, List> dataByRegistry = new HashMap<>(); + Iterator>> registryIterator = registries.streamAllRegistryKeys().iterator(); + + while (registryIterator.hasNext()) { + RegistryKey> registryKey = registryIterator.next(); + ResourceFinder resourceFinder = ResourceFinder.json(getDirectory(registryKey)); + + for (Map.Entry entry : resourceFinder.findResources(manager).entrySet()) { + Identifier resourcePath = entry.getKey(); + Identifier groupId = resourceFinder.toResourceId(resourcePath); + + try (Reader reader = entry.getValue().getReader()) { + JsonElement json = JsonParser.parseReader(reader); + Codec> codec = TagAliasGroup.codec((RegistryKey>) registryKey); + + switch (codec.parse(JsonOps.INSTANCE, json)) { + case DataResult.Success(TagAliasGroup group, Lifecycle unused) -> { + var data = new Data(groupId, group); + dataByRegistry.computeIfAbsent(registryKey, key -> new ArrayList<>()).add(data); + } + case DataResult.Error> error -> { + LOGGER.error("[Fabric] Couldn't parse tag alias group file '{}' from '{}': {}", groupId, resourcePath, error.message()); + } + } + } catch (IOException | JsonParseException e) { + LOGGER.error("[Fabric] Couldn't parse tag alias group file '{}' from '{}'", groupId, resourcePath, e); + } + } + } + + return dataByRegistry; + } + + private static String getDirectory(RegistryKey> registryKey) { + String directory = "fabric/tag_aliases/"; + Identifier registryId = registryKey.getValue(); + + if (!Identifier.DEFAULT_NAMESPACE.equals(registryId.getNamespace())) { + directory += registryId.getNamespace() + '/'; + } + + return directory + registryId.getPath(); + } + + @Override + protected void apply(Map>, List> prepared, ResourceManager manager, Profiler profiler) { + for (Map.Entry>, List> entry : prepared.entrySet()) { + Map, Set>> groupsByTag = new HashMap<>(); + + for (Data data : entry.getValue()) { + Set> group = new HashSet<>(data.group.tags()); + + for (TagKey tag : data.group.tags()) { + Set> oldGroup = groupsByTag.get(tag); + + // If there's an old group... + if (oldGroup != null) { + // ...merge all of its tags into the current group... + group.addAll(oldGroup); + + // ...and replace the recorded group of each tag in the old group with the new group. + for (TagKey other : oldGroup) { + groupsByTag.put(other, group); + } + } + + groupsByTag.put(tag, group); + } + } + + // Remove any groups of one tag, we don't need to apply them. + groupsByTag.values().removeIf(tags -> tags.size() == 1); + + RegistryWrapper.Impl wrapper = registries.getOrThrow(entry.getKey()); + + if (wrapper instanceof TagAliasEnabledRegistry registry) { + registry.fabric_applyTagAliases(groupsByTag); + } else { + LOGGER.error("[Fabric] Couldn't apply tag aliases to registry wrapper {} ({}), please report this!", wrapper, entry.getKey().getValue()); + } + } + } + + protected record Data(Identifier groupId, TagAliasGroup group) { + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagInit.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagInit.java new file mode 100644 index 0000000000..dbfb528ac8 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagInit.java @@ -0,0 +1,29 @@ +/* + * 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.tag; + +import net.minecraft.resource.ResourceType; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; + +public final class TagInit implements ModInitializer { + @Override + public void onInitialize() { + ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(TagAliasLoader.ID, TagAliasLoader::new); + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java new file mode 100644 index 0000000000..aafb14bc87 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java @@ -0,0 +1,40 @@ +/* + * 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.tag; + +import java.util.Map; +import java.util.Set; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.tag.TagKey; + +import net.fabricmc.fabric.impl.tag.TagAliasEnabledRegistry; + +@Mixin(targets = "net.minecraft.registry.SimpleRegistry$2") +abstract class SimpleRegistry2Mixin implements TagAliasEnabledRegistry { + // returns SimpleRegistry.this, which implements TagAliasEnabledRegistry + @Shadow + public abstract RegistryWrapper.Impl getBase(); + + @Override + public void fabric_applyTagAliases(Map, Set>> aliasGroups) { + ((TagAliasEnabledRegistry) getBase()).fabric_applyTagAliases(aliasGroups); + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java new file mode 100644 index 0000000000..cb572fa93c --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java @@ -0,0 +1,40 @@ +/* + * 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.tag; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.registry.SimpleRegistry; + +import net.fabricmc.fabric.impl.tag.SimpleRegistryExtension; + +@Mixin(targets = "net.minecraft.registry.SimpleRegistry$3") +abstract class SimpleRegistry3Mixin { + @Shadow + @Final + SimpleRegistry field_53689; + + @Inject(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/registry/SimpleRegistry;refreshTags()V")) + private void applyTagAliases(CallbackInfo info) { + ((SimpleRegistryExtension) field_53689).fabric_applyPendingTagAliases(); + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java new file mode 100644 index 0000000000..34054f4380 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -0,0 +1,97 @@ +/* + * 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.tag; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.SimpleRegistry; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryEntryList; +import net.minecraft.registry.tag.TagKey; + +import net.fabricmc.fabric.impl.tag.SimpleRegistryExtension; + +@Mixin(SimpleRegistry.class) +abstract class SimpleRegistryMixin implements SimpleRegistryExtension { + @Unique + private static final Logger LOGGER = LoggerFactory.getLogger("fabric-tag-api-v1"); + + @Unique + private Map, Set>> fabric_pendingTagAliasGroups; + + @Shadow + @Final + private RegistryKey> key; + + @Shadow + SimpleRegistry.TagLookup tagLookup; + + @Override + public void fabric_applyTagAliases(Map, Set>> aliasGroups) { + fabric_pendingTagAliasGroups = aliasGroups; + } + + @SuppressWarnings("unchecked") + @Override + public void fabric_applyPendingTagAliases() { + if (fabric_pendingTagAliasGroups == null) return; + + Set>> uniqueAliasGroups = Sets.newIdentityHashSet(); + uniqueAliasGroups.addAll(fabric_pendingTagAliasGroups.values()); + + for (Set> aliasGroup : uniqueAliasGroups) { + Set> entries = Sets.newIdentityHashSet(); + + // Fetch all entries from each tag. + for (TagKey tag : aliasGroup) { + RegistryEntryList.Named entryList = tagLookup.getOptional((TagKey) tag).orElse(null); + + if (entryList != null) { + entries.addAll(entryList.entries); + } else { + LOGGER.warn("[Fabric] Cannot apply aliases to tag {} because it doesn't exist!", tag); + } + } + + List> entriesAsList = List.copyOf(entries); + + // Replace the old entry list contents with the merged list. + for (TagKey tag : aliasGroup) { + RegistryEntryList.Named entryList = tagLookup.getOptional((TagKey) tag).orElse(null); + + if (entryList != null) { + entryList.entries = entriesAsList; + } + } + } + + LOGGER.info("[Fabric] Loaded {} tag alias groups for {}", uniqueAliasGroups.size(), key.getValue()); + fabric_pendingTagAliasGroups = null; + } +} diff --git a/fabric-tag-api-v1/src/main/resources/assets/fabric-tag-api-v1/icon.png b/fabric-tag-api-v1/src/main/resources/assets/fabric-tag-api-v1/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2931efbf610873c0084debb8690902b0103d27fe GIT binary patch literal 1579 zcmbVMTWB0r7@iGm)TAXsYw<=rnU=;v=W=GRbL=!tc4Brl6GO7t2vVJ$IlDV#XU;e? z+r2ymsZdMQqAyaFLLUo;RumtE8Z@?uf_*4nP^4;o6fOFoSkN+o1$K?f2nE9_*b5G-l)AV)k5Qhb^- zU{V4ZnTKgnmXdpcB*Kg!W(1hvM2N&RO30x1u~eI9meGQGe@_?PDQq%q1CiV$8~M7 z?MQ_mOdqCh^a65Sv|ntwSXjV5se1;VK1|Kr8G7TQoQL&*ctt{L{fClG}xPK5k^yK3%T69N6J=>3jBqc zDNvZsrJ-yOXI^^mWf1cmY^XST)CVzIGjvEPENowmy}ax zvJ8_(Cf#+H-dBlH53`_u-~6BVAMz|(g?jCVdBWNZ(+A}(pFV7>S3QgPiQcMaflkIC z-3Ti|VT~{au*vq0ts9O&m$p&Gl=L6+q6_m$IcVq}o~+Pl{g>1esQp4%wp~|*zk1n` zZ7T6Toc4`y88s}riCP|ZXrJ?FLz@^KTcyqLjey zu95Yz%F&S{<0~f)Iomek?+hQ%MhCu%T^zsg>C_L`1`Br`xNY&))k9yTQb$JC>)w_f zpU(^tu^Q)y%W~lVz`jz;_ jF?g&s@Y=Qe&c#kW|JbvqK0Y=Rw)4XDoVqsk_>;c_`@;F@ literal 0 HcmV?d00001 diff --git a/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.accesswidener b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.accesswidener new file mode 100644 index 0000000000..390d96c0a6 --- /dev/null +++ b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 named +accessible class net/minecraft/registry/SimpleRegistry$TagLookup +accessible field net/minecraft/registry/entry/RegistryEntryList$Named entries Ljava/util/List; diff --git a/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json new file mode 100644 index 0000000000..fadeff5b42 --- /dev/null +++ b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.tag", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "SimpleRegistryMixin", + "SimpleRegistry2Mixin", + "SimpleRegistry3Mixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-tag-api-v1/src/main/resources/fabric.mod.json b/fabric-tag-api-v1/src/main/resources/fabric.mod.json new file mode 100644 index 0000000000..2dc2520294 --- /dev/null +++ b/fabric-tag-api-v1/src/main/resources/fabric.mod.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "id": "fabric-tag-api-v1", + "name": "Fabric Tag API (v1)", + "version": "${version}", + "environment": "*", + "license": "Apache-2.0", + "icon": "assets/fabric-tag-api-v1/icon.png", + "contact": { + "homepage": "https://fabricmc.net", + "irc": "irc://irc.esper.net:6667/fabric", + "issues": "https://github.com/FabricMC/fabric/issues", + "sources": "https://github.com/FabricMC/fabric" + }, + "authors": [ + "FabricMC" + ], + "depends": { + "fabricloader": ">=0.16.8", + "fabric-api-base": "*", + "fabric-resource-loader-v0": "*" + }, + "entrypoints": { + "main": [ + "net.fabricmc.fabric.impl.tag.TagInit" + ] + }, + "description": "Hooks for working with tags.", + "mixins": [ + "fabric-tag-api-v1.mixins.json" + ], + "accessWidener": "fabric-tag-api-v1.accesswidener", + "custom": { + "fabric-api:module-lifecycle": "stable" + } +} diff --git a/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json b/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000000..655e17f28d --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json @@ -0,0 +1,15 @@ +{ + "schemaVersion": 1, + "id": "fabric-tag-v1-testmod", + "name": "Fabric Tag API (v1) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-tag-api-v1": "*" + }, + "entrypoints": { + "main": [ + ] + } +} diff --git a/gradle.properties b/gradle.properties index 8c873c60b3..35e4ac560d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -54,6 +54,7 @@ fabric-resource-loader-v0-version=3.0.6 fabric-screen-api-v1-version=2.0.33 fabric-screen-handler-api-v1-version=1.3.99 fabric-sound-api-v1-version=1.0.29 +fabric-tag-api-v1-version=1.0.0 fabric-transfer-api-v1-version=5.4.1 fabric-transitive-access-wideners-v1-version=6.1.8 fabric-convention-tags-v1-version=2.1.1 diff --git a/settings.gradle b/settings.gradle index 68a94ede37..8281f2d524 100644 --- a/settings.gradle +++ b/settings.gradle @@ -63,6 +63,7 @@ include 'fabric-resource-loader-v0' include 'fabric-screen-api-v1' include 'fabric-screen-handler-api-v1' include 'fabric-sound-api-v1' +include 'fabric-tag-api-v1' include 'fabric-transfer-api-v1' include 'fabric-transitive-access-wideners-v1' From aed325cbad8064913a94a3c2bcbce770b11564fb Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:04:07 +0200 Subject: [PATCH 02/21] Document and rename tag alias internals --- .../fabric/impl/tag/SimpleRegistryExtension.java | 2 +- ...stry.java => TagAliasEnabledRegistryWrapper.java} | 8 ++++++-- .../net/fabricmc/fabric/impl/tag/TagAliasLoader.java | 5 +++-- .../fabric/mixin/tag/SimpleRegistry2Mixin.java | 12 ++++++++---- .../fabric/mixin/tag/SimpleRegistry3Mixin.java | 6 ++++++ .../fabric/mixin/tag/SimpleRegistryMixin.java | 5 ++++- 6 files changed, 28 insertions(+), 10 deletions(-) rename fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/{TagAliasEnabledRegistry.java => TagAliasEnabledRegistryWrapper.java} (74%) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java index 661beb0c9e..f925a9a354 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java @@ -16,6 +16,6 @@ package net.fabricmc.fabric.impl.tag; -public interface SimpleRegistryExtension extends TagAliasEnabledRegistry { +public interface SimpleRegistryExtension extends TagAliasEnabledRegistryWrapper { void fabric_applyPendingTagAliases(); } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistryWrapper.java similarity index 74% rename from fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java rename to fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistryWrapper.java index 50eb6f576c..ee41ea66f7 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistry.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasEnabledRegistryWrapper.java @@ -21,6 +21,10 @@ import net.minecraft.registry.tag.TagKey; -public interface TagAliasEnabledRegistry { - void fabric_applyTagAliases(Map, Set>> aliasGroups); +/** + * Implemented on {@code RegistryWrapper.Impl} instances used during data loading + * to give access to the underlying registry. + */ +public interface TagAliasEnabledRegistryWrapper { + void fabric_loadTagAliases(Map, Set>> aliasGroups); } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index 65b46c8382..06c505d20b 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -143,8 +143,9 @@ protected void apply(Map>, List wrapper = registries.getOrThrow(entry.getKey()); - if (wrapper instanceof TagAliasEnabledRegistry registry) { - registry.fabric_applyTagAliases(groupsByTag); + if (wrapper instanceof TagAliasEnabledRegistryWrapper aliasWrapper) { + LOGGER.info("applying tag aliases to {}", wrapper.getClass()); // TODO: remove + aliasWrapper.fabric_loadTagAliases(groupsByTag); } else { LOGGER.error("[Fabric] Couldn't apply tag aliases to registry wrapper {} ({}), please report this!", wrapper, entry.getKey().getValue()); } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java index aafb14bc87..b5d49792c0 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry2Mixin.java @@ -25,16 +25,20 @@ import net.minecraft.registry.RegistryWrapper; import net.minecraft.registry.tag.TagKey; -import net.fabricmc.fabric.impl.tag.TagAliasEnabledRegistry; +import net.fabricmc.fabric.impl.tag.TagAliasEnabledRegistryWrapper; +/** + * Adds tag alias support to {@code SimpleRegistry$2}, which is the wrapper used + * for (TODO: only?) static registries during world creation and world/data reloading. + */ @Mixin(targets = "net.minecraft.registry.SimpleRegistry$2") -abstract class SimpleRegistry2Mixin implements TagAliasEnabledRegistry { +abstract class SimpleRegistry2Mixin implements TagAliasEnabledRegistryWrapper { // returns SimpleRegistry.this, which implements TagAliasEnabledRegistry @Shadow public abstract RegistryWrapper.Impl getBase(); @Override - public void fabric_applyTagAliases(Map, Set>> aliasGroups) { - ((TagAliasEnabledRegistry) getBase()).fabric_applyTagAliases(aliasGroups); + public void fabric_loadTagAliases(Map, Set>> aliasGroups) { + ((TagAliasEnabledRegistryWrapper) getBase()).fabric_loadTagAliases(aliasGroups); } } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java index cb572fa93c..3fa0ffda6d 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java @@ -27,6 +27,12 @@ import net.fabricmc.fabric.impl.tag.SimpleRegistryExtension; +/** + * This is a mixin to the Registry.PendingTagLoad implementation in SimpleRegistry. + * It applies pending tag aliases when data packs are reloaded. + * (Tags run on their own data loading system separate from resource reloaders, so we need to inject them + * once the tag and resource reloads are done, which is here.) + */ @Mixin(targets = "net.minecraft.registry.SimpleRegistry$3") abstract class SimpleRegistry3Mixin { @Shadow diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java index 34054f4380..d558699cf7 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -37,6 +37,9 @@ import net.fabricmc.fabric.impl.tag.SimpleRegistryExtension; +/** + * Adds tag alias support to {@code SimpleRegistry}, the primary registry implementation. + */ @Mixin(SimpleRegistry.class) abstract class SimpleRegistryMixin implements SimpleRegistryExtension { @Unique @@ -53,7 +56,7 @@ abstract class SimpleRegistryMixin implements SimpleRegistryExtension { SimpleRegistry.TagLookup tagLookup; @Override - public void fabric_applyTagAliases(Map, Set>> aliasGroups) { + public void fabric_loadTagAliases(Map, Set>> aliasGroups) { fabric_pendingTagAliasGroups = aliasGroups; } From 0169e531c4995f97dc7456547d291c5fa35f823c Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:24:12 +0200 Subject: [PATCH 03/21] Make the tag alias directory singular to match Mojang's recent style --- .../main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java | 2 +- .../main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java index 25cfcdb9ff..06013542ef 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java @@ -27,7 +27,7 @@ /** * A group of tags that refer to the same set of registry entries. * - *

Tag alias groups can be defined in data packs in the {@code data//fabric/tag_aliases/} + *

Tag alias groups can be defined in data packs in the {@code data//fabric/tag_alias/} * directory. {@code } is the path of the registry's ID, prefixed with {@code /} if it's * not {@value net.minecraft.util.Identifier#DEFAULT_NAMESPACE}. * diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index 06c505d20b..c1b8ab9d3e 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -102,7 +102,7 @@ protected Map>, List> pre } private static String getDirectory(RegistryKey> registryKey) { - String directory = "fabric/tag_aliases/"; + String directory = "fabric/tag_alias/"; Identifier registryId = registryKey.getValue(); if (!Identifier.DEFAULT_NAMESPACE.equals(registryId.getNamespace())) { From 598ac0a7ccb0ff3e23fc3eeed9b8dc5b9b68cca6 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:24:38 +0200 Subject: [PATCH 04/21] Add a note about tag aliases to client tag documentation --- .../java/net/fabricmc/fabric/api/tag/client/v1/ClientTags.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fabric-client-tags-api-v1/src/client/java/net/fabricmc/fabric/api/tag/client/v1/ClientTags.java b/fabric-client-tags-api-v1/src/client/java/net/fabricmc/fabric/api/tag/client/v1/ClientTags.java index f4186746ad..23407c94fc 100644 --- a/fabric-client-tags-api-v1/src/client/java/net/fabricmc/fabric/api/tag/client/v1/ClientTags.java +++ b/fabric-client-tags-api-v1/src/client/java/net/fabricmc/fabric/api/tag/client/v1/ClientTags.java @@ -37,6 +37,9 @@ *

Client Tags resolve that issue by lazily reading the tag json files within the mods on the side of the caller, * directly, allowing for mods to query tags such as {@link net.fabricmc.fabric.api.tag.convention.v2.ConventionalBlockTags} * even when connected to a vanilla server. + * + *

Note that locally read client tags don't currently support Fabric's tag aliases. The aliasing system is only + * implemented on servers. */ public final class ClientTags { private ClientTags() { From 062ca52f3d16798218e252dba35223da0476c812 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 15:10:30 +0200 Subject: [PATCH 05/21] Support missing tags in alias groups --- .../fabric/mixin/tag/SimpleRegistryMixin.java | 23 ++++++++---- .../tag/SimpleRegistryTagLookup2Accessor.java | 36 +++++++++++++++++++ .../resources/fabric-tag-api-v1.mixins.json | 3 +- 3 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryTagLookup2Accessor.java diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java index d558699cf7..39cf782653 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.mixin.tag; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -36,6 +37,7 @@ import net.minecraft.registry.tag.TagKey; import net.fabricmc.fabric.impl.tag.SimpleRegistryExtension; +import net.fabricmc.fabric.impl.tag.TagAliasEnabledRegistryWrapper; /** * Adds tag alias support to {@code SimpleRegistry}, the primary registry implementation. @@ -55,6 +57,9 @@ abstract class SimpleRegistryMixin implements SimpleRegistryExtension { @Shadow SimpleRegistry.TagLookup tagLookup; + @Shadow + protected abstract RegistryEntryList.Named createNamedEntryList(TagKey tag); + @Override public void fabric_loadTagAliases(Map, Set>> aliasGroups) { fabric_pendingTagAliasGroups = aliasGroups; @@ -78,7 +83,16 @@ public void fabric_applyPendingTagAliases() { if (entryList != null) { entries.addAll(entryList.entries); } else { - LOGGER.warn("[Fabric] Cannot apply aliases to tag {} because it doesn't exist!", tag); + LOGGER.info("[Fabric] Trying to add aliases to unknown tag {}, creating a new empty tag", tag); + Map, RegistryEntryList.Named> tagMap = ((SimpleRegistryTagLookup2Accessor) tagLookup).fabric_getTagMap(); + + if (!(tagMap instanceof HashMap)) { + // Unfreeze the backing map. + tagMap = new HashMap<>(tagMap); + ((SimpleRegistryTagLookup2Accessor) tagLookup).fabric_setTagMap(tagMap); + } + + tagMap.put((TagKey) tag, createNamedEntryList((TagKey) tag)); } } @@ -86,11 +100,8 @@ public void fabric_applyPendingTagAliases() { // Replace the old entry list contents with the merged list. for (TagKey tag : aliasGroup) { - RegistryEntryList.Named entryList = tagLookup.getOptional((TagKey) tag).orElse(null); - - if (entryList != null) { - entryList.entries = entriesAsList; - } + RegistryEntryList.Named entryList = tagLookup.getOptional((TagKey) tag).orElseThrow(); + entryList.entries = entriesAsList; } } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryTagLookup2Accessor.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryTagLookup2Accessor.java new file mode 100644 index 0000000000..8a484ac847 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryTagLookup2Accessor.java @@ -0,0 +1,36 @@ +/* + * 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.tag; + +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.registry.entry.RegistryEntryList; +import net.minecraft.registry.tag.TagKey; + +@Mixin(targets = "net.minecraft.registry.SimpleRegistry$TagLookup$2") +public interface SimpleRegistryTagLookup2Accessor { + @Accessor("field_53694") + Map, RegistryEntryList.Named> fabric_getTagMap(); + + @Accessor("field_53694") + @Mutable + void fabric_setTagMap(Map, RegistryEntryList.Named> tagMap); +} diff --git a/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json index fadeff5b42..aa82d5178b 100644 --- a/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json +++ b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json @@ -5,7 +5,8 @@ "mixins": [ "SimpleRegistryMixin", "SimpleRegistry2Mixin", - "SimpleRegistry3Mixin" + "SimpleRegistry3Mixin", + "SimpleRegistryTagLookup2Accessor" ], "injectors": { "defaultRequire": 1 From 1bb3e93e47fe10cf9b1708f603c02fb398043b58 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:22:05 +0200 Subject: [PATCH 06/21] Support tag aliases for dynamic and reloadable registries --- .../impl/tag/SimpleRegistryExtension.java | 3 +- .../fabric/impl/tag/TagAliasLoader.java | 26 ++++++++- .../mixin/tag/DataPackContentsMixin.java | 55 +++++++++++++++++++ .../mixin/tag/SimpleRegistry3Mixin.java | 2 +- .../fabric/mixin/tag/SimpleRegistryMixin.java | 15 ++++- .../resources/fabric-tag-api-v1.mixins.json | 1 + 6 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java index f925a9a354..815a21a01d 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/SimpleRegistryExtension.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.impl.tag; -public interface SimpleRegistryExtension extends TagAliasEnabledRegistryWrapper { +public interface SimpleRegistryExtension { void fabric_applyPendingTagAliases(); + void fabric_refreshTags(); } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index c1b8ab9d3e..f31d887e8a 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -36,9 +36,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.minecraft.registry.CombinedDynamicRegistries; +import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.ServerDynamicRegistryType; import net.minecraft.registry.tag.TagKey; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceFinder; @@ -53,7 +56,7 @@ public final class TagAliasLoader extends SinglePreparationResourceReloader>, List>> implements IdentifiableResourceReloadListener { public static final Identifier ID = Identifier.of("fabric-tag-api-v1", "tag_alias_groups"); - private static final Logger LOGGER = LoggerFactory.getLogger(TagAliasLoader.class); + private static final Logger LOGGER = LoggerFactory.getLogger("fabric-tag-api-v1"); private final RegistryWrapper.WrapperLookup registries; public TagAliasLoader(RegistryWrapper.WrapperLookup registries) { @@ -144,10 +147,27 @@ protected void apply(Map>, List wrapper = registries.getOrThrow(entry.getKey()); if (wrapper instanceof TagAliasEnabledRegistryWrapper aliasWrapper) { - LOGGER.info("applying tag aliases to {}", wrapper.getClass()); // TODO: remove aliasWrapper.fabric_loadTagAliases(groupsByTag); } else { - LOGGER.error("[Fabric] Couldn't apply tag aliases to registry wrapper {} ({}), please report this!", wrapper, entry.getKey().getValue()); + LOGGER.error("[Fabric] Couldn't apply tag aliases to registry wrapper {} ({}) since it had an unknown type", wrapper, entry.getKey().getValue()); + } + } + } + + public static void applyToDynamicRegistries(CombinedDynamicRegistries registries, T phase) { + Iterator> registryEntries = registries.get(phase).streamAllRegistries().iterator(); + + while (registryEntries.hasNext()) { + Registry registry = registryEntries.next().value(); + + if (registry instanceof SimpleRegistryExtension extension) { + extension.fabric_applyPendingTagAliases(); + // This is not needed in the static registry code path as the tag aliases are applied + // before the tags are refreshed. Dynamic registry loading (including tags) takes place earlier + // than the rest of a data reload, so we need to refresh the tags manually. + //extension.fabric_refreshTags(); + } else { + LOGGER.error("[Fabric] Could not apply pending tag aliases to registry {} ({}) since it had an unknown type", registry, registry.getClass().getName()); } } } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java new file mode 100644 index 0000000000..79d2d78524 --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java @@ -0,0 +1,55 @@ +/* + * 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.tag; + +import java.util.List; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.registry.CombinedDynamicRegistries; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.ServerDynamicRegistryType; +import net.minecraft.resource.featuretoggle.FeatureSet; +import net.minecraft.server.DataPackContents; +import net.minecraft.server.command.CommandManager; + +import net.fabricmc.fabric.impl.tag.TagAliasLoader; + +/** + * Applies pending tag aliases to dynamic (including reloadable) registries. + */ +@Mixin(DataPackContents.class) +abstract class DataPackContentsMixin { + @Unique + private CombinedDynamicRegistries dynamicRegistriesByType; + + @Inject(method = "", at = @At("RETURN")) + private void storeDynamicRegistries(CombinedDynamicRegistries dynamicRegistries, RegistryWrapper.WrapperLookup registries, FeatureSet enabledFeatures, CommandManager.RegistrationEnvironment environment, List pendingTagLoads, int functionPermissionLevel, CallbackInfo info) { + dynamicRegistriesByType = dynamicRegistries; + } + + // HEAD because we have to run before the lifecycle event injected into the same method. + @Inject(method = "applyPendingTagLoads", at = @At("HEAD")) + private void applyDynamicTagAliases(CallbackInfo info) { + TagAliasLoader.applyToDynamicRegistries(dynamicRegistriesByType, ServerDynamicRegistryType.WORLDGEN); + TagAliasLoader.applyToDynamicRegistries(dynamicRegistriesByType, ServerDynamicRegistryType.RELOADABLE); + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java index 3fa0ffda6d..f6bc22f5cf 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistry3Mixin.java @@ -29,7 +29,7 @@ /** * This is a mixin to the Registry.PendingTagLoad implementation in SimpleRegistry. - * It applies pending tag aliases when data packs are reloaded. + * It applies pending tag aliases to static registries when data packs are reloaded. * (Tags run on their own data loading system separate from resource reloaders, so we need to inject them * once the tag and resource reloads are done, which is here.) */ diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java index 39cf782653..04531a27c8 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -41,9 +41,11 @@ /** * Adds tag alias support to {@code SimpleRegistry}, the primary registry implementation. + * + *

Additionally, the {@link TagAliasEnabledRegistryWrapper} implementation is for dynamic registry tag loading. */ @Mixin(SimpleRegistry.class) -abstract class SimpleRegistryMixin implements SimpleRegistryExtension { +abstract class SimpleRegistryMixin implements SimpleRegistryExtension, TagAliasEnabledRegistryWrapper { @Unique private static final Logger LOGGER = LoggerFactory.getLogger("fabric-tag-api-v1"); @@ -60,6 +62,12 @@ abstract class SimpleRegistryMixin implements SimpleRegistryExtension { @Shadow protected abstract RegistryEntryList.Named createNamedEntryList(TagKey tag); + @Shadow + abstract void refreshTags(); + + @Shadow + public abstract RegistryKey> getKey(); + @Override public void fabric_loadTagAliases(Map, Set>> aliasGroups) { fabric_pendingTagAliasGroups = aliasGroups; @@ -108,4 +116,9 @@ public void fabric_applyPendingTagAliases() { LOGGER.info("[Fabric] Loaded {} tag alias groups for {}", uniqueAliasGroups.size(), key.getValue()); fabric_pendingTagAliasGroups = null; } + + @Override + public void fabric_refreshTags() { + refreshTags(); + } } diff --git a/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json index aa82d5178b..c9b582b157 100644 --- a/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json +++ b/fabric-tag-api-v1/src/main/resources/fabric-tag-api-v1.mixins.json @@ -3,6 +3,7 @@ "package": "net.fabricmc.fabric.mixin.tag", "compatibilityLevel": "JAVA_21", "mixins": [ + "DataPackContentsMixin", "SimpleRegistryMixin", "SimpleRegistry2Mixin", "SimpleRegistry3Mixin", From 8ef1e40be448efb61c7109e584e941c866b6a752 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:30:47 +0200 Subject: [PATCH 07/21] TagAliasGroup: Document naming conventions for c tag alias groups --- .../fabric/api/tag/v1/TagAliasGroup.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java index 06013542ef..7c94f473ed 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java @@ -26,6 +26,8 @@ /** * A group of tags that refer to the same set of registry entries. + * The contained tags will be linked together and get the combined set of entries + * of all the aliased tags in a group. * *

Tag alias groups can be defined in data packs in the {@code data//fabric/tag_alias/} * directory. {@code } is the path of the registry's ID, prefixed with {@code /} if it's @@ -36,6 +38,22 @@ *

If multiple tag alias groups include a tag, the groups will be combined and each tag will be an alias * for the same contents. * + *

Tag aliases in the {@code c} namespace

+ * + *

For the names of shared {@code c} tag alias groups, it's important that you use a short and descriptive name. + * A good way to do this is reusing the name of a contained {@code c} tag that follows the naming conventions. + * For example, if the tag alias group contains the tags {@code c:flowers/tall} and {@code minecraft:tall_flowers}, + * the tag alias file should be named {@code flowers/tall.json}, like the contained {@code c} tag. + * + *

Tag alias groups in the {@code c} namespace are primarily intended for merging a {@code c} tag + * with an equivalent vanilla tag with no potentially unwanted gameplay behavior. If a vanilla tag affects + * game mechanics (such as the water tag affecting swimming), don't alias it as a {@code c} tag. + * + *

If you want to have the contents of a {@code c} tag in your own tag, prefer including the {@code c} tag + * in your tag file directly. That way, data packs can modify your tag separately. Tag aliases make their contained + * tags almost fully indistinguishable since they get the exact same content, and you have to override the alias group + * in a higher-priority data pack to unlink them. + * * @param tags the tags in the group, must be from the same registry * @param the type of registry entries in the tags */ From 75d2b4b7c36f33e57d3a0f69ffde11702a076d91 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:39:32 +0200 Subject: [PATCH 08/21] Add tag alias test mod --- fabric-tag-api-v1/build.gradle | 4 + .../fabric/test/tag/TagAliasTest.java | 141 ++++++++++++++++++ .../fabric/tag_alias/block/bricks_ab.json | 6 + .../fabric/tag_alias/block/bricks_bc.json | 6 + .../fabric/tag_alias/item/beetroots.json | 6 + .../fabric/tag_alias/item/gems.json | 6 + .../fabric/tag_alias/item/redstone_dusts.json | 6 + .../tag_alias/loot_table/nether_bricks.json | 6 + .../tag_alias/worldgen/biome/classic.json | 6 + .../tags/block/brick_blocks.json | 6 + .../tags/block/bricks.json | 7 + .../tags/block/more_brick_blocks.json | 6 + .../tags/item/beetroots.json | 6 + .../tags/item/expensive_rocks.json | 6 + .../tags/item/gems.json | 6 + .../tags/item/redstone_dusts.json | 6 + .../tags/item/redstone_powders.json | 5 + .../tags/loot_table/nether_bricks_1.json | 6 + .../tags/loot_table/nether_bricks_2.json | 6 + .../tags/worldgen/biome/classic.json | 6 + .../tags/worldgen/biome/traditional.json | 6 + .../src/testmod/resources/fabric.mod.json | 1 + 22 files changed, 260 insertions(+) create mode 100644 fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_ab.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_bc.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/beetroots.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/gems.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/redstone_dusts.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/loot_table/nether_bricks.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/worldgen/biome/classic.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/brick_blocks.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/bricks.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/more_brick_blocks.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/beetroots.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/expensive_rocks.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/gems.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_dusts.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_powders.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_1.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_2.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/classic.json create mode 100644 fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/traditional.json diff --git a/fabric-tag-api-v1/build.gradle b/fabric-tag-api-v1/build.gradle index a9a380ad4a..35d162fff0 100644 --- a/fabric-tag-api-v1/build.gradle +++ b/fabric-tag-api-v1/build.gradle @@ -8,3 +8,7 @@ moduleDependencies(project, [ 'fabric-api-base', 'fabric-resource-loader-v0' ]) + +testDependencies(project, [ + ':fabric-lifecycle-events-v1', +]) diff --git a/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java b/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java new file mode 100644 index 0000000000..9fc98b5a45 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java @@ -0,0 +1,141 @@ +/* + * 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.test.tag; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.loot.LootTable; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryEntryLookup; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryEntryList; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeKeys; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; + +public final class TagAliasTest implements ModInitializer { + private static final Logger LOGGER = LoggerFactory.getLogger(TagAliasTest.class); + + // Test 1: Alias two non-empty tags + public static final TagKey GEMS = tagKey(RegistryKeys.ITEM, "gems"); + public static final TagKey EXPENSIVE_ROCKS = tagKey(RegistryKeys.ITEM, "expensive_rocks"); + + // Test 2: Alias a non-empty tag and an empty tag + public static final TagKey REDSTONE_DUSTS = tagKey(RegistryKeys.ITEM, "redstone_dusts"); + public static final TagKey REDSTONE_POWDERS = tagKey(RegistryKeys.ITEM, "redstone_powders"); + + // Test 3: Alias a non-empty tag and a missing tag + public static final TagKey BEETROOTS = tagKey(RegistryKeys.ITEM, "beetroots"); + public static final TagKey MISSING_BEETROOTS = tagKey(RegistryKeys.ITEM, "missing_beetroots"); + + // Test 4: Given tags A, B, C, make alias groups A+B and B+C. They should get merged. + public static final TagKey BRICK_BLOCKS = tagKey(RegistryKeys.BLOCK, "brick_blocks"); + public static final TagKey MORE_BRICK_BLOCKS = tagKey(RegistryKeys.BLOCK, "more_brick_blocks"); + public static final TagKey BRICKS = tagKey(RegistryKeys.BLOCK, "bricks"); + + // Test 5: Merge tags from a world generation dynamic registry + public static final TagKey CLASSIC_BIOMES = tagKey(RegistryKeys.BIOME, "classic"); + public static final TagKey TRADITIONAL_BIOMES = tagKey(RegistryKeys.BIOME, "traditional"); + + // Test 6: Merge tags from a reloadable registry + public static final TagKey NETHER_BRICKS_1 = tagKey(RegistryKeys.LOOT_TABLE, "nether_bricks_1"); + public static final TagKey NETHER_BRICKS_2 = tagKey(RegistryKeys.LOOT_TABLE, "nether_bricks_2"); + + private static TagKey tagKey(RegistryKey> registryRef, String name) { + return TagKey.of(registryRef, Identifier.of("fabric-tag-api-v1-testmod", name)); + } + + @Override + public void onInitialize() { + CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> { + LOGGER.info("Running tag alias tests on the {}...", client ? "client" : "server"); + + assertTagContent(registries, List.of(GEMS, EXPENSIVE_ROCKS), Item::getRegistryEntry, + Items.DIAMOND, Items.EMERALD); + assertTagContent(registries, List.of(REDSTONE_DUSTS, REDSTONE_POWDERS), Item::getRegistryEntry, + Items.REDSTONE); + assertTagContent(registries, List.of(BEETROOTS, MISSING_BEETROOTS), Item::getRegistryEntry, + Items.BEETROOT); + assertTagContent(registries, List.of(BRICK_BLOCKS, MORE_BRICK_BLOCKS, BRICKS), Block::getRegistryEntry, + Blocks.BRICKS, Blocks.STONE_BRICKS, Blocks.NETHER_BRICKS, Blocks.RED_NETHER_BRICKS); + assertTagContent(registries, List.of(CLASSIC_BIOMES, TRADITIONAL_BIOMES), + BiomeKeys.PLAINS, BiomeKeys.DESERT); + + // The loot table registry isn't synced to the client. + if (!client) { + assertTagContent(registries, List.of(NETHER_BRICKS_1, NETHER_BRICKS_2), + Blocks.NETHER_BRICKS.getLootTableKey().orElseThrow(), + Blocks.RED_NETHER_BRICKS.getLootTableKey().orElseThrow()); + } + + LOGGER.info("Tag alias tests completed successfully!"); + }); + } + + @SafeVarargs + private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, Function> entryExtractor, T... expected) { + Set> entries = Arrays.stream(expected) + .map(entryExtractor) + .collect(Collectors.toSet());; + assertTagContent(registries, tags, entries); + } + + @SafeVarargs + private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, RegistryKey... expected) { + RegistryEntryLookup lookup = registries.getOrThrow(tags.getFirst().registryRef()); + Set> entries = Arrays.stream(expected) + .map(lookup::getOrThrow) + .collect(Collectors.toSet()); + assertTagContent(registries, tags, entries); + } + + private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, Set> expected) { + RegistryEntryLookup lookup = registries.getOrThrow(tags.getFirst().registryRef()); + + for (TagKey tag : tags) { + RegistryEntryList.Named tagEntryList = lookup.getOrThrow(tag); + + if (!Set.copyOf(tagEntryList.entries).equals(expected)) { + throw new AssertionError("Expected tag %s to have contents %s, but it had %s instead" + .formatted(tag, expected, tagEntryList.entries)); + } + } + + LOGGER.info("Tags {} / {} were successfully aliased together", tags.getFirst().registryRef().getValue(), tags.stream() + .map(TagKey::id) + .map(Identifier::toString) + .collect(Collectors.joining(", "))); + } +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_ab.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_ab.json new file mode 100644 index 0000000000..669531cea5 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_ab.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:bricks", + "fabric-tag-api-v1-testmod:brick_blocks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_bc.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_bc.json new file mode 100644 index 0000000000..b5c065b8d3 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/block/bricks_bc.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:brick_blocks", + "fabric-tag-api-v1-testmod:more_brick_blocks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/beetroots.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/beetroots.json new file mode 100644 index 0000000000..b779e07a24 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/beetroots.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:beetroots", + "fabric-tag-api-v1-testmod:missing_beetroots" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/gems.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/gems.json new file mode 100644 index 0000000000..9a1ca39c6b --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/gems.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:expensive_rocks", + "fabric-tag-api-v1-testmod:gems" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/redstone_dusts.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/redstone_dusts.json new file mode 100644 index 0000000000..db710133dd --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/item/redstone_dusts.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:redstone_dusts", + "fabric-tag-api-v1-testmod:redstone_powders" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/loot_table/nether_bricks.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/loot_table/nether_bricks.json new file mode 100644 index 0000000000..66ede166ba --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/loot_table/nether_bricks.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:nether_bricks_1", + "fabric-tag-api-v1-testmod:nether_bricks_2" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/worldgen/biome/classic.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/worldgen/biome/classic.json new file mode 100644 index 0000000000..c658e8852b --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/fabric/tag_alias/worldgen/biome/classic.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "fabric-tag-api-v1-testmod:classic", + "fabric-tag-api-v1-testmod:traditional" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/brick_blocks.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/brick_blocks.json new file mode 100644 index 0000000000..39d086d8e1 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/brick_blocks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:nether_bricks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/bricks.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/bricks.json new file mode 100644 index 0000000000..cd4b051815 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/bricks.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:bricks", + "minecraft:stone_bricks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/more_brick_blocks.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/more_brick_blocks.json new file mode 100644 index 0000000000..215aa4e800 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/block/more_brick_blocks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:red_nether_bricks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/beetroots.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/beetroots.json new file mode 100644 index 0000000000..a3617f9e8a --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/beetroots.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:beetroot" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/expensive_rocks.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/expensive_rocks.json new file mode 100644 index 0000000000..0f3bdf92c3 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/expensive_rocks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:emerald" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/gems.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/gems.json new file mode 100644 index 0000000000..0b7f522446 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/gems.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:diamond" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_dusts.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_dusts.json new file mode 100644 index 0000000000..ffe4ba8887 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_dusts.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:redstone" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_powders.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_powders.json new file mode 100644 index 0000000000..d275da3f43 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/item/redstone_powders.json @@ -0,0 +1,5 @@ +{ + "replace": false, + "values": [ + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_1.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_1.json new file mode 100644 index 0000000000..2e3d5ab654 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_1.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:blocks/nether_bricks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_2.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_2.json new file mode 100644 index 0000000000..0fc36c475d --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/loot_table/nether_bricks_2.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:blocks/red_nether_bricks" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/classic.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/classic.json new file mode 100644 index 0000000000..946af1ea02 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/classic.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:plains" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/traditional.json b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/traditional.json new file mode 100644 index 0000000000..998789efbf --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/data/fabric-tag-api-v1-testmod/tags/worldgen/biome/traditional.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:desert" + ] +} diff --git a/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json b/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json index 655e17f28d..822e3f73be 100644 --- a/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-tag-api-v1/src/testmod/resources/fabric.mod.json @@ -10,6 +10,7 @@ }, "entrypoints": { "main": [ + "net.fabricmc.fabric.test.tag.TagAliasTest" ] } } From 597dd0b08df125fb13046986c930a37549b3fb9a Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:43:26 +0200 Subject: [PATCH 09/21] Fix inline return checkstyle --- .../fabric/api/datagen/v1/provider/FabricTagProvider.java | 4 ++-- .../java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) 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 bf2b9bac76..ece56cb9d2 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 @@ -147,7 +147,7 @@ protected AliasGroupBuilder getOrCreateAliasGroupBuilder(String group) { } /** - * {@return a read-only map of alias group builders by the alias group ID} + * {@return a read-only map of alias group builders by the alias group ID}. */ public Map getAliasGroupBuilders() { return Collections.unmodifiableMap(aliasGroupBuilders); @@ -441,7 +441,7 @@ public final class AliasGroupBuilder { private final List> tags = new ArrayList<>(); /** - * {@return a read-only list of the tags in this alias group} + * {@return a read-only list of the tags in this alias group}. */ public List> getTags() { return Collections.unmodifiableList(tags); diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java index 7c94f473ed..7a9c4edf6e 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java @@ -59,10 +59,11 @@ */ public record TagAliasGroup(List> tags) { /** - * {@return the codec for tag alias groups in the specified registry} + * Creates a codec for tag alias groups in the specified registry. * * @param registryKey the key of the registry where the tags are from - * @param the entry type + * @param the entry type + * @return the codec */ public static Codec> codec(RegistryKey> registryKey) { return TagKey.unprefixedCodec(registryKey) From c4799d4ed78c71fcaf949b679fdaaf6096b64efc Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:47:56 +0200 Subject: [PATCH 10/21] Add test for tag alias data generation --- .../fabric/tag_aliases/block/flowers.json | 6 ++++++ .../other_namespace/fabric/tag_aliases/block/flowers.json | 6 ++++++ .../fabric/test/datagen/DataGeneratorTestEntrypoint.java | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 fabric-data-generation-api-v1/src/testmod/generated/data/fabric-data-gen-api-v1-testmod/fabric/tag_aliases/block/flowers.json create mode 100644 fabric-data-generation-api-v1/src/testmod/generated/data/other_namespace/fabric/tag_aliases/block/flowers.json diff --git a/fabric-data-generation-api-v1/src/testmod/generated/data/fabric-data-gen-api-v1-testmod/fabric/tag_aliases/block/flowers.json b/fabric-data-generation-api-v1/src/testmod/generated/data/fabric-data-gen-api-v1-testmod/fabric/tag_aliases/block/flowers.json new file mode 100644 index 0000000000..69f4ed3098 --- /dev/null +++ b/fabric-data-generation-api-v1/src/testmod/generated/data/fabric-data-gen-api-v1-testmod/fabric/tag_aliases/block/flowers.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "minecraft:flowers", + "minecraft:flower_pots" + ] +} \ No newline at end of file diff --git a/fabric-data-generation-api-v1/src/testmod/generated/data/other_namespace/fabric/tag_aliases/block/flowers.json b/fabric-data-generation-api-v1/src/testmod/generated/data/other_namespace/fabric/tag_aliases/block/flowers.json new file mode 100644 index 0000000000..69f4ed3098 --- /dev/null +++ b/fabric-data-generation-api-v1/src/testmod/generated/data/other_namespace/fabric/tag_aliases/block/flowers.json @@ -0,0 +1,6 @@ +{ + "tags": [ + "minecraft:flowers", + "minecraft:flower_pots" + ] +} \ No newline at end of file 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 86af5fd0e2..a06210526c 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 @@ -332,6 +332,11 @@ protected void configure(RegistryWrapper.WrapperLookup registries) { getOrCreateTagBuilder(BlockTags.FIRE).setReplace(true).add(SIMPLE_BLOCK); getOrCreateTagBuilder(BlockTags.DIRT).add(SIMPLE_BLOCK); getOrCreateTagBuilder(BlockTags.ACACIA_LOGS).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON); + + getOrCreateAliasGroupBuilder("flowers") + .add(BlockTags.FLOWERS, BlockTags.FLOWER_POTS); + getOrCreateAliasGroupBuilder(Identifier.of("other_namespace", "flowers")) + .add(BlockTags.FLOWERS, BlockTags.FLOWER_POTS); } } From f06f3f8555ecf2dbf0229411d33570c05baf9e9c Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 16:58:52 +0200 Subject: [PATCH 11/21] Fix checkstyle (again) --- .../main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index f31d887e8a..ee66e0aa29 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -41,7 +41,6 @@ import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryWrapper; -import net.minecraft.registry.ServerDynamicRegistryType; import net.minecraft.registry.tag.TagKey; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceFinder; @@ -87,7 +86,7 @@ protected Map>, List> pre Codec> codec = TagAliasGroup.codec((RegistryKey>) registryKey); switch (codec.parse(JsonOps.INSTANCE, json)) { - case DataResult.Success(TagAliasGroup group, Lifecycle unused) -> { + case DataResult.Success(TagAliasGroup group, Lifecycle unused) -> { var data = new Data(groupId, group); dataByRegistry.computeIfAbsent(registryKey, key -> new ArrayList<>()).add(data); } From bf98da9eedc696e06ea56d55f9c8f1efe02d64a5 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 18:44:19 +0200 Subject: [PATCH 12/21] Add tag translations to tag API testmod --- .../fabric-tag-api-v1-testmod/lang/en_us.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 fabric-tag-api-v1/src/testmod/resources/assets/fabric-tag-api-v1-testmod/lang/en_us.json diff --git a/fabric-tag-api-v1/src/testmod/resources/assets/fabric-tag-api-v1-testmod/lang/en_us.json b/fabric-tag-api-v1/src/testmod/resources/assets/fabric-tag-api-v1-testmod/lang/en_us.json new file mode 100644 index 0000000000..af3ea0f849 --- /dev/null +++ b/fabric-tag-api-v1/src/testmod/resources/assets/fabric-tag-api-v1-testmod/lang/en_us.json @@ -0,0 +1,15 @@ +{ + "tag.block.fabric-tag-api-v1-testmod.bricks": "Bricks", + "tag.block.fabric-tag-api-v1-testmod.brick_blocks": "Brick Blocks", + "tag.block.fabric-tag-api-v1-testmod.more_brick_blocks": "More Brick Blocks", + "tag.item.fabric-tag-api-v1-testmod.beetroots": "Beetroots", + "tag.item.fabric-tag-api-v1-testmod.expensive_rocks": "Expensive Rocks", + "tag.item.fabric-tag-api-v1-testmod.gems": "Gems", + "tag.item.fabric-tag-api-v1-testmod.missing_beetroots": "Missing Beetroots", + "tag.item.fabric-tag-api-v1-testmod.redstone_dusts": "Redstone Dusts", + "tag.item.fabric-tag-api-v1-testmod.redstone_powders": "Redstone Powders", + "tag.loot_table.fabric-tag-api-v1-testmod.nether_bricks_1": "Nether Bricks 1", + "tag.loot_table.fabric-tag-api-v1-testmod.nether_bricks_2": "Nether Bricks 2", + "tag.worldgen.biome.fabric-tag-api-v1-testmod.classic": "Classic", + "tag.worldgen.biome.fabric-tag-api-v1-testmod.traditional": "Traditional" +} From a479beb3d935f110bcc9c0018dbd91fcb1fb0a49 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 19:03:21 +0200 Subject: [PATCH 13/21] Uncomment accidentally commented out code --- .../main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index ee66e0aa29..8cabef0d17 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -164,7 +164,7 @@ public static void applyToDynamicRegistries(CombinedDynamicRegistries reg // This is not needed in the static registry code path as the tag aliases are applied // before the tags are refreshed. Dynamic registry loading (including tags) takes place earlier // than the rest of a data reload, so we need to refresh the tags manually. - //extension.fabric_refreshTags(); + extension.fabric_refreshTags(); } else { LOGGER.error("[Fabric] Could not apply pending tag aliases to registry {} ({}) since it had an unknown type", registry, registry.getClass().getName()); } From ad89dbc4df1cef95f240a88376cbe3c89c17bcf7 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 19:14:23 +0200 Subject: [PATCH 14/21] SimpleRegistryMixin: Improve a log message --- .../java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java index 04531a27c8..a1043fa8f9 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -91,7 +91,7 @@ public void fabric_applyPendingTagAliases() { if (entryList != null) { entries.addAll(entryList.entries); } else { - LOGGER.info("[Fabric] Trying to add aliases to unknown tag {}, creating a new empty tag", tag); + LOGGER.info("[Fabric] Creating a new empty tag {} for unknown tag used in a tag alias group", tag); Map, RegistryEntryList.Named> tagMap = ((SimpleRegistryTagLookup2Accessor) tagLookup).fabric_getTagMap(); if (!(tagMap instanceof HashMap)) { From c6949bd52bfe11eae4bfd68b27d69f1111a4de45 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 19:17:15 +0200 Subject: [PATCH 15/21] TagAliasTest: Improve assertion messages --- .../fabric/test/tag/TagAliasTest.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java b/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java index 9fc98b5a45..511353e14c 100644 --- a/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java +++ b/fabric-tag-api-v1/src/testmod/java/net/fabricmc/fabric/test/tag/TagAliasTest.java @@ -35,7 +35,6 @@ import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryWrapper; -import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.registry.entry.RegistryEntryList; import net.minecraft.registry.tag.TagKey; import net.minecraft.util.Identifier; @@ -82,13 +81,13 @@ public void onInitialize() { CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> { LOGGER.info("Running tag alias tests on the {}...", client ? "client" : "server"); - assertTagContent(registries, List.of(GEMS, EXPENSIVE_ROCKS), Item::getRegistryEntry, + assertTagContent(registries, List.of(GEMS, EXPENSIVE_ROCKS), TagAliasTest::getItemKey, Items.DIAMOND, Items.EMERALD); - assertTagContent(registries, List.of(REDSTONE_DUSTS, REDSTONE_POWDERS), Item::getRegistryEntry, + assertTagContent(registries, List.of(REDSTONE_DUSTS, REDSTONE_POWDERS), TagAliasTest::getItemKey, Items.REDSTONE); - assertTagContent(registries, List.of(BEETROOTS, MISSING_BEETROOTS), Item::getRegistryEntry, + assertTagContent(registries, List.of(BEETROOTS, MISSING_BEETROOTS), TagAliasTest::getItemKey, Items.BEETROOT); - assertTagContent(registries, List.of(BRICK_BLOCKS, MORE_BRICK_BLOCKS, BRICKS), Block::getRegistryEntry, + assertTagContent(registries, List.of(BRICK_BLOCKS, MORE_BRICK_BLOCKS, BRICKS), TagAliasTest::getBlockKey, Blocks.BRICKS, Blocks.STONE_BRICKS, Blocks.NETHER_BRICKS, Blocks.RED_NETHER_BRICKS); assertTagContent(registries, List.of(CLASSIC_BIOMES, TRADITIONAL_BIOMES), BiomeKeys.PLAINS, BiomeKeys.DESERT); @@ -104,32 +103,40 @@ public void onInitialize() { }); } + private static RegistryKey getBlockKey(Block block) { + return block.getRegistryEntry().registryKey(); + } + + private static RegistryKey getItemKey(Item item) { + return item.getRegistryEntry().registryKey(); + } + @SafeVarargs - private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, Function> entryExtractor, T... expected) { - Set> entries = Arrays.stream(expected) - .map(entryExtractor) - .collect(Collectors.toSet());; - assertTagContent(registries, tags, entries); + private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, Function> keyExtractor, T... expected) { + Set> keys = Arrays.stream(expected) + .map(keyExtractor) + .collect(Collectors.toSet()); + assertTagContent(registries, tags, keys); } @SafeVarargs private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, RegistryKey... expected) { - RegistryEntryLookup lookup = registries.getOrThrow(tags.getFirst().registryRef()); - Set> entries = Arrays.stream(expected) - .map(lookup::getOrThrow) - .collect(Collectors.toSet()); - assertTagContent(registries, tags, entries); + assertTagContent(registries, tags, Set.of(expected)); } - private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, Set> expected) { + private static void assertTagContent(RegistryWrapper.WrapperLookup registries, List> tags, Set> expected) { RegistryEntryLookup lookup = registries.getOrThrow(tags.getFirst().registryRef()); for (TagKey tag : tags) { RegistryEntryList.Named tagEntryList = lookup.getOrThrow(tag); + Set> actual = tagEntryList.entries + .stream() + .map(entry -> entry.getKey().orElseThrow()) + .collect(Collectors.toSet()); - if (!Set.copyOf(tagEntryList.entries).equals(expected)) { + if (!actual.equals(expected)) { throw new AssertionError("Expected tag %s to have contents %s, but it had %s instead" - .formatted(tag, expected, tagEntryList.entries)); + .formatted(tag, expected, actual)); } } From 9a464a1fb18d223bc904fbc833661e31e313cc4f Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 10 Nov 2024 19:22:04 +0200 Subject: [PATCH 16/21] Fix tag aliases for dynamic registries not applying on /reload --- .../fabric/mixin/tag/DataPackContentsMixin.java | 11 ++++++++--- .../fabric/mixin/tag/SimpleRegistry3Mixin.java | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java index 79d2d78524..c0272436dc 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/DataPackContentsMixin.java @@ -35,8 +35,9 @@ /** * Applies pending tag aliases to dynamic (including reloadable) registries. + * The priority is 999 because it must apply the injection to applyPendingTagLoads before the tag loaded lifecycle event. */ -@Mixin(DataPackContents.class) +@Mixin(value = DataPackContents.class, priority = 999) abstract class DataPackContentsMixin { @Unique private CombinedDynamicRegistries dynamicRegistriesByType; @@ -46,9 +47,13 @@ private void storeDynamicRegistries(CombinedDynamicRegistries Date: Sun, 10 Nov 2024 19:28:44 +0200 Subject: [PATCH 17/21] Clean up log message once again --- .../java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java index a1043fa8f9..9b67156775 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -91,7 +91,7 @@ public void fabric_applyPendingTagAliases() { if (entryList != null) { entries.addAll(entryList.entries); } else { - LOGGER.info("[Fabric] Creating a new empty tag {} for unknown tag used in a tag alias group", tag); + LOGGER.info("[Fabric] Creating a new empty tag {} for unknown tag used in a tag alias group in {}", tag.id(), tag.registryRef().getValue()); Map, RegistryEntryList.Named> tagMap = ((SimpleRegistryTagLookup2Accessor) tagLookup).fabric_getTagMap(); if (!(tagMap instanceof HashMap)) { From 3a0a020807fad7d6185654cdcf71e7f5c83b61b8 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:20:13 +0200 Subject: [PATCH 18/21] Address review feedback --- .../api/datagen/v1/provider/FabricTagProvider.java | 7 +++++-- .../test/datagen/DataGeneratorTestEntrypoint.java | 4 ++-- .../fabric/mixin/tag/SimpleRegistryMixin.java | 12 ++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) 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 ece56cb9d2..de31526fc3 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 @@ -131,7 +131,7 @@ protected FabricTagBuilder getOrCreateTagBuilder(TagKey tag) { * @param groupId the group ID * @return the alias group builder */ - protected AliasGroupBuilder getOrCreateAliasGroupBuilder(Identifier groupId) { + protected AliasGroupBuilder aliasGroup(Identifier groupId) { return aliasGroupBuilders.computeIfAbsent(groupId, key -> new AliasGroupBuilder()); } @@ -141,7 +141,7 @@ protected AliasGroupBuilder getOrCreateAliasGroupBuilder(Identifier groupId) { * @param group the group name * @return the alias group builder */ - protected AliasGroupBuilder getOrCreateAliasGroupBuilder(String group) { + protected AliasGroupBuilder aliasGroup(String group) { Identifier groupId = Identifier.of(output.getModId(), group); return aliasGroupBuilders.computeIfAbsent(groupId, key -> new AliasGroupBuilder()); } @@ -440,6 +440,9 @@ public final FabricTagBuilder add(RegistryKey... registryKeys) { public final class AliasGroupBuilder { private final List> tags = new ArrayList<>(); + private AliasGroupBuilder() { + } + /** * {@return a read-only list of the tags in this alias group}. */ 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 a06210526c..488cdd679e 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 @@ -333,9 +333,9 @@ protected void configure(RegistryWrapper.WrapperLookup registries) { getOrCreateTagBuilder(BlockTags.DIRT).add(SIMPLE_BLOCK); getOrCreateTagBuilder(BlockTags.ACACIA_LOGS).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON); - getOrCreateAliasGroupBuilder("flowers") + aliasGroup("flowers") .add(BlockTags.FLOWERS, BlockTags.FLOWER_POTS); - getOrCreateAliasGroupBuilder(Identifier.of("other_namespace", "flowers")) + aliasGroup(Identifier.of("other_namespace", "flowers")) .add(BlockTags.FLOWERS, BlockTags.FLOWER_POTS); } } diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java index 9b67156775..6fcd23e7fe 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/mixin/tag/SimpleRegistryMixin.java @@ -50,7 +50,7 @@ abstract class SimpleRegistryMixin implements SimpleRegistryExtension, TagAli private static final Logger LOGGER = LoggerFactory.getLogger("fabric-tag-api-v1"); @Unique - private Map, Set>> fabric_pendingTagAliasGroups; + private Map, Set>> pendingTagAliasGroups; @Shadow @Final @@ -70,16 +70,16 @@ abstract class SimpleRegistryMixin implements SimpleRegistryExtension, TagAli @Override public void fabric_loadTagAliases(Map, Set>> aliasGroups) { - fabric_pendingTagAliasGroups = aliasGroups; + pendingTagAliasGroups = aliasGroups; } @SuppressWarnings("unchecked") @Override public void fabric_applyPendingTagAliases() { - if (fabric_pendingTagAliasGroups == null) return; + if (pendingTagAliasGroups == null) return; Set>> uniqueAliasGroups = Sets.newIdentityHashSet(); - uniqueAliasGroups.addAll(fabric_pendingTagAliasGroups.values()); + uniqueAliasGroups.addAll(pendingTagAliasGroups.values()); for (Set> aliasGroup : uniqueAliasGroups) { Set> entries = Sets.newIdentityHashSet(); @@ -113,8 +113,8 @@ public void fabric_applyPendingTagAliases() { } } - LOGGER.info("[Fabric] Loaded {} tag alias groups for {}", uniqueAliasGroups.size(), key.getValue()); - fabric_pendingTagAliasGroups = null; + LOGGER.debug("[Fabric] Loaded {} tag alias groups for {}", uniqueAliasGroups.size(), key.getValue()); + pendingTagAliasGroups = null; } @Override From d3f5e0b8788c85ef3e39db997e4a63816e7b70c7 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:33:02 +0200 Subject: [PATCH 19/21] Make missing interfaces throw CCEs --- .../java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index 8cabef0d17..d444daa8af 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -90,7 +90,7 @@ protected Map>, List> pre var data = new Data(groupId, group); dataByRegistry.computeIfAbsent(registryKey, key -> new ArrayList<>()).add(data); } - case DataResult.Error> error -> { + case DataResult.Error error -> { LOGGER.error("[Fabric] Couldn't parse tag alias group file '{}' from '{}': {}", groupId, resourcePath, error.message()); } } @@ -148,7 +148,8 @@ protected void apply(Map>, List void applyToDynamicRegistries(CombinedDynamicRegistries reg // than the rest of a data reload, so we need to refresh the tags manually. extension.fabric_refreshTags(); } else { - LOGGER.error("[Fabric] Could not apply pending tag aliases to registry {} ({}) since it had an unknown type", registry, registry.getClass().getName()); + throw new ClassCastException("[Fabric] Couldn't apply pending tag aliases to registry %s (%s) since it doesn't implement SimpleRegistryExtension" + .formatted(registry, registry.getClass().getName())); } } } From e01b48e85c112d04137a0de1d0d85d7722cb3bb4 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:37:42 +0200 Subject: [PATCH 20/21] Add README --- fabric-tag-api-v1/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 fabric-tag-api-v1/README.md diff --git a/fabric-tag-api-v1/README.md b/fabric-tag-api-v1/README.md new file mode 100644 index 0000000000..b2b4c3dfa2 --- /dev/null +++ b/fabric-tag-api-v1/README.md @@ -0,0 +1,17 @@ +# Fabric Tag API (v1) + +This module contains APIs for working with data pack tags. + +## Tag aliases + +*Tag alias groups* merge tags that refer to the same set of registry entries. +The contained tags will be linked together and get the combined set of entries +of all the aliased tags in a group. + +Tag alias groups can be defined in data packs in the `data//fabric/tag_alias/` +directory. `` is the path of the registry's ID, prefixed with `/` if it's +not `minecraft`. + +The JSON format of tag alias groups is an object with a `tags` list containing plain tag IDs. + +See the module javadoc for more information about tag aliases. From cb5f5a7412fb4d397fb4a81cc0f7caee9f1d5016 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:16:16 +0200 Subject: [PATCH 21/21] Move TagAliasGroup into the impl package --- .../impl/datagen/TagAliasGenerator.java | 2 +- .../fabric/api/tag/v1/TagAliasGroup.java | 75 ------------------- .../fabric/api/tag/v1/package-info.java | 32 +++++++- .../fabric/impl/tag/TagAliasGroup.java | 48 ++++++++++++ .../fabric/impl/tag/TagAliasLoader.java | 1 - 5 files changed, 80 insertions(+), 78 deletions(-) delete mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java create mode 100644 fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasGroup.java diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java index 6d9ce45902..9e818b5773 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/impl/datagen/TagAliasGenerator.java @@ -28,7 +28,7 @@ import net.minecraft.registry.tag.TagKey; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.tag.v1.TagAliasGroup; +import net.fabricmc.fabric.impl.tag.TagAliasGroup; public final class TagAliasGenerator { public static String getDirectory(RegistryKey> registryKey) { diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java deleted file mode 100644 index 7a9c4edf6e..0000000000 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/TagAliasGroup.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.api.tag.v1; - -import java.util.List; - -import com.mojang.serialization.Codec; - -import net.minecraft.registry.Registry; -import net.minecraft.registry.RegistryKey; -import net.minecraft.registry.tag.TagKey; - -/** - * A group of tags that refer to the same set of registry entries. - * The contained tags will be linked together and get the combined set of entries - * of all the aliased tags in a group. - * - *

Tag alias groups can be defined in data packs in the {@code data//fabric/tag_alias/} - * directory. {@code } is the path of the registry's ID, prefixed with {@code /} if it's - * not {@value net.minecraft.util.Identifier#DEFAULT_NAMESPACE}. - * - *

The JSON format of tag alias groups is an object with a {@code tags} list containing plain tag IDs. - * - *

If multiple tag alias groups include a tag, the groups will be combined and each tag will be an alias - * for the same contents. - * - *

Tag aliases in the {@code c} namespace

- * - *

For the names of shared {@code c} tag alias groups, it's important that you use a short and descriptive name. - * A good way to do this is reusing the name of a contained {@code c} tag that follows the naming conventions. - * For example, if the tag alias group contains the tags {@code c:flowers/tall} and {@code minecraft:tall_flowers}, - * the tag alias file should be named {@code flowers/tall.json}, like the contained {@code c} tag. - * - *

Tag alias groups in the {@code c} namespace are primarily intended for merging a {@code c} tag - * with an equivalent vanilla tag with no potentially unwanted gameplay behavior. If a vanilla tag affects - * game mechanics (such as the water tag affecting swimming), don't alias it as a {@code c} tag. - * - *

If you want to have the contents of a {@code c} tag in your own tag, prefer including the {@code c} tag - * in your tag file directly. That way, data packs can modify your tag separately. Tag aliases make their contained - * tags almost fully indistinguishable since they get the exact same content, and you have to override the alias group - * in a higher-priority data pack to unlink them. - * - * @param tags the tags in the group, must be from the same registry - * @param the type of registry entries in the tags - */ -public record TagAliasGroup(List> tags) { - /** - * Creates a codec for tag alias groups in the specified registry. - * - * @param registryKey the key of the registry where the tags are from - * @param the entry type - * @return the codec - */ - public static Codec> codec(RegistryKey> registryKey) { - return TagKey.unprefixedCodec(registryKey) - .listOf() - .fieldOf("tags") - .xmap(TagAliasGroup::new, TagAliasGroup::tags) - .codec(); - } -} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java index 22d56f5be4..1f5147f1d1 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/api/tag/v1/package-info.java @@ -17,6 +17,36 @@ /** * The Fabric Tag API for working with {@linkplain net.minecraft.registry.tag.TagKey tags}. * - * @see net.fabricmc.fabric.api.tag.v1.TagAliasGroup + *

Aliasing tags

+ * Tag alias groups are lists of tags that refer to the same set of registry entries. + * The contained tags will be linked together and get the combined set of entries + * of all the aliased tags in a group. + * + *

Tag alias groups can be defined in data packs in the {@code data//fabric/tag_alias/} + * directory. {@code } is the path of the registry's ID, prefixed with {@code /} if it's + * not {@value net.minecraft.util.Identifier#DEFAULT_NAMESPACE}. For example, an alias group for block tags would be placed + * in {@code data//fabric/tag_alias/block/}. + * + *

The JSON format of tag alias groups is an object with a {@code tags} list. The list contains plain tag IDs with + * no {@code #} prefix. + * + *

If multiple tag alias groups include a tag, the groups will be combined and each tag will be an alias + * for the same contents. + * + *

Tag aliases in the {@code c} namespace

+ * + *

For the names of shared {@code c} tag alias groups, it's important that you use a short and descriptive name. + * A good way to do this is reusing the name of a contained {@code c} tag that follows the naming conventions. + * For example, if the tag alias group contains the tags {@code c:flowers/tall} and {@code minecraft:tall_flowers}, + * the tag alias file should be named {@code flowers/tall.json}, like the contained {@code c} tag. + * + *

Tag alias groups in the {@code c} namespace are primarily intended for merging a {@code c} tag + * with an equivalent vanilla tag with no potentially unwanted gameplay behavior. If a vanilla tag affects + * game mechanics (such as the water tag affecting swimming), don't alias it as a {@code c} tag. + * + *

If you want to have the contents of a {@code c} tag in your own tag, prefer including the {@code c} tag + * in your tag file directly. That way, data packs can modify your tag separately. Tag aliases make their contained + * tags almost fully indistinguishable since they get the exact same content, and you have to override the alias group + * in a higher-priority data pack to unlink them. */ package net.fabricmc.fabric.api.tag.v1; diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasGroup.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasGroup.java new file mode 100644 index 0000000000..494e7f779e --- /dev/null +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasGroup.java @@ -0,0 +1,48 @@ +/* + * 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.tag; + +import java.util.List; + +import com.mojang.serialization.Codec; + +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.tag.TagKey; + +/** + * A wrapper record for tag alias groups. + * + * @param tags the tags in the group, must be from the same registry + * @param the type of registry entries in the tags + */ +public record TagAliasGroup(List> tags) { + /** + * Creates a codec for tag alias groups in the specified registry. + * + * @param registryKey the key of the registry where the tags are from + * @param the entry type + * @return the codec + */ + public static Codec> codec(RegistryKey> registryKey) { + return TagKey.unprefixedCodec(registryKey) + .listOf() + .fieldOf("tags") + .xmap(TagAliasGroup::new, TagAliasGroup::tags) + .codec(); + } +} diff --git a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java index d444daa8af..d26e8860c2 100644 --- a/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java +++ b/fabric-tag-api-v1/src/main/java/net/fabricmc/fabric/impl/tag/TagAliasLoader.java @@ -50,7 +50,6 @@ import net.minecraft.util.profiler.Profiler; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; -import net.fabricmc.fabric.api.tag.v1.TagAliasGroup; public final class TagAliasLoader extends SinglePreparationResourceReloader>, List>> implements IdentifiableResourceReloadListener { public static final Identifier ID = Identifier.of("fabric-tag-api-v1", "tag_alias_groups");