diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index 89980d349925..f39af3f07d2a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -51,6 +51,7 @@ import at.hannibal2.skyhanni.features.garden.fortuneguide.FFGuideGUI import at.hannibal2.skyhanni.features.garden.pests.PestFinder import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomLinesGui import at.hannibal2.skyhanni.features.mining.KingTalismanHelper import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker import at.hannibal2.skyhanni.features.minion.MinionFeatures @@ -66,6 +67,7 @@ import at.hannibal2.skyhanni.features.misc.visualwords.VisualWordGui import at.hannibal2.skyhanni.features.rift.area.westvillage.VerminTracker import at.hannibal2.skyhanni.features.slayer.SlayerProfitTracker import at.hannibal2.skyhanni.test.DebugCommand +import at.hannibal2.skyhanni.test.GraphEditor import at.hannibal2.skyhanni.test.PacketTest import at.hannibal2.skyhanni.test.SkyHanniConfigSearchResetCommand import at.hannibal2.skyhanni.test.SkyHanniDebugsAndTests @@ -530,6 +532,10 @@ object Commands { "shaddfoundburrowlocationsfromclipboard", "Add all ever found burrow locations from clipboard" ) { AllBurrowsList.addFromClipboard() } + registerCommand( + "shgraph", + "Enables the graph editor" + ) { GraphEditor.commandIn() } registerCommand( "shtoggleegglocationdebug", "Shows Hoppity egg locations with their internal API names and status." @@ -538,6 +544,7 @@ object Commands { private fun internalCommands() { registerCommand("shaction", "") { ChatClickActionManager.onCommand(it) } + registerCommand("shcustomlines", "Opens the config list for modifying custom lines") { openCustomLines() } } private fun shortenedCommands() { @@ -568,6 +575,15 @@ object Commands { } } + @JvmStatic + fun openCustomLines() { + if (!LorenzUtils.onHypixel) { + ChatUtils.userError("You need to join Hypixel to use this feature!") + } else { + SkyHanniMod.screenToOpen = CustomLinesGui() + } + } + private fun clearFarmingItems() { val storage = GardenAPI.storage?.fortune ?: return ChatUtils.chat("clearing farming items") diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java index e99fb656cedf..041134e416cc 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java @@ -103,6 +103,10 @@ public class DevConfig { @Category(name = "Minecraft Console", desc = "Minecraft Console Settings") public MinecraftConsoleConfig minecraftConsoles = new MinecraftConsoleConfig(); + @Expose + @Category(name = "Dev Tools", desc = "Tooling for devs") + public DevToolConfig devTool = new DevToolConfig(); + @Expose @Category(name = "Debug Mob", desc = "Every Debug related to the Mob System") public DebugMobConfig mobDebug = new DebugMobConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevToolConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevToolConfig.java new file mode 100644 index 000000000000..bd84cacaa994 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevToolConfig.java @@ -0,0 +1,14 @@ +package at.hannibal2.skyhanni.config.features.dev; + +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class DevToolConfig { + + @Expose + @ConfigOption(name = "Graph Tools", desc = "") + @Accordion + public GraphConfig graph = new GraphConfig(); + +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java new file mode 100644 index 000000000000..d5ee553f6791 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java @@ -0,0 +1,76 @@ +package at.hannibal2.skyhanni.config.features.dev; + +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import org.lwjgl.input.Keyboard; + +public class GraphConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Enables the graphing tool.") + @ConfigEditorBoolean + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Place Key", desc = "Places a new node at the current position. If a node is active automatically connects.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_F) + public int placeKey = Keyboard.KEY_F; + + @Expose + @ConfigOption(name = "Select Key", desc = "Select the nearest node to be active. Double press to unselect.") + @ConfigEditorKeybind(defaultKey = -98) // Middle Mouse + public int selectKey = -98; + + @Expose + @ConfigOption(name = "Connect Key", desc = "Connects the nearest node with the active node. If the nodes are already connected removes them.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_C) + public int connectKey = Keyboard.KEY_C; + + @Expose + @ConfigOption(name = "Exit Key", desc = "Exit out of stuff. If nothing active disables the graph editor.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_HOME) + public int exitKey = Keyboard.KEY_HOME; + + @Expose + @ConfigOption(name = "Edit Key", desc = "While holding the Key edit the position of the active node.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_TAB) + public int editKey = Keyboard.KEY_TAB; + + @Expose + @ConfigOption(name = "Text Key", desc = "Starts text mode, which allows editing a name of a node.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_T) + public int textKey = Keyboard.KEY_T; + + @Expose + @ConfigOption(name = "Test Dijkstra", desc = "On Keypress shows the shortest path between the nearest node and the active node.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_G) + public int dijkstraKey = Keyboard.KEY_G; + + @Expose + @ConfigOption(name = "Save Key", desc = "Saves the current graph to the clipboard.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_O) + public int saveKey = Keyboard.KEY_O; + + @Expose + @ConfigOption(name = "Load Key", desc = "Loades a graph from clipboard, if valid.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_I) + public int loadKey = Keyboard.KEY_I; + + @Expose + @ConfigOption(name = "Clear Key", desc = "Clears the graph. Also saves the graph to the clipboard.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_P) + public int clearKey = Keyboard.KEY_P; + + @Expose + @ConfigOption(name = "Vision Key", desc = "Toggles if the graph should render trough blocks.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_M) + public int throughBlocksKey = Keyboard.KEY_M; + + @Expose + @ConfigLink(owner = GraphConfig.class, field = "enabled") + public Position infoDisplay = new Position(20, 20); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java new file mode 100644 index 000000000000..1c522b24e794 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java @@ -0,0 +1,32 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStats; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.List; + +public class ChunkedStatsConfig { + + @Expose + @ConfigOption( + name = "ChunkedStats", + desc = "Select the stats you want to display chunked on the scoreboard." + ) + @ConfigEditorDraggableList + public List chunkedStats = new ArrayList<>(ChunkedStats.getEntries()); + + @Expose + @ConfigOption( + name = "Max Stats per Line", + desc = "The maximum amount of stats that will be displayed in one line." + ) + @ConfigEditorSlider( + minValue = 1, + maxValue = 10, + minStep = 1) + public int maxStatsPerLine = 3; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomLinesConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomLinesConfig.java new file mode 100644 index 000000000000..1a67e3b2ac5e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomLinesConfig.java @@ -0,0 +1,19 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import at.hannibal2.skyhanni.config.commands.Commands; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorButton; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorText; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class CustomLinesConfig { + + @ConfigOption(name = "Open Custom Lines GUI", desc = "Open the GUI to edit the custom lines") + @ConfigEditorButton(buttonText = "Open") + public Runnable open = Commands::openCustomLines; + + @Expose + @ConfigOption(name = "Custom Line 1", desc = "Custom line 1") + @ConfigEditorText + public String customLine1 = ""; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java index 30008a0d2ce9..03eed6ba8902 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java @@ -21,6 +21,16 @@ public class DisplayConfig { @Accordion public ArrowConfig arrow = new ArrowConfig(); + @Expose + @ConfigOption(name = "Chunked Stats Options", desc = "") + @Accordion + public ChunkedStatsConfig chunkedStats = new ChunkedStatsConfig(); + + @Expose + @ConfigOption(name = "Custom Lines", desc = "") + @Accordion + public CustomLinesConfig customLines = new CustomLinesConfig(); + @Expose @ConfigOption(name = "Events Options", desc = "") @Accordion @@ -46,17 +56,16 @@ public class DisplayConfig { @Accordion public TitleAndFooterConfig titleAndFooter = new TitleAndFooterConfig(); - @Expose @ConfigOption(name = "Hide Vanilla Scoreboard", desc = "Hide the vanilla scoreboard." + - "\n§cUsing mods that add their own scoreboard will not be affected by this setting!") + "\n§cUsing mods that add their own scoreboard will not be affected by this setting!") @ConfigEditorBoolean @FeatureToggle public Property hideVanillaScoreboard = Property.of(true); @Expose @ConfigOption(name = "Display Numbers First", desc = "Determines whether the number or line name displays first. " + - "§eNote: Will not update the preview above!") + "§eNote: Will not update the preview above!") @ConfigEditorBoolean public boolean displayNumbersFirst = false; @@ -97,8 +106,7 @@ public String toString() { public int lineSpacing = 10; @Expose - @ConfigOption(name = "Cache Scoreboard on Island Switch", - desc = "Will stop the Scoreboard from updating while switching islands.\nRemoves the shaking when loading data.") + @ConfigOption(name = "Cache Scoreboard on Island Switch", desc = "Will stop the Scoreboard from updating while switching islands.\nRemoves the shaking when loading data.") @ConfigEditorBoolean public boolean cacheScoreboardOnIslandSwitch = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java index f20643cc323b..ba3a44850d4f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java @@ -107,11 +107,10 @@ public class InventoryConfig { @ConfigOption(name = "Item Number", desc = "Showing the item number as a stack size for these items.") @ConfigEditorDraggableList public List itemNumberAsStackSize = new ArrayList<>(Arrays.asList( - NEW_YEAR_CAKE, - RANCHERS_BOOTS_SPEED, - LARVA_HOOK, - VACUUM_GARDEN - )); + NEW_YEAR_CAKE, + RANCHERS_BOOTS_SPEED, + LARVA_HOOK, + VACUUM_GARDEN)); public enum ItemNumberEntry implements HasLegacyId { MASTER_STAR_TIER("§bMaster Star Tier", 0), @@ -170,11 +169,10 @@ public String toString() { public boolean vacuumBagCap = true; @Expose - @ConfigOption(name = "Quick Craft Confirmation", - desc = "Require Ctrl+Click to craft items that aren't often quick crafted " + - "(e.g. armor, weapons, accessories). " + - "Sack items can be crafted normally." - ) + @ConfigOption(name = "Quick Craft Confirmation", desc = "Require Ctrl+Click to craft items that aren't often quick crafted " + + + "(e.g. armor, weapons, accessories). " + + "Sack items can be crafted normally.") @ConfigEditorBoolean @FeatureToggle public boolean quickCraftingConfirmation = false; @@ -199,14 +197,16 @@ public String toString() { @Expose @ConfigOption(name = "Missing Tasks", desc = "Highlight missing tasks in the SkyBlock Level Guide inventory.") - // TODO move( , "inventory.highlightMissingSkyBlockLevelGuide", "inventory.skyblockGuideConfig.highlightMissingSkyBlockLevelGuide") + // TODO move( , "inventory.highlightMissingSkyBlockLevelGuide", + // "inventory.skyblockGuideConfig.highlightMissingSkyBlockLevelGuide") @ConfigEditorBoolean @FeatureToggle public boolean highlightMissingSkyBlockLevelGuide = true; @Expose @ConfigOption(name = "Power Stone Guide", desc = "Highlight missing power stones, show their total bazaar price, and allows to open the bazaar when clicking on the items in the Power Stone Guide.") - // TODO move( , "inventory.powerStoneGuide", "inventory.skyblockGuideConfig.powerStoneGuide") + // TODO move( , "inventory.powerStoneGuide", + // "inventory.skyblockGuideConfig.powerStoneGuide") @ConfigEditorBoolean @FeatureToggle public boolean powerStoneGuide = true; diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/customwardrobe/SpacingConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/customwardrobe/SpacingConfig.java index 363a9a6a70bf..98206635e257 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/customwardrobe/SpacingConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/customwardrobe/SpacingConfig.java @@ -9,137 +9,77 @@ public class SpacingConfig { @Expose @ConfigOption(name = "Global Scale", desc = "Controls the scale of the entirety of the wardrobe.") - @ConfigEditorSlider( - minValue = 30, - maxValue = 200, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 30, maxValue = 200, minStep = 1) public Property globalScale = Property.of(100); @Expose @ConfigOption(name = "Outline Thickness", desc = "How thick the outline of the hovered slot is.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 15, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 15, minStep = 1) public Property outlineThickness = Property.of(5); @Expose @ConfigOption(name = "Outline Blur", desc = "Amount of blur of the outline.") - @ConfigEditorSlider( - minValue = 0f, - maxValue = 1f, - minStep = 0.1f - ) + @ConfigEditorSlider(minValue = 0f, maxValue = 1f, minStep = 0.1f) public Property outlineBlur = Property.of(0.5f); @Expose @ConfigOption(name = "Slot Width", desc = "Width of the wardrobe slots.") - @ConfigEditorSlider( - minValue = 30, - maxValue = 100, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 30, maxValue = 100, minStep = 1) public Property slotWidth = Property.of(75); @Expose @ConfigOption(name = "Slot Height", desc = "Height of the wardrobe slots.") - @ConfigEditorSlider( - minValue = 60, - maxValue = 200, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 60, maxValue = 200, minStep = 1) public Property slotHeight = Property.of(140); @Expose @ConfigOption(name = "Player Scale", desc = "Scale of the players.") - @ConfigEditorSlider( - minValue = 0, - maxValue = 100, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 0, maxValue = 100, minStep = 1) public Property playerScale = Property.of(75); @Expose @ConfigOption(name = "Slots per Row", desc = "Max amount of wardrobe slots per row.") - @ConfigEditorSlider( - minValue = 5, - maxValue = 18, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 5, maxValue = 18, minStep = 1) public Property maxPlayersPerRow = Property.of(9); @Expose @ConfigOption(name = "Slots Horizontal Spacing", desc = "How much space horizontally between wardrobe slots.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 20, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 20, minStep = 1) public Property horizontalSpacing = Property.of(3); @Expose @ConfigOption(name = "Slots Vertical Spacing", desc = "How much space vertically between wardrobe slots.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 20, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 20, minStep = 1) public Property verticalSpacing = Property.of(3); @Expose @ConfigOption(name = "Slots & Buttons Spacing", desc = "How much vertical space there is between wardrobe slots and the buttons.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 40, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 40, minStep = 1) public Property buttonSlotsVerticalSpacing = Property.of(10); @Expose @ConfigOption(name = "Button Horizontal Spacing", desc = "How much space horizontally between buttons.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 40, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 40, minStep = 1) public Property buttonHorizontalSpacing = Property.of(10); @Expose @ConfigOption(name = "Button Vertical Spacing", desc = "How much space vertically between buttons.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 40, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 40, minStep = 1) public Property buttonVerticalSpacing = Property.of(10); @Expose @ConfigOption(name = "Button Width", desc = "Width of the buttons.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 60, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 60, minStep = 1) public Property buttonWidth = Property.of(50); @Expose @ConfigOption(name = "Button Height", desc = "Height of the buttons.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 60, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 60, minStep = 1) public Property buttonHeight = Property.of(20); @Expose @ConfigOption(name = "Background Padding", desc = "Space between the edges of the background and the slots.") - @ConfigEditorSlider( - minValue = 1, - maxValue = 20, - minStep = 1 - ) + @ConfigEditorSlider(minValue = 1, maxValue = 20, minStep = 1) public Property backgroundPadding = Property.of(10); } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt index c25a567fbac0..bbd6d768e4a4 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.data.model +import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.json.SkyHanniTypeAdapters.registerTypeAdapter import at.hannibal2.skyhanni.utils.json.fromJson @@ -48,7 +49,7 @@ value class Graph( out.beginObject() it.neighbours.forEach { (node, weight) -> val id = node.id.toString() - out.name(id).value(weight) + out.name(id).value(weight.round(2)) } out.endObject() out.endObject() diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt new file mode 100644 index 000000000000..85a49eb8bd24 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt @@ -0,0 +1,134 @@ +package at.hannibal2.skyhanni.data.model + +import at.hannibal2.skyhanni.utils.KeyboardManager +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld +import at.hannibal2.skyhanni.utils.OSUtils +import at.hannibal2.skyhanni.utils.StringUtils.insert +import kotlinx.coroutines.runBlocking +import net.minecraft.client.settings.KeyBinding +import org.lwjgl.input.Keyboard +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable + +class TextInput { + + var textBox: String = "" + private var carriage: Int? = null + + fun editText() = textBox.let { + with(carriage) { + if (this == null) it + else it.insert(this, '|') + } + }.replace("§", "&&") + + fun finalText() = textBox.replace("&&", "§") + + fun makeActive() = Companion.activate(this) + fun disable() = Companion.disable() + fun handle() = Companion.handleTextInput() + fun clear() { + textBox = "" + carriage = null + } + + companion object { + private var activeInstance: TextInput? = null + + fun activate(instance: TextInput) { + activeInstance = instance + timeSinceKeyEvent = Keyboard.getEventNanoseconds() + } + + fun disable() { + activeInstance = null + } + + fun onMinecraftInput(keyBinding: KeyBinding, cir: CallbackInfoReturnable) { + if (activeInstance != null) { + cir.returnValue = false + return + } + } + + private var timeSinceKeyEvent = 0L + + private var carriage + get() = activeInstance?.carriage + set(value) { + activeInstance?.carriage = value + } + + private var textBox + get() = activeInstance?.textBox ?: "" + set(value) { + activeInstance?.textBox = value + } + + private fun handleTextInput() { + if (KeyboardManager.isCopyingKeysDown()) { + OSUtils.copyToClipboard(textBox) + return + } + if (KeyboardManager.isPastingKeysDown()) { + runBlocking { + textBox = OSUtils.readFromClipboard() ?: return@runBlocking + } + return + } + val tcarriage = carriage + + if (Keyboard.KEY_LEFT.isKeyHeld()) { + carriage = tcarriage?.moveCarriageLeft() ?: (textBox.length - 1) + return + } + if (Keyboard.KEY_RIGHT.isKeyHeld()) { + carriage = when { + tcarriage == null -> null + (tcarriage >= textBox.length - 1) -> null + else -> moveCarriageRight(tcarriage) + } + return + } + if (Keyboard.KEY_DELETE.isKeyClicked()) { // Does not work for some reason + if (tcarriage != null) { + textBox.removeRange(tcarriage, tcarriage + 1) + } else { + textBox.dropLast(1) + } + return + } + + if (timeSinceKeyEvent == Keyboard.getEventNanoseconds()) return + timeSinceKeyEvent = Keyboard.getEventNanoseconds() + val char = Keyboard.getEventCharacter() + textBox = when (char) { + Char(0) -> return + '\b' -> if (tcarriage != null) { + if (tcarriage == 0) { + textBox.substring(1) + } else { + carriage = tcarriage.minus(1) + textBox.removeRange(tcarriage - 1, tcarriage) + } + } else { + textBox.dropLast(1) + } + + else -> if (tcarriage != null) { + carriage = tcarriage + 1 + textBox.insert(tcarriage, char) + } else { + textBox + char + } + } + } + + private fun moveCarriageRight(tcarriage: Int) = tcarriage + 1 + + private fun Int.moveCarriageLeft(): Int = when { + this > 0 -> this - 1 + else -> 0 + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStats.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStats.kt new file mode 100644 index 000000000000..93c0aa862a9c --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStats.kt @@ -0,0 +1,124 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.data.MiningAPI.getCold +import at.hannibal2.skyhanni.data.PurseAPI +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.chunkedConfig +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.informationFilteringConfig +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.formatNum +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBank +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBits +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsAvailable +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsLine +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getCopper +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getGems +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getHeat +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getMotes +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getNorthStars +import java.util.function.Supplier + +val hideEmptyLines get() = informationFilteringConfig.hideEmptyLines + +enum class ChunkedStats( + private val displayPair: Supplier, + val showWhen: () -> Boolean, + private val configLine: String, +) { + PURSE( + { + "§6${PurseAPI.currentPurse.formatNum()}" + }, + { + !(hideEmptyLines && PurseAPI.currentPurse.toInt() == 0) && ScoreboardElement.PURSE.showWhen() + }, + "§6Purse" + ), + MOTES( + { + "§b${getMotes()}" + }, + { + !(hideEmptyLines && getMotes() == "0") && ScoreboardElement.MOTES.showWhen() + }, + "§dMotes" + ), + BANK( + { + "§6${getBank()}" + }, + { + !(hideEmptyLines && (getBank() == "0" || getBank() == "0§7 / §60")) && ScoreboardElement.BANK.showWhen() + }, + "§6Bank" + ), + BITS( + { + getBitsLine() + }, { + !(hideEmptyLines && getBits() == "0" && getBitsAvailable() == "0") && ScoreboardElement.BITS.showWhen() + }, + "§bBits" + ), + COPPER( + { + "§c${getCopper()}" + }, + { + !(hideEmptyLines && getCopper() == "0") && ScoreboardElement.COPPER.showWhen() + }, + "§cCopper" + ), + GEMS( + { + "§a${getGems()}" + }, + { + !(hideEmptyLines && getGems() == "0") && ScoreboardElement.GEMS.showWhen() + }, + "§aGems" + ), + HEAT( + { + "§c${getHeat()}" + }, + { + !(hideEmptyLines && getHeat() == "§c♨ 0") && ScoreboardElement.HEAT.showWhen() + }, + "§cHeat" + ), + COLD( + { + "§b${getCold()} ❄" + }, + { + !(hideEmptyLines && getCold() == 0) && ScoreboardElement.COLD.showWhen() + }, + "§bCold" + ), + NORTH_STARS( + { + "§d${getNorthStars()}" + }, + { + !(hideEmptyLines && getNorthStars() == "0") && ScoreboardElement.NORTH_STARS.showWhen() + }, + "§dNorth Stars" + ), + ; + + override fun toString() = configLine + + + fun getDisplay() = displayPair.get() + + companion object { + fun getChunkedStats() = buildList { + for (stat in chunkedConfig.chunkedStats) { + if (stat.showWhen()) { + add(stat.getDisplay()) + } + } + } + + fun shouldShowChunkedStats() = chunkedConfig.chunkedStats.any { it.showWhen() } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomLines.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomLines.kt new file mode 100644 index 000000000000..e2457bf4fd59 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomLines.kt @@ -0,0 +1,57 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.data.HypixelData +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBits +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsAvailable +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getPurse +import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.SkyBlockTime +import at.hannibal2.skyhanni.utils.TimeUtils.formatted +import net.minecraft.client.Minecraft + +object CustomLines { + + internal val replacements = listOf( + Triple("%x%", { Minecraft.getMinecraft().thePlayer.posX.round(2) }, "X-Coordinate"), + Triple("%y%", { Minecraft.getMinecraft().thePlayer.posY.round(2) }, "Y-Coordinate"), + Triple("%z%", { Minecraft.getMinecraft().thePlayer.posZ.round(2) }, "Z-Coordinate"), + Triple("%yaw%", { normalizeYaw(Minecraft.getMinecraft().thePlayer.rotationYaw).round(2) }, "Direction"), + Triple("%pitch%", { Minecraft.getMinecraft().thePlayer.rotationPitch.round(2) }, "Pitch"), + Triple("%purse%", { getPurse() }, "Purse"), + Triple("%bits%", { getBits() }, "Bits"), + Triple("%bits_available%", { getBitsAvailable() }, "Bits Available"), + Triple("%island%", { HypixelData.skyBlockIsland.displayName }, "Island"), + Triple("%area%", { HypixelData.skyBlockArea }, "Area"), + Triple("%date%", { SkyBlockTime.now().formatted(hoursAndMinutesElement = false, yearElement = false) }, "Date"), + Triple( + "%year%", + { SkyBlockTime.now().formatted(dayAndMonthElement = false, hoursAndMinutesElement = false) }, + "Year" + ), + Triple("%time%", { SkyBlockTime.now().formatted(dayAndMonthElement = false, yearElement = false) }, "Time") + ) + + internal fun String.handleCustomLine(): List { + return this.replace("&", "§").replaceWithReplacements() + } + + private fun String.replaceWithReplacements(): List { + var modifiedString = this + replacements.forEach { (placeholder, replacement) -> + modifiedString = modifiedString.replace(placeholder, replacement.invoke().toString()) + } + return modifiedString.split("\\n") + } + + private fun normalizeYaw(yaw: Float): Float { + var result = yaw % 360 + if (result > 180) { + result -= 360 + } else if (result <= -180) { + result += 360 + } + return result + } + + +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomLinesGui.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomLinesGui.kt new file mode 100644 index 000000000000..c5bbfafe591f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomLinesGui.kt @@ -0,0 +1,145 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.config.core.config.Position +import at.hannibal2.skyhanni.data.model.TextInput +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable +import at.hannibal2.skyhanni.utils.renderables.Renderable +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiScreen +import net.minecraft.client.gui.ScaledResolution +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +open class CustomLinesGui : GuiScreen() { + + private val scaledResolution get() = ScaledResolution(Minecraft.getMinecraft()) + private val windowWidth get() = scaledResolution.scaledWidth + private val windowHeight get() = scaledResolution.scaledHeight + + private val guiWidth = (windowWidth / (3 / 4f)).toInt() + private val guiHeight = (windowHeight / (3 / 4f)).toInt() + private val columnSpacing = 10 // temp value + private val maxSecondColumnWidth = 300 // temp value + + private var inTextMode = false + set(value) { + field = value + if (value) { + textBox.textBox = CustomScoreboard.customlineConfig.customLine1 + textBox.makeActive() + } else { + textBox.disable() + } + } + + private val textBox = TextInput() + + companion object { + fun isInGui() = Minecraft.getMinecraft().currentScreen is CustomLinesGui + } + + private fun getDisplay(): Renderable { + val secondColumn = createRenderableSecondColumn() + val secondColumnWidth = secondColumn.width + val firstColumnMaxWidth = guiWidth - secondColumnWidth - columnSpacing + + val secondColumnRenderable = Renderable.horizontalContainer( + listOf( + Renderable.placeholder(guiWidth - secondColumnWidth, 0), + secondColumn + ) + ) + + val firstRenderable = createRenderableFirstColumn(firstColumnMaxWidth) + + val fullRenderable = Renderable.drawInsideRoundedRect( + Renderable.doubleLayered( + Renderable.placeholder(guiWidth, guiHeight), + Renderable.doubleLayered( + secondColumnRenderable, + firstRenderable + ), + ), + LorenzColor.BLACK.addOpacity(100), + padding = 10, + ) + + return fullRenderable + } + + private fun createRenderableSecondColumn(): Renderable { + val list = mutableListOf() + CustomLines.replacements.forEach { + list.add( + Renderable.clickable( + Renderable.wrappedString( + "${it.third} | ${it.second.invoke()}", maxSecondColumnWidth + ), + { + if (inTextMode) { + textBox.textBox += it.first + } + }, + bypassChecks = true + ) + ) + } + val replacementsRenderable = Renderable.verticalContainer(list) + + return Renderable.verticalContainer( + listOf( + Renderable.string("Replacements"), + replacementsRenderable + ) + ) + } + + private fun createRenderableFirstColumn(maxWidth: Int) = + Renderable.verticalContainer( + listOf( + Renderable.string("Custom Lines"), + Renderable.clickable( + Renderable.drawInsideRoundedRectWithOutline( + Renderable.wrappedString(CustomScoreboard.customlineConfig.customLine1, maxWidth - 10), + if (inTextMode) LorenzColor.BLACK.addOpacity(100) else LorenzColor.BLACK.addOpacity(150), + padding = 5, + topOutlineColor = LorenzColor.BLACK.addOpacity(100).rgb, + bottomOutlineColor = LorenzColor.BLACK.addOpacity(100).rgb, + borderOutlineThickness = 2 + ), + { + inTextMode = !inTextMode + }, + bypassChecks = true + ) + ) + ) + + @SubscribeEvent + fun onOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { + if (!isInGui()) return + + val position = Position(windowWidth / 2 - guiWidth / 2, windowHeight / 2 - guiHeight / 2) + + position.renderRenderable( + getDisplay(), + posLabel = "Custom Lines Gui", + addToGuiManager = false + ) + } + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!isInGui()) { + inTextMode = false + return + } + + if (inTextMode) { + textBox.handle() + CustomScoreboard.customlineConfig.customLine1 = textBox.finalText().replace("§", "&") + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt index f0601c557440..6e2e54364803 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt @@ -2,10 +2,9 @@ // TODO LIST // V2 RELEASE // - Soulflow API -// - Bank API (actually maybe not, I like the current design) +// - Bank API // - beacon power // - skyblock level -// - more bg options (round, blurr, outline) // - countdown events like fishing festival + fiesta when its not on tablist // - CookieAPI https://discord.com/channels/997079228510117908/1162844830360146080/1195695210433351821 // - Rng meter display @@ -108,6 +107,8 @@ object CustomScoreboard { internal val displayConfig get() = config.display internal val alignmentConfig get() = displayConfig.alignment internal val arrowConfig get() = displayConfig.arrow + internal val chunkedConfig get() = displayConfig.chunkedStats + internal val customlineConfig get() = displayConfig.customLines internal val eventsConfig get() = displayConfig.events internal val mayorConfig get() = displayConfig.mayor internal val partyConfig get() = displayConfig.party diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt index 8aae8fe55528..8905cf93f1fc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt @@ -1,7 +1,9 @@ package at.hannibal2.skyhanni.features.gui.customscoreboard import at.hannibal2.skyhanni.config.features.gui.customscoreboard.DisplayConfig +import at.hannibal2.skyhanni.data.BitsAPI import at.hannibal2.skyhanni.data.HypixelData +import at.hannibal2.skyhanni.data.PurseAPI import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.features.bingo.BingoAPI import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.displayConfig @@ -11,6 +13,7 @@ import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.StringUtils.removeResets import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace +import at.hannibal2.skyhanni.utils.TabListData import java.util.regex.Pattern object CustomScoreboardUtils { @@ -41,5 +44,40 @@ object CustomScoreboardUtils { internal fun String.formatNum() = this.formatDouble().formatNum() + internal fun getPurse() = PurseAPI.currentPurse.formatNum() + + internal fun getMotes() = + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.motesPattern, "motes").formatNum() + + internal fun getBank() = + getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.bankPattern, "bank").formatNum() + + internal fun getBits() = BitsAPI.bits.coerceAtLeast(0).formatNum() + + internal fun getBitsAvailable() = BitsAPI.bitsAvailable.coerceAtLeast(0).formatNum() + + internal fun getBitsLine() = if (displayConfig.showUnclaimedBits) { + "§b${getBits()}§7/§b${getBitsAvailable()}" + } else { + "§b${getBits()}" + } + + internal fun getCopper() = + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.copperPattern, "copper").formatNum() + + internal fun getGems() = + getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.gemsPattern, "gems").formatNum() + + internal fun getHeat() = + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.heatPattern, "heat").formatNum() + + internal fun getNorthStars() = + getGroupFromPattern( + ScoreboardData.sidebarLinesFormatted, + ScoreboardPattern.northstarsPattern, + "northstars" + ).formatNum() + + class UndetectedScoreboardLines(message: String) : Exception(message) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/RenderBackground.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/RenderBackground.kt index 3d4e6daadf76..b96b66153c0f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/RenderBackground.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/RenderBackground.kt @@ -16,7 +16,7 @@ import org.lwjgl.opengl.GL11 class RenderBackground { - fun renderBackground() { + internal fun renderBackground() { val alignmentConfig = CustomScoreboard.alignmentConfig val backgroundConfig = CustomScoreboard.backgroundConfig val outlineConfig = backgroundConfig.outline diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt index 467f752daac2..073b61beaa67 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt @@ -17,15 +17,30 @@ import at.hannibal2.skyhanni.data.QuiverAPI.asArrowPercentage import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.data.SlayerAPI import at.hannibal2.skyhanni.features.dungeon.DungeonAPI +import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStats.Companion.getChunkedStats +import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStats.Companion.shouldShowChunkedStats +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomLines.handleCustomLine import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.arrowConfig +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.chunkedConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.config +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.customlineConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.displayConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.informationFilteringConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.maxwellConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.mayorConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.partyConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.formatNum +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBank +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBits +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsAvailable +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsLine +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getCopper +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getGems import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getGroupFromPattern +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getHeat +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getMotes +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getNorthStars +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getPurse import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter import at.hannibal2.skyhanni.utils.LorenzUtils.inAdvancedMiningIsland @@ -130,6 +145,11 @@ enum class ScoreboardElement( ::getNorthStarsShowWhen, "North Stars: §d756" ), + CHUNKED_STATS( + ::getChunkedStatsDisplayPair, + ::shouldShowChunkedStats, + "§652,763,737 §7| §d64,647 §7| §6249M §7| §b59,264 §7| §c23,495 §7| §a57,873 §7| §c♨ 0 §7| §b0❄ §7| §d756" + ), EMPTY_LINE( ::getEmptyLineDisplayPair, { true }, "" @@ -273,6 +293,11 @@ enum class ScoreboardElement( { true }, "" ), + CUSTOM_LINE1( + { getCustomLineDisplayPair(customlineConfig.customLine1.toString()) }, + { true }, + "Your custom line 1" + ), ; override fun toString() = configLine @@ -347,7 +372,7 @@ private fun getProfileDisplayPair() = listOf(CustomScoreboardUtils.getProfileTypeSymbol() + HypixelData.profileName.firstLetterUppercase() to HorizontalAlignment.LEFT) private fun getPurseDisplayPair(): List { - var purse = PurseAPI.currentPurse.formatNum() + var purse = getPurse() val earned = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, PurseAPI.coinsPattern, "earned") @@ -367,8 +392,7 @@ private fun getPurseDisplayPair(): List { private fun getPurseShowWhen() = !inAnyIsland(IslandType.THE_RIFT) private fun getMotesDisplayPair(): List { - val motes = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.motesPattern, "motes") - .formatNum() + val motes = getMotes() return listOf( when { @@ -382,7 +406,7 @@ private fun getMotesDisplayPair(): List { private fun getMotesShowWhen() = inAnyIsland(IslandType.THE_RIFT) private fun getBankDisplayPair(): List { - val bank = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.bankPattern, "bank") + val bank = getBank() return listOf( when { @@ -396,31 +420,18 @@ private fun getBankDisplayPair(): List { private fun getBankShowWhen() = !inAnyIsland(IslandType.THE_RIFT) private fun getBitsDisplayPair(): List { - val bits = BitsAPI.bits.coerceAtLeast(0).formatNum() + val bits = getBits() val bitsToClaim = if (BitsAPI.bitsAvailable == -1) { "§cOpen Sbmenu§b" } else { - BitsAPI.bitsAvailable.coerceAtLeast(0).formatNum() + getBitsAvailable() } return listOf( when { informationFilteringConfig.hideEmptyLines && bits == "0" && bitsToClaim == "0" -> "" - displayConfig.displayNumbersFirst -> { - if (displayConfig.showUnclaimedBits) { - "§b$bits§7/${if (bitsToClaim == "0") "§30" else "§b${bitsToClaim}"} §bBits" - } else { - "§b$bits Bits" - } - } - - else -> { - if (displayConfig.showUnclaimedBits) { - "Bits: §b$bits§7/${if (bitsToClaim == "0") "§30" else "§b${bitsToClaim}"}" - } else { - "Bits: §b$bits" - } - } + displayConfig.displayNumbersFirst -> "${getBitsLine()} Bits" + else -> "Bits: ${getBitsLine()}" } to HorizontalAlignment.LEFT ) } @@ -428,8 +439,7 @@ private fun getBitsDisplayPair(): List { private fun getBitsShowWhen() = !HypixelData.bingo && !inAnyIsland(IslandType.CATACOMBS, IslandType.KUUDRA_ARENA) private fun getCopperDisplayPair(): List { - val copper = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.copperPattern, "copper") - .formatNum() + val copper = getCopper() return listOf( when { @@ -443,7 +453,7 @@ private fun getCopperDisplayPair(): List { private fun getCopperShowWhen() = inAnyIsland(IslandType.GARDEN) private fun getGemsDisplayPair(): List { - val gems = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.gemsPattern, "gems") + val gems = getGems() return listOf( when { @@ -457,7 +467,7 @@ private fun getGemsDisplayPair(): List { private fun getGemsShowWhen() = !inAnyIsland(IslandType.THE_RIFT, IslandType.CATACOMBS, IslandType.KUUDRA_ARENA) private fun getHeatDisplayPair(): List { - val heat = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.heatPattern, "heat") + val heat = getHeat() return listOf( when { @@ -487,9 +497,7 @@ private fun getColdShowWhen() = inAnyIsland(IslandType.DWARVEN_MINES, IslandType && ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.coldPattern.matches(it) } private fun getNorthStarsDisplayPair(): List { - val northStars = - getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.northstarsPattern, "northstars") - .formatNum() + val northStars = getNorthStars() return listOf( when { @@ -502,6 +510,11 @@ private fun getNorthStarsDisplayPair(): List { private fun getNorthStarsShowWhen() = inAnyIsland(IslandType.WINTER) +private fun getChunkedStatsDisplayPair(): List = + getChunkedStats().chunked(chunkedConfig.maxStatsPerLine) + .map { it.joinToString(separator = " §f| ") } + .map { it to HorizontalAlignment.LEFT } + private fun getEmptyLineDisplayPair() = listOf("" to HorizontalAlignment.LEFT) private fun getIslandDisplayPair() = @@ -827,3 +840,7 @@ private fun getExtraShowWhen(): Boolean { } return confirmedUnknownLines.isNotEmpty() } + +private fun getCustomLineDisplayPair(customLine: String): List { + return customLine.handleCustomLine().map { it to HorizontalAlignment.LEFT } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/wardrobe/CustomWardrobe.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/wardrobe/CustomWardrobe.kt index 243b3132fdad..ba6c8b4cfd87 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/wardrobe/CustomWardrobe.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/wardrobe/CustomWardrobe.kt @@ -22,6 +22,7 @@ import at.hannibal2.skyhanni.utils.ConfigUtils.jumpToEditor import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.EntityUtils.getFakePlayer import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.InventoryUtils.getWindowId import at.hannibal2.skyhanni.utils.ItemUtils.removeEnchants import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java index 35a9bc78065a..a070f5e8928a 100644 --- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java +++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java @@ -1,6 +1,8 @@ package at.hannibal2.skyhanni.mixins.transformers; +import at.hannibal2.skyhanni.data.model.TextInput; import at.hannibal2.skyhanni.features.garden.farming.GardenCustomKeybinds; +import at.hannibal2.skyhanni.test.GraphEditor; import net.minecraft.client.settings.KeyBinding; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -18,5 +20,13 @@ private static void noOnTick(int keyCode, CallbackInfo ci) { @Inject(method = "isKeyDown", at = @At("HEAD"), cancellable = true) public void noIsKeyDown(CallbackInfoReturnable cir) { GardenCustomKeybinds.isKeyDown((KeyBinding) (Object) this, cir); + TextInput.Companion.onMinecraftInput((KeyBinding) (Object) this, cir); + GraphEditor.INSTANCE.onMinecraftInput((KeyBinding) (Object) this, cir); + } + + @Inject(method = "isPressed", at = @At("HEAD"), cancellable = true) + public void noIsPressed(CallbackInfoReturnable cir) { + TextInput.Companion.onMinecraftInput((KeyBinding) (Object) this, cir); + GraphEditor.INSTANCE.onMinecraftInput((KeyBinding) (Object) this, cir); } } diff --git a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt new file mode 100644 index 000000000000..f3776f0d5094 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt @@ -0,0 +1,421 @@ +package at.hannibal2.skyhanni.test + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.model.Graph +import at.hannibal2.skyhanni.data.model.GraphNode +import at.hannibal2.skyhanni.data.model.TextInput +import at.hannibal2.skyhanni.data.model.findShortestPathAsGraph +import at.hannibal2.skyhanni.data.model.toJson +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.GriffinUtils.drawWaypointFilled +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ColorUtils +import at.hannibal2.skyhanni.utils.KeyboardManager +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld +import at.hannibal2.skyhanni.utils.LocationUtils +import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.OSUtils +import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine_nea +import at.hannibal2.skyhanni.utils.RenderUtils.drawString +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import kotlinx.coroutines.runBlocking +import net.minecraft.client.settings.KeyBinding +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable + +@SkyHanniModule +object GraphEditor { + + private val config get() = SkyHanniMod.feature.dev.devTool.graph + + private fun isEnabled() = config != null && config.enabled + + private var id = 0 + + private val nodes = mutableListOf() + private val edge = mutableListOf() + + private var activeNode: GraphingNode? = null + private var closedNode: GraphingNode? = null + + private var seeThroughBlocks = true + + private var inEditMode = false + private var inTextMode = false + set(value) { + field = value + if (value) { + activeNode?.name?.let { + textBox.textBox = it + } + textBox.makeActive() + } else { + textBox.clear() + textBox.disable() + } + } + + private val textBox = TextInput() + + private val nodeColor = LorenzColor.BLUE.addOpacity(200) + private val activeColor = LorenzColor.GREEN.addOpacity(200) + private val closedColor = LorenzColor.YELLOW.addOpacity(200) + private val dijkstraColor = LorenzColor.LIGHT_PURPLE.addOpacity(200) + + private val edgeColor = LorenzColor.GOLD.addOpacity(150) + private val edgeDijkstraColor = LorenzColor.DARK_BLUE.addOpacity(150) + + @SubscribeEvent + fun onRender(event: LorenzRenderWorldEvent) { + if (!isEnabled()) return + nodes.forEach { event.drawNode(it) } + edge.forEach { event.drawEdge(it) } + } + + @SubscribeEvent + fun onOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { + if (!isEnabled()) return + config.infoDisplay.renderStrings( + buildList { + add("§eExit: §6${KeyboardManager.getKeyName(config.exitKey)}") + if (!inEditMode && !inTextMode) { + add("§ePlace: §6${KeyboardManager.getKeyName(config.placeKey)}") + add("§eSelect: §6${KeyboardManager.getKeyName(config.selectKey)}") + add("§eConnect: §6${KeyboardManager.getKeyName(config.connectKey)}") + add("§eTest: §6${KeyboardManager.getKeyName(config.dijkstraKey)}") + add("§eVision: §6${KeyboardManager.getKeyName(config.throughBlocksKey)}") + add("§eSave: §6${KeyboardManager.getKeyName(config.saveKey)}") + add("§eLoad: §6${KeyboardManager.getKeyName(config.loadKey)}") + add("§eClear: §6${KeyboardManager.getKeyName(config.clearKey)}") + if (activeNode != null) add("§eText: §6${KeyboardManager.getKeyName(config.textKey)}") + } + if (!inTextMode && activeNode != null) { + add("§eEdit: §6${KeyboardManager.getKeyName(config.editKey)}") + } + if (inEditMode) { + add("§ex+ §6${KeyboardManager.getKeyName(KeyboardManager.WasdInputMatrix.w.keyCode)}") + add("§ex- §6${KeyboardManager.getKeyName(KeyboardManager.WasdInputMatrix.s.keyCode)}") + add("§ez+ §6${KeyboardManager.getKeyName(KeyboardManager.WasdInputMatrix.a.keyCode)}") + add("§ez- §6${KeyboardManager.getKeyName(KeyboardManager.WasdInputMatrix.d.keyCode)}") + add("§ey+ §6${KeyboardManager.getKeyName(KeyboardManager.WasdInputMatrix.up.keyCode)}") + add("§ey- §6${KeyboardManager.getKeyName(KeyboardManager.WasdInputMatrix.down.keyCode)}") + } + if (inTextMode) { + add("§eFormat: ${textBox.finalText()}") + add("§eRaw: ${textBox.editText()}") + } + }, posLabel = "Graph Info" + ) + } + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!isEnabled()) return + input() + if (nodes.isEmpty()) return + closedNode = nodes.minBy { it.position.distanceSqToPlayer() } + } + + private fun LorenzRenderWorldEvent.drawNode(node: GraphingNode) { + this.drawWaypointFilled( + node.position, + node.getNodeColor(), + seeThroughBlocks = seeThroughBlocks, + minimumAlpha = 0.2f, + inverseAlphaScale = true + ) + if (node.name == null) return + this.drawString(node.position, node.name!!, seeThroughBlocks) + } + + private fun LorenzRenderWorldEvent.drawEdge(edge: GraphingEdge) = this.draw3DLine_nea( + edge.node1.position.add(0.5, 0.5, 0.5), + edge.node2.position.add(0.5, 0.5, 0.5), + if (edge !in highlightedEdges) edgeColor else edgeDijkstraColor, + 7, + !seeThroughBlocks + ) + + private fun GraphingNode.getNodeColor() = when (this) { + activeNode -> if (this == closedNode) ColorUtils.blendRGB(activeColor, closedColor, 0.5) else activeColor + closedNode -> closedColor + in highlightedNodes -> dijkstraColor + else -> nodeColor + } + + fun commandIn() { + config.enabled = !config.enabled + if (config.enabled) { + ChatUtils.chat("Graph Editor is now active") + } else { + chatAtDisable() + } + } + + private fun chatAtDisable() = + ChatUtils.clickableChat("Graph Editor is now inactive. §lClick to activate", ::commandIn) + + private fun input() { + if (LorenzUtils.isAnyGuiActive()) return + if (config.exitKey.isKeyClicked()) { + if (inTextMode) { + inTextMode = false + return + } + if (inEditMode) { + inEditMode = false + return + } + config.enabled = false + chatAtDisable() + } + if (inTextMode) { + textBox.handle() + val text = textBox.finalText() + if (text.isEmpty()) { + activeNode?.name = null + } else { + activeNode?.name = text + } + return + } + if (activeNode != null && config.textKey.isKeyClicked()) { + inTextMode = true + return + } + if (inEditMode) { + editModeClicks() + inEditMode = false + } + if (activeNode != null && config.editKey.isKeyHeld()) { + inEditMode = true + return + } + if (config.saveKey.isKeyClicked()) { + if (nodes.isEmpty()) { + ChatUtils.chat("Copied nothing since the graph is empty") + return + } + OSUtils.copyToClipboard(compileGraph().toJson()) + ChatUtils.chat("Copied Graph to Clipboard") + return + } + if (config.loadKey.isKeyClicked()) { + runBlocking { + OSUtils.readFromClipboard()?.let { + try { + Graph.fromJson(it) + } catch (e: Exception) { + ErrorManager.logErrorWithData( + e, + "Import of graph failed", + "json" to it, + ignoreErrorCache = true + ) + null + } + }?.let { import(it) } + } + return + } + if (config.clearKey.isKeyClicked()) { + OSUtils.copyToClipboard(compileGraph().toJson()) + ChatUtils.chat("Copied Graph to Clipboard and cleared the graph") + clear() + } + if (config.placeKey.isKeyClicked()) { + addNode() + } + if (config.selectKey.isKeyClicked()) { + activeNode = if (activeNode == closedNode) null else closedNode + } + if (activeNode != closedNode && config.connectKey.isKeyClicked()) { + val edge = getEdgeIndex(activeNode, closedNode) + if (edge == null) { + addEdge(activeNode, closedNode) + } else { + this.edge.removeAt(edge) + } + } + if (config.throughBlocksKey.isKeyClicked()) { + seeThroughBlocks = !seeThroughBlocks + } + if (config.dijkstraKey.isKeyClicked()) { + testDijkstra() + } + } + + private fun editModeClicks() { + KeyboardManager.WasdInputMatrix.w.handleEditClicks(x = 1) + KeyboardManager.WasdInputMatrix.s.handleEditClicks(x = -1) + KeyboardManager.WasdInputMatrix.a.handleEditClicks(z = 1) + KeyboardManager.WasdInputMatrix.d.handleEditClicks(z = -1) + KeyboardManager.WasdInputMatrix.up.handleEditClicks(y = 1) + KeyboardManager.WasdInputMatrix.down.handleEditClicks(y = -1) + } + + private fun KeyBinding.handleEditClicks(x: Int = 0, y: Int = 0, z: Int = 0) { + if (this.keyCode.isKeyClicked()) { + activeNode?.position = activeNode?.position?.add(x, y, z) ?: return + } + } + + fun onMinecraftInput(keyBinding: KeyBinding, cir: CallbackInfoReturnable) { + if (!isEnabled()) return + if (!inEditMode) return + if (keyBinding !in KeyboardManager.WasdInputMatrix) return + cir.returnValue = false + } + + private fun addNode() { + val closedNode = closedNode + if (closedNode != null && closedNode.position.distanceSqToPlayer() < 9.0) { + nodes.remove(closedNode) + edge.removeIf { it.isInEdge(closedNode) } + if (closedNode == activeNode) activeNode = null + this.closedNode = null + return + } + val position = LocationUtils.playerLocation().round(0) + val node = GraphingNode(id++, position) + nodes.add(node) + if (activeNode == null) return + addEdge(activeNode, node) + } + + private fun getEdgeIndex(node1: GraphingNode?, node2: GraphingNode?) = + if (node1 != null && node2 != null && node1 != node2) GraphingEdge( + node1, + node2 + ).let { e -> edge.indexOfFirst { it == e }.takeIf { it != -1 } } + else null + + private fun addEdge(node1: GraphingNode?, node2: GraphingNode?) = + if (node1 != null && node2 != null && node1 != node2) edge.add(GraphingEdge(node1, node2)) else false + + /** Has a side effect on the graphing graph, since it runs [prune] on the graphing graph*/ + private fun compileGraph(): Graph { + prune() + val indexedTable = nodes.mapIndexed { index, node -> node.id to index }.toMap() + val nodes = nodes.mapIndexed { index, it -> GraphNode(index, it.position, it.name) } + val neighbours = this.nodes.map { node -> + edge.filter { it.isInEdge(node) }.map { edge -> + val otherNode = if (node == edge.node1) edge.node2 else edge.node1 + nodes[indexedTable[otherNode.id]!!] to node.position.distance(otherNode.position) + }.sortedBy { it.second } + } + nodes.forEachIndexed { index, it -> it.neighbours = neighbours[index].toMap() } + return Graph(nodes) + } + + fun import(graph: Graph) { + clear() + nodes.addAll(graph.map { GraphingNode(it.id, it.position, it.name) }) + val translation = graph.mapIndexed { index, it -> it to nodes[index] }.toMap() + edge.addAll( + graph.map { node -> + node.neighbours.map { GraphingEdge(translation[node]!!, translation[it.key]!!) } + }.flatten().distinct() + ) + id = nodes.lastOrNull()?.id?.plus(1) ?: 0 + } + + private val highlightedNodes = mutableSetOf() + private val highlightedEdges = mutableSetOf() + + private fun testDijkstra() { + + val savedCurrent = closedNode ?: return + val savedActive = activeNode ?: return + + val compiled = compileGraph() + import(compiled) + highlightedEdges.clear() + highlightedNodes.clear() + + val current = compiled.firstOrNull { it.position == savedCurrent.position } ?: return + val goal = compiled.firstOrNull { it.position == savedActive.position } ?: return + + val path = compiled.findShortestPathAsGraph(current, goal) + + val inGraph = path.map { nodes[it.id] } + highlightedNodes.addAll(inGraph) + + val edge = edge.filter { highlightedNodes.contains(it.node1) && highlightedNodes.contains(it.node2) } + highlightedEdges.addAll(edge) + } + + private fun clear() { + id = 0 + nodes.clear() + edge.clear() + activeNode = null + closedNode = null + } + + private fun prune() { //TODO fix + val hasNeighbours = nodes.associateWith { false }.toMutableMap() + edge.forEach { + hasNeighbours[it.node1] = true + hasNeighbours[it.node2] = true + } + nodes.removeIf { hasNeighbours[it] == false } + } +} + +private class GraphingNode(val id: Int, var position: LorenzVec, var name: String? = null) { + + override fun hashCode(): Int { + return id + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as GraphingNode + + if (id != other.id) return false + + return true + } +} + +private class GraphingEdge(val node1: GraphingNode, val node2: GraphingNode) { + + fun isInEdge(node: GraphingNode) = node1 == node || node2 == node + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as GraphingEdge + + return (this.node1 == other.node1 && this.node2 == other.node2) || (this.node1 == other.node2 && this.node2 == other.node1) + } + + override fun hashCode(): Int { + val hash1 = node1.hashCode() + val hash2 = node2.hashCode() + + var result: Int + if (hash1 <= hash2) { + result = hash1 + result = 31 * result + hash2 + } else { + result = hash2 + result = 31 * result + hash1 + } + return result + } + +} + diff --git a/src/main/java/at/hannibal2/skyhanni/test/GriffinUtils.kt b/src/main/java/at/hannibal2/skyhanni/test/GriffinUtils.kt index b957129cc1ab..a9879ddd3b30 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/GriffinUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/GriffinUtils.kt @@ -18,6 +18,8 @@ object GriffinUtils { extraSize: Double = 0.0, extraSizeTopY: Double = extraSize, extraSizeBottomY: Double = extraSize, + minimumAlpha: Float = 0.2f, + inverseAlphaScale: Boolean = false, ) { val (viewerX, viewerY, viewerZ) = RenderUtils.getViewerPos(partialTicks) val x = location.x - viewerX @@ -27,24 +29,28 @@ object GriffinUtils { if (seeThroughBlocks) { GlStateManager.disableDepth() - GlStateManager.disableCull() } + + GlStateManager.disableCull() RenderUtils.drawFilledBoundingBox( AxisAlignedBB( x - extraSize, y - extraSizeBottomY, z - extraSize, x + 1 + extraSize, y + 1 + extraSizeTopY, z + 1 + extraSize ).expandBlock(), color, - (0.1f + 0.005f * distSq.toFloat()).coerceAtLeast(0.2f) + if (inverseAlphaScale) + (1.0f - 0.005f * distSq.toFloat()).coerceAtLeast(minimumAlpha) + else + (0.1f + 0.005f * distSq.toFloat()).coerceAtLeast(minimumAlpha) ) GlStateManager.disableTexture2D() if (distSq > 5 * 5 && beacon) RenderUtils.renderBeaconBeam(x, y + 1, z, color.rgb, 1.0f, partialTicks) GlStateManager.disableLighting() GlStateManager.enableTexture2D() + GlStateManager.enableCull() if (seeThroughBlocks) { GlStateManager.enableDepth() - GlStateManager.enableCull() } } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ConditionalUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ConditionalUtils.kt index 00aec1dc5f19..05e53b80210c 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/ConditionalUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/ConditionalUtils.kt @@ -30,4 +30,30 @@ object ConditionalUtils { whenChanged { _, new -> observer(new) } } + fun , K> comparatorFirst(pair1: Pair, pair2: Pair): Int { + val first1 = pair1.first + val first2 = pair2.first + + // Handle null cases + if (first1 == null && first2 == null) return 0 + if (first1 == null) return -1 + if (first2 == null) return 1 + + // Compare the non-null first values + return first1.compareTo(first2) + } + + fun > comparatorSecond(pair1: Pair, pair2: Pair): Int { + val second1 = pair1.second + val second2 = pair2.second + + // Handle null cases + if (second1 == null && second2 == null) return 0 + if (second1 == null) return 1 + if (second2 == null) return -1 + + // Compare the non-null second values + return second1.compareTo(second2) + } + } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt index c04057e725f0..9bf129be2eeb 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt @@ -133,4 +133,43 @@ object KeyboardManager { } fun getKeyName(keyCode: Int): String = KeybindHelper.getKeyName(keyCode) + + object WasdInputMatrix : Iterable { + operator fun contains(keyBinding: KeyBinding) = when (keyBinding) { + w, a, s, d, up, down -> true + else -> false + } + + val w get() = Minecraft.getMinecraft().gameSettings.keyBindForward!! + val a get() = Minecraft.getMinecraft().gameSettings.keyBindLeft!! + val s get() = Minecraft.getMinecraft().gameSettings.keyBindBack!! + val d get() = Minecraft.getMinecraft().gameSettings.keyBindRight!! + + val up get() = Minecraft.getMinecraft().gameSettings.keyBindJump!! + val down get() = Minecraft.getMinecraft().gameSettings.keyBindSneak!! + + override fun iterator(): Iterator = + object : Iterator { + + var current = w + + override fun hasNext(): Boolean = + current != down + + override fun next(): KeyBinding { + return current.also { + current = when (it) { + w -> a + a -> s + s -> d + d -> up + up -> down + else -> throw java.lang.IndexOutOfBoundsException() + } + } + } + + } + + } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt index f52f7f72b76d..17638f33e3b0 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt @@ -15,10 +15,12 @@ import at.hannibal2.skyhanni.test.TestBingo import at.hannibal2.skyhanni.utils.ChatUtils.lastButtonClicked import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.NEUItems.getItemStackOrNull +import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow import at.hannibal2.skyhanni.utils.StringUtils.capAtMinecraftLength import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.StringUtils.stripHypixelMessage import at.hannibal2.skyhanni.utils.StringUtils.toDashlessUUID +import at.hannibal2.skyhanni.utils.TimeUtils.ticks import at.hannibal2.skyhanni.utils.renderables.Renderable import com.google.gson.JsonPrimitive import net.minecraft.client.Minecraft @@ -352,6 +354,16 @@ object LorenzUtils { fun isBetaVersion() = UpdateManager.isCurrentlyBeta() + private var lastGuiTime = SimpleTimeMark.farPast() + + fun isAnyGuiActive(): Boolean { + val gui = Minecraft.getMinecraft().currentScreen != null + if (gui) { + lastGuiTime = 3.ticks.fromNow() + } + return !lastGuiTime.isInPast() + } + fun AxisAlignedBB.getCorners(y: Double): List { val cornerOne = LorenzVec(minX, y, minZ) val cornerTwo = LorenzVec(minX, y, maxZ) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt index 1506882cd40d..bf1077cacd6a 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt @@ -1536,7 +1536,6 @@ object RenderUtils { fun LorenzRenderWorldEvent.draw3DLine_nea( p1: LorenzVec, p2: LorenzVec, color: Color, lineWidth: Int, depth: Boolean, ) { - GlStateManager.disableDepth() GlStateManager.disableCull() val render = Minecraft.getMinecraft().renderViewEntity @@ -1571,7 +1570,7 @@ object RenderUtils { GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f) GlStateManager.popMatrix() GlStateManager.disableLighting() - GlStateManager.enableDepth() + GlStateManager.enableCull() } fun chromaColor( diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt index 3ddeb498ca60..bd6cf9250ba5 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt @@ -381,6 +381,12 @@ object StringUtils { fun generateRandomId() = UUID.randomUUID().toString() + fun String.insert(pos: Int, chars: CharSequence): String = + this.substring(0, pos) + chars + this.substring(pos) + + fun String.insert(pos: Int, char: Char): String = + this.substring(0, pos) + char + this.substring(pos) + fun replaceIfNeeded( original: ChatComponentText, newText: String,