mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-05 19:47:00 -04:00
Tag Factory API (#1562)
* Tag factory * Add static biome tag factory to the API * Use SERVER_STARTING event * Use the ctor directly * Use the default BIOME factory * AccessorDynamicRegistryManager -> DynamicRegistryManagerAccess * Return Tag.Identified * Load dynamic registry tags right after datapack entries loaded * DynamicRegistryManagerAccess -> DynamicRegistryManagerAccessor * Fix grammar
This commit is contained in:
parent
2e8bd82f1c
commit
5e85fc0a09
18 changed files with 642 additions and 19 deletions
fabric-tag-extensions-v0
build.gradle
src
main
java/net/fabricmc/fabric
api/tag
impl/tag/extension
mixin/tag/extension
resources
testmod
java/net/fabricmc/fabric/test/tag/extension
resources
data/fabric-tag-extensions-v0-testmod
fabric.mod.json
|
@ -5,3 +5,9 @@ moduleDependencies(project, [
|
|||
'fabric-api-base',
|
||||
'fabric-resource-loader-v0'
|
||||
])
|
||||
|
||||
dependencies {
|
||||
testmodImplementation project(path: ':fabric-command-api-v1', configuration: 'dev')
|
||||
testmodImplementation project(path: ':fabric-key-binding-api-v1', configuration: 'dev')
|
||||
testmodImplementation project(path: ':fabric-lifecycle-events-v1', configuration: 'dev')
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.tag.BlockTags;
|
||||
import net.minecraft.tag.EntityTypeTags;
|
||||
import net.minecraft.tag.FluidTags;
|
||||
import net.minecraft.tag.GameEventTags;
|
||||
import net.minecraft.tag.ItemTags;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.tag.TagGroup;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.event.GameEvent;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.TagFactoryImpl;
|
||||
|
||||
/**
|
||||
* A factory for accessing datapack tags.
|
||||
*/
|
||||
public interface TagFactory<T> {
|
||||
TagFactory<Item> ITEM = of(ItemTags::getTagGroup);
|
||||
TagFactory<Block> BLOCK = of(BlockTags::getTagGroup);
|
||||
TagFactory<Fluid> FLUID = of(FluidTags::getTagGroup);
|
||||
TagFactory<GameEvent> GAME_EVENT = of(GameEventTags::getTagGroup);
|
||||
TagFactory<EntityType<?>> ENTITY_TYPE = of(EntityTypeTags::getTagGroup);
|
||||
TagFactory<Biome> BIOME = of(Registry.BIOME_KEY, "tags/biomes");
|
||||
|
||||
/**
|
||||
* Create a new tag factory for specified registry.
|
||||
*
|
||||
* @param registryKey the key of the registry.
|
||||
* @param dataType the data type of this tag group, vanilla uses "tags/[plural]" format for built-in groups.
|
||||
*/
|
||||
static <T> TagFactory<T> of(RegistryKey<? extends Registry<T>> registryKey, String dataType) {
|
||||
return TagFactoryImpl.of(registryKey, dataType);
|
||||
}
|
||||
|
||||
static <T> TagFactory<T> of(Supplier<TagGroup<T>> tagGroupSupplier) {
|
||||
return TagFactoryImpl.of(tagGroupSupplier);
|
||||
}
|
||||
|
||||
Tag.Identified<T> create(Identifier id);
|
||||
}
|
|
@ -19,22 +19,21 @@ package net.fabricmc.fabric.api.tag;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.tag.TagGroup;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.tag.BlockTags;
|
||||
import net.minecraft.tag.EntityTypeTags;
|
||||
import net.minecraft.tag.ItemTags;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.tag.TagGroup;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.TagDelegate;
|
||||
import net.fabricmc.fabric.mixin.tag.extension.AccessorFluidTags;
|
||||
|
||||
/**
|
||||
* Helper methods for registering Tags.
|
||||
*
|
||||
* @deprecated use {@link TagFactory} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class TagRegistry {
|
||||
private TagRegistry() { }
|
||||
|
||||
|
@ -42,19 +41,35 @@ public final class TagRegistry {
|
|||
return new TagDelegate<>(id, containerSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link TagFactory#BLOCK}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Tag<Block> block(Identifier id) {
|
||||
return create(id, BlockTags::getTagGroup);
|
||||
return TagFactory.BLOCK.create(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link TagFactory#ENTITY_TYPE}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Tag<EntityType<?>> entityType(Identifier id) {
|
||||
return create(id, EntityTypeTags::getTagGroup);
|
||||
return TagFactory.ENTITY_TYPE.create(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link TagFactory#FLUID}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Tag<Fluid> fluid(Identifier id) {
|
||||
return create(id, () -> AccessorFluidTags.getRequiredTags().getGroup());
|
||||
return TagFactory.FLUID.create(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link TagFactory#ITEM}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Tag<Item> item(Identifier id) {
|
||||
return create(id, ItemTags::getTagGroup);
|
||||
return TagFactory.ITEM.create(id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import net.minecraft.tag.TagGroup;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
|
||||
public interface FabricTagManagerHooks {
|
||||
void fabric_addTagGroup(RegistryKey<? extends Registry<?>> registryKey, TagGroup<?> tagGroup);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.ServerResourceManager;
|
||||
import net.minecraft.server.Main;
|
||||
import net.minecraft.tag.RequiredTagList;
|
||||
import net.minecraft.tag.RequiredTagListRegistry;
|
||||
import net.minecraft.tag.ServerTagManagerHolder;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.tag.TagGroup;
|
||||
import net.minecraft.tag.TagGroupLoader;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.dynamic.RegistryOps;
|
||||
import net.minecraft.util.registry.DynamicRegistryManager;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
|
||||
import net.fabricmc.fabric.api.tag.TagFactory;
|
||||
import net.fabricmc.fabric.mixin.tag.extension.DynamicRegistryManagerAccessor;
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
public final class TagFactoryImpl<T> implements TagFactory<T> {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static final Map<RegistryKey<? extends Registry<?>>, RequiredTagList<?>> TAG_LISTS = new HashMap<>();
|
||||
public static final Set<RequiredTagList<?>> DYNAMICS = new HashSet<>();
|
||||
|
||||
public static <T> TagFactory<T> of(Supplier<TagGroup<T>> tagGroupSupplier) {
|
||||
return new TagFactoryImpl<>(tagGroupSupplier);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> TagFactory<T> of(RegistryKey<? extends Registry<T>> registryKey, String dataType) {
|
||||
RequiredTagList<T> tagList;
|
||||
|
||||
// Use already registered tag list for the registry if it has the same dataType, in case multiple mods tried to do it.
|
||||
if (TAG_LISTS.containsKey(registryKey)) {
|
||||
tagList = (RequiredTagList<T>) TAG_LISTS.get(registryKey);
|
||||
// Throw an exception if the tagList has different dataType.
|
||||
Preconditions.checkArgument(tagList.getDataType().equals(dataType), "Tag list for registry %s is already existed with data type %s", registryKey.getValue(), tagList.getDataType());
|
||||
} else {
|
||||
tagList = RequiredTagListRegistry.register(registryKey, dataType);
|
||||
TAG_LISTS.put(registryKey, tagList);
|
||||
|
||||
// Check whether the registry dynamic.
|
||||
if (DynamicRegistryManagerAccessor.getInfos().containsKey(registryKey)) {
|
||||
DYNAMICS.add(tagList);
|
||||
}
|
||||
}
|
||||
|
||||
return of(tagList::getGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually load tags for dynamic registries and add the resulting tag group to the tag list.
|
||||
*
|
||||
* <p>Minecraft loads the resource manager before dynamic registries, making tags for them fail to load
|
||||
* if it mentions datapack entries. The solution is to manually load tags after the registry is loaded.
|
||||
*
|
||||
* <p>Look at server's {@link Main#main} function calls for {@link ServerResourceManager#reload} and
|
||||
* {@link RegistryOps#method_36574} for the relevant code.
|
||||
*/
|
||||
public static void loadDynamicRegistryTags(DynamicRegistryManager registryManager, ResourceManager resourceManager) {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
int loadedTags = 0;
|
||||
|
||||
for (RequiredTagList<?> tagList : DYNAMICS) {
|
||||
RegistryKey<? extends Registry<?>> registryKey = tagList.getRegistryKey();
|
||||
Registry<?> registry = registryManager.get(registryKey);
|
||||
TagGroupLoader<?> tagGroupLoader = new TagGroupLoader<>(registry::getOrEmpty, tagList.getDataType());
|
||||
TagGroup<?> tagGroup = tagGroupLoader.load(resourceManager);
|
||||
((FabricTagManagerHooks) ServerTagManagerHolder.getTagManager()).fabric_addTagGroup(registryKey, tagGroup);
|
||||
tagList.updateTagManager(ServerTagManagerHolder.getTagManager());
|
||||
loadedTags += tagGroup.getTags().size();
|
||||
}
|
||||
|
||||
if (loadedTags > 0) {
|
||||
LOGGER.info("Loaded {} dynamic registry tags in {}", loadedTags, stopwatch);
|
||||
}
|
||||
}
|
||||
|
||||
private final Supplier<TagGroup<T>> tagGroupSupplier;
|
||||
|
||||
private TagFactoryImpl(Supplier<TagGroup<T>> tagGroupSupplier) {
|
||||
this.tagGroupSupplier = tagGroupSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag.Identified<T> create(Identifier id) {
|
||||
return new TagDelegate<>(id, tagGroupSupplier);
|
||||
}
|
||||
}
|
|
@ -16,17 +16,19 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.tag.extension;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.tag.FluidTags;
|
||||
import net.minecraft.tag.RequiredTagList;
|
||||
import net.minecraft.util.registry.DynamicRegistryManager;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
|
||||
@Mixin(FluidTags.class)
|
||||
public interface AccessorFluidTags {
|
||||
@Accessor("REQUIRED_TAGS")
|
||||
static RequiredTagList<Fluid> getRequiredTags() {
|
||||
throw new UnsupportedOperationException();
|
||||
@Mixin(DynamicRegistryManager.class)
|
||||
public interface DynamicRegistryManagerAccessor {
|
||||
@Accessor("INFOS")
|
||||
static Map<RegistryKey<? extends Registry<?>>, ?> getInfos() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
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.resource.ServerResourceManager;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.registry.DynamicRegistryManager;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.TagFactoryImpl;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public abstract class MixinMinecraftServer {
|
||||
@Shadow
|
||||
@Final
|
||||
protected DynamicRegistryManager.Impl registryManager;
|
||||
|
||||
@SuppressWarnings("UnresolvedMixinReference")
|
||||
@Inject(method = "method_29440", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ServerResourceManager;loadRegistryTags()V", shift = At.Shift.AFTER))
|
||||
private void method_29440(Collection<?> collection, ServerResourceManager serverResourceManager, CallbackInfo ci) {
|
||||
// Load dynamic registry tags on datapack reload.
|
||||
TagFactoryImpl.loadDynamicRegistryTags(registryManager, serverResourceManager.getResourceManager());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.dynamic.RegistryOps;
|
||||
import net.minecraft.util.registry.DynamicRegistryManager;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.TagFactoryImpl;
|
||||
|
||||
/**
|
||||
* This mixin loads dynamic registry tags right after datapack entries loaded.
|
||||
* Needs a higher priority so it will be called before biome modifications.
|
||||
*/
|
||||
@Mixin(value = RegistryOps.class, priority = 900)
|
||||
public class MixinRegistryOps {
|
||||
@Inject(method = "method_36574", at = @At("RETURN"))
|
||||
private static <T> void afterDynamicRegistryLoaded(DynamicOps<T> dynamicOps, ResourceManager resourceManager, DynamicRegistryManager registryManager, CallbackInfoReturnable<RegistryOps<T>> cir) {
|
||||
TagFactoryImpl.loadDynamicRegistryTags(registryManager, resourceManager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.tag.RequiredTagList;
|
||||
import net.minecraft.tag.RequiredTagListRegistry;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.TagFactoryImpl;
|
||||
|
||||
@Mixin(RequiredTagListRegistry.class)
|
||||
public class MixinRequiredTagListRegistry {
|
||||
@Inject(method = "getBuiltinTags", at = @At("TAIL"), cancellable = true)
|
||||
private static void getBuiltinTags(CallbackInfoReturnable<Set<RequiredTagList<?>>> cir) {
|
||||
// Add tag lists registered on fabric to the map.
|
||||
Set<RequiredTagList<?>> set = new HashSet<>(cir.getReturnValue());
|
||||
set.addAll(TagFactoryImpl.TAG_LISTS.values());
|
||||
cir.setReturnValue(set);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
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.tag.TagGroup;
|
||||
import net.minecraft.tag.TagManager;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.FabricTagManagerHooks;
|
||||
|
||||
@Mixin(TagManager.class)
|
||||
public class MixinTagManager implements FabricTagManagerHooks {
|
||||
@Shadow
|
||||
@Mutable
|
||||
@Final
|
||||
private Map<RegistryKey<? extends Registry<?>>, TagGroup<?>> tagGroups;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void init(Map<RegistryKey<? extends Registry<?>>, TagGroup<?>> tagGroups, CallbackInfo ci) {
|
||||
// Make it mutable so we can add dynamic registry tags later.
|
||||
this.tagGroups = new HashMap<>(tagGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fabric_addTagGroup(RegistryKey<? extends Registry<?>> registryKey, TagGroup<?> tagGroup) {
|
||||
tagGroups.put(registryKey, tagGroup);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.resource.ResourceManager;
|
||||
import net.minecraft.tag.RequiredTagList;
|
||||
import net.minecraft.tag.TagManagerLoader;
|
||||
|
||||
import net.fabricmc.fabric.impl.tag.extension.TagFactoryImpl;
|
||||
|
||||
@Mixin(TagManagerLoader.class)
|
||||
public abstract class MixinTagManagerLoader {
|
||||
// RequiredTagListRegistry.forEach in reload.
|
||||
@SuppressWarnings("UnresolvedMixinReference")
|
||||
@Inject(method = "method_33179", at = @At("HEAD"), cancellable = true)
|
||||
private void method_33179(ResourceManager resourceManager, Executor executor, List<?> list, RequiredTagList<?> requiredTagList, CallbackInfo ci) {
|
||||
// Don't load dynamic registry tags now, we need to load them after the dynamic registry.
|
||||
if (TagFactoryImpl.DYNAMICS.contains(requiredTagList)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,10 +3,15 @@
|
|||
"package": "net.fabricmc.fabric.mixin.tag.extension",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"mixins": [
|
||||
"AccessorFluidTags",
|
||||
"DynamicRegistryManagerAccessor",
|
||||
"MixinMinecraftServer",
|
||||
"MixinObjectBuilder",
|
||||
"MixinRegistryOps",
|
||||
"MixinRequiredTagListRegistry",
|
||||
"MixinTagBuilder",
|
||||
"MixinTagImpl",
|
||||
"MixinTagBuilder"
|
||||
"MixinTagManager",
|
||||
"MixinTagManagerLoader"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.tag.TagFactory;
|
||||
|
||||
public class TagExtensionTest implements ModInitializer {
|
||||
static final Tag<Biome> FACTORY_TEST = TagFactory.BIOME.create(new Identifier("fabric-tag-extensions-v0-testmod:factory_test"));
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(literal("biome_tag_test")
|
||||
.then(literal("factory").executes(context -> {
|
||||
FACTORY_TEST.values().forEach(biome -> {
|
||||
Identifier id = context.getSource().getRegistryManager().get(Registry.BIOME_KEY).getId(biome);
|
||||
context.getSource().sendFeedback(new LiteralText(id.toString()), false);
|
||||
});
|
||||
return 1;
|
||||
}))
|
||||
.then(literal("list_all").executes(context -> {
|
||||
Map<Identifier, Tag<Biome>> tags = context.getSource().getServer().getTagManager().getOrCreateTagGroup(Registry.BIOME_KEY).getTags();
|
||||
tags.forEach((tagId, tag) -> {
|
||||
LiteralText text = new LiteralText(tagId.toString() + ":");
|
||||
tag.values().forEach(biome -> {
|
||||
Optional<RegistryKey<Biome>> biomeKey = context.getSource().getRegistryManager().get(Registry.BIOME_KEY).getKey(biome);
|
||||
biomeKey.ifPresent(key -> text.append(" " + key.getValue()));
|
||||
});
|
||||
context.getSource().sendFeedback(text, false);
|
||||
});
|
||||
return 1;
|
||||
}))));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.extension;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
|
||||
public class TagExtensionTestClient implements ClientModInitializer {
|
||||
static final KeyBinding KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding("tag_test", GLFW.GLFW_KEY_EQUAL, "tag_test"));
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (KEY_BINDING.isPressed()) {
|
||||
TagExtensionTest.FACTORY_TEST.values().forEach(biome -> {
|
||||
Identifier id = client.getNetworkHandler().getRegistryManager().get(Registry.BIOME_KEY).getId(biome);
|
||||
client.player.sendMessage(new LiteralText(id.toString()), false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:plains",
|
||||
"minecraft:desert",
|
||||
"fabric-tag-extensions-v0-testmod:test"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:forest",
|
||||
"minecraft:taiga"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"surface_builder": "minecraft:grass",
|
||||
"depth": 0.125,
|
||||
"scale": 0.05,
|
||||
"temperature": 0.8,
|
||||
"downfall": 0.4,
|
||||
"precipitation": "rain",
|
||||
"category": "plains",
|
||||
"effects": {
|
||||
"sky_color": 7907327,
|
||||
"fog_color": 12638463,
|
||||
"water_color": 4159204,
|
||||
"water_fog_color": 329011
|
||||
},
|
||||
"starts": [],
|
||||
"spawners": {},
|
||||
"spawn_costs": {},
|
||||
"carvers": {},
|
||||
"features": []
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-tag-extensions-v0-testmod",
|
||||
"name": "Fabric Tag Extensions (v0) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-tag-extensions-v0": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.tag.extension.TagExtensionTest"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.tag.extension.TagExtensionTestClient"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue