diff options
8 files changed, 134 insertions, 20 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index 1b4a52ae..96867283 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -187,6 +187,8 @@ tasks.named("compileOneconfigJava", JavaCompile::class) { tasks.named<Test>("test") { useJUnitPlatform() + systemProperty("junit.jupiter.extensions.autodetection.enabled", "true") + this.javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) } tasks.named("jar", Jar::class) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java index 71dedb12..66b6d2d5 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java @@ -48,7 +48,7 @@ public class NeuSearchCalculator { lastInput = input; try { BigDecimal calculate = Calculator.calculate(input, PROVIDE_LOWEST_BIN); - lastResult = new DecimalFormat("#,##0.##").format(calculate); + lastResult = Calculator.getDecimalFormat().format(calculate); } catch (Calculator.CalculatorException ignored) { lastResult = null; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java index 72521821..a9a0856e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/Misc.java @@ -259,6 +259,18 @@ public class Misc { @Expose @ConfigOption( + name = "Calculator Precision", + desc = "Digits after the , to display in the calculator" + ) + @ConfigEditorSlider( + minValue = 1, + maxValue = 100, + minStep = 1 + ) + public int calculationPrecision = 5; + + @Expose + @ConfigOption( name = "Enable Abiphone Warning", desc = "Asks for confirmation when removing a contact in the abiphone" ) diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java index 2b741e94..6b6d0074 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java @@ -19,8 +19,11 @@ package io.github.moulberry.notenoughupdates.util; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; + import java.math.BigDecimal; import java.math.RoundingMode; +import java.text.DecimalFormat; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; @@ -34,6 +37,14 @@ public class Calculator { Optional<BigDecimal> provideVariable(String name) throws CalculatorException; } + public static DecimalFormat getDecimalFormat() { + StringBuilder f = new StringBuilder("#,##0."); + for (int i = 0; i < NotEnoughUpdates.INSTANCE.config.misc.calculationPrecision; i++) { + f.append("#"); + } + return new DecimalFormat(f.toString()); + } + public static BigDecimal calculate(String source, VariableProvider variables) throws CalculatorException { return evaluate(variables, shuntingYard(lex(source))); } @@ -269,6 +280,7 @@ public class Calculator { ///<editor-fold desc="Evaluating Time"> public static BigDecimal evaluate(VariableProvider provider, List<Token> rpnTokens) throws CalculatorException { Deque<BigDecimal> values = new ArrayDeque<>(); + int precision = NotEnoughUpdates.INSTANCE != null ? NotEnoughUpdates.INSTANCE.config.misc.calculationPrecision : 5; try { for (Token command : rpnTokens) { switch (command.type) { @@ -287,42 +299,54 @@ public class Calculator { values.push(new BigDecimal(command.numericValue).scaleByPowerOfTen(command.exponent)); break; case BINOP: - BigDecimal right = values.pop().setScale(2, RoundingMode.HALF_UP); - BigDecimal left = values.pop().setScale(2, RoundingMode.HALF_UP); + BigDecimal right = values.pop().setScale(precision, RoundingMode.HALF_UP); + BigDecimal left = values.pop().setScale(precision, RoundingMode.HALF_UP); switch (command.operatorValue.intern()) { case "^": if (right.compareTo(new BigDecimal(1000)) >= 0) { Token rightToken = rpnTokens.get(rpnTokens.indexOf(command) - 1); - throw new CalculatorException(right + " is too large, pick a power less than 1000", rightToken.tokenStart, rightToken.tokenLength); + throw new CalculatorException( + right + " is too large, pick a power less than 1000", + rightToken.tokenStart, + rightToken.tokenLength + ); } if (right.doubleValue() != right.intValue()) { Token rightToken = rpnTokens.get(rpnTokens.indexOf(command) - 1); - throw new CalculatorException(right + " has a decimal, pick a power that is non-decimal", rightToken.tokenStart, rightToken.tokenLength); + throw new CalculatorException( + right + " has a decimal, pick a power that is non-decimal", + rightToken.tokenStart, + rightToken.tokenLength + ); } if (right.doubleValue() < 0) { Token rightToken = rpnTokens.get(rpnTokens.indexOf(command) - 1); - throw new CalculatorException(right + " is a negative number, pick a power that is positive", rightToken.tokenStart, rightToken.tokenLength); + throw new CalculatorException( + right + " is a negative number, pick a power that is positive", + rightToken.tokenStart, + rightToken.tokenLength + ); } - values.push(left.pow(right.intValue()).setScale(2, RoundingMode.HALF_UP)); + values.push(left.pow(right.intValue()).setScale(precision, RoundingMode.HALF_UP)); break; case "x": case "*": - values.push(left.multiply(right).setScale(2, RoundingMode.HALF_UP)); + values.push(left.multiply(right).setScale(precision, RoundingMode.HALF_UP)); break; case "/": try { - values.push(left.divide(right, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP)); + values.push(left.divide(right, RoundingMode.HALF_UP).setScale(precision, RoundingMode.HALF_UP)); } catch (ArithmeticException e) { throw new CalculatorException("Encountered division by 0", command.tokenStart, command.tokenLength); } break; case "+": - values.push(left.add(right).setScale(2, RoundingMode.HALF_UP)); + values.push(left.add(right).setScale(precision, RoundingMode.HALF_UP)); break; case "-": - values.push(left.subtract(right).setScale(2, RoundingMode.HALF_UP)); + values.push(left.subtract(right).setScale(precision, RoundingMode.HALF_UP)); break; default: throw new CalculatorException( @@ -343,22 +367,25 @@ public class Calculator { BigDecimal p = values.pop(); switch (command.operatorValue.intern()) { case "s": - values.push(p.multiply(new BigDecimal(64)).setScale(2, RoundingMode.HALF_UP)); + values.push(p.multiply(new BigDecimal(64)).setScale(precision, RoundingMode.HALF_UP)); break; case "k": - values.push(p.multiply(new BigDecimal(1_000)).setScale(2, RoundingMode.HALF_UP)); + values.push(p.multiply(new BigDecimal(1_000)).setScale(precision, RoundingMode.HALF_UP)); break; case "m": - values.push(p.multiply(new BigDecimal(1_000_000)).setScale(2, RoundingMode.HALF_UP)); + values.push(p.multiply(new BigDecimal(1_000_000)).setScale(precision, RoundingMode.HALF_UP)); break; case "b": - values.push(p.multiply(new BigDecimal(1_000_000_000)).setScale(2, RoundingMode.HALF_UP)); + values.push(p.multiply(new BigDecimal(1_000_000_000)).setScale(precision, RoundingMode.HALF_UP)); break; case "t": - values.push(p.multiply(new BigDecimal("1000000000000")).setScale(2, RoundingMode.HALF_UP)); + values.push(p.multiply(new BigDecimal("1000000000000")).setScale(precision, RoundingMode.HALF_UP)); break; case "%": - values.push(p.setScale(3, RoundingMode.HALF_UP).divide(new BigDecimal(100), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP)); + values.push(p + .setScale(precision + 1, RoundingMode.HALF_UP) + .divide(new BigDecimal(100), RoundingMode.HALF_UP) + .setScale(precision, RoundingMode.HALF_UP)); break; default: throw new CalculatorException( diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt index 64ee444b..422871b4 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt @@ -40,7 +40,6 @@ import net.minecraft.client.renderer.OpenGlHelper import net.minecraft.util.ChatComponentText import net.minecraft.util.EnumChatFormatting.* import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import java.text.DecimalFormat import java.util.* import java.util.concurrent.CompletableFuture @@ -53,7 +52,7 @@ class MiscCommands { val calculation = this[calculation] try { val calculate = Calculator.calculate(calculation, NeuSearchCalculator.PROVIDE_LOWEST_BIN) - val formatter = DecimalFormat("#,##0.##") + val formatter = Calculator.getDecimalFormat() val formatted = formatter.format(calculate) reply("$WHITE$calculation $YELLOW= $GREEN$formatted") } catch (e: CalculatorException) { diff --git a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt new file mode 100644 index 00000000..cab10aaa --- /dev/null +++ b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/BootstrapHook.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.util + +import net.minecraft.block.Block +import net.minecraft.block.BlockFire +import net.minecraft.init.Bootstrap +import net.minecraft.item.Item +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.Extension +import org.junit.jupiter.api.extension.ExtensionContext +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock + +class BootstrapHook : BeforeAllCallback, Extension { + companion object { + private val LOCK: Lock = ReentrantLock() + private var bootstrapped = false + } + + override fun beforeAll(p0: ExtensionContext?) { + LOCK.lock() + try { + if (!bootstrapped) { + bootstrapped = true + + Bootstrap::class.java.getDeclaredField("alreadyRegistered").also { it.isAccessible = true } + .set(null, true) + Block.registerBlocks() + BlockFire.init() + Item.registerItems() + } + } finally { + LOCK.unlock() + } + } +} diff --git a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt index ce866eec..6c4b1e1c 100644 --- a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt +++ b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/CalculatorTest.kt @@ -41,7 +41,7 @@ internal class CalculatorTest { calculationShouldBe("(1)+1", 2) calculationShouldBe("-0", 0) calculationShouldBe("-10+2", -8) - calculationShouldBe("14k*23m/2.35+596123-9213", 137021863505.74) + calculationShouldBe("14k*23m/2.35+596123-9213", 137021863505.74467) calculationShouldBe("1+-10+2", -7) calculationShouldBe("2**--10", 2.0.pow(10)) } diff --git a/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000..6cc832b4 --- /dev/null +++ b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1,20 @@ +# +# Copyright (C) 2023 NotEnoughUpdates contributors +# +# This file is part of NotEnoughUpdates. +# +# NotEnoughUpdates is free software: you can redistribute it +# and/or modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation, either +# version 3 of the License, or (at your option) any later version. +# +# NotEnoughUpdates 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. +# + +io.github.moulberry.notenoughupdates.util.BootstrapHook |