mirror of
https://github.com/GTNewHorizons/Mantle.git
synced 2026-11-12 16:27:41 +00:00
Add three tag commands to mantle
Command to list all tags for an entry Command to list all values in a tag Command to merge all JSON from datapacks into a single JSON
This commit is contained in:
1 parent
e4f532087f
commit
cede30d3fa
9 files changed
+689
-3
No files matched your search
@@ -13,6 +13,7 @@ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import slimeknights.mantle.command.MantleCommand;
|
||||
import slimeknights.mantle.config.Config;
|
||||
import slimeknights.mantle.loot.AddEntryLootModifier;
|
||||
import slimeknights.mantle.loot.MantleLoot;
|
||||
@@ -55,6 +56,7 @@ public class Mantle {
|
||||
|
||||
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||
MantleNetwork.registerPackets();
|
||||
MantleCommand.init();
|
||||
}
|
||||
|
||||
private void registerRecipeSerializers(final RegistryEvent.Register<IRecipeSerializer<?>> event) {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package slimeknights.mantle.command;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
import net.minecraft.command.arguments.ResourceLocationArgument;
|
||||
import net.minecraft.resources.IResource;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.tags.ITag;
|
||||
import net.minecraft.util.JSONUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import slimeknights.mantle.Mantle;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/** Command that dumps a tag into a JSON object */
|
||||
public class DumpTagCommand {
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final Dynamic2CommandExceptionType ERROR_READING_TAG = new Dynamic2CommandExceptionType((type, name) -> new TranslationTextComponent("command.mantle.dump_tag.read_error", type, name));
|
||||
|
||||
/**
|
||||
* Registers this sub command with the root command
|
||||
* @param subCommand Command builder
|
||||
*/
|
||||
public static void register(LiteralArgumentBuilder<CommandSource> subCommand) {
|
||||
subCommand.requires(sender -> sender.hasPermissionLevel(MantleCommand.PERMISSION_EDIT_SPAWN))
|
||||
.then(Commands.argument("type", TagCollectionArgument.collection())
|
||||
.then(Commands.argument("name", ResourceLocationArgument.resourceLocation())
|
||||
.executes(DumpTagCommand::run)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the view-tag command
|
||||
* @param context Tag context
|
||||
* @return Integer return
|
||||
* @throws CommandSyntaxException If invalid values are passed
|
||||
*/
|
||||
private static int run(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
TagCollectionArgument.Result type = context.getArgument("type", TagCollectionArgument.Result.class);
|
||||
ResourceLocation name = context.getArgument("name", ResourceLocation.class);
|
||||
IResourceManager manager = context.getSource().getServer().getDataPackRegistries().getResourceManager();
|
||||
|
||||
ResourceLocation path = new ResourceLocation(name.getNamespace(), "tags/" + type.getTagFolder() + "/" + name.getPath() + ".json");
|
||||
try {
|
||||
// fetch tags from all datapacks for this, logic mostly based on vanilla tag loader
|
||||
List<IResource> resources = manager.getAllResources(path);
|
||||
// simply create a tag builder
|
||||
ITag.Builder builder = ITag.Builder.create();
|
||||
int tagsProcessed = 0;
|
||||
for (IResource resource : resources) {
|
||||
try (
|
||||
InputStream inputstream = resource.getInputStream();
|
||||
Reader reader = new BufferedReader(new InputStreamReader(inputstream, StandardCharsets.UTF_8));
|
||||
) {
|
||||
JsonObject json = JSONUtils.fromJson(GSON, reader, JsonObject.class);
|
||||
if (json == null) {
|
||||
// no json
|
||||
Mantle.logger.error("Couldn't load {} tag list {} from {} in data pack {} as it is empty or null", type.getName(), name, path, resource.getPackName());
|
||||
} else {
|
||||
builder.deserialize(json, resource.getPackName());
|
||||
tagsProcessed++;
|
||||
}
|
||||
} catch (RuntimeException | IOException ex) {
|
||||
// failed to parse
|
||||
Mantle.logger.error("Couldn't read {} tag list {} from {} in data pack {}", type.getName(), name, path, resource.getPackName(), ex);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resource);
|
||||
}
|
||||
}
|
||||
|
||||
// builder done, ready to dump
|
||||
ITextComponent message = new TranslationTextComponent("command.mantle.dump_tag.success", type.getName(), name);
|
||||
context.getSource().sendFeedback(message, true);
|
||||
Mantle.logger.info("Tag dump of {} tag '{}':\n{}", type.getName(), name, GSON.toJson(builder.serialize()));
|
||||
return tagsProcessed;
|
||||
} catch (IOException ex) {
|
||||
// if the tag does not exist in the collect, probably an invalid tag name
|
||||
if (type.getCollection().get(name) == null) {
|
||||
throw ViewTagCommand.TAG_NOT_FOUND.create(type.getName(), name);
|
||||
} else {
|
||||
// tag exists and we still could not read it? something went wrong
|
||||
Mantle.logger.error("Couldn't read {} tag list {} from {}", type.getName(), name, path, ex);
|
||||
throw ERROR_READING_TAG.create(type.getName(), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package slimeknights.mantle.command;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
import net.minecraft.command.arguments.ArgumentSerializer;
|
||||
import net.minecraft.command.arguments.ArgumentTypes;
|
||||
import net.minecraft.world.GameRules;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Root command for all commands in mantle
|
||||
*/
|
||||
public class MantleCommand {
|
||||
/** Permission level that allows a user to build in spawn protected areas */
|
||||
public static final int PERMISSION_EDIT_SPAWN = 1;
|
||||
/** Permission level that can run standard game commands, used by command blocks and functions */
|
||||
public static final int PERMISSION_GAME_COMMANDS = 2;
|
||||
/** Standard permission level for server operators */
|
||||
public static final int PERMISSION_PLAYER_COMMANDS = 3;
|
||||
/** Permission level for the server owner, server console, or the player in single player */
|
||||
public static final int PERMISSION_OWNER = 4;
|
||||
|
||||
/** Registers all Mantle command related content */
|
||||
public static void init() {
|
||||
// register arguments
|
||||
ArgumentTypes.register("mantle:tag_collection", TagCollectionArgument.class, new ArgumentSerializer<>(TagCollectionArgument::collection));
|
||||
// add command listener
|
||||
MinecraftForge.EVENT_BUS.addListener(MantleCommand::registerCommand);
|
||||
}
|
||||
|
||||
/** Registers a sub command for the root Mantle command */
|
||||
private static void register(LiteralArgumentBuilder<CommandSource> root, String name, Consumer<LiteralArgumentBuilder<CommandSource>> consumer) {
|
||||
LiteralArgumentBuilder<CommandSource> subCommand = Commands.literal(name);
|
||||
consumer.accept(subCommand);
|
||||
root.then(subCommand);
|
||||
}
|
||||
|
||||
/** Event listener to register the Mantle command */
|
||||
private static void registerCommand(RegisterCommandsEvent event) {
|
||||
LiteralArgumentBuilder<CommandSource> builder = Commands.literal("mantle");
|
||||
|
||||
// sub commands
|
||||
register(builder, "view_tag", ViewTagCommand::register);
|
||||
register(builder, "dump_tag", DumpTagCommand::register);
|
||||
register(builder, "tags_for", TagsForCommand::register);
|
||||
|
||||
// register final command
|
||||
event.getDispatcher().register(builder);
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
/**
|
||||
* Returns true if the source either does not have reduced debug info or they have the proper level
|
||||
* Allows limiting a command that prints debug info to not work in reduced debug info
|
||||
* @param source Command source
|
||||
* @param reducedDebugLevel Level to use when reduced debug info is true
|
||||
* @return True if the command can be run
|
||||
*/
|
||||
public static boolean requiresDebugInfoOrOp(CommandSource source, int reducedDebugLevel) {
|
||||
return !source.getWorld().getGameRules().getBoolean(GameRules.REDUCED_DEBUG_INFO) || source.hasPermissionLevel(reducedDebugLevel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package slimeknights.mantle.command;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.minecraft.command.ISuggestionProvider;
|
||||
import net.minecraft.tags.ITagCollection;
|
||||
import net.minecraft.tags.TagCollectionManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import net.minecraftforge.common.ForgeTagHandler;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.RegistryManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Argument type that supports any tag collection
|
||||
*/
|
||||
@NoArgsConstructor(staticName = "collection")
|
||||
public class TagCollectionArgument implements ArgumentType<TagCollectionArgument.Result> {
|
||||
private static final Collection<String> EXAMPLES = Arrays.asList("minecraft:blocks", "minecraft:enchantments");
|
||||
private static final Iterable<ResourceLocation> ALL_COLLECTIONS_ITERABLE = CollectionIterator::new;
|
||||
// errors
|
||||
/* Tag collection name is invalid */
|
||||
private static final DynamicCommandExceptionType TAG_COLLECTION_NOT_FOUND = new DynamicCommandExceptionType(name -> new TranslationTextComponent("command.mantle.tag_collection.not_found", name));
|
||||
|
||||
/**
|
||||
* Gets the tag type for a vanilla tag
|
||||
* @param name Name
|
||||
* @return Tag type
|
||||
*/
|
||||
@Nullable
|
||||
private static Result getVanillaTags(ForgeRegistry<?> registry, ResourceLocation name) {
|
||||
for (VanillaTagType type : VanillaTagType.values()) {
|
||||
if (name.equals(type.getName())) {
|
||||
return Result.of(name, name.getPath() + "s", registry, type.getCollection());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result parse(StringReader reader) throws CommandSyntaxException {
|
||||
ResourceLocation name = ResourceLocation.read(reader);
|
||||
// first, find the proper registry, if no registry the tag is probably the wrong type
|
||||
ForgeRegistry<?> registry = RegistryManager.ACTIVE.getRegistry(name);
|
||||
if (registry != null) {
|
||||
// try vanilla tags next
|
||||
Result result = getVanillaTags(registry, name);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// then forge tags
|
||||
ITagCollection<?> collection = ForgeTagHandler.getCustomTagTypes().get(name);
|
||||
String tagFolder = registry.getTagFolder();
|
||||
if (collection != null && tagFolder != null) {
|
||||
return Result.of(name, tagFolder, registry, collection);
|
||||
}
|
||||
}
|
||||
throw TAG_COLLECTION_NOT_FOUND.create(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
|
||||
return ISuggestionProvider.suggestIterable(ALL_COLLECTIONS_ITERABLE, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getExamples() {
|
||||
return EXAMPLES;
|
||||
}
|
||||
|
||||
/** Data class for result, to ensure its unique to the mod */
|
||||
@Data(staticConstructor = "of")
|
||||
public static class Result {
|
||||
private final ResourceLocation name;
|
||||
private final String tagFolder;
|
||||
private final ForgeRegistry<?> registry;
|
||||
private final ITagCollection<?> collection;
|
||||
}
|
||||
|
||||
/** Enum containing all vanilla tag collection types */
|
||||
@AllArgsConstructor
|
||||
private enum VanillaTagType {
|
||||
BLOCK(Registry.BLOCK_KEY.getLocation(), () -> TagCollectionManager.getManager().getBlockTags()),
|
||||
ITEM(Registry.ITEM_KEY.getLocation(), () -> TagCollectionManager.getManager().getItemTags()),
|
||||
FLUID(Registry.FLUID_KEY.getLocation(), () -> TagCollectionManager.getManager().getFluidTags()),
|
||||
ENTITY_TYPE(Registry.ENTITY_TYPE_KEY.getLocation(), () -> TagCollectionManager.getManager().getEntityTypeTags());
|
||||
|
||||
@Getter
|
||||
private final ResourceLocation name;
|
||||
private final Supplier<ITagCollection<?>> supplier;
|
||||
|
||||
public ITagCollection<?> getCollection() {
|
||||
return supplier.get();
|
||||
}
|
||||
}
|
||||
|
||||
/** Iterator for all possible collection names */
|
||||
private static class CollectionIterator extends AbstractIterator<ResourceLocation> {
|
||||
private VanillaTagType nextVanilla = VanillaTagType.BLOCK;
|
||||
private final Iterator<ResourceLocation> forgeIterator = ForgeTagHandler.getCustomTagTypeNames().iterator();
|
||||
|
||||
@Override
|
||||
protected ResourceLocation computeNext() {
|
||||
// iterate vanilla tags first
|
||||
if (nextVanilla != null) {
|
||||
ResourceLocation result = nextVanilla.getName();
|
||||
// simply increase index by 1 through enum
|
||||
int nextIndex = nextVanilla.ordinal() + 1;
|
||||
VanillaTagType[] values = VanillaTagType.values();
|
||||
if (nextIndex < values.length) {
|
||||
nextVanilla = values[nextIndex];
|
||||
} else {
|
||||
// null means time for forge tags
|
||||
nextVanilla = null;
|
||||
}
|
||||
return result;
|
||||
// for forge, just redirect to the collection iterator
|
||||
} else if (forgeIterator.hasNext()) {
|
||||
return forgeIterator.next();
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
package slimeknights.mantle.command;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
import net.minecraft.command.arguments.ResourceLocationArgument;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.projectile.ProjectileHelper;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.SpawnEggItem;
|
||||
import net.minecraft.potion.Potion;
|
||||
import net.minecraft.potion.PotionUtils;
|
||||
import net.minecraft.potion.Potions;
|
||||
import net.minecraft.tags.ITagCollection;
|
||||
import net.minecraft.tags.TagCollectionManager;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.EntityRayTraceResult;
|
||||
import net.minecraft.util.math.RayTraceContext.FluidMode;
|
||||
import net.minecraft.util.math.RayTraceResult.Type;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.text.IFormattableTextComponent;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
import net.minecraftforge.common.ForgeTagHandler;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
||||
import net.minecraftforge.fluids.capability.templates.EmptyFluidHandler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Command to list all tags for an entry
|
||||
*/
|
||||
public class TagsForCommand {
|
||||
/** Tag type cannot be found */
|
||||
protected static final Dynamic2CommandExceptionType VALUE_NOT_FOUND = new Dynamic2CommandExceptionType((type, name) -> new TranslationTextComponent("command.mantle.tags_for.not_found", type, name));
|
||||
|
||||
/* Missing target errors */
|
||||
private static final ITextComponent NO_HELD_BLOCK = new TranslationTextComponent("command.mantle.view_tags.no_held_block");
|
||||
private static final ITextComponent NO_HELD_ENTITY = new TranslationTextComponent("command.mantle.view_tags.no_held_entity");
|
||||
private static final ITextComponent NO_HELD_POTION = new TranslationTextComponent("command.mantle.view_tags.no_held_potion");
|
||||
private static final ITextComponent NO_HELD_FLUID = new TranslationTextComponent("command.mantle.view_tags.no_held_fluid");
|
||||
private static final ITextComponent NO_HELD_ENCHANTMENT = new TranslationTextComponent("command.mantle.view_tags.no_held_enchantment");
|
||||
private static final ITextComponent NO_TARGETED_ENTITY = new TranslationTextComponent("command.mantle.view_tags.no_targeted_entity");
|
||||
private static final ITextComponent NO_TARGETED_TILE_ENTITY = new TranslationTextComponent("command.mantle.view_tags.no_targeted_tile_entity");
|
||||
/** Value has no tags */
|
||||
private static final ITextComponent NO_TAGS = new TranslationTextComponent("command.mantle.view_tags.no_tags");
|
||||
|
||||
/**
|
||||
* Registers this sub command with the root command
|
||||
* @param subCommand Command builder
|
||||
*/
|
||||
public static void register(LiteralArgumentBuilder<CommandSource> subCommand) {
|
||||
subCommand.requires(source -> MantleCommand.requiresDebugInfoOrOp(source, MantleCommand.PERMISSION_GAME_COMMANDS))
|
||||
// by registry ID
|
||||
.then(Commands.literal("id")
|
||||
.then(Commands.argument("type", TagCollectionArgument.collection())
|
||||
.then(Commands.argument("name", ResourceLocationArgument.resourceLocation())
|
||||
.executes(TagsForCommand::runForId))))
|
||||
// held item
|
||||
.then(Commands.literal("held")
|
||||
.then(Commands.literal("item").executes(TagsForCommand::heldItem))
|
||||
.then(Commands.literal("block").executes(TagsForCommand::heldBlock))
|
||||
.then(Commands.literal("enchantments").executes(TagsForCommand::heldEnchantments))
|
||||
.then(Commands.literal("fluid").executes(TagsForCommand::heldFluid))
|
||||
.then(Commands.literal("entity").executes(TagsForCommand::heldEntity))
|
||||
.then(Commands.literal("potion").executes(TagsForCommand::heldPotion)))
|
||||
// targeted
|
||||
.then(Commands.literal("targeted")
|
||||
.then(Commands.literal("tile_entity").executes(TagsForCommand::targetedTileEntity))
|
||||
.then(Commands.literal("entity").executes(TagsForCommand::targetedEntity)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the final list of owning tags
|
||||
* @param context Command context
|
||||
* @param collection Tag collection
|
||||
* @param typeName Tag name
|
||||
* @param name Value name
|
||||
* @param value Value to print
|
||||
* @param <T> Collection type
|
||||
* @return Number of tags printed
|
||||
*/
|
||||
private static <T> int printOwningTags(CommandContext<CommandSource> context, ITagCollection<T> collection, ResourceLocation typeName, ResourceLocation name, Object value) {
|
||||
// TODO: not sure if there is a better way to do this, it did come out of that registry
|
||||
IFormattableTextComponent output = new TranslationTextComponent("command.mantle.tags_for.success", typeName, name);
|
||||
Collection<ResourceLocation> tags = collection.getOwningTags((T)value);
|
||||
if (tags.isEmpty()) {
|
||||
output.appendString("\n* ").append(NO_TAGS);
|
||||
} else {
|
||||
tags.stream()
|
||||
.sorted(ResourceLocation::compareNamespaced)
|
||||
.forEach(tag -> output.appendString("\n* " + tag));
|
||||
}
|
||||
context.getSource().sendFeedback(output, true);
|
||||
return tags.size();
|
||||
}
|
||||
|
||||
|
||||
/* Standard way: by ID */
|
||||
|
||||
/** Run the registry ID subcommand */
|
||||
private static int runForId(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
TagCollectionArgument.Result result = context.getArgument("type", TagCollectionArgument.Result.class);
|
||||
ResourceLocation name = context.getArgument("name", ResourceLocation.class);
|
||||
|
||||
// first, fetch value
|
||||
if (!result.getRegistry().containsKey(name)) {
|
||||
throw VALUE_NOT_FOUND.create(result.getName(), name);
|
||||
}
|
||||
Object value = result.getRegistry().getValue(name);
|
||||
if (value == null) {
|
||||
throw VALUE_NOT_FOUND.create(result.getName(), name);
|
||||
}
|
||||
return printOwningTags(context, result.getCollection(), result.getName(), name, value);
|
||||
}
|
||||
|
||||
|
||||
/* Held item, can extract some data from the stack */
|
||||
|
||||
/** Item tags for held item */
|
||||
private static int heldItem(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
Item item = context.getSource().asPlayer().getHeldItemMainhand().getItem();
|
||||
return printOwningTags(context, TagCollectionManager.getManager().getItemTags(), Registry.ITEM_KEY.getLocation(), Objects.requireNonNull(item.getRegistryName()), item);
|
||||
}
|
||||
|
||||
/** Block tags for held item */
|
||||
private static int heldBlock(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
Item item = source.asPlayer().getHeldItemMainhand().getItem();
|
||||
Block block = Block.getBlockFromItem(item);
|
||||
if (block != Blocks.AIR) {
|
||||
return printOwningTags(context, TagCollectionManager.getManager().getBlockTags(), Registry.BLOCK_KEY.getLocation(), Objects.requireNonNull(block.getRegistryName()), block);
|
||||
}
|
||||
source.sendFeedback(NO_HELD_BLOCK, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Fluid tags for held item */
|
||||
private static int heldFluid(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
ItemStack stack = source.asPlayer().getHeldItemMainhand();
|
||||
LazyOptional<IFluidHandlerItem> capability = stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY);
|
||||
if (capability.isPresent()) {
|
||||
IFluidHandler handler = capability.map(h -> (IFluidHandler) h).orElse(EmptyFluidHandler.INSTANCE);
|
||||
if (handler.getTanks() > 0) {
|
||||
FluidStack fluidStack = handler.getFluidInTank(0);
|
||||
if (!fluidStack.isEmpty()) {
|
||||
Fluid fluid = fluidStack.getFluid();
|
||||
return printOwningTags(context, TagCollectionManager.getManager().getFluidTags(), Registry.FLUID_KEY.getLocation(), Objects.requireNonNull(fluid.getRegistryName()), fluid);
|
||||
}
|
||||
}
|
||||
}
|
||||
source.sendFeedback(NO_HELD_FLUID, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Potion tags for held item */
|
||||
private static int heldPotion(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
ItemStack stack = source.asPlayer().getHeldItemMainhand();
|
||||
Potion potion = PotionUtils.getPotionFromItem(stack);
|
||||
if (potion != Potions.EMPTY) {
|
||||
ResourceLocation registry = Registry.POTION_KEY.getLocation();
|
||||
return printOwningTags(context, ForgeTagHandler.getCustomTagTypes().get(registry), registry, Objects.requireNonNull(potion.getRegistryName()), potion);
|
||||
}
|
||||
source.sendFeedback(NO_HELD_POTION, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Block tags for held item */
|
||||
private static int heldEnchantments(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
ItemStack stack = source.asPlayer().getHeldItemMainhand();
|
||||
Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(stack);
|
||||
if (!enchantments.isEmpty()) {
|
||||
int totalTags = 0;
|
||||
ResourceLocation registry = Registry.ENCHANTMENT_KEY.getLocation();
|
||||
ITagCollection<?> enchantmentTags = ForgeTagHandler.getCustomTagTypes().get(registry);
|
||||
// print tags for each contained enchantment
|
||||
for (Enchantment enchantment : enchantments.keySet()) {
|
||||
totalTags += printOwningTags(context, enchantmentTags, registry, Objects.requireNonNull(enchantment.getRegistryName()), enchantment);
|
||||
}
|
||||
return totalTags;
|
||||
}
|
||||
source.sendFeedback(NO_HELD_ENCHANTMENT, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Entity tags for held item */
|
||||
private static int heldEntity(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
ItemStack stack = source.asPlayer().getHeldItemMainhand();
|
||||
if (stack.getItem() instanceof SpawnEggItem) {
|
||||
EntityType<?> type = ((SpawnEggItem) stack.getItem()).getType(stack.getTag());
|
||||
return printOwningTags(context, TagCollectionManager.getManager().getEntityTypeTags(), Registry.ENTITY_TYPE_KEY.getLocation(), Objects.requireNonNull(type.getRegistryName()), type);
|
||||
}
|
||||
source.sendFeedback(NO_HELD_ENTITY, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Targeted, based on look vector. Leaves out anything on the debug screen */
|
||||
|
||||
/**
|
||||
* Gets the tags for the fluid being looked at
|
||||
* @param context Context
|
||||
* @return Tags for the looked at block or entity
|
||||
* @throws CommandSyntaxException For command errors
|
||||
*/
|
||||
private static int targetedTileEntity(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
PlayerEntity player = source.asPlayer();
|
||||
World world = source.getWorld();
|
||||
BlockRayTraceResult blockTrace = Item.rayTrace(world, player, FluidMode.NONE);
|
||||
if (blockTrace.getType() == Type.BLOCK) {
|
||||
TileEntity te = world.getTileEntity(blockTrace.getPos());
|
||||
if (te != null) {
|
||||
TileEntityType<?> type = te.getType();
|
||||
ResourceLocation registry = Registry.BLOCK_ENTITY_TYPE_KEY.getLocation();
|
||||
return printOwningTags(context, ForgeTagHandler.getCustomTagTypes().get(registry), registry, Objects.requireNonNull(type.getRegistryName()), type);
|
||||
}
|
||||
}
|
||||
// failed
|
||||
source.sendFeedback(NO_TARGETED_TILE_ENTITY, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tags for the entity being looked at
|
||||
* @param context Context
|
||||
* @return Tags for the looked at block or entity
|
||||
* @throws CommandSyntaxException For command errors
|
||||
*/
|
||||
private static int targetedEntity(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
CommandSource source = context.getSource();
|
||||
PlayerEntity player = source.asPlayer();
|
||||
Vector3d start = player.getEyePosition(1F);
|
||||
Vector3d look = player.getLookVec();
|
||||
double range = Objects.requireNonNull(player.getAttribute(ForgeMod.REACH_DISTANCE.get())).getValue();
|
||||
Vector3d direction = start.add(look.x * range, look.y * range, look.z * range);
|
||||
AxisAlignedBB bb = player.getBoundingBox().expand(look.x * range, look.y * range, look.z * range).expand(1, 1, 1);
|
||||
EntityRayTraceResult entityTrace = ProjectileHelper.rayTraceEntities(source.getWorld(), player, start, direction, bb, e -> true);
|
||||
if (entityTrace != null) {
|
||||
EntityType<?> target = entityTrace.getEntity().getType();
|
||||
return printOwningTags(context, TagCollectionManager.getManager().getEntityTypeTags(), Registry.ENTITY_TYPE_KEY.getLocation(), Objects.requireNonNull(target.getRegistryName()), target);
|
||||
}
|
||||
// failed
|
||||
source.sendFeedback(NO_TARGETED_ENTITY, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package slimeknights.mantle.command;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.Commands;
|
||||
import net.minecraft.command.arguments.ResourceLocationArgument;
|
||||
import net.minecraft.tags.ITag;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.IFormattableTextComponent;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/** Command that lists all values in a tag */
|
||||
public class ViewTagCommand {
|
||||
/** Tag has no values */
|
||||
private static final ITextComponent EMPTY = new TranslationTextComponent("command.mantle.tag.empty");
|
||||
/** Tag type cannot be found */
|
||||
protected static final Dynamic2CommandExceptionType TAG_NOT_FOUND = new Dynamic2CommandExceptionType((type, name) -> new TranslationTextComponent("command.mantle.tag.not_found", type, name));
|
||||
|
||||
/**
|
||||
* Registers this sub command with the root command
|
||||
* @param subCommand Command builder
|
||||
*/
|
||||
public static void register(LiteralArgumentBuilder<CommandSource> subCommand) {
|
||||
subCommand.requires(source -> MantleCommand.requiresDebugInfoOrOp(source, MantleCommand.PERMISSION_GAME_COMMANDS))
|
||||
.then(Commands.argument("type", TagCollectionArgument.collection())
|
||||
.then(Commands.argument("name", ResourceLocationArgument.resourceLocation())
|
||||
.executes(ViewTagCommand::run)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the view-tag command
|
||||
* @param context Tag context
|
||||
* @return Integer return
|
||||
* @throws CommandSyntaxException If invalid values are passed
|
||||
*/
|
||||
private static int run(CommandContext<CommandSource> context) throws CommandSyntaxException {
|
||||
TagCollectionArgument.Result result = context.getArgument("type", TagCollectionArgument.Result.class);
|
||||
ResourceLocation name = context.getArgument("name", ResourceLocation.class);
|
||||
ITag<?> tag = result.getCollection().get(name);
|
||||
if (tag != null) {
|
||||
// start building output message
|
||||
IFormattableTextComponent output = new TranslationTextComponent("command.mantle.view_tag.success", result.getName(), name);
|
||||
Collection<?> values = tag.getAllElements();
|
||||
|
||||
// if no values, print empty
|
||||
if (values.isEmpty()) {
|
||||
output.appendString("\n* ").append(EMPTY);
|
||||
} else {
|
||||
values.stream()
|
||||
.filter(value -> value instanceof IForgeRegistryEntry)
|
||||
.map(value -> (IForgeRegistryEntry<?>) value)
|
||||
.sorted((a, b) -> Objects.requireNonNull(a.getRegistryName()).compareNamespaced(Objects.requireNonNull(b.getRegistryName())))
|
||||
.forEach(value -> output.appendString("\n* " + Objects.requireNonNull(value.getRegistryName()).toString()));
|
||||
}
|
||||
context.getSource().sendFeedback(output, true);
|
||||
return values.size();
|
||||
}
|
||||
throw TAG_NOT_FOUND.create(result.getName(), name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package slimeknights.mantle.command;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -44,3 +44,6 @@ public net.minecraft.world.gen.feature.template.Template field_204769_a # blocks
|
||||
|
||||
# DimensionType
|
||||
public net.minecraft.world.DimensionType field_236004_h_ # OVERWORLD_TYPE
|
||||
|
||||
# Ray trace for tags command
|
||||
public net.minecraft.item.Item func_219968_a(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/math/RayTraceContext$FluidMode;)Lnet/minecraft/util/math/BlockRayTraceResult; # rayTrace
|
||||
@@ -1,4 +1,24 @@
|
||||
{
|
||||
"mantle:tooltip.cooktime": "Cook Time: %ds",
|
||||
"config.mantle.extraHeartRenderer": "Enable Extra Heart Renderer"
|
||||
}
|
||||
"mantle:tooltip.cooktime": "Cook Time: %ds",
|
||||
"config.mantle.extraHeartRenderer": "Enable Extra Heart Renderer",
|
||||
|
||||
"command.mantle.view_tags.success": "Values for %s tag '%s':",
|
||||
"command.mantle.view_tags.not_found": "Unknown %s registry value '%s'",
|
||||
"command.mantle.view_tags.no_held_block": "Held item is not a block",
|
||||
"command.mantle.view_tags.no_held_entity": "Held item is not a spawn egg",
|
||||
"command.mantle.view_tags.no_held_potion": "Held item is not a potion",
|
||||
"command.mantle.view_tags.no_held_fluid": "Unable to get fluid from the held item",
|
||||
"command.mantle.view_tags.no_held_enchantment": "Held item is not enchanted",
|
||||
"command.mantle.view_tags.no_targeted_entity": "No entity within range",
|
||||
"command.mantle.view_tags.no_targeted_tile_entity": "No fluid within range",
|
||||
"command.mantle.view_tags.no_tags": "No tags",
|
||||
|
||||
"command.mantle.dump_tag.success": "Printed combined %s tag '%s' to console log",
|
||||
"command.mantle.dump_tag.read_error": "Error reading %s tag '%s':",
|
||||
|
||||
"command.mantle.tags_for.success": "%s tags for '%s':",
|
||||
|
||||
"command.mantle.tag.empty": "Empty",
|
||||
"command.mantle.tag_collection.not_found": "Unknown tag collection '%s'",
|
||||
"command.mantle.tag.not_found": "Unknown %s tag '%s'"
|
||||
}
|
||||
Reference in new issue
Block a user