Skip to content

Commit 70f95ac

Browse files
IceTankemyfops
andauthored
Fix coordinate hud element in the most scuffed way possible (#165)
pls merge --------- Co-authored-by: Emy 💜 <swag@emy.systems>
1 parent 8faf2d9 commit 70f95ac

File tree

9 files changed

+291
-45
lines changed

9 files changed

+291
-45
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.config.groups
19+
20+
import com.lambda.util.Describable
21+
import com.lambda.util.NamedEnum
22+
import java.time.format.DateTimeFormatter
23+
import java.util.Locale
24+
25+
interface FormatterConfig {
26+
val locale: Locale
27+
val separator: String
28+
val prefix: String
29+
val postfix: String
30+
val precision: Int
31+
val format: DateTimeFormatter
32+
33+
enum class Locales(
34+
override val displayName: String,
35+
override val description: String,
36+
val locale: Locale,
37+
) : NamedEnum, Describable {
38+
France("France", "Numbers are formatted using a space as the thousands separator and a comma as the decimal separator", Locale.FRANCE),
39+
Germany("Germany", "Numbers are formatted using a dot as the thousands separator and a comma as the decimal separator", Locale.GERMANY),
40+
Italy("Italy", "Numbers are formatted using a comma as the thousands separator and a comma as the decimal separator", Locale.ITALY),
41+
Japan("Japan", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.JAPAN),
42+
Korea("Korea", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.KOREA),
43+
UK("United Kingdom", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.UK),
44+
US("United States", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.US),
45+
Canada("Canada", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.CANADA),
46+
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
47+
}
48+
49+
enum class Time(
50+
override val displayName: String,
51+
override val description: String,
52+
val format: DateTimeFormatter,
53+
) : NamedEnum, Describable {
54+
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),
55+
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),
56+
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),
57+
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),
58+
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),
59+
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),
60+
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),
61+
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),
62+
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),
63+
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),
64+
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),
65+
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),
66+
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),
67+
BasicIsoDate("ISO 8601", "The ISO date formatter that formats or parses a date without an offset, such as '20111203'", DateTimeFormatter.BASIC_ISO_DATE),
68+
Rfc1123("RFC 1123", "The RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'", DateTimeFormatter.RFC_1123_DATE_TIME);
69+
}
70+
71+
// For context, a tuple is an ordered list of identical value types such as a vec3d which is a tuple of doubles
72+
enum class TupleSeparator(
73+
override val displayName: String,
74+
val separator: String,
75+
) : NamedEnum {
76+
Comma("Comma", ", "),
77+
Dot("Dot", ". "),
78+
Semicolon("Semicolon", "; "),
79+
VerticalBar("Vertical Bar", "| "),
80+
Space("Space", " "),
81+
Custom("Custom", ":3c");
82+
}
83+
84+
enum class TupleGrouping(
85+
override val displayName: String,
86+
val prefix: String,
87+
val postfix: String,
88+
) : NamedEnum {
89+
Parentheses("Parenthesis", "(", ")"),
90+
SquareBrackets("Square Brackets", "[", "]"),
91+
CurlyBrackets("Curly Brackets", "{", "}"),
92+
VerticalBar("Vertical Bar", "|", "|");
93+
}
94+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.config.groups
19+
20+
import com.lambda.config.Configurable
21+
import com.lambda.util.NamedEnum
22+
import com.lambda.util.math.Vec2d
23+
import net.minecraft.util.math.Vec2f
24+
import net.minecraft.util.math.Vec3d
25+
import net.minecraft.util.math.Vec3i
26+
import org.joml.Vector3f
27+
import org.joml.Vector4f
28+
import java.time.LocalDate
29+
import java.time.LocalDateTime
30+
import java.time.ZonedDateTime
31+
32+
class FormatterSettings(
33+
owner: Configurable,
34+
vararg baseGroup: NamedEnum,
35+
vis: () -> Boolean = { true }
36+
) : FormatterConfig, SettingGroup(owner) {
37+
val localeEnum by owner.setting("Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers", vis).group(*baseGroup)
38+
override val locale get() = localeEnum.locale
39+
40+
val sep by owner.setting("Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures", vis).group(*baseGroup)
41+
val customSep by owner.setting("Custom Separator", "") { vis() && sep == FormatterConfig.TupleSeparator.Custom }.group(*baseGroup)
42+
override val separator get() = if (sep == FormatterConfig.TupleSeparator.Custom) customSep else sep.separator
43+
44+
val group by owner.setting("Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses) { vis() }.group(*baseGroup)
45+
override val prefix get() = group.prefix
46+
override val postfix get() = group.postfix
47+
48+
val floatingPrecision by owner.setting("Floating Precision", 3, 0..6, 1, "Precision for floating point numbers") { vis() }.group(*baseGroup)
49+
override val precision get() = floatingPrecision
50+
51+
val timeFormat by owner.setting("Time Format", FormatterConfig.Time.IsoDateTime) { vis() }.group(*baseGroup)
52+
override val format get() = timeFormat.format
53+
}

src/main/kotlin/com/lambda/module/hud/Coordinates.kt

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@
1717

1818
package com.lambda.module.hud
1919

20+
import com.lambda.config.groups.FormatterConfig
21+
import com.lambda.config.groups.FormatterSettings
2022
import com.lambda.gui.dsl.ImGuiBuilder
2123
import com.lambda.module.HudModule
2224
import com.lambda.module.tag.ModuleTag
2325
import com.lambda.threading.runSafe
24-
import com.lambda.util.Formatting.asString
25-
import com.lambda.util.Formatting.string
26+
import com.lambda.util.Formatting.format
27+
import com.lambda.util.NamedEnum
2628
import com.lambda.util.extension.dimensionName
2729
import com.lambda.util.extension.isNether
30+
import com.lambda.util.math.Vec2d
2831
import com.lambda.util.math.netherCoord
2932
import com.lambda.util.math.overworldCoord
3033

@@ -33,19 +36,34 @@ object Coordinates : HudModule(
3336
description = "Show your coordinates",
3437
tag = ModuleTag.HUD,
3538
) {
39+
private val page by setting("Page", Page.CurrentDimension)
3640
private val showDimension by setting("Show Dimension", true)
37-
private val decimals by setting("Decimals", 2, 0..4, 1)
41+
42+
private val formatter = FormatterSettings(this, Page.CurrentDimension).apply { ::timeFormat.edit { hide() } }
43+
private val otherFormatter = FormatterSettings(this, Page.OtherDimension).apply {
44+
::timeFormat.edit { hide() }
45+
::group.edit { defaultValue(FormatterConfig.TupleGrouping.SquareBrackets) }
46+
}
3847

3948
override fun ImGuiBuilder.buildLayout() {
4049
runSafe {
41-
val pos = player.pos.asString(decimals)
42-
val coord = if (world.isNether) {
43-
"$pos [${player.overworldCoord.x.string}, ${player.overworldCoord.z.string}]"
44-
} else {
45-
"$pos [${player.netherCoord.x.string}, ${player.netherCoord.z.string}]"
46-
}
47-
val dimension = if (showDimension) " ${world.dimensionName}" else ""
48-
textCopyable("$coord$dimension")
50+
val position = player.pos.format(formatter)
51+
val otherDimensionPos =
52+
if (world.isNether) player.overworldCoord.let { Vec2d(it.x, it.z) }.format(otherFormatter)
53+
else player.netherCoord.let { Vec2d(it.x, it.z) }.format(otherFormatter)
54+
55+
val text = "$position $otherDimensionPos"
56+
57+
val withDimension =
58+
if (showDimension) "$text ${world.dimensionName}"
59+
else text
60+
61+
textCopyable(withDimension)
4962
}
5063
}
64+
65+
enum class Page(override val displayName: String) : NamedEnum {
66+
CurrentDimension("Current Dimension"),
67+
OtherDimension("Other Dimension"),
68+
}
5169
}

src/main/kotlin/com/lambda/module/hud/Tps.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package com.lambda.module.hud
2020
import com.lambda.gui.dsl.ImGuiBuilder
2121
import com.lambda.module.HudModule
2222
import com.lambda.module.tag.ModuleTag
23-
import com.lambda.util.Formatting.string
23+
import com.lambda.util.Formatting.format
2424
import com.lambda.util.ServerTPS
2525
import com.lambda.util.ServerTPS.recentData
2626
import imgui.ImVec2
@@ -45,10 +45,10 @@ object Tps : HudModule(
4545
val current = data.last()
4646
val avg = data.average().toFloat()
4747
if (!showGraph) {
48-
text("${format.displayName}: ${avg.string}${format.unit}")
48+
text("${format.displayName}: ${avg.format()}${format.unit}")
4949
return
5050
}
51-
val overlay = "cur ${current.string}${format.unit} | avg ${avg.string}${format.unit}"
51+
val overlay = "cur ${current.format()}${format.unit} | avg ${avg.format()}${format.unit}"
5252

5353
plotLines(
5454
label = "##TPSPlot",

src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.lambda.module.tag.ModuleTag
2727
import com.lambda.sound.SoundManager.playSound
2828
import com.lambda.util.Communication
2929
import com.lambda.util.Communication.prefix
30-
import com.lambda.util.Formatting.string
30+
import com.lambda.util.Formatting.format
3131
import com.lambda.util.combat.CombatUtils.hasDeadlyCrystal
3232
import com.lambda.util.combat.DamageUtils.isFallDeadly
3333
import com.lambda.util.extension.fullHealth
@@ -125,7 +125,7 @@ object AutoDisconnect : Module(
125125
private fun SafeContext.damageDisconnect(source: DamageSource, amount: Float) {
126126
buildText {
127127
literal("Got ")
128-
highlighted(amount.string)
128+
highlighted(amount.format())
129129
literal(" damage of type ")
130130
highlighted(source.name)
131131
source.attacker?.let {
@@ -140,7 +140,7 @@ object AutoDisconnect : Module(
140140
}
141141
source.position?.let {
142142
literal(" at position ")
143-
highlighted(it.string)
143+
highlighted(it.format())
144144
}
145145
literal(".")
146146
}.let {
@@ -160,11 +160,11 @@ object AutoDisconnect : Module(
160160
text(text)
161161
literal("\n\n")
162162
literal("Disconnected at ")
163-
highlighted(player.pos.string)
163+
highlighted(player.pos.format())
164164
literal(" on ")
165165
highlighted(Communication.currentTime())
166166
literal(" with ")
167-
highlighted(player.fullHealth.string)
167+
highlighted(player.fullHealth.format())
168168
literal(" health.")
169169
if (player.isSubmergedInWater) {
170170
literal("\n")
@@ -197,7 +197,7 @@ object AutoDisconnect : Module(
197197
if (player.fullHealth < minimumHealth) {
198198
buildText {
199199
literal("Health ")
200-
highlighted(player.fullHealth.string)
200+
highlighted(player.fullHealth.format())
201201
literal(" below minimum of ")
202202
highlighted("$minimumHealth")
203203
literal("!")
@@ -223,7 +223,7 @@ object AutoDisconnect : Module(
223223
}?.let { creeper ->
224224
buildText {
225225
literal("An ignited creeper was ")
226-
highlighted(creeper.pos.distanceTo(player.pos).string)
226+
highlighted(creeper.pos.distanceTo(player.pos).format())
227227
literal(" blocks away!")
228228
}
229229
}
@@ -238,7 +238,7 @@ object AutoDisconnect : Module(
238238
literal("The player ")
239239
text(otherPlayer.name)
240240
literal(" was ")
241-
highlighted("${otherPlayer.distanceTo(player).string} blocks away")
241+
highlighted("${otherPlayer.distanceTo(player).format()} blocks away")
242242
literal("!")
243243
}
244244
}

src/main/kotlin/com/lambda/module/modules/player/Replay.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import com.lambda.util.Communication.logError
4747
import com.lambda.util.Communication.warn
4848
import com.lambda.util.FileUtils.locationBoundDirectory
4949
import com.lambda.util.FolderRegister
50-
import com.lambda.util.Formatting.asString
50+
import com.lambda.util.Formatting.format
5151
import com.lambda.util.Formatting.getTime
5252
import com.lambda.util.KeyCode
5353
import com.lambda.util.StringUtils.sanitizeForFilename
@@ -162,7 +162,7 @@ object Replay : Module(
162162
this@Replay.warn(
163163
"Position deviates from the recording by ${
164164
"%.3f".format(diff)
165-
} blocks. Desired position: ${pos.asString(3)}"
165+
} blocks. Desired position: ${pos.format()}"
166166
)
167167
if (cancelOnDeviation && diff > deviationThreshold) {
168168
state = State.Inactive
@@ -210,7 +210,7 @@ object Replay : Module(
210210
literal(" of ")
211211
color(ClickGuiLayout.primaryColor) { literal(saving.duration.toString()) }
212212
literal(" at ")
213-
color(ClickGuiLayout.primaryColor) { literal(saving.endPos.asString(1)) }
213+
color(ClickGuiLayout.primaryColor) { literal(saving.endPos.format(precision = 1)) }
214214
playMessage(saving)
215215
saveMessage(saving)
216216
pruneMessage(saving)
@@ -398,7 +398,7 @@ object Replay : Module(
398398
literal("Checkpoint #")
399399
color(ClickGuiLayout.primaryColor) { literal("${recordings.indexOf(checkRec)}") }
400400
literal(" created at ")
401-
color(ClickGuiLayout.primaryColor) { literal(checkRec.endPos.asString(0)) }
401+
color(ClickGuiLayout.primaryColor) { literal(checkRec.endPos.format(precision = 0)) }
402402
literal(".")
403403
playMessage(checkRec)
404404
saveMessage(checkRec)
@@ -581,8 +581,8 @@ object Replay : Module(
581581
)
582582

583583
override fun toString() = "Recording from ${
584-
startPos.asString(1)
585-
} to ${endPos.asString(1)} (in ${duration})"
584+
startPos.format(precision = 0)
585+
} to ${endPos.format(precision = 0)} (in ${duration})"
586586

587587
override fun serialize(
588588
src: Recording?,

src/main/kotlin/com/lambda/task/tasks/BuildTask.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import com.lambda.interaction.request.placing.PlaceRequest
5454
import com.lambda.task.Task
5555
import com.lambda.task.tasks.EatTask.Companion.eat
5656
import com.lambda.threading.runSafeAutomated
57-
import com.lambda.util.Formatting.string
57+
import com.lambda.util.Formatting.format
5858
import com.lambda.util.extension.Structure
5959
import com.lambda.util.extension.inventorySlots
6060
import com.lambda.util.item.ItemUtils.block
@@ -70,7 +70,7 @@ class BuildTask private constructor(
7070
private val lifeMaintenance: Boolean,
7171
automated: Automated
7272
) : Task<Structure>(), Automated by automated {
73-
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"
73+
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"
7474

7575
private val pendingInteractions = ConcurrentLinkedQueue<BuildContext>()
7676
private val atMaxPendingInteractions

src/main/kotlin/com/lambda/util/DebugInfoHud.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import com.lambda.Lambda.mc
2222
import com.lambda.command.CommandRegistry
2323
import com.lambda.event.EventFlow
2424
import com.lambda.module.ModuleRegistry
25-
import com.lambda.util.Formatting.asString
25+
import com.lambda.util.Formatting.format
2626
import com.lambda.util.extension.tickDelta
2727
import net.minecraft.util.Formatting
2828
import net.minecraft.util.hit.BlockHitResult
@@ -55,7 +55,7 @@ object DebugInfoHud {
5555
null -> add("Crosshair Target: None")
5656
}
5757

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

6060
return
6161
}

0 commit comments

Comments
 (0)