From f48b98906e79a0d1bc92183ed3f53799a089e63f Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 13 Apr 2024 23:00:11 +0300 Subject: [PATCH 01/63] Tag windows --- .../com/lambda/gui/impl/clickgui/GuiConfigurable.kt | 12 +++++++++++- .../lambda/gui/impl/clickgui/windows/TagWindow.kt | 2 +- .../kotlin/com/lambda/interaction/RotationManager.kt | 2 +- common/src/main/kotlin/com/lambda/module/Module.kt | 11 +++++++---- .../com/lambda/module/modules/client/Baritone.kt | 2 +- .../com/lambda/module/modules/client/ClickGui.kt | 6 +++--- .../com/lambda/module/modules/client/FontSettings.kt | 2 +- .../com/lambda/module/modules/client/GuiSettings.kt | 2 +- .../com/lambda/module/modules/client/Rubberband.kt | 2 +- .../com/lambda/module/modules/client/ServerSpoof.kt | 2 +- .../module/{ => modules/debug}/BaritoneTest.kt | 7 +++++-- .../modules/{render => debug}/InventoryDebug.kt | 6 +++--- .../module/modules/{ => debug}/Packetlogger.kt | 5 ++--- .../module/modules/{ => debug}/RotationTest.kt | 5 +++-- .../lambda/module/modules/movement/RocketExtend.kt | 2 +- .../com/lambda/module/modules/movement/SafeWalk.kt | 2 +- .../com/lambda/module/modules/movement/Speed.kt | 2 +- .../com/lambda/module/modules/movement/Sprint.kt | 2 +- .../com/lambda/module/modules/player/Freecam.kt | 6 +++--- .../com/lambda/module/modules/player/Interact.kt | 2 +- .../com/lambda/module/modules/render/Fullbright.kt | 2 +- .../com/lambda/module/modules/render/NoRender.kt | 2 +- .../kotlin/com/lambda/module/modules/render/XRay.kt | 6 ++---- .../com/lambda/module/modules/{ => world}/Timer.kt | 4 ++-- .../main/kotlin/com/lambda/module/tag/ModuleTag.kt | 10 +++++----- 25 files changed, 60 insertions(+), 46 deletions(-) rename common/src/main/kotlin/com/lambda/module/{ => modules/debug}/BaritoneTest.kt (70%) rename common/src/main/kotlin/com/lambda/module/modules/{render => debug}/InventoryDebug.kt (92%) rename common/src/main/kotlin/com/lambda/module/modules/{ => debug}/Packetlogger.kt (98%) rename common/src/main/kotlin/com/lambda/module/modules/{ => debug}/RotationTest.kt (94%) rename common/src/main/kotlin/com/lambda/module/modules/{ => world}/Timer.kt (85%) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt index 79158c61d..4f88a9cf9 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt @@ -3,8 +3,18 @@ package com.lambda.gui.impl.clickgui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.Vec2d object GuiConfigurable : Configurable(GuiConfig) { override val name = "gui" - val windows = setting("windows", listOf(TagWindow())) + val windows = setting("windows", defaultWindows) + + private val defaultWindows get() = + ModuleTag.defaults.mapIndexed { index, tag -> + TagWindow(setOf(tag), tag.name).apply { + val step = 3.0 + position = Vec2d((width + step) * index, 0.0) + step + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt index 7249a0e11..9beef6a56 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt @@ -18,7 +18,7 @@ class TagWindow( ) : WindowComponent(), IChildComponent { init { ModuleRegistry.modules.filter { module -> - module.customTags.value.any(tags::contains) || tags.isEmpty() + module.tags.any(tags::contains) }.forEach { children.add(ModuleButton(it, this)) } diff --git a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 709a23f1f..2f0159050 100644 --- a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -166,7 +166,7 @@ object RotationManager : Loadable { baritoneContext = null } - listener { + listener(Int.MAX_VALUE) { processPlayerMovement(it) } } diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 545bc6195..62c583acf 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -1,6 +1,5 @@ package com.lambda.module -import com.google.gson.reflect.TypeToken import com.lambda.config.AbstractSetting import com.lambda.config.Configurable import com.lambda.config.Configuration @@ -80,7 +79,8 @@ import com.lambda.util.Nameable * @property name The name of the module, displayed in-game. * @property description The description of the module, * shown on hover over the module button in the GUI and in commands. - * @property defaultTags The set of [ModuleTag]s associated with the module. + * @property tag The leading module tag associated with the module. + * @property extraTags The set of extra [ModuleTag]s associated with the module. * @property alwaysListening If true, the module's listeners will be triggered even if the module is not enabled. * @property isEnabledSetting The setting that determines if the module is enabled. * @property keybindSetting The setting that determines the keybind for the module. @@ -91,7 +91,8 @@ import com.lambda.util.Nameable abstract class Module( override val name: String, val description: String = "", - val defaultTags: Set = setOf(), + val tag: ModuleTag, + val extraTags: Set = setOf(), private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.Unbound, @@ -99,7 +100,9 @@ abstract class Module( private val isEnabledSetting = setting("Enabled", enabledByDefault, visibility = { false }) private val keybindSetting = setting("Keybind", defaultKeybind) private val isVisible = setting("Visible", true) - val customTags = setting("Tags", defaultTags, visibility = { false }) + private val customTags by setting("Tags", extraTags, visibility = { false }) + + val tags get() = customTags + tag var isEnabled by isEnabledSetting override val isMuted: Boolean diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt index 892478d99..d25f059b8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt @@ -9,7 +9,7 @@ import com.lambda.util.math.MathUtils.random object Baritone : Module( name = "Baritone", description = "Baritone configuration", - defaultTags = setOf(ModuleTag.CLIENT) + ModuleTag.CLIENT ) { private val r1 by setting("Turn Speed 1", 70.0, 1.0..180.0, 0.1) private val r2 by setting("Turn Speed 2", 110.0, 1.0..180.0, 0.1) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt index 4b18b7b80..f3f1402ae 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt @@ -5,13 +5,13 @@ import com.lambda.event.listener.UnsafeListener.Companion.unsafeListener import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.threading.mainThread -import java.awt.Color +import com.lambda.util.KeyCode object ClickGui : Module( name = "ClickGui", description = "Sexy", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT, + defaultKeybind = KeyCode.RIGHT_SHIFT ) { // General val windowRadius by setting("Window Radius", 2.0, 0.0..10.0, 0.1) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt index ed0c42c82..943387d92 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object FontSettings : Module( name = "FontSettings", description = "Font renderer configuration", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT ) { val shadow by setting("Shadow", true) val shadowBrightness by setting("Shadow Brightness", 0.35, 0.0..0.5, 0.01, visibility = { shadow }) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt index 60c98773f..eba68547a 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt @@ -7,7 +7,7 @@ import java.awt.Color object GuiSettings : Module( name = "GuiSettings", description = "Visual behaviour configuration", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT ) { private val page by setting("Page", Page.General) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt b/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt index 8b9ff9d03..af76e03c8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt @@ -21,7 +21,7 @@ import java.awt.Color object Rubberband : Module( name = "Rubberband", description = "Info about rubberbands", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT ) { private val showLastPacketInfo by setting("Show Last Packet", true) private val showConnectionState by setting("Show Connection State", true) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt index aaf045395..bcdb77aee 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt @@ -17,7 +17,7 @@ import java.awt.Color object ServerSpoof : Module( name = "ServerSpoof", description = "Decide yourself if you want to accept the server resource pack.", - defaultTags = setOf(ModuleTag.BYPASS) + tag = ModuleTag.CLIENT ) { private val spoofClientBrand by setting("Spoof Client Brand", true) private val spoofName by setting("Spoof Name", "vanilla", visibility = { spoofClientBrand }) diff --git a/common/src/main/kotlin/com/lambda/module/BaritoneTest.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt similarity index 70% rename from common/src/main/kotlin/com/lambda/module/BaritoneTest.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt index 604b744f6..e524396eb 100644 --- a/common/src/main/kotlin/com/lambda/module/BaritoneTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt @@ -1,13 +1,16 @@ -package com.lambda.module +package com.lambda.module.modules.debug import baritone.api.BaritoneAPI import baritone.api.pathing.goals.GoalXZ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag object BaritoneTest : Module( name = "BaritoneTest", - description = "Test Baritone" + description = "Test Baritone", + tag = ModuleTag.DEBUG ) { init { listener { diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/InventoryDebug.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt similarity index 92% rename from common/src/main/kotlin/com/lambda/module/modules/render/InventoryDebug.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt index 7f89d2ca8..87dcf597b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/InventoryDebug.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt @@ -1,10 +1,10 @@ -package com.lambda.module.modules.render +package com.lambda.module.modules.debug import com.lambda.Lambda.LOG import com.lambda.event.events.PacketEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module -import com.lambda.util.Communication.info +import com.lambda.module.tag.ModuleTag import com.lambda.util.DynamicReflectionSerializer.dynamicString import net.minecraft.network.packet.c2s.play.* import net.minecraft.network.packet.s2c.play.InventoryS2CPacket @@ -13,7 +13,7 @@ import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket object InventoryDebug : Module( name = "InventoryDebug", description = "Debugs the inventory", - defaultTags = setOf() + tag = ModuleTag.DEBUG ) { init { listener { diff --git a/common/src/main/kotlin/com/lambda/module/modules/Packetlogger.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/Packetlogger.kt similarity index 98% rename from common/src/main/kotlin/com/lambda/module/modules/Packetlogger.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/Packetlogger.kt index f2a44e6e4..1a31ed380 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/Packetlogger.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/Packetlogger.kt @@ -1,6 +1,5 @@ -package com.lambda.module.modules +package com.lambda.module.modules.debug -import com.google.gson.reflect.TypeToken import com.lambda.Lambda import com.lambda.Lambda.mc import com.lambda.event.EventFlow.lambdaScope @@ -30,7 +29,7 @@ import kotlin.io.path.pathString object Packetlogger : Module( name = "Packetlogger", description = "Serializes network traffic and persists it for later analysis", - defaultTags = setOf(ModuleTag.DEBUG) + tag = ModuleTag.DEBUG ) { private val logToChat by setting("Log To Chat", false, "Log packets to chat") // ToDo: Implement HUD logging when HUD is done diff --git a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt similarity index 94% rename from common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt index 2efdabd38..cdb86657b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt @@ -1,10 +1,11 @@ -package com.lambda.module.modules +package com.lambda.module.modules.debug import com.lambda.config.InteractionSettings import com.lambda.config.RotationSettings import com.lambda.event.events.RotationEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag import net.minecraft.util.Hand import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos @@ -13,7 +14,7 @@ import net.minecraft.util.math.Direction object RotationTest : Module( name = "RotationTest", description = "Test rotation", - defaultTags = setOf() + tag = ModuleTag.DEBUG ) { private val rotationConfig = RotationSettings(this) private val interactionConfig = InteractionSettings(this) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt index bea85a9d1..b01833d0e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt @@ -13,7 +13,7 @@ import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket object RocketExtend : Module( name = "RocketExtend", description = "Extends rocket length on grim", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { private var extendedRockets = mutableListOf() private var pingPacket: CommonPongC2SPacket? = null diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt index 5de96e318..e941632b8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt @@ -8,7 +8,7 @@ import com.lambda.module.tag.ModuleTag object SafeWalk : Module( name = "SafeWalk", description = "Keeps you at the edge", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { private val realisticCollision by setting("Collide", true, "Realistic collision on the edge") diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index 29455d524..21d422947 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -20,7 +20,7 @@ import kotlin.math.max object Speed : Module( name = "Speed", description = "Fastest module", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { private val mode by setting("Mode", Mode.MATRIX_STRAFE_1) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt index 145c68821..f0ec65992 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt @@ -6,5 +6,5 @@ import com.lambda.module.tag.ModuleTag object Sprint : Module( name = "Sprint", description = "Sprints automatically", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 220cd1423..0bd4b77e1 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -29,7 +29,7 @@ import net.minecraft.util.math.Vec3d object Freecam : Module( name = "Freecam", description = "Move your camera freely", - defaultTags = setOf(ModuleTag.RENDER), + tag = ModuleTag.PLAYER, defaultKeybind = KeyCode.G ) { private val speed by setting("Speed", 0.5f, 0.1f..1.0f, 0.1f) @@ -82,9 +82,9 @@ object Freecam : Module( listener { event -> // Don't block baritone from working - if (player.input !is PlayerMovementInput) { + if (event.input !is PlayerMovementInput) { // Reset actual input - player.input.cancel() + event.input.cancel() } // Create new input for freecam diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt index 694e6d78e..c294bfd1b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object Interact : Module( name = "Interact", description = "Modify players interaction with the world", - defaultTags = setOf(ModuleTag.PLAYER) + tag = ModuleTag.PLAYER ) { // ToDo: Is this fast place / fast use? Should it be relocated with more options? @JvmStatic val placeDelay by setting("Item Use / Place Delay", 4, 0..20, 1, "Sets the delay between placing blocks or using items") diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt b/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt index 1d3e3c855..46e766b16 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt @@ -6,5 +6,5 @@ import com.lambda.module.tag.ModuleTag object Fullbright : Module( name = "Fullbright", description = "Makes everything brighter", - defaultTags = setOf(ModuleTag.RENDER) + tag = ModuleTag.RENDER ) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt b/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt index bf0093645..11b649c8e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object NoRender : Module( name = "NoRender", description = "Disables rendering of certain things", - defaultTags = setOf(ModuleTag.RENDER) + tag = ModuleTag.RENDER ) { @JvmStatic val noDarkness by setting("No Darkness", true) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt b/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt index 6da4dd51c..02ee032d9 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt @@ -6,7 +6,5 @@ import com.lambda.module.tag.ModuleTag object XRay : Module( name = "XRay", description = "Allows you to see ores through walls", - defaultTags = setOf(ModuleTag.RENDER) -) { - -} \ No newline at end of file + tag = ModuleTag.RENDER +) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/Timer.kt b/common/src/main/kotlin/com/lambda/module/modules/world/Timer.kt similarity index 85% rename from common/src/main/kotlin/com/lambda/module/modules/Timer.kt rename to common/src/main/kotlin/com/lambda/module/modules/world/Timer.kt index 430df32cd..235b32bc8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/Timer.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/world/Timer.kt @@ -1,4 +1,4 @@ -package com.lambda.module.modules +package com.lambda.module.modules.world import com.lambda.event.events.ClientEvent import com.lambda.event.listener.SafeListener.Companion.listener @@ -8,7 +8,7 @@ import com.lambda.module.tag.ModuleTag object Timer : Module( name = "Timer", description = "Modify client tick speed.", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.WORLD ) { private val timer by setting("Timer", 50, 0..1000, 5, unit = "ms/tick") diff --git a/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt b/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt index 16da6cbc2..a4002c17b 100644 --- a/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt +++ b/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt @@ -15,18 +15,18 @@ import com.lambda.util.Nameable * * @param name The name of the tag. */ -class ModuleTag(override val name: String) : Nameable { +data class ModuleTag(override val name: String) : Nameable { companion object { val COMBAT = ModuleTag("Combat") val MOVEMENT = ModuleTag("Movement") val RENDER = ModuleTag("Render") val PLAYER = ModuleTag("Player") val WORLD = ModuleTag("World") - val MISC = ModuleTag("Misc") + val DEBUG = ModuleTag("Debug") val CLIENT = ModuleTag("Client") - val HIDDEN = ModuleTag("Hidden") + val GRIM = ModuleTag("Grim") - val BYPASS = ModuleTag("Bypass") - val DEBUG = ModuleTag("Debug") + + val defaults = listOf(COMBAT, MOVEMENT, RENDER, PLAYER, WORLD, DEBUG, CLIENT) } } \ No newline at end of file From 99ea78fcbe6035ab46c03333a4f09958bc323db5 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 13 Apr 2024 23:17:08 +0300 Subject: [PATCH 02/63] Freecam vertical movement fixes --- .../kotlin/com/lambda/module/modules/player/Freecam.kt | 5 ++--- .../main/kotlin/com/lambda/util/player/MovementUtils.kt | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 0bd4b77e1..1a579518d 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -29,8 +29,7 @@ import net.minecraft.util.math.Vec3d object Freecam : Module( name = "Freecam", description = "Move your camera freely", - tag = ModuleTag.PLAYER, - defaultKeybind = KeyCode.G + tag = ModuleTag.PLAYER ) { private val speed by setting("Speed", 0.5f, 0.1f..1.0f, 0.1f) private val sprint by setting("Sprint Multiplier", 3.0f, 0.1f..10.0f, 0.1f, description = "Set below 1.0 to fly slower on sprint.") @@ -94,7 +93,7 @@ object Freecam : Module( val inputVec = Vec3d( input.movementSideways.toDouble(), - verticalMovement.toDouble(), + input.verticalMovement.toDouble(), input.movementForward.toDouble() ) diff --git a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt index 511b0f1a8..e5b6926d1 100644 --- a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt @@ -26,13 +26,16 @@ object MovementUtils { pressingBack = false pressingLeft = false pressingRight = false + + sneaking = false + jumping = false } val SafeContext.isInputting: Boolean get() = roundedForward != 0f || roundedStrafing != 0f - val SafeContext.verticalMovement get() = - player.input.jumping.toInt() - player.input.sneaking.toInt() + val Input.verticalMovement get() = + jumping.toInt() - sneaking.toInt() fun SafeContext.calcMoveYaw( yawIn: Float = player.moveYaw, From 12745d6bdf306e9e39881fd51f40a21d1e3e0c13 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 19 Apr 2024 13:25:12 +0300 Subject: [PATCH 03/63] ClickGui: Open/Hide Animations Toggle animation improvements Tag Windows --- common/src/main/kotlin/com/lambda/Lambda.kt | 5 +- .../gui/CustomTagWindowSerializer.kt | 54 +++++++++++++++ .../serializer/gui/TagWindowSerializer.kt | 22 ++---- .../lambda/graphics/animation/Animation.kt | 3 + .../kotlin/com/lambda/gui/api/LambdaGui.kt | 3 + .../gui/api/component/WindowComponent.kt | 69 +++++++++++-------- .../{sub => button}/ButtonComponent.kt | 46 +++++++------ .../gui/api/component/button/ListButton.kt | 21 ++++++ .../api/component/core/list/ChildComponent.kt | 18 +++-- .../component/core/list/IChildComponent.kt | 7 -- .../api/component/core/list/IListComponent.kt | 10 ++- .../com/lambda/gui/api/layer/LayerEntry.kt | 23 +++++++ .../com/lambda/gui/api/layer/RenderLayer.kt | 12 ++-- .../gui/impl/clickgui/AbstractClickGui.kt | 66 ++++++++++++++++++ .../gui/impl/clickgui/GuiConfigurable.kt | 19 ++++- .../gui/impl/clickgui/LambdaClickGui.kt | 31 +++++++-- .../gui/impl/clickgui/buttons/ModuleButton.kt | 21 +++--- .../gui/impl/clickgui/windows/ModuleWindow.kt | 25 +++++++ .../gui/impl/clickgui/windows/TagWindow.kt | 41 ----------- .../clickgui/windows/tag/CustomTagWindow.kt | 39 +++++++++++ .../impl/clickgui/windows/tag/TagWindow.kt | 19 +++++ .../main/kotlin/com/lambda/module/Module.kt | 8 +-- .../lambda/module/modules/client/ClickGui.kt | 4 ++ .../lambda/module/modules/player/Freecam.kt | 1 - 24 files changed, 409 insertions(+), 158 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt rename common/src/main/kotlin/com/lambda/gui/api/component/{sub => button}/ButtonComponent.kt (77%) create mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt delete mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt delete mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt diff --git a/common/src/main/kotlin/com/lambda/Lambda.kt b/common/src/main/kotlin/com/lambda/Lambda.kt index 3a861bd35..5737c14ec 100644 --- a/common/src/main/kotlin/com/lambda/Lambda.kt +++ b/common/src/main/kotlin/com/lambda/Lambda.kt @@ -3,10 +3,12 @@ package com.lambda import com.google.gson.Gson import com.google.gson.GsonBuilder import com.lambda.config.serializer.* +import com.lambda.config.serializer.gui.CustomTagWindowSerializer import com.lambda.config.serializer.gui.ModuleTagSerializer import com.lambda.config.serializer.gui.TagWindowSerializer import com.lambda.core.Loader -import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.KeyCode import net.minecraft.block.Block @@ -27,6 +29,7 @@ object Lambda { val gson: Gson = GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(ModuleTag::class.java, ModuleTagSerializer) + .registerTypeAdapter(CustomTagWindow::class.java, CustomTagWindowSerializer) .registerTypeAdapter(TagWindow::class.java, TagWindowSerializer) .registerTypeAdapter(KeyCode::class.java, KeyCodeSerializer) .registerTypeAdapter(Color::class.java, ColorSerializer) diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt new file mode 100644 index 000000000..a62209659 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt @@ -0,0 +1,54 @@ +package com.lambda.config.serializer.gui + +import com.google.gson.* +import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.Vec2d +import java.lang.reflect.Type + +object CustomTagWindowSerializer : JsonSerializer, JsonDeserializer { + override fun serialize( + src: CustomTagWindow?, + typeOfSrc: Type?, + context: JsonSerializationContext?, + ): JsonElement = src?.let { + JsonObject().apply { + addProperty("title", it.title) + add("tags", JsonArray().apply { + it.tags.forEach { + add(it.name) + } + }) + addProperty("width", it.width) + addProperty("height", it.height) + addProperty("isOpen", it.isOpen) + add("position", JsonArray().apply { + add(it.position.x) + add(it.position.y) + }) + } + } ?: JsonNull.INSTANCE + + override fun deserialize( + json: JsonElement?, + typeOfT: Type?, + context: JsonDeserializationContext?, + ) = json?.asJsonObject?.let { + CustomTagWindow( + it["title"].asString, + it["tags"].asJsonArray.map { tag -> + ModuleTag(tag.asString) + }.toSet(), + LambdaClickGui + ).apply { + width = it["width"].asDouble + height = it["height"].asDouble + isOpen = it["isOpen"].asBoolean + position = Vec2d( + it["position"].asJsonArray[0].asDouble, + it["position"].asJsonArray[1].asDouble + ) + } + } ?: throw JsonParseException("Invalid window data") +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt index 337e34474..b37090db2 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt @@ -1,7 +1,9 @@ package com.lambda.config.serializer.gui import com.google.gson.* -import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d import java.lang.reflect.Type @@ -13,12 +15,7 @@ object TagWindowSerializer : JsonSerializer, JsonDeserializer - add(tag.name) - } - }) + addProperty("tag", it.tag.name) addProperty("width", it.width) addProperty("height", it.height) addProperty("isOpen", it.isOpen) @@ -33,15 +30,10 @@ object TagWindowSerializer : JsonSerializer, JsonDeserializer - ModuleTag(tag.asString) - }.toSet(), - title = it["title"].asString, - width = it["width"].asDouble, + ) = json?.asJsonObject?.let { + TagWindow(ModuleTag(it["tag"].asString), LambdaClickGui).apply { + width = it["width"].asDouble height = it["height"].asDouble - ).apply { isOpen = it["isOpen"].asBoolean position = Vec2d( it["position"].asJsonArray[0].asDouble, diff --git a/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt b/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt index 6afd4908f..5a23d10f3 100644 --- a/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt +++ b/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt @@ -33,6 +33,9 @@ class Animation(initialValue: Double, val update: (Double) -> Double) { fun AnimationTicker.exp(min: Double, max: Double, speed: Double, flag: () -> Boolean) = exp({ min }, { max }, { speed }, flag) + fun AnimationTicker.exp(target: () -> Double, speed: Double) = + exp(target, target, { speed }, { true }) + @Suppress("NAME_SHADOWING") fun AnimationTicker.exp(min: () -> Double, max: () -> Double, speed: () -> Double, flag: () -> Boolean) = Animation(min()) { diff --git a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt index 1131da747..ccf69ac78 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt @@ -5,6 +5,7 @@ import com.lambda.event.EventFlow.syncListeners import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.UnsafeListener +import com.lambda.graphics.animation.AnimationTicker import com.lambda.gui.api.component.core.IComponent import com.lambda.module.Module import com.lambda.util.KeyCode @@ -22,6 +23,7 @@ abstract class LambdaGui( private val owner: Module? = null ) : Screen(Text.of(name)), IComponent, Nameable { private var screenSize = Vec2d.ZERO + val animation = AnimationTicker() private val renderListener = UnsafeListener(0, this, false) { event -> event as RenderEvent.GUI.Scaled @@ -30,6 +32,7 @@ abstract class LambdaGui( } private val tickListener = UnsafeListener(0, this, false) { + animation.tick() onTick() } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index f6e13ced9..ef4ad988b 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -1,23 +1,28 @@ package com.lambda.gui.api.component import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.graphics.animation.AnimationTicker import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry -import com.lambda.gui.api.component.core.IComponent import com.lambda.gui.api.component.core.list.IListComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.layer.RenderLayer +import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.module.modules.client.ClickGui import com.lambda.module.modules.client.GuiSettings import com.lambda.util.KeyCode import com.lambda.util.Mouse +import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d +import java.awt.Color import kotlin.math.abs -abstract class WindowComponent : InteractiveComponent(), IListComponent { +abstract class WindowComponent ( + final override val owner: AbstractClickGui +) : ChildComponent(), IListComponent { abstract val title: String abstract var width: Double @@ -37,35 +42,41 @@ abstract class WindowComponent : InteractiveComponent(), IL private val titleFont: IFontEntry private val layer = RenderLayer() - private val animation = AnimationTicker() + private val renderer = layer.entry() + val subLayer = RenderLayer() - override val children = mutableListOf() - val subLayer = RenderLayer(true) + val animation = owner.animation + val guiAnimation get() = owner.guiAnimation private val actualHeight get() = height + padding * 2 * isOpen.toInt() - private var renderHeight by animation.exp({ 0.0 }, ::actualHeight, 0.5, ::isOpen) + private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) + private val renderHeight get() = lerp(0.0, renderHeightAnimation, guiAnimation) + + override val children = mutableListOf() init { // Background - layer.rect.build { + renderer.rect { position = rect roundRadius = ClickGui.windowRadius - color(GuiSettings.backgroundColor) + + val alpha = (guiAnimation * 2.0).coerceIn(0.0, 1.0) + color(GuiSettings.backgroundColor.multAlpha(alpha)) } // Title - titleFont = layer.font.build { + titleFont = renderer.font { text = title position = titleBar.center - widthVec * 0.5 + color = Color.WHITE.setAlpha(guiAnimation) } } override fun onShow() { - super.onShow() + super.onShow() super.onShow() dragOffset = null - renderHeight = 0.0 } override fun onHide() { @@ -73,33 +84,33 @@ abstract class WindowComponent : InteractiveComponent(), IL } override fun onTick() { - animation.tick() - - setChildrenAccessibility { child -> - child.rect in contentRect + children.forEach { child -> + child.accessible = child.rect in contentRect && this.accessible } - children - .filter(ChildComponent::accessible) - .forEach(IComponent::onTick) + super.onTick() } override fun onRender() { layer.render() scissor(contentRect) { - subLayer.render() + subLayer.apply { + allowEffects = true + render() + } + super.onRender() } } override fun onMouseMove(mouse: Vec2d) { - super.onMouseMove(mouse) - super.onMouseMove(mouse) - dragOffset?.let { position = mouse - it } + + super.onMouseMove(mouse) + super.onMouseMove(mouse) } override fun onKey(key: KeyCode) { @@ -111,7 +122,7 @@ abstract class WindowComponent : InteractiveComponent(), IL } override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - super.onMouseClick(button, action, mouse) + super.onMouseClick(button, action, mouse) dragOffset = null @@ -124,6 +135,8 @@ abstract class WindowComponent : InteractiveComponent(), IL if (abs(targetHeight - renderHeight) > 1) return isOpen = !isOpen + + if (isOpen) super.onShow() } } } @@ -131,9 +144,9 @@ abstract class WindowComponent : InteractiveComponent(), IL super.onMouseClick(button, action, mouse) } - private fun setChildrenAccessibility(flag: (T) -> Boolean) { - children.forEach { child -> - child.accessible = flag(child) - } + fun destroy() { + layer.destroy() + subLayer.destroy() + children.clear() } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/sub/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt similarity index 77% rename from common/src/main/kotlin/com/lambda/gui/api/component/sub/ButtonComponent.kt rename to common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 4e1265ead..86efc0c6b 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/sub/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -1,7 +1,6 @@ -package com.lambda.gui.api.component.sub +package com.lambda.gui.api.component.button import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.graphics.animation.AnimationTicker import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.module.modules.client.ClickGui @@ -9,7 +8,6 @@ import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp -import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d import java.awt.Color @@ -20,19 +18,23 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C abstract val size: Vec2d abstract val text: String - open val active get() = pressed + abstract val active: Boolean private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.contentRect.size.x else size.x, size.y) final override val rect get() = Rect.basedOn(position, actualSize) + owner.contentRect.leftTop private val layer = owner.subLayer - private val animation = AnimationTicker() + private val renderer = layer.entry() + protected val animation = owner.animation - private var activeAnimation by animation.exp(0.0, 1.0, 0.1, ::active) - private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.5 else 0.1 }, ::renderHovered) + private var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::active) + private var toggleFxDirection by animation.exp(0.0, 1.0, 0.6, ::active) + private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.6 else 0.07 }, ::renderHovered) private var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) private val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 + private val showAnimationRaw by animation.exp(0.0, 1.0, 0.7, owner::isOpen) + private val showAnimation get() = lerp(0.0, showAnimationRaw, owner.guiAnimation) private var lastHoveredTime = 0L private val renderHovered get() = hovered || @@ -40,22 +42,22 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C init { // Active color - layer.rect.build { + renderer.rect { position = rect.shrink(interactAnimation) - color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.2)) + color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.3 * showAnimation)) } // Hover glint - layer.rect.build { + renderer.rect { val hoverRect = Rect.basedOn(rect.leftTop, rect.size.x * hoverRectAnimation, rect.size.y) position = hoverRect.shrink(interactAnimation) - val alpha = interactAnimation * 0.3 + val alpha = interactAnimation * 0.2 color(GuiSettings.mainColor.multAlpha(alpha)) } // Toggle fx - layer.rect.build { + renderer.rect { val left = rect - Vec2d(rect.size.x, 0.0) val right = rect + Vec2d(rect.size.x, 0.0) @@ -65,23 +67,23 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C // 0.0 .. 1.0 .. 0.0 animation val alpha = 1.0 - (abs(activeAnimation - 0.5) * 2.0) - val color = GuiSettings.mainColor.multAlpha(alpha * 0.8) + val color = GuiSettings.mainColor.multAlpha(alpha * 0.6 * showAnimation) // "Tail" effect - val leftColor = color.multAlpha(1.0 - active.toInt()) - val rightColor = color.multAlpha(active.toInt().toDouble()) + val leftColor = color.multAlpha(1.0 - toggleFxDirection) + val rightColor = color.multAlpha(toggleFxDirection) colorH(leftColor, rightColor) } // Text - layer.font.build { + renderer.font { text = this@ButtonComponent.text scale = 1.0 - pressAnimation * 0.08 - color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation) + color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation).multAlpha(showAnimation) - val x = rect.left + ClickGui.windowPadding + interactAnimation + hoverFontAnimation * 2.0 + val x = rect.left + ClickGui.windowPadding + interactAnimation + hoverFontAnimation position = Vec2d(x, rect.center.y) } } @@ -98,10 +100,6 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C reset() } - override fun onTick() { - animation.tick() - } - override fun onRelease() { if (hovered) activeMouseButton?.let(::performClickAction) } @@ -113,6 +111,10 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C if (hovered) lastHoveredTime = time } + override fun onRemove() { + renderer.destroy() + } + private fun reset() { activeAnimation = 0.0 hoverRectAnimation = 0.0 diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt new file mode 100644 index 000000000..36cccd6d2 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -0,0 +1,21 @@ +package com.lambda.gui.api.component.button + +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.component.WindowComponent +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.math.MathUtils.toInt +import com.lambda.util.math.Vec2d + +abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { + override val position get() = Vec2d(0.0, renderHeightOffset) + override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) + + var heightOffset = 0.0 + private val targetHeightOffset get() = heightOffset * owner.guiAnimation * owner.isOpen.toInt() + private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.5) + + override fun onShow() { + super.onShow() + renderHeightOffset = 0.0 + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index c8209122f..fcc06bc12 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -1,14 +1,18 @@ package com.lambda.gui.api.component.core.list import com.lambda.gui.api.component.InteractiveComponent +import com.lambda.gui.api.component.core.IComponent +import com.lambda.util.math.Vec2d -abstract class ChildComponent : InteractiveComponent(), IChildComponent { - // mostly used to create an animation when an element appears - var accessible = false; set(value) { - if (field == value) return - field = value +abstract class ChildComponent : InteractiveComponent() { + abstract val owner: IComponent + open var accessible = false - if (value) onShow() - else onHide() + override fun onMouseMove(mouse: Vec2d) { + super.onMouseMove(mouse) + hovered = hovered && accessible } + + open fun onAdd() {} + open fun onRemove() {} } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt deleted file mode 100644 index 353ab501f..000000000 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.lambda.gui.api.component.core.list - -import com.lambda.gui.api.component.core.IComponent - -interface IChildComponent { - val owner: IComponent -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt index 303ea9ff5..bf7e6ba3d 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt @@ -39,17 +39,15 @@ interface IListComponent : IComponent { } override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - children.filter(::isChildAccessible).forEach { child -> - child.onMouseClick(button, action, mouse) + children.forEach { child -> + val newAction = if (isChildAccessible(child)) action else Mouse.Action.Release + child.onMouseClick(button, newAction, mouse) } } override fun onMouseMove(mouse: Vec2d) { children.forEach { child -> - child.onMouseMove( - if (isChildAccessible(child)) mouse - else Vec2d(-1000.0, -1000.0) // junky but worky way to unfocus - ) + child.onMouseMove(mouse) } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt new file mode 100644 index 000000000..67c172a7c --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt @@ -0,0 +1,23 @@ +package com.lambda.gui.api.layer + +import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.graphics.renderer.IRenderer +import com.lambda.graphics.renderer.gui.font.IFontEntry +import com.lambda.graphics.renderer.gui.rect.IRectEntry + +// Used to group all render entries related to a component +class LayerEntry ( + private val rect: IRenderer, + private val font: IRenderer +) { + private val entries = mutableSetOf>() + + fun rect(block: IRectEntry.() -> Unit) = + rect.build(block).apply(entries::add) + + fun font(block: IFontEntry.() -> Unit) = + font.build(block).apply(entries::add) + + fun destroy() = + entries.forEach(IRenderEntry<*>::destroy) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt index fe871fc28..97762b0f5 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt @@ -4,17 +4,19 @@ import com.lambda.graphics.renderer.gui.font.FontRenderer import com.lambda.graphics.renderer.gui.rect.RectRenderer import com.lambda.module.modules.client.GuiSettings -class RenderLayer(private val allowEffects: Boolean = false) { - private val rectRenderer = RectRenderer() +class RenderLayer { + var allowEffects = false - val rect = rectRenderer.asRenderer - val font = FontRenderer().asRenderer + private val rect = RectRenderer() + private val font = FontRenderer() + + fun entry() = LayerEntry(rect, font) fun render() { rect.update() font.update() - rectRenderer.apply { + rect.apply { shadeColor = GuiSettings.shade && allowEffects fancyBlending = GuiSettings.glow && allowEffects render() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt new file mode 100644 index 000000000..2f2a1e5b5 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -0,0 +1,66 @@ +package com.lambda.gui.impl.clickgui + +import com.lambda.Lambda.mc +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.LambdaGui +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.api.component.core.list.ChildComponent +import com.lambda.gui.api.component.core.list.IListComponent +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.Mouse +import com.lambda.util.math.Vec2d + +abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui), IListComponent { + override val children = mutableListOf() + protected var hoveredChild: ChildComponent? = null + + private var closing = false + var guiAnimation by animation.exp(0.0, 1.0, { + if (closing) ClickGui.closeSpeed else ClickGui.openSpeed + }) { !closing }; private set + + override fun onShow() { + super.onShow() + hoveredChild = null + closing = false + guiAnimation = 0.0 + } + + override fun onTick() { + super.onTick() + if (closing && guiAnimation < 0.01) mc.setScreen(null) + } + + override fun onRender() { + super.onRender() + + // only one window can be hovered at the same time + children.forEach { + it.accessible = false + } + + if (!closing) hoveredChild?.accessible = true + } + + override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { + // move hovered window into foreground + (hoveredChild as? WindowComponent<*>)?.let { + children.remove(it) + children.add(it) + } + + super.onMouseClick(button, action, mouse) + } + + override fun onMouseMove(mouse: Vec2d) { + hoveredChild = children.lastOrNull { child -> + mouse in child.rect + } + + super.onMouseMove(mouse) + } + + override fun close() { + closing = true + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt index 4f88a9cf9..c11d88e5a 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt @@ -2,17 +2,30 @@ package com.lambda.gui.impl.clickgui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig -import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d object GuiConfigurable : Configurable(GuiConfig) { override val name = "gui" - val windows = setting("windows", defaultWindows) + + val mainWindows by setting("windows", defaultWindows).apply { + listener { from, _ -> + from.forEach(WindowComponent<*>::destroy) // free vram + } + } + + val customWindows by setting("custom windows", listOf()).apply { + listener { from, _ -> + from.forEach(WindowComponent<*>::destroy) // free vram + } + } private val defaultWindows get() = ModuleTag.defaults.mapIndexed { index, tag -> - TagWindow(setOf(tag), tag.name).apply { + TagWindow(tag, LambdaClickGui).apply { val step = 3.0 position = Vec2d((width + step) * index, 0.0) + step } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index b24ccf7a0..f8d806bc9 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -1,10 +1,29 @@ package com.lambda.gui.impl.clickgui -import com.lambda.gui.api.LambdaGui -import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.core.list.IListComponent -import com.lambda.module.modules.client.ClickGui +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow -object LambdaClickGui : LambdaGui("ClickGui", ClickGui), IListComponent> { - override val children: List> get() = GuiConfigurable.windows.value +object LambdaClickGui : AbstractClickGui() { + override fun onShow() { + updateWindows() + super.onShow() + } + + override fun onTick() { + updateWindows() + super.onTick() + } + + private fun updateWindows() { + val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows + val new = windows.subtract(children) + children.addAll(new) + + children.removeIf { + if (it !is CustomTagWindow) return@removeIf false + + val flag = it !in windows + if (flag) it.destroy() + flag + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 3649b06ec..6d5bb93af 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,20 +1,13 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.sub.ButtonComponent +import com.lambda.gui.api.component.button.ListButton import com.lambda.module.Module -import com.lambda.module.modules.client.ClickGui import com.lambda.util.Mouse -import com.lambda.util.math.Vec2d -class ModuleButton(val module: Module, owner: WindowComponent<*>) : ButtonComponent(owner) { - override val position get() = Vec2d(0.0, heightOffset) - override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) - - override val text: String get() = module.name - override val active: Boolean get() = module.isEnabled - - var heightOffset = 0.0 +class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(owner) { + override val text get() = module.name + override val active get() = module.isEnabled override fun performClickAction(mouse: Mouse.Button) { when (mouse) { @@ -24,4 +17,10 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ButtonCompon } } } + + override fun equals(other: Any?) = + (other as? ModuleButton)?.module == module + + override fun hashCode() = + module.hashCode() } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt new file mode 100644 index 000000000..7f31faaf2 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt @@ -0,0 +1,25 @@ +package com.lambda.gui.impl.clickgui.windows + +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.module.modules.client.ClickGui + +abstract class ModuleWindow( + override var title: String, + override var width: Double = 110.0, + override var height: Double = 300.0, + owner: AbstractClickGui +) : WindowComponent(owner) { + override fun onTick() { + children.sortBy { + it.module.name + } + + children.forEachIndexed { i, button -> + button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) + } + + super.onTick() + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt deleted file mode 100644 index 9beef6a56..000000000 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.lambda.gui.impl.clickgui.windows - -import com.lambda.gui.api.LambdaGui -import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.core.list.IChildComponent -import com.lambda.gui.impl.clickgui.LambdaClickGui -import com.lambda.gui.impl.clickgui.buttons.ModuleButton -import com.lambda.module.ModuleRegistry -import com.lambda.module.modules.client.ClickGui -import com.lambda.module.tag.ModuleTag - -class TagWindow( - val tags: Set = setOf(), - override var title: String = "Untitled", - override var width: Double = 110.0, - override var height: Double = 300.0, - override val owner: LambdaGui = LambdaClickGui -) : WindowComponent(), IChildComponent { - init { - ModuleRegistry.modules.filter { module -> - module.tags.any(tags::contains) - }.forEach { - children.add(ModuleButton(it, this)) - } - } - - override fun onRender() { - updateModules() - super.onRender() - } - - private fun updateModules() { - children.sortBy { it.module.name } - - // ToDo: Update tag filter - - children.forEachIndexed { i, button -> - button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) - } - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt new file mode 100644 index 000000000..ca980e608 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt @@ -0,0 +1,39 @@ +package com.lambda.gui.impl.clickgui.windows.tag + +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.module.ModuleRegistry +import com.lambda.module.tag.ModuleTag + +class CustomTagWindow( + title: String = "Untitled", + val tags: Set, + owner: AbstractClickGui +) : ModuleWindow(title, owner = owner) { + override fun onTick() { + updateModules() + super.onTick() + } + + private fun updateModules() { + // TODO: Modules in windows > tags in modules + // Get needed modules + val modules = ModuleRegistry.modules + .filter { it.customTags.any(tags::contains) } + + // Add missing module buttons + modules.filter { module -> + children.all { button -> + button.module != module + } + }.map { ModuleButton(it, this) }.forEach(children::add) + + // Remove deleted modules + children.removeIf { + val flag = it.module !in modules + if (flag) it.onRemove() + flag + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt new file mode 100644 index 000000000..835c4cdf8 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt @@ -0,0 +1,19 @@ +package com.lambda.gui.impl.clickgui.windows.tag + +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.module.ModuleRegistry +import com.lambda.module.tag.ModuleTag + +class TagWindow( + val tag: ModuleTag, + owner: AbstractClickGui +) : ModuleWindow(tag.name, owner = owner) { + init { + ModuleRegistry.modules + .filter { it.tag == tag } + .map { ModuleButton(it, this) } + .forEach(children::add) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 62c583acf..27d90dbc5 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -80,7 +80,7 @@ import com.lambda.util.Nameable * @property description The description of the module, * shown on hover over the module button in the GUI and in commands. * @property tag The leading module tag associated with the module. - * @property extraTags The set of extra [ModuleTag]s associated with the module. + * @property extraTags The set of extra, basically user-defined [ModuleTag]s associated with the module. * @property alwaysListening If true, the module's listeners will be triggered even if the module is not enabled. * @property isEnabledSetting The setting that determines if the module is enabled. * @property keybindSetting The setting that determines the keybind for the module. @@ -92,7 +92,7 @@ abstract class Module( override val name: String, val description: String = "", val tag: ModuleTag, - val extraTags: Set = setOf(), + extraTags: Set = setOf(), private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.Unbound, @@ -100,9 +100,7 @@ abstract class Module( private val isEnabledSetting = setting("Enabled", enabledByDefault, visibility = { false }) private val keybindSetting = setting("Keybind", defaultKeybind) private val isVisible = setting("Visible", true) - private val customTags by setting("Tags", extraTags, visibility = { false }) - - val tags get() = customTags + tag + val customTags by setting("Tags", extraTags, visibility = { false }) var isEnabled by isEnabledSetting override val isMuted: Boolean diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt index f3f1402ae..fcb58ade0 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt @@ -19,6 +19,10 @@ object ClickGui : Module( val buttonHeight by setting("Button Height", 11.0, 8.0..20.0, 0.1) val buttonStep by setting("Button Step", 1.0, 0.0..5.0, 0.1) + // Animation + val openSpeed by setting("Open Speed", 0.6, 0.1..1.0, 0.01) + val closeSpeed by setting("Close Speed", 0.7, 0.1..1.0, 0.01) + init { onEnable { if (mc.currentScreen != LambdaClickGui) { diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 1a579518d..cfad77d59 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -14,7 +14,6 @@ import com.lambda.interaction.rotation.RotationContext import com.lambda.interaction.rotation.RotationMode import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.KeyCode import com.lambda.util.player.MovementUtils.cancel import com.lambda.util.player.MovementUtils.verticalMovement import com.lambda.util.primitives.extension.interpolate From 7a174aec33a94ac9bb2ba85915c7fa7a086c789b Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 19 Apr 2024 14:05:26 +0300 Subject: [PATCH 04/63] Raw CustomModuleWindow impl --- common/src/main/kotlin/com/lambda/Lambda.kt | 6 +++--- ...zer.kt => CustomModuleWindowSerializer.kt} | 21 +++++++++++-------- .../src/main/kotlin/com/lambda/core/Loader.kt | 4 +--- .../{impl/clickgui => }/GuiConfigurable.kt | 7 ++++--- .../gui/impl/clickgui/LambdaClickGui.kt | 5 +++-- ...stomTagWindow.kt => CustomModuleWindow.kt} | 12 ++++------- .../main/kotlin/com/lambda/module/Module.kt | 3 --- 7 files changed, 27 insertions(+), 31 deletions(-) rename common/src/main/kotlin/com/lambda/config/serializer/gui/{CustomTagWindowSerializer.kt => CustomModuleWindowSerializer.kt} (70%) rename common/src/main/kotlin/com/lambda/gui/{impl/clickgui => }/GuiConfigurable.kt (85%) rename common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/{CustomTagWindow.kt => CustomModuleWindow.kt} (76%) diff --git a/common/src/main/kotlin/com/lambda/Lambda.kt b/common/src/main/kotlin/com/lambda/Lambda.kt index 5737c14ec..1990b8ab3 100644 --- a/common/src/main/kotlin/com/lambda/Lambda.kt +++ b/common/src/main/kotlin/com/lambda/Lambda.kt @@ -3,11 +3,11 @@ package com.lambda import com.google.gson.Gson import com.google.gson.GsonBuilder import com.lambda.config.serializer.* -import com.lambda.config.serializer.gui.CustomTagWindowSerializer +import com.lambda.config.serializer.gui.CustomModuleWindowSerializer import com.lambda.config.serializer.gui.ModuleTagSerializer import com.lambda.config.serializer.gui.TagWindowSerializer import com.lambda.core.Loader -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.KeyCode @@ -29,7 +29,7 @@ object Lambda { val gson: Gson = GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(ModuleTag::class.java, ModuleTagSerializer) - .registerTypeAdapter(CustomTagWindow::class.java, CustomTagWindowSerializer) + .registerTypeAdapter(CustomModuleWindow::class.java, CustomModuleWindowSerializer) .registerTypeAdapter(TagWindow::class.java, TagWindowSerializer) .registerTypeAdapter(KeyCode::class.java, KeyCodeSerializer) .registerTypeAdapter(Color::class.java, ColorSerializer) diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt similarity index 70% rename from common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt rename to common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt index a62209659..4e7c8274f 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt @@ -2,21 +2,22 @@ package com.lambda.config.serializer.gui import com.google.gson.* import com.lambda.gui.impl.clickgui.LambdaClickGui -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow +import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d import java.lang.reflect.Type -object CustomTagWindowSerializer : JsonSerializer, JsonDeserializer { +object CustomModuleWindowSerializer : JsonSerializer, JsonDeserializer { override fun serialize( - src: CustomTagWindow?, + src: CustomModuleWindow?, typeOfSrc: Type?, context: JsonSerializationContext?, ): JsonElement = src?.let { JsonObject().apply { addProperty("title", it.title) - add("tags", JsonArray().apply { - it.tags.forEach { + add("modules", JsonArray().apply { + it.modules.forEach { add(it.name) } }) @@ -35,11 +36,13 @@ object CustomTagWindowSerializer : JsonSerializer, JsonDeserial typeOfT: Type?, context: JsonDeserializationContext?, ) = json?.asJsonObject?.let { - CustomTagWindow( + CustomModuleWindow( it["title"].asString, - it["tags"].asJsonArray.map { tag -> - ModuleTag(tag.asString) - }.toSet(), + it["modules"].asJsonArray.mapNotNull { name -> + ModuleRegistry.modules.firstOrNull { module -> + module.name == name.asString + } + } as MutableList, LambdaClickGui ).apply { width = it["width"].asDouble diff --git a/common/src/main/kotlin/com/lambda/core/Loader.kt b/common/src/main/kotlin/com/lambda/core/Loader.kt index ff7ab72ef..3c035b4eb 100644 --- a/common/src/main/kotlin/com/lambda/core/Loader.kt +++ b/common/src/main/kotlin/com/lambda/core/Loader.kt @@ -3,10 +3,8 @@ package com.lambda.core import com.lambda.Lambda import com.lambda.Lambda.LOG import com.lambda.command.CommandManager -import com.lambda.config.configurations.GuiConfig import com.lambda.graphics.renderer.gui.font.LambdaFont -import com.lambda.gui.impl.clickgui.GuiConfigurable -import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.GuiConfigurable import com.lambda.interaction.PlayerPacketManager import com.lambda.interaction.RotationManager import com.lambda.module.ModuleRegistry diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt similarity index 85% rename from common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt rename to common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index c11d88e5a..9253bd6ab 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -1,9 +1,10 @@ -package com.lambda.gui.impl.clickgui +package com.lambda.gui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d @@ -17,7 +18,7 @@ object GuiConfigurable : Configurable(GuiConfig) { } } - val customWindows by setting("custom windows", listOf()).apply { + val customWindows by setting("custom windows", listOf()).apply { listener { from, _ -> from.forEach(WindowComponent<*>::destroy) // free vram } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index f8d806bc9..09e336b0b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -1,6 +1,7 @@ package com.lambda.gui.impl.clickgui -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.GuiConfigurable +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow object LambdaClickGui : AbstractClickGui() { override fun onShow() { @@ -19,7 +20,7 @@ object LambdaClickGui : AbstractClickGui() { children.addAll(new) children.removeIf { - if (it !is CustomTagWindow) return@removeIf false + if (it !is CustomModuleWindow) return@removeIf false val flag = it !in windows if (flag) it.destroy() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt similarity index 76% rename from common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt rename to common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index ca980e608..5cd1bbe9b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -3,12 +3,13 @@ package com.lambda.gui.impl.clickgui.windows.tag import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.module.Module import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag -class CustomTagWindow( - title: String = "Untitled", - val tags: Set, +class CustomModuleWindow( + override var title: String = "Untitled", + val modules: MutableList = mutableListOf(), owner: AbstractClickGui ) : ModuleWindow(title, owner = owner) { override fun onTick() { @@ -17,11 +18,6 @@ class CustomTagWindow( } private fun updateModules() { - // TODO: Modules in windows > tags in modules - // Get needed modules - val modules = ModuleRegistry.modules - .filter { it.customTags.any(tags::contains) } - // Add missing module buttons modules.filter { module -> children.all { button -> diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 27d90dbc5..07cd8cf37 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -80,7 +80,6 @@ import com.lambda.util.Nameable * @property description The description of the module, * shown on hover over the module button in the GUI and in commands. * @property tag The leading module tag associated with the module. - * @property extraTags The set of extra, basically user-defined [ModuleTag]s associated with the module. * @property alwaysListening If true, the module's listeners will be triggered even if the module is not enabled. * @property isEnabledSetting The setting that determines if the module is enabled. * @property keybindSetting The setting that determines the keybind for the module. @@ -92,7 +91,6 @@ abstract class Module( override val name: String, val description: String = "", val tag: ModuleTag, - extraTags: Set = setOf(), private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.Unbound, @@ -100,7 +98,6 @@ abstract class Module( private val isEnabledSetting = setting("Enabled", enabledByDefault, visibility = { false }) private val keybindSetting = setting("Keybind", defaultKeybind) private val isVisible = setting("Visible", true) - val customTags by setting("Tags", extraTags, visibility = { false }) var isEnabled by isEnabledSetting override val isMuted: Boolean From ec4c3c0c227e90b046499e0bb59c4663eab0d91b Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 21 Apr 2024 20:29:21 +0300 Subject: [PATCH 05/63] Broken blur --- .../com/lambda/event/events/RenderEvent.kt | 4 +- .../kotlin/com/lambda/graphics/RenderMain.kt | 4 ++ .../buffer/vao/vertex/VertexAttrib.kt | 3 +- .../renderer/immediate/BlurPostProcessor.kt | 53 +++++++++++++++++++ .../gui/api/component/WindowComponent.kt | 2 + .../lambda/shaders/fragment/post/blur.frag | 22 ++++++++ .../lambda/shaders/vertex/post/blur.vert | 14 +++++ 7 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt create mode 100644 common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert diff --git a/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt b/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt index 178163df5..d222a7caa 100644 --- a/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt @@ -9,11 +9,11 @@ import com.lambda.util.math.Vec2d abstract class RenderEvent : Event { class World : RenderEvent() - abstract class GUI(val scaleFactor: Double) : RenderEvent() { + abstract class GUI(val scale: Double) : RenderEvent() { class Scaled(scaleFactor: Double) : GUI(scaleFactor) class Fixed : GUI(1.0) - val screenSize = Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) / scaleFactor + val screenSize = Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) / scale } class UpdateTarget : RenderEvent(), ICancellable by Cancellable() } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index c3a935af3..c00013cb0 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -8,12 +8,15 @@ import com.lambda.graphics.gl.Matrices import com.lambda.graphics.gl.Matrices.resetMatrix import com.lambda.graphics.gl.Matrices.translate import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.math.Vec2d import org.joml.Matrix4f object RenderMain { val projectionMatrix = Matrix4f() val modelViewMatrix: Matrix4f get() = Matrices.stack.peek().positionMatrix + var screenSize = Vec2d.ZERO + @JvmStatic fun render2D() { resetMatrix() @@ -35,6 +38,7 @@ object RenderMain { val scaledWidth = width / factor val scaledHeight = height / factor + screenSize = Vec2d(scaledWidth, scaledHeight) projectionMatrix.setOrtho(0f, scaledWidth.toFloat(), scaledHeight.toFloat(), 0f, 1000f, 21000f) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt index 8085a20c4..547050b89 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt @@ -12,7 +12,8 @@ enum class VertexAttrib(val componentCount: Int, componentSize: Int, val normali enum class Group(vararg val attributes: VertexAttrib) { FONT(Vec2, Vec2, Color), - RECT(Vec2, Vec2, Vec3, Color); + RECT(Vec2, Vec2, Vec3, Color), + BLUR(Vec2, Vec2); val stride = attributes.sumOf { attribute -> attribute.size } } diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt new file mode 100644 index 000000000..0f85814f4 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt @@ -0,0 +1,53 @@ +package com.lambda.graphics.renderer.immediate + +import com.lambda.Lambda.mc +import com.lambda.graphics.RenderMain +import com.lambda.graphics.buffer.vao.VAO +import com.lambda.graphics.buffer.vao.vertex.VertexAttrib +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.shader.Shader +import com.lambda.graphics.texture.TextureUtils.bindTexture +import com.lambda.util.math.Rect +import com.lambda.util.math.Vec2d + +object BlurPostProcessor { + private val vao = VAO(VertexMode.TRIANGLES, VertexAttrib.Group.BLUR) + private val shader = Shader("post/blur") + + + fun render(rect: Rect, level: Int) { + renderPass(rect, Vec2d.RIGHT, level) + renderPass(rect, Vec2d.BOTTOM, level) + } + + private fun renderPass(rect: Rect, direction: Vec2d, level: Int) { + val x1 = rect.leftTop.x + val y1 = rect.leftTop.y + val x2 = rect.rightBottom.x + val y2 = rect.rightBottom.y + + val screen = RenderMain.screenSize + val uv1x = x1 / screen.x + val uv1y = y1 / screen.y + val uv2x = x2 / screen.x + val uv2y = y2 / screen.y + + vao.use { + putQuad( + vec2(x1, y1).vec2(uv1x, 1.0 - uv1y).end(), + vec2(x2, y1).vec2(uv2x, 1.0 - uv1y).end(), + vec2(x2, y2).vec2(uv2x, 1.0 - uv2y).end(), + vec2(x1, y2).vec2(uv1x, 1.0 - uv2y).end() + ) + + shader.use() + shader["u_Direction"] = direction / Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) + shader["u_BlurLevel"] = level + + bindTexture(mc.framebuffer.colorAttachment) + upload() + render() + clear() + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index ef4ad988b..1df7a6296 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -3,6 +3,7 @@ package com.lambda.gui.api.component import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry +import com.lambda.graphics.renderer.immediate.BlurPostProcessor import com.lambda.gui.api.component.core.list.IListComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.layer.RenderLayer @@ -92,6 +93,7 @@ abstract class WindowComponent ( } override fun onRender() { + BlurPostProcessor.render(rect, 30) layer.render() scissor(contentRect) { diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag new file mode 100644 index 000000000..44e33ba14 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag @@ -0,0 +1,22 @@ +#version 330 core + +uniform sampler2D u_Texture; +uniform vec2 u_Direction; + +uniform int u_BlurLevel; + +in vec2 v_TexCoord; +out vec4 color; + +void main() { + vec4 col = texture(u_Texture, v_TexCoord); + int amt = 1; + + for (float i = -u_BlurLevel * 0.5; i < u_BlurLevel * 0.5; ++i) { + vec2 ofs = i * u_Direction; + col += texture(u_Texture, v_TexCoord + ofs); + amt++; + } + + color = col / amt; +} diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert b/common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert new file mode 100644 index 000000000..8280235af --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec4 pos; +layout (location = 1) in vec2 uv; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +out vec2 v_TexCoord; + +void main() { + gl_Position = u_Projection * u_ModelView * pos; + v_TexCoord = uv; +} \ No newline at end of file From f6f8068e84224b28ed0afedd6bbcd54593c08160 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 14:32:54 -0400 Subject: [PATCH 06/63] Faster texture upload (up to 20%) --- .../com/lambda/graphics/texture/TextureUtils.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt index 5361b4cc3..57769e7dc 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt @@ -3,7 +3,10 @@ package com.lambda.graphics.texture import com.mojang.blaze3d.systems.RenderSystem import net.minecraft.client.texture.NativeImage import org.lwjgl.BufferUtils +import org.lwjgl.opengl.ARBTextureStorage.glTexStorage2D +import org.lwjgl.opengl.GL11C import org.lwjgl.opengl.GL13C.* +import org.lwjgl.opengl.GL30C.glGenerateMipmap import java.awt.Color import java.awt.Font import java.awt.RenderingHints @@ -24,7 +27,13 @@ object TextureUtils { val width = bufferedImage.width val height = bufferedImage.height - glTexImage2D(GL_TEXTURE_2D, lod, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, readImage(bufferedImage)) + // GL_UNSIGNED_INT_8_8_8_8_REV -> 0xRRGGBBAA + // GL_UNSIGNED_BYTE -> [RR, GG, BB, AA] + // In the end it will be the exact same but in the case that you + // supply the data in the reverse order, GL_UNSIGNED_INT_8_8_8_8_REV + // will swap the bytes for you. + glTexImage2D(GL_TEXTURE_2D, lod, GL_BGRA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0) + glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, readImage(bufferedImage)) setupTexture(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR) } @@ -84,7 +93,7 @@ object TextureUtils { } fun BufferedImage.rescale(targetWidth: Int, targetHeight: Int): BufferedImage { - val type = if (this.transparency == Transparency.OPAQUE) + val type = if (transparency == Transparency.OPAQUE) BufferedImage.TYPE_INT_RGB else BufferedImage.TYPE_INT_ARGB @@ -117,4 +126,4 @@ object TextureUtils { return image } -} \ No newline at end of file +} From d2d37924acb087ec53b9cd2d5a80039503363b32 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 16:26:20 -0400 Subject: [PATCH 07/63] Better gaussian blur --- .../gui/api/component/WindowComponent.kt | 4 +-- .../lambda/shaders/fragment/post/blur.frag | 32 +++++++++++++++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 1df7a6296..f714a5293 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -93,7 +93,7 @@ abstract class WindowComponent ( } override fun onRender() { - BlurPostProcessor.render(rect, 30) + BlurPostProcessor.render(rect, 15) // TODO: Customizable blur level layer.render() scissor(contentRect) { @@ -151,4 +151,4 @@ abstract class WindowComponent ( subLayer.destroy() children.clear() } -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag index 44e33ba14..b5e18b761 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag @@ -1,22 +1,40 @@ #version 330 core +#define pow2(x) (x * x) + uniform sampler2D u_Texture; uniform vec2 u_Direction; - uniform int u_BlurLevel; in vec2 v_TexCoord; out vec4 color; +float gaussian(float x) { + return exp(-pow2(x) / (2.0 * pow2(u_BlurLevel) / (2.50662 * u_BlurLevel))); +} + void main() { vec4 col = texture(u_Texture, v_TexCoord); - int amt = 1; + float totalWeight = 1.0; + + for (int i = -u_BlurLevel; i <= u_BlurLevel; ++i) { + float offset = float(i); + vec2 texOffset = offset * u_Direction; + col += texture(u_Texture, v_TexCoord + texOffset) * gaussian(offset); + totalWeight += gaussian(offset); + } + + // Normalize the color + col /= totalWeight; - for (float i = -u_BlurLevel * 0.5; i < u_BlurLevel * 0.5; ++i) { - vec2 ofs = i * u_Direction; - col += texture(u_Texture, v_TexCoord + ofs); - amt++; + // Vertical blur + totalWeight = 0.0; + for (int i = -u_BlurLevel; i <= u_BlurLevel; ++i) { + float offset = float(i); + vec2 texOffset = offset * u_Direction; + col += texture(u_Texture, v_TexCoord + texOffset) * gaussian(offset); + totalWeight += gaussian(offset); } - color = col / amt; + color = col / totalWeight; } From d7b2f1886864df01275aa5b89a1a78273a9c6ec8 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:04:20 -0400 Subject: [PATCH 08/63] Get rid of the mojang's rendering utilities Mod loaders can edit them and cause issues (forge) --- .../com/lambda/graphics/gl/GlStateUtils.kt | 44 +++++----- .../kotlin/com/lambda/graphics/gl/Matrices.kt | 4 +- .../com/lambda/graphics/gl/MatrixStack.kt | 80 +++++++++++++++++++ .../kotlin/com/lambda/graphics/gl/Scissor.kt | 9 +-- .../kotlin/com/lambda/graphics/gl/VaoUtils.kt | 12 ++- 5 files changed, 109 insertions(+), 40 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt b/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt index b0e474eed..f29b8f5e3 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt @@ -1,10 +1,7 @@ package com.lambda.graphics.gl -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.systems.RenderSystem.depthMask -import org.lwjgl.opengl.GL30C +import org.lwjgl.opengl.GL30C.* -@Suppress("NOTHING_TO_INLINE") object GlStateUtils { private var depthTestState = true private var depthMaskState = true @@ -18,7 +15,7 @@ object GlStateUtils { val savedCull = cullState depthTest(false) - depthMask(false) + glDepthMask(false) blend(true) cull(false) lineSmooth(true) @@ -26,7 +23,7 @@ object GlStateUtils { block() depthTest(savedDepthTest) - depthMask(savedDepthMask) + glDepthMask(savedDepthMask) blend(savedBlend) cull(savedCull) lineSmooth(false) @@ -41,35 +38,32 @@ object GlStateUtils { @JvmStatic fun capSet(id: Int, flag: Boolean) { val field = when (id) { - GL30C.GL_DEPTH_TEST -> ::depthTestState - GL30C.GL_DEPTH -> ::depthMaskState - GL30C.GL_BLEND -> ::blendState - GL30C.GL_CULL_FACE -> ::cullState + GL_DEPTH_TEST -> ::depthTestState + GL_DEPTH -> ::depthMaskState + GL_BLEND -> ::blendState + GL_CULL_FACE -> ::cullState else -> return } field.set(flag) } - private inline fun blend(flag: Boolean) { + private fun blend(flag: Boolean) { if (flag) { - RenderSystem.enableBlend() - RenderSystem.defaultBlendFunc() - } else RenderSystem.disableBlend() + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + } else glDisable(GL_BLEND) } - private inline fun cull(flag: Boolean) { - if (flag) RenderSystem.enableCull() - else RenderSystem.disableCull() + private fun cull(flag: Boolean) { + if (flag) glEnable(GL_CULL_FACE) + else glDisable(GL_CULL_FACE) } - private inline fun depthTest(flag: Boolean) { - if (flag) RenderSystem.enableDepthTest() - else RenderSystem.disableDepthTest() - } + private fun depthTest(flag: Boolean) = glDepthMask(flag) - private inline fun lineSmooth(flag: Boolean) { - if (flag) GL30C.glEnable(GL30C.GL_LINE_SMOOTH) - else GL30C.glDisable(GL30C.GL_LINE_SMOOTH) + private fun lineSmooth(flag: Boolean) { + if (flag) glEnable(GL_LINE_SMOOTH) + else glDisable(GL_LINE_SMOOTH) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt index 1932ec531..fb8235840 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt @@ -1,7 +1,5 @@ package com.lambda.graphics.gl -import net.minecraft.client.util.math.MatrixStack - object Matrices { var stack = MatrixStack() private val matrix get() = stack.peek().positionMatrix @@ -30,4 +28,4 @@ object Matrices { val valueFloat = value.toFloat() matrix.scale(valueFloat, valueFloat, valueFloat) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt b/common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt new file mode 100644 index 000000000..506897f76 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt @@ -0,0 +1,80 @@ +package com.lambda.graphics.gl + +import org.joml.Matrix3f +import org.joml.Matrix4f +import org.joml.Quaternionf +import java.util.* +import kotlin.math.cbrt + +class MatrixStack { + private val stack: Deque = ArrayDeque() + + init { + val matrix4f = Matrix4f() + val matrix3f = Matrix3f() + stack.add( + Entry(Matrix4f(), Matrix3f() + )) + } + + fun translate(x: Double, y: Double, z: Double): Matrix4f = + translate(x.toFloat(), y.toFloat(), z.toFloat()) + + fun translate(x: Float, y: Float, z: Float): Matrix4f = + stack.last.positionMatrix.translate(x, y, z) + + fun scale(x: Float, y: Float, z: Float) { + val entry = stack.last + entry.positionMatrix.scale(x, y, z) + if (x == y && y == z) { + if (x > 0.0f) { + return + } + entry.normalMatrix.scale(-1.0f) + } + val f = 1.0f / x + val g = 1.0f / y + val h = 1.0f / z + val i = cbrt(f * g * h) + entry.normalMatrix.scale(i * f, i * g, i * h) + } + + fun multiply(quaternion: Quaternionf) { + val entry = stack.last + entry.positionMatrix.rotate(quaternion) + entry.normalMatrix.rotate(quaternion) + } + + fun multiply(quaternion: Quaternionf, originX: Float, originY: Float, originZ: Float) { + val entry = stack.last + entry.positionMatrix.rotateAround(quaternion, originX, originY, originZ) + entry.normalMatrix.rotate(quaternion) + } + + fun push() { + val entry = stack.last + stack.addLast(Entry(Matrix4f(entry.positionMatrix), Matrix3f(entry.normalMatrix))) + } + + fun pop() { + stack.removeLast() + } + + fun peek(): Entry { + return stack.last + } + + fun isEmpty() = stack.size <= 1 + + fun loadIdentity() { + val entry = stack.last + entry.positionMatrix.identity() + entry.normalMatrix.identity() + } + + fun multiplyPositionMatrix(matrix: Matrix4f) { + stack.last.positionMatrix.mul(matrix) + } + + data class Entry(val positionMatrix: Matrix4f, val normalMatrix: Matrix3f) +} diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt index 248975925..00d246d2a 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt @@ -5,8 +5,7 @@ import com.lambda.module.modules.client.GuiSettings import com.lambda.util.math.MathUtils.ceilToInt import com.lambda.util.math.MathUtils.floorToInt import com.lambda.util.math.Rect -import com.mojang.blaze3d.systems.RenderSystem.disableScissor -import com.mojang.blaze3d.systems.RenderSystem.enableScissor +import org.lwjgl.opengl.GL30C.* import kotlin.math.max object Scissor { @@ -29,7 +28,7 @@ object Scissor { private fun scissor(entry: Rect?) { if (entry == null) { - disableScissor() + glDisable(GL_SCISSOR_TEST) return } @@ -43,11 +42,11 @@ object Scissor { val y = mc.window.framebufferHeight - pos1.y - height - enableScissor( + glScissor( pos1.x.floorToInt(), y.floorToInt(), width.ceilToInt(), height.ceilToInt() ) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/VaoUtils.kt b/common/src/main/kotlin/com/lambda/graphics/gl/VaoUtils.kt index 4aa7d91ce..614082bfc 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/VaoUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/VaoUtils.kt @@ -1,11 +1,9 @@ package com.lambda.graphics.gl -import com.mojang.blaze3d.platform.GlStateManager import net.minecraft.client.render.BufferRenderer import org.lwjgl.opengl.GL30C.* import java.nio.ByteBuffer -@Suppress("NOTHING_TO_INLINE") object VaoUtils { @JvmField var lastIbo = 0 private var prevIbo = 0 @@ -33,12 +31,12 @@ object VaoUtils { fun unbindIndexBuffer() = bindIndexBuffer(0) - inline fun enableVertexAttribute(i: Int) = + fun enableVertexAttribute(i: Int) = glEnableVertexAttribArray(i) - inline fun vertexAttribute(index: Int, size: Int, type: Int, normalized: Boolean, stride: Int, pointer: Long) = + fun vertexAttribute(index: Int, size: Int, type: Int, normalized: Boolean, stride: Int, pointer: Long) = glVertexAttribPointer(index, size, type, normalized, stride, pointer) - inline fun bufferData(target: Int, data: ByteBuffer, usage: Int) = - GlStateManager._glBufferData(target, data, usage) -} \ No newline at end of file + fun bufferData(target: Int, data: ByteBuffer, usage: Int) = + glBufferData(target, data, usage) +} From dd59c3f940664330d3e058d3ce7cf3f78953c086 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 13 Apr 2024 23:00:11 +0300 Subject: [PATCH 09/63] Tag windows --- .../com/lambda/gui/impl/clickgui/GuiConfigurable.kt | 12 +++++++++++- .../lambda/gui/impl/clickgui/windows/TagWindow.kt | 2 +- .../kotlin/com/lambda/interaction/RotationManager.kt | 2 +- common/src/main/kotlin/com/lambda/module/Module.kt | 11 +++++++---- .../com/lambda/module/modules/client/Baritone.kt | 2 +- .../com/lambda/module/modules/client/ClickGui.kt | 6 +++--- .../com/lambda/module/modules/client/FontSettings.kt | 2 +- .../com/lambda/module/modules/client/GuiSettings.kt | 2 +- .../com/lambda/module/modules/client/Rubberband.kt | 2 +- .../com/lambda/module/modules/client/ServerSpoof.kt | 2 +- .../module/{ => modules/debug}/BaritoneTest.kt | 7 +++++-- .../modules/{render => debug}/InventoryDebug.kt | 6 +++--- .../module/modules/{ => debug}/Packetlogger.kt | 5 ++--- .../module/modules/{ => debug}/RotationTest.kt | 5 +++-- .../lambda/module/modules/movement/RocketExtend.kt | 2 +- .../com/lambda/module/modules/movement/SafeWalk.kt | 2 +- .../com/lambda/module/modules/movement/Speed.kt | 2 +- .../com/lambda/module/modules/movement/Sprint.kt | 2 +- .../com/lambda/module/modules/player/Freecam.kt | 6 +++--- .../com/lambda/module/modules/player/Interact.kt | 2 +- .../com/lambda/module/modules/render/Fullbright.kt | 2 +- .../com/lambda/module/modules/render/NoRender.kt | 2 +- .../kotlin/com/lambda/module/modules/render/XRay.kt | 6 ++---- .../com/lambda/module/modules/{ => world}/Timer.kt | 4 ++-- .../main/kotlin/com/lambda/module/tag/ModuleTag.kt | 10 +++++----- 25 files changed, 60 insertions(+), 46 deletions(-) rename common/src/main/kotlin/com/lambda/module/{ => modules/debug}/BaritoneTest.kt (70%) rename common/src/main/kotlin/com/lambda/module/modules/{render => debug}/InventoryDebug.kt (92%) rename common/src/main/kotlin/com/lambda/module/modules/{ => debug}/Packetlogger.kt (98%) rename common/src/main/kotlin/com/lambda/module/modules/{ => debug}/RotationTest.kt (94%) rename common/src/main/kotlin/com/lambda/module/modules/{ => world}/Timer.kt (85%) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt index 79158c61d..4f88a9cf9 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt @@ -3,8 +3,18 @@ package com.lambda.gui.impl.clickgui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.Vec2d object GuiConfigurable : Configurable(GuiConfig) { override val name = "gui" - val windows = setting("windows", listOf(TagWindow())) + val windows = setting("windows", defaultWindows) + + private val defaultWindows get() = + ModuleTag.defaults.mapIndexed { index, tag -> + TagWindow(setOf(tag), tag.name).apply { + val step = 3.0 + position = Vec2d((width + step) * index, 0.0) + step + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt index 7249a0e11..9beef6a56 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt @@ -18,7 +18,7 @@ class TagWindow( ) : WindowComponent(), IChildComponent { init { ModuleRegistry.modules.filter { module -> - module.customTags.value.any(tags::contains) || tags.isEmpty() + module.tags.any(tags::contains) }.forEach { children.add(ModuleButton(it, this)) } diff --git a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 709a23f1f..2f0159050 100644 --- a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -166,7 +166,7 @@ object RotationManager : Loadable { baritoneContext = null } - listener { + listener(Int.MAX_VALUE) { processPlayerMovement(it) } } diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 545bc6195..62c583acf 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -1,6 +1,5 @@ package com.lambda.module -import com.google.gson.reflect.TypeToken import com.lambda.config.AbstractSetting import com.lambda.config.Configurable import com.lambda.config.Configuration @@ -80,7 +79,8 @@ import com.lambda.util.Nameable * @property name The name of the module, displayed in-game. * @property description The description of the module, * shown on hover over the module button in the GUI and in commands. - * @property defaultTags The set of [ModuleTag]s associated with the module. + * @property tag The leading module tag associated with the module. + * @property extraTags The set of extra [ModuleTag]s associated with the module. * @property alwaysListening If true, the module's listeners will be triggered even if the module is not enabled. * @property isEnabledSetting The setting that determines if the module is enabled. * @property keybindSetting The setting that determines the keybind for the module. @@ -91,7 +91,8 @@ import com.lambda.util.Nameable abstract class Module( override val name: String, val description: String = "", - val defaultTags: Set = setOf(), + val tag: ModuleTag, + val extraTags: Set = setOf(), private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.Unbound, @@ -99,7 +100,9 @@ abstract class Module( private val isEnabledSetting = setting("Enabled", enabledByDefault, visibility = { false }) private val keybindSetting = setting("Keybind", defaultKeybind) private val isVisible = setting("Visible", true) - val customTags = setting("Tags", defaultTags, visibility = { false }) + private val customTags by setting("Tags", extraTags, visibility = { false }) + + val tags get() = customTags + tag var isEnabled by isEnabledSetting override val isMuted: Boolean diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt index 892478d99..d25f059b8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/Baritone.kt @@ -9,7 +9,7 @@ import com.lambda.util.math.MathUtils.random object Baritone : Module( name = "Baritone", description = "Baritone configuration", - defaultTags = setOf(ModuleTag.CLIENT) + ModuleTag.CLIENT ) { private val r1 by setting("Turn Speed 1", 70.0, 1.0..180.0, 0.1) private val r2 by setting("Turn Speed 2", 110.0, 1.0..180.0, 0.1) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt index 4b18b7b80..f3f1402ae 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt @@ -5,13 +5,13 @@ import com.lambda.event.listener.UnsafeListener.Companion.unsafeListener import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.threading.mainThread -import java.awt.Color +import com.lambda.util.KeyCode object ClickGui : Module( name = "ClickGui", description = "Sexy", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT, + defaultKeybind = KeyCode.RIGHT_SHIFT ) { // General val windowRadius by setting("Window Radius", 2.0, 0.0..10.0, 0.1) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt index ed0c42c82..943387d92 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object FontSettings : Module( name = "FontSettings", description = "Font renderer configuration", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT ) { val shadow by setting("Shadow", true) val shadowBrightness by setting("Shadow Brightness", 0.35, 0.0..0.5, 0.01, visibility = { shadow }) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt index 60c98773f..eba68547a 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt @@ -7,7 +7,7 @@ import java.awt.Color object GuiSettings : Module( name = "GuiSettings", description = "Visual behaviour configuration", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT ) { private val page by setting("Page", Page.General) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt b/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt index 8b9ff9d03..af76e03c8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/Rubberband.kt @@ -21,7 +21,7 @@ import java.awt.Color object Rubberband : Module( name = "Rubberband", description = "Info about rubberbands", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.CLIENT ) { private val showLastPacketInfo by setting("Show Last Packet", true) private val showConnectionState by setting("Show Connection State", true) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt index aaf045395..bcdb77aee 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ServerSpoof.kt @@ -17,7 +17,7 @@ import java.awt.Color object ServerSpoof : Module( name = "ServerSpoof", description = "Decide yourself if you want to accept the server resource pack.", - defaultTags = setOf(ModuleTag.BYPASS) + tag = ModuleTag.CLIENT ) { private val spoofClientBrand by setting("Spoof Client Brand", true) private val spoofName by setting("Spoof Name", "vanilla", visibility = { spoofClientBrand }) diff --git a/common/src/main/kotlin/com/lambda/module/BaritoneTest.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt similarity index 70% rename from common/src/main/kotlin/com/lambda/module/BaritoneTest.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt index 604b744f6..e524396eb 100644 --- a/common/src/main/kotlin/com/lambda/module/BaritoneTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/BaritoneTest.kt @@ -1,13 +1,16 @@ -package com.lambda.module +package com.lambda.module.modules.debug import baritone.api.BaritoneAPI import baritone.api.pathing.goals.GoalXZ import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag object BaritoneTest : Module( name = "BaritoneTest", - description = "Test Baritone" + description = "Test Baritone", + tag = ModuleTag.DEBUG ) { init { listener { diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/InventoryDebug.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt similarity index 92% rename from common/src/main/kotlin/com/lambda/module/modules/render/InventoryDebug.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt index 7f89d2ca8..87dcf597b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/InventoryDebug.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/InventoryDebug.kt @@ -1,10 +1,10 @@ -package com.lambda.module.modules.render +package com.lambda.module.modules.debug import com.lambda.Lambda.LOG import com.lambda.event.events.PacketEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module -import com.lambda.util.Communication.info +import com.lambda.module.tag.ModuleTag import com.lambda.util.DynamicReflectionSerializer.dynamicString import net.minecraft.network.packet.c2s.play.* import net.minecraft.network.packet.s2c.play.InventoryS2CPacket @@ -13,7 +13,7 @@ import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket object InventoryDebug : Module( name = "InventoryDebug", description = "Debugs the inventory", - defaultTags = setOf() + tag = ModuleTag.DEBUG ) { init { listener { diff --git a/common/src/main/kotlin/com/lambda/module/modules/Packetlogger.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/Packetlogger.kt similarity index 98% rename from common/src/main/kotlin/com/lambda/module/modules/Packetlogger.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/Packetlogger.kt index f2a44e6e4..1a31ed380 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/Packetlogger.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/Packetlogger.kt @@ -1,6 +1,5 @@ -package com.lambda.module.modules +package com.lambda.module.modules.debug -import com.google.gson.reflect.TypeToken import com.lambda.Lambda import com.lambda.Lambda.mc import com.lambda.event.EventFlow.lambdaScope @@ -30,7 +29,7 @@ import kotlin.io.path.pathString object Packetlogger : Module( name = "Packetlogger", description = "Serializes network traffic and persists it for later analysis", - defaultTags = setOf(ModuleTag.DEBUG) + tag = ModuleTag.DEBUG ) { private val logToChat by setting("Log To Chat", false, "Log packets to chat") // ToDo: Implement HUD logging when HUD is done diff --git a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt similarity index 94% rename from common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt index 2efdabd38..cdb86657b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/RotationTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/RotationTest.kt @@ -1,10 +1,11 @@ -package com.lambda.module.modules +package com.lambda.module.modules.debug import com.lambda.config.InteractionSettings import com.lambda.config.RotationSettings import com.lambda.event.events.RotationEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag import net.minecraft.util.Hand import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos @@ -13,7 +14,7 @@ import net.minecraft.util.math.Direction object RotationTest : Module( name = "RotationTest", description = "Test rotation", - defaultTags = setOf() + tag = ModuleTag.DEBUG ) { private val rotationConfig = RotationSettings(this) private val interactionConfig = InteractionSettings(this) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt index bea85a9d1..b01833d0e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/RocketExtend.kt @@ -13,7 +13,7 @@ import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket object RocketExtend : Module( name = "RocketExtend", description = "Extends rocket length on grim", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { private var extendedRockets = mutableListOf() private var pingPacket: CommonPongC2SPacket? = null diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt index 5de96e318..e941632b8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/SafeWalk.kt @@ -8,7 +8,7 @@ import com.lambda.module.tag.ModuleTag object SafeWalk : Module( name = "SafeWalk", description = "Keeps you at the edge", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { private val realisticCollision by setting("Collide", true, "Realistic collision on the edge") diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt index 29455d524..21d422947 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Speed.kt @@ -20,7 +20,7 @@ import kotlin.math.max object Speed : Module( name = "Speed", description = "Fastest module", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { private val mode by setting("Mode", Mode.MATRIX_STRAFE_1) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt index 145c68821..f0ec65992 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/Sprint.kt @@ -6,5 +6,5 @@ import com.lambda.module.tag.ModuleTag object Sprint : Module( name = "Sprint", description = "Sprints automatically", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 7ee5ad6ea..eb98f6710 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -29,7 +29,7 @@ import net.minecraft.util.math.Vec3d object Freecam : Module( name = "Freecam", description = "Move your camera freely", - defaultTags = setOf(ModuleTag.RENDER), + tag = ModuleTag.PLAYER, defaultKeybind = KeyCode.G ) { private val speed by setting("Speed", 0.5f, 0.1f..1.0f, 0.1f) @@ -82,9 +82,9 @@ object Freecam : Module( listener { // Don't block baritone from working - if (player.input !is PlayerMovementInput) { + if (event.input !is PlayerMovementInput) { // Reset actual input - player.input.cancel() + event.input.cancel() } // Create new input for freecam diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt index 694e6d78e..c294bfd1b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Interact.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object Interact : Module( name = "Interact", description = "Modify players interaction with the world", - defaultTags = setOf(ModuleTag.PLAYER) + tag = ModuleTag.PLAYER ) { // ToDo: Is this fast place / fast use? Should it be relocated with more options? @JvmStatic val placeDelay by setting("Item Use / Place Delay", 4, 0..20, 1, "Sets the delay between placing blocks or using items") diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt b/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt index 1d3e3c855..46e766b16 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/Fullbright.kt @@ -6,5 +6,5 @@ import com.lambda.module.tag.ModuleTag object Fullbright : Module( name = "Fullbright", description = "Makes everything brighter", - defaultTags = setOf(ModuleTag.RENDER) + tag = ModuleTag.RENDER ) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt b/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt index bf0093645..11b649c8e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/NoRender.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object NoRender : Module( name = "NoRender", description = "Disables rendering of certain things", - defaultTags = setOf(ModuleTag.RENDER) + tag = ModuleTag.RENDER ) { @JvmStatic val noDarkness by setting("No Darkness", true) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt b/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt index 6da4dd51c..02ee032d9 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/XRay.kt @@ -6,7 +6,5 @@ import com.lambda.module.tag.ModuleTag object XRay : Module( name = "XRay", description = "Allows you to see ores through walls", - defaultTags = setOf(ModuleTag.RENDER) -) { - -} \ No newline at end of file + tag = ModuleTag.RENDER +) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/Timer.kt b/common/src/main/kotlin/com/lambda/module/modules/world/Timer.kt similarity index 85% rename from common/src/main/kotlin/com/lambda/module/modules/Timer.kt rename to common/src/main/kotlin/com/lambda/module/modules/world/Timer.kt index 430df32cd..235b32bc8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/Timer.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/world/Timer.kt @@ -1,4 +1,4 @@ -package com.lambda.module.modules +package com.lambda.module.modules.world import com.lambda.event.events.ClientEvent import com.lambda.event.listener.SafeListener.Companion.listener @@ -8,7 +8,7 @@ import com.lambda.module.tag.ModuleTag object Timer : Module( name = "Timer", description = "Modify client tick speed.", - defaultTags = setOf(ModuleTag.CLIENT) + tag = ModuleTag.WORLD ) { private val timer by setting("Timer", 50, 0..1000, 5, unit = "ms/tick") diff --git a/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt b/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt index 16da6cbc2..a4002c17b 100644 --- a/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt +++ b/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt @@ -15,18 +15,18 @@ import com.lambda.util.Nameable * * @param name The name of the tag. */ -class ModuleTag(override val name: String) : Nameable { +data class ModuleTag(override val name: String) : Nameable { companion object { val COMBAT = ModuleTag("Combat") val MOVEMENT = ModuleTag("Movement") val RENDER = ModuleTag("Render") val PLAYER = ModuleTag("Player") val WORLD = ModuleTag("World") - val MISC = ModuleTag("Misc") + val DEBUG = ModuleTag("Debug") val CLIENT = ModuleTag("Client") - val HIDDEN = ModuleTag("Hidden") + val GRIM = ModuleTag("Grim") - val BYPASS = ModuleTag("Bypass") - val DEBUG = ModuleTag("Debug") + + val defaults = listOf(COMBAT, MOVEMENT, RENDER, PLAYER, WORLD, DEBUG, CLIENT) } } \ No newline at end of file From 8bb83c1c59bbf2a980da8ef7697f889f3575ff73 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 13 Apr 2024 23:17:08 +0300 Subject: [PATCH 10/63] Freecam vertical movement fixes --- .../kotlin/com/lambda/module/modules/player/Freecam.kt | 5 ++--- .../main/kotlin/com/lambda/util/player/MovementUtils.kt | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index eb98f6710..4bf7ec477 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -29,8 +29,7 @@ import net.minecraft.util.math.Vec3d object Freecam : Module( name = "Freecam", description = "Move your camera freely", - tag = ModuleTag.PLAYER, - defaultKeybind = KeyCode.G + tag = ModuleTag.PLAYER ) { private val speed by setting("Speed", 0.5f, 0.1f..1.0f, 0.1f) private val sprint by setting("Sprint Multiplier", 3.0f, 0.1f..10.0f, 0.1f, description = "Set below 1.0 to fly slower on sprint.") @@ -94,7 +93,7 @@ object Freecam : Module( val inputVec = Vec3d( input.movementSideways.toDouble(), - verticalMovement.toDouble(), + input.verticalMovement.toDouble(), input.movementForward.toDouble() ) diff --git a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt index 511b0f1a8..e5b6926d1 100644 --- a/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/player/MovementUtils.kt @@ -26,13 +26,16 @@ object MovementUtils { pressingBack = false pressingLeft = false pressingRight = false + + sneaking = false + jumping = false } val SafeContext.isInputting: Boolean get() = roundedForward != 0f || roundedStrafing != 0f - val SafeContext.verticalMovement get() = - player.input.jumping.toInt() - player.input.sneaking.toInt() + val Input.verticalMovement get() = + jumping.toInt() - sneaking.toInt() fun SafeContext.calcMoveYaw( yawIn: Float = player.moveYaw, From dd2a14e3c138a8519f94c75879421888093287e4 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 19 Apr 2024 13:25:12 +0300 Subject: [PATCH 11/63] ClickGui: Open/Hide Animations Toggle animation improvements Tag Windows --- common/src/main/kotlin/com/lambda/Lambda.kt | 5 +- .../gui/CustomTagWindowSerializer.kt | 54 +++++++++++++++ .../serializer/gui/TagWindowSerializer.kt | 22 ++---- .../lambda/graphics/animation/Animation.kt | 3 + .../kotlin/com/lambda/gui/api/LambdaGui.kt | 3 + .../gui/api/component/WindowComponent.kt | 69 +++++++++++-------- .../{sub => button}/ButtonComponent.kt | 46 +++++++------ .../gui/api/component/button/ListButton.kt | 21 ++++++ .../api/component/core/list/ChildComponent.kt | 18 +++-- .../component/core/list/IChildComponent.kt | 7 -- .../api/component/core/list/IListComponent.kt | 10 ++- .../com/lambda/gui/api/layer/LayerEntry.kt | 23 +++++++ .../com/lambda/gui/api/layer/RenderLayer.kt | 12 ++-- .../gui/impl/clickgui/AbstractClickGui.kt | 66 ++++++++++++++++++ .../gui/impl/clickgui/GuiConfigurable.kt | 19 ++++- .../gui/impl/clickgui/LambdaClickGui.kt | 31 +++++++-- .../gui/impl/clickgui/buttons/ModuleButton.kt | 21 +++--- .../gui/impl/clickgui/windows/ModuleWindow.kt | 25 +++++++ .../gui/impl/clickgui/windows/TagWindow.kt | 41 ----------- .../clickgui/windows/tag/CustomTagWindow.kt | 39 +++++++++++ .../impl/clickgui/windows/tag/TagWindow.kt | 19 +++++ .../main/kotlin/com/lambda/module/Module.kt | 8 +-- .../lambda/module/modules/client/ClickGui.kt | 4 ++ .../lambda/module/modules/player/Freecam.kt | 1 - 24 files changed, 409 insertions(+), 158 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt rename common/src/main/kotlin/com/lambda/gui/api/component/{sub => button}/ButtonComponent.kt (77%) create mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt delete mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt delete mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt diff --git a/common/src/main/kotlin/com/lambda/Lambda.kt b/common/src/main/kotlin/com/lambda/Lambda.kt index 3a861bd35..5737c14ec 100644 --- a/common/src/main/kotlin/com/lambda/Lambda.kt +++ b/common/src/main/kotlin/com/lambda/Lambda.kt @@ -3,10 +3,12 @@ package com.lambda import com.google.gson.Gson import com.google.gson.GsonBuilder import com.lambda.config.serializer.* +import com.lambda.config.serializer.gui.CustomTagWindowSerializer import com.lambda.config.serializer.gui.ModuleTagSerializer import com.lambda.config.serializer.gui.TagWindowSerializer import com.lambda.core.Loader -import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.KeyCode import net.minecraft.block.Block @@ -27,6 +29,7 @@ object Lambda { val gson: Gson = GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(ModuleTag::class.java, ModuleTagSerializer) + .registerTypeAdapter(CustomTagWindow::class.java, CustomTagWindowSerializer) .registerTypeAdapter(TagWindow::class.java, TagWindowSerializer) .registerTypeAdapter(KeyCode::class.java, KeyCodeSerializer) .registerTypeAdapter(Color::class.java, ColorSerializer) diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt new file mode 100644 index 000000000..a62209659 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt @@ -0,0 +1,54 @@ +package com.lambda.config.serializer.gui + +import com.google.gson.* +import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.Vec2d +import java.lang.reflect.Type + +object CustomTagWindowSerializer : JsonSerializer, JsonDeserializer { + override fun serialize( + src: CustomTagWindow?, + typeOfSrc: Type?, + context: JsonSerializationContext?, + ): JsonElement = src?.let { + JsonObject().apply { + addProperty("title", it.title) + add("tags", JsonArray().apply { + it.tags.forEach { + add(it.name) + } + }) + addProperty("width", it.width) + addProperty("height", it.height) + addProperty("isOpen", it.isOpen) + add("position", JsonArray().apply { + add(it.position.x) + add(it.position.y) + }) + } + } ?: JsonNull.INSTANCE + + override fun deserialize( + json: JsonElement?, + typeOfT: Type?, + context: JsonDeserializationContext?, + ) = json?.asJsonObject?.let { + CustomTagWindow( + it["title"].asString, + it["tags"].asJsonArray.map { tag -> + ModuleTag(tag.asString) + }.toSet(), + LambdaClickGui + ).apply { + width = it["width"].asDouble + height = it["height"].asDouble + isOpen = it["isOpen"].asBoolean + position = Vec2d( + it["position"].asJsonArray[0].asDouble, + it["position"].asJsonArray[1].asDouble + ) + } + } ?: throw JsonParseException("Invalid window data") +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt index 337e34474..b37090db2 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt @@ -1,7 +1,9 @@ package com.lambda.config.serializer.gui import com.google.gson.* -import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d import java.lang.reflect.Type @@ -13,12 +15,7 @@ object TagWindowSerializer : JsonSerializer, JsonDeserializer - add(tag.name) - } - }) + addProperty("tag", it.tag.name) addProperty("width", it.width) addProperty("height", it.height) addProperty("isOpen", it.isOpen) @@ -33,15 +30,10 @@ object TagWindowSerializer : JsonSerializer, JsonDeserializer - ModuleTag(tag.asString) - }.toSet(), - title = it["title"].asString, - width = it["width"].asDouble, + ) = json?.asJsonObject?.let { + TagWindow(ModuleTag(it["tag"].asString), LambdaClickGui).apply { + width = it["width"].asDouble height = it["height"].asDouble - ).apply { isOpen = it["isOpen"].asBoolean position = Vec2d( it["position"].asJsonArray[0].asDouble, diff --git a/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt b/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt index 6afd4908f..5a23d10f3 100644 --- a/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt +++ b/common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt @@ -33,6 +33,9 @@ class Animation(initialValue: Double, val update: (Double) -> Double) { fun AnimationTicker.exp(min: Double, max: Double, speed: Double, flag: () -> Boolean) = exp({ min }, { max }, { speed }, flag) + fun AnimationTicker.exp(target: () -> Double, speed: Double) = + exp(target, target, { speed }, { true }) + @Suppress("NAME_SHADOWING") fun AnimationTicker.exp(min: () -> Double, max: () -> Double, speed: () -> Double, flag: () -> Boolean) = Animation(min()) { diff --git a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt index 1131da747..ccf69ac78 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt @@ -5,6 +5,7 @@ import com.lambda.event.EventFlow.syncListeners import com.lambda.event.events.RenderEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.UnsafeListener +import com.lambda.graphics.animation.AnimationTicker import com.lambda.gui.api.component.core.IComponent import com.lambda.module.Module import com.lambda.util.KeyCode @@ -22,6 +23,7 @@ abstract class LambdaGui( private val owner: Module? = null ) : Screen(Text.of(name)), IComponent, Nameable { private var screenSize = Vec2d.ZERO + val animation = AnimationTicker() private val renderListener = UnsafeListener(0, this, false) { event -> event as RenderEvent.GUI.Scaled @@ -30,6 +32,7 @@ abstract class LambdaGui( } private val tickListener = UnsafeListener(0, this, false) { + animation.tick() onTick() } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index f6e13ced9..ef4ad988b 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -1,23 +1,28 @@ package com.lambda.gui.api.component import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.graphics.animation.AnimationTicker import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry -import com.lambda.gui.api.component.core.IComponent import com.lambda.gui.api.component.core.list.IListComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.layer.RenderLayer +import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.module.modules.client.ClickGui import com.lambda.module.modules.client.GuiSettings import com.lambda.util.KeyCode import com.lambda.util.Mouse +import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d +import java.awt.Color import kotlin.math.abs -abstract class WindowComponent : InteractiveComponent(), IListComponent { +abstract class WindowComponent ( + final override val owner: AbstractClickGui +) : ChildComponent(), IListComponent { abstract val title: String abstract var width: Double @@ -37,35 +42,41 @@ abstract class WindowComponent : InteractiveComponent(), IL private val titleFont: IFontEntry private val layer = RenderLayer() - private val animation = AnimationTicker() + private val renderer = layer.entry() + val subLayer = RenderLayer() - override val children = mutableListOf() - val subLayer = RenderLayer(true) + val animation = owner.animation + val guiAnimation get() = owner.guiAnimation private val actualHeight get() = height + padding * 2 * isOpen.toInt() - private var renderHeight by animation.exp({ 0.0 }, ::actualHeight, 0.5, ::isOpen) + private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) + private val renderHeight get() = lerp(0.0, renderHeightAnimation, guiAnimation) + + override val children = mutableListOf() init { // Background - layer.rect.build { + renderer.rect { position = rect roundRadius = ClickGui.windowRadius - color(GuiSettings.backgroundColor) + + val alpha = (guiAnimation * 2.0).coerceIn(0.0, 1.0) + color(GuiSettings.backgroundColor.multAlpha(alpha)) } // Title - titleFont = layer.font.build { + titleFont = renderer.font { text = title position = titleBar.center - widthVec * 0.5 + color = Color.WHITE.setAlpha(guiAnimation) } } override fun onShow() { - super.onShow() + super.onShow() super.onShow() dragOffset = null - renderHeight = 0.0 } override fun onHide() { @@ -73,33 +84,33 @@ abstract class WindowComponent : InteractiveComponent(), IL } override fun onTick() { - animation.tick() - - setChildrenAccessibility { child -> - child.rect in contentRect + children.forEach { child -> + child.accessible = child.rect in contentRect && this.accessible } - children - .filter(ChildComponent::accessible) - .forEach(IComponent::onTick) + super.onTick() } override fun onRender() { layer.render() scissor(contentRect) { - subLayer.render() + subLayer.apply { + allowEffects = true + render() + } + super.onRender() } } override fun onMouseMove(mouse: Vec2d) { - super.onMouseMove(mouse) - super.onMouseMove(mouse) - dragOffset?.let { position = mouse - it } + + super.onMouseMove(mouse) + super.onMouseMove(mouse) } override fun onKey(key: KeyCode) { @@ -111,7 +122,7 @@ abstract class WindowComponent : InteractiveComponent(), IL } override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - super.onMouseClick(button, action, mouse) + super.onMouseClick(button, action, mouse) dragOffset = null @@ -124,6 +135,8 @@ abstract class WindowComponent : InteractiveComponent(), IL if (abs(targetHeight - renderHeight) > 1) return isOpen = !isOpen + + if (isOpen) super.onShow() } } } @@ -131,9 +144,9 @@ abstract class WindowComponent : InteractiveComponent(), IL super.onMouseClick(button, action, mouse) } - private fun setChildrenAccessibility(flag: (T) -> Boolean) { - children.forEach { child -> - child.accessible = flag(child) - } + fun destroy() { + layer.destroy() + subLayer.destroy() + children.clear() } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/sub/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt similarity index 77% rename from common/src/main/kotlin/com/lambda/gui/api/component/sub/ButtonComponent.kt rename to common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 4e1265ead..86efc0c6b 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/sub/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -1,7 +1,6 @@ -package com.lambda.gui.api.component.sub +package com.lambda.gui.api.component.button import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.graphics.animation.AnimationTicker import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.module.modules.client.ClickGui @@ -9,7 +8,6 @@ import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp -import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d import java.awt.Color @@ -20,19 +18,23 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C abstract val size: Vec2d abstract val text: String - open val active get() = pressed + abstract val active: Boolean private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.contentRect.size.x else size.x, size.y) final override val rect get() = Rect.basedOn(position, actualSize) + owner.contentRect.leftTop private val layer = owner.subLayer - private val animation = AnimationTicker() + private val renderer = layer.entry() + protected val animation = owner.animation - private var activeAnimation by animation.exp(0.0, 1.0, 0.1, ::active) - private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.5 else 0.1 }, ::renderHovered) + private var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::active) + private var toggleFxDirection by animation.exp(0.0, 1.0, 0.6, ::active) + private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.6 else 0.07 }, ::renderHovered) private var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) private val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 + private val showAnimationRaw by animation.exp(0.0, 1.0, 0.7, owner::isOpen) + private val showAnimation get() = lerp(0.0, showAnimationRaw, owner.guiAnimation) private var lastHoveredTime = 0L private val renderHovered get() = hovered || @@ -40,22 +42,22 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C init { // Active color - layer.rect.build { + renderer.rect { position = rect.shrink(interactAnimation) - color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.2)) + color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.3 * showAnimation)) } // Hover glint - layer.rect.build { + renderer.rect { val hoverRect = Rect.basedOn(rect.leftTop, rect.size.x * hoverRectAnimation, rect.size.y) position = hoverRect.shrink(interactAnimation) - val alpha = interactAnimation * 0.3 + val alpha = interactAnimation * 0.2 color(GuiSettings.mainColor.multAlpha(alpha)) } // Toggle fx - layer.rect.build { + renderer.rect { val left = rect - Vec2d(rect.size.x, 0.0) val right = rect + Vec2d(rect.size.x, 0.0) @@ -65,23 +67,23 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C // 0.0 .. 1.0 .. 0.0 animation val alpha = 1.0 - (abs(activeAnimation - 0.5) * 2.0) - val color = GuiSettings.mainColor.multAlpha(alpha * 0.8) + val color = GuiSettings.mainColor.multAlpha(alpha * 0.6 * showAnimation) // "Tail" effect - val leftColor = color.multAlpha(1.0 - active.toInt()) - val rightColor = color.multAlpha(active.toInt().toDouble()) + val leftColor = color.multAlpha(1.0 - toggleFxDirection) + val rightColor = color.multAlpha(toggleFxDirection) colorH(leftColor, rightColor) } // Text - layer.font.build { + renderer.font { text = this@ButtonComponent.text scale = 1.0 - pressAnimation * 0.08 - color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation) + color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation).multAlpha(showAnimation) - val x = rect.left + ClickGui.windowPadding + interactAnimation + hoverFontAnimation * 2.0 + val x = rect.left + ClickGui.windowPadding + interactAnimation + hoverFontAnimation position = Vec2d(x, rect.center.y) } } @@ -98,10 +100,6 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C reset() } - override fun onTick() { - animation.tick() - } - override fun onRelease() { if (hovered) activeMouseButton?.let(::performClickAction) } @@ -113,6 +111,10 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C if (hovered) lastHoveredTime = time } + override fun onRemove() { + renderer.destroy() + } + private fun reset() { activeAnimation = 0.0 hoverRectAnimation = 0.0 diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt new file mode 100644 index 000000000..36cccd6d2 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -0,0 +1,21 @@ +package com.lambda.gui.api.component.button + +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.component.WindowComponent +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.math.MathUtils.toInt +import com.lambda.util.math.Vec2d + +abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { + override val position get() = Vec2d(0.0, renderHeightOffset) + override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) + + var heightOffset = 0.0 + private val targetHeightOffset get() = heightOffset * owner.guiAnimation * owner.isOpen.toInt() + private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.5) + + override fun onShow() { + super.onShow() + renderHeightOffset = 0.0 + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index c8209122f..fcc06bc12 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -1,14 +1,18 @@ package com.lambda.gui.api.component.core.list import com.lambda.gui.api.component.InteractiveComponent +import com.lambda.gui.api.component.core.IComponent +import com.lambda.util.math.Vec2d -abstract class ChildComponent : InteractiveComponent(), IChildComponent { - // mostly used to create an animation when an element appears - var accessible = false; set(value) { - if (field == value) return - field = value +abstract class ChildComponent : InteractiveComponent() { + abstract val owner: IComponent + open var accessible = false - if (value) onShow() - else onHide() + override fun onMouseMove(mouse: Vec2d) { + super.onMouseMove(mouse) + hovered = hovered && accessible } + + open fun onAdd() {} + open fun onRemove() {} } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt deleted file mode 100644 index 353ab501f..000000000 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IChildComponent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.lambda.gui.api.component.core.list - -import com.lambda.gui.api.component.core.IComponent - -interface IChildComponent { - val owner: IComponent -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt index 303ea9ff5..bf7e6ba3d 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt @@ -39,17 +39,15 @@ interface IListComponent : IComponent { } override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - children.filter(::isChildAccessible).forEach { child -> - child.onMouseClick(button, action, mouse) + children.forEach { child -> + val newAction = if (isChildAccessible(child)) action else Mouse.Action.Release + child.onMouseClick(button, newAction, mouse) } } override fun onMouseMove(mouse: Vec2d) { children.forEach { child -> - child.onMouseMove( - if (isChildAccessible(child)) mouse - else Vec2d(-1000.0, -1000.0) // junky but worky way to unfocus - ) + child.onMouseMove(mouse) } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt new file mode 100644 index 000000000..67c172a7c --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt @@ -0,0 +1,23 @@ +package com.lambda.gui.api.layer + +import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.graphics.renderer.IRenderer +import com.lambda.graphics.renderer.gui.font.IFontEntry +import com.lambda.graphics.renderer.gui.rect.IRectEntry + +// Used to group all render entries related to a component +class LayerEntry ( + private val rect: IRenderer, + private val font: IRenderer +) { + private val entries = mutableSetOf>() + + fun rect(block: IRectEntry.() -> Unit) = + rect.build(block).apply(entries::add) + + fun font(block: IFontEntry.() -> Unit) = + font.build(block).apply(entries::add) + + fun destroy() = + entries.forEach(IRenderEntry<*>::destroy) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt index fe871fc28..97762b0f5 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt @@ -4,17 +4,19 @@ import com.lambda.graphics.renderer.gui.font.FontRenderer import com.lambda.graphics.renderer.gui.rect.RectRenderer import com.lambda.module.modules.client.GuiSettings -class RenderLayer(private val allowEffects: Boolean = false) { - private val rectRenderer = RectRenderer() +class RenderLayer { + var allowEffects = false - val rect = rectRenderer.asRenderer - val font = FontRenderer().asRenderer + private val rect = RectRenderer() + private val font = FontRenderer() + + fun entry() = LayerEntry(rect, font) fun render() { rect.update() font.update() - rectRenderer.apply { + rect.apply { shadeColor = GuiSettings.shade && allowEffects fancyBlending = GuiSettings.glow && allowEffects render() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt new file mode 100644 index 000000000..2f2a1e5b5 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -0,0 +1,66 @@ +package com.lambda.gui.impl.clickgui + +import com.lambda.Lambda.mc +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.LambdaGui +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.api.component.core.list.ChildComponent +import com.lambda.gui.api.component.core.list.IListComponent +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.Mouse +import com.lambda.util.math.Vec2d + +abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui), IListComponent { + override val children = mutableListOf() + protected var hoveredChild: ChildComponent? = null + + private var closing = false + var guiAnimation by animation.exp(0.0, 1.0, { + if (closing) ClickGui.closeSpeed else ClickGui.openSpeed + }) { !closing }; private set + + override fun onShow() { + super.onShow() + hoveredChild = null + closing = false + guiAnimation = 0.0 + } + + override fun onTick() { + super.onTick() + if (closing && guiAnimation < 0.01) mc.setScreen(null) + } + + override fun onRender() { + super.onRender() + + // only one window can be hovered at the same time + children.forEach { + it.accessible = false + } + + if (!closing) hoveredChild?.accessible = true + } + + override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { + // move hovered window into foreground + (hoveredChild as? WindowComponent<*>)?.let { + children.remove(it) + children.add(it) + } + + super.onMouseClick(button, action, mouse) + } + + override fun onMouseMove(mouse: Vec2d) { + hoveredChild = children.lastOrNull { child -> + mouse in child.rect + } + + super.onMouseMove(mouse) + } + + override fun close() { + closing = true + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt index 4f88a9cf9..c11d88e5a 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt @@ -2,17 +2,30 @@ package com.lambda.gui.impl.clickgui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig -import com.lambda.gui.impl.clickgui.windows.TagWindow +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d object GuiConfigurable : Configurable(GuiConfig) { override val name = "gui" - val windows = setting("windows", defaultWindows) + + val mainWindows by setting("windows", defaultWindows).apply { + listener { from, _ -> + from.forEach(WindowComponent<*>::destroy) // free vram + } + } + + val customWindows by setting("custom windows", listOf()).apply { + listener { from, _ -> + from.forEach(WindowComponent<*>::destroy) // free vram + } + } private val defaultWindows get() = ModuleTag.defaults.mapIndexed { index, tag -> - TagWindow(setOf(tag), tag.name).apply { + TagWindow(tag, LambdaClickGui).apply { val step = 3.0 position = Vec2d((width + step) * index, 0.0) + step } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index b24ccf7a0..f8d806bc9 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -1,10 +1,29 @@ package com.lambda.gui.impl.clickgui -import com.lambda.gui.api.LambdaGui -import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.core.list.IListComponent -import com.lambda.module.modules.client.ClickGui +import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow -object LambdaClickGui : LambdaGui("ClickGui", ClickGui), IListComponent> { - override val children: List> get() = GuiConfigurable.windows.value +object LambdaClickGui : AbstractClickGui() { + override fun onShow() { + updateWindows() + super.onShow() + } + + override fun onTick() { + updateWindows() + super.onTick() + } + + private fun updateWindows() { + val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows + val new = windows.subtract(children) + children.addAll(new) + + children.removeIf { + if (it !is CustomTagWindow) return@removeIf false + + val flag = it !in windows + if (flag) it.destroy() + flag + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 3649b06ec..6d5bb93af 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,20 +1,13 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.sub.ButtonComponent +import com.lambda.gui.api.component.button.ListButton import com.lambda.module.Module -import com.lambda.module.modules.client.ClickGui import com.lambda.util.Mouse -import com.lambda.util.math.Vec2d -class ModuleButton(val module: Module, owner: WindowComponent<*>) : ButtonComponent(owner) { - override val position get() = Vec2d(0.0, heightOffset) - override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) - - override val text: String get() = module.name - override val active: Boolean get() = module.isEnabled - - var heightOffset = 0.0 +class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(owner) { + override val text get() = module.name + override val active get() = module.isEnabled override fun performClickAction(mouse: Mouse.Button) { when (mouse) { @@ -24,4 +17,10 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ButtonCompon } } } + + override fun equals(other: Any?) = + (other as? ModuleButton)?.module == module + + override fun hashCode() = + module.hashCode() } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt new file mode 100644 index 000000000..7f31faaf2 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt @@ -0,0 +1,25 @@ +package com.lambda.gui.impl.clickgui.windows + +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.module.modules.client.ClickGui + +abstract class ModuleWindow( + override var title: String, + override var width: Double = 110.0, + override var height: Double = 300.0, + owner: AbstractClickGui +) : WindowComponent(owner) { + override fun onTick() { + children.sortBy { + it.module.name + } + + children.forEachIndexed { i, button -> + button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) + } + + super.onTick() + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt deleted file mode 100644 index 9beef6a56..000000000 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/TagWindow.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.lambda.gui.impl.clickgui.windows - -import com.lambda.gui.api.LambdaGui -import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.core.list.IChildComponent -import com.lambda.gui.impl.clickgui.LambdaClickGui -import com.lambda.gui.impl.clickgui.buttons.ModuleButton -import com.lambda.module.ModuleRegistry -import com.lambda.module.modules.client.ClickGui -import com.lambda.module.tag.ModuleTag - -class TagWindow( - val tags: Set = setOf(), - override var title: String = "Untitled", - override var width: Double = 110.0, - override var height: Double = 300.0, - override val owner: LambdaGui = LambdaClickGui -) : WindowComponent(), IChildComponent { - init { - ModuleRegistry.modules.filter { module -> - module.tags.any(tags::contains) - }.forEach { - children.add(ModuleButton(it, this)) - } - } - - override fun onRender() { - updateModules() - super.onRender() - } - - private fun updateModules() { - children.sortBy { it.module.name } - - // ToDo: Update tag filter - - children.forEachIndexed { i, button -> - button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) - } - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt new file mode 100644 index 000000000..ca980e608 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt @@ -0,0 +1,39 @@ +package com.lambda.gui.impl.clickgui.windows.tag + +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.module.ModuleRegistry +import com.lambda.module.tag.ModuleTag + +class CustomTagWindow( + title: String = "Untitled", + val tags: Set, + owner: AbstractClickGui +) : ModuleWindow(title, owner = owner) { + override fun onTick() { + updateModules() + super.onTick() + } + + private fun updateModules() { + // TODO: Modules in windows > tags in modules + // Get needed modules + val modules = ModuleRegistry.modules + .filter { it.customTags.any(tags::contains) } + + // Add missing module buttons + modules.filter { module -> + children.all { button -> + button.module != module + } + }.map { ModuleButton(it, this) }.forEach(children::add) + + // Remove deleted modules + children.removeIf { + val flag = it.module !in modules + if (flag) it.onRemove() + flag + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt new file mode 100644 index 000000000..835c4cdf8 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt @@ -0,0 +1,19 @@ +package com.lambda.gui.impl.clickgui.windows.tag + +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.module.ModuleRegistry +import com.lambda.module.tag.ModuleTag + +class TagWindow( + val tag: ModuleTag, + owner: AbstractClickGui +) : ModuleWindow(tag.name, owner = owner) { + init { + ModuleRegistry.modules + .filter { it.tag == tag } + .map { ModuleButton(it, this) } + .forEach(children::add) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 62c583acf..27d90dbc5 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -80,7 +80,7 @@ import com.lambda.util.Nameable * @property description The description of the module, * shown on hover over the module button in the GUI and in commands. * @property tag The leading module tag associated with the module. - * @property extraTags The set of extra [ModuleTag]s associated with the module. + * @property extraTags The set of extra, basically user-defined [ModuleTag]s associated with the module. * @property alwaysListening If true, the module's listeners will be triggered even if the module is not enabled. * @property isEnabledSetting The setting that determines if the module is enabled. * @property keybindSetting The setting that determines the keybind for the module. @@ -92,7 +92,7 @@ abstract class Module( override val name: String, val description: String = "", val tag: ModuleTag, - val extraTags: Set = setOf(), + extraTags: Set = setOf(), private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.Unbound, @@ -100,9 +100,7 @@ abstract class Module( private val isEnabledSetting = setting("Enabled", enabledByDefault, visibility = { false }) private val keybindSetting = setting("Keybind", defaultKeybind) private val isVisible = setting("Visible", true) - private val customTags by setting("Tags", extraTags, visibility = { false }) - - val tags get() = customTags + tag + val customTags by setting("Tags", extraTags, visibility = { false }) var isEnabled by isEnabledSetting override val isMuted: Boolean diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt index f3f1402ae..fcb58ade0 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt @@ -19,6 +19,10 @@ object ClickGui : Module( val buttonHeight by setting("Button Height", 11.0, 8.0..20.0, 0.1) val buttonStep by setting("Button Step", 1.0, 0.0..5.0, 0.1) + // Animation + val openSpeed by setting("Open Speed", 0.6, 0.1..1.0, 0.01) + val closeSpeed by setting("Close Speed", 0.7, 0.1..1.0, 0.01) + init { onEnable { if (mc.currentScreen != LambdaClickGui) { diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 4bf7ec477..07ed20cb8 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -14,7 +14,6 @@ import com.lambda.interaction.rotation.RotationContext import com.lambda.interaction.rotation.RotationMode import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.KeyCode import com.lambda.util.player.MovementUtils.cancel import com.lambda.util.player.MovementUtils.verticalMovement import com.lambda.util.primitives.extension.interpolate From 3e4a9c82b37ab223033eb67d4cbb2d5cb6ab561c Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 19 Apr 2024 14:05:26 +0300 Subject: [PATCH 12/63] Raw CustomModuleWindow impl --- common/src/main/kotlin/com/lambda/Lambda.kt | 6 +++--- ...zer.kt => CustomModuleWindowSerializer.kt} | 21 +++++++++++-------- .../src/main/kotlin/com/lambda/core/Loader.kt | 4 +--- .../{impl/clickgui => }/GuiConfigurable.kt | 7 ++++--- .../gui/impl/clickgui/LambdaClickGui.kt | 5 +++-- ...stomTagWindow.kt => CustomModuleWindow.kt} | 12 ++++------- .../main/kotlin/com/lambda/module/Module.kt | 3 --- 7 files changed, 27 insertions(+), 31 deletions(-) rename common/src/main/kotlin/com/lambda/config/serializer/gui/{CustomTagWindowSerializer.kt => CustomModuleWindowSerializer.kt} (70%) rename common/src/main/kotlin/com/lambda/gui/{impl/clickgui => }/GuiConfigurable.kt (85%) rename common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/{CustomTagWindow.kt => CustomModuleWindow.kt} (76%) diff --git a/common/src/main/kotlin/com/lambda/Lambda.kt b/common/src/main/kotlin/com/lambda/Lambda.kt index 5737c14ec..1990b8ab3 100644 --- a/common/src/main/kotlin/com/lambda/Lambda.kt +++ b/common/src/main/kotlin/com/lambda/Lambda.kt @@ -3,11 +3,11 @@ package com.lambda import com.google.gson.Gson import com.google.gson.GsonBuilder import com.lambda.config.serializer.* -import com.lambda.config.serializer.gui.CustomTagWindowSerializer +import com.lambda.config.serializer.gui.CustomModuleWindowSerializer import com.lambda.config.serializer.gui.ModuleTagSerializer import com.lambda.config.serializer.gui.TagWindowSerializer import com.lambda.core.Loader -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.KeyCode @@ -29,7 +29,7 @@ object Lambda { val gson: Gson = GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(ModuleTag::class.java, ModuleTagSerializer) - .registerTypeAdapter(CustomTagWindow::class.java, CustomTagWindowSerializer) + .registerTypeAdapter(CustomModuleWindow::class.java, CustomModuleWindowSerializer) .registerTypeAdapter(TagWindow::class.java, TagWindowSerializer) .registerTypeAdapter(KeyCode::class.java, KeyCodeSerializer) .registerTypeAdapter(Color::class.java, ColorSerializer) diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt similarity index 70% rename from common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt rename to common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt index a62209659..4e7c8274f 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomTagWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt @@ -2,21 +2,22 @@ package com.lambda.config.serializer.gui import com.google.gson.* import com.lambda.gui.impl.clickgui.LambdaClickGui -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow +import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d import java.lang.reflect.Type -object CustomTagWindowSerializer : JsonSerializer, JsonDeserializer { +object CustomModuleWindowSerializer : JsonSerializer, JsonDeserializer { override fun serialize( - src: CustomTagWindow?, + src: CustomModuleWindow?, typeOfSrc: Type?, context: JsonSerializationContext?, ): JsonElement = src?.let { JsonObject().apply { addProperty("title", it.title) - add("tags", JsonArray().apply { - it.tags.forEach { + add("modules", JsonArray().apply { + it.modules.forEach { add(it.name) } }) @@ -35,11 +36,13 @@ object CustomTagWindowSerializer : JsonSerializer, JsonDeserial typeOfT: Type?, context: JsonDeserializationContext?, ) = json?.asJsonObject?.let { - CustomTagWindow( + CustomModuleWindow( it["title"].asString, - it["tags"].asJsonArray.map { tag -> - ModuleTag(tag.asString) - }.toSet(), + it["modules"].asJsonArray.mapNotNull { name -> + ModuleRegistry.modules.firstOrNull { module -> + module.name == name.asString + } + } as MutableList, LambdaClickGui ).apply { width = it["width"].asDouble diff --git a/common/src/main/kotlin/com/lambda/core/Loader.kt b/common/src/main/kotlin/com/lambda/core/Loader.kt index ff7ab72ef..3c035b4eb 100644 --- a/common/src/main/kotlin/com/lambda/core/Loader.kt +++ b/common/src/main/kotlin/com/lambda/core/Loader.kt @@ -3,10 +3,8 @@ package com.lambda.core import com.lambda.Lambda import com.lambda.Lambda.LOG import com.lambda.command.CommandManager -import com.lambda.config.configurations.GuiConfig import com.lambda.graphics.renderer.gui.font.LambdaFont -import com.lambda.gui.impl.clickgui.GuiConfigurable -import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.GuiConfigurable import com.lambda.interaction.PlayerPacketManager import com.lambda.interaction.RotationManager import com.lambda.module.ModuleRegistry diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt similarity index 85% rename from common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt rename to common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index c11d88e5a..9253bd6ab 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -1,9 +1,10 @@ -package com.lambda.gui.impl.clickgui +package com.lambda.gui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.impl.clickgui.LambdaClickGui +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d @@ -17,7 +18,7 @@ object GuiConfigurable : Configurable(GuiConfig) { } } - val customWindows by setting("custom windows", listOf()).apply { + val customWindows by setting("custom windows", listOf()).apply { listener { from, _ -> from.forEach(WindowComponent<*>::destroy) // free vram } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index f8d806bc9..09e336b0b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -1,6 +1,7 @@ package com.lambda.gui.impl.clickgui -import com.lambda.gui.impl.clickgui.windows.tag.CustomTagWindow +import com.lambda.gui.GuiConfigurable +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow object LambdaClickGui : AbstractClickGui() { override fun onShow() { @@ -19,7 +20,7 @@ object LambdaClickGui : AbstractClickGui() { children.addAll(new) children.removeIf { - if (it !is CustomTagWindow) return@removeIf false + if (it !is CustomModuleWindow) return@removeIf false val flag = it !in windows if (flag) it.destroy() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt similarity index 76% rename from common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt rename to common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index ca980e608..5cd1bbe9b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomTagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -3,12 +3,13 @@ package com.lambda.gui.impl.clickgui.windows.tag import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow +import com.lambda.module.Module import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag -class CustomTagWindow( - title: String = "Untitled", - val tags: Set, +class CustomModuleWindow( + override var title: String = "Untitled", + val modules: MutableList = mutableListOf(), owner: AbstractClickGui ) : ModuleWindow(title, owner = owner) { override fun onTick() { @@ -17,11 +18,6 @@ class CustomTagWindow( } private fun updateModules() { - // TODO: Modules in windows > tags in modules - // Get needed modules - val modules = ModuleRegistry.modules - .filter { it.customTags.any(tags::contains) } - // Add missing module buttons modules.filter { module -> children.all { button -> diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 27d90dbc5..07cd8cf37 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -80,7 +80,6 @@ import com.lambda.util.Nameable * @property description The description of the module, * shown on hover over the module button in the GUI and in commands. * @property tag The leading module tag associated with the module. - * @property extraTags The set of extra, basically user-defined [ModuleTag]s associated with the module. * @property alwaysListening If true, the module's listeners will be triggered even if the module is not enabled. * @property isEnabledSetting The setting that determines if the module is enabled. * @property keybindSetting The setting that determines the keybind for the module. @@ -92,7 +91,6 @@ abstract class Module( override val name: String, val description: String = "", val tag: ModuleTag, - extraTags: Set = setOf(), private val alwaysListening: Boolean = false, enabledByDefault: Boolean = false, defaultKeybind: KeyCode = KeyCode.Unbound, @@ -100,7 +98,6 @@ abstract class Module( private val isEnabledSetting = setting("Enabled", enabledByDefault, visibility = { false }) private val keybindSetting = setting("Keybind", defaultKeybind) private val isVisible = setting("Visible", true) - val customTags by setting("Tags", extraTags, visibility = { false }) var isEnabled by isEnabledSetting override val isMuted: Boolean From 1aebc8351050e5527e0747074be401be25865d6e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 21 Apr 2024 20:29:21 +0300 Subject: [PATCH 13/63] Broken blur --- .../com/lambda/event/events/RenderEvent.kt | 4 +- .../kotlin/com/lambda/graphics/RenderMain.kt | 4 ++ .../buffer/vao/vertex/VertexAttrib.kt | 3 +- .../renderer/immediate/BlurPostProcessor.kt | 53 +++++++++++++++++++ .../gui/api/component/WindowComponent.kt | 2 + .../lambda/shaders/fragment/post/blur.frag | 22 ++++++++ .../lambda/shaders/vertex/post/blur.vert | 14 +++++ 7 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt create mode 100644 common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert diff --git a/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt b/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt index 178163df5..d222a7caa 100644 --- a/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt +++ b/common/src/main/kotlin/com/lambda/event/events/RenderEvent.kt @@ -9,11 +9,11 @@ import com.lambda.util.math.Vec2d abstract class RenderEvent : Event { class World : RenderEvent() - abstract class GUI(val scaleFactor: Double) : RenderEvent() { + abstract class GUI(val scale: Double) : RenderEvent() { class Scaled(scaleFactor: Double) : GUI(scaleFactor) class Fixed : GUI(1.0) - val screenSize = Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) / scaleFactor + val screenSize = Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) / scale } class UpdateTarget : RenderEvent(), ICancellable by Cancellable() } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index c3a935af3..c00013cb0 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -8,12 +8,15 @@ import com.lambda.graphics.gl.Matrices import com.lambda.graphics.gl.Matrices.resetMatrix import com.lambda.graphics.gl.Matrices.translate import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.math.Vec2d import org.joml.Matrix4f object RenderMain { val projectionMatrix = Matrix4f() val modelViewMatrix: Matrix4f get() = Matrices.stack.peek().positionMatrix + var screenSize = Vec2d.ZERO + @JvmStatic fun render2D() { resetMatrix() @@ -35,6 +38,7 @@ object RenderMain { val scaledWidth = width / factor val scaledHeight = height / factor + screenSize = Vec2d(scaledWidth, scaledHeight) projectionMatrix.setOrtho(0f, scaledWidth.toFloat(), scaledHeight.toFloat(), 0f, 1000f, 21000f) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt index 8085a20c4..547050b89 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt @@ -12,7 +12,8 @@ enum class VertexAttrib(val componentCount: Int, componentSize: Int, val normali enum class Group(vararg val attributes: VertexAttrib) { FONT(Vec2, Vec2, Color), - RECT(Vec2, Vec2, Vec3, Color); + RECT(Vec2, Vec2, Vec3, Color), + BLUR(Vec2, Vec2); val stride = attributes.sumOf { attribute -> attribute.size } } diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt new file mode 100644 index 000000000..0f85814f4 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt @@ -0,0 +1,53 @@ +package com.lambda.graphics.renderer.immediate + +import com.lambda.Lambda.mc +import com.lambda.graphics.RenderMain +import com.lambda.graphics.buffer.vao.VAO +import com.lambda.graphics.buffer.vao.vertex.VertexAttrib +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.shader.Shader +import com.lambda.graphics.texture.TextureUtils.bindTexture +import com.lambda.util.math.Rect +import com.lambda.util.math.Vec2d + +object BlurPostProcessor { + private val vao = VAO(VertexMode.TRIANGLES, VertexAttrib.Group.BLUR) + private val shader = Shader("post/blur") + + + fun render(rect: Rect, level: Int) { + renderPass(rect, Vec2d.RIGHT, level) + renderPass(rect, Vec2d.BOTTOM, level) + } + + private fun renderPass(rect: Rect, direction: Vec2d, level: Int) { + val x1 = rect.leftTop.x + val y1 = rect.leftTop.y + val x2 = rect.rightBottom.x + val y2 = rect.rightBottom.y + + val screen = RenderMain.screenSize + val uv1x = x1 / screen.x + val uv1y = y1 / screen.y + val uv2x = x2 / screen.x + val uv2y = y2 / screen.y + + vao.use { + putQuad( + vec2(x1, y1).vec2(uv1x, 1.0 - uv1y).end(), + vec2(x2, y1).vec2(uv2x, 1.0 - uv1y).end(), + vec2(x2, y2).vec2(uv2x, 1.0 - uv2y).end(), + vec2(x1, y2).vec2(uv1x, 1.0 - uv2y).end() + ) + + shader.use() + shader["u_Direction"] = direction / Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) + shader["u_BlurLevel"] = level + + bindTexture(mc.framebuffer.colorAttachment) + upload() + render() + clear() + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index ef4ad988b..1df7a6296 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -3,6 +3,7 @@ package com.lambda.gui.api.component import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry +import com.lambda.graphics.renderer.immediate.BlurPostProcessor import com.lambda.gui.api.component.core.list.IListComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.layer.RenderLayer @@ -92,6 +93,7 @@ abstract class WindowComponent ( } override fun onRender() { + BlurPostProcessor.render(rect, 30) layer.render() scissor(contentRect) { diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag new file mode 100644 index 000000000..44e33ba14 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag @@ -0,0 +1,22 @@ +#version 330 core + +uniform sampler2D u_Texture; +uniform vec2 u_Direction; + +uniform int u_BlurLevel; + +in vec2 v_TexCoord; +out vec4 color; + +void main() { + vec4 col = texture(u_Texture, v_TexCoord); + int amt = 1; + + for (float i = -u_BlurLevel * 0.5; i < u_BlurLevel * 0.5; ++i) { + vec2 ofs = i * u_Direction; + col += texture(u_Texture, v_TexCoord + ofs); + amt++; + } + + color = col / amt; +} diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert b/common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert new file mode 100644 index 000000000..8280235af --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/post/blur.vert @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec4 pos; +layout (location = 1) in vec2 uv; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +out vec2 v_TexCoord; + +void main() { + gl_Position = u_Projection * u_ModelView * pos; + v_TexCoord = uv; +} \ No newline at end of file From 71dfaabfb6c693fa6d2b8d587daadff13e57b0f9 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 14:32:54 -0400 Subject: [PATCH 14/63] Faster texture upload (up to 20%) --- .../com/lambda/graphics/texture/TextureUtils.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt index 5361b4cc3..57769e7dc 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt @@ -3,7 +3,10 @@ package com.lambda.graphics.texture import com.mojang.blaze3d.systems.RenderSystem import net.minecraft.client.texture.NativeImage import org.lwjgl.BufferUtils +import org.lwjgl.opengl.ARBTextureStorage.glTexStorage2D +import org.lwjgl.opengl.GL11C import org.lwjgl.opengl.GL13C.* +import org.lwjgl.opengl.GL30C.glGenerateMipmap import java.awt.Color import java.awt.Font import java.awt.RenderingHints @@ -24,7 +27,13 @@ object TextureUtils { val width = bufferedImage.width val height = bufferedImage.height - glTexImage2D(GL_TEXTURE_2D, lod, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, readImage(bufferedImage)) + // GL_UNSIGNED_INT_8_8_8_8_REV -> 0xRRGGBBAA + // GL_UNSIGNED_BYTE -> [RR, GG, BB, AA] + // In the end it will be the exact same but in the case that you + // supply the data in the reverse order, GL_UNSIGNED_INT_8_8_8_8_REV + // will swap the bytes for you. + glTexImage2D(GL_TEXTURE_2D, lod, GL_BGRA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0) + glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, readImage(bufferedImage)) setupTexture(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR) } @@ -84,7 +93,7 @@ object TextureUtils { } fun BufferedImage.rescale(targetWidth: Int, targetHeight: Int): BufferedImage { - val type = if (this.transparency == Transparency.OPAQUE) + val type = if (transparency == Transparency.OPAQUE) BufferedImage.TYPE_INT_RGB else BufferedImage.TYPE_INT_ARGB @@ -117,4 +126,4 @@ object TextureUtils { return image } -} \ No newline at end of file +} From 83e53e5e1ed6211a6e6f7854bf3be5c410c26e90 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 16:26:20 -0400 Subject: [PATCH 15/63] Better gaussian blur --- .../gui/api/component/WindowComponent.kt | 4 +-- .../lambda/shaders/fragment/post/blur.frag | 32 +++++++++++++++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 1df7a6296..f714a5293 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -93,7 +93,7 @@ abstract class WindowComponent ( } override fun onRender() { - BlurPostProcessor.render(rect, 30) + BlurPostProcessor.render(rect, 15) // TODO: Customizable blur level layer.render() scissor(contentRect) { @@ -151,4 +151,4 @@ abstract class WindowComponent ( subLayer.destroy() children.clear() } -} \ No newline at end of file +} diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag index 44e33ba14..b5e18b761 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag @@ -1,22 +1,40 @@ #version 330 core +#define pow2(x) (x * x) + uniform sampler2D u_Texture; uniform vec2 u_Direction; - uniform int u_BlurLevel; in vec2 v_TexCoord; out vec4 color; +float gaussian(float x) { + return exp(-pow2(x) / (2.0 * pow2(u_BlurLevel) / (2.50662 * u_BlurLevel))); +} + void main() { vec4 col = texture(u_Texture, v_TexCoord); - int amt = 1; + float totalWeight = 1.0; + + for (int i = -u_BlurLevel; i <= u_BlurLevel; ++i) { + float offset = float(i); + vec2 texOffset = offset * u_Direction; + col += texture(u_Texture, v_TexCoord + texOffset) * gaussian(offset); + totalWeight += gaussian(offset); + } + + // Normalize the color + col /= totalWeight; - for (float i = -u_BlurLevel * 0.5; i < u_BlurLevel * 0.5; ++i) { - vec2 ofs = i * u_Direction; - col += texture(u_Texture, v_TexCoord + ofs); - amt++; + // Vertical blur + totalWeight = 0.0; + for (int i = -u_BlurLevel; i <= u_BlurLevel; ++i) { + float offset = float(i); + vec2 texOffset = offset * u_Direction; + col += texture(u_Texture, v_TexCoord + texOffset) * gaussian(offset); + totalWeight += gaussian(offset); } - color = col / amt; + color = col / totalWeight; } From 77c4bf1e15a9c5f9dbf3a94e9660381fc9d50ce8 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 18:16:41 -0400 Subject: [PATCH 16/63] Fix: Single tag --- .../com/lambda/module/modules/combat/CrystalAura.kt | 2 +- .../lambda/module/modules/{ => debug}/EntityTest.kt | 5 +++-- .../com/lambda/module/modules/player/Freecam.kt | 2 +- .../com/lambda/module/modules/render/FakePlayer.kt | 2 +- .../main/kotlin/com/lambda/module/tag/ModuleTag.kt | 12 ++++++++---- 5 files changed, 14 insertions(+), 9 deletions(-) rename common/src/main/kotlin/com/lambda/module/modules/{ => debug}/EntityTest.kt (82%) diff --git a/common/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt b/common/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt index 3a123265a..552d3d153 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt @@ -20,7 +20,7 @@ import net.minecraft.world.explosion.Explosion object CrystalAura : Module( name = "CrystalAura", description = "Automatically attacks entities with crystals", - defaultTags = setOf(ModuleTag.COMBAT), + tag = ModuleTag.COMBAT, ) { private val page by setting("Page", Page.General) diff --git a/common/src/main/kotlin/com/lambda/module/modules/EntityTest.kt b/common/src/main/kotlin/com/lambda/module/modules/debug/EntityTest.kt similarity index 82% rename from common/src/main/kotlin/com/lambda/module/modules/EntityTest.kt rename to common/src/main/kotlin/com/lambda/module/modules/debug/EntityTest.kt index df224646a..9b97dd622 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/EntityTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/debug/EntityTest.kt @@ -1,15 +1,16 @@ -package com.lambda.module.modules +package com.lambda.module.modules.debug import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listener import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag import com.lambda.util.world.EntityUtils.getClosestEntity import net.minecraft.entity.Entity object EntityTest : Module( name = "EntityTest", description = "Test entity", - defaultTags = setOf() + tag = ModuleTag.DEBUG, ) { init { listener { diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt index 07ed20cb8..72dae3e99 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Freecam.kt @@ -78,7 +78,7 @@ object Freecam : Module( it.context = RotationContext(rotation, rotationConfig) } - listener { + listener { event ->2 // Don't block baritone from working if (event.input !is PlayerMovementInput) { // Reset actual input diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt b/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt index 9d2989c2b..0a824757e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt @@ -10,7 +10,7 @@ import java.util.* object FakePlayer : Module( name = "FakePlayer", description = "Spawns a fake player", - defaultTags = setOf(ModuleTag.MISC, ModuleTag.RENDER) + tag = ModuleTag.MISC ) { private val playerName by setting("Name", "Steve") diff --git a/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt b/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt index a4002c17b..2d186116e 100644 --- a/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt +++ b/common/src/main/kotlin/com/lambda/module/tag/ModuleTag.kt @@ -22,11 +22,15 @@ data class ModuleTag(override val name: String) : Nameable { val RENDER = ModuleTag("Render") val PLAYER = ModuleTag("Player") val WORLD = ModuleTag("World") - val DEBUG = ModuleTag("Debug") + val MISC = ModuleTag("Misc") val CLIENT = ModuleTag("Client") - - val GRIM = ModuleTag("Grim") + val DEBUG = ModuleTag("Debug") val defaults = listOf(COMBAT, MOVEMENT, RENDER, PLAYER, WORLD, DEBUG, CLIENT) + + // Do something with this ? + val HIDDEN = ModuleTag("Hidden") + val GRIM = ModuleTag("Grim") + val BYPASS = ModuleTag("Bypass") } -} \ No newline at end of file +} From fb77000609e97dcaa565b7c0195b6cc9364dba06 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 18:55:56 -0400 Subject: [PATCH 17/63] Make the blur stronger --- .../main/kotlin/com/lambda/gui/api/component/WindowComponent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index f714a5293..64f366179 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -93,7 +93,7 @@ abstract class WindowComponent ( } override fun onRender() { - BlurPostProcessor.render(rect, 15) // TODO: Customizable blur level + BlurPostProcessor.render(rect, 50) // TODO: Customizable blur level layer.render() scissor(contentRect) { From 975e1ec3e980400a6e960578f2b641f9d2e87b38 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 18:56:08 -0400 Subject: [PATCH 18/63] Use our matrix --- .../kotlin/com/lambda/graphics/RenderMain.kt | 4 +- .../kotlin/com/lambda/graphics/gl/Matrices.kt | 79 ++++++++++++++---- .../com/lambda/graphics/gl/MatrixStack.kt | 80 ------------------- 3 files changed, 66 insertions(+), 97 deletions(-) delete mode 100644 common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index c00013cb0..00cdeb3c2 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -13,7 +13,7 @@ import org.joml.Matrix4f object RenderMain { val projectionMatrix = Matrix4f() - val modelViewMatrix: Matrix4f get() = Matrices.stack.peek().positionMatrix + val modelViewMatrix: Matrix4f get() = Matrices.peek().position var screenSize = Vec2d.ZERO @@ -41,4 +41,4 @@ object RenderMain { screenSize = Vec2d(scaledWidth, scaledHeight) projectionMatrix.setOrtho(0f, scaledWidth.toFloat(), scaledHeight.toFloat(), 0f, 1000f, 21000f) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt index fb8235840..33c2ad0f5 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt @@ -1,31 +1,80 @@ package com.lambda.graphics.gl +import org.joml.Matrix3f +import org.joml.Matrix4f +import org.joml.Quaternionf +import java.util.* +import kotlin.math.cbrt + object Matrices { - var stack = MatrixStack() - private val matrix get() = stack.peek().positionMatrix + private val stack: Deque = ArrayDeque( + listOf(Entry(Matrix4f(), Matrix3f())) + ) + + fun translate(x: Double, y: Double, z: Double): Matrix4f = + translate(x.toFloat(), y.toFloat(), z.toFloat()) - fun pushMatrix() { - stack.push() + fun translate(x: Float, y: Float, z: Float): Matrix4f = + stack.last.position.translate(x, y, z) + + fun scale(x: Float, y: Float, z: Float) { + val entry = stack.last + entry.position.scale(x, y, z) + if (x == y && y == z) { + if (x > 0.0f) { + return + } + entry.normal.scale(-1.0f) + } + val f = 1.0f / x + val g = 1.0f / y + val h = 1.0f / z + val i = cbrt(f * g * h) + entry.normal.scale(i * f, i * g, i * h) } - fun popMatrix() { - stack.push() + fun multiply(quaternion: Quaternionf) { + val entry = stack.last + entry.position.rotate(quaternion) + entry.normal.rotate(quaternion) } - fun resetMatrix() { - stack = MatrixStack() + fun multiply(quaternion: Quaternionf, originX: Float, originY: Float, originZ: Float) { + val entry = stack.last + entry.position.rotateAround(quaternion, originX, originY, originZ) + entry.normal.rotate(quaternion) } - fun translate(x: Double, y: Double, z: Double = 0.0) { - matrix.translate(x.toFloat(), y.toFloat(), z.toFloat()) + fun push() { + val entry = stack.last + stack.addLast(Entry(Matrix4f(entry.position), Matrix3f(entry.normal))) } - fun scale(x: Double, y: Double, z: Double = 1.0) { - matrix.scale(x.toFloat(), y.toFloat(), z.toFloat()) + fun pop() { + stack.removeLast() } - fun scale(value: Double) { - val valueFloat = value.toFloat() - matrix.scale(valueFloat, valueFloat, valueFloat) + fun peek(): Entry { + return stack.last } + + fun isEmpty() = stack.size <= 1 + + fun resetMatrix() { + val entry = stack.last + entry.position.identity() + entry.normal.identity() + } + + fun loadIdentity() { + val entry = stack.last + entry.position.identity() + entry.normal.identity() + } + + fun multiplyPositionMatrix(matrix: Matrix4f) { + stack.last.position.mul(matrix) + } + + data class Entry(val position: Matrix4f, val normal: Matrix3f) } diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt b/common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt deleted file mode 100644 index 506897f76..000000000 --- a/common/src/main/kotlin/com/lambda/graphics/gl/MatrixStack.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.lambda.graphics.gl - -import org.joml.Matrix3f -import org.joml.Matrix4f -import org.joml.Quaternionf -import java.util.* -import kotlin.math.cbrt - -class MatrixStack { - private val stack: Deque = ArrayDeque() - - init { - val matrix4f = Matrix4f() - val matrix3f = Matrix3f() - stack.add( - Entry(Matrix4f(), Matrix3f() - )) - } - - fun translate(x: Double, y: Double, z: Double): Matrix4f = - translate(x.toFloat(), y.toFloat(), z.toFloat()) - - fun translate(x: Float, y: Float, z: Float): Matrix4f = - stack.last.positionMatrix.translate(x, y, z) - - fun scale(x: Float, y: Float, z: Float) { - val entry = stack.last - entry.positionMatrix.scale(x, y, z) - if (x == y && y == z) { - if (x > 0.0f) { - return - } - entry.normalMatrix.scale(-1.0f) - } - val f = 1.0f / x - val g = 1.0f / y - val h = 1.0f / z - val i = cbrt(f * g * h) - entry.normalMatrix.scale(i * f, i * g, i * h) - } - - fun multiply(quaternion: Quaternionf) { - val entry = stack.last - entry.positionMatrix.rotate(quaternion) - entry.normalMatrix.rotate(quaternion) - } - - fun multiply(quaternion: Quaternionf, originX: Float, originY: Float, originZ: Float) { - val entry = stack.last - entry.positionMatrix.rotateAround(quaternion, originX, originY, originZ) - entry.normalMatrix.rotate(quaternion) - } - - fun push() { - val entry = stack.last - stack.addLast(Entry(Matrix4f(entry.positionMatrix), Matrix3f(entry.normalMatrix))) - } - - fun pop() { - stack.removeLast() - } - - fun peek(): Entry { - return stack.last - } - - fun isEmpty() = stack.size <= 1 - - fun loadIdentity() { - val entry = stack.last - entry.positionMatrix.identity() - entry.normalMatrix.identity() - } - - fun multiplyPositionMatrix(matrix: Matrix4f) { - stack.last.positionMatrix.mul(matrix) - } - - data class Entry(val positionMatrix: Matrix4f, val normalMatrix: Matrix3f) -} From 8d50d9615bdcef2b9f21112874a6c64c3753d843 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 20:37:24 -0400 Subject: [PATCH 19/63] Make GuiConfig loadable --- .../kotlin/com/lambda/config/configurations/GuiConfig.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt b/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt index 8b6a2fc59..cd5f930db 100644 --- a/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt +++ b/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt @@ -1,9 +1,10 @@ package com.lambda.config.configurations import com.lambda.config.Configuration +import com.lambda.core.Loadable import com.lambda.util.FolderRegister -object GuiConfig : Configuration() { +object GuiConfig : Configuration(), Loadable { override val configName = "gui" override val primary = FolderRegister.config.resolve("$configName.json") -} \ No newline at end of file +} From fd4100a789a2be1f3cc62304df0b196fcaa70cf7 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sun, 21 Apr 2024 20:45:09 -0400 Subject: [PATCH 20/63] Fix: Wrong loadable --- .../kotlin/com/lambda/config/configurations/GuiConfig.kt | 3 +-- common/src/main/kotlin/com/lambda/core/Loader.kt | 3 ++- common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt b/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt index cd5f930db..5a7497587 100644 --- a/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt +++ b/common/src/main/kotlin/com/lambda/config/configurations/GuiConfig.kt @@ -1,10 +1,9 @@ package com.lambda.config.configurations import com.lambda.config.Configuration -import com.lambda.core.Loadable import com.lambda.util.FolderRegister -object GuiConfig : Configuration(), Loadable { +object GuiConfig : Configuration() { override val configName = "gui" override val primary = FolderRegister.config.resolve("$configName.json") } diff --git a/common/src/main/kotlin/com/lambda/core/Loader.kt b/common/src/main/kotlin/com/lambda/core/Loader.kt index 687e5172f..7878c93a7 100644 --- a/common/src/main/kotlin/com/lambda/core/Loader.kt +++ b/common/src/main/kotlin/com/lambda/core/Loader.kt @@ -6,6 +6,7 @@ import com.lambda.command.CommandManager import com.lambda.config.configurations.GuiConfig import com.lambda.friend.FriendManager import com.lambda.graphics.renderer.gui.font.LambdaFont +import com.lambda.gui.GuiConfigurable import com.lambda.interaction.PlayerPacketManager import com.lambda.interaction.RotationManager import com.lambda.module.ModuleRegistry @@ -19,7 +20,7 @@ object Loader { RotationManager, PlayerPacketManager, LambdaFont.Loader, - GuiConfig, + GuiConfigurable, FriendManager, ) diff --git a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index 9253bd6ab..c652b2d7e 100644 --- a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -2,6 +2,7 @@ package com.lambda.gui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig +import com.lambda.core.Loadable import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow @@ -9,7 +10,7 @@ import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d -object GuiConfigurable : Configurable(GuiConfig) { +object GuiConfigurable : Configurable(GuiConfig), Loadable { override val name = "gui" val mainWindows by setting("windows", defaultWindows).apply { @@ -31,4 +32,4 @@ object GuiConfigurable : Configurable(GuiConfig) { position = Vec2d((width + step) * index, 0.0) + step } } -} \ No newline at end of file +} From b07fe53a47b8c53b28b49b5eb22c1158c254b00f Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:49:02 -0400 Subject: [PATCH 21/63] Fix: Tags --- .../kotlin/com/lambda/module/modules/movement/HorseUtils.kt | 2 +- .../kotlin/com/lambda/module/modules/movement/TridentBoost.kt | 2 +- .../kotlin/com/lambda/module/modules/movement/TridentFlight.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt index c5ad344b4..03231a4ef 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt @@ -12,7 +12,7 @@ import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket object HorseUtils : Module( name = "HorseUtils", description = "Various utilities for horses.", - defaultTags = setOf(ModuleTag.MOVEMENT, ModuleTag.BYPASS) + tag = ModuleTag.MOVEMENT ) { private val page by setting("Page", Page.General) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt index 0725c5b13..94e45bc06 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object TridentBoost : Module( name = "TridentBoost", description = "Boosts you with tridents", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { val tridentSpeed by setting("Speed Factor", 2.0, 0.1..3.0, 0.1, description = "Speed factor of the trident boost") val forceUse by setting("Force Use", true, description = "Try to use the trident outside of water or rain") diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt index a76273fe3..5eb42c5eb 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt @@ -20,7 +20,7 @@ import kotlin.math.sqrt object TridentFlight : Module( name = "TridentFlight", description = "Allows you to fly with tridents", - defaultTags = setOf(ModuleTag.MOVEMENT, ModuleTag.BYPASS, ModuleTag.GRIM), + tag = ModuleTag.MOVEMENT ) { private val bounce by setting("Bounce", true, description = "Automatically use the trident") private val delay by setting("Delay", 0, 0..20, 1, description = "Delay in ticks before releasing the trident", visibility = { bounce }) From 7a58391d7b01ed58d3022c41047022b86a76c255 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Wed, 24 Apr 2024 15:21:38 +0300 Subject: [PATCH 22/63] Blur Optimization & Refactor --- .../kotlin/com/lambda/graphics/RenderMain.kt | 2 +- .../kotlin/com/lambda/graphics/gl/Matrices.kt | 67 +++++-------------- .../renderer/immediate/BlurPostProcessor.kt | 11 +-- .../gui/api/component/WindowComponent.kt | 2 +- .../lambda/module/modules/client/ClickGui.kt | 1 + .../module/modules/movement/HorseUtils.kt | 2 +- .../module/modules/movement/TridentBoost.kt | 2 +- .../module/modules/movement/TridentFlight.kt | 2 +- .../lambda/shaders/fragment/post/blur.frag | 22 ++---- 9 files changed, 35 insertions(+), 76 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index 00cdeb3c2..a04f5787c 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -13,7 +13,7 @@ import org.joml.Matrix4f object RenderMain { val projectionMatrix = Matrix4f() - val modelViewMatrix: Matrix4f get() = Matrices.peek().position + val modelViewMatrix: Matrix4f get() = Matrices.peek() var screenSize = Vec2d.ZERO diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt index 33c2ad0f5..13a7530d4 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt @@ -1,80 +1,45 @@ package com.lambda.graphics.gl -import org.joml.Matrix3f import org.joml.Matrix4f import org.joml.Quaternionf -import java.util.* -import kotlin.math.cbrt +import kotlin.collections.ArrayDeque object Matrices { - private val stack: Deque = ArrayDeque( - listOf(Entry(Matrix4f(), Matrix3f())) - ) + private val stack = ArrayDeque(listOf(Matrix4f())) - fun translate(x: Double, y: Double, z: Double): Matrix4f = + fun translate(x: Double, y: Double, z: Double) { translate(x.toFloat(), y.toFloat(), z.toFloat()) + } - fun translate(x: Float, y: Float, z: Float): Matrix4f = - stack.last.position.translate(x, y, z) + fun translate(x: Float, y: Float, z: Float) { + stack.last().translate(x, y, z) + } fun scale(x: Float, y: Float, z: Float) { - val entry = stack.last - entry.position.scale(x, y, z) - if (x == y && y == z) { - if (x > 0.0f) { - return - } - entry.normal.scale(-1.0f) - } - val f = 1.0f / x - val g = 1.0f / y - val h = 1.0f / z - val i = cbrt(f * g * h) - entry.normal.scale(i * f, i * g, i * h) + stack.last().scale(x, y, z) } fun multiply(quaternion: Quaternionf) { - val entry = stack.last - entry.position.rotate(quaternion) - entry.normal.rotate(quaternion) + stack.last().rotate(quaternion) } fun multiply(quaternion: Quaternionf, originX: Float, originY: Float, originZ: Float) { - val entry = stack.last - entry.position.rotateAround(quaternion, originX, originY, originZ) - entry.normal.rotate(quaternion) + stack.last().rotateAround(quaternion, originX, originY, originZ) } fun push() { - val entry = stack.last - stack.addLast(Entry(Matrix4f(entry.position), Matrix3f(entry.normal))) + val entry = stack.last() + stack.addLast(Matrix4f(entry)) } fun pop() { stack.removeLast() } - fun peek(): Entry { - return stack.last - } - - fun isEmpty() = stack.size <= 1 + fun peek() = stack.last() fun resetMatrix() { - val entry = stack.last - entry.position.identity() - entry.normal.identity() + stack.clear() + stack.add(Matrix4f()) } - - fun loadIdentity() { - val entry = stack.last - entry.position.identity() - entry.normal.identity() - } - - fun multiplyPositionMatrix(matrix: Matrix4f) { - stack.last.position.mul(matrix) - } - - data class Entry(val position: Matrix4f, val normal: Matrix3f) -} +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt index 0f85814f4..e4d8ff863 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/immediate/BlurPostProcessor.kt @@ -14,13 +14,13 @@ object BlurPostProcessor { private val vao = VAO(VertexMode.TRIANGLES, VertexAttrib.Group.BLUR) private val shader = Shader("post/blur") - - fun render(rect: Rect, level: Int) { - renderPass(rect, Vec2d.RIGHT, level) - renderPass(rect, Vec2d.BOTTOM, level) + fun render(rect: Rect, level: Int, alpha: Double) { + if (level <= 0 || alpha <= 0.1) return + renderPass(rect, Vec2d.RIGHT, level, alpha) + renderPass(rect, Vec2d.BOTTOM, level, alpha) } - private fun renderPass(rect: Rect, direction: Vec2d, level: Int) { + private fun renderPass(rect: Rect, direction: Vec2d, level: Int, alpha: Double) { val x1 = rect.leftTop.x val y1 = rect.leftTop.y val x2 = rect.rightBottom.x @@ -43,6 +43,7 @@ object BlurPostProcessor { shader.use() shader["u_Direction"] = direction / Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) shader["u_BlurLevel"] = level + shader["u_Alpha"] = alpha bindTexture(mc.framebuffer.colorAttachment) upload() diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 64f366179..af9c13f89 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -93,7 +93,7 @@ abstract class WindowComponent ( } override fun onRender() { - BlurPostProcessor.render(rect, 50) // TODO: Customizable blur level + BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) layer.render() scissor(contentRect) { diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt index fcb58ade0..104f3c10a 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt @@ -18,6 +18,7 @@ object ClickGui : Module( val windowPadding by setting("Window Padding", 2.0, 0.0..10.0, 0.1) val buttonHeight by setting("Button Height", 11.0, 8.0..20.0, 0.1) val buttonStep by setting("Button Step", 1.0, 0.0..5.0, 0.1) + val windowBlur by setting("Window Blur", 30, 0..100, 1) // Animation val openSpeed by setting("Open Speed", 0.6, 0.1..1.0, 0.01) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt index c5ad344b4..03231a4ef 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt @@ -12,7 +12,7 @@ import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket object HorseUtils : Module( name = "HorseUtils", description = "Various utilities for horses.", - defaultTags = setOf(ModuleTag.MOVEMENT, ModuleTag.BYPASS) + tag = ModuleTag.MOVEMENT ) { private val page by setting("Page", Page.General) diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt index 0725c5b13..94e45bc06 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentBoost.kt @@ -6,7 +6,7 @@ import com.lambda.module.tag.ModuleTag object TridentBoost : Module( name = "TridentBoost", description = "Boosts you with tridents", - defaultTags = setOf(ModuleTag.MOVEMENT) + tag = ModuleTag.MOVEMENT ) { val tridentSpeed by setting("Speed Factor", 2.0, 0.1..3.0, 0.1, description = "Speed factor of the trident boost") val forceUse by setting("Force Use", true, description = "Try to use the trident outside of water or rain") diff --git a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt index a76273fe3..5eb42c5eb 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/movement/TridentFlight.kt @@ -20,7 +20,7 @@ import kotlin.math.sqrt object TridentFlight : Module( name = "TridentFlight", description = "Allows you to fly with tridents", - defaultTags = setOf(ModuleTag.MOVEMENT, ModuleTag.BYPASS, ModuleTag.GRIM), + tag = ModuleTag.MOVEMENT ) { private val bounce by setting("Bounce", true, description = "Automatically use the trident") private val delay by setting("Delay", 0, 0..20, 1, description = "Delay in ticks before releasing the trident", visibility = { bounce }) diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag index b5e18b761..48dd85bb7 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/post/blur.frag @@ -5,6 +5,7 @@ uniform sampler2D u_Texture; uniform vec2 u_Direction; uniform int u_BlurLevel; +uniform float u_Alpha; in vec2 v_TexCoord; out vec4 color; @@ -14,27 +15,18 @@ float gaussian(float x) { } void main() { - vec4 col = texture(u_Texture, v_TexCoord); float totalWeight = 1.0; + color = texture(u_Texture, v_TexCoord); for (int i = -u_BlurLevel; i <= u_BlurLevel; ++i) { float offset = float(i); + float amount = gaussian(offset); vec2 texOffset = offset * u_Direction; - col += texture(u_Texture, v_TexCoord + texOffset) * gaussian(offset); - totalWeight += gaussian(offset); - } - - // Normalize the color - col /= totalWeight; - // Vertical blur - totalWeight = 0.0; - for (int i = -u_BlurLevel; i <= u_BlurLevel; ++i) { - float offset = float(i); - vec2 texOffset = offset * u_Direction; - col += texture(u_Texture, v_TexCoord + texOffset) * gaussian(offset); - totalWeight += gaussian(offset); + color += texture(u_Texture, v_TexCoord + texOffset) * amount; + totalWeight += amount; } - color = col / totalWeight; + color /= totalWeight; + color *= vec4(1.0, 1.0, 1.0, u_Alpha); } From 2a92af950184375c0738b65aff73bb94e4b7477a Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:50:19 -0400 Subject: [PATCH 23/63] Removed useless coerce The variable is not the receiver --- .../main/kotlin/com/lambda/interaction/RotationManager.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 2f0159050..3d2e74e87 100644 --- a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -73,9 +73,6 @@ object RotationManager : Loadable { private fun rotate(newContext: RotationContext?) = runSafe { prevRotation = currentRotation - (keepTicks--).coerceAtLeast(0) - (pauseTicks--).coerceAtLeast(0) - currentContext?.let { current -> if (keepTicks + current.config.resetTicks < 0 || pauseTicks >= 0) { currentContext = null @@ -235,4 +232,4 @@ object RotationManager : Loadable { } } } -} \ No newline at end of file +} From 5edcf068781ea6dcf8ee590f62a2364f0c643a15 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:51:01 -0400 Subject: [PATCH 24/63] didn't meant to remove this --- .../src/main/kotlin/com/lambda/interaction/RotationManager.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt index 3d2e74e87..6c1d7fc17 100644 --- a/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt +++ b/common/src/main/kotlin/com/lambda/interaction/RotationManager.kt @@ -73,6 +73,9 @@ object RotationManager : Loadable { private fun rotate(newContext: RotationContext?) = runSafe { prevRotation = currentRotation + keepTicks-- + pauseTicks-- + currentContext?.let { current -> if (keepTicks + current.config.resetTicks < 0 || pauseTicks >= 0) { currentContext = null From 2f8d91d478a4700aa04c6b48b9f313d86ec46368 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Sat, 27 Apr 2024 13:17:17 -0400 Subject: [PATCH 25/63] Fix: VAO buffer leak --- .../main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt index dfec78dc7..3d6bdfa23 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt @@ -18,6 +18,7 @@ import com.lambda.graphics.gl.VaoUtils.bufferData import com.lambda.graphics.gl.VaoUtils.unbindIndexBuffer import com.lambda.graphics.gl.VaoUtils.unbindVertexArray import com.lambda.graphics.gl.VaoUtils.unbindVertexBuffer +import com.lambda.threading.mainThread import com.lambda.threading.runOnGameThread import com.mojang.blaze3d.systems.RenderSystem.drawElements import org.lwjgl.opengl.GL30C.* @@ -191,8 +192,10 @@ class VAO( } fun destroy() { - glDeleteBuffers(ibo) - glDeleteBuffers(vbo) - glDeleteVertexArrays(vao) + runOnGameThread { + glDeleteBuffers(ibo) + glDeleteBuffers(vbo) + glDeleteVertexArrays(vao) + } } -} \ No newline at end of file +} From 6fcc348c898e87323632cc62e8fa932c94abf6c0 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 28 Apr 2024 16:31:06 +0300 Subject: [PATCH 26/63] DirectionMask --- .../graphics/renderer/world/DirectionMask.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt new file mode 100644 index 000000000..394760bc1 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt @@ -0,0 +1,28 @@ +package com.lambda.graphics.renderer.world + +import net.minecraft.util.math.Direction + +object DirectionMask { + const val EAST = 1 // X + + const val WEST = 2 // X - + + const val UP = 4 // Y + + const val DOWN = 8 // Y - + + const val SOUTH = 16 // Z + + const val NORTH = 32 // Z - + + const val ALL = EAST or WEST or UP or DOWN or SOUTH or NORTH + + fun Int.exclude(dir: Int) = this xor dir + fun Int.hasDirection(dir: Int) = (this and dir) != 0 + + val Direction.mask get() = when (this) { + Direction.DOWN -> DOWN + Direction.UP -> UP + Direction.NORTH -> NORTH + Direction.SOUTH -> SOUTH + Direction.WEST -> WEST + Direction.EAST -> EAST + } +} \ No newline at end of file From de70f735b6baa1816dee5b90a65d01a350c1a23e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Mon, 29 Apr 2024 16:29:40 +0300 Subject: [PATCH 27/63] Optimization tweak --- .../com/lambda/graphics/renderer/Renderer.kt | 20 +++++++++++-- .../renderer/gui/AbstractGuiRenderer.kt | 30 +++++++++++++++++-- .../graphics/renderer/gui/font/FontEntry.kt | 2 +- .../renderer/gui/font/FontRenderer.kt | 6 ++-- .../graphics/renderer/gui/rect/RectEntry.kt | 2 +- .../renderer/gui/rect/RectRenderer.kt | 9 +++--- .../gui/api/component/WindowComponent.kt | 7 ++++- .../com/lambda/gui/api/layer/RenderLayer.kt | 6 ++++ .../com/lambda/util/TransformedObservable.kt | 21 +++++++++++++ 9 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/util/TransformedObservable.kt diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt index a806576ae..78cf45b6e 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt @@ -1,16 +1,23 @@ package com.lambda.graphics.renderer import com.lambda.graphics.buffer.vao.VAO +import com.lambda.graphics.gl.Matrices +import com.lambda.graphics.shader.Shader +import com.lambda.util.math.Vec2d import kotlinx.coroutines.* import kotlin.properties.Delegates -abstract class Renderer > : IRenderer { +abstract class Renderer > (private val shader: Shader) : IRenderer { private val entrySet = mutableSetOf() - private var rebuild = false + protected var rebuild = false private var destroyed = false val asRenderer get() = this as IRenderer + // Optimization tweak to reduce build calls when whole renderer moves + // Instead of rebuilding all entries you translate the matrix + var matrixOffset = Vec2d.ZERO + abstract val vao: VAO protected abstract fun newEntry(block: T.() -> Unit): T @@ -35,9 +42,18 @@ abstract class Renderer > : IRenderer { vao.upload() } + Matrices.push() + Matrices.translate(matrixOffset.x, matrixOffset.y, 0.0) + + shader.use() + preRender() vao.render() + + Matrices.pop() } + protected open fun preRender() {} + override fun update() { checkDestroyed() entrySet.forEach(IRenderEntry::update) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGuiRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGuiRenderer.kt index a074c5801..7ffe72e5a 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGuiRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/AbstractGuiRenderer.kt @@ -3,11 +3,37 @@ package com.lambda.graphics.renderer.gui import com.lambda.graphics.buffer.vao.VAO import com.lambda.graphics.buffer.vao.vertex.VertexAttrib import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.gl.Matrices import com.lambda.graphics.renderer.Renderer import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.graphics.shader.Shader +import com.lambda.util.TransformedObservable +import com.lambda.util.math.Rect +import com.lambda.util.math.Vec2d abstract class AbstractGuiRenderer > ( - vertexType: VertexAttrib.Group -) : Renderer() { + vertexType: VertexAttrib.Group, + shader: Shader +) : Renderer(shader) { override val vao = VAO(VertexMode.TRIANGLES, vertexType) + + fun positionVec2() = + object : TransformedObservable(Vec2d.ZERO) { + override fun transform(value: Vec2d) = + value - matrixOffset + + override fun onChange(oldValue: Vec2d, newValue: Vec2d) { + rebuild = true + } + } + + fun positionRect() = + object : TransformedObservable(Rect.ZERO) { + override fun transform(value: Rect) = + value - matrixOffset + + override fun onChange(oldValue: Rect, newValue: Rect) { + rebuild = true + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt index ade50fe8e..c80647712 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt @@ -13,7 +13,7 @@ class FontEntry( private val font: LambdaFont ) : IFontEntry { override var text by owner.field("") - override var position by owner.field(Vec2d.ZERO) + override var position by owner.positionVec2() override var color by owner.field(Color.WHITE) override var scale by owner.field(1.0) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt index a75513daf..754728d0e 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt @@ -5,12 +5,10 @@ import com.lambda.graphics.renderer.gui.AbstractGuiRenderer import com.lambda.graphics.shader.Shader class FontRenderer(private val font: LambdaFont = LambdaFont.FiraSansRegular) : AbstractGuiRenderer( - VertexAttrib.Group.FONT + VertexAttrib.Group.FONT, shader ) { - override fun render() { - shader.use() + override fun preRender() { font.glyphs.bind() - super.render() } override fun newEntry(block: IFontEntry.() -> Unit) = diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt index 085aaf4eb..a5872139d 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt @@ -10,7 +10,7 @@ class RectEntry( override val owner: RectRenderer, override val updateBlock: IRectEntry.() -> Unit ) : IRectEntry { - override var position by owner.field(Rect.ZERO) + override var position by owner.positionRect() override var roundRadius by owner.field(0.0) private var leftTop by owner.field(Color.WHITE!!) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt index 5ba178377..bf63317b2 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt @@ -12,14 +12,12 @@ import org.lwjgl.opengl.GL11.GL_ONE import org.lwjgl.opengl.GL11.GL_SRC_ALPHA class RectRenderer : AbstractGuiRenderer( - VertexAttrib.Group.RECT + VertexAttrib.Group.RECT, shader ) { var shadeColor = false var fancyBlending = false - override fun render() { - shader.use() - + override fun preRender() { shader["u_Shade"] = shadeColor if (shadeColor) { @@ -30,6 +28,9 @@ class RectRenderer : AbstractGuiRenderer( } if (fancyBlending) blendFunc(GL_SRC_ALPHA, GL_ONE) + } + + override fun render() { super.render() defaultBlendFunc() } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index af9c13f89..4b6aabc89 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -93,7 +93,12 @@ abstract class WindowComponent ( } override fun onRender() { - BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) + // TODO: fix blur + // BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) + + layer.assignOffset(position) + subLayer.assignOffset(position) + layer.render() scissor(contentRect) { diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt index 97762b0f5..42b131209 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt @@ -3,6 +3,7 @@ package com.lambda.gui.api.layer import com.lambda.graphics.renderer.gui.font.FontRenderer import com.lambda.graphics.renderer.gui.rect.RectRenderer import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.math.Vec2d class RenderLayer { var allowEffects = false @@ -12,6 +13,11 @@ class RenderLayer { fun entry() = LayerEntry(rect, font) + fun assignOffset(ofs: Vec2d) { + rect.matrixOffset = ofs + font.matrixOffset = ofs + } + fun render() { rect.update() font.update() diff --git a/common/src/main/kotlin/com/lambda/util/TransformedObservable.kt b/common/src/main/kotlin/com/lambda/util/TransformedObservable.kt new file mode 100644 index 000000000..750f3a61f --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/TransformedObservable.kt @@ -0,0 +1,21 @@ +package com.lambda.util + +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +abstract class TransformedObservable(initialValue: T) : ReadWriteProperty { + private var value = initialValue + + override fun getValue(thisRef: Any?, property: KProperty<*>) = value + + override fun setValue(thisRef: Any?, property: KProperty<*>, valueIn: T) { + val oldValue = this.value + this.value = transform(valueIn) + if (oldValue != value) onChange(oldValue, value) + } + + protected open fun transform(value: T): T = value + protected open fun onChange(oldValue: T, newValue: T) {} + + override fun toString(): String = "TransformedObservableProperty(value=$value)" +} \ No newline at end of file From 0e807d46c7195c509c1dae2ac24bb335f9082da6 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Mon, 29 Apr 2024 16:44:37 +0300 Subject: [PATCH 28/63] Quick refactor --- .../src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt | 4 +++- common/src/main/kotlin/com/lambda/graphics/shader/Shader.kt | 4 ++++ .../src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt index 78cf45b6e..d945dbc0f 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt @@ -7,7 +7,9 @@ import com.lambda.util.math.Vec2d import kotlinx.coroutines.* import kotlin.properties.Delegates -abstract class Renderer > (private val shader: Shader) : IRenderer { +abstract class Renderer > ( + protected val shader: Shader +) : IRenderer { private val entrySet = mutableSetOf() protected var rebuild = false private var destroyed = false diff --git a/common/src/main/kotlin/com/lambda/graphics/shader/Shader.kt b/common/src/main/kotlin/com/lambda/graphics/shader/Shader.kt index b0ec5c513..69c15e1d5 100644 --- a/common/src/main/kotlin/com/lambda/graphics/shader/Shader.kt +++ b/common/src/main/kotlin/com/lambda/graphics/shader/Shader.kt @@ -9,6 +9,7 @@ import com.lambda.util.LambdaResource import com.lambda.util.math.Vec2d import it.unimi.dsi.fastutil.objects.Object2IntMap import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap +import net.minecraft.util.math.Vec3d import org.joml.Matrix4f import org.lwjgl.opengl.GL20C.* import java.awt.Color @@ -52,6 +53,9 @@ class Shader(fragmentPath: String, vertexPath: String) { operator fun set(name: String, vec: Vec2d) = glUniform2f(loc(name), vec.x.toFloat(), vec.y.toFloat()) + operator fun set(name: String, vec: Vec3d) = + glUniform3f(loc(name), vec.x.toFloat(), vec.y.toFloat(), vec.z.toFloat()) + operator fun set(name: String, color: Color) = glUniform4f( loc(name), diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt index 42b131209..953e72ed3 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt @@ -25,9 +25,9 @@ class RenderLayer { rect.apply { shadeColor = GuiSettings.shade && allowEffects fancyBlending = GuiSettings.glow && allowEffects - render() } + rect.render() font.render() } From 4e8599ffe0a7ace2e32919dfb3e78773cd41c1d2 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Mon, 29 Apr 2024 20:41:38 -0400 Subject: [PATCH 29/63] Fix: Texture upload doesn't work on other architectures --- .../lambda/graphics/texture/TextureUtils.kt | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt index 57769e7dc..0af82b138 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt @@ -27,13 +27,32 @@ object TextureUtils { val width = bufferedImage.width val height = bufferedImage.height - // GL_UNSIGNED_INT_8_8_8_8_REV -> 0xRRGGBBAA + // Here we cannot use GL_UNSIGNED_INT_8_8_8_8_REV or GL_UNSIGNED_INT_8_8_8_8 + // because the RGBA values are affected by the machine's endianness. + // On little-endian machines, you would read the data as + // 0xAABBGGRR and on big-endian machines as 0xRRGGBBAA. + // The solution is to use GL_UNSIGNED_BYTE and swap the bytes + // manually if necessary. (We won't need to) + // // GL_UNSIGNED_BYTE -> [RR, GG, BB, AA] - // In the end it will be the exact same but in the case that you - // supply the data in the reverse order, GL_UNSIGNED_INT_8_8_8_8_REV - // will swap the bytes for you. - glTexImage2D(GL_TEXTURE_2D, lod, GL_BGRA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0) - glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, readImage(bufferedImage)) + // Array of floats normalized to [0.0, 1.0] -> [R, G, B, A] + glTexImage2D(GL_TEXTURE_2D, lod, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, readImage(bufferedImage)) + + // I'd also like to use glTexSubImage2D, but we have an issue where the function + // would return an error about an invalid texture format. + // + // It would allow us to upload texture data asynchronously and is more efficient + // from testing we gain approximately 20% runtime performance. + // If someone with advanced OpenGL knowledge could help us out, that would be great. + // (Very unlikely to happen, but I can hope) + // + // I've also read online that glTexStorage2D can be used for the same purpose as + // glTexImage2D with NULL data. + // However, some users may have ancient hardware that does not support this function. + // as it was implemented in OpenGL 4.2 and ES 3.0. + // + // glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readImage(bufferedImage)) + setupTexture(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR) } From 2f6bf5cb7f7e2b3200f84227e0d46eccb4666348 Mon Sep 17 00:00:00 2001 From: Constructor Date: Tue, 30 Apr 2024 19:04:46 +0200 Subject: [PATCH 30/63] Fix double destroying This caused a crash on reloading config --- .../kotlin/com/lambda/config/AbstractSetting.kt | 4 ++-- common/src/main/kotlin/com/lambda/core/Loader.kt | 2 +- .../com/lambda/graphics/texture/TextureUtils.kt | 3 --- .../main/kotlin/com/lambda/gui/GuiConfigurable.kt | 12 ++++++------ .../lambda/gui/impl/clickgui/LambdaClickGui.kt | 15 +++++++-------- .../src/main/kotlin/com/lambda/module/Module.kt | 12 ++++++------ 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/config/AbstractSetting.kt b/common/src/main/kotlin/com/lambda/config/AbstractSetting.kt index 80e03935e..6e562bc84 100644 --- a/common/src/main/kotlin/com/lambda/config/AbstractSetting.kt +++ b/common/src/main/kotlin/com/lambda/config/AbstractSetting.kt @@ -78,7 +78,7 @@ abstract class AbstractSetting( value = gson.fromJson(serialized, value::class.java) } - fun listener(block: SafeContext.(from: T, to: T) -> Unit) { + fun onValueChange(block: SafeContext.(from: T, to: T) -> Unit) { listeners.add { from, to -> runSafe { block(from, to) @@ -86,7 +86,7 @@ abstract class AbstractSetting( } } - fun unsafeListener(block: (from: T, to: T) -> Unit) { + fun onValueChangeUnsafe(block: (from: T, to: T) -> Unit) { listeners.add(block) } diff --git a/common/src/main/kotlin/com/lambda/core/Loader.kt b/common/src/main/kotlin/com/lambda/core/Loader.kt index 7878c93a7..60ed586d2 100644 --- a/common/src/main/kotlin/com/lambda/core/Loader.kt +++ b/common/src/main/kotlin/com/lambda/core/Loader.kt @@ -30,7 +30,7 @@ object Loader { val initTime = measureTimeMillis { loadables.forEach { loadable -> - var info: String + val info: String val phaseTime = measureTimeMillis { info = loadable.load() } diff --git a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt index 0af82b138..1142dec70 100644 --- a/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt @@ -3,10 +3,7 @@ package com.lambda.graphics.texture import com.mojang.blaze3d.systems.RenderSystem import net.minecraft.client.texture.NativeImage import org.lwjgl.BufferUtils -import org.lwjgl.opengl.ARBTextureStorage.glTexStorage2D -import org.lwjgl.opengl.GL11C import org.lwjgl.opengl.GL13C.* -import org.lwjgl.opengl.GL30C.glGenerateMipmap import java.awt.Color import java.awt.Font import java.awt.RenderingHints diff --git a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index c652b2d7e..a2b5fdee2 100644 --- a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -3,7 +3,6 @@ package com.lambda.gui import com.lambda.config.Configurable import com.lambda.config.configurations.GuiConfig import com.lambda.core.Loadable -import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow @@ -12,22 +11,23 @@ import com.lambda.util.math.Vec2d object GuiConfigurable : Configurable(GuiConfig), Loadable { override val name = "gui" + private val ownerGui = LambdaClickGui val mainWindows by setting("windows", defaultWindows).apply { - listener { from, _ -> - from.forEach(WindowComponent<*>::destroy) // free vram + onValueChange { _, _ -> + ownerGui.updateWindows() } } val customWindows by setting("custom windows", listOf()).apply { - listener { from, _ -> - from.forEach(WindowComponent<*>::destroy) // free vram + onValueChange { _, _ -> + ownerGui.updateWindows() } } private val defaultWindows get() = ModuleTag.defaults.mapIndexed { index, tag -> - TagWindow(tag, LambdaClickGui).apply { + TagWindow(tag, ownerGui).apply { val step = 3.0 position = Vec2d((width + step) * index, 0.0) + step } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index 09e336b0b..9976a8f78 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -1,7 +1,7 @@ package com.lambda.gui.impl.clickgui import com.lambda.gui.GuiConfigurable -import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow +import com.lambda.gui.api.component.WindowComponent object LambdaClickGui : AbstractClickGui() { override fun onShow() { @@ -14,17 +14,16 @@ object LambdaClickGui : AbstractClickGui() { super.onTick() } - private fun updateWindows() { + fun updateWindows() { val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows - val new = windows.subtract(children) + val new = windows.subtract(children.toSet()) children.addAll(new) - children.removeIf { - if (it !is CustomModuleWindow) return@removeIf false + if (it !is WindowComponent<*>) return@removeIf false - val flag = it !in windows - if (flag) it.destroy() - flag + val absent = it !in windows + if (absent) it.destroy() + absent } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/Module.kt b/common/src/main/kotlin/com/lambda/module/Module.kt index 07cd8cf37..b50027643 100644 --- a/common/src/main/kotlin/com/lambda/module/Module.kt +++ b/common/src/main/kotlin/com/lambda/module/Module.kt @@ -127,37 +127,37 @@ abstract class Module( } protected fun onEnable(block: SafeContext.() -> Unit) { - isEnabledSetting.listener { from, to -> + isEnabledSetting.onValueChange { from, to -> if (!from && to) block() } } protected fun onDisable(block: SafeContext.() -> Unit) { - isEnabledSetting.listener { from, to -> + isEnabledSetting.onValueChange { from, to -> if (from && !to) block() } } protected fun onToggle(block: SafeContext.(to: Boolean) -> Unit) { - isEnabledSetting.listener { from, to -> + isEnabledSetting.onValueChange { from, to -> if (from != to) block(to) } } protected fun onEnableUnsafe(block: () -> Unit) { - isEnabledSetting.unsafeListener { from, to -> + isEnabledSetting.onValueChangeUnsafe { from, to -> if (!from && to) block() } } protected fun onDisableUnsafe(block: () -> Unit) { - isEnabledSetting.unsafeListener { from, to -> + isEnabledSetting.onValueChangeUnsafe { from, to -> if (from && !to) block() } } protected fun onToggleUnsafe(block: (to: Boolean) -> Unit) { - isEnabledSetting.unsafeListener { from, to -> + isEnabledSetting.onValueChangeUnsafe { from, to -> if (from != to) block(to) } } From 84ddc4eccd948b4c20b1ddb79bfbb2d97eeded2b Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Tue, 30 Apr 2024 23:11:54 +0300 Subject: [PATCH 31/63] Dynamic, Static BlockESPs and Tracers --- .../mixin/render/GameRendererMixin.java | 7 ++ .../kotlin/com/lambda/graphics/RenderMain.kt | 11 +++ .../buffer/vao/vertex/VertexAttrib.kt | 11 ++- .../com/lambda/graphics/gl/GlStateUtils.kt | 19 ++-- .../kotlin/com/lambda/graphics/gl/Matrices.kt | 4 +- .../renderer/world/AbstractEspRenderer.kt | 27 ++++++ .../graphics/renderer/world/DirectionMask.kt | 6 ++ .../graphics/renderer/world/core/IESPEntry.kt | 25 +++++ .../world/core/box/DynamicFilledRenderer.kt | 70 ++++++++++++++ .../world/core/box/DynamicOutlineRenderer.kt | 92 +++++++++++++++++++ .../world/core/box/StaticFilledRenderer.kt | 56 +++++++++++ .../world/core/box/StaticOutlineRenderer.kt | 78 ++++++++++++++++ .../core/tracer/DynamicTracerRenderer.kt | 45 +++++++++ .../world/core/tracer/StaticTracerRenderer.kt | 33 +++++++ .../module/modules/render/RenderTest.kt | 51 ++++++++++ .../lambda/util/primitives/extension/Box.kt | 8 ++ .../util/primitives/extension/Entity.kt | 16 ---- .../shaders/fragment/renderer/pos_color.frag | 8 ++ .../shaders/vertex/renderer/box_dynamic.vert | 20 ++++ .../shaders/vertex/renderer/box_static.vert | 18 ++++ .../vertex/renderer/tracer_dynamic.vert | 23 +++++ .../vertex/renderer/tracer_static.vert | 21 +++++ 22 files changed, 620 insertions(+), 29 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/AbstractEspRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/IESPEntry.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicFilledRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicOutlineRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticFilledRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticOutlineRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/DynamicTracerRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/StaticTracerRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt create mode 100644 common/src/main/kotlin/com/lambda/util/primitives/extension/Box.kt create mode 100644 common/src/main/resources/assets/lambda/shaders/fragment/renderer/pos_color.frag create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_dynamic.vert create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_static.vert create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_dynamic.vert create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_static.vert diff --git a/common/src/main/java/com/lambda/mixin/render/GameRendererMixin.java b/common/src/main/java/com/lambda/mixin/render/GameRendererMixin.java index 00149bcf1..683686ee7 100644 --- a/common/src/main/java/com/lambda/mixin/render/GameRendererMixin.java +++ b/common/src/main/java/com/lambda/mixin/render/GameRendererMixin.java @@ -2,7 +2,9 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.RenderEvent; +import com.lambda.graphics.RenderMain; import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -16,4 +18,9 @@ private void updateTargetedEntityInvoke(float tickDelta, CallbackInfo info) { info.cancel(); } } + + @Inject(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;render(Lnet/minecraft/client/util/math/MatrixStack;FJZLnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/GameRenderer;Lnet/minecraft/client/render/LightmapTextureManager;Lorg/joml/Matrix4f;)V", shift = At.Shift.AFTER)) + private void onRenderWorld(float tickDelta, long limitTime, MatrixStack matrix, CallbackInfo ci) { + RenderMain.render3D(matrix.peek().getPositionMatrix()); + } } diff --git a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt index a04f5787c..24594a991 100644 --- a/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt +++ b/common/src/main/kotlin/com/lambda/graphics/RenderMain.kt @@ -9,6 +9,7 @@ import com.lambda.graphics.gl.Matrices.resetMatrix import com.lambda.graphics.gl.Matrices.translate import com.lambda.module.modules.client.GuiSettings import com.lambda.util.math.Vec2d +import com.mojang.blaze3d.systems.RenderSystem.getProjectionMatrix import org.joml.Matrix4f object RenderMain { @@ -31,6 +32,16 @@ object RenderMain { } } + @JvmStatic + fun render3D(matrix: Matrix4f) { + resetMatrix(matrix) + projectionMatrix.set(getProjectionMatrix()) + + setupGL { + RenderEvent.World().post() + } + } + private fun rescale(factor: Double) { val width = mc.window.framebufferWidth.toFloat() val height = mc.window.framebufferHeight.toFloat() diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt index 547050b89..72232b05b 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt @@ -11,9 +11,14 @@ enum class VertexAttrib(val componentCount: Int, componentSize: Int, val normali val size = componentCount * componentSize enum class Group(vararg val attributes: VertexAttrib) { - FONT(Vec2, Vec2, Color), - RECT(Vec2, Vec2, Vec3, Color), - BLUR(Vec2, Vec2); + // GUI + FONT(Vec2, Vec2, Color), // pos, uv, color + RECT(Vec2, Vec2, Vec3, Color), // pos, uv, , color + BLUR(Vec2, Vec2), // pos, uv + + // WORLD + DYNAMIC_RENDERER(Vec3, Vec3, Color), // prev pos, pos, color + STATIC_RENDERER(Vec3, Color); // pos, color val stride = attributes.sumOf { attribute -> attribute.size } } diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt b/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt index f29b8f5e3..71b463f83 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/GlStateUtils.kt @@ -4,29 +4,30 @@ import org.lwjgl.opengl.GL30C.* object GlStateUtils { private var depthTestState = true - private var depthMaskState = true private var blendState = false private var cullState = true fun setupGL(block: () -> Unit) { val savedDepthTest = depthTestState - val savedDepthMask = depthMaskState val savedBlend = blendState val savedCull = cullState - depthTest(false) glDepthMask(false) + lineSmooth(true) + + depthTest(false) blend(true) cull(false) - lineSmooth(true) + block() + glDepthMask(true) + lineSmooth(false) + depthTest(savedDepthTest) - glDepthMask(savedDepthMask) blend(savedBlend) cull(savedCull) - lineSmooth(false) } fun withDepth(block: () -> Unit) { @@ -39,7 +40,6 @@ object GlStateUtils { fun capSet(id: Int, flag: Boolean) { val field = when (id) { GL_DEPTH_TEST -> ::depthTestState - GL_DEPTH -> ::depthMaskState GL_BLEND -> ::blendState GL_CULL_FACE -> ::cullState else -> return @@ -60,7 +60,10 @@ object GlStateUtils { else glDisable(GL_CULL_FACE) } - private fun depthTest(flag: Boolean) = glDepthMask(flag) + private fun depthTest(flag: Boolean) { + if (flag) glEnable(GL_DEPTH_TEST) + else glDisable(GL_DEPTH_TEST) + } private fun lineSmooth(flag: Boolean) { if (flag) glEnable(GL_LINE_SMOOTH) diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt index 13a7530d4..10e9cc60c 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Matrices.kt @@ -38,8 +38,8 @@ object Matrices { fun peek() = stack.last() - fun resetMatrix() { + fun resetMatrix(entry: Matrix4f = Matrix4f()) { stack.clear() - stack.add(Matrix4f()) + stack.add(entry) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/AbstractEspRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/AbstractEspRenderer.kt new file mode 100644 index 000000000..6c168ef80 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/AbstractEspRenderer.kt @@ -0,0 +1,27 @@ +package com.lambda.graphics.renderer.world + +import com.lambda.Lambda.mc +import com.lambda.graphics.buffer.vao.VAO +import com.lambda.graphics.buffer.vao.vertex.VertexAttrib +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.graphics.renderer.Renderer +import com.lambda.graphics.shader.Shader +import com.lambda.util.primitives.extension.partialTicks +import net.minecraft.util.math.Vec3d + +abstract class AbstractEspRenderer > ( + vertexMode: VertexMode, + shader: Shader, + private val dynamic: Boolean +) : Renderer(shader) { + override val vao = VAO(vertexMode, + if (dynamic) VertexAttrib.Group.DYNAMIC_RENDERER + else VertexAttrib.Group.STATIC_RENDERER + ) + + override fun preRender() { + if (dynamic) shader["u_TickDelta"] = mc.partialTicks + shader["u_CameraPosition"] = mc.gameRenderer.camera.pos + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt index 394760bc1..957f60aa4 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/DirectionMask.kt @@ -13,6 +13,7 @@ object DirectionMask { const val NORTH = 32 // Z - const val ALL = EAST or WEST or UP or DOWN or SOUTH or NORTH + const val NONE = 0 fun Int.exclude(dir: Int) = this xor dir fun Int.hasDirection(dir: Int) = (this and dir) != 0 @@ -25,4 +26,9 @@ object DirectionMask { Direction.WEST -> WEST Direction.EAST -> EAST } + + enum class OutlineMode(val check: (Boolean, Boolean) -> Boolean) { + AND(Boolean::and), + OR(Boolean::or) + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/IESPEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/IESPEntry.kt new file mode 100644 index 000000000..ef00cd14b --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/IESPEntry.kt @@ -0,0 +1,25 @@ +package com.lambda.graphics.renderer.world.core + +import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.graphics.renderer.world.DirectionMask +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d +import java.awt.Color + +interface IESPEntry > : IRenderEntry { + var color: Color + + interface IBoxEntry > : IESPEntry { + var box: Box + var sides: Int + + interface Filled : IBoxEntry + interface Outline : IBoxEntry { + var outlineMode: DirectionMask.OutlineMode + } + } + + interface ITracerEntry : IESPEntry { + var position: Vec3d + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicFilledRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicFilledRenderer.kt new file mode 100644 index 000000000..4a43113ab --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicFilledRenderer.kt @@ -0,0 +1,70 @@ +package com.lambda.graphics.renderer.world.core.box + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.world.AbstractEspRenderer +import com.lambda.graphics.renderer.world.DirectionMask +import com.lambda.graphics.renderer.world.DirectionMask.hasDirection +import com.lambda.graphics.renderer.world.core.IESPEntry +import com.lambda.graphics.shader.Shader +import com.lambda.util.primitives.extension.max +import com.lambda.util.primitives.extension.min +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d +import java.awt.Color + +class DynamicFilledRenderer : AbstractEspRenderer( + VertexMode.TRIANGLES, shader, true +) { + override fun newEntry(block: IESPEntry.IBoxEntry.Filled.() -> Unit) = Builder(this, block) + + class Builder( + override val owner: DynamicFilledRenderer, + override val updateBlock: IESPEntry.IBoxEntry.Filled.() -> Unit + ) : IESPEntry.IBoxEntry.Filled { + override var box by owner.field(Box.from(Vec3d.ZERO)) + override var color by owner.field(Color.WHITE) + override var sides by owner.field(DirectionMask.ALL) + + private var prevBox by owner.field(Box.from(Vec3d.ZERO)) + + init { + update() + prevBox = box + } + + override fun update() { + prevBox = box + super.update() + } + + override fun build(ctx: IRenderContext) = ctx.use { + val pos11 = prevBox.min + val pos12 = prevBox.max + val pos21 = box.min + val pos22 = box.max + + ctx.grow(8) + + val blb by lazy { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color).end() } + val blf by lazy { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color).end() } + val brb by lazy { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color).end() } + val brf by lazy { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color).end() } + val tlb by lazy { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color).end() } + val tlf by lazy { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color).end() } + val trb by lazy { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color).end() } + val trf by lazy { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color).end() } + + if (sides.hasDirection(DirectionMask.EAST)) putQuad(brb, brf, trf, trb) + if (sides.hasDirection(DirectionMask.WEST)) putQuad(blb, blf, tlf, tlb) + if (sides.hasDirection(DirectionMask.UP)) putQuad(tlb, tlf, trf, trb) + if (sides.hasDirection(DirectionMask.DOWN)) putQuad(blb, brb, brf, blf) + if (sides.hasDirection(DirectionMask.SOUTH)) putQuad(blf, brf, trf, tlf) + if (sides.hasDirection(DirectionMask.NORTH)) putQuad(blb, brb, trb, tlb) + } + } + + companion object { + private val shader = Shader("renderer/pos_color", "renderer/box_dynamic") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicOutlineRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicOutlineRenderer.kt new file mode 100644 index 000000000..c6b0aebdd --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/DynamicOutlineRenderer.kt @@ -0,0 +1,92 @@ +package com.lambda.graphics.renderer.world.core.box + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.world.AbstractEspRenderer +import com.lambda.graphics.renderer.world.DirectionMask +import com.lambda.graphics.renderer.world.DirectionMask.DOWN +import com.lambda.graphics.renderer.world.DirectionMask.EAST +import com.lambda.graphics.renderer.world.DirectionMask.NORTH +import com.lambda.graphics.renderer.world.DirectionMask.SOUTH +import com.lambda.graphics.renderer.world.DirectionMask.UP +import com.lambda.graphics.renderer.world.DirectionMask.WEST +import com.lambda.graphics.renderer.world.DirectionMask.hasDirection +import com.lambda.graphics.renderer.world.core.IESPEntry +import com.lambda.graphics.shader.Shader +import com.lambda.util.primitives.extension.max +import com.lambda.util.primitives.extension.min +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d +import java.awt.Color + +class DynamicOutlineRenderer : AbstractEspRenderer( + VertexMode.LINES, shader, true +) { + override fun newEntry(block: IESPEntry.IBoxEntry.Outline.() -> Unit) = Builder(this, block) + + class Builder( + override val owner: DynamicOutlineRenderer, + override val updateBlock: IESPEntry.IBoxEntry.Outline.() -> Unit + ) : IESPEntry.IBoxEntry.Outline { + override var box by owner.field(Box.from(Vec3d.ZERO)) + override var color by owner.field(Color.WHITE) + override var sides by owner.field(DirectionMask.ALL) + override var outlineMode by owner.field(DirectionMask.OutlineMode.OR) + + private var prevBox by owner.field(Box.from(Vec3d.ZERO)) + + init { + update() + prevBox = box + } + + override fun update() { + prevBox = box + super.update() + } + + override fun build(ctx: IRenderContext) = ctx.use { + val pos11 = prevBox.min + val pos12 = prevBox.max + val pos21 = box.min + val pos22 = box.max + + ctx.grow(8) + + val blb by lazy { vec3(pos11.x, pos11.y, pos11.z).vec3(pos21.x, pos21.y, pos21.z).color(color).end() } + val blf by lazy { vec3(pos11.x, pos11.y, pos12.z).vec3(pos21.x, pos21.y, pos22.z).color(color).end() } + val brb by lazy { vec3(pos12.x, pos11.y, pos11.z).vec3(pos22.x, pos21.y, pos21.z).color(color).end() } + val brf by lazy { vec3(pos12.x, pos11.y, pos12.z).vec3(pos22.x, pos21.y, pos22.z).color(color).end() } + val tlb by lazy { vec3(pos11.x, pos12.y, pos11.z).vec3(pos21.x, pos22.y, pos21.z).color(color).end() } + val tlf by lazy { vec3(pos11.x, pos12.y, pos12.z).vec3(pos21.x, pos22.y, pos22.z).color(color).end() } + val trb by lazy { vec3(pos12.x, pos12.y, pos11.z).vec3(pos22.x, pos22.y, pos21.z).color(color).end() } + val trf by lazy { vec3(pos12.x, pos12.y, pos12.z).vec3(pos22.x, pos22.y, pos22.z).color(color).end() } + + val hasEast = sides.hasDirection(EAST) + val hasWest = sides.hasDirection(WEST) + val hasUp = sides.hasDirection(UP) + val hasDown = sides.hasDirection(DOWN) + val hasSouth = sides.hasDirection(SOUTH) + val hasNorth = sides.hasDirection(NORTH) + + if (outlineMode.check(hasUp, hasNorth)) putLine(tlb, trb) + if (outlineMode.check(hasUp, hasSouth)) putLine(tlf, trf) + if (outlineMode.check(hasUp, hasWest)) putLine(tlb, tlf) + if (outlineMode.check(hasUp, hasEast)) putLine(trf, trb) + + if (outlineMode.check(hasDown, hasNorth)) putLine(blb, brb) + if (outlineMode.check(hasDown, hasSouth)) putLine(blf, brf) + if (outlineMode.check(hasDown, hasWest)) putLine(blb, blf) + if (outlineMode.check(hasDown, hasEast)) putLine(brb, brf) + + if (outlineMode.check(hasWest, hasNorth)) putLine(tlb, blb) + if (outlineMode.check(hasNorth, hasEast)) putLine(trb, brb) + if (outlineMode.check(hasEast, hasSouth)) putLine(trf, brf) + if (outlineMode.check(hasSouth, hasWest)) putLine(tlf, blf) + } + } + + companion object { + private val shader = Shader("renderer/pos_color", "renderer/box_dynamic") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticFilledRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticFilledRenderer.kt new file mode 100644 index 000000000..e46675435 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticFilledRenderer.kt @@ -0,0 +1,56 @@ +package com.lambda.graphics.renderer.world.core.box + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.world.AbstractEspRenderer +import com.lambda.graphics.renderer.world.DirectionMask +import com.lambda.graphics.renderer.world.DirectionMask.hasDirection +import com.lambda.graphics.renderer.world.core.IESPEntry +import com.lambda.graphics.shader.Shader +import com.lambda.util.primitives.extension.max +import com.lambda.util.primitives.extension.min +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d +import java.awt.Color + +class StaticFilledRenderer : AbstractEspRenderer( + VertexMode.TRIANGLES, shader, false +) { + override fun newEntry(block: IESPEntry.IBoxEntry.Filled.() -> Unit) = Builder(this, block) + + class Builder( + override val owner: StaticFilledRenderer, + override val updateBlock: IESPEntry.IBoxEntry.Filled.() -> Unit + ) : IESPEntry.IBoxEntry.Filled { + override var box by owner.field(Box.from(Vec3d.ZERO)) + override var sides by owner.field(DirectionMask.ALL) + override var color by owner.field(Color.WHITE) + + override fun build(ctx: IRenderContext) = ctx.use { + val pos1 = box.min + val pos2 = box.max + + ctx.grow(8) + + val blb by lazy { vec3(pos1.x, pos1.y, pos1.z).color(color).end() } + val blf by lazy { vec3(pos1.x, pos1.y, pos2.z).color(color).end() } + val brb by lazy { vec3(pos2.x, pos1.y, pos1.z).color(color).end() } + val brf by lazy { vec3(pos2.x, pos1.y, pos2.z).color(color).end() } + val tlb by lazy { vec3(pos1.x, pos2.y, pos1.z).color(color).end() } + val tlf by lazy { vec3(pos1.x, pos2.y, pos2.z).color(color).end() } + val trb by lazy { vec3(pos2.x, pos2.y, pos1.z).color(color).end() } + val trf by lazy { vec3(pos2.x, pos2.y, pos2.z).color(color).end() } + + if (sides.hasDirection(DirectionMask.EAST)) putQuad(brb, brf, trf, trb) + if (sides.hasDirection(DirectionMask.WEST)) putQuad(blb, blf, tlf, tlb) + if (sides.hasDirection(DirectionMask.UP)) putQuad(tlb, tlf, trf, trb) + if (sides.hasDirection(DirectionMask.DOWN)) putQuad(blb, brb, brf, blf) + if (sides.hasDirection(DirectionMask.SOUTH)) putQuad(blf, brf, trf, tlf) + if (sides.hasDirection(DirectionMask.NORTH)) putQuad(blb, brb, trb, tlb) + } + } + + companion object { + private val shader = Shader("renderer/pos_color", "renderer/box_static") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticOutlineRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticOutlineRenderer.kt new file mode 100644 index 000000000..6160c3efa --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/box/StaticOutlineRenderer.kt @@ -0,0 +1,78 @@ +package com.lambda.graphics.renderer.world.core.box + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.world.AbstractEspRenderer +import com.lambda.graphics.renderer.world.DirectionMask +import com.lambda.graphics.renderer.world.DirectionMask.DOWN +import com.lambda.graphics.renderer.world.DirectionMask.EAST +import com.lambda.graphics.renderer.world.DirectionMask.NORTH +import com.lambda.graphics.renderer.world.DirectionMask.SOUTH +import com.lambda.graphics.renderer.world.DirectionMask.UP +import com.lambda.graphics.renderer.world.DirectionMask.WEST +import com.lambda.graphics.renderer.world.DirectionMask.hasDirection +import com.lambda.graphics.renderer.world.core.IESPEntry +import com.lambda.graphics.shader.Shader +import com.lambda.util.primitives.extension.max +import com.lambda.util.primitives.extension.min +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d +import java.awt.Color + +class StaticOutlineRenderer : AbstractEspRenderer( + VertexMode.LINES, shader, false +) { + override fun newEntry(block: IESPEntry.IBoxEntry.Outline.() -> Unit) = Builder(this, block) + + class Builder( + override val owner: StaticOutlineRenderer, + override val updateBlock: IESPEntry.IBoxEntry.Outline.() -> Unit + ) : IESPEntry.IBoxEntry.Outline { + override var box by owner.field(Box.from(Vec3d.ZERO)) + override var sides by owner.field(DirectionMask.ALL) + override var color by owner.field(Color.WHITE) + override var outlineMode by owner.field(DirectionMask.OutlineMode.OR) + + override fun build(ctx: IRenderContext) = ctx.use { + val pos1 = box.min + val pos2 = box.max + + ctx.grow(8) + + val blb by lazy { vec3(pos1.x, pos1.y, pos1.z).color(color).end() } + val blf by lazy { vec3(pos1.x, pos1.y, pos2.z).color(color).end() } + val brb by lazy { vec3(pos2.x, pos1.y, pos1.z).color(color).end() } + val brf by lazy { vec3(pos2.x, pos1.y, pos2.z).color(color).end() } + val tlb by lazy { vec3(pos1.x, pos2.y, pos1.z).color(color).end() } + val tlf by lazy { vec3(pos1.x, pos2.y, pos2.z).color(color).end() } + val trb by lazy { vec3(pos2.x, pos2.y, pos1.z).color(color).end() } + val trf by lazy { vec3(pos2.x, pos2.y, pos2.z).color(color).end() } + + val hasEast = sides.hasDirection(EAST) + val hasWest = sides.hasDirection(WEST) + val hasUp = sides.hasDirection(UP) + val hasDown = sides.hasDirection(DOWN) + val hasSouth = sides.hasDirection(SOUTH) + val hasNorth = sides.hasDirection(NORTH) + + if (outlineMode.check(hasUp, hasNorth)) putLine(tlb, trb) + if (outlineMode.check(hasUp, hasSouth)) putLine(tlf, trf) + if (outlineMode.check(hasUp, hasWest)) putLine(tlb, tlf) + if (outlineMode.check(hasUp, hasEast)) putLine(trf, trb) + + if (outlineMode.check(hasDown, hasNorth)) putLine(blb, brb) + if (outlineMode.check(hasDown, hasSouth)) putLine(blf, brf) + if (outlineMode.check(hasDown, hasWest)) putLine(blb, blf) + if (outlineMode.check(hasDown, hasEast)) putLine(brb, brf) + + if (outlineMode.check(hasWest, hasNorth)) putLine(tlb, blb) + if (outlineMode.check(hasNorth, hasEast)) putLine(trb, brb) + if (outlineMode.check(hasEast, hasSouth)) putLine(trf, brf) + if (outlineMode.check(hasSouth, hasWest)) putLine(tlf, blf) + } + } + + companion object { + private val shader = Shader("renderer/pos_color", "renderer/box_static") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/DynamicTracerRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/DynamicTracerRenderer.kt new file mode 100644 index 000000000..d63eaece5 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/DynamicTracerRenderer.kt @@ -0,0 +1,45 @@ +package com.lambda.graphics.renderer.world.core.tracer + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.world.AbstractEspRenderer +import com.lambda.graphics.renderer.world.core.IESPEntry +import com.lambda.graphics.shader.Shader +import net.minecraft.util.math.Vec3d +import java.awt.Color + +class DynamicTracerRenderer : AbstractEspRenderer( + VertexMode.LINES, shader, true +) { + override fun newEntry(block: IESPEntry.ITracerEntry.() -> Unit) = Builder(this, block) + + class Builder( + override val owner: DynamicTracerRenderer, + override val updateBlock: IESPEntry.ITracerEntry.() -> Unit + ) : IESPEntry.ITracerEntry { + private var prevPos by owner.field(Vec3d.ZERO) + override var position by owner.field(Vec3d.ZERO) + + override var color by owner.field(Color.WHITE) + + init { + update() + prevPos = position + } + + override fun update() { + prevPos = position + super.update() + } + + override fun build(ctx: IRenderContext) = ctx.use { + // Each other vertex is moved into the center of the screen (provided by shader) + val i = vec3(prevPos.x, prevPos.y, prevPos.z).vec3(position.x, position.y, position.z).color(color).end() + putLine(i, i) + } + } + + companion object { + private val shader = Shader("renderer/pos_color", "renderer/tracer_dynamic") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/StaticTracerRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/StaticTracerRenderer.kt new file mode 100644 index 000000000..9ac61bc93 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/world/core/tracer/StaticTracerRenderer.kt @@ -0,0 +1,33 @@ +package com.lambda.graphics.renderer.world.core.tracer + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.buffer.vao.vertex.VertexMode +import com.lambda.graphics.renderer.world.AbstractEspRenderer +import com.lambda.graphics.renderer.world.core.IESPEntry +import com.lambda.graphics.shader.Shader +import net.minecraft.util.math.Vec3d +import java.awt.Color + +class StaticTracerRenderer : AbstractEspRenderer( + VertexMode.LINES, shader, false +) { + override fun newEntry(block: IESPEntry.ITracerEntry.() -> Unit) = Builder(this, block) + + class Builder( + override val owner: StaticTracerRenderer, + override val updateBlock: IESPEntry.ITracerEntry.() -> Unit + ) : IESPEntry.ITracerEntry { + override var position by owner.field(Vec3d.ZERO!!) + override var color by owner.field(Color.WHITE!!) + + override fun build(ctx: IRenderContext) = ctx.use { + // Each other vertex is moved into the center of the screen (provided by shader) + val i = vec3(position.x, position.y, position.z).color(color).end() + putLine(i, i) + } + } + + companion object { + private val shader = Shader("renderer/pos_color", "renderer/tracer_static") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt new file mode 100644 index 000000000..26b99c74f --- /dev/null +++ b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt @@ -0,0 +1,51 @@ +package com.lambda.module.modules.render + +import com.lambda.Lambda.mc +import com.lambda.event.events.RenderEvent +import com.lambda.event.events.TickEvent +import com.lambda.event.listener.SafeListener.Companion.listener +import com.lambda.graphics.renderer.world.DirectionMask.mask +import com.lambda.graphics.renderer.world.core.box.DynamicFilledRenderer +import com.lambda.graphics.renderer.world.core.box.DynamicOutlineRenderer +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag +import com.lambda.util.math.ColorUtils.a +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.toIntSign +import com.lambda.util.world.raycast.RayCastUtils.blockResult +import net.minecraft.util.math.Box +import java.awt.Color + +object RenderTest : Module( + name = "RenderTest", + description = "RenderTest", + tag = ModuleTag.RENDER +) { + private val filled = DynamicFilledRenderer() + private val outline = DynamicOutlineRenderer() + private val color = Color(60, 200, 60) + + init { + filled.build { + val flag = mc.crosshairTarget?.blockResult?.blockPos?.let { box = Box(it) } != null + color = this@RenderTest.color.setAlpha((color.a + flag.toIntSign() * 0.05).coerceAtMost(0.2)) + } + + outline.build { + val block = mc.crosshairTarget?.blockResult + val flag = block?.blockPos?.let { box = Box(it) } != null + color = this@RenderTest.color.setAlpha(color.a + flag.toIntSign() * 0.2) + sides = block?.side?.mask ?: sides + } + + listener { + filled.update() + outline.update() + } + + listener { + filled.render() + outline.render() + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/primitives/extension/Box.kt b/common/src/main/kotlin/com/lambda/util/primitives/extension/Box.kt new file mode 100644 index 000000000..8afe25f01 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/util/primitives/extension/Box.kt @@ -0,0 +1,8 @@ +package com.lambda.util.primitives.extension + +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d + +val Box.min get() = Vec3d(minX, minY, minZ) + +val Box.max get() = Vec3d(maxX, maxY, maxZ) \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt b/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt index 7c61d51e4..86ed6f794 100644 --- a/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt +++ b/common/src/main/kotlin/com/lambda/util/primitives/extension/Entity.kt @@ -2,29 +2,13 @@ package com.lambda.util.primitives.extension import com.lambda.interaction.rotation.Rotation import com.lambda.util.math.MathUtils.lerp -import net.minecraft.client.MinecraftClient import net.minecraft.entity.Entity -import net.minecraft.util.math.Box import net.minecraft.util.math.Vec3d val Entity.prevPos get() = Vec3d(prevX, prevY, prevZ) -val Entity.interpolatedPos - get() = lerp(prevPos, pos, MinecraftClient.getInstance().partialTicks) - val Entity.rotation get() = Rotation(yaw, pitch) -val Entity.interpolatedBox: Box - get() { - val box = boundingBox - val xw = (box.maxX - box.minX) * 0.5 - val yw = box.maxY - box.minY - val zw = (box.maxZ - box.minZ) * 0.5 - - val pos = interpolatedPos - return Box(pos.x - xw, pos.y, pos.z - zw, pos.x + xw, pos.y + yw, pos.z + zw) - } - fun Vec3d.interpolate(other: Vec3d, t: Double) = lerp(this, other, t) \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/pos_color.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/pos_color.frag new file mode 100644 index 000000000..71f50775d --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/pos_color.frag @@ -0,0 +1,8 @@ +#version 330 core + +in vec4 v_Color; +out vec4 color; + +void main() { + color = v_Color; +} \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_dynamic.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_dynamic.vert new file mode 100644 index 000000000..7061f3df9 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_dynamic.vert @@ -0,0 +1,20 @@ +#version 330 core + +layout (location = 0) in vec3 pos1; +layout (location = 1) in vec3 pos2; +layout (location = 2) in vec4 color; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +uniform float u_TickDelta; +uniform vec3 u_CameraPosition; + +out vec4 v_Color; + +#define VERTEX_POSITION mix(pos1, pos2, u_TickDelta) - u_CameraPosition + +void main() { + gl_Position = u_Projection * u_ModelView * vec4(VERTEX_POSITION, 1.0); + v_Color = color; +} diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_static.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_static.vert new file mode 100644 index 000000000..8ab8e8660 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/box_static.vert @@ -0,0 +1,18 @@ +#version 330 core + +layout (location = 0) in vec3 pos; +layout (location = 1) in vec4 color; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +uniform vec3 u_CameraPosition; + +out vec4 v_Color; + +#define VERTEX_POSITION pos - u_CameraPosition + +void main() { + gl_Position = u_Projection * u_ModelView * vec4(VERTEX_POSITION, 1.0); + v_Color = color; +} diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_dynamic.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_dynamic.vert new file mode 100644 index 000000000..2ec823a2e --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_dynamic.vert @@ -0,0 +1,23 @@ +#version 330 core + +layout (location = 0) in vec3 pos1; +layout (location = 1) in vec3 pos2; +layout (location = 2) in vec4 color; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +uniform float u_TickDelta; +uniform vec3 u_CameraPosition; + +out vec4 v_Color; + +#define VERTEX_POSITION mix(pos1, pos2, u_TickDelta) - u_CameraPosition + +#define SCREEN_CENTER vec4(0.0, 0.0, 0.0, 1.0) +#define PROJECTED u_Projection * u_ModelView * vec4(VERTEX_POSITION, 1.0) + +void main() { + gl_Position = gl_VertexID % 2 == 0 ? SCREEN_CENTER : PROJECTED; + v_Color = color; +} diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_static.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_static.vert new file mode 100644 index 000000000..838117d38 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/tracer_static.vert @@ -0,0 +1,21 @@ +#version 330 core + +layout (location = 0) in vec3 pos; +layout (location = 1) in vec4 color; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +uniform vec3 u_CameraPosition; + +out vec4 v_Color; + +#define VERTEX_POSITION pos - u_CameraPosition + +#define SCREEN_CENTER vec4(0.0, 0.0, 0.0, 1.0) +#define PROJECTED u_Projection * u_ModelView * vec4(VERTEX_POSITION, 1.0) + +void main() { + gl_Position = gl_VertexID % 2 == 0 ? SCREEN_CENTER : PROJECTED; + v_Color = color; +} From f53baca77f9d828a7d82a53a877c49d583b0fbe9 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Wed, 1 May 2024 17:44:46 +0300 Subject: [PATCH 32/63] Refucktor --- .../com/lambda/module/modules/render/FakePlayer.kt | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt b/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt index 0a824757e..2191d1c0e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/FakePlayer.kt @@ -15,19 +15,14 @@ object FakePlayer : Module( private val playerName by setting("Name", "Steve") private val uuid = UUID.fromString("41C82C87-7AfB-4024-BA57-13D2C99CAE77") - private var fakePlayer: OtherClientPlayerEntity? = null init { onEnable { - OtherClientPlayerEntity(world, GameProfile(uuid, playerName)).apply { - copyFrom(player) - id = -2024-4-20 - - fakePlayer = this - } - - world.addEntity(fakePlayer) + fakePlayer = OtherClientPlayerEntity(world, GameProfile(uuid, playerName)) + .apply(player::copyFrom) + .apply(world::addEntity) + .apply { id = -2024-4-20 } } onDisable { From 1ff8730e6545a9215cda82eb4e3b47f40bc993f9 Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Wed, 1 May 2024 18:58:35 -0400 Subject: [PATCH 33/63] Added position iterator --- .../com/lambda/util/world/WorldUtils.kt | 112 +++++++++++------- 1 file changed, 68 insertions(+), 44 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt b/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt index e7fa43107..c57cc358b 100644 --- a/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt @@ -42,20 +42,23 @@ object WorldUtils { /** * Gets the closest entity of type [T] within a specified range. * + * Because we don't want to troll the CPU speculative execution, we only use the [getFastEntities] function. + * This should not be an issue as the performance of this function is optimized for small distances. + * * @param pos The position to search from. * @param range The maximum distance to search for entities. - * @param predicate Optional predicate to filter entities. + * @param predicate Predicate to filter entities. * @return The first entity of type [T] that is closest to the position within the specified range. */ inline fun SafeContext.getClosestEntity( - pos: Vec3d = player.pos, - range: Double = 6.0, - noinline predicate: (T) -> Boolean = { true }, + pos: Vec3d, + range: Double, + predicate: (T) -> Boolean = { true }, ): T? { var closest: T? = null var closestDistance = Double.MAX_VALUE - val comparator = { entity: T -> + val comparator = { entity: T, _: Int -> val distance = pos.squaredDistanceTo(entity.pos) if (distance < closestDistance) { closest = entity @@ -63,9 +66,7 @@ object WorldUtils { } } - // Speculative execution trolling - if (range > 64) getEntities(null, comparator, predicate) - else getFastEntities(pos, range, null, comparator, predicate) + getFastEntities(pos, range, null, comparator, predicate) return closest } @@ -95,17 +96,15 @@ object WorldUtils { * @param pos The position to search from. * @param distance The maximum distance to search for entities. * @param pointer The mutable list to store the entities in. - * @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties. - * @param iterator Optional iterator to perform operations on each entity. - * @return A list of entities of type [T] within the specified distance from the position, excluding the player. - * + * @param iterator Iterator to perform operations on each entity. + * @param predicate Predicate to filter entities. */ inline fun SafeContext.getFastEntities( pos: Vec3d, distance: Double, pointer: MutableList? = null, - noinline iterator: (T) -> Unit = { }, - noinline predicate: (T) -> Boolean = { true }, + iterator: (T, Int) -> Unit = { _, _ -> }, + predicate: (T) -> Boolean = { true }, ) { val chunks = ceil(distance / 16).toInt() val sectionX = pos.x.toInt() shr 4 @@ -118,9 +117,13 @@ object WorldUtils { for (x in sectionX - chunks..sectionX + chunks) { for (y in sectionY - chunks..sectionY + chunks) { for (z in sectionZ - chunks..sectionZ + chunks) { - val section = world.entityManager.cache.findTrackingSection(ChunkSectionPos.asLong(x, y, z)) ?: continue + val section = + world.entityManager.cache.findTrackingSection(ChunkSectionPos.asLong(x, y, z)) ?: continue + section.collection.filterPointer(pointer, iterator) { entity -> - entity != player && entity.squaredDistanceTo(pos) <= distance * distance && predicate(entity) + entity != player && + entity.squaredDistanceTo(pos) <= distance * distance && + predicate(entity) } } } @@ -134,16 +137,20 @@ object WorldUtils { * [getFastEntities], it traverses all entities in the world to find matches, while also excluding the player entity. * * @param pointer The mutable list to store the entities in. - * @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties. - * @param iterator Optional iterator to perform operations on each entity. + * @param iterator Iterator to perform operations on each entity. + * @param predicate Predicate to filter entities. */ inline fun SafeContext.getEntities( + pos: Vec3d, + distance: Double, pointer: MutableList? = null, - noinline iterator: (T) -> Unit = { }, - noinline predicate: (T) -> Boolean = { true }, + iterator: (T, Int) -> Unit = { _, _ -> }, + predicate: (T) -> Boolean = { true }, ) { world.entities.filterPointer(pointer, iterator) { entity -> - entity != player && predicate(entity) + entity != player && + entity.squaredDistanceTo(pos) <= distance * distance && + predicate(entity) } } @@ -155,18 +162,16 @@ object WorldUtils { * @param rangeY The maximum distance to search for entities in the y-axis. * @param rangeZ The maximum distance to search for entities in the z-axis. * @param pointer The mutable list to store the positions in. - * @param predicate Optional predicate to filter the blocks. - * @param iterator Optional iterator to perform operations on each block. - * - * @return A list of positions that match the predicate. + * @param iterator Iterator to perform operations on each block. + * @param predicate Predicate to filter the blocks. */ - fun SafeContext.searchBlock( + inline fun SafeContext.searchBlock( pos: Vec3i, rangeX: Int, rangeY: Int, rangeZ: Int, pointer: MutableList? = null, - iterator: (Block) -> Unit = { }, + iterator: (Block, Int) -> Unit = { _, _ -> }, predicate: (Block) -> Boolean = { true }, ) = searchBlock(pos, Vec3i(rangeX, rangeY, rangeZ), pointer, iterator, predicate) @@ -176,23 +181,23 @@ object WorldUtils { * @param pos The position to search from. * @param range The maximum distance to search for entities in each axis. * @param pointer The mutable list to store the positions in. - * @param predicate Optional predicate to filter the blocks. - * @param iterator Optional iterator to perform operations on each block. - * - * @return A list of positions that match the predicate. + * @param iterator Iterator to perform operations on each block. + * @param predicate Predicate to filter the blocks. */ - fun SafeContext.searchBlock( + inline fun SafeContext.searchBlock( pos: Vec3i, range: Vec3i, pointer: MutableList? = null, - iterator: (Block) -> Unit = { }, + iterator: (Block, Int) -> Unit = { _, _ -> }, predicate: (Block) -> Boolean = { true }, ) { - // TODO: Implement O(1) pointer mapping - BlockPos.iterateOutwards(BlockPos(pos), range.x, range.y, range.z) - .map { world.getBlockState(it).block }.filterPointer(pointer, iterator) { block -> - predicate(block) + iteratePositions(pos, range) { blockPos, index -> + val block = world.getBlockState(blockPos).block + if (predicate(block)) { + pointer?.add(block) + iterator(block, index) } + } } /** @@ -201,20 +206,39 @@ object WorldUtils { * @param pos The position to search from. * @param range The maximum distance to search for fluids in each axis. * @param pointer The mutable list to store the positions in. - * @param predicate Optional predicate to filter the fluids. - * @param iterator Optional iterator to perform operations on each fluid. + * @param iterator Iterator to perform operations on each fluid. + * @param predicate Predicate to filter the fluids. */ inline fun SafeContext.searchFluid( pos: Vec3i, range: Vec3i, pointer: MutableList? = null, - noinline predicate: (T) -> Boolean = { true }, - noinline iterator: (T) -> Unit = { }, + iterator: (T, Int) -> Unit = { _, _ -> }, + predicate: (T) -> Boolean = { true }, + ) { + iteratePositions(pos, range) { blockPos, index -> + val fluid = world.getFluidState(blockPos).fluid as? T ?: return@iteratePositions + if (predicate(fluid)) { + pointer?.add(fluid) + iterator(fluid, index) + } + } + } + + /** + * Iterates over all positions within the specified range. + * @param pos The position to start from. + * @param range The maximum distance to search for entities in each axis. + * @param iterator Iterator to perform operations on each position. + */ + inline fun SafeContext.iteratePositions( + pos: Vec3i, + range: Vec3i, + iterator: (BlockPos, Int) -> Unit, ) { - // TODO: Implement O(1) pointer mapping BlockPos.iterateOutwards(BlockPos(pos), range.x, range.y, range.z) - .map { world.getFluidState(it).fluid }.filterPointer(pointer, iterator) { fluid -> - predicate(fluid) + .forEachIndexed { index, blockPos -> + iterator(blockPos, index) } } } From 6b01d57dca119854d0997df38abbd1e8e46dbefe Mon Sep 17 00:00:00 2001 From: Kamigen <46357922+Edouard127@users.noreply.github.com> Date: Wed, 1 May 2024 19:13:38 -0400 Subject: [PATCH 34/63] Revert "Added position iterator" This reverts commit 1ff8730e6545a9215cda82eb4e3b47f40bc993f9. --- .../com/lambda/util/world/WorldUtils.kt | 112 +++++++----------- 1 file changed, 44 insertions(+), 68 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt b/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt index c57cc358b..e7fa43107 100644 --- a/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt @@ -42,23 +42,20 @@ object WorldUtils { /** * Gets the closest entity of type [T] within a specified range. * - * Because we don't want to troll the CPU speculative execution, we only use the [getFastEntities] function. - * This should not be an issue as the performance of this function is optimized for small distances. - * * @param pos The position to search from. * @param range The maximum distance to search for entities. - * @param predicate Predicate to filter entities. + * @param predicate Optional predicate to filter entities. * @return The first entity of type [T] that is closest to the position within the specified range. */ inline fun SafeContext.getClosestEntity( - pos: Vec3d, - range: Double, - predicate: (T) -> Boolean = { true }, + pos: Vec3d = player.pos, + range: Double = 6.0, + noinline predicate: (T) -> Boolean = { true }, ): T? { var closest: T? = null var closestDistance = Double.MAX_VALUE - val comparator = { entity: T, _: Int -> + val comparator = { entity: T -> val distance = pos.squaredDistanceTo(entity.pos) if (distance < closestDistance) { closest = entity @@ -66,7 +63,9 @@ object WorldUtils { } } - getFastEntities(pos, range, null, comparator, predicate) + // Speculative execution trolling + if (range > 64) getEntities(null, comparator, predicate) + else getFastEntities(pos, range, null, comparator, predicate) return closest } @@ -96,15 +95,17 @@ object WorldUtils { * @param pos The position to search from. * @param distance The maximum distance to search for entities. * @param pointer The mutable list to store the entities in. - * @param iterator Iterator to perform operations on each entity. - * @param predicate Predicate to filter entities. + * @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties. + * @param iterator Optional iterator to perform operations on each entity. + * @return A list of entities of type [T] within the specified distance from the position, excluding the player. + * */ inline fun SafeContext.getFastEntities( pos: Vec3d, distance: Double, pointer: MutableList? = null, - iterator: (T, Int) -> Unit = { _, _ -> }, - predicate: (T) -> Boolean = { true }, + noinline iterator: (T) -> Unit = { }, + noinline predicate: (T) -> Boolean = { true }, ) { val chunks = ceil(distance / 16).toInt() val sectionX = pos.x.toInt() shr 4 @@ -117,13 +118,9 @@ object WorldUtils { for (x in sectionX - chunks..sectionX + chunks) { for (y in sectionY - chunks..sectionY + chunks) { for (z in sectionZ - chunks..sectionZ + chunks) { - val section = - world.entityManager.cache.findTrackingSection(ChunkSectionPos.asLong(x, y, z)) ?: continue - + val section = world.entityManager.cache.findTrackingSection(ChunkSectionPos.asLong(x, y, z)) ?: continue section.collection.filterPointer(pointer, iterator) { entity -> - entity != player && - entity.squaredDistanceTo(pos) <= distance * distance && - predicate(entity) + entity != player && entity.squaredDistanceTo(pos) <= distance * distance && predicate(entity) } } } @@ -137,20 +134,16 @@ object WorldUtils { * [getFastEntities], it traverses all entities in the world to find matches, while also excluding the player entity. * * @param pointer The mutable list to store the entities in. - * @param iterator Iterator to perform operations on each entity. - * @param predicate Predicate to filter entities. + * @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties. + * @param iterator Optional iterator to perform operations on each entity. */ inline fun SafeContext.getEntities( - pos: Vec3d, - distance: Double, pointer: MutableList? = null, - iterator: (T, Int) -> Unit = { _, _ -> }, - predicate: (T) -> Boolean = { true }, + noinline iterator: (T) -> Unit = { }, + noinline predicate: (T) -> Boolean = { true }, ) { world.entities.filterPointer(pointer, iterator) { entity -> - entity != player && - entity.squaredDistanceTo(pos) <= distance * distance && - predicate(entity) + entity != player && predicate(entity) } } @@ -162,16 +155,18 @@ object WorldUtils { * @param rangeY The maximum distance to search for entities in the y-axis. * @param rangeZ The maximum distance to search for entities in the z-axis. * @param pointer The mutable list to store the positions in. - * @param iterator Iterator to perform operations on each block. - * @param predicate Predicate to filter the blocks. + * @param predicate Optional predicate to filter the blocks. + * @param iterator Optional iterator to perform operations on each block. + * + * @return A list of positions that match the predicate. */ - inline fun SafeContext.searchBlock( + fun SafeContext.searchBlock( pos: Vec3i, rangeX: Int, rangeY: Int, rangeZ: Int, pointer: MutableList? = null, - iterator: (Block, Int) -> Unit = { _, _ -> }, + iterator: (Block) -> Unit = { }, predicate: (Block) -> Boolean = { true }, ) = searchBlock(pos, Vec3i(rangeX, rangeY, rangeZ), pointer, iterator, predicate) @@ -181,23 +176,23 @@ object WorldUtils { * @param pos The position to search from. * @param range The maximum distance to search for entities in each axis. * @param pointer The mutable list to store the positions in. - * @param iterator Iterator to perform operations on each block. - * @param predicate Predicate to filter the blocks. + * @param predicate Optional predicate to filter the blocks. + * @param iterator Optional iterator to perform operations on each block. + * + * @return A list of positions that match the predicate. */ - inline fun SafeContext.searchBlock( + fun SafeContext.searchBlock( pos: Vec3i, range: Vec3i, pointer: MutableList? = null, - iterator: (Block, Int) -> Unit = { _, _ -> }, + iterator: (Block) -> Unit = { }, predicate: (Block) -> Boolean = { true }, ) { - iteratePositions(pos, range) { blockPos, index -> - val block = world.getBlockState(blockPos).block - if (predicate(block)) { - pointer?.add(block) - iterator(block, index) + // TODO: Implement O(1) pointer mapping + BlockPos.iterateOutwards(BlockPos(pos), range.x, range.y, range.z) + .map { world.getBlockState(it).block }.filterPointer(pointer, iterator) { block -> + predicate(block) } - } } /** @@ -206,39 +201,20 @@ object WorldUtils { * @param pos The position to search from. * @param range The maximum distance to search for fluids in each axis. * @param pointer The mutable list to store the positions in. - * @param iterator Iterator to perform operations on each fluid. - * @param predicate Predicate to filter the fluids. + * @param predicate Optional predicate to filter the fluids. + * @param iterator Optional iterator to perform operations on each fluid. */ inline fun SafeContext.searchFluid( pos: Vec3i, range: Vec3i, pointer: MutableList? = null, - iterator: (T, Int) -> Unit = { _, _ -> }, - predicate: (T) -> Boolean = { true }, - ) { - iteratePositions(pos, range) { blockPos, index -> - val fluid = world.getFluidState(blockPos).fluid as? T ?: return@iteratePositions - if (predicate(fluid)) { - pointer?.add(fluid) - iterator(fluid, index) - } - } - } - - /** - * Iterates over all positions within the specified range. - * @param pos The position to start from. - * @param range The maximum distance to search for entities in each axis. - * @param iterator Iterator to perform operations on each position. - */ - inline fun SafeContext.iteratePositions( - pos: Vec3i, - range: Vec3i, - iterator: (BlockPos, Int) -> Unit, + noinline predicate: (T) -> Boolean = { true }, + noinline iterator: (T) -> Unit = { }, ) { + // TODO: Implement O(1) pointer mapping BlockPos.iterateOutwards(BlockPos(pos), range.x, range.y, range.z) - .forEachIndexed { index, blockPos -> - iterator(blockPos, index) + .map { world.getFluidState(it).fluid }.filterPointer(pointer, iterator) { fluid -> + predicate(fluid) } } } From 13e1ca23b55646f360dbed9c7345b8507595939d Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 13:38:26 +0300 Subject: [PATCH 35/63] Scissor fix --- common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt index 00d246d2a..5b97b2c22 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Scissor.kt @@ -13,7 +13,7 @@ object Scissor { fun scissor(rect: Rect, block: () -> Unit) { // clamp corners so children scissor box can't overlap parent - val processed = stack.lastOrNull()?.let { rect.clamp(it) } ?: rect + val processed = stack.lastOrNull()?.let(rect::clamp) ?: rect registerScissor(processed, block) } @@ -42,6 +42,7 @@ object Scissor { val y = mc.window.framebufferHeight - pos1.y - height + glEnable(GL_SCISSOR_TEST) glScissor( pos1.x.floorToInt(), y.floorToInt(), From 67b2d999a2bc23716e7d3d64c8a26e8940772655 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 13:39:03 +0300 Subject: [PATCH 36/63] Children system rework --- .../kotlin/com/lambda/gui/api/GuiEvent.kt | 17 +++ .../kotlin/com/lambda/gui/api/LambdaGui.kt | 18 +-- .../gui/api/component/InteractiveComponent.kt | 31 ++--- .../lambda/gui/api/component/ListWindow.kt | 20 +++ .../gui/api/component/WindowComponent.kt | 118 ++++++++---------- .../api/component/button/ButtonComponent.kt | 31 +++-- .../gui/api/component/button/ListButton.kt | 8 +- .../gui/api/component/core/IComponent.kt | 21 +--- .../api/component/core/list/ChildComponent.kt | 9 +- .../gui/api/component/core/list/ChildLayer.kt | 42 +++++++ .../api/component/core/list/IListComponent.kt | 53 -------- .../gui/impl/clickgui/AbstractClickGui.kt | 79 ++++++------ .../gui/impl/clickgui/LambdaClickGui.kt | 31 +++-- .../gui/impl/clickgui/buttons/ModuleButton.kt | 2 +- .../gui/impl/clickgui/windows/ModuleWindow.kt | 20 +-- .../windows/tag/CustomModuleWindow.kt | 32 ++--- .../impl/clickgui/windows/tag/TagWindow.kt | 2 +- 17 files changed, 266 insertions(+), 268 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/api/GuiEvent.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt delete mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt diff --git a/common/src/main/kotlin/com/lambda/gui/api/GuiEvent.kt b/common/src/main/kotlin/com/lambda/gui/api/GuiEvent.kt new file mode 100644 index 000000000..a9daccdac --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/GuiEvent.kt @@ -0,0 +1,17 @@ +package com.lambda.gui.api + +import com.lambda.event.Event +import com.lambda.util.KeyCode +import com.lambda.util.Mouse +import com.lambda.util.math.Vec2d + +abstract class GuiEvent : Event { + class Show : GuiEvent() + class Hide : GuiEvent() + class Tick : GuiEvent() + class Render : GuiEvent() + class KeyPress(val key: KeyCode) : GuiEvent() + class CharTyped(val char: Char) : GuiEvent() + class MouseClick(val button: Mouse.Button, val action: Mouse.Action, val mouse: Vec2d) : GuiEvent() + class MouseMove(val mouse: Vec2d) : GuiEvent() +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt index ccf69ac78..f4ceab393 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt @@ -28,12 +28,12 @@ abstract class LambdaGui( private val renderListener = UnsafeListener(0, this, false) { event -> event as RenderEvent.GUI.Scaled screenSize = event.screenSize - onRender() + onEvent(GuiEvent.Render()) } private val tickListener = UnsafeListener(0, this, false) { animation.tick() - onTick() + onEvent(GuiEvent.Tick()) } /** @@ -50,7 +50,7 @@ abstract class LambdaGui( } final override fun onDisplayed() { - onShow() + onEvent(GuiEvent.Show()) with(syncListeners) { subscribe(renderListener) @@ -59,7 +59,7 @@ abstract class LambdaGui( } final override fun removed() { - onHide() + onEvent(GuiEvent.Hide()) // quick crashfix (is there any other way to prevent gui being closed twice?) mc.currentScreen = null @@ -77,7 +77,7 @@ abstract class LambdaGui( } final override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - onKey(KeyCode(keyCode)) + onEvent(GuiEvent.KeyPress(KeyCode(keyCode))) if (keyCode == KeyCode.Escape.key) { close() @@ -87,22 +87,22 @@ abstract class LambdaGui( } final override fun charTyped(chr: Char, modifiers: Int): Boolean { - onChar(chr) + onEvent(GuiEvent.CharTyped(chr)) return true } final override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - onMouseClick(Mouse.Button(button), Mouse.Action.Click, rescaleMouse(mouseX, mouseY)) + onEvent(GuiEvent.MouseClick(Mouse.Button(button), Mouse.Action.Click, rescaleMouse(mouseX, mouseY))) return true } final override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { - onMouseClick(Mouse.Button(button), Mouse.Action.Release, rescaleMouse(mouseX, mouseY)) + onEvent(GuiEvent.MouseClick(Mouse.Button(button), Mouse.Action.Release, rescaleMouse(mouseX, mouseY))) return true } final override fun mouseMoved(mouseX: Double, mouseY: Double) { - onMouseMove(rescaleMouse(mouseX, mouseY)) + onEvent(GuiEvent.MouseMove(rescaleMouse(mouseX, mouseY))) } final override fun shouldPause() = false diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt index 0bd6e7555..31c91a611 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt @@ -1,9 +1,9 @@ package com.lambda.gui.api.component +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.IComponent import com.lambda.gui.api.component.core.IRectComponent import com.lambda.util.Mouse -import com.lambda.util.math.Vec2d abstract class InteractiveComponent : IComponent, IRectComponent { protected var hovered = false @@ -20,21 +20,24 @@ abstract class InteractiveComponent : IComponent, IRectComponent { protected open fun onPress() {} protected open fun onRelease() {} - override fun onShow() { - hovered = false - pressed = false - } + override fun onEvent(e: GuiEvent) { + when (e) { + is GuiEvent.Show -> { + hovered = false + pressed = false + } - override fun onMouseMove(mouse: Vec2d) { - hovered = rect.contains(mouse) - } + is GuiEvent.MouseMove -> { + hovered = rect.contains(e.mouse) + } + + is GuiEvent.MouseClick -> { + activeMouseButton = e.button.takeUnless { + it.isMainButton && e.action == Mouse.Action.Click + } - override fun onMouseClick( - button: Mouse.Button, action: Mouse.Action, mouse: Vec2d - ) { - activeMouseButton = button.takeUnless { - it.isMainButton && action == Mouse.Action.Click + pressed = hovered && e.button.isMainButton && e.action == Mouse.Action.Click + } } - pressed = hovered && button.isMainButton && action == Mouse.Action.Click } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt new file mode 100644 index 000000000..60ff72798 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt @@ -0,0 +1,20 @@ +package com.lambda.gui.api.component + +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.button.ListButton +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.module.modules.client.ClickGui + +abstract class ListWindow ( + owner: AbstractClickGui +) : WindowComponent(owner) { + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Tick) { + contentComponents.children.forEachIndexed { i, button -> + button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) + } + } + + super.onEvent(e) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 4b6aabc89..93faab6d6 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -3,14 +3,14 @@ package com.lambda.gui.api.component import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry -import com.lambda.graphics.renderer.immediate.BlurPostProcessor -import com.lambda.gui.api.component.core.list.IListComponent +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.button.ButtonComponent import com.lambda.gui.api.component.core.list.ChildComponent +import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.module.modules.client.ClickGui import com.lambda.module.modules.client.GuiSettings -import com.lambda.util.KeyCode import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.ColorUtils.setAlpha @@ -23,7 +23,7 @@ import kotlin.math.abs abstract class WindowComponent ( final override val owner: AbstractClickGui -) : ChildComponent(), IListComponent { +) : ChildComponent() { abstract val title: String abstract var width: Double @@ -53,7 +53,13 @@ abstract class WindowComponent ( private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) private val renderHeight get() = lerp(0.0, renderHeightAnimation, guiAnimation) - override val children = mutableListOf() + val contentComponents = ChildLayer { child -> + child.rect in contentRect && accessible && isOpen + } + + /*val titleBarComponents = ChildLayer { child -> + child.rect in titleBar && accessible + }*/ // TODO: window close button init { // Background @@ -73,87 +79,63 @@ abstract class WindowComponent ( } } - override fun onShow() { - super.onShow() - super.onShow() - - dragOffset = null - } - - override fun onHide() { - super.onHide() - } - - override fun onTick() { - children.forEach { child -> - child.accessible = child.rect in contentRect && this.accessible - } - - super.onTick() - } - - override fun onRender() { - // TODO: fix blur - // BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) - - layer.assignOffset(position) - subLayer.assignOffset(position) + override fun onEvent(e: GuiEvent) { + super.onEvent(e) - layer.render() - - scissor(contentRect) { - subLayer.apply { - allowEffects = true - render() + when (e) { + is GuiEvent.Show -> { + dragOffset = null } - super.onRender() - } - } - - override fun onMouseMove(mouse: Vec2d) { - dragOffset?.let { - position = mouse - it - } + is GuiEvent.Render -> { + layer.assignOffset(position) + subLayer.assignOffset(position) - super.onMouseMove(mouse) - super.onMouseMove(mouse) - } + // TODO: fix blur + // BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) - override fun onKey(key: KeyCode) { - super.onKey(key) - } + layer.render() - override fun onChar(char: Char) { - super.onChar(char) - } + scissor(contentRect) { + subLayer.apply { + allowEffects = true + render() + } + } + } - override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - super.onMouseClick(button, action, mouse) + is GuiEvent.MouseMove -> { + dragOffset?.let { + position = e.mouse - it + } + } - dragOffset = null + is GuiEvent.MouseClick -> { + dragOffset = null - if (mouse in titleBar && action == Mouse.Action.Click) { - when(button) { - Mouse.Button.Left -> dragOffset = mouse - position - Mouse.Button.Right -> { - // Don't let user spam - val targetHeight = if (isOpen) actualHeight else 0.0 - if (abs(targetHeight - renderHeight) > 1) return + if (e.mouse in titleBar && e.action == Mouse.Action.Click) { + when (e.button) { + Mouse.Button.Left -> dragOffset = e.mouse - position + Mouse.Button.Right -> { + // Don't let user spam + val targetHeight = if (isOpen) actualHeight else 0.0 + if (abs(targetHeight - renderHeight) > 1) return - isOpen = !isOpen + isOpen = !isOpen - if (isOpen) super.onShow() + if (isOpen) contentComponents.onEvent(GuiEvent.Show()) + } + } } } } - super.onMouseClick(button, action, mouse) + contentComponents.onEvent(e) + //titleBarComponents.onEvent(e) } - fun destroy() { + override fun onRemove() { layer.destroy() subLayer.destroy() - children.clear() } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 86efc0c6b..a84b3a149 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -1,6 +1,7 @@ package com.lambda.gui.api.component.button import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.module.modules.client.ClickGui @@ -13,7 +14,9 @@ import com.lambda.util.math.Vec2d import java.awt.Color import kotlin.math.abs -abstract class ButtonComponent(final override val owner: WindowComponent<*>) : ChildComponent() { +abstract class ButtonComponent( + final override val owner: WindowComponent<*> +) : ChildComponent() { abstract val position: Vec2d abstract val size: Vec2d @@ -90,25 +93,21 @@ abstract class ButtonComponent(final override val owner: WindowComponent<*>) : C abstract fun performClickAction(mouse: Mouse.Button) - override fun onShow() { - super.onShow() - reset() - } + override fun onEvent(e: GuiEvent) { + super.onEvent(e) - override fun onHide() { - super.onHide() - reset() - } + when (e) { + is GuiEvent.Show, is GuiEvent.Hide -> reset() - override fun onRelease() { - if (hovered) activeMouseButton?.let(::performClickAction) + is GuiEvent.MouseMove -> { + val time = System.currentTimeMillis() + if (hovered) lastHoveredTime = time + } + } } - override fun onMouseMove(mouse: Vec2d) { - super.onMouseMove(mouse) - - val time = System.currentTimeMillis() - if (hovered) lastHoveredTime = time + override fun onRelease() { + activeMouseButton?.let(::performClickAction) } override fun onRemove() { diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 36cccd6d2..78b434517 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -1,6 +1,7 @@ package com.lambda.gui.api.component.button import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.WindowComponent import com.lambda.module.modules.client.ClickGui import com.lambda.util.math.MathUtils.toInt @@ -14,8 +15,9 @@ abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { private val targetHeightOffset get() = heightOffset * owner.guiAnimation * owner.isOpen.toInt() private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.5) - override fun onShow() { - super.onShow() - renderHeightOffset = 0.0 + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + + if (e is GuiEvent.Show) renderHeightOffset = 0.0 } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt index 7dc3504ae..91c2f2d03 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt @@ -1,23 +1,8 @@ package com.lambda.gui.api.component.core -import com.lambda.util.KeyCode -import com.lambda.util.Mouse -import com.lambda.util.math.Vec2d +import com.lambda.gui.api.GuiEvent interface IComponent { - fun onShow() {} - - fun onHide() {} - - fun onTick() {} - - fun onRender() {} - - fun onKey(key: KeyCode) {} - - fun onChar(char: Char) {} - - fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) {} - - fun onMouseMove(mouse: Vec2d) {} + // TODO: Use event system? + fun onEvent(e: GuiEvent) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index fcc06bc12..2c9805afb 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -1,16 +1,17 @@ package com.lambda.gui.api.component.core.list +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.InteractiveComponent import com.lambda.gui.api.component.core.IComponent -import com.lambda.util.math.Vec2d abstract class ChildComponent : InteractiveComponent() { abstract val owner: IComponent open var accessible = false - override fun onMouseMove(mouse: Vec2d) { - super.onMouseMove(mouse) - hovered = hovered && accessible + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + + if (e is GuiEvent.MouseMove) hovered = hovered && accessible } open fun onAdd() {} diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt new file mode 100644 index 000000000..f2a4c9545 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt @@ -0,0 +1,42 @@ +package com.lambda.gui.api.component.core.list + +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.core.IComponent +import com.lambda.util.Mouse + +open class ChildLayer (val childAccessible: (T) -> Boolean) : IComponent { + val children = mutableListOf() + + fun addChild(child : T) { + children.add(child) + child.onAdd() + } + + fun removeChild(child : T) { + children.remove(child) + child.onRemove() + } + + override fun onEvent(e: GuiEvent) { + children.forEach { child -> + when (e) { + is GuiEvent.Tick -> { + child.accessible = childAccessible(child) + } + + is GuiEvent.KeyPress, is GuiEvent.CharTyped -> { + if (!child.accessible) return@forEach + } + + is GuiEvent.MouseClick -> { + val newAction = if (child.accessible) e.action else Mouse.Action.Release + val newEvent = GuiEvent.MouseClick(e.button, newAction, e.mouse) + child.onEvent(newEvent) + return@forEach + } + } + + child.onEvent(e) + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt deleted file mode 100644 index bf7e6ba3d..000000000 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/IListComponent.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.lambda.gui.api.component.core.list - -import com.lambda.gui.api.component.core.IComponent -import com.lambda.util.KeyCode -import com.lambda.util.Mouse -import com.lambda.util.math.Vec2d - -interface IListComponent : IComponent { - val children: List - - fun isChildAccessible(child: T): Boolean = (child as? ChildComponent)?.accessible ?: true - - override fun onShow() { - children.forEach(IComponent::onShow) - } - - override fun onHide() { - children.forEach(IComponent::onHide) - } - - override fun onTick() { - children.forEach(IComponent::onTick) - } - - override fun onRender() { - children.forEach(IComponent::onRender) - } - - override fun onKey(key: KeyCode) { - children.filter(::isChildAccessible).forEach { child -> - child.onKey(key) - } - } - - override fun onChar(char: Char) { - children.filter(::isChildAccessible).forEach { child -> - child.onChar(char) - } - } - - override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - children.forEach { child -> - val newAction = if (isChildAccessible(child)) action else Mouse.Action.Release - child.onMouseClick(button, newAction, mouse) - } - } - - override fun onMouseMove(mouse: Vec2d) { - children.forEach { child -> - child.onMouseMove(mouse) - } - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 2f2a1e5b5..52138dc3b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -2,62 +2,55 @@ package com.lambda.gui.impl.clickgui import com.lambda.Lambda.mc import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildComponent -import com.lambda.gui.api.component.core.list.IListComponent +import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui -import com.lambda.util.Mouse -import com.lambda.util.math.Vec2d -abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui), IListComponent { - override val children = mutableListOf() - protected var hoveredChild: ChildComponent? = null +abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui) { + protected val windows = ChildLayer> { child -> + child == activeWindow && !closing + } + + protected var activeWindow: WindowComponent<*>? = null private var closing = false var guiAnimation by animation.exp(0.0, 1.0, { if (closing) ClickGui.closeSpeed else ClickGui.openSpeed }) { !closing }; private set - override fun onShow() { - super.onShow() - hoveredChild = null - closing = false - guiAnimation = 0.0 - } - - override fun onTick() { - super.onTick() - if (closing && guiAnimation < 0.01) mc.setScreen(null) - } - - override fun onRender() { - super.onRender() - - // only one window can be hovered at the same time - children.forEach { - it.accessible = false - } - - if (!closing) hoveredChild?.accessible = true - } - - override fun onMouseClick(button: Mouse.Button, action: Mouse.Action, mouse: Vec2d) { - // move hovered window into foreground - (hoveredChild as? WindowComponent<*>)?.let { - children.remove(it) - children.add(it) - } - - super.onMouseClick(button, action, mouse) - } - - override fun onMouseMove(mouse: Vec2d) { - hoveredChild = children.lastOrNull { child -> - mouse in child.rect + override fun onEvent(e: GuiEvent) { + when (e) { + is GuiEvent.Show -> { + activeWindow = null + closing = false + guiAnimation = 0.0 + } + + is GuiEvent.Tick -> { + if (closing && guiAnimation < 0.01) mc.setScreen(null) + } + + is GuiEvent.MouseClick -> { + // move active window into foreground + activeWindow?.let { + windows.children.apply { + remove(it) + add(it) + } + } + } + + is GuiEvent.MouseMove -> { + activeWindow = windows.children.lastOrNull { child -> + e.mouse in child.rect + } + } } - super.onMouseMove(mouse) + windows.onEvent(e) } override fun close() { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index 9976a8f78..cb0e65c37 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -1,29 +1,28 @@ package com.lambda.gui.impl.clickgui import com.lambda.gui.GuiConfigurable -import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.api.GuiEvent object LambdaClickGui : AbstractClickGui() { - override fun onShow() { - updateWindows() - super.onShow() - } + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Show || e is GuiEvent.Tick) { + updateWindows() + } - override fun onTick() { - updateWindows() - super.onTick() + super.onEvent(e) } fun updateWindows() { - val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows - val new = windows.subtract(children.toSet()) - children.addAll(new) - children.removeIf { - if (it !is WindowComponent<*>) return@removeIf false + windows.apply { + val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows + val new = windows.subtract(children.toSet()) + children.addAll(new) - val absent = it !in windows - if (absent) it.destroy() - absent + val iterator = children.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + if (next !in windows) removeChild(next) + } } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 6d5bb93af..91aefc6fa 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -11,7 +11,7 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o override fun performClickAction(mouse: Mouse.Button) { when (mouse) { - Mouse.Button.Left -> module.toggle() + Mouse.Button.Left -> if (hovered) module.toggle() Mouse.Button.Right -> { // open settings window } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt index 7f31faaf2..946b766a8 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt @@ -1,5 +1,7 @@ package com.lambda.gui.impl.clickgui.windows +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.ListWindow import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton @@ -10,16 +12,18 @@ abstract class ModuleWindow( override var width: Double = 110.0, override var height: Double = 300.0, owner: AbstractClickGui -) : WindowComponent(owner) { - override fun onTick() { - children.sortBy { - it.module.name - } +) : ListWindow(owner) { + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Tick) { + contentComponents.children.apply { + sortBy { + it.module.name + } + - children.forEachIndexed { i, button -> - button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) + } } - super.onTick() + super.onEvent(e) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index 5cd1bbe9b..ab99840cb 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -1,5 +1,6 @@ package com.lambda.gui.impl.clickgui.windows.tag +import com.lambda.gui.api.GuiEvent import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow @@ -12,24 +13,27 @@ class CustomModuleWindow( val modules: MutableList = mutableListOf(), owner: AbstractClickGui ) : ModuleWindow(title, owner = owner) { - override fun onTick() { - updateModules() - super.onTick() + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Tick) updateModules() + super.onEvent(e) } private fun updateModules() { - // Add missing module buttons - modules.filter { module -> - children.all { button -> - button.module != module - } - }.map { ModuleButton(it, this) }.forEach(children::add) + contentComponents.apply { + // Add missing module buttons + modules.filter { module -> + children.all { button -> + button.module != module + } + }.map { ModuleButton(it, this@CustomModuleWindow) } + .forEach(contentComponents::addChild) - // Remove deleted modules - children.removeIf { - val flag = it.module !in modules - if (flag) it.onRemove() - flag + // Remove deleted modules + val iterator = children.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + if (next.module !in modules) removeChild(next) + } } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt index 835c4cdf8..d5e26f9d0 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt @@ -14,6 +14,6 @@ class TagWindow( ModuleRegistry.modules .filter { it.tag == tag } .map { ModuleButton(it, this) } - .forEach(children::add) + .forEach(contentComponents::addChild) } } \ No newline at end of file From 81b4bde4b87466e219dd521c430d54223bd5b98c Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 13:52:08 +0300 Subject: [PATCH 37/63] oopsie --- .../lambda/gui/impl/clickgui/windows/ModuleWindow.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt index 946b766a8..2ef0ea40b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt @@ -2,10 +2,8 @@ package com.lambda.gui.impl.clickgui.windows import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.ListWindow -import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton -import com.lambda.module.modules.client.ClickGui abstract class ModuleWindow( override var title: String, @@ -15,12 +13,8 @@ abstract class ModuleWindow( ) : ListWindow(owner) { override fun onEvent(e: GuiEvent) { if (e is GuiEvent.Tick) { - contentComponents.children.apply { - sortBy { - it.module.name - } - - + contentComponents.children.sortBy { + it.module.name } } From 49eb6d436d191ff8b16366da5756f08973f481a0 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 15:07:07 +0300 Subject: [PATCH 38/63] Window creation tests --- .../gui/impl/clickgui/AbstractClickGui.kt | 10 ++++--- .../gui/impl/clickgui/LambdaClickGui.kt | 10 ++++--- .../gui/impl/clickgui/buttons/ModuleButton.kt | 8 +++++- .../impl/clickgui/windows/SettingsWindow.kt | 26 +++++++++++++++++++ .../windows/tag/CustomModuleWindow.kt | 10 ++++--- 5 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 52138dc3b..376d95a60 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -5,23 +5,27 @@ import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent -import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui) { - protected val windows = ChildLayer> { child -> + val windows = ChildLayer> { child -> child == activeWindow && !closing } - protected var activeWindow: WindowComponent<*>? = null + private var activeWindow: WindowComponent<*>? = null private var closing = false var guiAnimation by animation.exp(0.0, 1.0, { if (closing) ClickGui.closeSpeed else ClickGui.openSpeed }) { !closing }; private set + private val actionPool = ArrayDeque<() -> Unit>() + fun scheduleAction(block: () -> Unit) = actionPool.add(block) + override fun onEvent(e: GuiEvent) { + while (actionPool.isNotEmpty()) actionPool.last().invoke() + when (e) { is GuiEvent.Show -> { activeWindow = null diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index cb0e65c37..911a7b735 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -18,10 +18,12 @@ object LambdaClickGui : AbstractClickGui() { val new = windows.subtract(children.toSet()) children.addAll(new) - val iterator = children.iterator() - while (iterator.hasNext()) { - val next = iterator.next() - if (next !in windows) removeChild(next) + children.forEach { window -> + if (window !in windows) { + scheduleAction { + removeChild(window) + } + } } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 91aefc6fa..c30ef0474 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -2,6 +2,7 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.button.ListButton +import com.lambda.gui.impl.clickgui.windows.SettingsWindow import com.lambda.module.Module import com.lambda.util.Mouse @@ -13,7 +14,12 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o when (mouse) { Mouse.Button.Left -> if (hovered) module.toggle() Mouse.Button.Right -> { - // open settings window + val gui = owner.owner + + gui.scheduleAction { + val settingsWindow = SettingsWindow(this, gui) + gui.windows.addChild(settingsWindow) + } } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt new file mode 100644 index 000000000..d1647fb4a --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt @@ -0,0 +1,26 @@ +package com.lambda.gui.impl.clickgui.windows + +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.ListWindow +import com.lambda.gui.api.component.button.ListButton +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton + +class SettingsWindow( + button: ModuleButton, + owner: AbstractClickGui +) : ListWindow(owner) { + private val module = button.module + + override val title = module.name + override var width = button.owner.width + override var height = 0.0 + + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Tick) { + height = contentComponents.children.sumOf { it.size.y } + } + + super.onEvent(e) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index ab99840cb..50b491529 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -29,10 +29,12 @@ class CustomModuleWindow( .forEach(contentComponents::addChild) // Remove deleted modules - val iterator = children.iterator() - while (iterator.hasNext()) { - val next = iterator.next() - if (next.module !in modules) removeChild(next) + children.forEach { button -> + if (button.module !in modules) { + owner.scheduleAction { + removeChild(button) + } + } } } } From 498b5afcf46a4989f18dfdd12a611d33cfb4bbde Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 15:22:39 +0300 Subject: [PATCH 39/63] Button action refactor --- .../gui/api/component/InteractiveComponent.kt | 23 +++++++------------ .../api/component/button/ButtonComponent.kt | 7 +++--- .../gui/impl/clickgui/buttons/ModuleButton.kt | 15 +++++++----- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt index 31c91a611..4d975a59c 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt @@ -7,18 +7,10 @@ import com.lambda.util.Mouse abstract class InteractiveComponent : IComponent, IRectComponent { protected var hovered = false - protected var pressed = false; set(value) { - if (field == value) return - field = value + protected var pressed = false - if (value) onPress() - else onRelease() - } - - protected var activeMouseButton: Mouse.Button? = null - - protected open fun onPress() {} - protected open fun onRelease() {} + protected open fun onPress(e: GuiEvent.MouseClick) {} + protected open fun onRelease(e: GuiEvent.MouseClick) {} override fun onEvent(e: GuiEvent) { when (e) { @@ -32,11 +24,12 @@ abstract class InteractiveComponent : IComponent, IRectComponent { } is GuiEvent.MouseClick -> { - activeMouseButton = e.button.takeUnless { - it.isMainButton && e.action == Mouse.Action.Click - } - + val prevPressed = pressed pressed = hovered && e.button.isMainButton && e.action == Mouse.Action.Click + + if (prevPressed == pressed) return + if (pressed) onPress(e) + else onRelease(e) } } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index a84b3a149..ed67a8abc 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -6,7 +6,6 @@ import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.module.modules.client.ClickGui import com.lambda.module.modules.client.GuiSettings -import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Rect @@ -91,7 +90,7 @@ abstract class ButtonComponent( } } - abstract fun performClickAction(mouse: Mouse.Button) + abstract fun performClickAction(e: GuiEvent.MouseClick) override fun onEvent(e: GuiEvent) { super.onEvent(e) @@ -106,8 +105,8 @@ abstract class ButtonComponent( } } - override fun onRelease() { - activeMouseButton?.let(::performClickAction) + override fun onRelease(e: GuiEvent.MouseClick) { + performClickAction(e) } override fun onRemove() { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index c30ef0474..d7152deae 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,5 +1,6 @@ package com.lambda.gui.impl.clickgui.buttons +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.windows.SettingsWindow @@ -9,16 +10,18 @@ import com.lambda.util.Mouse class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(owner) { override val text get() = module.name override val active get() = module.isEnabled + private val gui = owner.owner - override fun performClickAction(mouse: Mouse.Button) { - when (mouse) { + private val settingsWindow = SettingsWindow(this, gui) + + override fun performClickAction(e: GuiEvent.MouseClick) { + when (e.button) { Mouse.Button.Left -> if (hovered) module.toggle() Mouse.Button.Right -> { - val gui = owner.owner - gui.scheduleAction { - val settingsWindow = SettingsWindow(this, gui) - gui.windows.addChild(settingsWindow) + gui.windows.addChild(settingsWindow.apply { + position = e.mouse + }) } } } From e2e434f2fd240d45d8a6376409a0693612a170a5 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 15:26:32 +0300 Subject: [PATCH 40/63] Single settings window --- .../gui/impl/clickgui/buttons/ModuleButton.kt | 21 +++++++++++++------ .../impl/clickgui/windows/SettingsWindow.kt | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index d7152deae..dbac7f8a1 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -12,17 +12,26 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o override val active get() = module.isEnabled private val gui = owner.owner - private val settingsWindow = SettingsWindow(this, gui) - override fun performClickAction(e: GuiEvent.MouseClick) { when (e.button) { Mouse.Button.Left -> if (hovered) module.toggle() Mouse.Button.Right -> { - gui.scheduleAction { - gui.windows.addChild(settingsWindow.apply { - position = e.mouse - }) + gui.apply { + windows.children.forEach { child -> + if (child is SettingsWindow && child.button == this@ModuleButton) { + gui.scheduleAction { + gui.windows.removeChild(child) + } + } + } + + scheduleAction { + windows.addChild(SettingsWindow(this@ModuleButton, this).apply { + position = e.mouse + }) + } } + } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt index d1647fb4a..d90586755 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt @@ -7,7 +7,7 @@ import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton class SettingsWindow( - button: ModuleButton, + val button: ModuleButton, owner: AbstractClickGui ) : ListWindow(owner) { private val module = button.module From 363bb6171a199aafbf151d4012f299442ff9b6e7 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 18:14:50 +0300 Subject: [PATCH 41/63] Pool spam fix --- .../kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 376d95a60..bcce52812 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -24,7 +24,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli fun scheduleAction(block: () -> Unit) = actionPool.add(block) override fun onEvent(e: GuiEvent) { - while (actionPool.isNotEmpty()) actionPool.last().invoke() + while (actionPool.isNotEmpty()) actionPool.removeLast().invoke() when (e) { is GuiEvent.Show -> { From 9e4ae2c1c7b4b4588d90130bf7cd3d77006e62f8 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 18:21:16 +0300 Subject: [PATCH 42/63] Settings open animation & refactor --- .../gui/api/component/WindowComponent.kt | 17 ++++++++++----- .../api/component/button/ButtonComponent.kt | 2 +- .../gui/api/component/button/ListButton.kt | 2 +- .../gui/impl/clickgui/AbstractClickGui.kt | 6 +++--- .../gui/impl/clickgui/LambdaClickGui.kt | 19 ++++++----------- .../gui/impl/clickgui/buttons/ModuleButton.kt | 21 ++++++++----------- .../impl/clickgui/windows/SettingsWindow.kt | 5 +++++ 7 files changed, 37 insertions(+), 35 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 93faab6d6..93df642ad 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -4,7 +4,6 @@ import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.button.ButtonComponent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer @@ -47,11 +46,11 @@ abstract class WindowComponent ( val subLayer = RenderLayer() val animation = owner.animation - val guiAnimation get() = owner.guiAnimation + open val showAnimation get() = owner.showAnimation private val actualHeight get() = height + padding * 2 * isOpen.toInt() private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) - private val renderHeight get() = lerp(0.0, renderHeightAnimation, guiAnimation) + private val renderHeight get() = lerp(0.0, renderHeightAnimation, showAnimation) val contentComponents = ChildLayer { child -> child.rect in contentRect && accessible && isOpen @@ -67,7 +66,7 @@ abstract class WindowComponent ( position = rect roundRadius = ClickGui.windowRadius - val alpha = (guiAnimation * 2.0).coerceIn(0.0, 1.0) + val alpha = (showAnimation * 2.0).coerceIn(0.0, 1.0) color(GuiSettings.backgroundColor.multAlpha(alpha)) } @@ -75,7 +74,7 @@ abstract class WindowComponent ( titleFont = renderer.font { text = title position = titleBar.center - widthVec * 0.5 - color = Color.WHITE.setAlpha(guiAnimation) + color = Color.WHITE.setAlpha(showAnimation) } } @@ -134,6 +133,14 @@ abstract class WindowComponent ( //titleBarComponents.onEvent(e) } + fun destroy() { + owner.apply { + scheduleAction { + windows.removeChild(this@WindowComponent) + } + } + } + override fun onRemove() { layer.destroy() subLayer.destroy() diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index ed67a8abc..b71370e46 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -36,7 +36,7 @@ abstract class ButtonComponent( private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) private val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 private val showAnimationRaw by animation.exp(0.0, 1.0, 0.7, owner::isOpen) - private val showAnimation get() = lerp(0.0, showAnimationRaw, owner.guiAnimation) + private val showAnimation get() = lerp(0.0, showAnimationRaw, owner.showAnimation) private var lastHoveredTime = 0L private val renderHovered get() = hovered || diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 78b434517..401510e40 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -12,7 +12,7 @@ abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) var heightOffset = 0.0 - private val targetHeightOffset get() = heightOffset * owner.guiAnimation * owner.isOpen.toInt() + private val targetHeightOffset get() = heightOffset * owner.showAnimation * owner.isOpen.toInt() private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.5) override fun onEvent(e: GuiEvent) { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index bcce52812..8aa92775d 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -16,7 +16,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli private var activeWindow: WindowComponent<*>? = null private var closing = false - var guiAnimation by animation.exp(0.0, 1.0, { + var showAnimation by animation.exp(0.0, 1.0, { if (closing) ClickGui.closeSpeed else ClickGui.openSpeed }) { !closing }; private set @@ -30,11 +30,11 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli is GuiEvent.Show -> { activeWindow = null closing = false - guiAnimation = 0.0 + showAnimation = 0.0 } is GuiEvent.Tick -> { - if (closing && guiAnimation < 0.01) mc.setScreen(null) + if (closing && showAnimation < 0.01) mc.setScreen(null) } is GuiEvent.MouseClick -> { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index 911a7b735..98de93a14 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -2,29 +2,22 @@ package com.lambda.gui.impl.clickgui import com.lambda.gui.GuiConfigurable import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow object LambdaClickGui : AbstractClickGui() { override fun onEvent(e: GuiEvent) { - if (e is GuiEvent.Show || e is GuiEvent.Tick) { - updateWindows() - } - + if (e is GuiEvent.Show || e is GuiEvent.Tick) updateWindows() super.onEvent(e) } fun updateWindows() { windows.apply { val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows - val new = windows.subtract(children.toSet()) - children.addAll(new) + children.addAll(windows.subtract(children.toSet())) - children.forEach { window -> - if (window !in windows) { - scheduleAction { - removeChild(window) - } - } - } + children.filter { it !in windows && it is CustomModuleWindow } + .forEach(WindowComponent<*>::destroy) } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index dbac7f8a1..dc3761b24 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -17,21 +17,18 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o Mouse.Button.Left -> if (hovered) module.toggle() Mouse.Button.Right -> { gui.apply { - windows.children.forEach { child -> - if (child is SettingsWindow && child.button == this@ModuleButton) { - gui.scheduleAction { - gui.windows.removeChild(child) + // Open new settings window or move existing one to the cursor + windows.children + .firstOrNull { it is SettingsWindow && it.button == this@ModuleButton } + ?.let { it.position = e.mouse } + ?: run { + scheduleAction { + windows.addChild(SettingsWindow(this@ModuleButton, this).apply { + position = e.mouse + }) } } - } - - scheduleAction { - windows.addChild(SettingsWindow(this@ModuleButton, this).apply { - position = e.mouse - }) - } } - } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt index d90586755..debcad103 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt @@ -1,10 +1,12 @@ package com.lambda.gui.impl.clickgui.windows +import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.ListWindow import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.module.modules.client.ClickGui class SettingsWindow( val button: ModuleButton, @@ -16,9 +18,12 @@ class SettingsWindow( override var width = button.owner.width override var height = 0.0 + override val showAnimation by animation.exp(0.0, 1.0, ClickGui.openSpeed, ::isOpen) + override fun onEvent(e: GuiEvent) { if (e is GuiEvent.Tick) { height = contentComponents.children.sumOf { it.size.y } + if (showAnimation < 0.05 && !isOpen) destroy() } super.onEvent(e) From 63021f7ddf2878d5b5824111c8a7822e4e1fb3c3 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 2 May 2024 20:29:06 +0300 Subject: [PATCH 43/63] Misc stuff --- .../gui/CustomModuleWindowSerializer.kt | 5 ++- .../serializer/gui/TagWindowSerializer.kt | 5 ++- .../lambda/graphics/animation/Animation.kt | 4 +-- .../com/lambda/graphics/renderer/Renderer.kt | 14 +++----- .../kotlin/com/lambda/gui/GuiConfigurable.kt | 2 +- .../gui/api/component/WindowComponent.kt | 32 +++++++++++++++++-- .../gui/impl/clickgui/AbstractClickGui.kt | 13 ++++---- .../gui/impl/clickgui/buttons/ModuleButton.kt | 21 ++++++++---- .../impl/clickgui/windows/SettingsWindow.kt | 4 ++- 9 files changed, 63 insertions(+), 37 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt index 4e7c8274f..f06fb7cae 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt @@ -4,7 +4,6 @@ import com.google.gson.* import com.lambda.gui.impl.clickgui.LambdaClickGui import com.lambda.gui.impl.clickgui.windows.tag.CustomModuleWindow import com.lambda.module.ModuleRegistry -import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d import java.lang.reflect.Type @@ -48,10 +47,10 @@ object CustomModuleWindowSerializer : JsonSerializer, JsonDe width = it["width"].asDouble height = it["height"].asDouble isOpen = it["isOpen"].asBoolean - position = Vec2d( + forceSetPosition(Vec2d( it["position"].asJsonArray[0].asDouble, it["position"].asJsonArray[1].asDouble - ) + )) } } ?: throw JsonParseException("Invalid window data") } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt index b37090db2..a6f8033bb 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt @@ -2,7 +2,6 @@ package com.lambda.config.serializer.gui import com.google.gson.* import com.lambda.gui.impl.clickgui.LambdaClickGui -import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.gui.impl.clickgui.windows.tag.TagWindow import com.lambda.module.tag.ModuleTag import com.lambda.util.math.Vec2d @@ -35,10 +34,10 @@ object TagWindowSerializer : JsonSerializer, JsonDeserializer Double) { else lerp(it, target, speed()) }.apply(::register) - // Exponent animation will never reach target value - private const val CLAMP = 0.001 + // Exponent animation never reaches target value + private const val CLAMP = 0.01 } } diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt index d945dbc0f..0c6c38b83 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/Renderer.kt @@ -24,17 +24,15 @@ abstract class Renderer > ( protected abstract fun newEntry(block: T.() -> Unit): T override fun build(block: T.() -> Unit): T { - checkDestroyed() return newEntry(block).process(entrySet::add) } override fun remove(entry: T): T { - checkDestroyed() return entry.process(entrySet::remove) } override fun render() { - checkDestroyed() + if (destroyed) return if (rebuild) { rebuild = false @@ -57,19 +55,19 @@ abstract class Renderer > ( protected open fun preRender() {} override fun update() { - checkDestroyed() + if (destroyed) return entrySet.forEach(IRenderEntry::update) } override fun clear() { - checkDestroyed() + if (destroyed) return entrySet.clear() vao.clear() } override fun destroy() { - checkDestroyed() + if (destroyed) return entrySet.clear() vao.destroy() @@ -88,8 +86,4 @@ abstract class Renderer > ( if (prev == curr) return@observable rebuild = true } - - private fun checkDestroyed() { - check(!destroyed) { "Using the renderer after it is destroyed" } - } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index a2b5fdee2..d08c6d737 100644 --- a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -29,7 +29,7 @@ object GuiConfigurable : Configurable(GuiConfig), Loadable { ModuleTag.defaults.mapIndexed { index, tag -> TagWindow(tag, ownerGui).apply { val step = 3.0 - position = Vec2d((width + step) * index, 0.0) + step + forceSetPosition(Vec2d((width + step) * index, 0.0) + step) } } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 93df642ad..adda26adc 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -1,5 +1,6 @@ package com.lambda.gui.api.component +import com.lambda.Lambda.mc import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry @@ -17,6 +18,7 @@ import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d +import com.lambda.util.primitives.extension.partialTicks import java.awt.Color import kotlin.math.abs @@ -29,12 +31,13 @@ abstract class WindowComponent ( abstract var height: Double var position = Vec2d.ZERO + private var prevPosition = position var isOpen = true private var dragOffset: Vec2d? = null private val padding get() = ClickGui.windowPadding - final override val rect get() = Rect.basedOn(position, width, renderHeight + titleBarHeight) + final override val rect get() = Rect.basedOn(renderPosition, width, renderHeight + titleBarHeight) val contentRect get() = rect.shrink(padding).moveFirst(Vec2d(0.0, titleBarHeight - padding)) private val titleBar get() = Rect.basedOn(rect.leftTop, rect.size.x, titleBarHeight) @@ -51,6 +54,7 @@ abstract class WindowComponent ( private val actualHeight get() = height + padding * 2 * isOpen.toInt() private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) private val renderHeight get() = lerp(0.0, renderHeightAnimation, showAnimation) + private val renderPosition get() = lerp(prevPosition, position, mc.partialTicks) val contentComponents = ChildLayer { child -> child.rect in contentRect && accessible && isOpen @@ -86,9 +90,13 @@ abstract class WindowComponent ( dragOffset = null } + is GuiEvent.Tick -> { + prevPosition = position + } + is GuiEvent.Render -> { - layer.assignOffset(position) - subLayer.assignOffset(position) + layer.assignOffset(renderPosition) + subLayer.assignOffset(renderPosition) // TODO: fix blur // BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) @@ -133,6 +141,24 @@ abstract class WindowComponent ( //titleBarComponents.onEvent(e) } + fun forceSetPosition(pos: Vec2d) { + position = pos + prevPosition = position + } + + fun focus() { + // move window into foreground + owner.apply { + scheduleAction { + windows.children.apply { + this@WindowComponent + .apply(::remove) + .apply(::add) + } + } + } + } + fun destroy() { owner.apply { scheduleAction { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 8aa92775d..683bbca3b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -6,6 +6,7 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.windows.SettingsWindow import com.lambda.module.modules.client.ClickGui abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui) { @@ -31,6 +32,10 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli activeWindow = null closing = false showAnimation = 0.0 + + windows.children + .filterIsInstance() + .forEach(WindowComponent<*>::destroy) } is GuiEvent.Tick -> { @@ -38,13 +43,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli } is GuiEvent.MouseClick -> { - // move active window into foreground - activeWindow?.let { - windows.children.apply { - remove(it) - add(it) - } - } + activeWindow?.focus() } is GuiEvent.MouseMove -> { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index dc3761b24..7650ccb87 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -6,6 +6,7 @@ import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.windows.SettingsWindow import com.lambda.module.Module import com.lambda.util.Mouse +import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(owner) { override val text get() = module.name @@ -18,16 +19,22 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o Mouse.Button.Right -> { gui.apply { // Open new settings window or move existing one to the cursor - windows.children - .firstOrNull { it is SettingsWindow && it.button == this@ModuleButton } - ?.let { it.position = e.mouse } - ?: run { + val settingsWindow = windows.children.filterIsInstance() + .firstOrNull { it.button == this@ModuleButton }?.apply { + position = e.mouse + } ?: SettingsWindow(this@ModuleButton, this).apply { + forceSetPosition(e.mouse) + scheduleAction { - windows.addChild(SettingsWindow(this@ModuleButton, this).apply { - position = e.mouse - }) + windows.addChild(this) } } + + // we have to wait this tag window to be focused after handling a click event + // to place settings window over it + recordRenderCall { + settingsWindow.focus() + } } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt index debcad103..b9ac20dcc 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt @@ -7,6 +7,7 @@ import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.module.modules.client.ClickGui +import com.lambda.util.math.MathUtils.lerp class SettingsWindow( val button: ModuleButton, @@ -18,7 +19,8 @@ class SettingsWindow( override var width = button.owner.width override var height = 0.0 - override val showAnimation by animation.exp(0.0, 1.0, ClickGui.openSpeed, ::isOpen) + private val showAnimation0 by animation.exp(0.0, 1.0, ClickGui.openSpeed, ::isOpen) + override val showAnimation get() = lerp(0.0, showAnimation0, owner.showAnimation) override fun onEvent(e: GuiEvent) { if (e is GuiEvent.Tick) { From ab4107aa5ab5a75dae906f23ded9a0bc59bf1f76 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 3 May 2024 11:41:45 +0300 Subject: [PATCH 44/63] Added boolean button --- .../lambda/gui/api/component/ListWindow.kt | 10 +++- .../api/component/button/ButtonComponent.kt | 31 ++-------- .../gui/api/component/button/ListButton.kt | 2 +- .../gui/api/component/core/IComponent.kt | 1 - .../com/lambda/gui/api/layer/LayerEntry.kt | 2 +- .../com/lambda/gui/api/layer/RenderLayer.kt | 2 +- .../gui/impl/clickgui/AbstractClickGui.kt | 4 +- .../gui/impl/clickgui/buttons/ModuleButton.kt | 57 ++++++++++++++----- .../impl/clickgui/buttons/SettingButton.kt | 33 +++++++++++ .../clickgui/buttons/setting/BooleanButton.kt | 20 +++++++ .../{SettingsWindow.kt => SettingWindow.kt} | 26 ++++++--- .../module/modules/render/RenderTest.kt | 8 +++ 12 files changed, 139 insertions(+), 57 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt rename common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/{SettingsWindow.kt => SettingWindow.kt} (56%) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt index 60ff72798..420da3df1 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt @@ -3,15 +3,19 @@ package com.lambda.gui.api.component import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.ClickGui abstract class ListWindow ( owner: AbstractClickGui ) : WindowComponent(owner) { override fun onEvent(e: GuiEvent) { - if (e is GuiEvent.Tick) { - contentComponents.children.forEachIndexed { i, button -> - button.heightOffset = i * (ClickGui.buttonHeight + ClickGui.buttonStep) + if (e is GuiEvent.Show || e is GuiEvent.Tick) { + var y = 0.0 + contentComponents.children.forEach { button -> + if (button is SettingButton<*, *> && !button.visible) return@forEach + button.heightOffset = y + y += button.size.y + ClickGui.buttonStep } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index b71370e46..bb9640e09 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -11,7 +11,6 @@ import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d import java.awt.Color -import kotlin.math.abs abstract class ButtonComponent( final override val owner: WindowComponent<*> @@ -20,23 +19,21 @@ abstract class ButtonComponent( abstract val size: Vec2d abstract val text: String - abstract val active: Boolean + protected abstract var activeAnimation: Double private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.contentRect.size.x else size.x, size.y) final override val rect get() = Rect.basedOn(position, actualSize) + owner.contentRect.leftTop private val layer = owner.subLayer - private val renderer = layer.entry() + protected val renderer = layer.entry() protected val animation = owner.animation - private var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::active) - private var toggleFxDirection by animation.exp(0.0, 1.0, 0.6, ::active) private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.6 else 0.07 }, ::renderHovered) private var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) - private val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 + protected val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 private val showAnimationRaw by animation.exp(0.0, 1.0, 0.7, owner::isOpen) - private val showAnimation get() = lerp(0.0, showAnimationRaw, owner.showAnimation) + protected open val showAnimation get() = lerp(0.0, showAnimationRaw, owner.showAnimation) private var lastHoveredTime = 0L private val renderHovered get() = hovered || @@ -58,26 +55,6 @@ abstract class ButtonComponent( color(GuiSettings.mainColor.multAlpha(alpha)) } - // Toggle fx - renderer.rect { - val left = rect - Vec2d(rect.size.x, 0.0) - val right = rect + Vec2d(rect.size.x, 0.0) - - position = lerp(left, right, activeAnimation) - .clamp(rect) - .shrink(interactAnimation) - - // 0.0 .. 1.0 .. 0.0 animation - val alpha = 1.0 - (abs(activeAnimation - 0.5) * 2.0) - val color = GuiSettings.mainColor.multAlpha(alpha * 0.6 * showAnimation) - - // "Tail" effect - val leftColor = color.multAlpha(1.0 - toggleFxDirection) - val rightColor = color.multAlpha(toggleFxDirection) - - colorH(leftColor, rightColor) - } - // Text renderer.font { text = this@ButtonComponent.text diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 401510e40..81d9377c3 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -12,7 +12,7 @@ abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) var heightOffset = 0.0 - private val targetHeightOffset get() = heightOffset * owner.showAnimation * owner.isOpen.toInt() + protected open val targetHeightOffset get() = heightOffset * owner.showAnimation * owner.isOpen.toInt() private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.5) override fun onEvent(e: GuiEvent) { diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt index 91c2f2d03..1197a9446 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt @@ -3,6 +3,5 @@ package com.lambda.gui.api.component.core import com.lambda.gui.api.GuiEvent interface IComponent { - // TODO: Use event system? fun onEvent(e: GuiEvent) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt index 67c172a7c..2e93ac3ee 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt @@ -3,7 +3,7 @@ package com.lambda.gui.api.layer import com.lambda.graphics.renderer.IRenderEntry import com.lambda.graphics.renderer.IRenderer import com.lambda.graphics.renderer.gui.font.IFontEntry -import com.lambda.graphics.renderer.gui.rect.IRectEntry +import com.lambda.graphics.renderer.gui.rect.filled.IRectEntry // Used to group all render entries related to a component class LayerEntry ( diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt index 953e72ed3..d2b90c41b 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt @@ -1,7 +1,7 @@ package com.lambda.gui.api.layer import com.lambda.graphics.renderer.gui.font.FontRenderer -import com.lambda.graphics.renderer.gui.rect.RectRenderer +import com.lambda.graphics.renderer.gui.rect.filled.RectRenderer import com.lambda.module.modules.client.GuiSettings import com.lambda.util.math.Vec2d diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 683bbca3b..c27190cdd 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -6,7 +6,7 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildLayer -import com.lambda.gui.impl.clickgui.windows.SettingsWindow +import com.lambda.gui.impl.clickgui.windows.SettingWindow import com.lambda.module.modules.client.ClickGui abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui) { @@ -34,7 +34,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli showAnimation = 0.0 windows.children - .filterIsInstance() + .filterIsInstance() .forEach(WindowComponent<*>::destroy) } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 7650ccb87..dab67a17e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,39 +1,68 @@ package com.lambda.gui.impl.clickgui.buttons +import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.button.ListButton -import com.lambda.gui.impl.clickgui.windows.SettingsWindow +import com.lambda.gui.impl.clickgui.windows.SettingWindow import com.lambda.module.Module +import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse +import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.Vec2d import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall +import kotlin.math.abs class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(owner) { override val text get() = module.name - override val active get() = module.isEnabled + private val active get() = module.isEnabled private val gui = owner.owner + override var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::active) + private var toggleFxDirection by animation.exp(0.0, 1.0, 0.7, ::active) + + init { + // Toggle fx + renderer.rect { + val left = rect - Vec2d(rect.size.x, 0.0) + val right = rect + Vec2d(rect.size.x, 0.0) + + position = lerp(left, right, activeAnimation) + .clamp(rect) + .shrink(interactAnimation) + + // 0.0 .. 1.0 .. 0.0 animation + val alpha = 1.0 - (abs(activeAnimation - 0.5) * 2.0) + val color = GuiSettings.mainColor.multAlpha(alpha * 0.6 * showAnimation) + + // "Tail" effect + val leftColor = color.multAlpha(1.0 - toggleFxDirection) + val rightColor = color.multAlpha(toggleFxDirection) + + colorH(leftColor, rightColor) + } + } + override fun performClickAction(e: GuiEvent.MouseClick) { when (e.button) { Mouse.Button.Left -> if (hovered) module.toggle() - Mouse.Button.Right -> { + Mouse.Button.Right -> { // Open new settings window gui.apply { - // Open new settings window or move existing one to the cursor - val settingsWindow = windows.children.filterIsInstance() - .firstOrNull { it.button == this@ModuleButton }?.apply { - position = e.mouse - } ?: SettingsWindow(this@ModuleButton, this).apply { - forceSetPosition(e.mouse) + val check = windows.children + .filterIsInstance() + .filter { it.button.module == module } + .onEach { it.isOpen = false } + .isNotEmpty() - scheduleAction { - windows.addChild(this) - } - } + if (check) return // we have to wait this tag window to be focused after handling a click event // to place settings window over it recordRenderCall { - settingsWindow.focus() + SettingWindow(this@ModuleButton, this).apply { + forceSetPosition(e.mouse) + }.apply(windows::addChild) } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt new file mode 100644 index 000000000..fdeebf104 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -0,0 +1,33 @@ +package com.lambda.gui.impl.clickgui.buttons + +import com.lambda.config.AbstractSetting +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.api.component.button.ListButton +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.MathUtils.toInt + +abstract class SettingButton > ( + val setting: T, + owner: WindowComponent<*> +): ListButton(owner) { + protected var value by setting + var visible = true + + private var visibilityAnimation by animation.exp(0.0, 1.0, 0.6, ::visible) + override val showAnimation get() = lerp(0.0, super.showAnimation, visibilityAnimation) + override val targetHeightOffset: Double get() { + var out = super.targetHeightOffset + if (!visible) out -= size.y * 0.5 + return out + } + + override var accessible: Boolean = false; get() = field && visible + + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Show || e is GuiEvent.Tick) visible = setting.visibility() + if (e is GuiEvent.Show) visibilityAnimation = visible.toInt().toDouble() + super.onEvent(e) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt new file mode 100644 index 000000000..3666817cc --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -0,0 +1,20 @@ +package com.lambda.gui.impl.clickgui.buttons.setting + +import com.lambda.config.settings.comparable.BooleanSetting +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.util.Mouse + +class BooleanButton( + setting: BooleanSetting, + owner: WindowComponent<*> +) : SettingButton(setting, owner) { + override val text = setting.name + override var activeAnimation by animation.exp(0.0, 1.0, 0.5, ::value) + + override fun performClickAction(e: GuiEvent.MouseClick) { + if (e.button == Mouse.Button.Left && hovered) value = !value + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt similarity index 56% rename from common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt rename to common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt index b9ac20dcc..e5722a4bf 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingsWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt @@ -1,18 +1,20 @@ package com.lambda.gui.impl.clickgui.windows +import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.ListWindow -import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton import com.lambda.module.modules.client.ClickGui import com.lambda.util.math.MathUtils.lerp -class SettingsWindow( +class SettingWindow( val button: ModuleButton, owner: AbstractClickGui -) : ListWindow(owner) { +) : ListWindow>(owner) { private val module = button.module override val title = module.name @@ -22,12 +24,22 @@ class SettingsWindow( private val showAnimation0 by animation.exp(0.0, 1.0, ClickGui.openSpeed, ::isOpen) override val showAnimation get() = lerp(0.0, showAnimation0, owner.showAnimation) + init { + button.module.settings.mapNotNull { setting -> + when (setting) { + is BooleanSetting -> BooleanButton(setting, this) + else -> null + } + }.forEach(contentComponents::addChild) + } + override fun onEvent(e: GuiEvent) { - if (e is GuiEvent.Tick) { - height = contentComponents.children.sumOf { it.size.y } + super.onEvent(e) + + if (e is GuiEvent.Show || e is GuiEvent.Tick) { + val c = contentComponents.children.filter { it.visible } + height = c.sumOf { it.size.y } + ClickGui.buttonStep * (c.size - 1) if (showAnimation < 0.05 && !isOpen) destroy() } - - super.onEvent(e) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt index 26b99c74f..8fe7e6222 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt @@ -21,6 +21,14 @@ object RenderTest : Module( description = "RenderTest", tag = ModuleTag.RENDER ) { + private val test1 by setting("Toggle visibility", true) + private val test21 by setting("Hallo 1", true, visibility = ::test1) + private val test22 by setting("Hallo 2", true, visibility = ::test1) + private val test23 by setting("Hallo 3", true, visibility = ::test1) + private val test31 by setting("Holla 1", true, visibility = { !test1 }) + private val test32 by setting("Holla 2", true, visibility = { !test1 }) + private val test33 by setting("Holla 3", true, visibility = { !test1 }) + private val filled = DynamicFilledRenderer() private val outline = DynamicOutlineRenderer() private val color = Color(60, 200, 60) From 6170a3062d27f5e7e45d0fb5e25dcdb061173cb9 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 3 May 2024 20:35:22 +0300 Subject: [PATCH 45/63] Outline renderer & many misc stuff --- .../graphics/buffer/vao/IRenderContext.kt | 1 + .../com/lambda/graphics/buffer/vao/VAO.kt | 6 ++ .../buffer/vao/vertex/VertexAttrib.kt | 5 +- .../kotlin/com/lambda/graphics/gl/Memory.kt | 4 +- .../renderer/gui/rect/AbstractRectRenderer.kt | 21 +++++ .../graphics/renderer/gui/rect/IRectEntry.kt | 23 +++++ .../graphics/renderer/gui/rect/RectEntry.kt | 76 ---------------- .../renderer/gui/rect/RectRenderer.kt | 49 ---------- .../gui/rect/filled/FilledRectEntry.kt | 58 ++++++++++++ .../gui/rect/filled/FilledRectRenderer.kt | 17 ++++ .../gui/rect/outline/OutlineRectEntry.kt | 91 +++++++++++++++++++ .../gui/rect/outline/OutlineRectRenderer.kt | 17 ++++ .../kotlin/com/lambda/gui/GuiConfigurable.kt | 2 +- .../gui/api/component/WindowComponent.kt | 20 ++-- .../api/component/button/ButtonComponent.kt | 6 +- .../gui/api/component/button/ListButton.kt | 1 - .../com/lambda/gui/api/layer/LayerEntry.kt | 12 ++- .../com/lambda/gui/api/layer/RenderLayer.kt | 28 +++--- .../gui/impl/clickgui/buttons/ModuleButton.kt | 9 +- .../impl/clickgui/buttons/SettingButton.kt | 9 +- .../module/modules/client/GuiSettings.kt | 10 +- .../renderer/{rect.frag => rect_filled.frag} | 6 +- .../fragment/renderer/rect_outline.frag | 31 +++++++ .../renderer/{rect.vert => rect_filled.vert} | 12 ++- .../shaders/vertex/renderer/rect_outline.vert | 23 +++++ 25 files changed, 362 insertions(+), 175 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/IRectEntry.kt delete mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt delete mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectRenderer.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectEntry.kt create mode 100644 common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectRenderer.kt rename common/src/main/resources/assets/lambda/shaders/fragment/renderer/{rect.frag => rect_filled.frag} (86%) create mode 100644 common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag rename common/src/main/resources/assets/lambda/shaders/vertex/renderer/{rect.vert => rect_filled.vert} (61%) create mode 100644 common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/IRenderContext.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/IRenderContext.kt index d19a7ec69..cf849d16b 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/IRenderContext.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/IRenderContext.kt @@ -5,6 +5,7 @@ import java.awt.Color interface IRenderContext { fun vec3(x: Double, y: Double, z: Double): IRenderContext fun vec2(x: Double, y: Double): IRenderContext + fun float(v: Double): IRenderContext fun color(color: Color): IRenderContext fun end(): Int diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt index 3d6bdfa23..340a2af64 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/VAO.kt @@ -7,6 +7,7 @@ import com.lambda.graphics.gl.Memory.byteBuffer import com.lambda.graphics.gl.Memory.capacity import com.lambda.graphics.gl.Memory.color import com.lambda.graphics.gl.Memory.copy +import com.lambda.graphics.gl.Memory.float import com.lambda.graphics.gl.Memory.int import com.lambda.graphics.gl.Memory.vec2 import com.lambda.graphics.gl.Memory.vec3 @@ -89,6 +90,11 @@ class VAO( return this } + override fun float(v: Double): VAO { + verticesPosition += float(verticesPosition, v) + return this + } + override fun color(color: Color): VAO { verticesPosition += color(verticesPosition, color) return this diff --git a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt index 72232b05b..87c5700fd 100644 --- a/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt +++ b/common/src/main/kotlin/com/lambda/graphics/buffer/vao/vertex/VertexAttrib.kt @@ -2,8 +2,10 @@ package com.lambda.graphics.buffer.vao.vertex import com.lambda.graphics.gl.GLObject import org.lwjgl.opengl.GL11C.* +import org.lwjgl.opengl.GL20C.GL_MAX_VERTEX_ATTRIBS enum class VertexAttrib(val componentCount: Int, componentSize: Int, val normalized: Boolean, override val gl: Int) : GLObject { + Float(1, 4, false, GL_FLOAT), Vec2(2, 4, false, GL_FLOAT), Vec3(3, 4, false, GL_FLOAT), Color(4, 1, true, GL_UNSIGNED_BYTE); @@ -13,7 +15,8 @@ enum class VertexAttrib(val componentCount: Int, componentSize: Int, val normali enum class Group(vararg val attributes: VertexAttrib) { // GUI FONT(Vec2, Vec2, Color), // pos, uv, color - RECT(Vec2, Vec2, Vec3, Color), // pos, uv, , color + RECT_FILLED(Vec2, Vec2, Vec2, Float, Float, Color), // pos, uv, size, roundRadius, shade, color + RECT_OUTLINE(Vec2, Float, Float, Color), // pos, alpha, shade, color BLUR(Vec2, Vec2), // pos, uv // WORLD diff --git a/common/src/main/kotlin/com/lambda/graphics/gl/Memory.kt b/common/src/main/kotlin/com/lambda/graphics/gl/Memory.kt index 95374e8b8..d199980f5 100644 --- a/common/src/main/kotlin/com/lambda/graphics/gl/Memory.kt +++ b/common/src/main/kotlin/com/lambda/graphics/gl/Memory.kt @@ -8,6 +8,7 @@ import java.nio.Buffer import java.nio.ByteBuffer object Memory { + private val floatSize = VertexAttrib.Float.size private val vec2Size = VertexAttrib.Vec2.size private val vec3Size = VertexAttrib.Vec3.size private val colorSize = VertexAttrib.Color.size @@ -41,8 +42,9 @@ object Memory { MemoryUtil.memPutInt(address, value) } - fun float(address: Long, value: Double) { + fun float(address: Long, value: Double): Int { MemoryUtil.memPutFloat(address, value.toFloat()) + return floatSize } fun address(buffer: Buffer): Long { diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt new file mode 100644 index 000000000..8cbe85948 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt @@ -0,0 +1,21 @@ +package com.lambda.graphics.renderer.gui.rect + +import com.lambda.graphics.buffer.vao.vertex.VertexAttrib +import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.graphics.renderer.gui.AbstractGuiRenderer +import com.lambda.graphics.shader.Shader +import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.math.Vec2d +import org.lwjgl.glfw.GLFW.glfwGetTime + +abstract class AbstractRectRenderer > ( + vertexType: VertexAttrib.Group, + shader: Shader +) : AbstractGuiRenderer(vertexType, shader) { + override fun preRender() { + shader["u_Time"] = glfwGetTime() * GuiSettings.colorSpeed * 5.0 + shader["u_Color1"] = GuiSettings.shadeColor1 + shader["u_Color2"] = GuiSettings.shadeColor2 + shader["u_Size"] = Vec2d.ONE / Vec2d(GuiSettings.colorWidth, GuiSettings.colorHeight) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/IRectEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/IRectEntry.kt new file mode 100644 index 000000000..ace898a07 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/IRectEntry.kt @@ -0,0 +1,23 @@ +package com.lambda.graphics.renderer.gui.rect + +import com.lambda.graphics.renderer.IRenderEntry +import com.lambda.util.math.Rect +import java.awt.Color + +interface IRectEntry > : IRenderEntry { + var position: Rect + var roundRadius: Double + var shade: Boolean + + fun color(leftTop: Color, rightTop: Color, rightBottom: Color, leftBottom: Color) + fun color(color: Color) = color(color, color, color, color) + fun colorH(left: Color, right: Color) = color(left, right, right, left) + fun colorV(top: Color, bottom: Color) = color(top, top, bottom, bottom) + + interface Filled : IRectEntry + + interface Outline : IRectEntry { + var outerGlow: Double + var innerGlow: Double + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt deleted file mode 100644 index a5872139d..000000000 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectEntry.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.lambda.graphics.renderer.gui.rect - -import com.lambda.graphics.buffer.vao.IRenderContext -import com.lambda.graphics.renderer.IRenderEntry -import com.lambda.util.math.Rect -import java.awt.Color -import kotlin.math.min - -class RectEntry( - override val owner: RectRenderer, - override val updateBlock: IRectEntry.() -> Unit -) : IRectEntry { - override var position by owner.positionRect() - override var roundRadius by owner.field(0.0) - - private var leftTop by owner.field(Color.WHITE!!) - private var rightTop by owner.field(Color.WHITE!!) - private var rightBottom by owner.field(Color.WHITE!!) - private var leftBottom by owner.field(Color.WHITE!!) - - override fun color(leftTop: Color, rightTop: Color, rightBottom: Color, leftBottom: Color) { - this.leftTop = leftTop - this.rightTop = rightTop - this.rightBottom = rightBottom - this.leftBottom = leftBottom - } - - override fun build(ctx: IRenderContext) = ctx.use { - if (leftTop .alpha < MIN_ALPHA && - rightTop .alpha < MIN_ALPHA && - rightBottom.alpha < MIN_ALPHA && - leftBottom .alpha < MIN_ALPHA - ) return@use - - val pos1 = position.leftTop - val pos2 = position.rightBottom - - val size = pos2 - pos1 - if (size.x < MIN_SIZE || size.y < MIN_SIZE) return@use - - val halfSize = size * 0.5 - val maxRadius = min(halfSize.x, halfSize.y) - - val round = min(roundRadius, maxRadius) - - val p1 = pos1 - 0.75 - val p2 = pos2 + 0.75 - - grow(4) - - putQuad( - vec2(p1.x, p1.y).vec2(0.0, 0.0).vec3(size.x, size.y, round).color(leftTop).end(), - vec2(p1.x, p2.y).vec2(0.0, 1.0).vec3(size.x, size.y, round).color(leftBottom).end(), - vec2(p2.x, p2.y).vec2(1.0, 1.0).vec3(size.x, size.y, round).color(rightBottom).end(), - vec2(p2.x, p1.y).vec2(1.0, 0.0).vec3(size.x, size.y, round).color(rightTop).end() - ) - } - - companion object { - private const val MIN_ALPHA = 5 - private const val MIN_SIZE = 0.5 - } -} - -interface IRectEntry : IRenderEntry { - var position: Rect - var roundRadius: Double - - fun color(leftTop: Color, rightTop: Color, rightBottom: Color, leftBottom: Color) - - fun color(color: Color) = color(color, color, color, color) - - fun colorH(left: Color, right: Color) = color(left, right, right, left) - - fun colorV(top: Color, bottom: Color) = color(top, top, bottom, bottom) -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt deleted file mode 100644 index bf63317b2..000000000 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/RectRenderer.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.lambda.graphics.renderer.gui.rect - -import com.lambda.graphics.buffer.vao.vertex.VertexAttrib -import com.lambda.graphics.renderer.gui.AbstractGuiRenderer -import com.lambda.graphics.shader.Shader -import com.lambda.module.modules.client.GuiSettings -import com.lambda.util.math.Vec2d -import com.mojang.blaze3d.systems.RenderSystem.blendFunc -import com.mojang.blaze3d.systems.RenderSystem.defaultBlendFunc -import org.lwjgl.glfw.GLFW.glfwGetTime -import org.lwjgl.opengl.GL11.GL_ONE -import org.lwjgl.opengl.GL11.GL_SRC_ALPHA - -class RectRenderer : AbstractGuiRenderer( - VertexAttrib.Group.RECT, shader -) { - var shadeColor = false - var fancyBlending = false - - override fun preRender() { - shader["u_Shade"] = shadeColor - - if (shadeColor) { - shader["u_Time"] = glfwGetTime() * GuiSettings.colorSpeed * 5.0 - shader["u_Color1"] = GuiSettings.shadeColor1 - shader["u_Color2"] = GuiSettings.shadeColor2 - shader["u_Size"] = Vec2d.ONE / Vec2d(GuiSettings.colorWidth, GuiSettings.colorHeight) - } - - if (fancyBlending) blendFunc(GL_SRC_ALPHA, GL_ONE) - } - - override fun render() { - super.render() - defaultBlendFunc() - } - - override fun build(block: IRectEntry.() -> Unit): IRectEntry { - shadeColor = false - return super.build(block) - } - - override fun newEntry(block: IRectEntry.() -> Unit) = - RectEntry(this, block) - - companion object { - private val shader = Shader("renderer/rect") - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt new file mode 100644 index 000000000..76e86fe80 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt @@ -0,0 +1,58 @@ +package com.lambda.graphics.renderer.gui.rect.filled + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.renderer.gui.rect.IRectEntry +import com.lambda.util.math.MathUtils.toInt +import java.awt.Color +import kotlin.math.min + +class FilledRectEntry( + override val owner: FilledRectRenderer, + override val updateBlock: IRectEntry.Filled.() -> Unit +) : IRectEntry.Filled { + override var position by owner.positionRect() + override var roundRadius by owner.field(0.0) + override var shade by owner.field(false) + + private var leftTop by owner.field(Color.WHITE) + private var rightTop by owner.field(Color.WHITE) + private var rightBottom by owner.field(Color.WHITE) + private var leftBottom by owner.field(Color.WHITE) + + override fun color(leftTop: Color, rightTop: Color, rightBottom: Color, leftBottom: Color) { + this.leftTop = leftTop + this.rightTop = rightTop + this.rightBottom = rightBottom + this.leftBottom = leftBottom + } + + override fun build(ctx: IRenderContext) = ctx.use { + val pos1 = position.leftTop + val pos2 = position.rightBottom + + val size = pos2 - pos1 + if (size.x < MIN_SIZE || size.y < MIN_SIZE) return@use + + val halfSize = size * 0.5 + val maxRadius = min(halfSize.x, halfSize.y) + + val round = min(roundRadius, maxRadius) + + val p1 = pos1 - 0.75 + val p2 = pos2 + 0.75 + val s = shade.toInt().toDouble() + + grow(4) + + putQuad( + vec2(p1.x, p1.y).vec2(0.0, 0.0).vec2(size.x, size.y).float(round).float(s).color(leftTop).end(), + vec2(p1.x, p2.y).vec2(0.0, 1.0).vec2(size.x, size.y).float(round).float(s).color(leftBottom).end(), + vec2(p2.x, p2.y).vec2(1.0, 1.0).vec2(size.x, size.y).float(round).float(s).color(rightBottom).end(), + vec2(p2.x, p1.y).vec2(1.0, 0.0).vec2(size.x, size.y).float(round).float(s).color(rightTop).end() + ) + } + + companion object { + private const val MIN_SIZE = 0.5 + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectRenderer.kt new file mode 100644 index 000000000..3100e8e28 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectRenderer.kt @@ -0,0 +1,17 @@ +package com.lambda.graphics.renderer.gui.rect.filled + +import com.lambda.graphics.buffer.vao.vertex.VertexAttrib +import com.lambda.graphics.renderer.gui.rect.AbstractRectRenderer +import com.lambda.graphics.renderer.gui.rect.IRectEntry +import com.lambda.graphics.shader.Shader + +class FilledRectRenderer : AbstractRectRenderer( + VertexAttrib.Group.RECT_FILLED, shader +) { + override fun newEntry(block: IRectEntry.Filled.() -> Unit) = + FilledRectEntry(this, block) + + companion object { + private val shader = Shader("renderer/rect_filled") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectEntry.kt new file mode 100644 index 000000000..00a828496 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectEntry.kt @@ -0,0 +1,91 @@ +package com.lambda.graphics.renderer.gui.rect.outline + +import com.lambda.graphics.buffer.vao.IRenderContext +import com.lambda.graphics.renderer.gui.rect.IRectEntry +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.MathUtils.toInt +import com.lambda.util.math.MathUtils.toRadian +import com.lambda.util.math.Vec2d +import java.awt.Color +import kotlin.math.cos +import kotlin.math.min +import kotlin.math.sin + +class OutlineRectEntry( + override val owner: OutlineRectRenderer, + override val updateBlock: IRectEntry.Outline.() -> Unit +) : IRectEntry.Outline { + override var position by owner.positionRect() + override var roundRadius by owner.field(0.0) + override var shade by owner.field(false) + + override var outerGlow by owner.field(1.0) + override var innerGlow by owner.field(1.0) + + private var leftTop by owner.field(Color.WHITE) + private var rightTop by owner.field(Color.WHITE) + private var rightBottom by owner.field(Color.WHITE) + private var leftBottom by owner.field(Color.WHITE) + + override fun color(leftTop: Color, rightTop: Color, rightBottom: Color, leftBottom: Color) { + this.leftTop = leftTop + this.rightTop = rightTop + this.rightBottom = rightBottom + this.leftBottom = leftBottom + } + + private val quality = 8 + private val verticesCount = quality * 4 + + override fun build(ctx: IRenderContext) = ctx.use { + grow(verticesCount * 3) + + val main = genVertices(0.0, false) + val outer = genVertices(outerGlow, true) + val inner = genVertices(-innerGlow, true) + + fun drawStripWith(vertices: MutableList) { + var prev = main.last() to vertices.last() + repeat(verticesCount) { + val new = main[it] to vertices[it] + putQuad(new.first, new.second, prev.second, prev.first) + prev = new + } + } + + drawStripWith(outer) + drawStripWith(inner) + } + + private fun IRenderContext.genVertices(size: Double, isGlow: Boolean): MutableList { + val r = position.expand(size) + val a = (!isGlow).toInt().toDouble() + + val halfSize = r.size * 0.5 + val maxRadius = min(halfSize.x, halfSize.y) - 0.5 + val round = (roundRadius + size).coerceAtMost(maxRadius) + + fun MutableList.buildCorners(base: Vec2d, c: Color, angleRange: IntRange) = repeat(quality) { + val min = angleRange.first.toDouble() + val max = angleRange.last.toDouble() + val p = it.toDouble() / quality + val angle = lerp(min, max, p).toRadian() + + val pos = base + Vec2d(cos(angle), -sin(angle)) * round + val s = shade.toInt().toDouble() + add(vec2(pos.x, pos.y).float(a).float(s).color(c).end()) + } + + val rt = r.rightTop + Vec2d(-round, round) + val lt = r.leftTop + Vec2d( round, round) + val lb = r.leftBottom + Vec2d( round, -round) + val rb = r.rightBottom + Vec2d(-round, -round) + + return mutableListOf().apply { + buildCorners(rt, rightTop, 0..90) + buildCorners(lt, leftTop, 90..180) + buildCorners(lb, leftBottom, 180..270) + buildCorners(rb, rightBottom, 270..360) + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectRenderer.kt new file mode 100644 index 000000000..9c2c550da --- /dev/null +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/outline/OutlineRectRenderer.kt @@ -0,0 +1,17 @@ +package com.lambda.graphics.renderer.gui.rect.outline + +import com.lambda.graphics.buffer.vao.vertex.VertexAttrib +import com.lambda.graphics.renderer.gui.rect.AbstractRectRenderer +import com.lambda.graphics.renderer.gui.rect.IRectEntry +import com.lambda.graphics.shader.Shader + +class OutlineRectRenderer : AbstractRectRenderer ( + VertexAttrib.Group.RECT_OUTLINE, shader +) { + override fun newEntry(block: IRectEntry.Outline.() -> Unit) = + OutlineRectEntry(this, block) + + companion object { + private val shader = Shader("renderer/rect_outline") + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index d08c6d737..938a17c41 100644 --- a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -28,7 +28,7 @@ object GuiConfigurable : Configurable(GuiConfig), Loadable { private val defaultWindows get() = ModuleTag.defaults.mapIndexed { index, tag -> TagWindow(tag, ownerGui).apply { - val step = 3.0 + val step = 5.0 forceSetPosition(Vec2d((width + step) * index, 0.0) + step) } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index adda26adc..121c6c64b 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -66,14 +66,25 @@ abstract class WindowComponent ( init { // Background - renderer.rect { + renderer.filled { position = rect roundRadius = ClickGui.windowRadius + shade = GuiSettings.shadeBackground val alpha = (showAnimation * 2.0).coerceIn(0.0, 1.0) color(GuiSettings.backgroundColor.multAlpha(alpha)) } + renderer.outline { + position = rect + roundRadius = ClickGui.windowRadius + outerGlow = ClickGui.windowRadius + shade = GuiSettings.shade + + val alpha = (showAnimation * 2.0).coerceIn(0.0, 1.0) + color(GuiSettings.mainColor.multAlpha(alpha)) + } + // Title titleFont = renderer.font { text = title @@ -104,10 +115,7 @@ abstract class WindowComponent ( layer.render() scissor(contentRect) { - subLayer.apply { - allowEffects = true - render() - } + subLayer.render() } } @@ -130,7 +138,7 @@ abstract class WindowComponent ( isOpen = !isOpen - if (isOpen) contentComponents.onEvent(GuiEvent.Show()) + if (isOpen) onEvent(GuiEvent.Show()) } } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index bb9640e09..56f45b9aa 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -41,15 +41,17 @@ abstract class ButtonComponent( init { // Active color - renderer.rect { + renderer.filled { position = rect.shrink(interactAnimation) + shade = GuiSettings.shade color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.3 * showAnimation)) } // Hover glint - renderer.rect { + renderer.filled { val hoverRect = Rect.basedOn(rect.leftTop, rect.size.x * hoverRectAnimation, rect.size.y) position = hoverRect.shrink(interactAnimation) + shade = GuiSettings.shade val alpha = interactAnimation * 0.2 color(GuiSettings.mainColor.multAlpha(alpha)) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 81d9377c3..94e40c078 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -17,7 +17,6 @@ abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { override fun onEvent(e: GuiEvent) { super.onEvent(e) - if (e is GuiEvent.Show) renderHeightOffset = 0.0 } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt index 2e93ac3ee..34d29cf32 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/LayerEntry.kt @@ -3,17 +3,21 @@ package com.lambda.gui.api.layer import com.lambda.graphics.renderer.IRenderEntry import com.lambda.graphics.renderer.IRenderer import com.lambda.graphics.renderer.gui.font.IFontEntry -import com.lambda.graphics.renderer.gui.rect.filled.IRectEntry +import com.lambda.graphics.renderer.gui.rect.IRectEntry // Used to group all render entries related to a component class LayerEntry ( - private val rect: IRenderer, + private val filled: IRenderer, + private val outline: IRenderer, private val font: IRenderer ) { private val entries = mutableSetOf>() - fun rect(block: IRectEntry.() -> Unit) = - rect.build(block).apply(entries::add) + fun filled(block: IRectEntry.Filled.() -> Unit) = + filled.build(block).apply(entries::add) + + fun outline(block: IRectEntry.Outline.() -> Unit) = + outline.build(block).apply(entries::add) fun font(block: IFontEntry.() -> Unit) = font.build(block).apply(entries::add) diff --git a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt index d2b90c41b..017d43700 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/layer/RenderLayer.kt @@ -1,38 +1,38 @@ package com.lambda.gui.api.layer import com.lambda.graphics.renderer.gui.font.FontRenderer -import com.lambda.graphics.renderer.gui.rect.filled.RectRenderer +import com.lambda.graphics.renderer.gui.rect.AbstractRectRenderer +import com.lambda.graphics.renderer.gui.rect.filled.FilledRectRenderer +import com.lambda.graphics.renderer.gui.rect.outline.OutlineRectRenderer import com.lambda.module.modules.client.GuiSettings import com.lambda.util.math.Vec2d class RenderLayer { - var allowEffects = false - - private val rect = RectRenderer() + private val filled = FilledRectRenderer() + private val outline = OutlineRectRenderer() private val font = FontRenderer() - fun entry() = LayerEntry(rect, font) + fun entry() = LayerEntry(filled, outline, font) fun assignOffset(ofs: Vec2d) { - rect.matrixOffset = ofs + filled.matrixOffset = ofs + outline.matrixOffset = ofs font.matrixOffset = ofs } fun render() { - rect.update() + filled.update() + outline.update() font.update() - rect.apply { - shadeColor = GuiSettings.shade && allowEffects - fancyBlending = GuiSettings.glow && allowEffects - } - - rect.render() + filled.render() + outline.render() font.render() } fun destroy() { - rect.destroy() + filled.destroy() + outline.destroy() font.destroy() } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index dab67a17e..bcf045f14 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -24,7 +24,7 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o init { // Toggle fx - renderer.rect { + renderer.filled { val left = rect - Vec2d(rect.size.x, 0.0) val right = rect + Vec2d(rect.size.x, 0.0) @@ -40,10 +40,17 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o val leftColor = color.multAlpha(1.0 - toggleFxDirection) val rightColor = color.multAlpha(toggleFxDirection) + shade = GuiSettings.shade colorH(leftColor, rightColor) } } + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + + if (e is GuiEvent.Show) toggleFxDirection = 0.0 + } + override fun performClickAction(e: GuiEvent.MouseClick) { when (e.button) { Mouse.Button.Left -> if (hovered) module.toggle() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index fdeebf104..71446453a 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -13,15 +13,10 @@ abstract class SettingButton > ( owner: WindowComponent<*> ): ListButton(owner) { protected var value by setting - var visible = true + var visible = false - private var visibilityAnimation by animation.exp(0.0, 1.0, 0.6, ::visible) + private var visibilityAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (visible) 0.2 else 0.8 }, ::visible) override val showAnimation get() = lerp(0.0, super.showAnimation, visibilityAnimation) - override val targetHeightOffset: Double get() { - var out = super.targetHeightOffset - if (!visible) out -= size.y * 0.5 - return out - } override var accessible: Boolean = false; get() = field && visible diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt index eba68547a..facca8785 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt @@ -17,11 +17,11 @@ object GuiSettings : Module( // Colors private val primaryColor by setting("Primary Color", Color(130, 200, 255), visibility = { page == Page.Colors }) private val secondaryColor by setting("Secondary Color", Color(225, 130, 225), visibility = { page == Page.Colors && shade }) - val backgroundColor by setting("Background Color", Color(0, 0, 0, 80), visibility = { page == Page.Colors }) - val glow by setting("Glow", true, visibility = { page == Page.Colors }) - val shade by setting("Shade Color", true, visibility = { page == Page.Colors }) - val colorWidth by setting("Color Width", 40.0, 1.0..100.0, 1.0, visibility = { page == Page.Colors && shade }) - val colorHeight by setting("Color Height", 40.0, 1.0..100.0, 1.0, visibility = { page == Page.Colors && shade }) + val backgroundColor by setting("Background Color", Color(50, 50, 50), visibility = { page == Page.Colors }) + val shade by setting("Shade", true, visibility = { page == Page.Colors }) + val shadeBackground by setting("Shade Background", true, visibility = { page == Page.Colors }) + val colorWidth by setting("Color Width", 100.0, 1.0..100.0, 1.0, visibility = { page == Page.Colors && shade }) + val colorHeight by setting("Color Height", 100.0, 1.0..100.0, 1.0, visibility = { page == Page.Colors && shade }) val colorSpeed by setting("Color Speed", 1.0, 0.1..10.0, 0.1, visibility = { page == Page.Colors && shade }) val mainColor: Color get() = if (shade) Color.WHITE else primaryColor diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag similarity index 86% rename from common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect.frag rename to common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag index 08a07c8be..3f3fdea26 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag @@ -1,6 +1,5 @@ #version 330 core -uniform bool u_Shade; uniform float u_Time; uniform vec4 u_Color1; uniform vec4 u_Color2; @@ -11,18 +10,19 @@ in vec2 v_TexCoord; in vec4 v_Color; in vec2 v_Size; in float v_RoundRadius; +in float v_Shade; out vec4 color; #define SMOOTHING 0.5 vec4 shade() { - if (!u_Shade) return v_Color; + if (v_Shade != 1.0) return v_Color; vec2 pos = v_Position * u_Size; float p = sin(pos.x + pos.y - u_Time) * 0.5 + 0.5; - return mix(u_Color1, u_Color2, p) * vec4(1.0, 1.0, 1.0, v_Color.a); + return mix(u_Color1, u_Color2, p) * v_Color; } vec4 round() { diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag new file mode 100644 index 000000000..19fb62887 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag @@ -0,0 +1,31 @@ +#version 330 core + +uniform float u_Time; +uniform vec4 u_Color1; +uniform vec4 u_Color2; +uniform vec2 u_Size; + +in vec2 v_Position; +in float v_Alpha; +in vec4 v_Color; +in float v_Shade; + +out vec4 color; + +vec4 shade() { + if (v_Shade != 1.0) return v_Color; + + vec2 pos = v_Position * u_Size; + float p = sin(pos.x + pos.y - u_Time) * 0.5 + 0.5; + + return mix(u_Color1, u_Color2, p) * v_Color; +} + +vec4 glow() { + float newAlpha = min(1.0, (v_Alpha * v_Alpha)); + return vec4(1.0, 1.0, 1.0, newAlpha); +} + +void main() { + color = shade() * glow(); +} \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert similarity index 61% rename from common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect.vert rename to common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert index 39940d4b9..accd43403 100644 --- a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect.vert +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert @@ -2,8 +2,10 @@ layout (location = 0) in vec4 pos; layout (location = 1) in vec2 uv; -layout (location = 2) in vec3 data; -layout (location = 3) in vec4 color; +layout (location = 2) in vec2 size; +layout (location = 3) in float round; +layout (location = 4) in float shade; +layout (location = 5) in vec4 color; uniform mat4 u_Projection; uniform mat4 u_ModelView; @@ -13,6 +15,7 @@ out vec2 v_TexCoord; out vec4 v_Color; out vec2 v_Size; out float v_RoundRadius; +out float v_Shade; void main() { gl_Position = u_Projection * u_ModelView * pos; @@ -21,6 +24,7 @@ void main() { v_TexCoord = uv; v_Color = color; - v_Size = data.xy; - v_RoundRadius = data.z; + v_Size = size; + v_RoundRadius = round; + v_Shade = shade; } \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert new file mode 100644 index 000000000..6beb3f5b8 --- /dev/null +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert @@ -0,0 +1,23 @@ +#version 330 core + +layout (location = 0) in vec4 pos; +layout (location = 1) in float alpha; +layout (location = 2) in float shade; +layout (location = 3) in vec4 color; + +uniform mat4 u_Projection; +uniform mat4 u_ModelView; + +out vec2 v_Position; +out float v_Alpha; +out vec4 v_Color; +out float v_Shade; + +void main() { + gl_Position = u_Projection * u_ModelView * pos; + + v_Position = pos.xy; + v_Alpha = alpha; + v_Color = color; + v_Shade = shade; +} \ No newline at end of file From 9ade9f7ce4d2bd304d701553eda4494d2170844d Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 5 May 2024 12:51:40 +0300 Subject: [PATCH 46/63] Child logic rework(again), dropdown buttons --- .../gui/CustomModuleWindowSerializer.kt | 4 +- .../serializer/gui/TagWindowSerializer.kt | 4 +- .../kotlin/com/lambda/graphics/gl/Scissor.kt | 15 ++-- .../kotlin/com/lambda/gui/GuiConfigurable.kt | 2 +- .../kotlin/com/lambda/gui/api/LambdaGui.kt | 3 + .../gui/api/component/InteractiveComponent.kt | 4 +- .../lambda/gui/api/component/ListWindow.kt | 2 - .../gui/api/component/WindowComponent.kt | 52 ++++++------- .../api/component/button/ButtonComponent.kt | 28 ++++--- .../gui/api/component/button/ListButton.kt | 8 +- .../gui/api/component/core/IComponent.kt | 5 ++ .../gui/api/component/core/IRectComponent.kt | 7 -- .../api/component/core/list/ChildComponent.kt | 4 +- .../gui/api/component/core/list/ChildLayer.kt | 26 ++++++- .../gui/impl/clickgui/AbstractClickGui.kt | 25 +++--- .../gui/impl/clickgui/LambdaClickGui.kt | 2 +- .../gui/impl/clickgui/buttons/ModuleButton.kt | 78 ++++++++++++------- .../impl/clickgui/buttons/SettingButton.kt | 4 +- .../clickgui/buttons/setting/BooleanButton.kt | 4 +- .../impl/clickgui/windows/SettingWindow.kt | 45 ----------- .../windows/tag/CustomModuleWindow.kt | 6 +- .../impl/clickgui/windows/tag/TagWindow.kt | 2 +- 22 files changed, 160 insertions(+), 170 deletions(-) delete mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/core/IRectComponent.kt delete mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt index f06fb7cae..ba71fda64 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/CustomModuleWindowSerializer.kt @@ -47,10 +47,10 @@ object CustomModuleWindowSerializer : JsonSerializer, JsonDe width = it["width"].asDouble height = it["height"].asDouble isOpen = it["isOpen"].asBoolean - forceSetPosition(Vec2d( + position = Vec2d( it["position"].asJsonArray[0].asDouble, it["position"].asJsonArray[1].asDouble - )) + ) } } ?: throw JsonParseException("Invalid window data") } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt index a6f8033bb..e9a3731a3 100644 --- a/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt +++ b/common/src/main/kotlin/com/lambda/config/serializer/gui/TagWindowSerializer.kt @@ -34,10 +34,10 @@ object TagWindowSerializer : JsonSerializer, JsonDeserializer Unit) { - scissor(rect) + stack.add(rect) + scissor(rect) block() stack.removeLast() @@ -28,22 +30,19 @@ object Scissor { private fun scissor(entry: Rect?) { if (entry == null) { - glDisable(GL_SCISSOR_TEST) + RenderSystem.disableScissor() return } - stack.add(entry) - val pos1 = entry.leftTop * GuiSettings.scale val pos2 = entry.rightBottom * GuiSettings.scale - val width = max(pos2.x - pos1.x, 0.0) - val height = max(pos2.y - pos1.y, 0.0) + val width = max(pos2.x - pos1.x, 1.0) + val height = max(pos2.y - pos1.y, 1.0) val y = mc.window.framebufferHeight - pos1.y - height - glEnable(GL_SCISSOR_TEST) - glScissor( + RenderSystem.enableScissor( pos1.x.floorToInt(), y.floorToInt(), width.ceilToInt(), diff --git a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt index 938a17c41..1266d531a 100644 --- a/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt +++ b/common/src/main/kotlin/com/lambda/gui/GuiConfigurable.kt @@ -29,7 +29,7 @@ object GuiConfigurable : Configurable(GuiConfig), Loadable { ModuleTag.defaults.mapIndexed { index, tag -> TagWindow(tag, ownerGui).apply { val step = 5.0 - forceSetPosition(Vec2d((width + step) * index, 0.0) + step) + position = Vec2d((width + step) * index, 0.0) + step } } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt index f4ceab393..5700cba2c 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/LambdaGui.kt @@ -11,6 +11,7 @@ import com.lambda.module.Module import com.lambda.util.KeyCode import com.lambda.util.Mouse import com.lambda.util.Nameable +import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall import net.minecraft.client.gui.DrawContext @@ -23,6 +24,8 @@ abstract class LambdaGui( private val owner: Module? = null ) : Screen(Text.of(name)), IComponent, Nameable { private var screenSize = Vec2d.ZERO + override val rect get() = Rect(Vec2d.ZERO, screenSize) + val animation = AnimationTicker() private val renderListener = UnsafeListener(0, this, false) { event -> diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt index 4d975a59c..0548c1875 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt @@ -2,10 +2,10 @@ package com.lambda.gui.api.component import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.IComponent -import com.lambda.gui.api.component.core.IRectComponent import com.lambda.util.Mouse +import com.lambda.util.math.Rect -abstract class InteractiveComponent : IComponent, IRectComponent { +abstract class InteractiveComponent : IComponent { protected var hovered = false protected var pressed = false diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt index 420da3df1..e08904f30 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt @@ -3,7 +3,6 @@ package com.lambda.gui.api.component import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.AbstractClickGui -import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.ClickGui abstract class ListWindow ( @@ -13,7 +12,6 @@ abstract class ListWindow ( if (e is GuiEvent.Show || e is GuiEvent.Tick) { var y = 0.0 contentComponents.children.forEach { button -> - if (button is SettingButton<*, *> && !button.visible) return@forEach button.heightOffset = y y += button.size.y + ClickGui.buttonStep } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 121c6c64b..5d546993f 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -1,6 +1,5 @@ package com.lambda.gui.api.component -import com.lambda.Lambda.mc import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.graphics.renderer.gui.font.IFontEntry @@ -18,27 +17,27 @@ import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d -import com.lambda.util.primitives.extension.partialTicks import java.awt.Color import kotlin.math.abs abstract class WindowComponent ( final override val owner: AbstractClickGui -) : ChildComponent() { +) : ChildComponent(owner) { abstract val title: String abstract var width: Double abstract var height: Double var position = Vec2d.ZERO - private var prevPosition = position var isOpen = true + override val isActive get() = isOpen + private var dragOffset: Vec2d? = null private val padding get() = ClickGui.windowPadding - final override val rect get() = Rect.basedOn(renderPosition, width, renderHeight + titleBarHeight) - val contentRect get() = rect.shrink(padding).moveFirst(Vec2d(0.0, titleBarHeight - padding)) + final override val rect get() = Rect.basedOn(position, width, renderHeight + titleBarHeight) + private val contentRect get() = rect.shrink(padding).moveFirst(Vec2d(0.0, titleBarHeight - padding)) private val titleBar get() = Rect.basedOn(rect.leftTop, rect.size.x, titleBarHeight) private val titleBarHeight get() = titleFont.height + 2 + padding * 2 @@ -46,19 +45,20 @@ abstract class WindowComponent ( private val layer = RenderLayer() private val renderer = layer.entry() - val subLayer = RenderLayer() + private val contentLayer = RenderLayer() + + private val animation = owner.animation + private val gui = owner - val animation = owner.animation - open val showAnimation get() = owner.showAnimation + // Show animation for children + private val showAnimation0 by animation.exp(0.0, 1.0, 0.5, ::isOpen) + override val showAnimation get() = lerp(0.0, showAnimation0, gui.showAnimation) private val actualHeight get() = height + padding * 2 * isOpen.toInt() private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) private val renderHeight get() = lerp(0.0, renderHeightAnimation, showAnimation) - private val renderPosition get() = lerp(prevPosition, position, mc.partialTicks) - val contentComponents = ChildLayer { child -> - child.rect in contentRect && accessible && isOpen - } + val contentComponents = ChildLayer.Drawable(gui, this, contentLayer, ::contentRect) /*val titleBarComponents = ChildLayer { child -> child.rect in titleBar && accessible @@ -71,7 +71,7 @@ abstract class WindowComponent ( roundRadius = ClickGui.windowRadius shade = GuiSettings.shadeBackground - val alpha = (showAnimation * 2.0).coerceIn(0.0, 1.0) + val alpha = (gui.showAnimation * 2.0).coerceIn(0.0, 1.0) color(GuiSettings.backgroundColor.multAlpha(alpha)) } @@ -81,7 +81,7 @@ abstract class WindowComponent ( outerGlow = ClickGui.windowRadius shade = GuiSettings.shade - val alpha = (showAnimation * 2.0).coerceIn(0.0, 1.0) + val alpha = (gui.showAnimation * 2.0).coerceIn(0.0, 1.0) color(GuiSettings.mainColor.multAlpha(alpha)) } @@ -89,7 +89,7 @@ abstract class WindowComponent ( titleFont = renderer.font { text = title position = titleBar.center - widthVec * 0.5 - color = Color.WHITE.setAlpha(showAnimation) + color = Color.WHITE.setAlpha(gui.showAnimation) } } @@ -101,13 +101,9 @@ abstract class WindowComponent ( dragOffset = null } - is GuiEvent.Tick -> { - prevPosition = position - } - is GuiEvent.Render -> { - layer.assignOffset(renderPosition) - subLayer.assignOffset(renderPosition) + layer.assignOffset(position) + contentLayer.assignOffset(position) // TODO: fix blur // BlurPostProcessor.render(rect, ClickGui.windowBlur, guiAnimation) @@ -115,8 +111,11 @@ abstract class WindowComponent ( layer.render() scissor(contentRect) { - subLayer.render() + contentLayer.render() + contentComponents.onEvent(e) } + + return } is GuiEvent.MouseMove -> { @@ -149,11 +148,6 @@ abstract class WindowComponent ( //titleBarComponents.onEvent(e) } - fun forceSetPosition(pos: Vec2d) { - position = pos - prevPosition = position - } - fun focus() { // move window into foreground owner.apply { @@ -177,6 +171,6 @@ abstract class WindowComponent ( override fun onRemove() { layer.destroy() - subLayer.destroy() + contentLayer.destroy() } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 56f45b9aa..b1008fe5e 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -2,8 +2,8 @@ package com.lambda.gui.api.component.button import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildComponent +import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui import com.lambda.module.modules.client.GuiSettings import com.lambda.util.math.ColorUtils.multAlpha @@ -13,31 +13,29 @@ import com.lambda.util.math.Vec2d import java.awt.Color abstract class ButtonComponent( - final override val owner: WindowComponent<*> -) : ChildComponent() { + final override val owner: ChildLayer.Drawable<*> +) : ChildComponent(owner) { abstract val position: Vec2d abstract val size: Vec2d abstract val text: String + protected open val textY: Double get() = rect.size.y protected abstract var activeAnimation: Double - private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.contentRect.size.x else size.x, size.y) - final override val rect get() = Rect.basedOn(position, actualSize) + owner.contentRect.leftTop + private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.rect.size.x else size.x, size.y) + final override val rect get() = Rect.basedOn(position, actualSize) + owner.rect.leftTop - private val layer = owner.subLayer - protected val renderer = layer.entry() - protected val animation = owner.animation + protected val renderer = owner.renderer.entry() + protected val animation = owner.gui.animation private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.6 else 0.07 }, ::renderHovered) private var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) protected val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 - private val showAnimationRaw by animation.exp(0.0, 1.0, 0.7, owner::isOpen) - protected open val showAnimation get() = lerp(0.0, showAnimationRaw, owner.showAnimation) + override val showAnimation: Double get() = owner.showAnimation private var lastHoveredTime = 0L - private val renderHovered get() = hovered || - System.currentTimeMillis() - lastHoveredTime < 110 // a bit more than 2 ticks + private val renderHovered get() = hovered || System.currentTimeMillis() - lastHoveredTime < 110 init { // Active color @@ -64,8 +62,8 @@ abstract class ButtonComponent( color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation).multAlpha(showAnimation) - val x = rect.left + ClickGui.windowPadding + interactAnimation + hoverFontAnimation - position = Vec2d(x, rect.center.y) + val x = ClickGui.windowPadding + interactAnimation + hoverFontAnimation + position = rect.leftTop + Vec2d(x, textY) } } @@ -85,7 +83,7 @@ abstract class ButtonComponent( } override fun onRelease(e: GuiEvent.MouseClick) { - performClickAction(e) + if (hovered) performClickAction(e) } override fun onRemove() { diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 94e40c078..7728b7813 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -2,18 +2,18 @@ package com.lambda.gui.api.component.button import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Vec2d -abstract class ListButton(owner: WindowComponent<*>) : ButtonComponent(owner) { +abstract class ListButton(owner: ChildLayer.Drawable<*>) : ButtonComponent(owner) { override val position get() = Vec2d(0.0, renderHeightOffset) override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) var heightOffset = 0.0 - protected open val targetHeightOffset get() = heightOffset * owner.showAnimation * owner.isOpen.toInt() - private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.5) + protected open val targetHeightOffset get() = heightOffset * owner.showAnimation * owner.isActive.toInt() + private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.7) override fun onEvent(e: GuiEvent) { super.onEvent(e) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt index 1197a9446..6a84e6f82 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt @@ -1,7 +1,12 @@ package com.lambda.gui.api.component.core import com.lambda.gui.api.GuiEvent +import com.lambda.util.math.Rect interface IComponent { + val isActive: Boolean get() = true + val showAnimation: Double get() = 1.0 + val rect: Rect + fun onEvent(e: GuiEvent) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/IRectComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/IRectComponent.kt deleted file mode 100644 index 0843a1ccb..000000000 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/IRectComponent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.lambda.gui.api.component.core - -import com.lambda.util.math.Rect - -interface IRectComponent { - val rect: Rect -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index 2c9805afb..50d8b87fa 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -4,13 +4,11 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.InteractiveComponent import com.lambda.gui.api.component.core.IComponent -abstract class ChildComponent : InteractiveComponent() { - abstract val owner: IComponent +abstract class ChildComponent(open val owner: IComponent) : InteractiveComponent() { open var accessible = false override fun onEvent(e: GuiEvent) { super.onEvent(e) - if (e is GuiEvent.MouseMove) hovered = hovered && accessible } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt index f2a4c9545..0461f4e42 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt @@ -1,10 +1,21 @@ package com.lambda.gui.api.component.core.list import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.core.IComponent +import com.lambda.gui.api.layer.RenderLayer import com.lambda.util.Mouse - -open class ChildLayer (val childAccessible: (T) -> Boolean) : IComponent { +import com.lambda.util.math.Rect + +open class ChildLayer ( + val gui: LambdaGui, + val owner: IComponent, + private val childRect: () -> Rect, + private val childAccessible: (T) -> Boolean = { true } +) : IComponent { + override val isActive get() = owner.isActive + override val showAnimation get() = owner.showAnimation + override val rect get() = childRect() val children = mutableListOf() fun addChild(child : T) { @@ -21,7 +32,8 @@ open class ChildLayer (val childAccessible: (T) -> Boolean) children.forEach { child -> when (e) { is GuiEvent.Tick -> { - child.accessible = childAccessible(child) + val ownerAccessible = (owner as? ChildComponent)?.accessible ?: true + child.accessible = childAccessible(child) && child.rect in rect && ownerAccessible && owner.isActive } is GuiEvent.KeyPress, is GuiEvent.CharTyped -> { @@ -39,4 +51,12 @@ open class ChildLayer (val childAccessible: (T) -> Boolean) child.onEvent(e) } } + + class Drawable ( + gui: LambdaGui, + owner: IComponent, + val renderer: RenderLayer, + contentRect: () -> Rect, + childAccessible: (T) -> Boolean = { true } + ) : ChildLayer(gui, owner, contentRect, childAccessible) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index c27190cdd..2815d7f0e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -6,21 +6,21 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildLayer -import com.lambda.gui.impl.clickgui.windows.SettingWindow import com.lambda.module.modules.client.ClickGui +import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui) { - val windows = ChildLayer> { child -> - child == activeWindow && !closing - } - private var activeWindow: WindowComponent<*>? = null - private var closing = false - var showAnimation by animation.exp(0.0, 1.0, { + + final override var showAnimation by animation.exp(0.0, 1.0, { if (closing) ClickGui.closeSpeed else ClickGui.openSpeed }) { !closing }; private set + val windows = ChildLayer>(this, this, ::rect) { child -> + child == activeWindow && !closing + } + private val actionPool = ArrayDeque<() -> Unit>() fun scheduleAction(block: () -> Unit) = actionPool.add(block) @@ -32,10 +32,6 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli activeWindow = null closing = false showAnimation = 0.0 - - windows.children - .filterIsInstance() - .forEach(WindowComponent<*>::destroy) } is GuiEvent.Tick -> { @@ -56,6 +52,13 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli windows.onEvent(e) } + fun showWindow(window: WindowComponent<*>) { + // we have to wait some time to place this window over other ones + recordRenderCall { + windows.addChild(window) + } + } + override fun close() { closing = true } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt index 98de93a14..2fbad35ad 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/LambdaClickGui.kt @@ -14,7 +14,7 @@ object LambdaClickGui : AbstractClickGui() { fun updateWindows() { windows.apply { val windows = GuiConfigurable.mainWindows + GuiConfigurable.customWindows - children.addAll(windows.subtract(children.toSet())) + windows.subtract(children.toSet()).forEach(::showWindow) children.filter { it !in windows && it is CustomModuleWindow } .forEach(WindowComponent<*>::destroy) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index bcf045f14..1c39bc298 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,26 +1,39 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.graphics.gl.Scissor.scissor import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.button.ListButton -import com.lambda.gui.impl.clickgui.windows.SettingWindow +import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.api.layer.RenderLayer import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Vec2d -import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall import kotlin.math.abs -class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(owner) { +class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButton(owner) { override val text get() = module.name private val active get() = module.isEnabled - private val gui = owner.owner + + override val size: Vec2d get() = super.size + Vec2d(0.0, renderHeight) + override val textY: Double get() = super.size.y * 0.5 override var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::active) - private var toggleFxDirection by animation.exp(0.0, 1.0, 0.7, ::active) + private val toggleFxDirection by animation.exp(0.0, 1.0, 0.7, ::active) + + private var isOpen = false + override val isActive get() = isOpen + + private var settingsHeight = 0.0 + private var renderHeight by animation.exp(::settingsHeight, 0.6) + private val settingsRect get() = rect.moveFirst(Vec2d(0.0, super.size.y)) + + private val settingsRenderer = RenderLayer() + private val settingsLayer = ChildLayer.Drawable>(owner.gui, this, settingsRenderer, ::settingsRect) init { // Toggle fx @@ -48,30 +61,43 @@ class ModuleButton(val module: Module, owner: WindowComponent<*>) : ListButton(o override fun onEvent(e: GuiEvent) { super.onEvent(e) - if (e is GuiEvent.Show) toggleFxDirection = 0.0 + when (e) { + is GuiEvent.Show -> { + isOpen = false + renderHeight = 0.0 + } + + is GuiEvent.Tick -> { + updateSettingsHeight() + } + + is GuiEvent.Render -> { + scissor(settingsRect) { + settingsRenderer.render() + settingsLayer.onEvent(e) + } + return + } + } + } + + private fun updateSettingsHeight() { + /*val c = settingsLayer.children + settingsHeight = c.sumOf { it.size.y } + ((c.size - 1) * ClickGui.buttonStep).coerceAtLeast(0.0)*/ + + settingsHeight = 30.0 * isOpen.toInt() } override fun performClickAction(e: GuiEvent.MouseClick) { when (e.button) { - Mouse.Button.Left -> if (hovered) module.toggle() - Mouse.Button.Right -> { // Open new settings window - gui.apply { - val check = windows.children - .filterIsInstance() - .filter { it.button.module == module } - .onEach { it.isOpen = false } - .isNotEmpty() - - if (check) return - - // we have to wait this tag window to be focused after handling a click event - // to place settings window over it - recordRenderCall { - SettingWindow(this@ModuleButton, this).apply { - forceSetPosition(e.mouse) - }.apply(windows::addChild) - } - } + Mouse.Button.Left -> module.toggle() + Mouse.Button.Right -> { + // Don't let user spam + val targetHeight = if (isOpen) settingsHeight else 0.0 + if (abs(targetHeight - renderHeight) > 1) return + + isOpen = !isOpen + updateSettingsHeight() } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index 71446453a..9d0957fb7 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -3,14 +3,14 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.config.AbstractSetting import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.button.ListButton +import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.toInt abstract class SettingButton > ( val setting: T, - owner: WindowComponent<*> + owner: ChildLayer.Drawable<*> ): ListButton(owner) { protected var value by setting var visible = false diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 3666817cc..f9761e63f 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -3,13 +3,13 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.WindowComponent +import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.util.Mouse class BooleanButton( setting: BooleanSetting, - owner: WindowComponent<*> + owner: ChildLayer.Drawable<*> ) : SettingButton(setting, owner) { override val text = setting.name override var activeAnimation by animation.exp(0.0, 1.0, 0.5, ::value) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt deleted file mode 100644 index e5722a4bf..000000000 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/SettingWindow.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.lambda.gui.impl.clickgui.windows - -import com.lambda.config.settings.comparable.BooleanSetting -import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.gui.api.GuiEvent -import com.lambda.gui.api.component.ListWindow -import com.lambda.gui.impl.clickgui.AbstractClickGui -import com.lambda.gui.impl.clickgui.buttons.ModuleButton -import com.lambda.gui.impl.clickgui.buttons.SettingButton -import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton -import com.lambda.module.modules.client.ClickGui -import com.lambda.util.math.MathUtils.lerp - -class SettingWindow( - val button: ModuleButton, - owner: AbstractClickGui -) : ListWindow>(owner) { - private val module = button.module - - override val title = module.name - override var width = button.owner.width - override var height = 0.0 - - private val showAnimation0 by animation.exp(0.0, 1.0, ClickGui.openSpeed, ::isOpen) - override val showAnimation get() = lerp(0.0, showAnimation0, owner.showAnimation) - - init { - button.module.settings.mapNotNull { setting -> - when (setting) { - is BooleanSetting -> BooleanButton(setting, this) - else -> null - } - }.forEach(contentComponents::addChild) - } - - override fun onEvent(e: GuiEvent) { - super.onEvent(e) - - if (e is GuiEvent.Show || e is GuiEvent.Tick) { - val c = contentComponents.children.filter { it.visible } - height = c.sumOf { it.size.y } + ClickGui.buttonStep * (c.size - 1) - if (showAnimation < 0.05 && !isOpen) destroy() - } - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index 50b491529..b571a5d54 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -5,8 +5,6 @@ import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.Module -import com.lambda.module.ModuleRegistry -import com.lambda.module.tag.ModuleTag class CustomModuleWindow( override var title: String = "Untitled", @@ -25,13 +23,13 @@ class CustomModuleWindow( children.all { button -> button.module != module } - }.map { ModuleButton(it, this@CustomModuleWindow) } + }.map { ModuleButton(it, contentComponents) } .forEach(contentComponents::addChild) // Remove deleted modules children.forEach { button -> if (button.module !in modules) { - owner.scheduleAction { + this@CustomModuleWindow.owner.scheduleAction { removeChild(button) } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt index d5e26f9d0..fe05ea53b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt @@ -13,7 +13,7 @@ class TagWindow( init { ModuleRegistry.modules .filter { it.tag == tag } - .map { ModuleButton(it, this) } + .map { ModuleButton(it, contentComponents) } .forEach(contentComponents::addChild) } } \ No newline at end of file From 9babf6f47dd910b6830ef2ed2d3c836a5132aff8 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 9 May 2024 15:44:23 +0300 Subject: [PATCH 47/63] Setting animations rework --- .../lambda/gui/api/component/ListWindow.kt | 5 +- .../gui/api/component/WindowComponent.kt | 15 ++-- .../api/component/button/ButtonComponent.kt | 8 +- .../gui/api/component/button/ListButton.kt | 14 ++-- .../gui/api/component/core/IComponent.kt | 2 +- .../gui/api/component/core/list/ChildLayer.kt | 2 +- .../gui/impl/clickgui/AbstractClickGui.kt | 6 +- .../gui/impl/clickgui/buttons/ModuleButton.kt | 83 ++++++++++++++----- .../impl/clickgui/buttons/SettingButton.kt | 18 ++-- .../clickgui/buttons/setting/BooleanButton.kt | 32 ++++++- .../module/modules/render/RenderTest.kt | 5 +- .../main/kotlin/com/lambda/util/math/Rect.kt | 2 + 12 files changed, 132 insertions(+), 60 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt index e08904f30..5f094779a 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/ListWindow.kt @@ -3,17 +3,16 @@ package com.lambda.gui.api.component import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.impl.clickgui.AbstractClickGui -import com.lambda.module.modules.client.ClickGui abstract class ListWindow ( owner: AbstractClickGui ) : WindowComponent(owner) { override fun onEvent(e: GuiEvent) { - if (e is GuiEvent.Show || e is GuiEvent.Tick) { + if (e is GuiEvent.Tick) { var y = 0.0 contentComponents.children.forEach { button -> button.heightOffset = y - y += button.size.y + ClickGui.buttonStep + y += button.size.y + button.listStep } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 5d546993f..c4efff751 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -40,7 +40,7 @@ abstract class WindowComponent ( private val contentRect get() = rect.shrink(padding).moveFirst(Vec2d(0.0, titleBarHeight - padding)) private val titleBar get() = Rect.basedOn(rect.leftTop, rect.size.x, titleBarHeight) - private val titleBarHeight get() = titleFont.height + 2 + padding * 2 + private val titleBarHeight get() = ClickGui.buttonHeight + padding * 2 private val titleFont: IFontEntry private val layer = RenderLayer() @@ -50,13 +50,12 @@ abstract class WindowComponent ( private val animation = owner.animation private val gui = owner - // Show animation for children - private val showAnimation0 by animation.exp(0.0, 1.0, 0.5, ::isOpen) - override val showAnimation get() = lerp(0.0, showAnimation0, gui.showAnimation) + private val showAnimation by animation.exp(0.0, 1.0, 0.6, ::isOpen) + override val childShowAnimation get() = lerp(0.0, showAnimation, gui.childShowAnimation) private val actualHeight get() = height + padding * 2 * isOpen.toInt() private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) - private val renderHeight get() = lerp(0.0, renderHeightAnimation, showAnimation) + private val renderHeight get() = lerp(0.0, renderHeightAnimation, childShowAnimation) val contentComponents = ChildLayer.Drawable(gui, this, contentLayer, ::contentRect) @@ -71,7 +70,7 @@ abstract class WindowComponent ( roundRadius = ClickGui.windowRadius shade = GuiSettings.shadeBackground - val alpha = (gui.showAnimation * 2.0).coerceIn(0.0, 1.0) + val alpha = (gui.childShowAnimation * 2.0).coerceIn(0.0, 1.0) color(GuiSettings.backgroundColor.multAlpha(alpha)) } @@ -81,7 +80,7 @@ abstract class WindowComponent ( outerGlow = ClickGui.windowRadius shade = GuiSettings.shade - val alpha = (gui.showAnimation * 2.0).coerceIn(0.0, 1.0) + val alpha = (gui.childShowAnimation * 2.0).coerceIn(0.0, 1.0) color(GuiSettings.mainColor.multAlpha(alpha)) } @@ -89,7 +88,7 @@ abstract class WindowComponent ( titleFont = renderer.font { text = title position = titleBar.center - widthVec * 0.5 - color = Color.WHITE.setAlpha(gui.showAnimation) + color = Color.WHITE.setAlpha(gui.childShowAnimation) } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index b1008fe5e..9a69a68c4 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -19,7 +19,6 @@ abstract class ButtonComponent( abstract val size: Vec2d abstract val text: String - protected open val textY: Double get() = rect.size.y protected abstract var activeAnimation: Double private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.rect.size.x else size.x, size.y) @@ -32,7 +31,8 @@ abstract class ButtonComponent( private var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) protected val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 - override val showAnimation: Double get() = owner.showAnimation + override val childShowAnimation: Double get() = owner.childShowAnimation + protected open val showAnimation get() = owner.childShowAnimation private var lastHoveredTime = 0L private val renderHovered get() = hovered || System.currentTimeMillis() - lastHoveredTime < 110 @@ -51,7 +51,7 @@ abstract class ButtonComponent( position = hoverRect.shrink(interactAnimation) shade = GuiSettings.shade - val alpha = interactAnimation * 0.2 + val alpha = interactAnimation * 0.2 * showAnimation color(GuiSettings.mainColor.multAlpha(alpha)) } @@ -63,7 +63,7 @@ abstract class ButtonComponent( color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation).multAlpha(showAnimation) val x = ClickGui.windowPadding + interactAnimation + hoverFontAnimation - position = rect.leftTop + Vec2d(x, textY) + position = rect.leftTop + Vec2d(x, rect.size.y * 0.5) } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 7728b7813..da9a75b4a 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -4,19 +4,23 @@ import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui -import com.lambda.util.math.MathUtils.toInt +import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Vec2d abstract class ListButton(owner: ChildLayer.Drawable<*>) : ButtonComponent(owner) { - override val position get() = Vec2d(0.0, renderHeightOffset) + override val position get() = Vec2d(0.0, lerp(0.0, renderHeightOffset, owner.childShowAnimation)) override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) + open val listStep get() = ClickGui.buttonStep + var heightOffset = 0.0 - protected open val targetHeightOffset get() = heightOffset * owner.showAnimation * owner.isActive.toInt() - private var renderHeightOffset by animation.exp(::targetHeightOffset, 0.7) + protected open var renderHeightOffset by animation.exp(::heightOffset, 0.9) override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Show) { + heightOffset = 0.0 + renderHeightOffset = 0.0 + } super.onEvent(e) - if (e is GuiEvent.Show) renderHeightOffset = 0.0 } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt index 6a84e6f82..751523395 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/IComponent.kt @@ -5,7 +5,7 @@ import com.lambda.util.math.Rect interface IComponent { val isActive: Boolean get() = true - val showAnimation: Double get() = 1.0 + val childShowAnimation: Double get() = 1.0 val rect: Rect fun onEvent(e: GuiEvent) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt index 0461f4e42..f509c8ca5 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt @@ -14,7 +14,7 @@ open class ChildLayer ( private val childAccessible: (T) -> Boolean = { true } ) : IComponent { override val isActive get() = owner.isActive - override val showAnimation get() = owner.showAnimation + override val childShowAnimation get() = owner.childShowAnimation override val rect get() = childRect() val children = mutableListOf() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 2815d7f0e..06c766d0a 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -13,7 +13,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli private var activeWindow: WindowComponent<*>? = null private var closing = false - final override var showAnimation by animation.exp(0.0, 1.0, { + final override var childShowAnimation by animation.exp(0.0, 1.0, { if (closing) ClickGui.closeSpeed else ClickGui.openSpeed }) { !closing }; private set @@ -31,11 +31,11 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli is GuiEvent.Show -> { activeWindow = null closing = false - showAnimation = 0.0 + childShowAnimation = 0.0 } is GuiEvent.Tick -> { - if (closing && showAnimation < 0.01) mc.setScreen(null) + if (closing && childShowAnimation < 0.01) mc.setScreen(null) } is GuiEvent.MouseClick -> { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 1c39bc298..2a32ccb47 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,39 +1,45 @@ package com.lambda.gui.impl.clickgui.buttons +import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer +import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp -import com.lambda.util.math.MathUtils.toInt +import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d import kotlin.math.abs class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButton(owner) { override val text get() = module.name - private val active get() = module.isEnabled + private val enabled get() = module.isEnabled - override val size: Vec2d get() = super.size + Vec2d(0.0, renderHeight) - override val textY: Double get() = super.size.y * 0.5 + override var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::enabled) + private val toggleFxDirection by animation.exp(0.0, 1.0, 0.7, ::enabled) - override var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::active) - private val toggleFxDirection by animation.exp(0.0, 1.0, 0.7, ::active) + override val listStep: Double get() = super.listStep * 2.0 + renderHeight private var isOpen = false override val isActive get() = isOpen + private val childShowAnimation0 by animation.exp(0.0, 1.0, 0.7, ::isOpen) + override val childShowAnimation get() = lerp(0.0, childShowAnimation0, owner.childShowAnimation) + private var settingsHeight = 0.0 private var renderHeight by animation.exp(::settingsHeight, 0.6) - private val settingsRect get() = rect.moveFirst(Vec2d(0.0, super.size.y)) + private val settingsRect get() = rect + .moveFirst(Vec2d(childShowAnimation * 2.0, size.y + super.listStep)) + .moveSecond(Vec2d(0.0, listStep)) private val settingsRenderer = RenderLayer() - private val settingsLayer = ChildLayer.Drawable>(owner.gui, this, settingsRenderer, ::settingsRect) + private val settingsLayer = ChildLayer.Drawable(owner.gui, this, settingsRenderer, ::settingsRect, SettingButton<*, *>::visible) init { // Toggle fx @@ -56,36 +62,72 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt shade = GuiSettings.shade colorH(leftColor, rightColor) } + + // Line + renderer.filled { + val pos1 = Vec2d(rect.left, settingsRect.top) + val pos2 = Vec2d(rect.left + childShowAnimation * 1.0, settingsRect.bottom) + val color = GuiSettings.mainColor.multAlpha(childShowAnimation * 0.6) + + position = Rect(pos1, pos2) + + shade = GuiSettings.shade + color(color) + } + + module.settings.mapNotNull { + when (it) { + is BooleanSetting -> BooleanButton(it, settingsLayer) + else -> null + } + }.forEach(settingsLayer::addChild) } override fun onEvent(e: GuiEvent) { - super.onEvent(e) - when (e) { is GuiEvent.Show -> { isOpen = false - renderHeight = 0.0 + updateHeight(true) } is GuiEvent.Tick -> { - updateSettingsHeight() + if (renderHeight > 0.5) { + updateHeight() + } } is GuiEvent.Render -> { - scissor(settingsRect) { - settingsRenderer.render() - settingsLayer.onEvent(e) + var y = 0.0 + settingsLayer.children.filter(SettingButton<*, *>::visible).forEach { button -> + button.heightOffset = y + y += button.size.y + button.listStep + } + + if (renderHeight > 0.5) { + scissor(settingsRect) { + settingsLayer.onEvent(e) + settingsRenderer.render() + } } + return } } + + super.onEvent(e) + settingsLayer.onEvent(e) } - private fun updateSettingsHeight() { - /*val c = settingsLayer.children - settingsHeight = c.sumOf { it.size.y } + ((c.size - 1) * ClickGui.buttonStep).coerceAtLeast(0.0)*/ + private fun updateHeight(forceAnimation: Boolean = false) { + settingsHeight = if (isOpen) { + var lastStep = 0.0 + settingsLayer.children + .filter(SettingButton<*, *>::visible) + .sumOf { lastStep = it.listStep; it.size.y + it.listStep } - lastStep + } + else 0.0 - settingsHeight = 30.0 * isOpen.toInt() + if (forceAnimation) renderHeight = settingsHeight } override fun performClickAction(e: GuiEvent.MouseClick) { @@ -97,7 +139,8 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt if (abs(targetHeight - renderHeight) > 1) return isOpen = !isOpen - updateSettingsHeight() + if (isOpen) settingsLayer.onEvent(GuiEvent.Show()) + updateHeight() } } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index 9d0957fb7..1b638e293 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -2,27 +2,23 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.config.AbstractSetting import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.util.math.MathUtils.lerp -import com.lambda.util.math.MathUtils.toInt abstract class SettingButton > ( val setting: T, owner: ChildLayer.Drawable<*> ): ListButton(owner) { protected var value by setting - var visible = false - private var visibilityAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (visible) 0.2 else 0.8 }, ::visible) - override val showAnimation get() = lerp(0.0, super.showAnimation, visibilityAnimation) + val visible; get() = setting.visibility() - override var accessible: Boolean = false; get() = field && visible + private var visibilityAnimation by animation.exp(0.0, 1.0, 0.7, ::visible) + override val showAnimation get() = lerp(0.0, super.showAnimation, visibilityAnimation) + override var activeAnimation = 0.0 - override fun onEvent(e: GuiEvent) { - if (e is GuiEvent.Show || e is GuiEvent.Tick) visible = setting.visibility() - if (e is GuiEvent.Show) visibilityAnimation = visible.toInt().toDouble() - super.onEvent(e) - } + override var renderHeightOffset + get() = heightOffset + lerp(-size.y, 0.0, visibilityAnimation) + set(value) { heightOffset = value } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index f9761e63f..f73cd0afd 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -5,14 +5,44 @@ import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.Rect +import com.lambda.util.math.Rect.Companion.inv +import com.lambda.util.math.Vec2d class BooleanButton( setting: BooleanSetting, owner: ChildLayer.Drawable<*> ) : SettingButton(setting, owner) { override val text = setting.name - override var activeAnimation by animation.exp(0.0, 1.0, 0.5, ::value) + private var active by animation.exp(0.0, 1.0, 0.5, ::value) + + private val checkboxRect get() = Rect(rect.rightTop - Vec2d(rect.size.y * 1.75, 0.0), rect.rightBottom) + .shrink(2.0 - showAnimation) + + private val knobStart get() = Rect.basedOn(checkboxRect.leftTop, Vec2d.ONE * checkboxRect.size.y) + private val knobEnd get() = Rect.basedOn(checkboxRect.rightBottom, Vec2d.ONE * checkboxRect.size.y * -1.0).inv() + private val checkboxKnob get() = lerp(knobStart, knobEnd, active) + .shrink(2.0 - showAnimation + interactAnimation) + + init { + // Checkbox Background + renderer.filled { + position = checkboxRect + roundRadius = checkboxRect.size.y + color(GuiSettings.mainColor.setAlpha(showAnimation)) + } + + // Checkbox Knob + renderer.filled { + position = checkboxKnob + roundRadius = checkboxKnob.size.y + color(GuiSettings.backgroundColor.setAlpha(showAnimation)) + } + } override fun performClickAction(e: GuiEvent.MouseClick) { if (e.button == Mouse.Button.Left && hovered) value = !value diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt index 8fe7e6222..4524f810f 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt @@ -25,9 +25,8 @@ object RenderTest : Module( private val test21 by setting("Hallo 1", true, visibility = ::test1) private val test22 by setting("Hallo 2", true, visibility = ::test1) private val test23 by setting("Hallo 3", true, visibility = ::test1) - private val test31 by setting("Holla 1", true, visibility = { !test1 }) - private val test32 by setting("Holla 2", true, visibility = { !test1 }) - private val test33 by setting("Holla 3", true, visibility = { !test1 }) + private val test31 by setting("Holla huh 1", true, visibility = { !test1 }) + private val test32 by setting("Holla buh 2", true, visibility = { !test1 }) private val filled = DynamicFilledRenderer() private val outline = DynamicOutlineRenderer() diff --git a/common/src/main/kotlin/com/lambda/util/math/Rect.kt b/common/src/main/kotlin/com/lambda/util/math/Rect.kt index 5b58cf6f4..7c222d5b7 100644 --- a/common/src/main/kotlin/com/lambda/util/math/Rect.kt +++ b/common/src/main/kotlin/com/lambda/util/math/Rect.kt @@ -51,5 +51,7 @@ data class Rect(private val pos1: Vec2d, private val pos2: Vec2d) { fun basedOn(base: Vec2d, size: Vec2d) = Rect(base, base + size) + + fun Rect.inv() = Rect(rightBottom, leftTop) } } From 83ce0a62930f7e73b8581b72601726340a6beba6 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 9 May 2024 20:06:49 +0300 Subject: [PATCH 48/63] Sexy animations & many fixes --- .../lambda/config/settings/NumericSetting.kt | 2 +- .../graphics/renderer/gui/font/FontEntry.kt | 12 +++---- .../renderer/gui/rect/AbstractRectRenderer.kt | 6 +++- .../gui/api/component/InteractiveComponent.kt | 2 ++ .../gui/api/component/WindowComponent.kt | 2 +- .../api/component/button/ButtonComponent.kt | 2 +- .../gui/api/component/button/ListButton.kt | 6 ++-- .../api/component/core/list/ChildComponent.kt | 2 +- .../gui/impl/clickgui/buttons/ModuleButton.kt | 22 ++++++------ .../impl/clickgui/buttons/SettingButton.kt | 19 ++++++++--- .../clickgui/buttons/setting/BooleanButton.kt | 15 ++++---- .../clickgui/buttons/setting/NumberSlider.kt | 34 +++++++++++++++++++ .../clickgui/buttons/setting/SliderSetting.kt | 22 ++++++++++++ .../fragment/renderer/rect_filled.frag | 2 +- .../fragment/renderer/rect_outline.frag | 2 +- .../shaders/vertex/renderer/rect_filled.vert | 2 +- .../shaders/vertex/renderer/rect_outline.vert | 2 +- 17 files changed, 115 insertions(+), 39 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt diff --git a/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt b/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt index 50553e401..c4719ad0f 100644 --- a/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt +++ b/common/src/main/kotlin/com/lambda/config/settings/NumericSetting.kt @@ -31,6 +31,6 @@ abstract class NumericSetting( override fun toString() = "$value$unit" override operator fun setValue(thisRef: Any?, property: KProperty<*>, valueIn: T) { - value = valueIn.coerceIn(range).roundToStep(step) + value = valueIn.coerceIn(range) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt index c80647712..ea0da8fb7 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontEntry.kt @@ -37,7 +37,7 @@ class FontEntry( return width * actualScale } - override val height: Double + override val stringHeight: Double get() = font.glyphs.fontHeight * actualScale * 0.7 override fun build(ctx: IRenderContext) = ctx.use { @@ -46,7 +46,7 @@ class FontEntry( val shadowColor = getShadowColor(color) var posX = 0.0 - val posY = height * -0.5 + baselineOffset * actualScale + val posY = stringHeight * -0.5 + baselineOffset * actualScale text.toCharArray().forEach { char -> val charInfo = font[char] ?: return@forEach @@ -109,9 +109,9 @@ interface IFontEntry : IRenderEntry { fun getWidth(text: String): Double - val width get() = getWidth(text) - val height: Double + val stringWidth get() = getWidth(text) + val stringHeight: Double - val widthVec get() = Vec2d(width, 0.0) - val heightVec get() = Vec2d(0.0, height) + val widthVec get() = Vec2d(stringWidth, 0.0) + val heightVec get() = Vec2d(0.0, stringHeight) } diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt index 8cbe85948..0a6541724 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/AbstractRectRenderer.kt @@ -1,5 +1,6 @@ package com.lambda.graphics.renderer.gui.rect +import com.lambda.Lambda.mc import com.lambda.graphics.buffer.vao.vertex.VertexAttrib import com.lambda.graphics.renderer.IRenderEntry import com.lambda.graphics.renderer.gui.AbstractGuiRenderer @@ -16,6 +17,9 @@ abstract class AbstractRectRenderer > ( shader["u_Time"] = glfwGetTime() * GuiSettings.colorSpeed * 5.0 shader["u_Color1"] = GuiSettings.shadeColor1 shader["u_Color2"] = GuiSettings.shadeColor2 - shader["u_Size"] = Vec2d.ONE / Vec2d(GuiSettings.colorWidth, GuiSettings.colorHeight) + + val screen = Vec2d(mc.window.framebufferWidth, mc.window.framebufferHeight) + val size = Vec2d(GuiSettings.colorWidth, GuiSettings.colorHeight) + shader["u_Size"] = screen / size } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt index 0548c1875..6242cb125 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt @@ -24,6 +24,8 @@ abstract class InteractiveComponent : IComponent { } is GuiEvent.MouseClick -> { + hovered = rect.contains(e.mouse) + val prevPressed = pressed pressed = hovered && e.button.isMainButton && e.action == Mouse.Action.Click diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index c4efff751..9a9a1a184 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -40,7 +40,7 @@ abstract class WindowComponent ( private val contentRect get() = rect.shrink(padding).moveFirst(Vec2d(0.0, titleBarHeight - padding)) private val titleBar get() = Rect.basedOn(rect.leftTop, rect.size.x, titleBarHeight) - private val titleBarHeight get() = ClickGui.buttonHeight + padding * 2 + private val titleBarHeight get() = ClickGui.buttonHeight * 1.25 private val titleFont: IFontEntry private val layer = RenderLayer() diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 9a69a68c4..9cb2eadc0 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -67,7 +67,7 @@ abstract class ButtonComponent( } } - abstract fun performClickAction(e: GuiEvent.MouseClick) + open fun performClickAction(e: GuiEvent.MouseClick) {} override fun onEvent(e: GuiEvent) { super.onEvent(e) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index da9a75b4a..2dd49353f 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -14,12 +14,14 @@ abstract class ListButton(owner: ChildLayer.Drawable<*>) : ButtonComponent(owner open val listStep get() = ClickGui.buttonStep var heightOffset = 0.0 - protected open var renderHeightOffset by animation.exp(::heightOffset, 0.9) + + protected var renderHeightAnimation by animation.exp(::heightOffset, 0.8) + protected open val renderHeightOffset get() = renderHeightAnimation override fun onEvent(e: GuiEvent) { if (e is GuiEvent.Show) { heightOffset = 0.0 - renderHeightOffset = 0.0 + renderHeightAnimation = 0.0 } super.onEvent(e) } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index 50d8b87fa..20b304783 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -9,7 +9,7 @@ abstract class ChildComponent(open val owner: IComponent) : InteractiveComponent override fun onEvent(e: GuiEvent) { super.onEvent(e) - if (e is GuiEvent.MouseMove) hovered = hovered && accessible + if (e is GuiEvent.MouseMove || e is GuiEvent.MouseClick) hovered = hovered && accessible } open fun onAdd() {} diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 2a32ccb47..3fc356bf2 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,5 +1,6 @@ package com.lambda.gui.impl.clickgui.buttons +import com.lambda.config.settings.NumericSetting import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor @@ -8,6 +9,7 @@ import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton +import com.lambda.gui.impl.clickgui.buttons.setting.NumberSlider import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse @@ -78,6 +80,7 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt module.settings.mapNotNull { when (it) { is BooleanSetting -> BooleanButton(it, settingsLayer) + is NumericSetting<*> -> NumberSlider(it, settingsLayer) else -> null } }.forEach(settingsLayer::addChild) @@ -87,22 +90,22 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt when (e) { is GuiEvent.Show -> { isOpen = false - updateHeight(true) + updateHeight() + renderHeight = settingsHeight } is GuiEvent.Tick -> { - if (renderHeight > 0.5) { - updateHeight() - } - } + if (renderHeight < 0.5) return + updateHeight() - is GuiEvent.Render -> { var y = 0.0 settingsLayer.children.filter(SettingButton<*, *>::visible).forEach { button -> button.heightOffset = y y += button.size.y + button.listStep } + } + is GuiEvent.Render -> { if (renderHeight > 0.5) { scissor(settingsRect) { settingsLayer.onEvent(e) @@ -118,16 +121,13 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt settingsLayer.onEvent(e) } - private fun updateHeight(forceAnimation: Boolean = false) { + private fun updateHeight() { settingsHeight = if (isOpen) { var lastStep = 0.0 settingsLayer.children .filter(SettingButton<*, *>::visible) .sumOf { lastStep = it.listStep; it.size.y + it.listStep } - lastStep - } - else 0.0 - - if (forceAnimation) renderHeight = settingsHeight + } else 0.0 } override fun performClickAction(e: GuiEvent.MouseClick) { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index 1b638e293..335ca9879 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -2,6 +2,7 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.config.AbstractSetting import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.util.math.MathUtils.lerp @@ -10,15 +11,25 @@ abstract class SettingButton > ( val setting: T, owner: ChildLayer.Drawable<*> ): ListButton(owner) { + override val text = setting.name protected var value by setting val visible; get() = setting.visibility() + private var prevTickVisible = false - private var visibilityAnimation by animation.exp(0.0, 1.0, 0.7, ::visible) + private var visibilityAnimation by animation.exp(0.0, 1.0, 0.6, ::visible) override val showAnimation get() = lerp(0.0, super.showAnimation, visibilityAnimation) override var activeAnimation = 0.0 + override val renderHeightOffset get() = renderHeightAnimation + lerp(-size.y, 0.0, visibilityAnimation) - override var renderHeightOffset - get() = heightOffset + lerp(-size.y, 0.0, visibilityAnimation) - set(value) { heightOffset = value } + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + + when (e) { + is GuiEvent.Tick -> { + if (!prevTickVisible && visible) renderHeightAnimation = heightOffset + prevTickVisible = visible + } + } + } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index f73cd0afd..717c35b82 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -17,34 +17,35 @@ class BooleanButton( setting: BooleanSetting, owner: ChildLayer.Drawable<*> ) : SettingButton(setting, owner) { - override val text = setting.name - private var active by animation.exp(0.0, 1.0, 0.5, ::value) + private var active by animation.exp(0.0, 1.0, 0.6, ::value) + private val zoomAnimation get() = lerp(2.0, 0.0, showAnimation) private val checkboxRect get() = Rect(rect.rightTop - Vec2d(rect.size.y * 1.75, 0.0), rect.rightBottom) - .shrink(2.0 - showAnimation) + .shrink(1.0 + zoomAnimation) private val knobStart get() = Rect.basedOn(checkboxRect.leftTop, Vec2d.ONE * checkboxRect.size.y) private val knobEnd get() = Rect.basedOn(checkboxRect.rightBottom, Vec2d.ONE * checkboxRect.size.y * -1.0).inv() - private val checkboxKnob get() = lerp(knobStart, knobEnd, active) - .shrink(2.0 - showAnimation + interactAnimation) + private val checkboxKnob get() = lerp(knobStart, knobEnd, active).shrink(1.0 + zoomAnimation + interactAnimation) init { // Checkbox Background renderer.filled { position = checkboxRect roundRadius = checkboxRect.size.y - color(GuiSettings.mainColor.setAlpha(showAnimation)) + shade = GuiSettings.shade + color(GuiSettings.mainColor.setAlpha(showAnimation * (0.3 + active * 0.15))) } // Checkbox Knob renderer.filled { position = checkboxKnob roundRadius = checkboxKnob.size.y + shade = GuiSettings.shadeBackground color(GuiSettings.backgroundColor.setAlpha(showAnimation)) } } override fun performClickAction(e: GuiEvent.MouseClick) { - if (e.button == Mouse.Button.Left && hovered) value = !value + if (e.button == Mouse.Button.Left) value = !value } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt new file mode 100644 index 000000000..b5ba95887 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt @@ -0,0 +1,34 @@ +package com.lambda.gui.impl.clickgui.buttons.setting + +import com.lambda.config.settings.NumericSetting +import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.MathUtils.roundToStep +import com.lambda.util.math.MathUtils.typeConvert +import com.lambda.util.math.Vec2d +import java.awt.Color + +class NumberSlider ( + setting: NumericSetting, + owner: ChildLayer.Drawable<*> +) : SliderSetting>( + setting, owner +) where N : Number, N : Comparable { + init { + renderer.font { + text = value.let(Number::toString) + position = Vec2d(rect.right, rect.center.y) - Vec2d(ClickGui.windowPadding + stringWidth, 0.0) + color = Color.WHITE.setAlpha(showAnimation) + } + } + + override fun setValueByProgress(progress: Double) { + value = value.typeConvert(lerp( + setting.range.start.toDouble(), + setting.range.endInclusive.toDouble(), + progress + ).roundToStep(setting.step.toDouble())) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt new file mode 100644 index 000000000..13dfbb7dc --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt @@ -0,0 +1,22 @@ +package com.lambda.gui.impl.clickgui.buttons.setting + +import com.lambda.config.AbstractSetting +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.util.math.transform + +abstract class SliderSetting >( + setting: T, owner: ChildLayer.Drawable<*> +) : SettingButton(setting, owner) { + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + + if (e is GuiEvent.MouseMove && pressed) { + val p = transform(e.mouse.x, rect.left, rect.right, 0.0, 1.0) + setValueByProgress(p.coerceIn(0.0, 1.0)) + } + } + + protected abstract fun setValueByProgress(progress: Double) +} \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag index 3f3fdea26..d796497e5 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag @@ -20,7 +20,7 @@ vec4 shade() { if (v_Shade != 1.0) return v_Color; vec2 pos = v_Position * u_Size; - float p = sin(pos.x + pos.y - u_Time) * 0.5 + 0.5; + float p = sin(pos.x - pos.y - u_Time) * 0.5 + 0.5; return mix(u_Color1, u_Color2, p) * v_Color; } diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag index 19fb62887..b6647a229 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_outline.frag @@ -16,7 +16,7 @@ vec4 shade() { if (v_Shade != 1.0) return v_Color; vec2 pos = v_Position * u_Size; - float p = sin(pos.x + pos.y - u_Time) * 0.5 + 0.5; + float p = sin(pos.x - pos.y - u_Time) * 0.5 + 0.5; return mix(u_Color1, u_Color2, p) * v_Color; } diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert index accd43403..0e3891429 100644 --- a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_filled.vert @@ -20,7 +20,7 @@ out float v_Shade; void main() { gl_Position = u_Projection * u_ModelView * pos; - v_Position = pos.xy; + v_Position = gl_Position.xy * 0.5 + 0.5; v_TexCoord = uv; v_Color = color; diff --git a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert index 6beb3f5b8..192864a29 100644 --- a/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert +++ b/common/src/main/resources/assets/lambda/shaders/vertex/renderer/rect_outline.vert @@ -16,7 +16,7 @@ out float v_Shade; void main() { gl_Position = u_Projection * u_ModelView * pos; - v_Position = pos.xy; + v_Position = gl_Position.xy * 0.5 + 0.5; v_Alpha = alpha; v_Color = color; v_Shade = shade; From 6a8b2bca763a3793c06efe75bf2fc273f09fba6e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 9 May 2024 21:03:42 +0300 Subject: [PATCH 49/63] Slider progress rendering --- .../gui/impl/clickgui/buttons/ModuleButton.kt | 4 ++-- .../clickgui/buttons/setting/NumberSlider.kt | 8 ++++++++ .../clickgui/buttons/setting/SliderSetting.kt | 16 ++++++++++++++-- .../lambda/module/modules/client/GuiSettings.kt | 4 ++-- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 3fc356bf2..e6dfc4132 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -26,7 +26,7 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt override var activeAnimation by animation.exp(0.0, 1.0, 0.15, ::enabled) private val toggleFxDirection by animation.exp(0.0, 1.0, 0.7, ::enabled) - override val listStep: Double get() = super.listStep * 2.0 + renderHeight + override val listStep: Double get() = super.listStep + renderHeight private var isOpen = false override val isActive get() = isOpen @@ -126,7 +126,7 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt var lastStep = 0.0 settingsLayer.children .filter(SettingButton<*, *>::visible) - .sumOf { lastStep = it.listStep; it.size.y + it.listStep } - lastStep + .sumOf { lastStep = it.listStep; it.size.y + it.listStep } - lastStep + super.listStep } else 0.0 } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt index b5ba95887..a4eb45558 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt @@ -1,6 +1,8 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.NumericSetting +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui import com.lambda.util.math.ColorUtils.setAlpha @@ -8,6 +10,7 @@ import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.roundToStep import com.lambda.util.math.MathUtils.typeConvert import com.lambda.util.math.Vec2d +import com.lambda.util.math.normalize import java.awt.Color class NumberSlider ( @@ -16,6 +19,11 @@ class NumberSlider ( ) : SliderSetting>( setting, owner ) where N : Number, N : Comparable { + private val doubleRange get() = setting.range.let { it.start.toDouble()..it.endInclusive.toDouble() } + private val targetProgress get() = doubleRange.normalize(value.toDouble()) + private val renderProgress0 by animation.exp(::targetProgress, 0.6) + override val renderProgress get() = lerp(0.0, renderProgress0, showAnimation) + init { renderer.font { text = value.let(Number::toString) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt index 13dfbb7dc..57e15510a 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt @@ -4,11 +4,25 @@ import com.lambda.config.AbstractSetting import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.Vec2d import com.lambda.util.math.transform abstract class SliderSetting >( setting: T, owner: ChildLayer.Drawable<*> ) : SettingButton(setting, owner) { + protected abstract val renderProgress: Double + protected abstract fun setValueByProgress(progress: Double) + + init { + renderer.filled { + position = rect.moveSecond(Vec2d(-rect.size.x * (1.0 - renderProgress), 0.0)).shrink(interactAnimation) + shade = GuiSettings.shade + color(GuiSettings.mainColor.multAlpha(showAnimation * 0.3)) + } + } + override fun onEvent(e: GuiEvent) { super.onEvent(e) @@ -17,6 +31,4 @@ abstract class SliderSetting >( setValueByProgress(p.coerceIn(0.0, 1.0)) } } - - protected abstract fun setValueByProgress(progress: Double) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt index facca8785..c10de4a3e 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt @@ -20,8 +20,8 @@ object GuiSettings : Module( val backgroundColor by setting("Background Color", Color(50, 50, 50), visibility = { page == Page.Colors }) val shade by setting("Shade", true, visibility = { page == Page.Colors }) val shadeBackground by setting("Shade Background", true, visibility = { page == Page.Colors }) - val colorWidth by setting("Color Width", 100.0, 1.0..100.0, 1.0, visibility = { page == Page.Colors && shade }) - val colorHeight by setting("Color Height", 100.0, 1.0..100.0, 1.0, visibility = { page == Page.Colors && shade }) + val colorWidth by setting("Color Width", 400.0, 10.0..1000.0, 10.0, visibility = { page == Page.Colors && shade }) + val colorHeight by setting("Color Height", 400.0, 10.0..1000.0, 10.0, visibility = { page == Page.Colors && shade }) val colorSpeed by setting("Color Speed", 1.0, 0.1..10.0, 0.1, visibility = { page == Page.Colors && shade }) val mainColor: Color get() = if (shade) Color.WHITE else primaryColor From 991d9a14209c8c776eef4eb4dc712e88e120d790 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Thu, 9 May 2024 22:18:12 +0300 Subject: [PATCH 50/63] Rect sharpness & misc --- .../kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt | 3 ++- .../lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt | 2 +- .../lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt | 1 - .../assets/lambda/shaders/fragment/renderer/rect_filled.frag | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 06c766d0a..810f09dc6 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -7,6 +7,7 @@ import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui +import com.lambda.util.Mouse import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, ClickGui) { @@ -39,7 +40,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli } is GuiEvent.MouseClick -> { - activeWindow?.focus() + if (e.action == Mouse.Action.Click) activeWindow?.focus() } is GuiEvent.MouseMove -> { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 717c35b82..7c9b50ee5 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -33,7 +33,7 @@ class BooleanButton( position = checkboxRect roundRadius = checkboxRect.size.y shade = GuiSettings.shade - color(GuiSettings.mainColor.setAlpha(showAnimation * (0.3 + active * 0.15))) + color(GuiSettings.mainColor.setAlpha(showAnimation * (0.2 + active * 0.2))) } // Checkbox Knob diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt index a4eb45558..4bf7824fd 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt @@ -2,7 +2,6 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.NumericSetting import com.lambda.graphics.animation.Animation.Companion.exp -import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui import com.lambda.util.math.ColorUtils.setAlpha diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag index d796497e5..286fecc98 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag @@ -14,7 +14,7 @@ in float v_Shade; out vec4 color; -#define SMOOTHING 0.5 +#define SMOOTHING 0.25 vec4 shade() { if (v_Shade != 1.0) return v_Color; From bd3587557e288220bf4b3df22e39864bd6b11de1 Mon Sep 17 00:00:00 2001 From: Constructor Date: Thu, 9 May 2024 22:42:08 +0200 Subject: [PATCH 51/63] Added SoundManager --- .../src/main/kotlin/com/lambda/core/Loader.kt | 1 + .../kotlin/com/lambda/core/SoundManager.kt | 34 ++++++++++++++++++ .../clickgui/buttons/setting/BooleanButton.kt | 6 ++++ .../lambda/module/modules/player/Replay.kt | 3 +- .../main/kotlin/com/lambda/util/SoundUtils.kt | 13 ------- .../resources/assets/lambda/sound/test.ogg | Bin 0 -> 8833 bytes 6 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/core/SoundManager.kt delete mode 100644 common/src/main/kotlin/com/lambda/util/SoundUtils.kt create mode 100644 common/src/main/resources/assets/lambda/sound/test.ogg diff --git a/common/src/main/kotlin/com/lambda/core/Loader.kt b/common/src/main/kotlin/com/lambda/core/Loader.kt index 60ed586d2..33bb10418 100644 --- a/common/src/main/kotlin/com/lambda/core/Loader.kt +++ b/common/src/main/kotlin/com/lambda/core/Loader.kt @@ -22,6 +22,7 @@ object Loader { LambdaFont.Loader, GuiConfigurable, FriendManager, + SoundManager, ) fun initialize() { diff --git a/common/src/main/kotlin/com/lambda/core/SoundManager.kt b/common/src/main/kotlin/com/lambda/core/SoundManager.kt new file mode 100644 index 000000000..82a0f6723 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/core/SoundManager.kt @@ -0,0 +1,34 @@ +package com.lambda.core + +import com.lambda.Lambda +import com.lambda.context.SafeContext +import net.minecraft.client.sound.PositionedSoundInstance +import net.minecraft.registry.Registries +import net.minecraft.registry.Registry +import net.minecraft.sound.SoundEvent +import net.minecraft.util.Identifier + +object SoundManager : Loadable { + + override fun load(): String { + LambdaSound.entries.forEach { + Registry.register(Registries.SOUND_EVENT, it.id, it.event) + } + + return "Loaded ${LambdaSound.entries.size} sounds" + } + + enum class LambdaSound(val id: Identifier) { + MODULE_TOGGLE("module_toggle".toIdentifier()); + + val event: SoundEvent = SoundEvent.of(id) + } + + fun SafeContext.playSound(event: SoundEvent, pitch: Float = 1.0f) { + mc.soundManager.play( + PositionedSoundInstance.master(event, pitch) + ) + } + + private fun String.toIdentifier() = Identifier("${Lambda.MOD_ID}:${this}") +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 7c9b50ee5..827e4726a 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -1,11 +1,14 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.comparable.BooleanSetting +import com.lambda.core.SoundManager +import com.lambda.core.SoundManager.playSound import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.GuiSettings +import com.lambda.threading.runSafe import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.setAlpha import com.lambda.util.math.MathUtils.lerp @@ -47,5 +50,8 @@ class BooleanButton( override fun performClickAction(e: GuiEvent.MouseClick) { if (e.button == Mouse.Button.Left) value = !value + runSafe { + playSound(SoundManager.LambdaSound.MODULE_TOGGLE.event) + } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/Replay.kt b/common/src/main/kotlin/com/lambda/module/modules/player/Replay.kt index 8af3303ec..5b13ab4c0 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/Replay.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/Replay.kt @@ -4,6 +4,7 @@ import com.google.gson.* import com.lambda.brigadier.CommandResult import com.lambda.config.RotationSettings import com.lambda.context.SafeContext +import com.lambda.core.SoundManager.playSound import com.lambda.core.TimerManager import com.lambda.event.EventFlow.lambdaScope import com.lambda.event.events.KeyPressEvent @@ -25,9 +26,7 @@ import com.lambda.util.FolderRegister.locationBoundDirectory import com.lambda.util.Formatting.asString import com.lambda.util.Formatting.getTime import com.lambda.util.KeyCode -import com.lambda.util.SoundUtils.playSound import com.lambda.util.StringUtils.sanitizeForFilename -import com.lambda.util.math.MathUtils.roundToStep import com.lambda.util.primitives.extension.rotation import com.lambda.util.text.* import kotlinx.coroutines.Dispatchers diff --git a/common/src/main/kotlin/com/lambda/util/SoundUtils.kt b/common/src/main/kotlin/com/lambda/util/SoundUtils.kt deleted file mode 100644 index ff9ed8e64..000000000 --- a/common/src/main/kotlin/com/lambda/util/SoundUtils.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.lambda.util - -import com.lambda.context.SafeContext -import net.minecraft.client.sound.PositionedSoundInstance -import net.minecraft.sound.SoundEvent - -object SoundUtils { - fun SafeContext.playSound(event: SoundEvent, pitch: Float = 1.0f) { - mc.soundManager.play( - PositionedSoundInstance.master(event, pitch) - ) - } -} \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/sound/test.ogg b/common/src/main/resources/assets/lambda/sound/test.ogg new file mode 100644 index 0000000000000000000000000000000000000000..36e467eee89cd9871b4f57c7149b7d1d2789a5ac GIT binary patch literal 8833 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 qr@47 Date: Thu, 9 May 2024 23:56:34 +0200 Subject: [PATCH 52/63] Fixed sound manager --- .../src/main/kotlin/com/lambda/core/LambdaSound.kt | 11 +++++++++++ .../src/main/kotlin/com/lambda/core/SoundManager.kt | 12 +++--------- .../impl/clickgui/buttons/setting/BooleanButton.kt | 6 ++---- common/src/main/resources/assets/lambda/sounds.json | 7 +++++++ .../{sound/test.ogg => sounds/ui/module_toggle.ogg} | Bin 5 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/core/LambdaSound.kt create mode 100644 common/src/main/resources/assets/lambda/sounds.json rename common/src/main/resources/assets/lambda/{sound/test.ogg => sounds/ui/module_toggle.ogg} (100%) diff --git a/common/src/main/kotlin/com/lambda/core/LambdaSound.kt b/common/src/main/kotlin/com/lambda/core/LambdaSound.kt new file mode 100644 index 000000000..4354ce365 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/core/LambdaSound.kt @@ -0,0 +1,11 @@ +package com.lambda.core + +import com.lambda.core.SoundManager.toIdentifier +import net.minecraft.sound.SoundEvent +import net.minecraft.util.Identifier + +enum class LambdaSound(val id: Identifier) { + MODULE_TOGGLE("module_toggle".toIdentifier()); + + val event: SoundEvent = SoundEvent.of(id) +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/core/SoundManager.kt b/common/src/main/kotlin/com/lambda/core/SoundManager.kt index 82a0f6723..fa9959ce2 100644 --- a/common/src/main/kotlin/com/lambda/core/SoundManager.kt +++ b/common/src/main/kotlin/com/lambda/core/SoundManager.kt @@ -1,7 +1,7 @@ package com.lambda.core import com.lambda.Lambda -import com.lambda.context.SafeContext +import com.lambda.Lambda.mc import net.minecraft.client.sound.PositionedSoundInstance import net.minecraft.registry.Registries import net.minecraft.registry.Registry @@ -18,17 +18,11 @@ object SoundManager : Loadable { return "Loaded ${LambdaSound.entries.size} sounds" } - enum class LambdaSound(val id: Identifier) { - MODULE_TOGGLE("module_toggle".toIdentifier()); - - val event: SoundEvent = SoundEvent.of(id) - } - - fun SafeContext.playSound(event: SoundEvent, pitch: Float = 1.0f) { + fun playSound(event: SoundEvent, pitch: Float = 1.0f) { mc.soundManager.play( PositionedSoundInstance.master(event, pitch) ) } - private fun String.toIdentifier() = Identifier("${Lambda.MOD_ID}:${this}") + fun String.toIdentifier() = Identifier(Lambda.MOD_ID, this) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 827e4726a..6498c83a6 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -1,6 +1,7 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.comparable.BooleanSetting +import com.lambda.core.LambdaSound import com.lambda.core.SoundManager import com.lambda.core.SoundManager.playSound import com.lambda.graphics.animation.Animation.Companion.exp @@ -8,7 +9,6 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.GuiSettings -import com.lambda.threading.runSafe import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.setAlpha import com.lambda.util.math.MathUtils.lerp @@ -50,8 +50,6 @@ class BooleanButton( override fun performClickAction(e: GuiEvent.MouseClick) { if (e.button == Mouse.Button.Left) value = !value - runSafe { - playSound(SoundManager.LambdaSound.MODULE_TOGGLE.event) - } + playSound(LambdaSound.MODULE_TOGGLE.event) } } \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/sounds.json b/common/src/main/resources/assets/lambda/sounds.json new file mode 100644 index 000000000..360823f2a --- /dev/null +++ b/common/src/main/resources/assets/lambda/sounds.json @@ -0,0 +1,7 @@ +{ + "module_toggle": { + "sounds": [ + "lambda:ui/module_toggle" + ] + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/sound/test.ogg b/common/src/main/resources/assets/lambda/sounds/ui/module_toggle.ogg similarity index 100% rename from common/src/main/resources/assets/lambda/sound/test.ogg rename to common/src/main/resources/assets/lambda/sounds/ui/module_toggle.ogg From b3829c2f8fb17648c582876a09bb92d15c32b480 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 10 May 2024 02:00:24 +0300 Subject: [PATCH 53/63] Font artifacts fix --- .../renderer/gui/font/glyph/FontGlyphs.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt index 0e4a98466..b6abde4ec 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/glyph/FontGlyphs.kt @@ -30,13 +30,12 @@ class FontGlyphs(font: Font) { var y = 0 var rowHeight = 0 - // Because UTF16 takes 2 bytes per character, we can't use the full range of characters - (Char.MIN_VALUE.. + (Char.MIN_VALUE.. val charImage = getCharImage(font, char) ?: return@forEach - rowHeight = max(rowHeight, charImage.height) + rowHeight = max(rowHeight, charImage.height + STEP) - if (x + charImage.width >= TEXTURE_SIZE) { + if (x + charImage.width + STEP >= TEXTURE_SIZE) { y += rowHeight x = 0 rowHeight = 0 @@ -53,7 +52,7 @@ class FontGlyphs(font: Font) { charMap[char.code] = CharInfo(size, uv1, uv2) fontHeight = max(fontHeight, size.y) - x += charImage.width + x += charImage.width + STEP } fontTexture = MipmapTexture(image) @@ -73,13 +72,12 @@ class FontGlyphs(font: Font) { charMap[char.code] companion object { - // The size cannot be bigger than 2^15 because the rasterizer needs to be fed with dimensions that when multiplied together are less than 2^31 - // This can be bypassed by using a custom rasterizer, but it's not worth the effort - // The size is also limited by the java heap size, as the image is stored in memory - // and then uploaded to the GPU // Since most Lambda users probably have bad pc, the default size is 2048, which includes latin, cyrillic, greek and arabic // and in the future we could grow the textures when needed - private val TEXTURE_SIZE = FontSettings.amountOfGlyphs * 2 - private val ONE_TEXEL_SIZE = 1.0 / TEXTURE_SIZE + private const val CHAR_AMOUNT = 2048 + private const val TEXTURE_SIZE = 4096 + private const val ONE_TEXEL_SIZE = 1.0 / TEXTURE_SIZE + // The space between glyphs is necessary to prevent artifacts from appearing when the font texture is blurred + private const val STEP = 2 } } From 168e705cea604161b4f27914a14448ff4aae08e9 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 10 May 2024 02:00:53 +0300 Subject: [PATCH 54/63] Added alpha check --- .../graphics/renderer/gui/rect/filled/FilledRectEntry.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt index 76e86fe80..431c089a1 100644 --- a/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt +++ b/common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/filled/FilledRectEntry.kt @@ -31,6 +31,7 @@ class FilledRectEntry( val pos2 = position.rightBottom val size = pos2 - pos1 + if (leftTop.alpha < MIN_ALPHA && rightTop.alpha < MIN_ALPHA && rightBottom.alpha < MIN_ALPHA && leftBottom.alpha < MIN_ALPHA) return@use if (size.x < MIN_SIZE || size.y < MIN_SIZE) return@use val halfSize = size * 0.5 @@ -38,8 +39,8 @@ class FilledRectEntry( val round = min(roundRadius, maxRadius) - val p1 = pos1 - 0.75 - val p2 = pos2 + 0.75 + val p1 = pos1 - 0.25 + val p2 = pos2 + 0.25 val s = shade.toInt().toDouble() grow(4) @@ -54,5 +55,6 @@ class FilledRectEntry( companion object { private const val MIN_SIZE = 0.5 + private const val MIN_ALPHA = 3 } } \ No newline at end of file From d249ba33f047e9d80d27d1125222d0680ba46fde Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 10 May 2024 02:02:54 +0300 Subject: [PATCH 55/63] Removed useless setting --- .../main/kotlin/com/lambda/module/modules/client/FontSettings.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt b/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt index ed0c42c82..e552225b5 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/FontSettings.kt @@ -13,7 +13,6 @@ object FontSettings : Module( val shadowShift by setting("Shadow Shift", 1.0, 0.0..2.0, 0.05, visibility = { shadow }) val gapSetting by setting("Gap", 1.5, -10.0..10.0, 0.5) val baselineOffset by setting("Vertical Offset", 0.0, -10.0..10.0, 0.5) - val amountOfGlyphs by setting("Glyph Count", 2048, 128..65536, 1, description = "Restart required") private val lodBiasSetting by setting("Smoothing", 0.0, -10.0..10.0, 0.5) val lodBias get() = lodBiasSetting * 0.25f - 0.75f From 3128295c42aefd5b576304197bc3e450bc132ff5 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 10 May 2024 02:03:26 +0300 Subject: [PATCH 56/63] Setting space shadow --- .../gui/impl/clickgui/buttons/ModuleButton.kt | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index e6dfc4132..7b5e390fb 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -10,13 +10,18 @@ import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton import com.lambda.gui.impl.clickgui.buttons.setting.NumberSlider +import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.ColorUtils.setAlpha import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.MathUtils.toInt import com.lambda.util.math.Rect import com.lambda.util.math.Vec2d +import com.lambda.util.math.transform +import java.awt.Color import kotlin.math.abs class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButton(owner) { @@ -37,16 +42,18 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt private var settingsHeight = 0.0 private var renderHeight by animation.exp(::settingsHeight, 0.6) private val settingsRect get() = rect - .moveFirst(Vec2d(childShowAnimation * 2.0, size.y + super.listStep)) - .moveSecond(Vec2d(0.0, listStep)) + .moveFirst(Vec2d(0.0, size.y + super.listStep)) + .moveSecond(Vec2d(0.0, renderHeight)) private val settingsRenderer = RenderLayer() - private val settingsLayer = ChildLayer.Drawable(owner.gui, this, settingsRenderer, ::settingsRect, SettingButton<*, *>::visible) + private val settingsLayer = ChildLayer.Drawable>(owner.gui, this, settingsRenderer, ::settingsRect) { + it.visible && abs(settingsHeight - renderHeight) <3 + } init { // Toggle fx renderer.filled { - val left = rect - Vec2d(rect.size.x, 0.0) + val left = rect - Vec2d(rect.size.x, 0.0) val right = rect + Vec2d(rect.size.x, 0.0) position = lerp(left, right, activeAnimation) @@ -58,23 +65,32 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt val color = GuiSettings.mainColor.multAlpha(alpha * 0.6 * showAnimation) // "Tail" effect - val leftColor = color.multAlpha(1.0 - toggleFxDirection) + val leftColor = color.multAlpha(1.0 - toggleFxDirection) val rightColor = color.multAlpha(toggleFxDirection) shade = GuiSettings.shade colorH(leftColor, rightColor) } - // Line + // Shadow renderer.filled { - val pos1 = Vec2d(rect.left, settingsRect.top) - val pos2 = Vec2d(rect.left + childShowAnimation * 1.0, settingsRect.bottom) - val color = GuiSettings.mainColor.multAlpha(childShowAnimation * 0.6) + position = Rect( + rect.leftTop + Vec2d(0.0, size.y), + rect.rightTop + Vec2d(0.0, size.y + 5.0) + ) + val progress = transform(renderHeight, 0.0, 10.0, 0.0, 1.0).coerceIn(0.0, 1.0) + colorV(Color.BLACK.setAlpha(0.2 * progress), Color.BLACK.setAlpha(0.0)) + } - position = Rect(pos1, pos2) + // Bottom shadow + renderer.filled { + val show = (owner.owner as? ModuleWindow)?.let { + this@ModuleButton != it.contentComponents.children.lastOrNull() + } ?: false - shade = GuiSettings.shade - color(color) + position = Rect(settingsRect.leftBottom - Vec2d(0.0, 5.0), settingsRect.rightBottom) + val progress = transform(renderHeight, 0.0, 10.0, 0.0, 1.0).coerceIn(0.0, 1.0) * show.toInt() + colorV(Color.BLACK.setAlpha(0.0), Color.BLACK.setAlpha(0.2 * progress)) } module.settings.mapNotNull { @@ -126,7 +142,7 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt var lastStep = 0.0 settingsLayer.children .filter(SettingButton<*, *>::visible) - .sumOf { lastStep = it.listStep; it.size.y + it.listStep } - lastStep + super.listStep + .sumOf { lastStep = it.listStep; it.size.y + it.listStep } - lastStep + super.listStep * 2.0 } else 0.0 } From 4b1e263c8eec778a3c967638ce3dc8d9636a530e Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Fri, 10 May 2024 23:29:05 +0300 Subject: [PATCH 57/63] Gui sounds --- .../kotlin/com/lambda/core/LambdaSound.kt | 11 +++++- .../kotlin/com/lambda/core/SoundManager.kt | 13 +++++-- .../api/component/button/ButtonComponent.kt | 8 +++++ .../gui/impl/clickgui/buttons/ModuleButton.kt | 14 ++++++-- .../clickgui/buttons/setting/BooleanButton.kt | 11 +++--- .../clickgui/buttons/setting/SliderSetting.kt | 24 +++++++++++-- .../main/resources/assets/lambda/sounds.json | 34 ++++++++++++++++-- .../assets/lambda/sounds/ui/bool_off.ogg | Bin 0 -> 7317 bytes .../assets/lambda/sounds/ui/bool_on.ogg | Bin 0 -> 8096 bytes .../assets/lambda/sounds/ui/button_click.ogg | Bin 0 -> 7047 bytes .../assets/lambda/sounds/ui/module_off.ogg | Bin 0 -> 14015 bytes .../assets/lambda/sounds/ui/module_on.ogg | Bin 0 -> 13897 bytes .../assets/lambda/sounds/ui/module_toggle.ogg | Bin 8833 -> 0 bytes .../lambda/sounds/ui/settings_close.ogg | Bin 0 -> 17991 bytes .../assets/lambda/sounds/ui/settings_open.ogg | Bin 0 -> 20270 bytes 15 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/bool_off.ogg create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/bool_on.ogg create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/button_click.ogg create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/module_off.ogg create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/module_on.ogg delete mode 100644 common/src/main/resources/assets/lambda/sounds/ui/module_toggle.ogg create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/settings_close.ogg create mode 100644 common/src/main/resources/assets/lambda/sounds/ui/settings_open.ogg diff --git a/common/src/main/kotlin/com/lambda/core/LambdaSound.kt b/common/src/main/kotlin/com/lambda/core/LambdaSound.kt index 4354ce365..edd499847 100644 --- a/common/src/main/kotlin/com/lambda/core/LambdaSound.kt +++ b/common/src/main/kotlin/com/lambda/core/LambdaSound.kt @@ -5,7 +5,16 @@ import net.minecraft.sound.SoundEvent import net.minecraft.util.Identifier enum class LambdaSound(val id: Identifier) { - MODULE_TOGGLE("module_toggle".toIdentifier()); + BUTTON_CLICK("button_click".toIdentifier()), + + BOOLEAN_SETTING_ON("bool_on".toIdentifier()), + BOOLEAN_SETTING_OFF("bool_off".toIdentifier()), + + MODULE_ON("module_on".toIdentifier()), + MODULE_OFF("module_off".toIdentifier()), + + SETTINGS_OPEN("settings_open".toIdentifier()), + SETTINGS_CLOSE("settings_close".toIdentifier()); val event: SoundEvent = SoundEvent.of(id) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/core/SoundManager.kt b/common/src/main/kotlin/com/lambda/core/SoundManager.kt index fa9959ce2..31a418abc 100644 --- a/common/src/main/kotlin/com/lambda/core/SoundManager.kt +++ b/common/src/main/kotlin/com/lambda/core/SoundManager.kt @@ -2,6 +2,7 @@ package com.lambda.core import com.lambda.Lambda import com.lambda.Lambda.mc +import com.lambda.util.math.random import net.minecraft.client.sound.PositionedSoundInstance import net.minecraft.registry.Registries import net.minecraft.registry.Registry @@ -18,9 +19,17 @@ object SoundManager : Loadable { return "Loaded ${LambdaSound.entries.size} sounds" } - fun playSound(event: SoundEvent, pitch: Float = 1.0f) { + fun playSound(event: SoundEvent, pitch: Double = 1.0) { mc.soundManager.play( - PositionedSoundInstance.master(event, pitch) + PositionedSoundInstance.master(event, pitch.toFloat()) + ) + } + + fun playSoundRandomly(event: SoundEvent, pitch: Double = 1.0, pitchRange: Double = 0.05) { + val actualPitch = (pitch - pitchRange..pitch + pitchRange).random() + + mc.soundManager.play( + PositionedSoundInstance.master(event, actualPitch.toFloat()) ) } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 9cb2eadc0..635b0f4d2 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -1,11 +1,14 @@ package com.lambda.gui.api.component.button +import com.lambda.core.LambdaSound +import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildComponent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.module.modules.client.ClickGui import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Rect @@ -82,6 +85,11 @@ abstract class ButtonComponent( } } + override fun onPress(e: GuiEvent.MouseClick) { + val pitch = if (e.button == Mouse.Button.Left) 1.0 else 0.9 + playSoundRandomly(LambdaSound.BUTTON_CLICK.event, pitch) + } + override fun onRelease(e: GuiEvent.MouseClick) { if (hovered) performClickAction(e) } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 7b5e390fb..74f6d5642 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -2,6 +2,8 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.config.settings.NumericSetting import com.lambda.config.settings.comparable.BooleanSetting +import com.lambda.core.LambdaSound +import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.gui.api.GuiEvent @@ -147,8 +149,11 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt } override fun performClickAction(e: GuiEvent.MouseClick) { - when (e.button) { - Mouse.Button.Left -> module.toggle() + val sound = when (e.button) { + Mouse.Button.Left -> { + module.toggle() + if (module.isEnabled) LambdaSound.MODULE_ON else LambdaSound.MODULE_OFF + } Mouse.Button.Right -> { // Don't let user spam val targetHeight = if (isOpen) settingsHeight else 0.0 @@ -157,8 +162,13 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt isOpen = !isOpen if (isOpen) settingsLayer.onEvent(GuiEvent.Show()) updateHeight() + + if (isOpen) LambdaSound.SETTINGS_OPEN else LambdaSound.SETTINGS_CLOSE } + else -> return } + + playSoundRandomly(sound.event) } override fun equals(other: Any?) = diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 6498c83a6..8d25a9065 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -2,8 +2,7 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.core.LambdaSound -import com.lambda.core.SoundManager -import com.lambda.core.SoundManager.playSound +import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer @@ -49,7 +48,11 @@ class BooleanButton( } override fun performClickAction(e: GuiEvent.MouseClick) { - if (e.button == Mouse.Button.Left) value = !value - playSound(LambdaSound.MODULE_TOGGLE.event) + if (e.button != Mouse.Button.Left) return + value = !value + + val sound = if (value) LambdaSound.BOOLEAN_SETTING_ON else LambdaSound.BOOLEAN_SETTING_OFF + val pitch = if (value) 1.0 else 0.9 + playSoundRandomly(sound.event, pitch) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt index 57e15510a..a0592a2f9 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt @@ -1,19 +1,26 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.AbstractSetting +import com.lambda.core.LambdaSound +import com.lambda.core.SoundManager.playSound +import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.GuiSettings import com.lambda.util.math.ColorUtils.multAlpha +import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Vec2d import com.lambda.util.math.transform +import kotlin.math.abs abstract class SliderSetting >( setting: T, owner: ChildLayer.Drawable<*> ) : SettingButton(setting, owner) { protected abstract val renderProgress: Double protected abstract fun setValueByProgress(progress: Double) + private var lastPlayedValue = value + private var lastPlayedTiming = 0L init { renderer.filled { @@ -26,9 +33,20 @@ abstract class SliderSetting >( override fun onEvent(e: GuiEvent) { super.onEvent(e) - if (e is GuiEvent.MouseMove && pressed) { - val p = transform(e.mouse.x, rect.left, rect.right, 0.0, 1.0) - setValueByProgress(p.coerceIn(0.0, 1.0)) + when (e) { + is GuiEvent.MouseMove -> { + if (!pressed) return + val p = transform(e.mouse.x, rect.left, rect.right, 0.0, 1.0).coerceIn(0.0, 1.0) + setValueByProgress(p) + + val time = System.currentTimeMillis() + if (lastPlayedValue == value || time - lastPlayedTiming < 50) return + + lastPlayedValue = value + lastPlayedTiming = time + + playSound(LambdaSound.BUTTON_CLICK.event, lerp(0.9, 1.2, p)) + } } } } \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/sounds.json b/common/src/main/resources/assets/lambda/sounds.json index 360823f2a..e85566499 100644 --- a/common/src/main/resources/assets/lambda/sounds.json +++ b/common/src/main/resources/assets/lambda/sounds.json @@ -1,7 +1,37 @@ { - "module_toggle": { + "button_click": { "sounds": [ - "lambda:ui/module_toggle" + "lambda:ui/button_click" + ] + }, + "bool_on": { + "sounds": [ + "lambda:ui/bool_on" + ] + }, + "bool_off": { + "sounds": [ + "lambda:ui/bool_off" + ] + }, + "module_on": { + "sounds": [ + "lambda:ui/module_on" + ] + }, + "module_off": { + "sounds": [ + "lambda:ui/module_off" + ] + }, + "settings_open": { + "sounds": [ + "lambda:ui/settings_open" + ] + }, + "settings_close": { + "sounds": [ + "lambda:ui/settings_close" ] } } \ No newline at end of file diff --git a/common/src/main/resources/assets/lambda/sounds/ui/bool_off.ogg b/common/src/main/resources/assets/lambda/sounds/ui/bool_off.ogg new file mode 100644 index 0000000000000000000000000000000000000000..6ec76aff2e62e520a596ad94acfde1b5de799a5f GIT binary patch literal 7317 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 z�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 MjNQvA`R-o-3%z$N=Kufz literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/lambda/sounds/ui/module_on.ogg b/common/src/main/resources/assets/lambda/sounds/ui/module_on.ogg new file mode 100644 index 0000000000000000000000000000000000000000..40d853b6f435aeb71e42d083d2f2b3f659efdc90 GIT binary patch literal 13897 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 KZ~Fl(_LtRthINn{QPVo7U*~Bm;2Re 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 qr@47ri*#5OIWu}Urz6HL=|+5rRu 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 Ac>n+a literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/lambda/sounds/ui/settings_open.ogg b/common/src/main/resources/assets/lambda/sounds/ui/settings_open.ogg new file mode 100644 index 0000000000000000000000000000000000000000..02ebe61c05724bdfbfe21dc1bc2994d72a4866c4 GIT binary patch literal 20270 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 Date: Fri, 10 May 2024 23:56:13 +0300 Subject: [PATCH 58/63] Color banding dithering --- .../lambda/shaders/fragment/renderer/rect_filled.frag | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag index 286fecc98..306a00247 100644 --- a/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag +++ b/common/src/main/resources/assets/lambda/shaders/fragment/renderer/rect_filled.frag @@ -15,6 +15,14 @@ in float v_Shade; out vec4 color; #define SMOOTHING 0.25 +#define NOISE_GRANULARITY 0.005 + +vec4 noise() { + // https://shader-tutorial.dev/advanced/color-banding-dithering/ + float random = fract(sin(dot(v_TexCoord, vec2(12.9898, 78.233))) * 43758.5453); + float ofs = mix(-NOISE_GRANULARITY, NOISE_GRANULARITY, random); + return vec4(ofs, ofs, ofs, 0.0); +} vec4 shade() { if (v_Shade != 1.0) return v_Color; @@ -41,5 +49,5 @@ vec4 round() { } void main() { - color = shade() * round(); + color = shade() * round() + noise(); } \ No newline at end of file From 3d0a54904f45496ff278d1a7bf7f075749ba5aee Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 11 May 2024 23:01:25 +0300 Subject: [PATCH 59/63] Crash fix --- common/src/main/kotlin/com/lambda/util/math/MathUtils.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt b/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt index 94abd79f5..5538ca020 100644 --- a/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt +++ b/common/src/main/kotlin/com/lambda/util/math/MathUtils.kt @@ -59,6 +59,7 @@ object MathUtils { private fun decimalPlaces(value: Double) = BigDecimal.valueOf(value).scale() fun random(v1: Double, v2: Double): Double { + if (v1 == v2) return v1 val min = min(v1, v2) val max = max(v1, v2) return nextDouble(min, max) From cc38ff98bddc37c4fc0cbddd078a596deabdd8ae Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sat, 11 May 2024 23:06:25 +0300 Subject: [PATCH 60/63] InputBar --- .../gui/api/component/InteractiveComponent.kt | 10 +- .../gui/api/component/WindowComponent.kt | 13 ++- .../api/component/button/ButtonComponent.kt | 20 ++-- .../api/component/button/InputBarOverlay.kt | 100 ++++++++++++++++++ .../gui/api/component/button/ListButton.kt | 3 +- .../api/component/core/list/ChildComponent.kt | 3 +- .../gui/api/component/core/list/ChildLayer.kt | 18 ++-- .../gui/impl/clickgui/AbstractClickGui.kt | 2 +- .../gui/impl/clickgui/buttons/ModuleButton.kt | 18 ++-- .../impl/clickgui/buttons/SettingButton.kt | 13 +-- .../clickgui/buttons/setting/BooleanButton.kt | 9 +- .../clickgui/buttons/setting/NumberSlider.kt | 62 ++++++++++- .../clickgui/buttons/setting/SliderSetting.kt | 37 ++++--- .../gui/impl/clickgui/windows/ModuleWindow.kt | 6 +- .../windows/tag/CustomModuleWindow.kt | 6 +- .../impl/clickgui/windows/tag/TagWindow.kt | 2 +- 16 files changed, 241 insertions(+), 81 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt index 6242cb125..d0c8bfe14 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt @@ -3,11 +3,10 @@ package com.lambda.gui.api.component import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.IComponent import com.lambda.util.Mouse -import com.lambda.util.math.Rect abstract class InteractiveComponent : IComponent { protected var hovered = false - protected var pressed = false + protected var activeButton: Mouse.Button? = null protected open fun onPress(e: GuiEvent.MouseClick) {} protected open fun onRelease(e: GuiEvent.MouseClick) {} @@ -16,7 +15,7 @@ abstract class InteractiveComponent : IComponent { when (e) { is GuiEvent.Show -> { hovered = false - pressed = false + activeButton = null } is GuiEvent.MouseMove -> { @@ -26,8 +25,9 @@ abstract class InteractiveComponent : IComponent { is GuiEvent.MouseClick -> { hovered = rect.contains(e.mouse) - val prevPressed = pressed - pressed = hovered && e.button.isMainButton && e.action == Mouse.Action.Click + val prevPressed = activeButton != null + activeButton = if (hovered && e.button.isMainButton && e.action == Mouse.Action.Click) e.button else null + val pressed = activeButton != null if (prevPressed == pressed) return if (pressed) onPress(e) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt index 9a9a1a184..1af9a2860 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/WindowComponent.kt @@ -21,8 +21,8 @@ import java.awt.Color import kotlin.math.abs abstract class WindowComponent ( - final override val owner: AbstractClickGui -) : ChildComponent(owner) { + val gui: AbstractClickGui +) : ChildComponent(gui.windows) { abstract val title: String abstract var width: Double @@ -47,8 +47,7 @@ abstract class WindowComponent ( private val renderer = layer.entry() private val contentLayer = RenderLayer() - private val animation = owner.animation - private val gui = owner + private val animation = gui.animation private val showAnimation by animation.exp(0.0, 1.0, 0.6, ::isOpen) override val childShowAnimation get() = lerp(0.0, showAnimation, gui.childShowAnimation) @@ -57,7 +56,7 @@ abstract class WindowComponent ( private var renderHeightAnimation by animation.exp({ 0.0 }, ::actualHeight, 0.6, ::isOpen) private val renderHeight get() = lerp(0.0, renderHeightAnimation, childShowAnimation) - val contentComponents = ChildLayer.Drawable(gui, this, contentLayer, ::contentRect) + open val contentComponents = ChildLayer.Drawable>(gui, this, contentLayer, ::contentRect) /*val titleBarComponents = ChildLayer { child -> child.rect in titleBar && accessible @@ -149,7 +148,7 @@ abstract class WindowComponent ( fun focus() { // move window into foreground - owner.apply { + gui.apply { scheduleAction { windows.children.apply { this@WindowComponent @@ -161,7 +160,7 @@ abstract class WindowComponent ( } fun destroy() { - owner.apply { + gui.apply { scheduleAction { windows.removeChild(this@WindowComponent) } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index 635b0f4d2..c8e56f414 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -16,23 +16,24 @@ import com.lambda.util.math.Vec2d import java.awt.Color abstract class ButtonComponent( - final override val owner: ChildLayer.Drawable<*> + owner: ChildLayer.Drawable<*, *> ) : ChildComponent(owner) { abstract val position: Vec2d abstract val size: Vec2d abstract val text: String + protected open val textColor get() = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation).multAlpha(showAnimation) protected abstract var activeAnimation: Double private val actualSize get() = Vec2d(if (size.x == FILL_PARENT) owner.rect.size.x else size.x, size.y) final override val rect get() = Rect.basedOn(position, actualSize) + owner.rect.leftTop - protected val renderer = owner.renderer.entry() + val renderer = owner.renderer.entry() protected val animation = owner.gui.animation private var hoverRectAnimation by animation.exp({ 0.0 }, { 1.0 }, { if (renderHovered) 0.6 else 0.07 }, ::renderHovered) - private var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) - private var pressAnimation by animation.exp(0.0, 1.0, 0.5, ::pressed) + protected var hoverFontAnimation by animation.exp(0.0, 1.0, 0.5, ::renderHovered) + protected var pressAnimation by animation.exp(0.0, 1.0, 0.5) { activeButton != null } protected val interactAnimation get() = lerp(hoverRectAnimation, 1.5, pressAnimation) * 0.4 override val childShowAnimation: Double get() = owner.childShowAnimation protected open val showAnimation get() = owner.childShowAnimation @@ -40,10 +41,13 @@ abstract class ButtonComponent( private var lastHoveredTime = 0L private val renderHovered get() = hovered || System.currentTimeMillis() - lastHoveredTime < 110 + // Removes button shrinking if there's no space between buttons + protected val shrink get() = lerp(0.0, interactAnimation, ClickGui.buttonStep) + init { // Active color renderer.filled { - position = rect.shrink(interactAnimation) + position = rect.shrink(shrink) shade = GuiSettings.shade color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.3 * showAnimation)) } @@ -51,7 +55,7 @@ abstract class ButtonComponent( // Hover glint renderer.filled { val hoverRect = Rect.basedOn(rect.leftTop, rect.size.x * hoverRectAnimation, rect.size.y) - position = hoverRect.shrink(interactAnimation) + position = hoverRect.shrink(shrink) shade = GuiSettings.shade val alpha = interactAnimation * 0.2 * showAnimation @@ -63,10 +67,10 @@ abstract class ButtonComponent( text = this@ButtonComponent.text scale = 1.0 - pressAnimation * 0.08 - color = lerp(Color.WHITE, GuiSettings.mainColor, activeAnimation).multAlpha(showAnimation) + color = textColor val x = ClickGui.windowPadding + interactAnimation + hoverFontAnimation - position = rect.leftTop + Vec2d(x, rect.size.y * 0.5) + position = Vec2d(rect.left + x, rect.center.y) } } diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt new file mode 100644 index 000000000..c98598a1e --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt @@ -0,0 +1,100 @@ +package com.lambda.gui.api.component.button + +import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.core.list.ChildComponent +import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.api.layer.LayerEntry +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.KeyCode +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.Rect +import com.lambda.util.math.Vec2d +import java.awt.Color +import kotlin.math.abs + +abstract class InputBarOverlay (renderer: LayerEntry, owner: ChildLayer.Drawable) : ChildComponent(owner) { + override val rect: Rect get() = owner.rect + override var isActive = false + + abstract val pressAnimation: Double + abstract val interactAnimation: Double + abstract val hoverFontAnimation: Double + abstract val showAnimation: Double + + val activeAnimation by owner.gui.animation.exp(0.0, 1.0, 0.7, ::isActive) + private var typeAnimation by owner.gui.animation.exp({ 0.0 }, 0.2) + + private var targetOffset = 0.0 + private var offset by owner.gui.animation.exp(::targetOffset, 0.4) + + abstract fun getInitText(): String + abstract fun setValue(string: String) + + open fun isCharAllowed(char: Char): Boolean = true + + private val field = renderer.font { + scale = lerp(0.5, 1.0, activeAnimation) - pressAnimation * 0.08 + color = Color.WHITE.setAlpha(lerp(0.0, activeAnimation, showAnimation)) + + val x = ClickGui.windowPadding + interactAnimation + hoverFontAnimation + position = Vec2d(rect.left + x, rect.center.y) + targetOffset = stringWidth + } + + init { + renderer.filled { + val shrink = lerp(rect.size.y * 0.5, 2 + abs(typeAnimation), activeAnimation) + val x = field.position.x + offset + 2 + + position = Rect( + Vec2d(0.0, rect.top + shrink), + Vec2d(1.0, rect.bottom - shrink) + ) + Vec2d(lerp(rect.right, x, activeAnimation), 0.0) + + color(field.color.setAlpha(0.8)) + } + } + + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + + when (e) { + is GuiEvent.Show -> { + isActive = false + } + + is GuiEvent.CharTyped -> { + if (!isActive || !isCharAllowed(e.char)) return + field.text += e.char + typeAnimation = 1.0 + } + + is GuiEvent.KeyPress -> { + if (!isActive) return + + when (e.key) { + KeyCode.Enter -> { + setValue(field.text) + toggle() + } + + KeyCode.Backspace -> { + field.text = field.text.dropLast(1) + typeAnimation = -1.0 + } + } + } + } + } + + fun toggle() { + isActive = !isActive + + if (isActive) { + field.text = getInitText() + targetOffset = field.stringWidth + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt index 2dd49353f..b66d8443d 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ListButton.kt @@ -7,14 +7,13 @@ import com.lambda.module.modules.client.ClickGui import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Vec2d -abstract class ListButton(owner: ChildLayer.Drawable<*>) : ButtonComponent(owner) { +abstract class ListButton(owner: ChildLayer.Drawable<*, *>) : ButtonComponent(owner) { override val position get() = Vec2d(0.0, lerp(0.0, renderHeightOffset, owner.childShowAnimation)) override val size get() = Vec2d(FILL_PARENT, ClickGui.buttonHeight) open val listStep get() = ClickGui.buttonStep var heightOffset = 0.0 - protected var renderHeightAnimation by animation.exp(::heightOffset, 0.8) protected open val renderHeightOffset get() = renderHeightAnimation diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index 20b304783..b1d2ec298 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -2,9 +2,8 @@ package com.lambda.gui.api.component.core.list import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.InteractiveComponent -import com.lambda.gui.api.component.core.IComponent -abstract class ChildComponent(open val owner: IComponent) : InteractiveComponent() { +abstract class ChildComponent(open val owner: ChildLayer<*, *>) : InteractiveComponent() { open var accessible = false override fun onEvent(e: GuiEvent) { diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt index f509c8ca5..ff493c911 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildLayer.kt @@ -7,14 +7,14 @@ import com.lambda.gui.api.layer.RenderLayer import com.lambda.util.Mouse import com.lambda.util.math.Rect -open class ChildLayer ( +open class ChildLayer ( val gui: LambdaGui, - val owner: IComponent, + val ownerComponent: R, private val childRect: () -> Rect, private val childAccessible: (T) -> Boolean = { true } ) : IComponent { - override val isActive get() = owner.isActive - override val childShowAnimation get() = owner.childShowAnimation + override val isActive get() = ownerComponent.isActive + override val childShowAnimation get() = ownerComponent.childShowAnimation override val rect get() = childRect() val children = mutableListOf() @@ -32,8 +32,8 @@ open class ChildLayer ( children.forEach { child -> when (e) { is GuiEvent.Tick -> { - val ownerAccessible = (owner as? ChildComponent)?.accessible ?: true - child.accessible = childAccessible(child) && child.rect in rect && ownerAccessible && owner.isActive + val ownerAccessible = (ownerComponent as? ChildComponent)?.accessible ?: true + child.accessible = childAccessible(child) && child.rect in rect && ownerAccessible && ownerComponent.isActive } is GuiEvent.KeyPress, is GuiEvent.CharTyped -> { @@ -52,11 +52,11 @@ open class ChildLayer ( } } - class Drawable ( + class Drawable ( gui: LambdaGui, - owner: IComponent, + owner: R, val renderer: RenderLayer, contentRect: () -> Rect, childAccessible: (T) -> Boolean = { true } - ) : ChildLayer(gui, owner, contentRect, childAccessible) + ) : ChildLayer(gui, owner, contentRect, childAccessible) } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 810f09dc6..4d4c8e027 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -18,7 +18,7 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli if (closing) ClickGui.closeSpeed else ClickGui.openSpeed }) { !closing }; private set - val windows = ChildLayer>(this, this, ::rect) { child -> + val windows = ChildLayer, AbstractClickGui>(this, this, ::rect) { child -> child == activeWindow && !closing } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 74f6d5642..0bff07314 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -7,12 +7,12 @@ import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.graphics.gl.Scissor.scissor import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton import com.lambda.gui.impl.clickgui.buttons.setting.NumberSlider -import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse @@ -26,7 +26,10 @@ import com.lambda.util.math.transform import java.awt.Color import kotlin.math.abs -class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButton(owner) { +class ModuleButton( + val module: Module, + override val owner: ChildLayer.Drawable> +) : ListButton(owner) { override val text get() = module.name private val enabled get() = module.isEnabled @@ -38,8 +41,8 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt private var isOpen = false override val isActive get() = isOpen - private val childShowAnimation0 by animation.exp(0.0, 1.0, 0.7, ::isOpen) - override val childShowAnimation get() = lerp(0.0, childShowAnimation0, owner.childShowAnimation) + private val openAnimation by animation.exp(0.0, 1.0, 0.7, ::isOpen) + override val childShowAnimation get() = lerp(0.0, openAnimation, owner.childShowAnimation) private var settingsHeight = 0.0 private var renderHeight by animation.exp(::settingsHeight, 0.6) @@ -48,7 +51,7 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt .moveSecond(Vec2d(0.0, renderHeight)) private val settingsRenderer = RenderLayer() - private val settingsLayer = ChildLayer.Drawable>(owner.gui, this, settingsRenderer, ::settingsRect) { + val settingsLayer = ChildLayer.Drawable, ModuleButton>(owner.gui, this, settingsRenderer, ::settingsRect) { it.visible && abs(settingsHeight - renderHeight) <3 } @@ -86,9 +89,8 @@ class ModuleButton(val module: Module, owner: ChildLayer.Drawable<*>) : ListButt // Bottom shadow renderer.filled { - val show = (owner.owner as? ModuleWindow)?.let { - this@ModuleButton != it.contentComponents.children.lastOrNull() - } ?: false + val last = this@ModuleButton.owner.ownerComponent.contentComponents.children.lastOrNull() + val show = this@ModuleButton != last position = Rect(settingsRect.leftBottom - Vec2d(0.0, 5.0), settingsRect.rightBottom) val progress = transform(renderHeight, 0.0, 10.0, 0.0, 1.0).coerceIn(0.0, 1.0) * show.toInt() diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index 335ca9879..0d37fec00 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -9,7 +9,7 @@ import com.lambda.util.math.MathUtils.lerp abstract class SettingButton > ( val setting: T, - owner: ChildLayer.Drawable<*> + final override val owner: ChildLayer.Drawable<*, ModuleButton> ): ListButton(owner) { override val text = setting.name protected var value by setting @@ -19,17 +19,14 @@ abstract class SettingButton > ( private var visibilityAnimation by animation.exp(0.0, 1.0, 0.6, ::visible) override val showAnimation get() = lerp(0.0, super.showAnimation, visibilityAnimation) - override var activeAnimation = 0.0 override val renderHeightOffset get() = renderHeightAnimation + lerp(-size.y, 0.0, visibilityAnimation) + override var activeAnimation = 0.0 override fun onEvent(e: GuiEvent) { super.onEvent(e) - when (e) { - is GuiEvent.Tick -> { - if (!prevTickVisible && visible) renderHeightAnimation = heightOffset - prevTickVisible = visible - } - } + if (e !is GuiEvent.Tick) return + if (!prevTickVisible && visible) renderHeightAnimation = heightOffset + prevTickVisible = visible } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 8d25a9065..529feffe5 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -6,10 +6,11 @@ import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse -import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Rect import com.lambda.util.math.Rect.Companion.inv @@ -17,7 +18,7 @@ import com.lambda.util.math.Vec2d class BooleanButton( setting: BooleanSetting, - owner: ChildLayer.Drawable<*> + owner: ChildLayer.Drawable<*, ModuleButton> ) : SettingButton(setting, owner) { private var active by animation.exp(0.0, 1.0, 0.6, ::value) private val zoomAnimation get() = lerp(2.0, 0.0, showAnimation) @@ -35,7 +36,7 @@ class BooleanButton( position = checkboxRect roundRadius = checkboxRect.size.y shade = GuiSettings.shade - color(GuiSettings.mainColor.setAlpha(showAnimation * (0.2 + active * 0.2))) + color(GuiSettings.mainColor.multAlpha(showAnimation * (0.2 + active * 0.2))) } // Checkbox Knob @@ -43,7 +44,7 @@ class BooleanButton( position = checkboxKnob roundRadius = checkboxKnob.size.y shade = GuiSettings.shadeBackground - color(GuiSettings.backgroundColor.setAlpha(showAnimation)) + color(GuiSettings.backgroundColor.multAlpha(showAnimation)) } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt index 4bf7824fd..c924ec778 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt @@ -2,8 +2,15 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.NumericSetting import com.lambda.graphics.animation.Animation.Companion.exp +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.button.InputBarOverlay import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.modules.client.ClickGui +import com.lambda.util.Mouse +import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.ColorUtils.setAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.roundToStep @@ -14,7 +21,7 @@ import java.awt.Color class NumberSlider ( setting: NumericSetting, - owner: ChildLayer.Drawable<*> + owner: ChildLayer.Drawable<*, ModuleButton> ) : SliderSetting>( setting, owner ) where N : Number, N : Comparable { @@ -23,19 +30,66 @@ class NumberSlider ( private val renderProgress0 by animation.exp(::targetProgress, 0.6) override val renderProgress get() = lerp(0.0, renderProgress0, showAnimation) + private val layer = ChildLayer.Drawable(owner.gui, this, owner.renderer, ::rect, InputBarOverlay::isActive) + private val inputBar: InputBarOverlay = object : InputBarOverlay(renderer, layer) { + override val pressAnimation get() = this@NumberSlider.pressAnimation + override val interactAnimation get() = this@NumberSlider.interactAnimation + override val hoverFontAnimation get() = this@NumberSlider.hoverFontAnimation + override val showAnimation get() = this@NumberSlider.showAnimation + + override fun getInitText() = value.let(Number::toString) + override fun setValue(string: String) { + string.toDoubleOrNull()?.let(::setValue) + } + }.apply(layer::addChild) + + override val textColor get() = super.textColor.multAlpha(1.0 - inputBar.activeAnimation) + init { renderer.font { text = value.let(Number::toString) + + val progress = 1.0 - inputBar.activeAnimation + scale = lerp(0.5, 1.0, progress) position = Vec2d(rect.right, rect.center.y) - Vec2d(ClickGui.windowPadding + stringWidth, 0.0) - color = Color.WHITE.setAlpha(showAnimation) + color = Color.WHITE.setAlpha(lerp(0.0, progress, showAnimation)) + } + } + + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + layer.onEvent(e) + } + + override fun performClickAction(e: GuiEvent.MouseClick) { + if (e.button != Mouse.Button.Right) return + + val windows = (owner.gui as AbstractClickGui).windows + windows.children.filterIsInstance().forEach { moduleWindow -> + moduleWindow.contentComponents.children.forEach { moduleButton -> + moduleButton.settingsLayer.children + .filterIsInstance>() + .apply { (this as MutableList).remove(this@NumberSlider) } + .forEach { it.inputBar.isActive = false } + } } + + inputBar.toggle() + } + + override fun slide(mouse: Vec2d) { + if (!inputBar.isActive) super.slide(mouse) } override fun setValueByProgress(progress: Double) { - value = value.typeConvert(lerp( + setValue(lerp( setting.range.start.toDouble(), setting.range.endInclusive.toDouble(), progress - ).roundToStep(setting.step.toDouble())) + )) + } + + private fun setValue(valueIn: Double) { + value = value.typeConvert(valueIn.roundToStep(setting.step.toDouble())) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt index a0592a2f9..5486dc96d 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt @@ -3,19 +3,19 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.AbstractSetting import com.lambda.core.LambdaSound import com.lambda.core.SoundManager.playSound -import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.module.modules.client.GuiSettings +import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Vec2d import com.lambda.util.math.transform -import kotlin.math.abs abstract class SliderSetting >( - setting: T, owner: ChildLayer.Drawable<*> + setting: T, owner: ChildLayer.Drawable<*, ModuleButton> ) : SettingButton(setting, owner) { protected abstract val renderProgress: Double protected abstract fun setValueByProgress(progress: Double) @@ -24,7 +24,7 @@ abstract class SliderSetting >( init { renderer.filled { - position = rect.moveSecond(Vec2d(-rect.size.x * (1.0 - renderProgress), 0.0)).shrink(interactAnimation) + position = rect.moveSecond(Vec2d(-rect.size.x * (1.0 - renderProgress), 0.0)).shrink(shrink) shade = GuiSettings.shade color(GuiSettings.mainColor.multAlpha(showAnimation * 0.3)) } @@ -32,21 +32,26 @@ abstract class SliderSetting >( override fun onEvent(e: GuiEvent) { super.onEvent(e) + if (e is GuiEvent.MouseMove) slide(e.mouse) + } - when (e) { - is GuiEvent.MouseMove -> { - if (!pressed) return - val p = transform(e.mouse.x, rect.left, rect.right, 0.0, 1.0).coerceIn(0.0, 1.0) - setValueByProgress(p) + override fun onPress(e: GuiEvent.MouseClick) { + super.onPress(e) + slide(e.mouse) + } - val time = System.currentTimeMillis() - if (lastPlayedValue == value || time - lastPlayedTiming < 50) return + protected open fun slide(mouse: Vec2d) { + if (activeButton != Mouse.Button.Left) return - lastPlayedValue = value - lastPlayedTiming = time + val p = transform(mouse.x, rect.left, rect.right, 0.0, 1.0).coerceIn(0.0, 1.0) + setValueByProgress(p) - playSound(LambdaSound.BUTTON_CLICK.event, lerp(0.9, 1.2, p)) - } - } + val time = System.currentTimeMillis() + if (lastPlayedValue == value || time - lastPlayedTiming < 50) return + + lastPlayedValue = value + lastPlayedTiming = time + + playSound(LambdaSound.BUTTON_CLICK.event, lerp(0.9, 1.2, p)) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt index 2ef0ea40b..67fe48ae1 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt @@ -9,9 +9,9 @@ abstract class ModuleWindow( override var title: String, override var width: Double = 110.0, override var height: Double = 300.0, - owner: AbstractClickGui -) : ListWindow(owner) { - override fun onEvent(e: GuiEvent) { + gui: AbstractClickGui +) : ListWindow(gui) { + override fun onEvent(e: GuiEvent) { if (e is GuiEvent.Tick) { contentComponents.children.sortBy { it.module.name diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index b571a5d54..05962ce36 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -9,8 +9,8 @@ import com.lambda.module.Module class CustomModuleWindow( override var title: String = "Untitled", val modules: MutableList = mutableListOf(), - owner: AbstractClickGui -) : ModuleWindow(title, owner = owner) { + gui: AbstractClickGui +) : ModuleWindow(title, gui = gui) { override fun onEvent(e: GuiEvent) { if (e is GuiEvent.Tick) updateModules() super.onEvent(e) @@ -29,7 +29,7 @@ class CustomModuleWindow( // Remove deleted modules children.forEach { button -> if (button.module !in modules) { - this@CustomModuleWindow.owner.scheduleAction { + this@CustomModuleWindow.gui.scheduleAction { removeChild(button) } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt index 1d10ff66e..1ddcbe558 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt @@ -9,7 +9,7 @@ import com.lambda.module.tag.ModuleTag class TagWindow( val tag: ModuleTag, owner: AbstractClickGui -) : ModuleWindow(tag.name, owner = owner) { +) : ModuleWindow(tag.name, gui = owner) { init { ModuleRegistry.modules .filter { it.defaultTags.firstOrNull() == tag } From d876309c5f376f988202a6091e145cfb9ac69a0a Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 12 May 2024 18:31:54 +0300 Subject: [PATCH 61/63] String setting --- .../api/component/button/InputBarOverlay.kt | 24 +++++++--- .../gui/impl/clickgui/AbstractClickGui.kt | 10 +++++ .../gui/impl/clickgui/buttons/ModuleButton.kt | 3 ++ .../impl/clickgui/buttons/SettingButton.kt | 4 +- .../clickgui/buttons/setting/BooleanButton.kt | 2 +- .../clickgui/buttons/setting/NumberSlider.kt | 36 ++++----------- .../clickgui/buttons/setting/SliderSetting.kt | 2 +- .../clickgui/buttons/setting/StringButton.kt | 44 +++++++++++++++++++ .../module/modules/render/RenderTest.kt | 4 +- 9 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/StringButton.kt diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt index c98598a1e..11adbf1b4 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/InputBarOverlay.kt @@ -7,6 +7,7 @@ import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.LayerEntry import com.lambda.module.modules.client.ClickGui import com.lambda.util.KeyCode +import com.lambda.util.math.ColorUtils.multAlpha import com.lambda.util.math.ColorUtils.setAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Rect @@ -18,10 +19,10 @@ abstract class InputBarOverlay (renderer: LayerEntry, owner: ChildLayer.Drawable override val rect: Rect get() = owner.rect override var isActive = false - abstract val pressAnimation: Double - abstract val interactAnimation: Double - abstract val hoverFontAnimation: Double - abstract val showAnimation: Double + protected abstract val pressAnimation: Double + protected abstract val interactAnimation: Double + protected abstract val hoverFontAnimation: Double + protected abstract val showAnimation: Double val activeAnimation by owner.gui.animation.exp(0.0, 1.0, 0.7, ::isActive) private var typeAnimation by owner.gui.animation.exp({ 0.0 }, 0.2) @@ -29,7 +30,7 @@ abstract class InputBarOverlay (renderer: LayerEntry, owner: ChildLayer.Drawable private var targetOffset = 0.0 private var offset by owner.gui.animation.exp(::targetOffset, 0.4) - abstract fun getInitText(): String + abstract fun getText(): String abstract fun setValue(string: String) open fun isCharAllowed(char: Char): Boolean = true @@ -53,7 +54,16 @@ abstract class InputBarOverlay (renderer: LayerEntry, owner: ChildLayer.Drawable Vec2d(1.0, rect.bottom - shrink) ) + Vec2d(lerp(rect.right, x, activeAnimation), 0.0) - color(field.color.setAlpha(0.8)) + color(field.color.multAlpha(0.8)) + } + + renderer.font { + text = getText() + + val progress = 1.0 - activeAnimation + scale = lerp(0.5, 1.0, progress) + position = Vec2d(rect.right, rect.center.y) - Vec2d(ClickGui.windowPadding + stringWidth, 0.0) + color = Color.WHITE.setAlpha(lerp(0.0, progress, showAnimation)) } } @@ -93,7 +103,7 @@ abstract class InputBarOverlay (renderer: LayerEntry, owner: ChildLayer.Drawable isActive = !isActive if (isActive) { - field.text = getInitText() + field.text = getText() targetOffset = field.stringWidth } } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt index 4d4c8e027..41fdbf5a6 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/AbstractClickGui.kt @@ -6,6 +6,8 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.LambdaGui import com.lambda.gui.api.component.WindowComponent import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.modules.client.ClickGui import com.lambda.util.Mouse import com.mojang.blaze3d.systems.RenderSystem.recordRenderCall @@ -60,6 +62,14 @@ abstract class AbstractClickGui(name: String = "ClickGui") : LambdaGui(name, Cli } } + fun unfocusSettings() { + windows.children.filterIsInstance().forEach { moduleWindow -> + moduleWindow.contentComponents.children.forEach { moduleButton -> + moduleButton.settingsLayer.children.forEach(SettingButton<*, *>::unfocus) + } + } + } + override fun close() { closing = true } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 0bff07314..f95123586 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -1,6 +1,7 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.config.settings.NumericSetting +import com.lambda.config.settings.StringSetting import com.lambda.config.settings.comparable.BooleanSetting import com.lambda.core.LambdaSound import com.lambda.core.SoundManager.playSoundRandomly @@ -13,6 +14,7 @@ import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton import com.lambda.gui.impl.clickgui.buttons.setting.NumberSlider +import com.lambda.gui.impl.clickgui.buttons.setting.StringButton import com.lambda.module.Module import com.lambda.module.modules.client.GuiSettings import com.lambda.util.Mouse @@ -101,6 +103,7 @@ class ModuleButton( when (it) { is BooleanSetting -> BooleanButton(it, settingsLayer) is NumericSetting<*> -> NumberSlider(it, settingsLayer) + is StringSetting -> StringButton(it, settingsLayer) else -> null } }.forEach(settingsLayer::addChild) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index 0d37fec00..e006e226e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -9,7 +9,7 @@ import com.lambda.util.math.MathUtils.lerp abstract class SettingButton > ( val setting: T, - final override val owner: ChildLayer.Drawable<*, ModuleButton> + final override val owner: ChildLayer.Drawable, ModuleButton> ): ListButton(owner) { override val text = setting.name protected var value by setting @@ -29,4 +29,6 @@ abstract class SettingButton > ( if (!prevTickVisible && visible) renderHeightAnimation = heightOffset prevTickVisible = visible } + + open fun unfocus() {} } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt index 529feffe5..27a55a353 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/BooleanButton.kt @@ -18,7 +18,7 @@ import com.lambda.util.math.Vec2d class BooleanButton( setting: BooleanSetting, - owner: ChildLayer.Drawable<*, ModuleButton> + owner: ChildLayer.Drawable, ModuleButton> ) : SettingButton(setting, owner) { private var active by animation.exp(0.0, 1.0, 0.6, ::value) private val zoomAnimation get() = lerp(2.0, 0.0, showAnimation) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt index c924ec778..7aff8d98e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt @@ -7,21 +7,18 @@ import com.lambda.gui.api.component.button.InputBarOverlay import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton -import com.lambda.gui.impl.clickgui.windows.ModuleWindow -import com.lambda.module.modules.client.ClickGui +import com.lambda.gui.impl.clickgui.buttons.SettingButton import com.lambda.util.Mouse import com.lambda.util.math.ColorUtils.multAlpha -import com.lambda.util.math.ColorUtils.setAlpha import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.MathUtils.roundToStep import com.lambda.util.math.MathUtils.typeConvert import com.lambda.util.math.Vec2d import com.lambda.util.math.normalize -import java.awt.Color class NumberSlider ( setting: NumericSetting, - owner: ChildLayer.Drawable<*, ModuleButton> + owner: ChildLayer.Drawable, ModuleButton> ) : SliderSetting>( setting, owner ) where N : Number, N : Comparable { @@ -37,7 +34,7 @@ class NumberSlider ( override val hoverFontAnimation get() = this@NumberSlider.hoverFontAnimation override val showAnimation get() = this@NumberSlider.showAnimation - override fun getInitText() = value.let(Number::toString) + override fun getText() = value.let(Number::toString) override fun setValue(string: String) { string.toDoubleOrNull()?.let(::setValue) } @@ -45,35 +42,18 @@ class NumberSlider ( override val textColor get() = super.textColor.multAlpha(1.0 - inputBar.activeAnimation) - init { - renderer.font { - text = value.let(Number::toString) - - val progress = 1.0 - inputBar.activeAnimation - scale = lerp(0.5, 1.0, progress) - position = Vec2d(rect.right, rect.center.y) - Vec2d(ClickGui.windowPadding + stringWidth, 0.0) - color = Color.WHITE.setAlpha(lerp(0.0, progress, showAnimation)) - } - } - override fun onEvent(e: GuiEvent) { super.onEvent(e) layer.onEvent(e) } + override fun unfocus() { + inputBar.isActive = false + } + override fun performClickAction(e: GuiEvent.MouseClick) { if (e.button != Mouse.Button.Right) return - - val windows = (owner.gui as AbstractClickGui).windows - windows.children.filterIsInstance().forEach { moduleWindow -> - moduleWindow.contentComponents.children.forEach { moduleButton -> - moduleButton.settingsLayer.children - .filterIsInstance>() - .apply { (this as MutableList).remove(this@NumberSlider) } - .forEach { it.inputBar.isActive = false } - } - } - + if (!inputBar.isActive) (owner.gui as? AbstractClickGui)?.unfocusSettings() inputBar.toggle() } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt index 5486dc96d..1f9974b87 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt @@ -15,7 +15,7 @@ import com.lambda.util.math.Vec2d import com.lambda.util.math.transform abstract class SliderSetting >( - setting: T, owner: ChildLayer.Drawable<*, ModuleButton> + setting: T, owner: ChildLayer.Drawable, ModuleButton> ) : SettingButton(setting, owner) { protected abstract val renderProgress: Double protected abstract fun setValueByProgress(progress: Double) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/StringButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/StringButton.kt new file mode 100644 index 000000000..fa3a2d1b0 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/StringButton.kt @@ -0,0 +1,44 @@ +package com.lambda.gui.impl.clickgui.buttons.setting + +import com.lambda.config.settings.StringSetting +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.button.InputBarOverlay +import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.AbstractClickGui +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.util.Mouse +import com.lambda.util.math.ColorUtils.multAlpha + +class StringButton( + setting: StringSetting, + owner: ChildLayer.Drawable, ModuleButton> +) : SettingButton(setting, owner) { + private val layer = ChildLayer.Drawable(owner.gui, this, owner.renderer, ::rect, InputBarOverlay::isActive) + private val inputBar: InputBarOverlay = object : InputBarOverlay(renderer, layer) { + override val pressAnimation get() = this@StringButton.pressAnimation + override val interactAnimation get() = this@StringButton.interactAnimation + override val hoverFontAnimation get() = this@StringButton.hoverFontAnimation + override val showAnimation get() = this@StringButton.showAnimation + + override fun getText() = value + override fun setValue(string: String) { value = string } + }.apply(layer::addChild) + + override val textColor get() = super.textColor.multAlpha(1.0 - inputBar.activeAnimation) + + override fun onEvent(e: GuiEvent) { + super.onEvent(e) + layer.onEvent(e) + } + + override fun unfocus() { + inputBar.isActive = false + } + + override fun performClickAction(e: GuiEvent.MouseClick) { + if (e.button != Mouse.Button.Right) return + if (!inputBar.isActive) (owner.gui as? AbstractClickGui)?.unfocusSettings() + inputBar.toggle() + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt index e5a697b2e..6f0b44c98 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/render/RenderTest.kt @@ -23,8 +23,8 @@ object RenderTest : Module( ) { private val test1 by setting("Toggle visibility", true) private val test21 by setting("Hallo 1", true, visibility = ::test1) - private val test22 by setting("Hallo 2", true, visibility = ::test1) - private val test23 by setting("Hallo 3", true, visibility = ::test1) + private val test22 by setting("Hallo Slider", 1.0, 0.0..5.0, 0.5, visibility = ::test1) + private val test23 by setting("Hallo String", "bruh", visibility = ::test1) private val test31 by setting("Holla huh 1", true, visibility = { !test1 }) private val test32 by setting("Holla buh 2", true, visibility = { !test1 }) From 179a54e3257665f8fd3d703bc19dba77766cd073 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 12 May 2024 20:06:04 +0300 Subject: [PATCH 62/63] Enum setting & misc --- .../config/settings/comparable/EnumSetting.kt | 10 +++- .../gui/api/component/InteractiveComponent.kt | 11 ++-- .../api/component/core/list/ChildComponent.kt | 7 +-- .../gui/impl/clickgui/buttons/ModuleButton.kt | 4 ++ .../impl/clickgui/buttons/SettingButton.kt | 3 ++ .../clickgui/buttons/setting/EnumSlider.kt | 51 +++++++++++++++++++ .../clickgui/buttons/setting/NumberSlider.kt | 7 +-- .../setting/{SliderSetting.kt => Slider.kt} | 8 ++- .../lambda/module/modules/client/ClickGui.kt | 2 +- 9 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/EnumSlider.kt rename common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/{SliderSetting.kt => Slider.kt} (85%) diff --git a/common/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt b/common/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt index 151215ecd..ed0287463 100644 --- a/common/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt +++ b/common/src/main/kotlin/com/lambda/config/settings/comparable/EnumSetting.kt @@ -1,6 +1,8 @@ package com.lambda.config.settings.comparable import com.lambda.config.AbstractSetting +import com.lambda.util.Nameable +import java.util.* class EnumSetting>( override val name: String, @@ -12,7 +14,13 @@ class EnumSetting>( description, visibility, ) { - private val enumValues: Array = defaultValue.declaringJavaClass.enumConstants + val displayValue get() = (value as? Nameable)?.name ?: value.name.split('_').joinToString(" ") { low -> + low.lowercase().replaceFirstChar { + if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() + } + } + + val enumValues: Array = defaultValue.declaringJavaClass.enumConstants fun next() { value = enumValues[((value.ordinal + 1) % enumValues.size)] diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt index d0c8bfe14..b10817edf 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/InteractiveComponent.kt @@ -3,27 +3,30 @@ package com.lambda.gui.api.component import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.IComponent import com.lambda.util.Mouse +import com.lambda.util.math.Vec2d abstract class InteractiveComponent : IComponent { - protected var hovered = false + protected open val hovered get() = rect.contains(lastMouse) protected var activeButton: Mouse.Button? = null protected open fun onPress(e: GuiEvent.MouseClick) {} protected open fun onRelease(e: GuiEvent.MouseClick) {} + private var lastMouse = Vec2d.ZERO + override fun onEvent(e: GuiEvent) { when (e) { is GuiEvent.Show -> { - hovered = false + lastMouse = Vec2d.ONE * -1000.0 activeButton = null } is GuiEvent.MouseMove -> { - hovered = rect.contains(e.mouse) + lastMouse = e.mouse } is GuiEvent.MouseClick -> { - hovered = rect.contains(e.mouse) + lastMouse = e.mouse val prevPressed = activeButton != null activeButton = if (hovered && e.button.isMainButton && e.action == Mouse.Action.Click) e.button else null diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt index b1d2ec298..9c71aec5c 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/core/list/ChildComponent.kt @@ -1,15 +1,10 @@ package com.lambda.gui.api.component.core.list -import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.InteractiveComponent abstract class ChildComponent(open val owner: ChildLayer<*, *>) : InteractiveComponent() { open var accessible = false - - override fun onEvent(e: GuiEvent) { - super.onEvent(e) - if (e is GuiEvent.MouseMove || e is GuiEvent.MouseClick) hovered = hovered && accessible - } + override val hovered; get() = super.hovered && accessible open fun onAdd() {} open fun onRemove() {} diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index f95123586..074041e7b 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -3,6 +3,7 @@ package com.lambda.gui.impl.clickgui.buttons import com.lambda.config.settings.NumericSetting import com.lambda.config.settings.StringSetting import com.lambda.config.settings.comparable.BooleanSetting +import com.lambda.config.settings.comparable.EnumSetting import com.lambda.core.LambdaSound import com.lambda.core.SoundManager.playSoundRandomly import com.lambda.graphics.animation.Animation.Companion.exp @@ -13,6 +14,7 @@ import com.lambda.gui.api.component.button.ListButton import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.api.layer.RenderLayer import com.lambda.gui.impl.clickgui.buttons.setting.BooleanButton +import com.lambda.gui.impl.clickgui.buttons.setting.EnumSlider import com.lambda.gui.impl.clickgui.buttons.setting.NumberSlider import com.lambda.gui.impl.clickgui.buttons.setting.StringButton import com.lambda.module.Module @@ -99,11 +101,13 @@ class ModuleButton( colorV(Color.BLACK.setAlpha(0.0), Color.BLACK.setAlpha(0.2 * progress)) } + // TODO: resort when all settings are implemented module.settings.mapNotNull { when (it) { is BooleanSetting -> BooleanButton(it, settingsLayer) is NumericSetting<*> -> NumberSlider(it, settingsLayer) is StringSetting -> StringButton(it, settingsLayer) + is EnumSetting<*> -> EnumSlider(it, settingsLayer) else -> null } }.forEach(settingsLayer::addChild) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt index e006e226e..351e0fa76 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/SettingButton.kt @@ -26,8 +26,11 @@ abstract class SettingButton > ( super.onEvent(e) if (e !is GuiEvent.Tick) return + if (!prevTickVisible && visible) renderHeightAnimation = heightOffset prevTickVisible = visible + + if (!visible) unfocus() } open fun unfocus() {} diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/EnumSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/EnumSlider.kt new file mode 100644 index 000000000..4ffca31b1 --- /dev/null +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/EnumSlider.kt @@ -0,0 +1,51 @@ +package com.lambda.gui.impl.clickgui.buttons.setting + +import com.lambda.config.settings.comparable.EnumSetting +import com.lambda.gui.api.GuiEvent +import com.lambda.gui.api.component.core.list.ChildLayer +import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.gui.impl.clickgui.buttons.SettingButton +import com.lambda.module.modules.client.ClickGui +import com.lambda.util.math.ColorUtils.setAlpha +import com.lambda.util.math.MathUtils.lerp +import com.lambda.util.math.Vec2d +import com.lambda.util.math.transform +import java.awt.Color +import kotlin.math.floor + +class EnumSlider > ( + setting: EnumSetting, + owner: ChildLayer.Drawable, ModuleButton> +) : Slider>(setting, owner) { + private val values = setting.enumValues + private val enumSize = values.size + + override val progress get() = if (dragProgress != -1.0) dragProgress else + transform(value.ordinal.toDouble(), 0.0, enumSize - 1.0, 0.0, 1.0) + + private var dragProgress = -1.0 + + override fun setValueByProgress(progress: Double) { + val entryIndex = floor(progress * enumSize).toInt().coerceIn(0, enumSize - 1) + value = values[entryIndex] + dragProgress = progress + } + + override fun onPress(e: GuiEvent.MouseClick) {} + + override fun onRelease(e: GuiEvent.MouseClick) { + if (dragProgress == -1.0) setting.next() + dragProgress = -1.0 + } + + init { + renderer.font { + text = setting.displayValue + + val progress = 1.0 - activeAnimation + scale = lerp(0.5, 1.0, progress) + position = Vec2d(rect.right, rect.center.y) - Vec2d(ClickGui.windowPadding + stringWidth, 0.0) + color = Color.WHITE.setAlpha(lerp(0.0, progress, showAnimation)) + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt index 7aff8d98e..84541b64e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/NumberSlider.kt @@ -1,7 +1,6 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.settings.NumericSetting -import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.button.InputBarOverlay import com.lambda.gui.api.component.core.list.ChildLayer @@ -19,13 +18,11 @@ import com.lambda.util.math.normalize class NumberSlider ( setting: NumericSetting, owner: ChildLayer.Drawable, ModuleButton> -) : SliderSetting>( +) : Slider>( setting, owner ) where N : Number, N : Comparable { private val doubleRange get() = setting.range.let { it.start.toDouble()..it.endInclusive.toDouble() } - private val targetProgress get() = doubleRange.normalize(value.toDouble()) - private val renderProgress0 by animation.exp(::targetProgress, 0.6) - override val renderProgress get() = lerp(0.0, renderProgress0, showAnimation) + override val progress get() = doubleRange.normalize(value.toDouble()) private val layer = ChildLayer.Drawable(owner.gui, this, owner.renderer, ::rect, InputBarOverlay::isActive) private val inputBar: InputBarOverlay = object : InputBarOverlay(renderer, layer) { diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt similarity index 85% rename from common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt rename to common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt index 1f9974b87..b9d1dddf1 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/SliderSetting.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt @@ -3,6 +3,7 @@ package com.lambda.gui.impl.clickgui.buttons.setting import com.lambda.config.AbstractSetting import com.lambda.core.LambdaSound import com.lambda.core.SoundManager.playSound +import com.lambda.graphics.animation.Animation.Companion.exp import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.core.list.ChildLayer import com.lambda.gui.impl.clickgui.buttons.ModuleButton @@ -14,10 +15,13 @@ import com.lambda.util.math.MathUtils.lerp import com.lambda.util.math.Vec2d import com.lambda.util.math.transform -abstract class SliderSetting >( +abstract class Slider >( setting: T, owner: ChildLayer.Drawable, ModuleButton> ) : SettingButton(setting, owner) { - protected abstract val renderProgress: Double + protected abstract val progress: Double + private val progressAnimation by animation.exp(::progress, 0.6) + private val renderProgress get() = lerp(0.0, progressAnimation, showAnimation) + protected abstract fun setValueByProgress(progress: Double) private var lastPlayedValue = value private var lastPlayedTiming = 0L diff --git a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt index fcd19d313..3a9af4480 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt @@ -17,7 +17,7 @@ object ClickGui : Module( val windowRadius by setting("Window Radius", 2.0, 0.0..10.0, 0.1) val windowPadding by setting("Window Padding", 2.0, 0.0..10.0, 0.1) val buttonHeight by setting("Button Height", 11.0, 8.0..20.0, 0.1) - val buttonStep by setting("Button Step", 1.0, 0.0..5.0, 0.1) + val buttonStep by setting("Button Step", 0.0, 0.0..5.0, 0.1) val windowBlur by setting("Window Blur", 30, 0..100, 1) // Animation From b9bfa6891c2068321ff9b5eea47b056247f4ff37 Mon Sep 17 00:00:00 2001 From: Blade-gl Date: Sun, 12 May 2024 23:35:33 +0300 Subject: [PATCH 63/63] Fix: Empty click gui at first launch --- .../api/component/button/ButtonComponent.kt | 6 ++-- .../gui/impl/clickgui/buttons/ModuleButton.kt | 2 +- .../impl/clickgui/buttons/setting/Slider.kt | 2 +- .../gui/impl/clickgui/windows/ModuleWindow.kt | 36 ++++++++++++++++++- .../windows/tag/CustomModuleWindow.kt | 28 +-------------- .../impl/clickgui/windows/tag/TagWindow.kt | 9 ++--- 6 files changed, 43 insertions(+), 40 deletions(-) diff --git a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt index c8e56f414..54ee20a19 100644 --- a/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt +++ b/common/src/main/kotlin/com/lambda/gui/api/component/button/ButtonComponent.kt @@ -42,12 +42,12 @@ abstract class ButtonComponent( private val renderHovered get() = hovered || System.currentTimeMillis() - lastHoveredTime < 110 // Removes button shrinking if there's no space between buttons - protected val shrink get() = lerp(0.0, interactAnimation, ClickGui.buttonStep) + protected val shrinkAnimation get() = lerp(0.0, interactAnimation, ClickGui.buttonStep) init { // Active color renderer.filled { - position = rect.shrink(shrink) + position = rect.shrink(shrinkAnimation) shade = GuiSettings.shade color(GuiSettings.mainColor.multAlpha(activeAnimation * 0.3 * showAnimation)) } @@ -55,7 +55,7 @@ abstract class ButtonComponent( // Hover glint renderer.filled { val hoverRect = Rect.basedOn(rect.leftTop, rect.size.x * hoverRectAnimation, rect.size.y) - position = hoverRect.shrink(shrink) + position = hoverRect.shrink(shrinkAnimation) shade = GuiSettings.shade val alpha = interactAnimation * 0.2 * showAnimation diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt index 074041e7b..2785ee916 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/ModuleButton.kt @@ -67,7 +67,7 @@ class ModuleButton( position = lerp(left, right, activeAnimation) .clamp(rect) - .shrink(interactAnimation) + .shrink(shrinkAnimation) // 0.0 .. 1.0 .. 0.0 animation val alpha = 1.0 - (abs(activeAnimation - 0.5) * 2.0) diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt index b9d1dddf1..df78bf16e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/buttons/setting/Slider.kt @@ -28,7 +28,7 @@ abstract class Slider >( init { renderer.filled { - position = rect.moveSecond(Vec2d(-rect.size.x * (1.0 - renderProgress), 0.0)).shrink(shrink) + position = rect.moveSecond(Vec2d(-rect.size.x * (1.0 - renderProgress), 0.0)).shrink(shrinkAnimation) shade = GuiSettings.shade color(GuiSettings.mainColor.multAlpha(showAnimation * 0.3)) } diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt index 67fe48ae1..1b7dce0c1 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/ModuleWindow.kt @@ -4,6 +4,7 @@ import com.lambda.gui.api.GuiEvent import com.lambda.gui.api.component.ListWindow import com.lambda.gui.impl.clickgui.AbstractClickGui import com.lambda.gui.impl.clickgui.buttons.ModuleButton +import com.lambda.module.Module abstract class ModuleWindow( override var title: String, @@ -11,7 +12,40 @@ abstract class ModuleWindow( override var height: Double = 300.0, gui: AbstractClickGui ) : ListWindow(gui) { - override fun onEvent(e: GuiEvent) { + private var lastUpdate = 0L + + abstract fun getModuleList(): Collection + + private fun updateModules() { + val time = System.currentTimeMillis() + if (time - lastUpdate < 1000L) return + lastUpdate = time + + contentComponents.apply { + val modules = getModuleList() + + // Add missing module buttons + modules.filter { module -> + children.all { button -> + button.module != module + } + }.map { ModuleButton(it, contentComponents) } + .forEach(contentComponents::addChild) + + // Remove deleted modules + children.forEach { button -> + if (button.module !in modules) { + this@ModuleWindow.gui.scheduleAction { + removeChild(button) + } + } + } + } + } + + override fun onEvent(e: GuiEvent) { + if (e is GuiEvent.Show || e is GuiEvent.Tick) updateModules() + if (e is GuiEvent.Tick) { contentComponents.children.sortBy { it.module.name diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt index 05962ce36..7d6103ea7 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/CustomModuleWindow.kt @@ -1,8 +1,6 @@ package com.lambda.gui.impl.clickgui.windows.tag -import com.lambda.gui.api.GuiEvent import com.lambda.gui.impl.clickgui.AbstractClickGui -import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.Module @@ -11,29 +9,5 @@ class CustomModuleWindow( val modules: MutableList = mutableListOf(), gui: AbstractClickGui ) : ModuleWindow(title, gui = gui) { - override fun onEvent(e: GuiEvent) { - if (e is GuiEvent.Tick) updateModules() - super.onEvent(e) - } - - private fun updateModules() { - contentComponents.apply { - // Add missing module buttons - modules.filter { module -> - children.all { button -> - button.module != module - } - }.map { ModuleButton(it, contentComponents) } - .forEach(contentComponents::addChild) - - // Remove deleted modules - children.forEach { button -> - if (button.module !in modules) { - this@CustomModuleWindow.gui.scheduleAction { - removeChild(button) - } - } - } - } - } + override fun getModuleList() = modules } \ No newline at end of file diff --git a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt index 1ddcbe558..a418ba53e 100644 --- a/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt +++ b/common/src/main/kotlin/com/lambda/gui/impl/clickgui/windows/tag/TagWindow.kt @@ -1,7 +1,6 @@ package com.lambda.gui.impl.clickgui.windows.tag import com.lambda.gui.impl.clickgui.AbstractClickGui -import com.lambda.gui.impl.clickgui.buttons.ModuleButton import com.lambda.gui.impl.clickgui.windows.ModuleWindow import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag @@ -10,10 +9,6 @@ class TagWindow( val tag: ModuleTag, owner: AbstractClickGui ) : ModuleWindow(tag.name, gui = owner) { - init { - ModuleRegistry.modules - .filter { it.defaultTags.firstOrNull() == tag } - .map { ModuleButton(it, contentComponents) } - .forEach(contentComponents::addChild) - } + override fun getModuleList() = ModuleRegistry.modules + .filter { it.defaultTags.firstOrNull() == tag } } \ No newline at end of file