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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.tfminecraft.advancedcrafting.utils;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashSet;
Expand All @@ -27,34 +28,33 @@ public static double getFactor(StatTemplate template, String statId) {
return template.getFactor(statId);
}

public static double applyGlobalOffset(double raw, String statId) {
/**
* Value written to the item. A stat with a global offset (movement_speed: 100) is rounded in
* config units and then divided, so the item keeps the precision the config shows. Rounding
* after the division kept 2 decimals of the divided value, which turned 1.4 into 1.
*/
public static double applyScaledValue(double raw, String statId, StatTemplate template) {
double scaled = applyScaledValueForPreview(raw, statId, template);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Double offset = Cache.globalStatOffsets.get(statId.toLowerCase());
if (offset == null || offset == 0) {
return raw;
return scaled;
}
return round(raw / offset);
}

public static double applyScaledValue(double raw, String statId, StatTemplate template) {
return applyFactor(applyGlobalOffset(raw, statId), getFactor(template, statId));
return BigDecimal.valueOf(scaled)
.divide(BigDecimal.valueOf(offset), MathContext.DECIMAL64)
.doubleValue();
}

/** Config-scale value for converter preview (reverses global offset division). */
/** Config-scale value for converter preview: the factor applied, before any global offset. */
public static double applyScaledValueForPreview(double raw, String statId, StatTemplate template) {
double scaled = applyScaledValue(raw, statId, template);
Double offset = Cache.globalStatOffsets.get(statId.toLowerCase());
if (offset == null || offset == 0) {
return scaled;
}
return round(scaled * offset);
return applyFactor(raw, getFactor(template, statId));
}

public static double applyFactor(double raw, double factor) {
return round(raw * factor);
}

private static double round(double value) {
BigDecimal bd = new BigDecimal(value);
BigDecimal bd = BigDecimal.valueOf(value); // decimal digits, so 1.005 rounds half-up to 1.01
double abs = Math.abs(value);
if (abs >= 0.01 || abs == 0) {
return bd.setScale(2, RoundingMode.HALF_UP).doubleValue();
Expand Down
7 changes: 6 additions & 1 deletion src/main/resources/stats.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ greataxe:
base-stats:
- attack_speed(1.2)
- blunt_power(3)
- movement_speed(0.6)
- movement_speed(0.1)
stats:
- attack_damage
- attack_speed
Expand All @@ -165,6 +165,11 @@ greataxe:
- lifesteal
- movement_speed
- max_item_damage
# Two-handed, so it never has an off-hand shortsword: movement is (0.1 + leather/wool) x 2,
# what a battleaxe plus an off-hand shortsword with a 0.2 movement base give with the same
# leather and wool.
factors:
movement_speed: 2.0

light_armor:
name: "搂fLight Armor"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,47 @@ void templateScalingFiltersAddsBaseStatsAndRendersPreview() throws Exception {
assertTrue(StatTemplateMath.formatPercentSuffix(1.001).contains("0%"));
assertEquals(.005, StatTemplateMath.applyFactor(.01, .5));
assertEquals(0, StatTemplateMath.applyFactor(0, 3));
assertEquals(2, StatTemplateMath.applyGlobalOffset(2, "missing"));
assertEquals(2, StatTemplateMath.applyScaledValue(2, "missing", template));
Cache.globalStatOffsets.put("attack", 0.);
assertEquals(2, StatTemplateMath.applyGlobalOffset(2, "attack"));
assertEquals(3, StatTemplateMath.applyScaledValue(2, "attack", template));
assertEquals(3, StatTemplateMath.applyScaledValueForPreview(2, "attack", template));
Cache.globalStatOffsets.put("attack", 100.);
assertEquals(.02, StatTemplateMath.applyGlobalOffset(2, "ATTACK"));
assertEquals(.03, StatTemplateMath.applyScaledValue(2, "ATTACK", template));
assertEquals(3, StatTemplateMath.applyScaledValueForPreview(2, "attack", template));
assertEquals(0, StatTemplateMath.getFactor(template, "attack") - 1.5);
assertNotNull(new StatTemplate("invalid", yaml("icon: bad")).getName());
assertNotNull(new StatTemplate("default", yaml("")).getIcon());
}

@Test
void offsetStatsKeepTheirConfigPrecisionOnTheItem() throws Exception {
Cache.globalStatOffsets.put("movement_speed", 100.);
var axe =
new StatTemplate(
"greataxe",
yaml(
"stats: [movement_speed]\n"
+ "factors:\n"
+ " movement_speed: 2.0\n"
+ "base-stats: ['movement_speed(0.1)']"));
var shield =
new StatTemplate(
"shield", yaml("stats: [movement_speed]\nbase-stats: ['movement_speed(-1.6)']"));
var leather = new StatData(List.of("movement_speed(0.6)"));
var mod = new StatModifier("movement_speed", 0);
// (0.1 + 0.6) x 2 = 1.4 movement; rounding after the division used to store 0.01 (1.0)
assertEquals(.014, StatTemplateMath.filterAndApply(leather, axe).getAmount(mod));
assertEquals(-.01, StatTemplateMath.filterAndApply(leather, shield).getAmount(mod));
var wool = new StatData(List.of("movement_speed(0.3)"));
assertEquals(-.013, StatTemplateMath.filterAndApply(wool, shield).getAmount(mod));
// Below 1.0 the old 3-decimal rounding also lost the second config decimal (0.65 -> 0.7)
assertEquals(.0065, StatTemplateMath.applyScaledValue(.65, "movement_speed", shield));
assertEquals(1.4, StatTemplateMath.applyScaledValueForPreview(.7, "movement_speed", axe));
// Half-up on the decimal digits: 1.005 is 1.00499... as a binary double
assertEquals(1.01, StatTemplateMath.applyFactor(1.005, 1));
assertEquals(.0101, StatTemplateMath.applyScaledValue(1.005, "movement_speed", shield));
}

@Test
void bucketAveragesCountMissingStatsAsZeroAndSumSeparateBuckets() throws Exception {
ingredient("iron", "stats: ['armor(6)', 'speed(2)']");
Expand Down
Loading