Pin biome fitness against vanilla runtime
This commit is contained in:
parent
be8f030698
commit
b11e6f14cb
5 changed files with 86 additions and 10 deletions
|
|
@ -102,8 +102,8 @@ func makeBiomeParameter(e rawParameter, depth worldgen.ClimateRange) worldgen.Bi
|
|||
qr(e.Param.Humidity),
|
||||
qr(e.Param.Continentalness),
|
||||
qr(e.Param.Erosion),
|
||||
qr(e.Param.Weirdness),
|
||||
depth,
|
||||
qr(e.Param.Weirdness),
|
||||
},
|
||||
Offset: worldgen.Quantize(e.Param.Offset),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const dataVersion26 = 4790
|
|||
// first time it ran: chunkAt prefers the store over the generator, so the
|
||||
// already-explored area around spawn keeps its old terrain and every later fix
|
||||
// looks like it did nothing in exactly the place you are standing.
|
||||
const generatorVersion = 15
|
||||
const generatorVersion = 16
|
||||
|
||||
// generatorVersionTag is the NBT key holding generatorVersion. It is namespaced
|
||||
// because it is ours, not part of the vanilla chunk format.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import "math"
|
|||
|
||||
// This file reproduces net.minecraft.world.level.biome.Climate, the multi-noise
|
||||
// biome selector. A point in climate space is six quantized coordinates
|
||||
// (temperature, humidity, continentalness, erosion, weirdness, depth); the
|
||||
// (temperature, humidity, continentalness, erosion, depth, weirdness); the
|
||||
// finder returns the biome whose parameter range is closest to the point by the
|
||||
// vanilla fitDistance metric.
|
||||
//
|
||||
|
|
@ -23,13 +23,13 @@ func quantize(v float64) int64 {
|
|||
func Quantize(v float64) int64 { return quantize(v) }
|
||||
|
||||
// AxisCount is the number of climate coordinates (temperature, humidity,
|
||||
// continentalness, erosion, weirdness, depth).
|
||||
// continentalness, erosion, depth, weirdness).
|
||||
const AxisCount = 6
|
||||
|
||||
// TargetPoint is a fully-specified climate point: the value the biome finder
|
||||
// tries to match against parameter ranges. Fields are pre-quantized longs.
|
||||
type TargetPoint struct {
|
||||
Temperature, Humidity, Continentalness, Erosion, Weirdness, Depth int64
|
||||
Temperature, Humidity, Continentalness, Erosion, Depth, Weirdness int64
|
||||
}
|
||||
|
||||
// NewTargetPoint quantizes six float climate coordinates into a TargetPoint.
|
||||
|
|
@ -39,15 +39,15 @@ func NewTargetPoint(temp, humid, cont, ero, weird, depth float64) TargetPoint {
|
|||
Humidity: quantize(humid),
|
||||
Continentalness: quantize(cont),
|
||||
Erosion: quantize(ero),
|
||||
Weirdness: quantize(weird),
|
||||
Depth: quantize(depth),
|
||||
Weirdness: quantize(weird),
|
||||
}
|
||||
}
|
||||
|
||||
// fitDistance is the vanilla distance from a point to a parameter range. A
|
||||
// coordinate inside a range contributes zero; offset is applied separately.
|
||||
func fitDistance(point TargetPoint, ranges [AxisCount]ClimateRange, offset int64) int64 {
|
||||
values := [AxisCount]int64{point.Temperature, point.Humidity, point.Continentalness, point.Erosion, point.Weirdness, point.Depth}
|
||||
values := [AxisCount]int64{point.Temperature, point.Humidity, point.Continentalness, point.Erosion, point.Depth, point.Weirdness}
|
||||
var total int64
|
||||
for i, value := range values {
|
||||
r := ranges[i]
|
||||
|
|
@ -73,7 +73,7 @@ func (r ClimateRange) contains(v int64) bool { return v >= r.Min && v <= r.Max }
|
|||
// BiomeParameter is one biome entry's full climate signature plus its name.
|
||||
type BiomeParameter struct {
|
||||
Name string
|
||||
// ranges[0..5] = temperature, humidity, continentalness, erosion, weirdness, depth.
|
||||
// ranges[0..5] = temperature, humidity, continentalness, erosion, depth, weirdness.
|
||||
Ranges [AxisCount]ClimateRange
|
||||
Offset int64
|
||||
}
|
||||
|
|
@ -118,6 +118,6 @@ func containsAll(ranges [AxisCount]ClimateRange, p TargetPoint) bool {
|
|||
ranges[1].contains(p.Humidity) &&
|
||||
ranges[2].contains(p.Continentalness) &&
|
||||
ranges[3].contains(p.Erosion) &&
|
||||
ranges[4].contains(p.Weirdness) &&
|
||||
ranges[5].contains(p.Depth)
|
||||
ranges[4].contains(p.Depth) &&
|
||||
ranges[5].contains(p.Weirdness)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,32 @@ func TestParameterTableDistanceOffsetAndTies(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFitnessVectorsAgainstVanillaRuntime(t *testing.T) {
|
||||
zero := [AxisCount]ClimateRange{}
|
||||
temperatureRange := zero
|
||||
temperatureRange[0] = ClimateRange{Min: 0, Max: 10}
|
||||
depthWeirdness := zero
|
||||
depthWeirdness[4] = ClimateRange{Min: 20, Max: 20}
|
||||
depthWeirdness[5] = ClimateRange{Min: 30, Max: 30}
|
||||
for _, vector := range []struct {
|
||||
name string
|
||||
point TargetPoint
|
||||
ranges [AxisCount]ClimateRange
|
||||
offset int64
|
||||
want int64
|
||||
}{
|
||||
{"inside", TargetPoint{Temperature: 5}, temperatureRange, 0, 0},
|
||||
{"below", TargetPoint{Temperature: -3}, temperatureRange, 0, 9},
|
||||
{"above", TargetPoint{Temperature: 14}, temperatureRange, 0, 16},
|
||||
{"offset", TargetPoint{Temperature: 5}, temperatureRange, 7, 49},
|
||||
{"depth-weirdness-order", TargetPoint{Depth: 23, Weirdness: 35}, depthWeirdness, 0, 34},
|
||||
} {
|
||||
if got := fitDistance(vector.point, vector.ranges, vector.offset); got != vector.want {
|
||||
t.Errorf("%s fitness = %d, want vanilla runtime %d", vector.name, got, vector.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestFitDistanceZero confirms identical points are zero-distance and distinct
|
||||
// points are positive; the exact value is not asserted to stay robust to
|
||||
// representation choices.
|
||||
|
|
@ -78,6 +104,21 @@ func TestRangeContains(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestContainsAllUsesVanillaAxisOrder(t *testing.T) {
|
||||
var ranges [AxisCount]ClimateRange
|
||||
for i := range ranges {
|
||||
ranges[i] = ClimateRange{Min: 0, Max: 0}
|
||||
}
|
||||
ranges[4] = ClimateRange{Min: 20, Max: 20}
|
||||
ranges[5] = ClimateRange{Min: 30, Max: 30}
|
||||
if !containsAll(ranges, TargetPoint{Depth: 20, Weirdness: 30}) {
|
||||
t.Fatal("depth/weirdness ranges were not matched in vanilla order")
|
||||
}
|
||||
if containsAll(ranges, TargetPoint{Depth: 30, Weirdness: 20}) {
|
||||
t.Fatal("accepted swapped depth/weirdness axes")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSampleColumnDeterministic verifies the same seed/coords give the same
|
||||
// biome and a different seed gives (almost certainly) a different one.
|
||||
func TestSampleColumnDeterministic(t *testing.T) {
|
||||
|
|
|
|||
35
tools/VanillaClimateVectors.java
Normal file
35
tools/VanillaClimateVectors.java
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import java.lang.reflect.Method;
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
|
||||
// Prints fixed Climate.ParameterPoint fitness vectors from the official jar.
|
||||
public final class VanillaClimateVectors {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Method fitness = Climate.ParameterPoint.class.getDeclaredMethod("fitness", Climate.TargetPoint.class);
|
||||
fitness.setAccessible(true);
|
||||
vector(fitness, "inside", ranges(0, 10, 0), point(5, 0));
|
||||
vector(fitness, "below", ranges(0, 10, 0), point(-3, 0));
|
||||
vector(fitness, "above", ranges(0, 10, 0), point(14, 0));
|
||||
vector(fitness, "offset", ranges(0, 10, 7), point(5, 0));
|
||||
|
||||
Climate.Parameter zero = new Climate.Parameter(0, 0);
|
||||
Climate.Parameter depth = new Climate.Parameter(20, 20);
|
||||
Climate.Parameter weird = new Climate.Parameter(30, 30);
|
||||
Climate.ParameterPoint axes = new Climate.ParameterPoint(zero, zero, zero, zero, depth, weird, 0);
|
||||
Climate.TargetPoint target = new Climate.TargetPoint(0, 0, 0, 0, 23, 35);
|
||||
vector(fitness, "depth-weirdness-order", axes, target);
|
||||
}
|
||||
|
||||
private static Climate.ParameterPoint ranges(long min, long max, long offset) {
|
||||
Climate.Parameter range = new Climate.Parameter(min, max);
|
||||
Climate.Parameter zero = new Climate.Parameter(0, 0);
|
||||
return new Climate.ParameterPoint(range, zero, zero, zero, zero, zero, offset);
|
||||
}
|
||||
|
||||
private static Climate.TargetPoint point(long temperature, long depth) {
|
||||
return new Climate.TargetPoint(temperature, 0, 0, 0, depth, 0);
|
||||
}
|
||||
|
||||
private static void vector(Method fitness, String name, Climate.ParameterPoint p, Climate.TargetPoint target) throws Exception {
|
||||
System.out.println(name + "=" + fitness.invoke(p, target));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue