From eca15a21614805caea09596c76041b61de0db4e5 Mon Sep 17 00:00:00 2001 From: Ashli Katt Date: Tue, 12 Mar 2024 18:50:33 -0500 Subject: [PATCH 1/2] Add CopyValueCommand for only locations --- .../recode/mod/commands/CommandHandler.java | 3 +- .../commands/impl/text/CopyValueCommand.kt | 94 +++++++++++++++++++ .../recode/mod/config/impl/CommandsGroup.java | 6 ++ .../recode/util/item/ValueItemUtils.kt | 32 +++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt create mode 100644 src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt diff --git a/src/main/java/io/github/homchom/recode/mod/commands/CommandHandler.java b/src/main/java/io/github/homchom/recode/mod/commands/CommandHandler.java index fddbf4a7..90597969 100644 --- a/src/main/java/io/github/homchom/recode/mod/commands/CommandHandler.java +++ b/src/main/java/io/github/homchom/recode/mod/commands/CommandHandler.java @@ -44,7 +44,8 @@ public static void load(CommandDispatcher dispatcher, new TitleCommand(), new SubTitleCommand(), new ActionbarCommand(), - new CalcCommand() + new CalcCommand(), + new CopyValueCommand() ); if (Config.getBoolean("dfCommands")) { diff --git a/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt b/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt new file mode 100644 index 00000000..edd0652a --- /dev/null +++ b/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt @@ -0,0 +1,94 @@ +package io.github.homchom.recode.mod.commands.impl.text + +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import com.mojang.brigadier.CommandDispatcher +import io.github.homchom.recode.mod.commands.Command +import io.github.homchom.recode.mod.commands.arguments.ArgBuilder +import io.github.homchom.recode.mod.config.Config +import io.github.homchom.recode.sys.player.chat.ChatType +import io.github.homchom.recode.sys.player.chat.ChatUtil +import io.github.homchom.recode.util.item.getDFValueItemData +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource +import net.minecraft.client.Minecraft +import net.minecraft.commands.CommandBuildContext +import net.minecraft.world.item.Items + +private const val COMMAND_NAME = "copyval" +private const val MUST_HOLD_AIR_ITEM = "You need to hold an item that is not air." +private const val MUST_USE_VALUE_ITEM = "You need to hold an value item, such as a location." +private const val INVALID_VALUE_ITEM_DATA = "The held item's value data is malformed." +private const val UNSUPPORTED_VALUE_ITEM = "This type of value item is unsupported for this command." +private const val SUCCESSFULLY_COPIED = "Value copied to clipboard!" + +/** + * This command will copy text to your clipboard based on the held DF Value. + * The value will be converted into text using a user-defined format in the mod config. + * This is primarily meant to be used for Text -> DiamondFire languages, allowing easy copying of locations in particular. + */ +class CopyValueCommand : Command() { + override fun register( + mc: Minecraft, + cd: CommandDispatcher, + context: CommandBuildContext + ) { + cd.register(ArgBuilder.literal(COMMAND_NAME).executes cmd@{ ctx -> + val heldItem = mc.player!!.mainHandItem + + // Disallow air items entirely + if (heldItem.item == Items.AIR) { + ChatUtil.sendMessage(MUST_HOLD_AIR_ITEM, ChatType.FAIL) + return@cmd -1 + } + + // Get valueitem data or error if it doesn't exist + val compound = heldItem.getDFValueItemData() + if (compound == null) { + ChatUtil.sendMessage(MUST_USE_VALUE_ITEM, ChatType.FAIL) + return@cmd -1 + } + + // Technically .asString can return "12" and whatnot for a number tag, but that doesn't matter in this case. + val id = compound.get("id")?.asJsonPrimitive?.asString + when (id) { + "loc" -> { + val dataObject = (compound.get("data") as? JsonObject)?.get("loc") as? JsonObject + val x = (dataObject?.get("x") as? JsonPrimitive)?.asDouble + val y = (dataObject?.get("y") as? JsonPrimitive)?.asDouble + val z = (dataObject?.get("z") as? JsonPrimitive)?.asDouble + val pitch = (dataObject?.get("pitch") as? JsonPrimitive)?.asDouble + val yaw = (dataObject?.get("yaw") as? JsonPrimitive)?.asDouble + + if (dataObject != null && x != null && y != null && z != null && pitch != null && yaw != null) { + val expression = Config.getString("itemTextFormatLocation") ?: "[%f, %f, %f, %f, %f]" + mc.keyboardHandler.clipboard = expression.format(x, y, z, pitch, yaw) + ChatUtil.sendMessage(SUCCESSFULLY_COPIED, ChatType.SUCCESS) + return@cmd 1 + } + } + null -> { + ChatUtil.sendMessage(INVALID_VALUE_ITEM_DATA, ChatType.FAIL) + return@cmd -1 + } + else -> { + ChatUtil.sendMessage(UNSUPPORTED_VALUE_ITEM, ChatType.FAIL) + return@cmd -1 + } + } + + ChatUtil.sendMessage(INVALID_VALUE_ITEM_DATA, ChatType.FAIL) + return@cmd -1 + }) + } + + override fun getDescription(): String { + return """ + [blue]/$COMMAND_NAME [text][reset] + + Copies the held DF value item to clipboard using the format defined in the mod config. + """.trimIndent() + } + + override fun getName() = "/$COMMAND_NAME" + +} \ No newline at end of file diff --git a/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java b/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java index abdb7d17..3d38d2e7 100644 --- a/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java +++ b/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java @@ -5,6 +5,7 @@ import io.github.homchom.recode.mod.config.types.BooleanSetting; import io.github.homchom.recode.mod.config.types.IntegerSetting; import io.github.homchom.recode.mod.config.types.LongSetting; +import io.github.homchom.recode.mod.config.types.StringSetting; public class CommandsGroup extends ConfigGroup { public CommandsGroup(String name) { @@ -30,5 +31,10 @@ public void initialize() { heads.register(new BooleanSetting("headsEnabled", false)); heads.register(new IntegerSetting("headMenuMaxRender", 1000)); this.register(heads); + + // copyval + ConfigSubGroup copyVal = new ConfigSubGroup("copyval"); + copyVal.register(new StringSetting("itemTextFormatLocation", "[%f, %f, %f, %f, %f]")); + this.register(copyVal); } } diff --git a/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt b/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt new file mode 100644 index 00000000..cedefdf4 --- /dev/null +++ b/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt @@ -0,0 +1,32 @@ +package io.github.homchom.recode.util.item + +import com.google.gson.Gson +import com.google.gson.JsonObject +import net.minecraft.world.item.ItemStack + +/** + * If this ItemStack is a DF ValueItem, returns its json object, otherwise return null. + * ValueItem compounds are in the following format: + * + * ```json + * { + * "id": , + * "data": + * } + * ``` + * + * @return This item's DF ValueItem JsonObject, if one exists. + */ +fun ItemStack.getDFValueItemData() : JsonObject? { + // TODO May need to change once Item Components release + val nbt = this.tag?.getCompound("tag") + ?.getCompound("PublicBukkitValues") + ?.getString("hypercube:varitem") + + if (nbt == null) { + return null + } + + val gson = Gson() + return gson.toJsonTree(nbt) as? JsonObject +} \ No newline at end of file From 9ce5bbb4a98bd87c5b2ad6b96f55f082eb68d496 Mon Sep 17 00:00:00 2001 From: Ashli Katt Date: Tue, 12 Mar 2024 20:26:00 -0500 Subject: [PATCH 2/2] Add string, text, number, vector --- .../commands/impl/text/CopyValueCommand.kt | 112 ++++++++++++++++-- .../recode/mod/config/impl/CommandsGroup.java | 12 ++ .../recode/util/item/ValueItemUtils.kt | 9 +- .../resources/assets/recode/lang/en_us.json | 29 +++++ 4 files changed, 150 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt b/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt index edd0652a..425ceb94 100644 --- a/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt +++ b/src/main/java/io/github/homchom/recode/mod/commands/impl/text/CopyValueCommand.kt @@ -16,11 +16,15 @@ import net.minecraft.world.item.Items private const val COMMAND_NAME = "copyval" private const val MUST_HOLD_AIR_ITEM = "You need to hold an item that is not air." -private const val MUST_USE_VALUE_ITEM = "You need to hold an value item, such as a location." -private const val INVALID_VALUE_ITEM_DATA = "The held item's value data is malformed." +private const val MUST_USE_VALUE_ITEM = "You need to hold a value item, such as a location." +private const val INVALID_VALUE_ITEM_DATA = "The held item's value data is malformed. ('data' tag invalid)" +private const val INVALID_VALUE_ITEM_ID = "The held item's value data is malformed. ('id' tag invalid)" private const val UNSUPPORTED_VALUE_ITEM = "This type of value item is unsupported for this command." private const val SUCCESSFULLY_COPIED = "Value copied to clipboard!" +// Numbers are stored as strings normally, this checks if a number string is a literal value or not +private val NUMBER_LITERAL_REGEX = Regex("\\d+(?:.\\d{0,3})?|.\\d{1,3}") + /** * This command will copy text to your clipboard based on the held DF Value. * The value will be converted into text using a user-defined format in the mod config. @@ -32,7 +36,7 @@ class CopyValueCommand : Command() { cd: CommandDispatcher, context: CommandBuildContext ) { - cd.register(ArgBuilder.literal(COMMAND_NAME).executes cmd@{ ctx -> + cd.register(ArgBuilder.literal(COMMAND_NAME).executes cmd@{ _ -> val heldItem = mc.player!!.mainHandItem // Disallow air items entirely @@ -50,7 +54,8 @@ class CopyValueCommand : Command() { // Technically .asString can return "12" and whatnot for a number tag, but that doesn't matter in this case. val id = compound.get("id")?.asJsonPrimitive?.asString - when (id) { + val result = when (id) { + // Location item "loc" -> { val dataObject = (compound.get("data") as? JsonObject)?.get("loc") as? JsonObject val x = (dataObject?.get("x") as? JsonPrimitive)?.asDouble @@ -61,21 +66,112 @@ class CopyValueCommand : Command() { if (dataObject != null && x != null && y != null && z != null && pitch != null && yaw != null) { val expression = Config.getString("itemTextFormatLocation") ?: "[%f, %f, %f, %f, %f]" - mc.keyboardHandler.clipboard = expression.format(x, y, z, pitch, yaw) - ChatUtil.sendMessage(SUCCESSFULLY_COPIED, ChatType.SUCCESS) - return@cmd 1 + expression.format(x, y, z, pitch, yaw) + } else { + null + } + } + + // Vector item + "vec" -> { + val dataObject = compound.get("data") as? JsonObject + val x = (dataObject?.get("x") as? JsonPrimitive)?.asDouble + val y = (dataObject?.get("y") as? JsonPrimitive)?.asDouble + val z = (dataObject?.get("z") as? JsonPrimitive)?.asDouble + + if (dataObject != null && x != null && y != null && z != null) { + val expression = Config.getString("itemTextFormatVector") ?: "<%f, %f, %f>" + expression.format(x, y, z) + } else { + null } } + + // String + "txt" -> { + val dataObject = compound.get("data") as? JsonObject + val name = (dataObject?.get("name") as? JsonPrimitive)?.asString + + if (dataObject != null && name != null) { + // TODO Could be replaced with a more powerful thing? (Such as a list of regex post-process replacement rules? Feels overkill) + val delimiter = Config.getString("itemTextFormatStringDelimiter") ?: "\"" + val escape = Config.getString("itemTextFormatStringEscape") ?: "\\" + val expression = Config.getString("itemTextFormatString") ?: "\"%s\"" + + if (delimiter.isNotEmpty() && escape.isNotEmpty()) { + val newName = name + .replace(escape, "$escape$escape") + .replace(delimiter, "$escape$delimiter") + + expression.format(newName) + } else { + expression.format(name) + } + } else { + null + } + } + + // Styled Text + "comp" -> { + val dataObject = compound.get("data") as? JsonObject + val name = (dataObject?.get("name") as? JsonPrimitive)?.asString + + if (dataObject != null && name != null) { + val delimiter = Config.getString("itemTextFormatTextDelimiter") ?: "\"" + val escape = Config.getString("itemTextFormatTextEscape") ?: "\\" + val expression = Config.getString("itemTextFormatText") ?: "T\"%s\"" + + if (delimiter.isNotEmpty() && escape.isNotEmpty()) { + val newName = name + .replace(escape, "$escape$escape") + .replace(delimiter, "$escape$delimiter") + + expression.format(newName) + } else { + expression.format(name) + } + } else { + null + } + } + + // Number + "num" -> { + val dataObject = compound.get("data") as? JsonObject + val name = (dataObject?.get("name") as? JsonPrimitive)?.asString // Yes, asString + + if (dataObject != null && name != null) { + val expression = if (NUMBER_LITERAL_REGEX.matches(name)) { + Config.getString("itemTextFormatNumberLiteral") ?: "%s" + } else { + Config.getString("itemTextFormatNumber") ?: "%s" + } + + expression.format(name) + } else { + null + } + } + + // General null -> { - ChatUtil.sendMessage(INVALID_VALUE_ITEM_DATA, ChatType.FAIL) + ChatUtil.sendMessage(INVALID_VALUE_ITEM_ID, ChatType.FAIL) return@cmd -1 } + else -> { ChatUtil.sendMessage(UNSUPPORTED_VALUE_ITEM, ChatType.FAIL) return@cmd -1 } } + if (result != null) { + mc.keyboardHandler.clipboard = result + ChatUtil.sendMessage(SUCCESSFULLY_COPIED, ChatType.SUCCESS) + return@cmd 1 + } + ChatUtil.sendMessage(INVALID_VALUE_ITEM_DATA, ChatType.FAIL) return@cmd -1 }) diff --git a/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java b/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java index 3d38d2e7..2a4835eb 100644 --- a/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java +++ b/src/main/java/io/github/homchom/recode/mod/config/impl/CommandsGroup.java @@ -34,7 +34,19 @@ public void initialize() { // copyval ConfigSubGroup copyVal = new ConfigSubGroup("copyval"); + copyVal.register(new StringSetting("itemTextFormatNumber", "%s")); + copyVal.register(new StringSetting("itemTextFormatNumberLiteral", "%s")); + copyVal.register(new StringSetting("itemTextFormatLocation", "[%f, %f, %f, %f, %f]")); + copyVal.register(new StringSetting("itemTextFormatVector", "<%f, %f, %f>")); + + copyVal.register(new StringSetting("itemTextFormatString", "\"%s\"")); + copyVal.register(new StringSetting("itemTextFormatStringEscape", "\\")); + copyVal.register(new StringSetting("itemTextFormatStringDelimiter", "\"")); + + copyVal.register(new StringSetting("itemTextFormatText", "T\"%s\"")); + copyVal.register(new StringSetting("itemTextFormatTextEscape", "\\")); + copyVal.register(new StringSetting("itemTextFormatTextDelimiter", "\"")); this.register(copyVal); } } diff --git a/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt b/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt index cedefdf4..e5d05f1a 100644 --- a/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt +++ b/src/main/java/io/github/homchom/recode/util/item/ValueItemUtils.kt @@ -2,6 +2,8 @@ package io.github.homchom.recode.util.item import com.google.gson.Gson import com.google.gson.JsonObject +import com.google.gson.JsonParser +import net.minecraft.nbt.CompoundTag import net.minecraft.world.item.ItemStack /** @@ -18,8 +20,8 @@ import net.minecraft.world.item.ItemStack * @return This item's DF ValueItem JsonObject, if one exists. */ fun ItemStack.getDFValueItemData() : JsonObject? { - // TODO May need to change once Item Components release - val nbt = this.tag?.getCompound("tag") + // TODO May need to change once Item Components release? + val nbt = this.tag ?.getCompound("PublicBukkitValues") ?.getString("hypercube:varitem") @@ -27,6 +29,5 @@ fun ItemStack.getDFValueItemData() : JsonObject? { return null } - val gson = Gson() - return gson.toJsonTree(nbt) as? JsonObject + return JsonParser.parseString(nbt) as? JsonObject } \ No newline at end of file diff --git a/src/main/resources/assets/recode/lang/en_us.json b/src/main/resources/assets/recode/lang/en_us.json index 690556b0..e29e46d8 100644 --- a/src/main/resources/assets/recode/lang/en_us.json +++ b/src/main/resources/assets/recode/lang/en_us.json @@ -91,6 +91,35 @@ "config.recode.option.autotimeval": "Auto /time value", "config.recode.option.autotimeval.tooltip": "Value to use in auto /time", + + "config.recode.subcategory.commands_copyval": "Copied Value Text Form", + "config.recode.subcategory.commands_copyval.tooltip": "Changes how /copyval generates\ntext versions of values.\nUses Java's formatting rules.", + + "config.recode.option.itemTextFormatNumber": "Number", + "config.recode.option.itemTextFormatNumber.tooltip": "Args:\n1. Value (String)", + "config.recode.option.itemTextFormatNumberLiteral": "Number Literal", + "config.recode.option.itemTextFormatNumberLiteral.tooltip": "Args:\n1. Value (String)\n\nUsed when a number value is just a single\nnumber with no % expressions.", + + "config.recode.option.itemTextFormatLocation": "Location", + "config.recode.option.itemTextFormatLocation.tooltip": "Args:\n1. X (double)\n2. Y (double)\n3. Z (double)\n4. Pitch (double)\n5. Yaw (double)", + "config.recode.option.itemTextFormatVector": "Vector", + "config.recode.option.itemTextFormatVector.tooltip": "Args:\n1. X (double)\n2. Y (double)\n3. Z (double)", + + "config.recode.option.itemTextFormatString": "String", + "config.recode.option.itemTextFormatString.tooltip": "Args:\n1. Value (String)", + "config.recode.option.itemTextFormatStringDelimiter": "String - Delimiter", + "config.recode.option.itemTextFormatStringDelimiter.tooltip": "If both this and delimiter are set,\nevery instance of this delimiter in\nthe source text will be preceded\nby the escape code.", + "config.recode.option.itemTextFormatStringEscape": "String - Escape", + "config.recode.option.itemTextFormatStringEscape.tooltip": "If both this and delimiter are set,\nevery instance of this escape will\nbe preceded by another escape code.", + + "config.recode.option.itemTextFormatText": "Styled Text", + "config.recode.option.itemTextFormatText.tooltip": "Args:\n1. Value (String)", + "config.recode.option.itemTextFormatTextDelimiter": "Styled Text - Delimiter", + "config.recode.option.itemTextFormatTextDelimiter.tooltip": "If both this and delimiter are set,\nevery instance of this delimiter in\nthe source text will be preceded\nby the escape code.", + "config.recode.option.itemTextFormatTextEscape": "Styled Text - Escape", + "config.recode.option.itemTextFormatTextEscape.tooltip": "If both this and delimiter are set,\nevery instance of this escape will\nbe preceded by another escape code.", + + "config.recode.option.autowand": "Auto //wand", "config.recode.option.autowand.tooltip": "Automatically runs //wand upon\nentering build mode", "config.recode.option.autoRC": "Auto /rc",