diff options
author | hannibal2 <24389977+hannibal002@users.noreply.github.com> | 2023-06-12 12:49:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-12 12:49:20 +0200 |
commit | 56c5f9fc485731f2a33a2b61fa8b7d81193c207c (patch) | |
tree | 501b76594f2afa2057b1e45e402aa4c7f109dd12 /src/main | |
parent | f7b36cc696105948a31a871f493a515c3be658cd (diff) | |
download | skyhanni-56c5f9fc485731f2a33a2b61fa8b7d81193c207c.tar.gz skyhanni-56c5f9fc485731f2a33a2b61fa8b7d81193c207c.tar.bz2 skyhanni-56c5f9fc485731f2a33a2b61fa8b7d81193c207c.zip |
Quick Mod Menu Switch (#232)
Diffstat (limited to 'src/main')
7 files changed, 285 insertions, 15 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index ba8bb974d..9de04e760 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -296,6 +296,7 @@ class SkyHanniMod { loadModule(SlayerItemsOnGround()) loadModule(DetectBrokenHyperion()) loadModule(RestorePieceOfWizardPortalLore()) + loadModule(QuickModMenuSwitch) init() diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/DevData.java b/src/main/java/at/hannibal2/skyhanni/config/features/DevData.java index d94d3a39a..85120f929 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/DevData.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/DevData.java @@ -32,6 +32,22 @@ public class DevData { public boolean commandLogs = false; @Expose + @ConfigOption( + name = "Mod Menu Log", + desc = "Enables debug messages when the currently opened gui changes, with the path to the gui class. " + + "Useful for adding more mods to quick mod menu switch." + ) + @ConfigEditorBoolean + @ConfigAccordionId(id = 0) + public boolean modMenuLog = false; + + @Expose + @ConfigOption(name = "Show internal name", desc = "Show internal names in item lores.") + @ConfigEditorBoolean + @ConfigAccordionId(id = 0) + public boolean showInternalName = false; + + @Expose public Position debugPos = new Position(10, 10, false, true); @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java index 97a885cdc..64f14947a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java @@ -446,6 +446,32 @@ public class Misc { public boolean replaceLore = true; } + @ConfigOption(name = "Quick Mod Menu Switch", desc = "") + @Accordion + @Expose + public QuickModMenuSwitch quickModMenuSwitch = new QuickModMenuSwitch(); + + public static class QuickModMenuSwitch { + + @Expose + @ConfigOption(name = "Enabled", desc = "Adding a mod list, allowing to quickly switch between different mod menus") + @ConfigEditorBoolean + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Inside Escape Menu", desc = "Show the mod list while inside the Escape menu") + @ConfigEditorBoolean + public boolean insideEscapeMenu = true; + + @Expose + @ConfigOption(name = "Inside Inventory", desc = "Show the mod list while inside the player inventory (no chest inventory)") + @ConfigEditorBoolean + public boolean insidePlayerInventory = false; + + @Expose + public Position pos = new Position(-178, 143, false, true); + } + @Expose @ConfigOption(name = "Exp Bottles", desc = "Hides all the experience orbs lying on the ground.") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/QuickModMenuSwitch.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/QuickModMenuSwitch.kt new file mode 100644 index 000000000..a33cda9d1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/QuickModMenuSwitch.kt @@ -0,0 +1,192 @@ +package at.hannibal2.skyhanni.features.misc + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.test.command.CopyErrorCommand +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems +import at.hannibal2.skyhanni.utils.jsonobjects.ModsJson +import at.hannibal2.skyhanni.utils.renderables.Renderable +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraftforge.client.ClientCommandHandler +import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent + +object QuickModMenuSwitch { + private val config get() = SkyHanniMod.feature.misc.quickModMenuSwitch + private var display = listOf<List<Any>>() + private var tick = 0 + private var latestGuiPath = "" + + private var mods: List<Mod>? = null + + private var currentlyOpeningMod = "" + private var lastGuiOpen = 0L + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val modsJar = event.getConstant<ModsJson>("ModGuiSwitcher") ?: return + mods = buildList { + out@ for ((name, mod) in modsJar.mods) { + for (path in mod.guiPath) { + try { + Class.forName(path) + add(Mod(name, mod.description, mod.command, mod.guiPath)) + continue@out + } catch (ignored_: Exception) { + } + } + } + } + } + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (!isEnabled()) return + + if (tick++ % 5 == 0) { + update() + } + } + + class Mod(val name: String, val description: List<String>, val command: String, val guiPath: List<String>) { + + fun isInGui() = guiPath.any { latestGuiPath.startsWith(it) } + } + + private fun update() { + var openGui = Minecraft.getMinecraft().currentScreen?.javaClass?.name ?: "none" + openGui = handleAbstractGuis(openGui) + if (latestGuiPath != openGui) { + latestGuiPath = openGui + + if (SkyHanniMod.feature.dev.modMenuLog) { + LorenzUtils.debug("Open GUI: $latestGuiPath") + } + } + val mods = mods ?: return + + display = if (!shouldShow(mods)) { + emptyList() + } else { + renderDisplay(mods) + } + } + + private fun shouldShow(mods: List<Mod>): Boolean { + if (config.insideEscapeMenu && latestGuiPath == "net.minecraft.client.gui.GuiIngameMenu") return true + if (config.insidePlayerInventory && latestGuiPath == "net.minecraft.client.gui.inventory.GuiInventory") return true + + return mods.any { it.isInGui() } + } + + private fun handleAbstractGuis(openGui: String): String { + if (openGui == "gg.essential.vigilance.gui.SettingsGui") { + val clazz = Class.forName("gg.essential.vigilance.gui.SettingsGui") + val titleBarDelegate = clazz.getDeclaredField("titleBar\$delegate").also { it.isAccessible = true } + .get(Minecraft.getMinecraft().currentScreen) + val titleBar = + titleBarDelegate.javaClass.declaredFields[0].also { it.isAccessible = true }.get(titleBarDelegate) + val gui = titleBar.javaClass.getDeclaredField("gui").also { it.isAccessible = true }.get(titleBar) + val config = gui.javaClass.getDeclaredField("config").also { it.isAccessible = true }.get(gui) + + return config.javaClass.name + } + if (openGui == "cc.polyfrost.oneconfig.gui.OneConfigGui") { + /** TODO support different oneconfig mods: + * Partly Sane Skies + * Dankers SkyBlock Mod + * Dulkir + */ + } + + return openGui + } + + private fun renderDisplay(mods: List<Mod>) = buildList { + for (mod in mods) { + val currentlyOpen = mod.isInGui() + val nameFormat = if (currentlyOpen) "§c" else "" + var opening = mod.name == currentlyOpeningMod + if (currentlyOpen && opening) { + currentlyOpeningMod = "" + opening = false + } + val nameSuffix = if (opening) " §7(opening...)" else "" + val renderable = Renderable.link( + Renderable.string(nameFormat + mod.name), + bypassChecks = true, + onClick = { open(mod) }, + condition = { System.currentTimeMillis() > lastGuiOpen + 250 } + ) + add(listOf(renderable, nameSuffix)) + } + } + + private fun open(mod: Mod) { + lastGuiOpen = System.currentTimeMillis() + currentlyOpeningMod = mod.name + update() + try { + when (mod.command) { + "patcher" -> { + println("try opening patcher") + // GuiUtil.open(Objects.requireNonNull(Patcher.instance.getPatcherConfig().gui())) + val patcher = Class.forName("club.sk1er.patcher.Patcher") + val instance = patcher.getDeclaredField("instance").get(null) + val config = instance.javaClass.getDeclaredMethod("getPatcherConfig").invoke(instance) + val gui = Class.forName("gg.essential.vigilance.Vigilant").getDeclaredMethod("gui").invoke(config) + val guiUtils = Class.forName("gg.essential.api.utils.GuiUtil") + for (method in guiUtils.declaredMethods) { + try { + method.invoke(null, gui) + println("opened patcher") + return + } catch (_: Exception) { + } + } + LorenzUtils.chat("§c[SkyHanni] Error trying to open the gui for mod " + mod.name + "!") + } + + "hytil" -> { + println("try opening hytil") + // HytilsReborn.INSTANCE.getConfig().openGui() + val hytilsReborn = Class.forName("cc.woverflow.hytils.HytilsReborn") + val instance = hytilsReborn.getDeclaredField("INSTANCE").get(null) + val config = instance.javaClass.getDeclaredMethod("getConfig").invoke(instance) + val gui = Class.forName("gg.essential.vigilance.Vigilant").getDeclaredMethod("gui").invoke(config) + val guiUtils = Class.forName("gg.essential.api.utils.GuiUtil") + for (method in guiUtils.declaredMethods) { + try { + method.invoke(null, gui) + println("opened hytil") + return + } catch (_: Exception) { + } + } + LorenzUtils.chat("§c[SkyHanni] Error trying to open the gui for mod " + mod.name + "!") + } + + else -> { + val thePlayer = Minecraft.getMinecraft().thePlayer + ClientCommandHandler.instance.executeCommand(thePlayer, "/${mod.command}") + } + } + } catch (e: Exception) { + CopyErrorCommand.logError(e, "Error trying to open the gui for mod " + mod.name) + } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiScreenEvent.DrawScreenEvent.Post) { + if (!isEnabled()) return + + GlStateManager.pushMatrix() + config.pos.renderStringsAndItems(display, posLabel = "Quick Mod Menu Switch") + GlStateManager.popMatrix() + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled +} diff --git a/src/main/java/at/hannibal2/skyhanni/test/SkyHanniTestCommand.kt b/src/main/java/at/hannibal2/skyhanni/test/SkyHanniTestCommand.kt index bb03898d6..d3a7e982f 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/SkyHanniTestCommand.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/SkyHanniTestCommand.kt @@ -163,7 +163,7 @@ class SkyHanniTestCommand { @SubscribeEvent fun onItemTooltipLow(event: ItemTooltipEvent) { - if (!SkyHanniMod.feature.dev.debugEnabled) return + if (!SkyHanniMod.feature.dev.showInternalName) return val itemStack = event.itemStack if (itemStack != null) { val internalName = itemStack.getInternalName() diff --git a/src/main/java/at/hannibal2/skyhanni/utils/jsonobjects/ModsJson.java b/src/main/java/at/hannibal2/skyhanni/utils/jsonobjects/ModsJson.java new file mode 100644 index 000000000..d765f3e02 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/jsonobjects/ModsJson.java @@ -0,0 +1,25 @@ +package at.hannibal2.skyhanni.utils.jsonobjects; + +import com.google.gson.annotations.Expose; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ModsJson { + + @Expose + public Map<String, Mod> mods = new HashMap<>(); + + public class Mod { + @Expose + public List<String> description = new ArrayList<>(); + + @Expose + public String command = ""; + + @Expose + public List<String> guiPath = new ArrayList<>(); + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt index 5047c4744..acd1085ba 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -40,19 +40,19 @@ interface Renderable { else -> null } - fun link(text: String, onClick: () -> Unit): Renderable = link(string(text), onClick) { true } - fun optionalLink(text: String, onClick: () -> Unit, condition: () -> Boolean = { true }): Renderable = - link(string(text), onClick, condition) + fun link(text: String, bypassChecks: Boolean = false, onClick: () -> Unit): Renderable = link(string(text), onClick, bypassChecks = bypassChecks) { true } + fun optionalLink(text: String, onClick: () -> Unit, bypassChecks: Boolean = false, condition: () -> Boolean = { true }): Renderable = + link(string(text), onClick, bypassChecks, condition) - fun link(renderable: Renderable, onClick: () -> Unit, condition: () -> Boolean = { true }): Renderable { - return clickable(hoverable(underlined(renderable), renderable, condition), onClick, 0, condition) + fun link(renderable: Renderable, onClick: () -> Unit, bypassChecks: Boolean = false, condition: () -> Boolean = { true }): Renderable { + return clickable(hoverable(underlined(renderable), renderable, bypassChecks, condition = condition), onClick, 0, bypassChecks, condition) } - fun clickAndHover(text: String, tips: List<String>, onClick: () -> Unit): Renderable { - return clickable(hoverTips(text, tips), onClick) + fun clickAndHover(text: String, tips: List<String>, bypassChecks: Boolean = false, onClick: () -> Unit): Renderable { + return clickable(hoverTips(text, tips, bypassChecks = bypassChecks), onClick, bypassChecks = bypassChecks) } - fun clickable(render: Renderable, onClick: () -> Unit, button: Int = 0, condition: () -> Boolean = { true }) = + fun clickable(render: Renderable, onClick: () -> Unit, button: Int = 0, bypassChecks: Boolean = false, condition: () -> Boolean = { true }) = object : Renderable { override val width: Int get() = render.width @@ -63,7 +63,7 @@ interface Renderable { override fun render(posX: Int, posY: Int) { val isDown = Mouse.isButtonDown(button) if (isDown > wasDown && isHovered(posX, posY)) { - if (condition() && shouldAllowLink(true)) { + if (condition() && shouldAllowLink(true, bypassChecks)) { onClick() } } @@ -72,7 +72,7 @@ interface Renderable { } } - fun hoverTips(text: String, tips: List<String>, condition: () -> Boolean = { true }): Renderable { + fun hoverTips(text: String, tips: List<String>, bypassChecks: Boolean = false, condition: () -> Boolean = { true }): Renderable { val render = string(text) return object : Renderable { override val width: Int @@ -82,7 +82,7 @@ interface Renderable { override fun render(posX: Int, posY: Int) { render.render(posX, posY) if (isHovered(posX, posY)) { - if (condition() && shouldAllowLink(true)) { + if (condition() && shouldAllowLink(true, bypassChecks)) { renderToolTips(posX, posY, tips) } } @@ -91,6 +91,11 @@ interface Renderable { } private fun renderToolTips(posX: Int, posY: Int, tips: List<String>, border: Int = 1) { + GlStateManager.pushMatrix() +// GlStateManager.translate(0f, 0f, 2f) +// GuiRenderUtils.drawTooltip(tips, posX, posY, 0) +// GlStateManager.translate(0f, 0f, -2f) + val x = Utils.getMouseX() - posX + 10 val startY = Utils.getMouseY() - posY - 10 var maxX = 0 @@ -121,10 +126,15 @@ interface Renderable { LorenzColor.DARK_GRAY.toColor().rgb ) GlStateManager.translate(0f, 0f, -1f) + + GlStateManager.popMatrix() } - private fun shouldAllowLink(debug: Boolean = false): Boolean { + private fun shouldAllowLink(debug: Boolean = false, bypassChecks: Boolean): Boolean { val isGuiScreen = Minecraft.getMinecraft().currentScreen != null + if (bypassChecks) { + return isGuiScreen + } val isGuiPositionEditor = Minecraft.getMinecraft().currentScreen !is GuiPositionEditor val isNotInSignAndOnSlot = if (Minecraft.getMinecraft().currentScreen !is GuiEditSign) { ToolTipData.lastSlot == null @@ -161,14 +171,14 @@ interface Renderable { } } - fun hoverable(hovered: Renderable, unhovered: Renderable, condition: () -> Boolean = { true }) = + fun hoverable(hovered: Renderable, unhovered: Renderable, bypassChecks: Boolean = false, condition: () -> Boolean = { true }) = object : Renderable { override val width: Int get() = max(hovered.width, unhovered.width) override val height = 10 override fun render(posX: Int, posY: Int) { - if (isHovered(posX, posY) && condition() && shouldAllowLink()) + if (isHovered(posX, posY) && condition() && shouldAllowLink(true, bypassChecks)) hovered.render(posX, posY) else unhovered.render(posX, posY) |