From f295c028d4c61235ae3f4187cd4e9743e2bc6958 Mon Sep 17 00:00:00 2001 From: Jkibbels Date: Sat, 10 Aug 2024 15:19:42 -0400 Subject: [PATCH] [Historical] Committing for changes. Added colored chat in game + fleshed out more note commands Merge conflict paste error resolution [issue/note-commands] Fleshed out modifynote + documentation --- .../keeblarcraft/Commands/NoteCommands.java | 206 +++++++++++++++--- .../Commands/ShortcutCommands.java | 4 +- .../JsonClassObjects/PlayerNote.java | 176 +++++++++++---- .../java/jesse/keeblarcraft/Keeblarcraft.java | 3 +- .../jesse/keeblarcraft/Utils/ChatUtil.java | 91 +++++++- 5 files changed, 404 insertions(+), 76 deletions(-) diff --git a/src/main/java/jesse/keeblarcraft/Commands/NoteCommands.java b/src/main/java/jesse/keeblarcraft/Commands/NoteCommands.java index eef027f..656839b 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/NoteCommands.java +++ b/src/main/java/jesse/keeblarcraft/Commands/NoteCommands.java @@ -1,12 +1,8 @@ package jesse.keeblarcraft.Commands; -import java.util.UUID; - -import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; -import com.mojang.datafixers.Products.P1; import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.JsonClassObjects.PlayerNote; @@ -19,13 +15,16 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; public class NoteCommands { - - // IMPORTANT NOTE: - // - // Each player will retain their own private file of notes inside a "notes" directory inside the overall mod config directory + /// Class Variables ConfigManager notesConfig = new ConfigManager(); String NOTES_GLOBAL_DIRECTORY = "notes"; // The overall "notes" dir inside cfg folder + ///////////////////////////////////////////////////////////////////////////// + /// @fn NoteCommands + /// + /// @brief This classes non-trivial constructor. Ensures creation + // of notes directory exists before commands can be ran + ///////////////////////////////////////////////////////////////////////////// public NoteCommands() { // Check if directory exists if (notesConfig.DoesDirectoryExist(NOTES_GLOBAL_DIRECTORY) == false) { @@ -44,6 +43,11 @@ public class NoteCommands { } } + ///////////////////////////////////////////////////////////////////////////// + /// @fn RegisterNoteCommands + /// + /// @brief Registers all the commands for this class + ///////////////////////////////////////////////////////////////////////////// public void RegisterNoteCommands() { // Command: "/addnote note goes here" CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { @@ -62,15 +66,21 @@ public class NoteCommands { // Command: "/purgenotes" CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { dispatcher.register(CommandManager.literal("purgenotes") - .then(CommandManager.argument("value", StringArgumentType.greedyString()) - .executes(context -> PurgeAllNotes(StringArgumentType.getString(context, "value"), context)))); + .executes(context -> PurgeAllNotes(context))); }); - // Command: "/modifynote noteIdHere" + // Command: "/modifynote noteIdHere new_note_string_here" + // Alises: "/editnote" CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { - dispatcher.register(CommandManager.literal("editnote") - .then(CommandManager.argument("value", IntegerArgumentType.integer()) - .executes(context -> ModifyNote(IntegerArgumentType.getInteger(context, "value"), context)))); + final var mNote = dispatcher.register(CommandManager.literal("editnote") + .then(CommandManager.argument("note_id", IntegerArgumentType.integer()) + .then(CommandManager.argument("new_note", StringArgumentType.string()) + .executes(context -> ModifyNote( + IntegerArgumentType.getInteger(context, "note_id"), + StringArgumentType.getString(context, "new_note"), + context))))); + + dispatcher.register(CommandManager.literal("editnote").redirect(mNote)); }); // Command Root: "/delnote noteIdHere" @@ -84,14 +94,39 @@ public class NoteCommands { dispatcher.register(CommandManager.literal("rmnote").redirect(rootDeleteCmd)); dispatcher.register(CommandManager.literal("deletenote").redirect(rootDeleteCmd)); }); + + // Command Root: "/notegui" + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + dispatcher.register(CommandManager.literal("notegui") + .executes(context -> { OpenNoteGui(context); + return 0; + })); + }); + + // Command Root: "/notelist" + // Aliases: "/listnotes" + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + final var rootListNotes = dispatcher.register(CommandManager.literal("notelist") + .executes(context -> { ListNotes(context); + return 0; + })); + + dispatcher.register(CommandManager.literal("listnotes").redirect(rootListNotes)); + }); } - /// COMMAND HANDLERS BELOW - - // AddNote - // - // Adds a new note based on the string value provided by the player. The note is labeled in the background based on the portion - // of the story they are currently in as well to help provide filtering methods later on + ///////////////////////////////////////////////////////////////////////////// + /// @fn AddNote + /// + /// @brief Adds a new note to the players notebook + /// + /// @arg[in] value is the new note to be added + /// + /// @arg[in] context is the context of the ServerCommandSource object + /// the command was run with + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// private Integer AddNote(String value, CommandContext context) { Integer ret = -1; @@ -111,39 +146,154 @@ public class NoteCommands { return ret; } + ///////////////////////////////////////////////////////////////////////////// + /// @fn DeleteNote + /// + /// @brief Deletes a note by id + /// + /// @arg[in] value is the integer ID of the note to be deleted + /// + /// @arg[in] context is the context of the ServerCommandSource object + /// the command was run with + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// private int DeleteNote(int value, CommandContext context) { int ret = -1; - return ret; - } + if (context.getSource().isExecutedByPlayer()) { + ServerPlayerEntity player = context.getSource().getPlayer(); - private int ModifyNote(int value, CommandContext context) { - int ret = -1; + PlayerNote note = new PlayerNote(player.getUuidAsString()); + ChatUtil.SendPlayerMsg(player, "Deleted note entry. View notes any time with /notegui"); + + ret = 0; + note.DeleteNote(value); + } else { + System.out.println("Only a player can execute this command!"); + } return ret; } - private int PurgeAllNotes(String value, CommandContext context) { + ///////////////////////////////////////////////////////////////////////////// + /// @fn ModifyNote + /// + /// @brief Modifies a single note by id value + /// + /// @arg[in] value is the integer ID of the note to be modified + /// + /// @arg[in] newNote is the new version of the edited note + /// + /// @arg[in] context is the context of the ServerCommandSource object + /// the command was run with + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// + private int ModifyNote(Integer value, String newNote, CommandContext context) { int ret = -1; + if (context.getSource().isExecutedByPlayer() && value > 0) { + ServerPlayerEntity player = context.getSource().getPlayer(); + PlayerNote note = new PlayerNote(player.getUuidAsString()); + + long time = context.getSource().getWorld().getTime(); + // long day = ; ///TODO: Docs lack this for some reason? Add in future + long epochTime = System.currentTimeMillis(); + long storyChapter = -1; // Intentional garbage until story is fleshed out later (TODO) + long storyPart = -1; // Intentional garbage until story is fleshed out later (TODO) + + note.ModifyNote(value, newNote, epochTime, storyChapter, storyPart); + + ret = 0; + } + return ret; } - private int ListNotes(String value, CommandContext context) { + ///////////////////////////////////////////////////////////////////////////// + /// @fn PurgeAllNotes + /// + /// @brief Removes all notes from a players note file + /// + /// @arg[in] context is the context of the ServerCommandSource object + /// the command was run with + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// + private int PurgeAllNotes(CommandContext context) { int ret = -1; + if (context.getSource().isExecutedByPlayer()) { + ServerPlayerEntity player = context.getSource().getPlayer(); + + PlayerNote note = new PlayerNote(player.getUuidAsString()); + note.PurgeAllNotes(); + ChatUtil.SendPlayerMsg(player, "Purged all notes. View notes any time with /notegui"); + + ret = 0; + } else { + System.out.println("Only a player can execute this command!"); + } + return ret; } - private int OpenNoteGui(String value, CommandContext context) { + ///////////////////////////////////////////////////////////////////////////// + /// @fn ListNotes + /// + /// @brief Lists notes in pages in the players active chat + /// + /// @arg[in] context is the context of the ServerCommandSource object + /// the command was run with + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// + private int ListNotes(CommandContext context) { int ret = -1; + if (context.getSource().isExecutedByPlayer()) { + ServerPlayerEntity player = context.getSource().getPlayer(); + + PlayerNote notes = new PlayerNote(player.getUuidAsString()); + ChatUtil.SendPlayerMsg(player, "Listing all notes..."); + for (int i = 0; i <= notes.GetNotebookSize(); i++) { + String individualNote = notes.GetNoteString(i); + if (individualNote != "") { + ChatUtil.SendPlayerMsg(player, "Note " + i + ": " + individualNote); + } + } + + ret = 0; + } else { + System.out.println("Only a player can execute this command!"); + } + return ret; } - private int FilterForNote(String value, CommandContext context) { + ///TODO: Blocked until GUI manager is available + ///////////////////////////////////////////////////////////////////////////// + /// @fn OpenNoteGui + /// + /// @brief Opens up the graphical display of the note manager + /// + /// @arg[in] context is the context of the ServerCommandSource object + /// the command was run with + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// + private int OpenNoteGui(CommandContext context) { int ret = -1; + if (context.getSource().isExecutedByPlayer()) { + ServerPlayerEntity player = context.getSource().getPlayer(); + + ret = 0; + } else { + System.out.println("Only a player can execute this command!"); + } + return ret; } } diff --git a/src/main/java/jesse/keeblarcraft/Commands/ShortcutCommands.java b/src/main/java/jesse/keeblarcraft/Commands/ShortcutCommands.java index 0b73ebe..09400aa 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/ShortcutCommands.java +++ b/src/main/java/jesse/keeblarcraft/Commands/ShortcutCommands.java @@ -21,7 +21,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; public class ShortcutCommands { - + float DEFAULT_FLIGHT_SPEED = 0.05f; // Minecraft operates on a 0.0 -> 1.0 scale; with each .01 making a difference in speed. 0.05 is creative flight speed float SPEED_SCALAR = 20.0f; // For clamping speed down to half of its max output (So 0.5 will be max speed on a system that goes up in 0.05'ths) @@ -34,7 +34,7 @@ public class ShortcutCommands { .executes(context -> GamemodeShortcut(IntegerArgumentType.getInteger(context, "value"), context)))); }); - // Fly command ///TODO: Is this just being condensed into the FlightSpeedShortcut fn? + // Fly command CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { dispatcher.register(CommandManager.literal("fly") .executes(context -> { FlightShortcut(context); diff --git a/src/main/java/jesse/keeblarcraft/JsonClassObjects/PlayerNote.java b/src/main/java/jesse/keeblarcraft/JsonClassObjects/PlayerNote.java index 12ca41e..d95e9f8 100644 --- a/src/main/java/jesse/keeblarcraft/JsonClassObjects/PlayerNote.java +++ b/src/main/java/jesse/keeblarcraft/JsonClassObjects/PlayerNote.java @@ -7,7 +7,6 @@ package jesse.keeblarcraft.JsonClassObjects; -import java.math.BigInteger; import java.util.HashMap; import java.util.Map.Entry; @@ -17,13 +16,25 @@ import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION; public class PlayerNote { + /// Class variables + NoteFile thisNote = new NoteFile(); + ConfigManager config = new ConfigManager(); - // Internal class structure that defines a blank note. It represents the overall loaded json object + ///////////////////////////////////////////////////////////////////////////// + /// @class NoteMetadata + /// + /// @brief The metadata that is attached to each entry in the notebook. + /// This includes not just the note itself, but other important + /// factors that can be characteristic to each note and useful + /// + /// @note You can picture this as each page in the notebook if it's + /// an easier mental image + ///////////////////////////////////////////////////////////////////////////// private class NoteMetadata { - public NoteMetadata(String note, long id, long mcday, long sysTime, long chapter, long part) { + public NoteMetadata(String note, long id, /*long mcday,*/ long sysTime, long chapter, long part) { this.note = note; this.noteId = id; - this.minecraftDay = mcday; + // this.minecraftDay = mcday; this.systemTime = sysTime; this.storyChapter = chapter; this.storyPart = part; @@ -32,50 +43,31 @@ public class PlayerNote { String note; // The note itself long noteId; // Copied in from the file name, noteId - long minecraftDay; // The minecraft day the note was taken on + // long minecraftDay; // The minecraft day the note was taken on long systemTime; // The current system time of the server long storyChapter; // The chapter of the story the player is in long storyPart; // Every event in a story is one part } + ///////////////////////////////////////////////////////////////////////////// + /// @class NoteFile + /// + /// @brief This is the notebook + ///////////////////////////////////////////////////////////////////////////// public class NoteFile { - // Players uuid is the name of the file String uuid; - - // Contents of file - /* - * Example: - * player_uuid_here: - * { - * "1": - * { - * "note": "this is the players first note"; - * "noteId": "1"; - * "minecraftDay": "443"; - * "systemTime": "4849892839823"; - * "storyChapter": "3"; - * "storyPart": "2"; - * } - * "2": - * { - * Etc. - * } - * } - */ public HashMap noteMap = new HashMap(); } - - NoteFile thisNote = new NoteFile(); - ConfigManager config = new ConfigManager(); - - class TestClass { - String testString; - } - - // PlayerNote - // - // String uuid - The uuid of the player (used in searching for existing notes file and writing to it) + ///////////////////////////////////////////////////////////////////////////// + /// @fn PlayerNote + /// + /// @brief This class's non-trivial constructor. Grabs a handle on the + /// server-side file that is the players notebook at object + /// creation. If one does not exist, one is created + /// + /// @arg[in] uuid is the players uuid value + ///////////////////////////////////////////////////////////////////////////// public PlayerNote(String uuid) { // DEVELOPER NOTE: @@ -112,23 +104,114 @@ public class PlayerNote { } } + ///////////////////////////////////////////////////////////////////////////// + /// @fn AddNote + /// + /// @brief Adds a new note to the notebook + /// + /// @arg[in] newNote is the new string value of the note + /// + /// @arg[in] minecraftDay is currently unsupported but will be the day of + /// the minecraft world when it is implemented + /// + /// @arg[in] systemTime is the epoch time in milliseconds + /// + /// @arg[in] storyChapter is the chapter in the story this note was taken + /// + /// @arg[in] storyPart is the part in the chapter the note was taken + ///////////////////////////////////////////////////////////////////////////// public void AddNote(String newNote, long minecraftDay, long systemTime, long storyChapter, long storyPart) { Integer noteKey = thisNote.noteMap.size() + 1; - thisNote.noteMap.put(noteKey, new NoteMetadata(newNote, noteKey, minecraftDay, systemTime, storyChapter, storyPart)); + thisNote.noteMap.put(noteKey, new NoteMetadata(newNote, noteKey, /*minecraftDay,*/ systemTime, storyChapter, storyPart)); FlashConfig(); ///TODO: This might be really unnecessary and may only be required on clean up as opposed to everytime the command is run } + ///////////////////////////////////////////////////////////////////////////// + /// @fn DeleteNote + /// + /// @brief Deletes a note in the notebook + /// + /// @arg[in] noteId is the id to delete + ///////////////////////////////////////////////////////////////////////////// public void DeleteNote(Integer noteId) { thisNote.noteMap.remove(noteId); + FlashConfig(); } - public void ModifyNote(Integer noteId, String newNote, long minecraftDay, long systemTime, long storyChapter, long storyPart) { - thisNote.noteMap.put(noteId, new NoteMetadata(newNote, noteId, minecraftDay, systemTime, storyChapter, storyPart)); + ///////////////////////////////////////////////////////////////////////////// + /// @fn ModifyNote + /// + /// @brief Modifies a note at noteId entry OR creates new note at that + /// entry if the id didn't exist previously + /// + /// @arg[in] noteId is the id we wish to modify the note of + /// + /// @arg[in] newNote is the new string value of the note + /// + /// @arg[in] minecraftDay is currently unsupported but will be the day of + /// the minecraft world when it is implemented + /// + /// @arg[in] systemTime is the epoch time in milliseconds + /// + /// @arg[in] storyChapter is the chapter in the story this note was taken + /// + /// @arg[in] storyPart is the part in the chapter the note was taken + /// + /// @return 0 if success, -1 if not + ///////////////////////////////////////////////////////////////////////////// + public void ModifyNote(Integer noteId, String newNote, /*long minecraftDay,*/ long systemTime, long storyChapter, long storyPart) { + thisNote.noteMap.put(noteId, new NoteMetadata(newNote, noteId, /*minecraftDay,*/ systemTime, storyChapter, storyPart)); + FlashConfig(); } - // Find the key of a note if it exists (O(n) search time) - // Returns -1 on failure to find note key + ///////////////////////////////////////////////////////////////////////////// + /// @fn PurgeAllNotes + /// + /// @brief Wipes the players notebook clean + ///////////////////////////////////////////////////////////////////////////// + public void PurgeAllNotes() { + thisNote.noteMap.clear(); + FlashConfig(); + } + + ///////////////////////////////////////////////////////////////////////////// + /// @fn GetNoteString + /// + /// @brief Gets the note string in the map by identifier. NOT metadata + /// + /// @arg[in] key is the map key we wish to return + /// + /// @return Empty string if that ID contains no note, or string with note + ///////////////////////////////////////////////////////////////////////////// + public String GetNoteString(Integer key) { + if (thisNote.noteMap.containsKey(key)) { + return thisNote.noteMap.get(key).note; + } else { + return ""; + } + } + + ///////////////////////////////////////////////////////////////////////////// + /// @fn GetNotebookSize + /// + /// @brief Returns the size of the notebook object + /// + /// @return Size of notebook + ///////////////////////////////////////////////////////////////////////////// + public Integer GetNotebookSize() { + return thisNote.noteMap.size(); + } + + ///////////////////////////////////////////////////////////////////////////// + /// @fn GetNoteKey + /// + /// @brief Returns the key identifier of a note by the value in the map + /// + /// @arg[in] currentNote is the string note that we wish to see if exists + /// + /// @return 0 or positive number if key found, negative number if not + ///////////////////////////////////////////////////////////////////////////// public Integer GetNoteKey(String currentNote) { Integer ret = -1; for (Entry entry : thisNote.noteMap.entrySet()) { @@ -136,10 +219,15 @@ public class PlayerNote { ret = entry.getKey(); } } - + FlashConfig(); return ret; } + ///////////////////////////////////////////////////////////////////////////// + /// @fn FlashConfig + /// + /// @brief Writes to the configuration file + ///////////////////////////////////////////////////////////////////////////// public void FlashConfig() { try { config.WriteToJsonFile("notes/" + thisNote.uuid.toString() + ".json", thisNote); diff --git a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java index f981ba6..b8c6ab4 100644 --- a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java +++ b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java @@ -7,10 +7,11 @@ * */ +// color colour + package jesse.keeblarcraft; import net.fabricmc.api.ModInitializer; -// import net.minecraft.server.command.ServerCommandSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/jesse/keeblarcraft/Utils/ChatUtil.java b/src/main/java/jesse/keeblarcraft/Utils/ChatUtil.java index a71305b..b8478ae 100644 --- a/src/main/java/jesse/keeblarcraft/Utils/ChatUtil.java +++ b/src/main/java/jesse/keeblarcraft/Utils/ChatUtil.java @@ -11,11 +11,16 @@ package jesse.keeblarcraft.Utils; import org.slf4j.Logger; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Map.Entry; public class ChatUtil { //This is a private class only used internally to get ANSI colors - private static class ConsoleColor { + private static class ConsoleColor { public static String getColor(CONSOLE_COLOR color) { String ret = ""; switch(color) { @@ -51,11 +56,95 @@ public class ChatUtil { CYAN; } + static int CHATBOX_WIDTH_CHARS = 80; // Maximum length of the textbox in individual characters + // Helpful print wrapper function static public void SendPlayerMsg(ServerPlayerEntity player, String text) { player.sendMessage(Text.literal(text)); } + /// TODO: Add this back in later under a chat ticket + // Prints a table of data in chat + // static public void ChatBlock(ServerPlayerEntity player, HashMap> table) { + + // ///DEBUG + // for (Entry> entry : table.entrySet()) { + // for (int debug = 0; debug < entry.getValue().size(); debug++) { + // System.out.println("KEY: " + entry.getKey().toString() + " VALUE: " + entry.getValue().get(debug).toString()); + // } + + // } + + // // The user will likely pass in text strings longer than the character limit for num of columns; therefore + // // we are required to split these into this finalPrintList structure + // HashMap> finalPrintList = new HashMap>(); + + // int maxColumnWidth = CHATBOX_WIDTH_CHARS / table.size(); // Represents max char allowance per data column + // maxColumnWidth -= table.size(); // Represents a separating '|' between each column + + // // This first behemoth of a loop is to take the given table hashmap and look at + // // the Text values & split them + // // should their size exceed the maxColumnWidth given for each entry key + // System.out.println("Entry data is size " + table.size()); + // for (Entry> entry : table.entrySet()) { + // // Each text line found cannot be longer than "maxColumnWidth" or else it must + // // wrap which splits it + // // into two texts; thus adding an additional row that is required for iteration. + // // Each split text must + // // maintain the same formatting as the root text it is split from + + // finalPrintList.put(entry.getKey(), new ArrayList()); // Instantiate the key & array + // System.out.println("Map size is " + finalPrintList.size()); + // System.out.println("Entry value size is " + entry.getValue().size()); + // for (Text item : entry.getValue()) { + // int numItems = (int) Math.ceil((item.getString().length() / maxColumnWidth)); + // int strOffset = numItems; // Represents number of items per string + // System.out.println("numItems: " + numItems); + // System.out.println("strOffset: " + strOffset); + + // for (int offset = 0; offset <= numItems; offset++) { /// TODO: might need to be <= + // int start = strOffset * offset; // Multiple from start of string to needed point + // int end = start + strOffset; // The original start offset + the width spacer + // String substr = item.toString().substring(start, end); // Contains the string to be Textified + + // MutableText newText = Text.literal(substr).setStyle(item.getStyle()); + // finalPrintList.get(entry.getKey()).add(newText); // Add back into list + // System.out.println("SPLIT DEBUG: " + newText.toString()); + // } + // } + // } + + // // This loop does the printing of the table in chat + // int tempPreventInfiniteLoops = 10; + // while (finalPrintList.size() != 0) { + + // // This is a one time print + // MutableText line = Text.literal(""); + // for (Entry> entry : finalPrintList.entrySet()) { + // if (entry.getValue().size() != 0) { + // line.append(entry.getValue().get(0)); + + // System.out.println("new line is now " + line.toString()); + // line.append("|"); + // } else { + // finalPrintList.remove(entry.getKey()); // Clear the key; as we are done with this column for + // // printing + // } + + // player.sendMessage(line); + // String debugPrint = line.toString(); + // System.out.println("Debug line to be printed: " + debugPrint); + // line = Text.literal(""); + // break; + // } + + // tempPreventInfiniteLoops--; + // if (tempPreventInfiniteLoops <= 0) { + // return; + // } + // } + // } + // Returns a string with the proper ANSI encoding for the specified CONSOLE_COLOR static public String ColoredString(String msg, CONSOLE_COLOR color) { return "\033[" + ConsoleColor.getColor(color) + "m" + msg + "\033[0m";