Describe the bug
There is a behavior discrepancy between Vanilla Minecraft and Deepslate when using a density function that multiplies a constant 0 with a non-finite value such as NaN or Infinity
In Vanilla Minecraft, the function 0 * invert(0) + 5 results in NaN, which ultimately generates an empty world (Air) because NaN > 0 is false.
In Deepslate, the same density function evaluates to 5, incorrectly suggesting a solid world.
Technical Details & Root Cause
The discrepancy stems from how Vanilla Minecraft optimizes mul operations compared to Deepslate:
-
In Deepslate:
When parsing a mul density function, it is unconditionally instantiated as an Ap2 class. The compute method of Ap2 contains a short-circuit:
case 'mul': return a === 0 ? 0 : a * this.argument2.compute(context)
Because the first argument is 0, the short-circuit prevents the evaluation of the second argument (invert(0)), neglecting results other than 0 (even if non-finite).
-
In Vanilla Minecraft:
When Vanilla parses a mul (or add) operation where one of the arguments is a constant, it optimizes it into a MulOrAdd class instead of a standard TwoArgumentSimpleFunction (Ap2).
MulOrAdd implements the PureTransformer interface, which evaluates the inner function first, before applying the constant:
// PureTransformer implementation
default double compute(final FunctionContext context) {
return this.transform(this.input().compute(context));
}
// MulOrAdd implementation
public double transform(final double input) {
return switch (this.specificType) {
case MUL -> input * this.argument;
// ...
};
}
Because the dynamic input is evaluated first, invert(0) results in Double.POSITIVE_INFINITY. The transformation then multiplies Infinity * 0.0, which strictly yields Double.NaN.
Expected behavior
Deepslate should mimic Vanilla Minecraft's parsing optimization. If one argument of add or mul is a constant, it should be wrapped in a MulOrAdd-like structure that evaluates the dynamic input first to ensure parity with edge-cases involving Infinity and NaN.
Steps to reproduce
Use a custom dimension or density function evaluating 0 * invert(0) + 5.
{
"type": "minecraft:add",
"argument1": {
"type": "minecraft:mul",
"argument1": 0,
"argument2": {
"type": "minecraft:invert",
"argument": 0
}
},
"argument2": 5
}
- Vanilla MC: Empty world (Density is
NaN).
- Deepslate: Solid world (Density is
5).
Describe the bug
There is a behavior discrepancy between Vanilla Minecraft and Deepslate when using a density function that multiplies a constant
0with a non-finite value such asNaNorInfinityIn Vanilla Minecraft, the function
0 * invert(0) + 5results inNaN, which ultimately generates an empty world (Air) becauseNaN > 0isfalse.In Deepslate, the same density function evaluates to
5, incorrectly suggesting a solid world.Technical Details & Root Cause
The discrepancy stems from how Vanilla Minecraft optimizes
muloperations compared to Deepslate:In Deepslate:
When parsing a
muldensity function, it is unconditionally instantiated as anAp2class. Thecomputemethod ofAp2contains a short-circuit:Because the first argument is
0, the short-circuit prevents the evaluation of the second argument (invert(0)), neglecting results other than0(even if non-finite).In Vanilla Minecraft:
When Vanilla parses a
mul(oradd) operation where one of the arguments is a constant, it optimizes it into aMulOrAddclass instead of a standardTwoArgumentSimpleFunction(Ap2).MulOrAddimplements thePureTransformerinterface, which evaluates the inner function first, before applying the constant:Because the dynamic input is evaluated first,
invert(0)results inDouble.POSITIVE_INFINITY. The transformation then multipliesInfinity * 0.0, which strictly yieldsDouble.NaN.Expected behavior
Deepslate should mimic Vanilla Minecraft's parsing optimization. If one argument of
addormulis a constant, it should be wrapped in aMulOrAdd-like structure that evaluates the dynamic input first to ensure parity with edge-cases involvingInfinityandNaN.Steps to reproduce
Use a custom dimension or density function evaluating
0 * invert(0) + 5.{ "type": "minecraft:add", "argument1": { "type": "minecraft:mul", "argument1": 0, "argument2": { "type": "minecraft:invert", "argument": 0 } }, "argument2": 5 }NaN).5).