diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt new file mode 100644 index 000000000..a70ad48ac --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt @@ -0,0 +1,395 @@ +package ru.dbotthepony.mc.otm.core.util + +import net.minecraft.network.chat.Component +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.math.isNegative +import ru.dbotthepony.mc.otm.core.math.isZero +import java.math.BigDecimal +import java.math.BigInteger + +fun BigInteger.formatReadableNumber(): String { + if (isZero) { + return "0" + } + + val strValue = toString() + + val absLength = strValue.length - (if (isNegative) 1 else 0) + val remainder = absLength % 3 + var groups = absLength / 3 + + if (remainder == 0) { + groups-- + } + + val buffer = CharArray((if (remainder == 0) 3 else remainder) + groups * 4 + if (isNegative) 1 else 0) + var c = 0 + var index = buffer.size - 1 + + for (i in strValue.length - 1 downTo (if (isNegative) 1 else 0)) { + c++ + + if (c == 4) { + buffer[index] = ' ' + index-- + c = 1 + } + + buffer[index] = strValue[i] + index-- + } + + if (isNegative) { + buffer[index] = '-' + } + + return String(buffer) +} + +fun BigDecimal.determineSiPrefix(): SiPrefix? { + if (isZero) { + return null + } + + var num = this + + if (isNegative) { + num = -this + } + + var prev: SiPrefix? = null + + if (num >= BigDecimal.ONE) { + for (value in SiPrefix.MULTIPLIES) { + if (value.decimal <= num) { + prev = value + } else { + break + } + } + } else { + for (value in SiPrefix.DECIMALS) { + if (value.decimal >= num) { + prev = value + } else { + break + } + } + } + + return prev +} + +fun BigDecimal.formatSiTranslatable(): Component { + if (isZero) { + return TextComponent("0.00") + } else if (this == BigDecimal.ONE) { + return TextComponent("1.00") + } + + return TextComponent("1.00") +} + +fun BigInteger.determineSiPrefix(): SiPrefix? { + if (isZero) { + return null + } + + var num = this + + if (isNegative) { + num = -this + } + + var prev: SiPrefix? = null + + if (num >= BigInteger.ONE) { + for (value in SiPrefix.MULTIPLIES) { + if (value.integer!! <= num) { + prev = value + } else { + break + } + } + } + + return prev +} + +fun BigInteger.formatSi(decimalPlaces: Int = 2): String { + require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } + val prefix = determineSiPrefix() ?: return toString() // + "." + "0".repeat(decimalPlaces) + val isNegative = isNegative + val arr = (if (isNegative) -this else this).divideAndRemainder(prefix.integer) + val divided = arr[0].toString() + val remainder = arr[1].toString() + + if (decimalPlaces == 0) { + if (isNegative) { + return "-" + divided + prefix.symbol + } else { + return divided + prefix.symbol + } + } + + @Suppress("NAME_SHADOWING") + val decimalPlaces = decimalPlaces.coerceAtMost(prefix.power) + + val add = (if (isNegative) 1 else 0) + + val buffer = CharArray(divided.length + 2 + decimalPlaces + add) + buffer[buffer.size - 1] = prefix.symbol + + if (isNegative) { + buffer[0] = '-' + } + + for (i in divided.indices) { + buffer[add + i] = divided[i] + } + + buffer[add + divided.length] = '.' + + for (i in 0 until decimalPlaces) { + buffer[add + i + divided.length + 1] = prefix.paddedIndex(remainder, i) + } + + return String(buffer) +} + +fun BigInteger.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { + require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } + val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString(decimalPlaces)) else if (suffix is Component) TextComponent( + toString(decimalPlaces) + suffix.string + ) else TextComponent(toString(decimalPlaces) + suffix) + val isNegative = isNegative + val arr = (if (isNegative) -this else this).divideAndRemainder(prefix.integer) + val divided = arr[0].toString() + val remainder = arr[1].toString() + + if (decimalPlaces == 0) { + if (isNegative) { + return TranslatableComponent(prefix.formatLocaleKey, "-$divided", suffix) + } else { + return TranslatableComponent(prefix.formatLocaleKey, divided + prefix.symbol, suffix) + } + } + + @Suppress("NAME_SHADOWING") + val decimalPlaces = decimalPlaces.coerceAtMost(prefix.power) + + val add = (if (isNegative) 1 else 0) + + val buffer = CharArray(divided.length + 1 + decimalPlaces + add) + + if (isNegative) { + buffer[0] = '-' + } + + for (i in divided.indices) { + buffer[add + i] = divided[i] + } + + buffer[add + divided.length] = '.' + + for (i in 0 until decimalPlaces) { + buffer[add + i + divided.length + 1] = prefix.paddedIndex(remainder, i) + } + + return TranslatableComponent(prefix.formatLocaleKey, String(buffer), suffix) +} + +fun Decimal.determineSiPrefix(): SiPrefix? { + if (isZero) { + return null + } + + var num = this + + if (isNegative) { + num = -this + } + + var prev: SiPrefix? = null + + if (num >= Decimal.ONE) { + for (value in SiPrefix.MULTIPLIES) { + if (value.impreciseFraction <= num) { + prev = value + } else { + break + } + } + } else { + for (value in SiPrefix.DECIMALS_IMPRECISE) { + if (value.impreciseFraction >= num) { + prev = value + } else { + break + } + } + } + + return prev +} + +fun Int.determineSiPrefix(): SiPrefix? { + if (this == 0) { + return null + } + + var num = this + + if (this < 0) { + num = -this + } + + var prev: SiPrefix? = null + + if (num >= 1) { + for (value in SiPrefix.MULTIPLIES) { + if (value.int != null && value.int <= num) { + prev = value + } else { + break + } + } + } + + return prev +} + +fun Double.determineSiPrefix(): SiPrefix? { + if (this == 0.0) { + return null + } + + var num = this + + if (this < 0) { + num = -this + } + + var prev: SiPrefix? = null + + if (num >= 1) { + for (value in SiPrefix.MULTIPLIES) { + if (value.double <= num) { + prev = value + } else { + break + } + } + } + + return prev +} + +fun Decimal.formatSi(decimalPlaces: Int = 2): String { + require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } + val prefix = determineSiPrefix() ?: return toString(decimalPlaces) + return (this / prefix.impreciseFraction).toString(decimalPlaces) + prefix.symbol +} + +fun Int.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { + require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } + val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString()) else if (suffix is Component) TextComponent( + toString() + " " + suffix.string + ) else TextComponent(toString() + " " + suffix) + return TranslatableComponent( + prefix.formatLocaleKey, + "%.${decimalPlaces}f".format(this.toFloat() / prefix.int!!.toFloat()), + suffix + ) +} + +fun Double.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { + require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } + val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent("%.${decimalPlaces}f".format(this)) else if (suffix is Component) TextComponent( + "%.${decimalPlaces}f".format(this) + " " + suffix.string + ) else TextComponent("%.${decimalPlaces}f".format(this) + " " + suffix) + return TranslatableComponent(prefix.formatLocaleKey, "%.${decimalPlaces}f".format(this / prefix.double), suffix) +} + +fun Decimal.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { + require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } + val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString(decimalPlaces)) else if (suffix is Component) TextComponent( + toString(decimalPlaces) + " " + suffix.string + ) else TextComponent(toString(decimalPlaces) + " " + suffix) + return TranslatableComponent( + prefix.formatLocaleKey, + (this / prefix.impreciseFraction).toString(decimalPlaces), + suffix + ) +} + +val POWER_NAME = TranslatableComponent("otm.gui.power.name") +val MATTER_NAME = TranslatableComponent("otm.gui.matter.name") +fun Int.formatPower(decimalPlaces: Int = 2) = formatSiComponent(POWER_NAME, decimalPlaces) +fun Decimal.formatPower(decimalPlaces: Int = 2) = formatSiComponent(POWER_NAME, decimalPlaces) +fun Decimal.formatMatter(decimalPlaces: Int = 2) = formatSiComponent(MATTER_NAME, decimalPlaces) +fun Decimal.formatMatterFull(decimalPlaces: Int = 2) = TranslatableComponent( + "otm.gui.matter.format", formatSiComponent( + MATTER_NAME, decimalPlaces + ) +) + +fun BigInteger.formatPower(decimalPlaces: Int = 2) = formatSiComponent(POWER_NAME, decimalPlaces) +fun BigInteger.formatMatter(decimalPlaces: Int = 2) = formatSiComponent(MATTER_NAME, decimalPlaces) +fun BigInteger.formatMatterFull(decimalPlaces: Int = 2) = TranslatableComponent( + "otm.gui.matter.format", formatSiComponent( + MATTER_NAME, decimalPlaces + ) +) + +fun formatPowerLevel(a: Decimal, b: Decimal, decimalPlaces: Int = 2) = + TranslatableComponent("otm.gui.level", a.formatPower(decimalPlaces), b.formatPower(decimalPlaces)) +fun formatMatterLevel(a: Decimal, b: Decimal, decimalPlaces: Int = 2) = + TranslatableComponent("otm.gui.level", a.formatMatter(decimalPlaces), b.formatMatter(decimalPlaces)) +private fun padded(num: Int): String { + if (num in 0 .. 9) { + return "0$num" + } + + return num.toString() +} + +fun formatTickDuration(ticks: Int, longFormat: Boolean = false): String { + @Suppress("name_shadowing") + var leftTicks = ticks + + // val mTicks = leftTicks % 20 + leftTicks /= 20 + + val seconds = padded(leftTicks % 60) + leftTicks /= 60 + + if (longFormat) { + if (ticks <= 0) { + return "00:00:00" + } else if (ticks <= 20) { + return ".00000${padded(ticks)}" + } + + val minutes = padded(leftTicks % 60) + leftTicks /= 60 + val hours = padded(leftTicks) + return "$hours:$minutes:$seconds" + } else { + if (ticks <= 0) { + return "00:00" + } else if (ticks <= 20) { + return ".00${padded(ticks)}" + } + + val minutes = leftTicks + + if (minutes > 99) { + return "**:**" + } + + return "${padded(minutes)}:$seconds" + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt index 62e093cdf..b12ac983d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt @@ -1,54 +1,10 @@ package ru.dbotthepony.mc.otm.core.util import com.google.common.collect.ImmutableList -import net.minecraft.network.chat.Component -import ru.dbotthepony.mc.otm.core.TextComponent -import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.isNegative -import ru.dbotthepony.mc.otm.core.math.isZero import java.math.BigDecimal import java.math.BigInteger -fun BigInteger.formatReadableNumber(): String { - if (isZero) { - return "0" - } - - val strValue = toString() - - val absLength = strValue.length - (if (isNegative) 1 else 0) - val remainder = absLength % 3 - var groups = absLength / 3 - - if (remainder == 0) { - groups-- - } - - val buffer = CharArray((if (remainder == 0) 3 else remainder) + groups * 4 + if (isNegative) 1 else 0) - var c = 0 - var index = buffer.size - 1 - - for (i in strValue.length - 1 downTo (if (isNegative) 1 else 0)) { - c++ - - if (c == 4) { - buffer[index] = ' ' - index-- - c = 1 - } - - buffer[index] = strValue[i] - index-- - } - - if (isNegative) { - buffer[index] = '-' - } - - return String(buffer) -} - enum class SiPrefix( val power: Int, fractional: Boolean, @@ -133,327 +89,3 @@ enum class SiPrefix( } } -fun BigDecimal.determineSiPrefix(): SiPrefix? { - if (isZero) { - return null - } - - var num = this - - if (isNegative) { - num = -this - } - - var prev: SiPrefix? = null - - if (num >= BigDecimal.ONE) { - for (value in SiPrefix.MULTIPLIES) { - if (value.decimal <= num) { - prev = value - } else { - break - } - } - } else { - for (value in SiPrefix.DECIMALS) { - if (value.decimal >= num) { - prev = value - } else { - break - } - } - } - - return prev -} - -fun BigDecimal.formatSiTranslatable(): Component { - if (isZero) { - return TextComponent("0.00") - } else if (this == BigDecimal.ONE) { - return TextComponent("1.00") - } - - return TextComponent("1.00") -} - -fun BigInteger.determineSiPrefix(): SiPrefix? { - if (isZero) { - return null - } - - var num = this - - if (isNegative) { - num = -this - } - - var prev: SiPrefix? = null - - if (num >= BigInteger.ONE) { - for (value in SiPrefix.MULTIPLIES) { - if (value.integer!! <= num) { - prev = value - } else { - break - } - } - } - - return prev -} - -fun BigInteger.formatSi(decimalPlaces: Int = 2): String { - require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return toString() // + "." + "0".repeat(decimalPlaces) - val isNegative = isNegative - val arr = (if (isNegative) -this else this).divideAndRemainder(prefix.integer) - val divided = arr[0].toString() - val remainder = arr[1].toString() - - if (decimalPlaces == 0) { - if (isNegative) { - return "-" + divided + prefix.symbol - } else { - return divided + prefix.symbol - } - } - - @Suppress("NAME_SHADOWING") - val decimalPlaces = decimalPlaces.coerceAtMost(prefix.power) - - val add = (if (isNegative) 1 else 0) - - val buffer = CharArray(divided.length + 2 + decimalPlaces + add) - buffer[buffer.size - 1] = prefix.symbol - - if (isNegative) { - buffer[0] = '-' - } - - for (i in divided.indices) { - buffer[add + i] = divided[i] - } - - buffer[add + divided.length] = '.' - - for (i in 0 until decimalPlaces) { - buffer[add + i + divided.length + 1] = prefix.paddedIndex(remainder, i) - } - - return String(buffer) -} - -fun BigInteger.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { - require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString(decimalPlaces)) else if (suffix is Component) TextComponent(toString(decimalPlaces) + suffix.string) else TextComponent(toString(decimalPlaces) + suffix) - val isNegative = isNegative - val arr = (if (isNegative) -this else this).divideAndRemainder(prefix.integer) - val divided = arr[0].toString() - val remainder = arr[1].toString() - - if (decimalPlaces == 0) { - if (isNegative) { - return TranslatableComponent(prefix.formatLocaleKey, "-$divided", suffix) - } else { - return TranslatableComponent(prefix.formatLocaleKey, divided + prefix.symbol, suffix) - } - } - - @Suppress("NAME_SHADOWING") - val decimalPlaces = decimalPlaces.coerceAtMost(prefix.power) - - val add = (if (isNegative) 1 else 0) - - val buffer = CharArray(divided.length + 1 + decimalPlaces + add) - - if (isNegative) { - buffer[0] = '-' - } - - for (i in divided.indices) { - buffer[add + i] = divided[i] - } - - buffer[add + divided.length] = '.' - - for (i in 0 until decimalPlaces) { - buffer[add + i + divided.length + 1] = prefix.paddedIndex(remainder, i) - } - - return TranslatableComponent(prefix.formatLocaleKey, String(buffer), suffix) -} - -fun Decimal.determineSiPrefix(): SiPrefix? { - if (isZero) { - return null - } - - var num = this - - if (isNegative) { - num = -this - } - - var prev: SiPrefix? = null - - if (num >= Decimal.ONE) { - for (value in SiPrefix.MULTIPLIES) { - if (value.impreciseFraction <= num) { - prev = value - } else { - break - } - } - } else { - for (value in SiPrefix.DECIMALS_IMPRECISE) { - if (value.impreciseFraction >= num) { - prev = value - } else { - break - } - } - } - - return prev -} - -fun Int.determineSiPrefix(): SiPrefix? { - if (this == 0) { - return null - } - - var num = this - - if (this < 0) { - num = -this - } - - var prev: SiPrefix? = null - - if (num >= 1) { - for (value in SiPrefix.MULTIPLIES) { - if (value.int != null && value.int <= num) { - prev = value - } else { - break - } - } - } - - return prev -} - -fun Double.determineSiPrefix(): SiPrefix? { - if (this == 0.0) { - return null - } - - var num = this - - if (this < 0) { - num = -this - } - - var prev: SiPrefix? = null - - if (num >= 1) { - for (value in SiPrefix.MULTIPLIES) { - if (value.double <= num) { - prev = value - } else { - break - } - } - } - - return prev -} - -fun Decimal.formatSi(decimalPlaces: Int = 2): String { - require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return toString(decimalPlaces) - return (this / prefix.impreciseFraction).toString(decimalPlaces) + prefix.symbol -} - -fun Int.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { - require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString()) else if (suffix is Component) TextComponent(toString() + " " + suffix.string) else TextComponent(toString() + " " + suffix) - return TranslatableComponent(prefix.formatLocaleKey, "%.${decimalPlaces}f".format(this.toFloat() / prefix.int!!.toFloat()), suffix) -} - -fun Double.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { - require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent("%.${decimalPlaces}f".format(this)) else if (suffix is Component) TextComponent("%.${decimalPlaces}f".format(this) + " " + suffix.string) else TextComponent("%.${decimalPlaces}f".format(this) + " " + suffix) - return TranslatableComponent(prefix.formatLocaleKey, "%.${decimalPlaces}f".format(this / prefix.double), suffix) -} - -fun Decimal.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2): Component { - require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" } - val prefix = determineSiPrefix() ?: return if (suffix == "") TextComponent(toString(decimalPlaces)) else if (suffix is Component) TextComponent(toString(decimalPlaces) + " " + suffix.string) else TextComponent(toString(decimalPlaces) + " " + suffix) - return TranslatableComponent(prefix.formatLocaleKey, (this / prefix.impreciseFraction).toString(decimalPlaces), suffix) -} - -val POWER_NAME = TranslatableComponent("otm.gui.power.name") -val MATTER_NAME = TranslatableComponent("otm.gui.matter.name") - -fun Int.formatPower(decimalPlaces: Int = 2) = formatSiComponent(POWER_NAME, decimalPlaces) - -fun Decimal.formatPower(decimalPlaces: Int = 2) = formatSiComponent(POWER_NAME, decimalPlaces) -fun Decimal.formatMatter(decimalPlaces: Int = 2) = formatSiComponent(MATTER_NAME, decimalPlaces) -fun Decimal.formatMatterFull(decimalPlaces: Int = 2) = TranslatableComponent("otm.gui.matter.format", formatSiComponent( - MATTER_NAME, decimalPlaces)) - -fun BigInteger.formatPower(decimalPlaces: Int = 2) = formatSiComponent(POWER_NAME, decimalPlaces) -fun BigInteger.formatMatter(decimalPlaces: Int = 2) = formatSiComponent(MATTER_NAME, decimalPlaces) -fun BigInteger.formatMatterFull(decimalPlaces: Int = 2) = TranslatableComponent("otm.gui.matter.format", formatSiComponent( - MATTER_NAME, decimalPlaces)) - -fun formatPowerLevel(a: Decimal, b: Decimal, decimalPlaces: Int = 2) = TranslatableComponent("otm.gui.level", a.formatPower(decimalPlaces), b.formatPower(decimalPlaces)) -fun formatMatterLevel(a: Decimal, b: Decimal, decimalPlaces: Int = 2) = TranslatableComponent("otm.gui.level", a.formatMatter(decimalPlaces), b.formatMatter(decimalPlaces)) - -private fun padded(num: Int): String { - if (num in 0 .. 9) { - return "0$num" - } - - return num.toString() -} - -fun formatTickDuration(ticks: Int, longFormat: Boolean = false): String { - @Suppress("name_shadowing") - var leftTicks = ticks - - // val mTicks = leftTicks % 20 - leftTicks /= 20 - - val seconds = padded(leftTicks % 60) - leftTicks /= 60 - - if (longFormat) { - if (ticks <= 0) { - return "00:00:00" - } else if (ticks <= 20) { - return ".00000${padded(ticks)}" - } - - val minutes = padded(leftTicks % 60) - leftTicks /= 60 - val hours = padded(leftTicks) - return "$hours:$minutes:$seconds" - } else { - if (ticks <= 0) { - return "00:00" - } else if (ticks <= 20) { - return ".00${padded(ticks)}" - } - - val minutes = leftTicks - - if (minutes > 99) { - return "**:**" - } - - return "${padded(minutes)}:$seconds" - } -}