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:
KnightMiner committed 2021-05-12 19:46:34 -04:00
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'"
}