diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917..b1b8ef56b 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cb6c7808d..eb84db68d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,24 +1,9 @@ -# -# Copyright 2026 Lambda -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 32402bdc2..249efbb03 100755 --- a/gradlew +++ b/gradlew @@ -1,25 +1,26 @@ #!/bin/sh # -# Copyright 2026 Lambda +# Copyright © 2015 the original authors. # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# https://www.apache.org/licenses/LICENSE-2.0 # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 # ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -28,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -56,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -85,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -113,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -171,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -204,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 25da30dbd..a51ec4f58 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,16 +13,18 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -49,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -63,30 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% -:mainEnd -if "%OS%"=="Windows_NT" endlocal +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/main/kotlin/com/lambda/Lambda.kt b/src/main/kotlin/com/lambda/Lambda.kt index e5a3c6dc5..8a35f68b7 100644 --- a/src/main/kotlin/com/lambda/Lambda.kt +++ b/src/main/kotlin/com/lambda/Lambda.kt @@ -45,9 +45,9 @@ import tools.jackson.module.kotlin.jsonMapper import tools.jackson.module.kotlin.kotlinModule object Lambda : ClientModInitializer { - const val MOD_NAME = "Lambda" - const val MOD_ID = "lambda" - const val SYMBOL = "λ" + const val MOD_NAME = "Comet" + const val MOD_ID = "comet" + const val SYMBOL = "☄" const val APP_ID = "1221289599427416127" const val REPO_URL = "https://github.com/lambda-client/lambda" val VERSION: String = diff --git a/src/main/kotlin/com/lambda/module/hud/ModuleList.kt b/src/main/kotlin/com/lambda/module/hud/ModuleList.kt index cd438fbc2..6aaba1946 100644 --- a/src/main/kotlin/com/lambda/module/hud/ModuleList.kt +++ b/src/main/kotlin/com/lambda/module/hud/ModuleList.kt @@ -18,10 +18,13 @@ package com.lambda.module.hud import com.lambda.gui.dsl.ImGuiBuilder +import com.lambda.imgui.ImColor +import com.lambda.imgui.ImGui import com.lambda.imgui.flag.ImGuiCol import com.lambda.module.HudModule import com.lambda.module.ModuleRegistry import com.lambda.module.tag.ModuleTag +import com.lambda.util.NamedEnum import java.awt.Color @Suppress("unused") @@ -29,27 +32,104 @@ object ModuleList : HudModule( name = "ModuleList", tag = ModuleTag.HUD, ) { - val onlyBound by setting("Only Bound", false, "Only displays modules with a keybind") - val showKeybind by setting("Show Keybind", true, "Display keybind next to a module") + private val onlyBound by setting("Only Bound", false, "Only displays modules with a keybind") + private val showKeybind by setting("Show Keybind", true, "Display keybind next to a module") + private val textColor by setting( + "Text Color", + Color(80, 210, 255), + "Module name color" + ) + private val alignment by setting("Alignment", Alignment.Left, "Align shorter names to the left or right") + private val sortOrder by setting("Sort Order", SortOrder.LengthLongToShort, "Order the module list") + private val boundKeybindColor by setting( + "Bound Keybind Color", + Color(90, 255, 120), + "Color for modules with a keybind", + visibility = { showKeybind } + ) + private val unboundKeybindColor by setting( + "Unbound Keybind Color", + Color(255, 80, 80), + "Color for modules without a keybind", + visibility = { showKeybind && !onlyBound } + ) init { drawSetting.value = false } override fun ImGuiBuilder.buildLayout() { - val enabled = ModuleRegistry.modules.filter { it.isEnabled && it.draw } + val rows = ModuleRegistry.modules + .asSequence() + .filter { it.isEnabled && it.draw } + .mapNotNull { + val bound = it.keybind.key != 0 || it.keybind.mouse != -1 + if (onlyBound && !bound) return@mapNotNull null - enabled.forEach { - val bound = it.keybind.key != 0 || it.keybind.mouse != -1 - if (onlyBound && !bound) return@forEach - text(it.name) + val keybindText = if (showKeybind) " [${it.keybind.name}]" else "" + val fullText = it.name + keybindText - if (showKeybind) { - val color = if (!bound) Color.RED else Color.GREEN + ModuleRow( + name = it.name, + keybindText = keybindText, + bound = bound, + width = ImGui.calcTextSize(fullText).x + ) + } + .toList() + .sorted() - sameLine() - withStyleColor(ImGuiCol.Text, color) { text(" [${it.keybind.name}]") } - } + val maxWidth = rows.maxOfOrNull { it.width } ?: return + val lineStartX = cursorPosX + + rows.forEach { row -> + cursorPosX = when (alignment) { + Alignment.Left -> lineStartX + Alignment.Right -> lineStartX + maxWidth - row.width + } + + withStyleColor(ImGuiCol.Text, textColor.toImColor()) { + text(row.name) + } + + if (row.keybindText.isNotEmpty()) { + val keybindColor = if (row.bound) boundKeybindColor else unboundKeybindColor + sameLine(0f, 0f) + withStyleColor(ImGuiCol.Text, keybindColor.toImColor()) { + text(row.keybindText) + } + } } } + + private fun List.sorted() = + when (sortOrder) { + SortOrder.Default -> this + SortOrder.LengthLongToShort -> sortedByDescending { it.width } + SortOrder.LengthShortToLong -> sortedBy { it.width } + SortOrder.NameAToZ -> sortedBy { it.name.lowercase() } + SortOrder.NameZToA -> sortedByDescending { it.name.lowercase() } + } + + private fun Color.toImColor() = ImColor.rgba(red, green, blue, alpha) + + private data class ModuleRow( + val name: String, + val keybindText: String, + val bound: Boolean, + val width: Float, + ) + + private enum class Alignment(override val displayName: String) : NamedEnum { + Left("Left"), + Right("Right") + } + + private enum class SortOrder(override val displayName: String) : NamedEnum { + Default("Default"), + LengthLongToShort("Length: Long to Short"), + LengthShortToLong("Length: Short to Long"), + NameAToZ("Name: A to Z"), + NameZToA("Name: Z to A") + } } diff --git a/src/main/kotlin/com/lambda/module/modules/combat/autodisconnect/AutoDisconnect.kt b/src/main/kotlin/com/lambda/module/modules/combat/autodisconnect/AutoDisconnect.kt index b06319f15..09e098cc3 100644 --- a/src/main/kotlin/com/lambda/module/modules/combat/autodisconnect/AutoDisconnect.kt +++ b/src/main/kotlin/com/lambda/module/modules/combat/autodisconnect/AutoDisconnect.kt @@ -32,6 +32,7 @@ import com.lambda.sound.SoundHandler.playSound import com.lambda.util.CommunicationUtils import com.lambda.util.CommunicationUtils.prefix import com.lambda.util.FormattingUtils.format +import com.lambda.util.NamedEnum import com.lambda.util.combat.CombatUtils.hasDeadlyCrystal import com.lambda.util.combat.DamageUtils.isFallDeadly import com.lambda.util.extension.fullHealth @@ -80,11 +81,20 @@ object AutoDisconnect : Module( private const val PACKET_DISCONNECT_GROUP = "Packet Disconnect Methods" private const val DAMAGE_DISCONNECT_GROUP = "Disconnects by Damage Type" + private const val COORDINATE_DISCONNECT_GROUP = "Coordinate Disconnect" + private const val WORLD_BORDER_COORDINATE = 30_000_000 @Tab(DISCONNECT_CONDITIONS_TAB) private val health by setting("Health", true, "Disconnect from the server when health is below the set limit.") @Tab(DISCONNECT_CONDITIONS_TAB) private val minimumHealth by setting("Min Health", 10, 1..36, 1, "Set the minimum health threshold for disconnection.", unit = " half-hearts") { health } @Tab(DISCONNECT_CONDITIONS_TAB) private val yLevel by setting("Y Level", false, "Disconnect from the server when the player is below a certain y level") @Tab(DISCONNECT_CONDITIONS_TAB) private val minimumYLevel by setting("Minimum Y Level", 50, 0..319, 1, "The minimum y level the player can be at before disconnecting") { yLevel } + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val coordinates by setting("Coordinates", false, "Disconnect from the server when selected coordinate limits are reached or passed.") + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val xCoordinate by setting("X Axis", false, "Check the player's X coordinate.") { coordinates } + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val xCoordinateMode by setting("X Mode", CoordinateMode.LowerOrEqual, "Choose whether X disconnects at or below the limit, or at or above it.") { coordinates && xCoordinate } + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val xCoordinateLimit by setting("X Value", 0, -WORLD_BORDER_COORDINATE..WORLD_BORDER_COORDINATE, 1, "The X coordinate limit to disconnect at or beyond.") { coordinates && xCoordinate } + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val zCoordinate by setting("Z Axis", false, "Check the player's Z coordinate.") { coordinates } + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val zCoordinateMode by setting("Z Mode", CoordinateMode.LowerOrEqual, "Choose whether Z disconnects at or below the limit, or at or above it.") { coordinates && zCoordinate } + @Tab(DISCONNECT_CONDITIONS_TAB) @Group(COORDINATE_DISCONNECT_GROUP) private val zCoordinateLimit by setting("Z Value", 0, -WORLD_BORDER_COORDINATE..WORLD_BORDER_COORDINATE, 1, "The Z coordinate limit to disconnect at or beyond.") { coordinates && zCoordinate } @Tab(DISCONNECT_CONDITIONS_TAB) private val falls by setting("Falls", false, "Disconnect if the player will die of fall damage") @Tab(DISCONNECT_CONDITIONS_TAB) private val fallDistance by setting("Falls Time", 10, 0..30, 1, "Number of blocks fallen before disconnecting for fall damage.", unit = " blocks") { falls } @Tab(DISCONNECT_CONDITIONS_TAB) private val crystals by setting("Crystals", false, "Disconnect if an End Crystal explosion would be lethal.") @@ -282,6 +292,29 @@ object AutoDisconnect : Module( } } + private fun CoordinateMode.reached(value: Double, limit: Int): Boolean = + when (this) { + CoordinateMode.GreaterOrEqual -> value >= limit + CoordinateMode.LowerOrEqual -> value <= limit + } + + private fun buildCoordinateDisconnectReason( + axis: String, + value: Double, + limit: Int, + mode: CoordinateMode + ) = buildText { + literal("Player ") + highlighted(axis) + literal(" coordinate ") + highlighted(value.format()) + literal(" reached ") + highlighted(mode.displayName.lowercase()) + literal(" ") + highlighted("$limit") + literal("!") + } + enum class Reason(val check: () -> Boolean, val generateReason: SafeContext.() -> Text?) { Health({ health }, { if (player.fullHealth < minimumHealth) { @@ -303,6 +336,15 @@ object AutoDisconnect : Module( } } else null }), + Coordinates({ coordinates && (xCoordinate || zCoordinate) }, { + when { + xCoordinate && xCoordinateMode.reached(player.pos.x, xCoordinateLimit) -> + buildCoordinateDisconnectReason("X", player.pos.x, xCoordinateLimit, xCoordinateMode) + zCoordinate && zCoordinateMode.reached(player.pos.z, zCoordinateLimit) -> + buildCoordinateDisconnectReason("Z", player.pos.z, zCoordinateLimit, zCoordinateMode) + else -> null + } + }), Totem({ totem }, { val totemCount = player.allStacks.count { it.item == Items.TOTEM_OF_UNDYING } if (totemCount < minTotems) { @@ -357,6 +399,11 @@ object AutoDisconnect : Module( else null }) } + + private enum class CoordinateMode(override val displayName: String) : NamedEnum { + GreaterOrEqual("Greater or Equal"), + LowerOrEqual("Lower or Equal") + } } data class DisconnectDetails( diff --git a/src/main/resources/assets/lambda/textures/icon/logo_128.png b/src/main/resources/assets/lambda/textures/icon/logo_128.png index 886ac704f..69319ba6d 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_128.png and b/src/main/resources/assets/lambda/textures/icon/logo_128.png differ diff --git a/src/main/resources/assets/lambda/textures/icon/logo_16.png b/src/main/resources/assets/lambda/textures/icon/logo_16.png index ab98ecc12..b6f20e230 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_16.png and b/src/main/resources/assets/lambda/textures/icon/logo_16.png differ diff --git a/src/main/resources/assets/lambda/textures/icon/logo_24.png b/src/main/resources/assets/lambda/textures/icon/logo_24.png index 40788a586..cb6036e2e 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_24.png and b/src/main/resources/assets/lambda/textures/icon/logo_24.png differ diff --git a/src/main/resources/assets/lambda/textures/icon/logo_256.png b/src/main/resources/assets/lambda/textures/icon/logo_256.png index 679fcf0de..bfbe7ac13 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_256.png and b/src/main/resources/assets/lambda/textures/icon/logo_256.png differ diff --git a/src/main/resources/assets/lambda/textures/icon/logo_32.png b/src/main/resources/assets/lambda/textures/icon/logo_32.png index 35a0165d3..c8f57cbad 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_32.png and b/src/main/resources/assets/lambda/textures/icon/logo_32.png differ diff --git a/src/main/resources/assets/lambda/textures/icon/logo_48.png b/src/main/resources/assets/lambda/textures/icon/logo_48.png index a27ee2aef..6a1b19307 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_48.png and b/src/main/resources/assets/lambda/textures/icon/logo_48.png differ diff --git a/src/main/resources/assets/lambda/textures/icon/logo_64.png b/src/main/resources/assets/lambda/textures/icon/logo_64.png index 2ee4b7a32..756bd15fb 100644 Binary files a/src/main/resources/assets/lambda/textures/icon/logo_64.png and b/src/main/resources/assets/lambda/textures/icon/logo_64.png differ diff --git a/src/main/resources/assets/lambda/textures/lambda.png b/src/main/resources/assets/lambda/textures/lambda.png index 5283f59be..7a2029c9c 100644 Binary files a/src/main/resources/assets/lambda/textures/lambda.png and b/src/main/resources/assets/lambda/textures/lambda.png differ diff --git a/src/main/resources/assets/lambda/textures/lambda_banner.png b/src/main/resources/assets/lambda/textures/lambda_banner.png index 9140cf5a5..5c5cfed48 100644 Binary files a/src/main/resources/assets/lambda/textures/lambda_banner.png and b/src/main/resources/assets/lambda/textures/lambda_banner.png differ diff --git a/src/main/resources/assets/lambda/textures/lambda_mono.png b/src/main/resources/assets/lambda/textures/lambda_mono.png index cfb84fdf8..03d34052b 100644 Binary files a/src/main/resources/assets/lambda/textures/lambda_mono.png and b/src/main/resources/assets/lambda/textures/lambda_mono.png differ diff --git a/src/main/resources/assets/lambda/textures/lambda_text_color.png b/src/main/resources/assets/lambda/textures/lambda_text_color.png index b47f2f4ff..9f4f4e608 100644 Binary files a/src/main/resources/assets/lambda/textures/lambda_text_color.png and b/src/main/resources/assets/lambda/textures/lambda_text_color.png differ