diff --git a/src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt b/src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt
new file mode 100644
index 000000000..c9d824e08
--- /dev/null
+++ b/src/main/kotlin/com/lambda/config/groups/FormatterConfig.kt
@@ -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 .
+ */
+
+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", "|", "|");
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt b/src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt
new file mode 100644
index 000000000..3967f7f0a
--- /dev/null
+++ b/src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt
@@ -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 .
+ */
+
+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
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/lambda/module/hud/Coordinates.kt b/src/main/kotlin/com/lambda/module/hud/Coordinates.kt
index a20020500..5727d1413 100644
--- a/src/main/kotlin/com/lambda/module/hud/Coordinates.kt
+++ b/src/main/kotlin/com/lambda/module/hud/Coordinates.kt
@@ -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
@@ -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"),
+ }
}
diff --git a/src/main/kotlin/com/lambda/module/hud/Tps.kt b/src/main/kotlin/com/lambda/module/hud/Tps.kt
index fb4a3f075..b490e26b4 100644
--- a/src/main/kotlin/com/lambda/module/hud/Tps.kt
+++ b/src/main/kotlin/com/lambda/module/hud/Tps.kt
@@ -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
@@ -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",
diff --git a/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt b/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt
index bdb6426ec..eb46ab4c6 100644
--- a/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt
+++ b/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt
@@ -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
@@ -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 {
@@ -140,7 +140,7 @@ object AutoDisconnect : Module(
}
source.position?.let {
literal(" at position ")
- highlighted(it.string)
+ highlighted(it.format())
}
literal(".")
}.let {
@@ -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")
@@ -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("!")
@@ -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!")
}
}
@@ -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("!")
}
}
diff --git a/src/main/kotlin/com/lambda/module/modules/player/Replay.kt b/src/main/kotlin/com/lambda/module/modules/player/Replay.kt
index 97b3897ad..c65e0f069 100644
--- a/src/main/kotlin/com/lambda/module/modules/player/Replay.kt
+++ b/src/main/kotlin/com/lambda/module/modules/player/Replay.kt
@@ -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
@@ -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
@@ -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)
@@ -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)
@@ -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?,
diff --git a/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt b/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt
index 11c66b24a..d80a16761 100644
--- a/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt
+++ b/src/main/kotlin/com/lambda/task/tasks/BuildTask.kt
@@ -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
@@ -70,7 +70,7 @@ class BuildTask private constructor(
private val lifeMaintenance: Boolean,
automated: Automated
) : Task(), 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()
private val atMaxPendingInteractions
diff --git a/src/main/kotlin/com/lambda/util/DebugInfoHud.kt b/src/main/kotlin/com/lambda/util/DebugInfoHud.kt
index 0723f1413..198eb0a1d 100644
--- a/src/main/kotlin/com/lambda/util/DebugInfoHud.kt
+++ b/src/main/kotlin/com/lambda/util/DebugInfoHud.kt
@@ -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
@@ -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
}
diff --git a/src/main/kotlin/com/lambda/util/Formatting.kt b/src/main/kotlin/com/lambda/util/Formatting.kt
index 134d93fdd..2aec6f476 100644
--- a/src/main/kotlin/com/lambda/util/Formatting.kt
+++ b/src/main/kotlin/com/lambda/util/Formatting.kt
@@ -17,8 +17,12 @@
package com.lambda.util
-import net.minecraft.util.math.BlockPos
+import com.lambda.config.groups.FormatterConfig
+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 java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
@@ -26,27 +30,104 @@ import java.time.format.DateTimeFormatter
import java.util.*
object Formatting {
- val Vec3d.string: String
- get() = asString()
+ fun Short.format(formatter: FormatterConfig) = format(formatter.locale)
+ fun Short.format(locale: Locale = Default.locale) = "%d".format(locale, this)
- val Float.string: String
- get() = "%.2f".format(Locale.US, this)
+ fun Int.format(formatter: FormatterConfig) = format(formatter.locale)
+ fun Int.format(locale: Locale = Default.locale) = "%d".format(locale, this)
- val Double.string: String
- get() = "%.2f".format(Locale.US, this)
+ fun Long.format(formatter: FormatterConfig) = format(formatter.locale)
+ fun Long.format(locale: Locale = Default.locale) = "%d".format(locale, this)
- fun Vec3d.asString(decimals: Int = 2): String {
- val format = "%.${decimals}f"
- return "(${format.format(Locale.US, x)}, ${format.format(Locale.US, y)}, ${format.format(Locale.US, z)})"
- }
+ fun Float.format(formatter: FormatterConfig) = format(formatter.locale, formatter.precision)
+ fun Float.format(locale: Locale = Default.locale, precision: Int = Default.precision) = "%,.${precision}f".format(locale, this)
+
+ fun Double.format(formatter: FormatterConfig) = format(formatter.locale, formatter.precision)
+ fun Double.format(locale: Locale = Default.locale, precision: Int = Default.precision) = "%,.${precision}f".format(locale, this)
+
+ fun Vec2f.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ fun Vec2f.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ "$prefix${x.format(locale, precision)}$separator${y.format(locale, precision)}$postfix"
+
+ fun Vec2d.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ fun Vec2d.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ "$prefix${x.format(locale, precision)}$separator${y.format(locale, precision)}$postfix"
+
+ fun Vec3i.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix)
+ fun Vec3i.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix) =
+ "$prefix${x.format(locale)}$separator${y.format(locale)}$separator${z.format(locale)}$postfix"
+
+ fun Vec3d.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ fun Vec3d.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ "$prefix${x.format(locale, precision)}$separator${y.format(locale, precision)}$separator${z.format(locale, precision)}$postfix"
+
+ fun ShortArray.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix)
+ fun ShortArray.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix) =
+ joinToString(separator, prefix, postfix) { it.format(locale) }
+
+ fun IntArray.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix)
+ fun IntArray.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix) =
+ joinToString(separator, prefix, postfix) { it.format(locale) }
+
+ fun LongArray.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix)
+ fun LongArray.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix) =
+ joinToString(separator, prefix, postfix) { it.format(locale) }
+
+ fun FloatArray.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ fun FloatArray.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ joinToString(separator, prefix, postfix) { it.format(locale, precision) }
- fun BlockPos.asString() = "($x, $y, $z)"
+ fun DoubleArray.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ fun DoubleArray.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ joinToString(separator, prefix, postfix) { it.format(locale, precision) }
- fun getTime(formatter: DateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME): String {
+ @JvmName("formatVec2fiList1")
+ fun Iterable.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ @JvmName("formatVec2fList2")
+ fun Iterable.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ joinToString(separator, prefix, postfix) { it.format(locale, separator, prefix, postfix, precision) }
+
+ @JvmName("formatVec2dList1")
+ fun Iterable.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ @JvmName("formatVec2dList2")
+ fun Iterable.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ joinToString(separator, prefix, postfix) { it.format(locale, separator, prefix, postfix, precision) }
+
+ @JvmName("formatVec3iList1")
+ fun Iterable.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix)
+ @JvmName("formatVec3iList2")
+ fun Iterable.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix) =
+ joinToString(separator, prefix, postfix) { it.format(locale, separator, prefix, postfix) }
+
+ @JvmName("formatVec3dList1")
+ fun Iterable.format(formatter: FormatterConfig) = format(formatter.locale, formatter.separator, formatter.prefix, formatter.postfix, formatter.precision)
+ @JvmName("formatVec3dList2")
+ fun Iterable.format(locale: Locale = Default.locale, separator: String = Default.separator, prefix: String = Default.prefix, postfix: String = Default.postfix, precision: Int = Default.precision) =
+ joinToString(separator, prefix, postfix) { it.format(locale, separator, prefix, postfix, precision) }
+
+ fun LocalDate.format(formatter: FormatterConfig): String = format(formatter.format)
+ fun LocalDate.format(format: DateTimeFormatter = Default.format): String = format(format)
+
+ fun LocalDateTime.format(formatter: FormatterConfig): String = format(formatter.format)
+ fun LocalDateTime.format(format: DateTimeFormatter = Default.format): String = format(format)
+
+ fun ZonedDateTime.format(formatter: FormatterConfig): String = format(formatter.format)
+ fun ZonedDateTime.format(format: DateTimeFormatter = Default.format): String = format(format)
+
+ fun getTime(formatter: DateTimeFormatter = Default.format): String {
val localDateTime = LocalDateTime.now()
val zoneId = ZoneId.systemDefault()
val zonedDateTime = ZonedDateTime.of(localDateTime, zoneId)
return zonedDateTime.format(formatter)
}
+
+ object Default : FormatterConfig {
+ override val locale: Locale = Locale.US
+ override val separator: String = ","
+ override val prefix: String = "("
+ override val postfix: String = ")"
+ override val precision: Int = 3
+ override val format: DateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME
+ }
}