Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2025 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 <http://www.gnu.org/licenses/>.
*/

package com.lambda.config.groups

import com.lambda.util.Describable
import com.lambda.util.NamedEnum
import java.time.format.DateTimeFormatter
import java.util.Locale

interface FormatterConfig {
val locale: Locale
val separator: String
val prefix: String
val postfix: String
val precision: Int
val format: DateTimeFormatter

enum class Locales(
override val displayName: String,
override val description: String,
val locale: Locale,
) : NamedEnum, Describable {
France("France", "Numbers are formatted using a space as the thousands separator and a comma as the decimal separator", Locale.FRANCE),
Germany("Germany", "Numbers are formatted using a dot as the thousands separator and a comma as the decimal separator", Locale.GERMANY),
Italy("Italy", "Numbers are formatted using a comma as the thousands separator and a comma as the decimal separator", Locale.ITALY),
Japan("Japan", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.JAPAN),
Korea("Korea", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.KOREA),
UK("United Kingdom", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.UK),
US("United States", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.US),
Canada("Canada", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.CANADA),
Quebec("Québec", "Numbers are formatted using a space as the thousands separator and a comma as the decimal separator", Locale.CANADA_FRENCH); // this the best one :3
}

enum class Time(
override val displayName: String,
override val description: String,
val format: DateTimeFormatter,
) : NamedEnum, Describable {
IsoLocalDate("ISO-8601 Extended", "The ISO date formatter that formats or parses a date without an offset, such as '2011-12-03'", DateTimeFormatter.ISO_LOCAL_DATE),
IsoOffsetDate("ISO-8601 Offset", "The ISO date formatter that formats or parses a date with an offset, such as '2011-12-03+01:00'", DateTimeFormatter.ISO_OFFSET_DATE),
IsoDate("ISO-8601 Date", "The ISO date formatter that formats or parses a date with the offset if available, such as '2011-12-03' or '2011-12-03+01:00'", DateTimeFormatter.ISO_DATE),
IsoLocalTime("ISO-8601 Local Time", "The ISO time formatter that formats or parses a time without an offset, such as '10:15' or '10:15:30'", DateTimeFormatter.ISO_LOCAL_TIME),
IsoOffsetTime("ISO-8601 Offset Time", "The ISO time formatter that formats or parses a time with an offset, such as '10:15+01:00' or '10:15:30+01:00'", DateTimeFormatter.ISO_OFFSET_TIME),
IsoTime("ISO-8601 Time", "The ISO time formatter that formats or parses a time, with the offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'", DateTimeFormatter.ISO_TIME),
IsoLocalDateTime("ISO-8601 Local Date Time", "The ISO date-time formatter that formats or parses a date-time without an offset, such as '2011-12-03T10:15:30'", DateTimeFormatter.ISO_LOCAL_DATE_TIME),
IsoOffsetDateTime("ISO-8601 Offset Date Time", "The ISO date-time formatter that formats or parses a date-time with an offset, such as '2011-12-03T10:15:30+01:00'", DateTimeFormatter.ISO_OFFSET_DATE_TIME),
IsoZonedDateTime("ISO-8601 Zoned Date Time", "The ISO-like date-time formatter that formats or parses a date-time with offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'", DateTimeFormatter.ISO_ZONED_DATE_TIME),
IsoDateTime("ISO-8601 Date Time", "The ISO-like date-time formatter that formats or parses a date-time with the offset and zone if available, such as '2011-12-03T10:15:30', '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'", DateTimeFormatter.ISO_DATE_TIME),
IsoOrdinalDate("ISO-8601 Ordinal Date", "The ISO date formatter that formats or parses the ordinal date without an offset, such as '2012-337'", DateTimeFormatter.ISO_ORDINAL_DATE),
IsoWeekDate("ISO-8601 Week Date", "The ISO date formatter that formats or parses the week-based date without an offset, such as '2012-W48-6'", DateTimeFormatter.ISO_WEEK_DATE),
IsoInstant("ISO-8601 Instant", "The ISO instant formatter that formats or parses an instant in UTC, such as '2011-12-03T10:15:30Z'", DateTimeFormatter.ISO_INSTANT),
BasicIsoDate("ISO 8601", "The ISO date formatter that formats or parses a date without an offset, such as '20111203'", DateTimeFormatter.BASIC_ISO_DATE),
Rfc1123("RFC 1123", "The RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'", DateTimeFormatter.RFC_1123_DATE_TIME);
}

// For context, a tuple is an ordered list of identical value types such as a vec3d which is a tuple of doubles
enum class TupleSeparator(
override val displayName: String,
val separator: String,
) : NamedEnum {
Comma("Comma", ", "),
Dot("Dot", ". "),
Semicolon("Semicolon", "; "),
VerticalBar("Vertical Bar", "| "),
Space("Space", " "),
Custom("Custom", ":3c");
}

enum class TupleGrouping(
override val displayName: String,
val prefix: String,
val postfix: String,
) : NamedEnum {
Parentheses("Parenthesis", "(", ")"),
SquareBrackets("Square Brackets", "[", "]"),
CurlyBrackets("Curly Brackets", "{", "}"),
VerticalBar("Vertical Bar", "|", "|");
}
}
53 changes: 53 additions & 0 deletions src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2025 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 <http://www.gnu.org/licenses/>.
*/

