Skip to content

Commit

Permalink
Add tag aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
Juuxel committed Nov 1, 2024
1 parent fd37071 commit 738bc5d
Show file tree
Hide file tree
Showing 22 changed files with 750 additions and 2 deletions.
1 change: 1 addition & 0 deletions fabric-data-generation-api-v1/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,6 +75,9 @@
* @see EntityTypeTagProvider
*/
public abstract class FabricTagProvider<T> extends TagProvider<T> {
private final FabricDataOutput output;
private final Map<Identifier, AliasGroupBuilder> aliasGroupBuilders = new HashMap<>();

/**
* Constructs a new {@link FabricTagProvider} with the default computed path.
*
Expand All @@ -80,6 +88,7 @@ public abstract class FabricTagProvider<T> extends TagProvider<T> {
*/
public FabricTagProvider(FabricDataOutput output, RegistryKey<? extends Registry<T>> registryKey, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registryKey, registriesFuture);
this.output = output;
}

/**
Expand Down Expand Up @@ -116,6 +125,34 @@ protected FabricTagBuilder getOrCreateTagBuilder(TagKey<T> 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());
}

/**

Check failure on line 149 in fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricTagProvider.java

View workflow job for this annotation

GitHub Actions / build (21-ubuntu)

First sentence should end with a period.
* {@return a read-only map of alias group builders by the alias group ID}
*/
public Map<Identifier, AliasGroupBuilder> getAliasGroupBuilders() {
return Collections.unmodifiableMap(aliasGroupBuilders);
}

/**
* Extend this class to create {@link Block} tags in the "/blocks" tag directory.
*/
Expand Down Expand Up @@ -396,4 +433,49 @@ public final FabricTagBuilder add(RegistryKey<T>... registryKeys) {
return this;
}
}

/**
* A builder for tag alias groups.
*/
public final class AliasGroupBuilder {
private final List<TagKey<T>> tags = new ArrayList<>();

/**

Check failure on line 443 in fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricTagProvider.java

View workflow job for this annotation

GitHub Actions / build (21-ubuntu)

First sentence should end with a period.
* {@return a read-only list of the tags in this alias group}
*/
public List<TagKey<T>> getTags() {
return Collections.unmodifiableList(tags);
}

public AliasGroupBuilder add(TagKey<T> 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<T>... tags) {
for (TagKey<T> 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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<? extends Registry<?>> 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 <T> CompletableFuture<?> writeTagAlias(DataWriter writer, DataOutput.PathResolver pathResolver, RegistryKey<? extends Registry<T>> registryRef, Identifier groupId, List<TagKey<T>> tags) {
Path path = pathResolver.resolveJson(groupId);
return DataProvider.writeCodecToPath(writer, TagAliasGroup.codec(registryRef), new TagAliasGroup<>(tags), path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> {
@Shadow
@Final
protected RegistryKey<? extends Registry<T>> registryRef;

@Unique
private DataOutput.PathResolver tagAliasPathResolver;

@Inject(method = "<init>(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<? extends Registry<T>> 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;<init>(Ljava/util/List;Z)V"), index = 1)
private boolean addReplaced(boolean replaced, @Local TagBuilder tagBuilder) {
if (tagBuilder instanceof FabricTagBuilder fabricTagBuilder) {
Expand All @@ -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<Void> addTagAliasGroupBuilders(CompletableFuture<?>[] futures, Operation<CompletableFuture<Void>> original, @Local(argsOnly = true) DataWriter writer) {
if ((Object) this instanceof FabricTagProvider<?>) {
// Note: no pattern matching instanceof so that we can cast directly to FabricTagProvider<T> instead of a wildcard
Map<Identifier, FabricTagProvider<T>.AliasGroupBuilder> builders = ((FabricTagProvider<T>) (Object) this).getAliasGroupBuilders();
CompletableFuture<?>[] newFutures = Arrays.copyOf(futures, futures.length + builders.size());
int index = futures.length;

for (Map.Entry<Identifier, FabricTagProvider<T>.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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
10 changes: 10 additions & 0 deletions fabric-tag-api-v1/build.gradle
Original file line number Diff line number Diff line change
@@ -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'
])
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>Tag alias groups can be defined in data packs in the {@code data/<mod namespace>/fabric/tag_aliases/<registry>}
* directory. {@code <registry>} is the path of the registry's ID, prefixed with {@code <registry's namespace>/} if it's
* not {@value net.minecraft.util.Identifier#DEFAULT_NAMESPACE}.
*
* <p>The JSON format of tag alias groups is an object with a {@code tags} list containing plain tag IDs.
*
* <p>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 <T> the type of registry entries in the tags
*/
public record TagAliasGroup<T>(List<TagKey<T>> 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 <T> the entry type
*/
public static <T> Codec<TagAliasGroup<T>> codec(RegistryKey<? extends Registry<T>> registryKey) {
return TagKey.unprefixedCodec(registryKey)
.listOf()
.fieldOf("tags")
.xmap(TagAliasGroup::new, TagAliasGroup::tags)
.codec();
}
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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<TagKey<?>, Set<TagKey<?>>> aliasGroups);
}
Loading

0 comments on commit 738bc5d

Please sign in to comment.