package com.lambda.config.groups

import com.lambda.config.Configurable
import com.lambda.util.NamedEnum
import com.lambda.util.math.Vec2d
import net.minecraft.util.math.Vec2f
import net.minecraft.util.math.Vec3d
import net.minecraft.util.math.Vec3i
import org.joml.Vector3f
import org.joml.Vector4f
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime

class FormatterSettings(
owner: Configurable,
vararg baseGroup: NamedEnum,
vis: () -> Boolean = { true }
) : FormatterConfig, SettingGroup(owner) {
val localeEnum by owner.setting("Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers", vis).group(*baseGroup)
override val locale get() = localeEnum.locale

val sep by owner.setting("Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures", vis).group(*baseGroup)
val customSep by owner.setting("Custom Separator", "") { vis() && sep == FormatterConfig.TupleSeparator.Custom }.group(*baseGroup)
override val separator get() = if (sep == FormatterConfig.TupleSeparator.Custom) customSep else sep.separator

val group by owner.setting("Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses) { vis() }.group(*baseGroup)
override val prefix get() = group.prefix
override val postfix get() = group.postfix

val floatingPrecision by owner.setting("Floating Precision", 3, 0..6, 1, "Precision for floating point numbers") { vis() }.group(*baseGroup)
override val precision get() = floatingPrecision

val timeFormat by owner.setting("Time Format", FormatterConfig.Time.IsoDateTime) { vis() }.group(*baseGroup)
override val format get() = timeFormat.format
}
40 changes: 29 additions & 11 deletions src/main/kotlin/com/lambda/module/hud/Coordinates.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@

package com.lambda.module.hud

import com.lambda.config.groups.FormatterConfig
import com.lambda.config.groups.FormatterSettings
import com.lambda.gui.dsl.ImGuiBuilder
import com.lambda.module.HudModule
import com.lambda.module.tag.ModuleTag
import com.lambda.threading.runSafe
import com.lambda.util.Formatting.asString
import com.lambda.util.Formatting.string
import com.lambda.util.Formatting.format
import com.lambda.util.NamedEnum
import com.lambda.util.extension.dimensionName
import com.lambda.util.extension.isNether
import com.lambda.util.math.Vec2d
import com.lambda.util.math.netherCoord
import com.lambda.util.math.overworldCoord

Expand All @@ -33,19 +36,34 @@ object Coordinates : HudModule(
description = "Show your coordinates",
tag = ModuleTag.HUD,
) {
private val page by setting("Page", Page.CurrentDimension)
private val showDimension by setting("Show Dimension", true)
private val decimals by setting("Decimals", 2, 0..4, 1)

private val formatter = FormatterSettings(this, Page.CurrentDimension).apply { ::timeFormat.edit { hide() } }
private val otherFormatter = FormatterSettings(this, Page.OtherDimension).apply {
::timeFormat.edit { hide() }
::group.edit { defaultValue(FormatterConfig.TupleGrouping.SquareBrackets) }
}

override fun ImGuiBuilder.buildLayout() {
runSafe {
val pos = player.pos.asString(decimals)
val coord = if (world.isNether) {
"$pos [${player.overworldCoord.x.string}, ${player.overworldCoord.z.string}]"
} else {
"$pos [${player.netherCoord.x.string}, ${player.netherCoord.z.string}]"
}
val dimension = if (showDimension) " ${world.dimensionName}" else ""
textCopyable("$coord$dimension")
val position = player.pos.format(formatter)
val otherDimensionPos =
if (world.isNether) player.overworldCoord.let { Vec2d(it.x, it.z) }.format(otherFormatter)
else player.netherCoord.let { Vec2d(it.x, it.z) }.format(otherFormatter)

val text = "$position $otherDimensionPos"

val withDimension =
if (showDimension) "$text ${world.dimensionName}"
else text

textCopyable(withDimension)
}
}

enum class Page(override val displayName: String) : NamedEnum {
CurrentDimension("Current Dimension"),
OtherDimension("Other Dimension"),
}
}
6 changes: 3 additions & 3 deletions src/main/kotlin/com/lambda/module/hud/Tps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package com.lambda.module.hud
import com.lambda.gui.dsl.ImGuiBuilder
import com.lambda.module.HudModule
import com.lambda.module.tag.ModuleTag
import com.lambda.util.Formatting.string
import com.lambda.util.Formatting.format
import com.lambda.util.ServerTPS
import com.lambda.util.ServerTPS.recentData
import imgui.ImVec2
Expand All @@ -45,10 +45,10 @@ object Tps : HudModule(
val current = data.last()
val avg = data.average().toFloat()
if (!showGraph) {
text("${format.displayName}: ${avg.string}${format.unit}")
text("${format.displayName}: ${avg.format()}${format.unit}")
return
}
val overlay = "cur ${current.string}${format.unit} | avg ${avg.string}${format.unit}"
val overlay = "cur ${current.format()}${format.unit} | avg ${avg.format()}${format.unit}"

plotLines(
label = "##TPSPlot",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import com.lambda.module.tag.ModuleTag
import com.lambda.sound.SoundManager.playSound
import com.lambda.util.Communication
import com.lambda.util.Communication.prefix
import com.lambda.util.Formatting.string
import com.lambda.util.Formatting.format
import com.lambda.util.combat.CombatUtils.hasDeadlyCrystal
import com.lambda.util.combat.DamageUtils.isFallDeadly
import com.lambda.util.extension.fullHealth
Expand Down Expand Up @@ -125,7 +125,7 @@ object AutoDisconnect : Module(
private fun SafeContext.damageDisconnect(source: DamageSource, amount: Float) {
buildText {
literal("Got ")
highlighted(amount.string)
highlighted(amount.format())
literal(" damage of type ")
highlighted(source.name)
source.attacker?.let {
Expand All @@ -140,7 +140,7 @@ object AutoDisconnect : Module(
}
source.position?.let {
literal(" at position ")
highlighted(it.string)
highlighted(it.format())
}
literal(".")
}.let {
Expand All @@ -160,11 +160,11 @@ object AutoDisconnect : Module(
text(text)
literal("\n\n")
literal("Disconnected at ")
highlighted(player.pos.string)
highlighted(player.pos.format())
literal(" on ")
highlighted(Communication.currentTime())
literal(" with ")
highlighted(player.fullHealth.string)
highlighted(player.fullHealth.format())
literal(" health.")
if (player.isSubmergedInWater) {
literal("\n")
Expand Down Expand Up @@ -197,7 +197,7 @@ object AutoDisconnect : Module(
if (player.fullHealth < minimumHealth) {
buildText {
literal("Health ")
highlighted(player.fullHealth.string)
highlighted(player.fullHealth.format())
literal(" below minimum of ")
highlighted("$minimumHealth")
literal("!")
Expand All @@ -223,7 +223,7 @@ object AutoDisconnect : Module(
}?.let { creeper ->
buildText {
literal("An ignited creeper was ")
highlighted(creeper.pos.distanceTo(player.pos).string)
highlighted(creeper.pos.distanceTo(player.pos).format())
literal(" blocks away!")
}
}
Expand All @@ -238,7 +238,7 @@ object AutoDisconnect : Module(
literal("The player ")
text(otherPlayer.name)
literal(" was ")
highlighted("${otherPlayer.distanceTo(player).string} blocks away")
highlighted("${otherPlayer.distanceTo(player).format()} blocks away")
literal("!")
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/main/kotlin/com/lambda/module/modules/player/Replay.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import com.lambda.util.Communication.logError
import com.lambda.util.Communication.warn
import com.lambda.util.FileUtils.locationBoundDirectory
import com.lambda.util.FolderRegister
import com.lambda.util.Formatting.asString
import com.lambda.util.Formatting.format
import com.lambda.util.Formatting.getTime
import com.lambda.util.KeyCode
import com.lambda.util.StringUtils.sanitizeForFilename
Expand Down Expand Up @@ -162,7 +162,7 @@ object Replay : Module(
this@Replay.warn(
"Position deviates from the recording by ${
"%.3f".format(diff)
} blocks. Desired position: ${pos.asString(3)}"
} blocks. Desired position: ${pos.format()}"
)
if (cancelOnDeviation && diff > deviationThreshold) {
state = State.Inactive
Expand Down Expand Up @@ -210,7 +210,7 @@ object Replay : Module(
literal(" of ")
color(ClickGuiLayout.primaryColor) { literal(saving.duration.toString()) }
literal(" at ")
color(ClickGuiLayout.primaryColor) { literal(saving.endPos.asString(1)) }
color(ClickGuiLayout.primaryColor) { literal(saving.endPos.format(precision = 1)) }
playMessage(saving)
saveMessage(saving)
pruneMessage(saving)
Expand Down Expand Up @@ -398,7 +398,7 @@ object Replay : Module(
literal("Checkpoint #")
color(ClickGuiLayout.primaryColor) { literal("${recordings.indexOf(checkRec)}") }
literal(" created at ")
color(ClickGuiLayout.primaryColor) { literal(checkRec.endPos.asString(0)) }
color(ClickGuiLayout.primaryColor) { literal(checkRec.endPos.format(precision = 0)) }
literal(".")
playMessage(checkRec)
saveMessage(checkRec)
Expand Down Expand Up @@ -581,8 +581,8 @@ object Replay : Module(
)

override fun toString() = "Recording from ${
startPos.asString(1)
} to ${endPos.asString(1)} (in ${duration})"
startPos.format(precision = 0)
} to ${endPos.format(precision = 0)} (in ${duration})"

override fun serialize(
src: Recording?,
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/lambda/task/tasks/BuildTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import com.lambda.interaction.request.placing.PlaceRequest
import com.lambda.task.Task
import com.lambda.task.tasks.EatTask.Companion.eat
import com.lambda.threading.runSafeAutomated
import com.lambda.util.Formatting.string
import com.lambda.util.Formatting.format
import com.lambda.util.extension.Structure
import com.lambda.util.extension.inventorySlots
import com.lambda.util.item.ItemUtils.block
Expand All @@ -70,7 +70,7 @@ class BuildTask private constructor(
private val lifeMaintenance: Boolean,
automated: Automated
) : Task<Structure>(), Automated by automated {
override val name: String get() = "Building $blueprint with ${(breaks / (age / 20.0 + 0.001)).string} b/s ${(placements / (age / 20.0 + 0.001)).string} p/s"
override val name: String get() = "Building $blueprint with ${(breaks / (age / 20.0 + 0.001)).format(precision = 1)} b/s ${(placements / (age / 20.0 + 0.001)).format(precision = 1)} p/s"

private val pendingInteractions = ConcurrentLinkedQueue<BuildContext>()
private val atMaxPendingInteractions
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/lambda/util/DebugInfoHud.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import com.lambda.Lambda.mc
import com.lambda.command.CommandRegistry
import com.lambda.event.EventFlow
import com.lambda.module.ModuleRegistry
import com.lambda.util.Formatting.asString
import com.lambda.util.Formatting.format
import com.lambda.util.extension.tickDelta
import net.minecraft.util.Formatting
import net.minecraft.util.hit.BlockHitResult
Expand Down Expand Up @@ -55,7 +55,7 @@ object DebugInfoHud {
null -> add("Crosshair Target: None")
}

add("Eye Pos: ${mc.cameraEntity?.getCameraPosVec(mc.tickDelta.toFloat())?.asString(3)}")
add("Eye Pos: ${mc.cameraEntity?.getCameraPosVec(mc.tickDelta)?.format()}")

return
}
Expand Down
Loading
Loading