558 lines
23 KiB
Java
558 lines
23 KiB
Java
|
package net.minecraft.world.level.biome;
|
||
|
|
||
|
import com.google.common.annotations.VisibleForTesting;
|
||
|
import com.google.common.collect.ImmutableList;
|
||
|
import com.google.common.collect.Lists;
|
||
|
import com.mojang.datafixers.util.Pair;
|
||
|
import com.mojang.serialization.Codec;
|
||
|
import com.mojang.serialization.DataResult;
|
||
|
import com.mojang.serialization.MapCodec;
|
||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||
|
import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.Comparator;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.List;
|
||
|
import java.util.Locale;
|
||
|
import java.util.stream.Collectors;
|
||
|
import javax.annotation.Nullable;
|
||
|
import net.minecraft.core.BlockPos;
|
||
|
import net.minecraft.core.QuartPos;
|
||
|
import net.minecraft.util.ExtraCodecs;
|
||
|
import net.minecraft.util.Mth;
|
||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||
|
|
||
|
public class Climate {
|
||
|
private static final boolean DEBUG_SLOW_BIOME_SEARCH = false;
|
||
|
private static final float QUANTIZATION_FACTOR = 10000.0F;
|
||
|
@VisibleForTesting
|
||
|
protected static final int PARAMETER_COUNT = 7;
|
||
|
|
||
|
public static Climate.TargetPoint target(float p_186782_, float p_186783_, float p_186784_, float p_186785_, float p_186786_, float p_186787_) {
|
||
|
return new Climate.TargetPoint(
|
||
|
quantizeCoord(p_186782_), quantizeCoord(p_186783_), quantizeCoord(p_186784_), quantizeCoord(p_186785_), quantizeCoord(p_186786_), quantizeCoord(p_186787_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static Climate.ParameterPoint parameters(
|
||
|
float p_186789_, float p_186790_, float p_186791_, float p_186792_, float p_186793_, float p_186794_, float p_186795_
|
||
|
) {
|
||
|
return new Climate.ParameterPoint(
|
||
|
Climate.Parameter.point(p_186789_),
|
||
|
Climate.Parameter.point(p_186790_),
|
||
|
Climate.Parameter.point(p_186791_),
|
||
|
Climate.Parameter.point(p_186792_),
|
||
|
Climate.Parameter.point(p_186793_),
|
||
|
Climate.Parameter.point(p_186794_),
|
||
|
quantizeCoord(p_186795_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static Climate.ParameterPoint parameters(
|
||
|
Climate.Parameter p_186799_,
|
||
|
Climate.Parameter p_186800_,
|
||
|
Climate.Parameter p_186801_,
|
||
|
Climate.Parameter p_186802_,
|
||
|
Climate.Parameter p_186803_,
|
||
|
Climate.Parameter p_186804_,
|
||
|
float p_186805_
|
||
|
) {
|
||
|
return new Climate.ParameterPoint(p_186799_, p_186800_, p_186801_, p_186802_, p_186803_, p_186804_, quantizeCoord(p_186805_));
|
||
|
}
|
||
|
|
||
|
public static long quantizeCoord(float p_186780_) {
|
||
|
return (long)(p_186780_ * 10000.0F);
|
||
|
}
|
||
|
|
||
|
public static float unquantizeCoord(long p_186797_) {
|
||
|
return (float)p_186797_ / 10000.0F;
|
||
|
}
|
||
|
|
||
|
public static Climate.Sampler empty() {
|
||
|
DensityFunction densityfunction = DensityFunctions.zero();
|
||
|
return new Climate.Sampler(densityfunction, densityfunction, densityfunction, densityfunction, densityfunction, densityfunction, List.of());
|
||
|
}
|
||
|
|
||
|
public static BlockPos findSpawnPosition(List<Climate.ParameterPoint> p_207843_, Climate.Sampler p_207844_) {
|
||
|
return (new Climate.SpawnFinder(p_207843_, p_207844_)).result.location();
|
||
|
}
|
||
|
|
||
|
interface DistanceMetric<T> {
|
||
|
long distance(Climate.RTree.Node<T> p_186810_, long[] p_186811_);
|
||
|
}
|
||
|
|
||
|
public record Parameter(long min, long max) {
|
||
|
public static final Codec<Climate.Parameter> CODEC = ExtraCodecs.intervalCodec(
|
||
|
Codec.floatRange(-2.0F, 2.0F),
|
||
|
"min",
|
||
|
"max",
|
||
|
(p_275164_, p_275165_) -> p_275164_.compareTo(p_275165_) > 0
|
||
|
? DataResult.error(() -> "Cannon construct interval, min > max (" + p_275164_ + " > " + p_275165_ + ")")
|
||
|
: DataResult.success(new Climate.Parameter(Climate.quantizeCoord(p_275164_), Climate.quantizeCoord(p_275165_))),
|
||
|
p_186841_ -> Climate.unquantizeCoord(p_186841_.min()),
|
||
|
p_186839_ -> Climate.unquantizeCoord(p_186839_.max())
|
||
|
);
|
||
|
|
||
|
public static Climate.Parameter point(float p_186821_) {
|
||
|
return span(p_186821_, p_186821_);
|
||
|
}
|
||
|
|
||
|
public static Climate.Parameter span(float p_186823_, float p_186824_) {
|
||
|
if (p_186823_ > p_186824_) {
|
||
|
throw new IllegalArgumentException("min > max: " + p_186823_ + " " + p_186824_);
|
||
|
} else {
|
||
|
return new Climate.Parameter(Climate.quantizeCoord(p_186823_), Climate.quantizeCoord(p_186824_));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static Climate.Parameter span(Climate.Parameter p_186830_, Climate.Parameter p_186831_) {
|
||
|
if (p_186830_.min() > p_186831_.max()) {
|
||
|
throw new IllegalArgumentException("min > max: " + p_186830_ + " " + p_186831_);
|
||
|
} else {
|
||
|
return new Climate.Parameter(p_186830_.min(), p_186831_.max());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return this.min == this.max
|
||
|
? String.format(Locale.ROOT, "%d", this.min)
|
||
|
: String.format(Locale.ROOT, "[%d-%d]", this.min, this.max);
|
||
|
}
|
||
|
|
||
|
public long distance(long p_186826_) {
|
||
|
long i = p_186826_ - this.max;
|
||
|
long j = this.min - p_186826_;
|
||
|
return i > 0L ? i : Math.max(j, 0L);
|
||
|
}
|
||
|
|
||
|
public long distance(Climate.Parameter p_186828_) {
|
||
|
long i = p_186828_.min() - this.max;
|
||
|
long j = this.min - p_186828_.max();
|
||
|
return i > 0L ? i : Math.max(j, 0L);
|
||
|
}
|
||
|
|
||
|
public Climate.Parameter span(@Nullable Climate.Parameter p_186837_) {
|
||
|
return p_186837_ == null
|
||
|
? this
|
||
|
: new Climate.Parameter(Math.min(this.min, p_186837_.min()), Math.max(this.max, p_186837_.max()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class ParameterList<T> {
|
||
|
private final List<Pair<Climate.ParameterPoint, T>> values;
|
||
|
private final Climate.RTree<T> index;
|
||
|
|
||
|
public static <T> Codec<Climate.ParameterList<T>> codec(MapCodec<T> p_275523_) {
|
||
|
return ExtraCodecs.nonEmptyList(
|
||
|
RecordCodecBuilder.<Pair<Climate.ParameterPoint, T>>create(
|
||
|
p_275233_ -> p_275233_.group(
|
||
|
Climate.ParameterPoint.CODEC.fieldOf("parameters").forGetter(Pair::getFirst), p_275523_.forGetter(Pair::getSecond)
|
||
|
)
|
||
|
.apply(p_275233_, Pair::of)
|
||
|
)
|
||
|
.listOf()
|
||
|
)
|
||
|
.xmap(Climate.ParameterList::new, Climate.ParameterList::values);
|
||
|
}
|
||
|
|
||
|
public ParameterList(List<Pair<Climate.ParameterPoint, T>> p_186849_) {
|
||
|
this.values = p_186849_;
|
||
|
this.index = Climate.RTree.create(p_186849_);
|
||
|
}
|
||
|
|
||
|
public List<Pair<Climate.ParameterPoint, T>> values() {
|
||
|
return this.values;
|
||
|
}
|
||
|
|
||
|
public T findValue(Climate.TargetPoint p_204253_) {
|
||
|
return this.findValueIndex(p_204253_);
|
||
|
}
|
||
|
|
||
|
@VisibleForTesting
|
||
|
public T findValueBruteForce(Climate.TargetPoint p_204255_) {
|
||
|
Iterator<Pair<Climate.ParameterPoint, T>> iterator = this.values().iterator();
|
||
|
Pair<Climate.ParameterPoint, T> pair = iterator.next();
|
||
|
long i = pair.getFirst().fitness(p_204255_);
|
||
|
T t = pair.getSecond();
|
||
|
|
||
|
while (iterator.hasNext()) {
|
||
|
Pair<Climate.ParameterPoint, T> pair1 = iterator.next();
|
||
|
long j = pair1.getFirst().fitness(p_204255_);
|
||
|
if (j < i) {
|
||
|
i = j;
|
||
|
t = pair1.getSecond();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
public T findValueIndex(Climate.TargetPoint p_186852_) {
|
||
|
return this.findValueIndex(p_186852_, Climate.RTree.Node::distance);
|
||
|
}
|
||
|
|
||
|
protected T findValueIndex(Climate.TargetPoint p_186854_, Climate.DistanceMetric<T> p_186855_) {
|
||
|
return this.index.search(p_186854_, p_186855_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public record ParameterPoint(
|
||
|
Climate.Parameter temperature,
|
||
|
Climate.Parameter humidity,
|
||
|
Climate.Parameter continentalness,
|
||
|
Climate.Parameter erosion,
|
||
|
Climate.Parameter depth,
|
||
|
Climate.Parameter weirdness,
|
||
|
long offset
|
||
|
) {
|
||
|
public static final Codec<Climate.ParameterPoint> CODEC = RecordCodecBuilder.create(
|
||
|
p_186885_ -> p_186885_.group(
|
||
|
Climate.Parameter.CODEC.fieldOf("temperature").forGetter(p_186905_ -> p_186905_.temperature),
|
||
|
Climate.Parameter.CODEC.fieldOf("humidity").forGetter(p_186902_ -> p_186902_.humidity),
|
||
|
Climate.Parameter.CODEC.fieldOf("continentalness").forGetter(p_186897_ -> p_186897_.continentalness),
|
||
|
Climate.Parameter.CODEC.fieldOf("erosion").forGetter(p_186894_ -> p_186894_.erosion),
|
||
|
Climate.Parameter.CODEC.fieldOf("depth").forGetter(p_186891_ -> p_186891_.depth),
|
||
|
Climate.Parameter.CODEC.fieldOf("weirdness").forGetter(p_186888_ -> p_186888_.weirdness),
|
||
|
Codec.floatRange(0.0F, 1.0F).fieldOf("offset").xmap(Climate::quantizeCoord, Climate::unquantizeCoord).forGetter(p_186881_ -> p_186881_.offset)
|
||
|
)
|
||
|
.apply(p_186885_, Climate.ParameterPoint::new)
|
||
|
);
|
||
|
|
||
|
long fitness(Climate.TargetPoint p_186883_) {
|
||
|
return Mth.square(this.temperature.distance(p_186883_.temperature))
|
||
|
+ Mth.square(this.humidity.distance(p_186883_.humidity))
|
||
|
+ Mth.square(this.continentalness.distance(p_186883_.continentalness))
|
||
|
+ Mth.square(this.erosion.distance(p_186883_.erosion))
|
||
|
+ Mth.square(this.depth.distance(p_186883_.depth))
|
||
|
+ Mth.square(this.weirdness.distance(p_186883_.weirdness))
|
||
|
+ Mth.square(this.offset);
|
||
|
}
|
||
|
|
||
|
protected List<Climate.Parameter> parameterSpace() {
|
||
|
return ImmutableList.of(
|
||
|
this.temperature,
|
||
|
this.humidity,
|
||
|
this.continentalness,
|
||
|
this.erosion,
|
||
|
this.depth,
|
||
|
this.weirdness,
|
||
|
new Climate.Parameter(this.offset, this.offset)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected static final class RTree<T> {
|
||
|
private static final int CHILDREN_PER_NODE = 6;
|
||
|
private final Climate.RTree.Node<T> root;
|
||
|
private final ThreadLocal<Climate.RTree.Leaf<T>> lastResult = new ThreadLocal<>();
|
||
|
|
||
|
private RTree(Climate.RTree.Node<T> p_186913_) {
|
||
|
this.root = p_186913_;
|
||
|
}
|
||
|
|
||
|
public static <T> Climate.RTree<T> create(List<Pair<Climate.ParameterPoint, T>> p_186936_) {
|
||
|
if (p_186936_.isEmpty()) {
|
||
|
throw new IllegalArgumentException("Need at least one value to build the search tree.");
|
||
|
} else {
|
||
|
int i = p_186936_.get(0).getFirst().parameterSpace().size();
|
||
|
if (i != 7) {
|
||
|
throw new IllegalStateException("Expecting parameter space to be 7, got " + i);
|
||
|
} else {
|
||
|
List<Climate.RTree.Leaf<T>> list = p_186936_.stream()
|
||
|
.map(p_186934_ -> new Climate.RTree.Leaf<T>(p_186934_.getFirst(), p_186934_.getSecond()))
|
||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||
|
return new Climate.RTree<>(build(i, list));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static <T> Climate.RTree.Node<T> build(int p_186921_, List<? extends Climate.RTree.Node<T>> p_186922_) {
|
||
|
if (p_186922_.isEmpty()) {
|
||
|
throw new IllegalStateException("Need at least one child to build a node");
|
||
|
} else if (p_186922_.size() == 1) {
|
||
|
return (Climate.RTree.Node<T>)p_186922_.get(0);
|
||
|
} else if (p_186922_.size() <= 6) {
|
||
|
p_186922_.sort(Comparator.comparingLong(p_186916_ -> {
|
||
|
long i1 = 0L;
|
||
|
|
||
|
for (int j1 = 0; j1 < p_186921_; j1++) {
|
||
|
Climate.Parameter climate$parameter = p_186916_.parameterSpace[j1];
|
||
|
i1 += Math.abs((climate$parameter.min() + climate$parameter.max()) / 2L);
|
||
|
}
|
||
|
|
||
|
return i1;
|
||
|
}));
|
||
|
return new Climate.RTree.SubTree<>(p_186922_);
|
||
|
} else {
|
||
|
long i = Long.MAX_VALUE;
|
||
|
int j = -1;
|
||
|
List<Climate.RTree.SubTree<T>> list = null;
|
||
|
|
||
|
for (int k = 0; k < p_186921_; k++) {
|
||
|
sort(p_186922_, p_186921_, k, false);
|
||
|
List<Climate.RTree.SubTree<T>> list1 = bucketize(p_186922_);
|
||
|
long l = 0L;
|
||
|
|
||
|
for (Climate.RTree.SubTree<T> subtree : list1) {
|
||
|
l += cost(subtree.parameterSpace);
|
||
|
}
|
||
|
|
||
|
if (i > l) {
|
||
|
i = l;
|
||
|
j = k;
|
||
|
list = list1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sort(list, p_186921_, j, true);
|
||
|
return new Climate.RTree.SubTree<>(
|
||
|
list.stream().map(p_186919_ -> build(p_186921_, Arrays.asList(p_186919_.children))).collect(Collectors.toList())
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static <T> void sort(List<? extends Climate.RTree.Node<T>> p_186938_, int p_186939_, int p_186940_, boolean p_186941_) {
|
||
|
Comparator<Climate.RTree.Node<T>> comparator = comparator(p_186940_, p_186941_);
|
||
|
|
||
|
for (int i = 1; i < p_186939_; i++) {
|
||
|
comparator = comparator.thenComparing(comparator((p_186940_ + i) % p_186939_, p_186941_));
|
||
|
}
|
||
|
|
||
|
p_186938_.sort(comparator);
|
||
|
}
|
||
|
|
||
|
private static <T> Comparator<Climate.RTree.Node<T>> comparator(int p_186924_, boolean p_186925_) {
|
||
|
return Comparator.comparingLong(p_186929_ -> {
|
||
|
Climate.Parameter climate$parameter = p_186929_.parameterSpace[p_186924_];
|
||
|
long i = (climate$parameter.min() + climate$parameter.max()) / 2L;
|
||
|
return p_186925_ ? Math.abs(i) : i;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private static <T> List<Climate.RTree.SubTree<T>> bucketize(List<? extends Climate.RTree.Node<T>> p_186945_) {
|
||
|
List<Climate.RTree.SubTree<T>> list = Lists.newArrayList();
|
||
|
List<Climate.RTree.Node<T>> list1 = Lists.newArrayList();
|
||
|
int i = (int)Math.pow(6.0, Math.floor(Math.log(p_186945_.size() - 0.01) / Math.log(6.0)));
|
||
|
|
||
|
for (Climate.RTree.Node<T> node : p_186945_) {
|
||
|
list1.add(node);
|
||
|
if (list1.size() >= i) {
|
||
|
list.add(new Climate.RTree.SubTree<>(list1));
|
||
|
list1 = Lists.newArrayList();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!list1.isEmpty()) {
|
||
|
list.add(new Climate.RTree.SubTree<>(list1));
|
||
|
}
|
||
|
|
||
|
return list;
|
||
|
}
|
||
|
|
||
|
private static long cost(Climate.Parameter[] p_186943_) {
|
||
|
long i = 0L;
|
||
|
|
||
|
for (Climate.Parameter climate$parameter : p_186943_) {
|
||
|
i += Math.abs(climate$parameter.max() - climate$parameter.min());
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
static <T> List<Climate.Parameter> buildParameterSpace(List<? extends Climate.RTree.Node<T>> p_186947_) {
|
||
|
if (p_186947_.isEmpty()) {
|
||
|
throw new IllegalArgumentException("SubTree needs at least one child");
|
||
|
} else {
|
||
|
int i = 7;
|
||
|
List<Climate.Parameter> list = Lists.newArrayList();
|
||
|
|
||
|
for (int j = 0; j < 7; j++) {
|
||
|
list.add(null);
|
||
|
}
|
||
|
|
||
|
for (Climate.RTree.Node<T> node : p_186947_) {
|
||
|
for (int k = 0; k < 7; k++) {
|
||
|
list.set(k, node.parameterSpace[k].span(list.get(k)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return list;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public T search(Climate.TargetPoint p_186931_, Climate.DistanceMetric<T> p_186932_) {
|
||
|
long[] along = p_186931_.toParameterArray();
|
||
|
Climate.RTree.Leaf<T> leaf = this.root.search(along, this.lastResult.get(), p_186932_);
|
||
|
this.lastResult.set(leaf);
|
||
|
return leaf.value;
|
||
|
}
|
||
|
|
||
|
static final class Leaf<T> extends Climate.RTree.Node<T> {
|
||
|
final T value;
|
||
|
|
||
|
Leaf(Climate.ParameterPoint p_186950_, T p_186951_) {
|
||
|
super(p_186950_.parameterSpace());
|
||
|
this.value = p_186951_;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected Climate.RTree.Leaf<T> search(long[] p_186953_, @Nullable Climate.RTree.Leaf<T> p_186954_, Climate.DistanceMetric<T> p_186955_) {
|
||
|
return this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
abstract static class Node<T> {
|
||
|
protected final Climate.Parameter[] parameterSpace;
|
||
|
|
||
|
protected Node(List<Climate.Parameter> p_186958_) {
|
||
|
this.parameterSpace = p_186958_.toArray(new Climate.Parameter[0]);
|
||
|
}
|
||
|
|
||
|
protected abstract Climate.RTree.Leaf<T> search(long[] p_186961_, @Nullable Climate.RTree.Leaf<T> p_186962_, Climate.DistanceMetric<T> p_186963_);
|
||
|
|
||
|
protected long distance(long[] p_186960_) {
|
||
|
long i = 0L;
|
||
|
|
||
|
for (int j = 0; j < 7; j++) {
|
||
|
i += Mth.square(this.parameterSpace[j].distance(p_186960_[j]));
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return Arrays.toString((Object[])this.parameterSpace);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static final class SubTree<T> extends Climate.RTree.Node<T> {
|
||
|
final Climate.RTree.Node<T>[] children;
|
||
|
|
||
|
protected SubTree(List<? extends Climate.RTree.Node<T>> p_186967_) {
|
||
|
this(Climate.RTree.buildParameterSpace(p_186967_), p_186967_);
|
||
|
}
|
||
|
|
||
|
protected SubTree(List<Climate.Parameter> p_186969_, List<? extends Climate.RTree.Node<T>> p_186970_) {
|
||
|
super(p_186969_);
|
||
|
this.children = p_186970_.toArray(new Climate.RTree.Node[0]);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected Climate.RTree.Leaf<T> search(long[] p_186972_, @Nullable Climate.RTree.Leaf<T> p_186973_, Climate.DistanceMetric<T> p_186974_) {
|
||
|
long i = p_186973_ == null ? Long.MAX_VALUE : p_186974_.distance(p_186973_, p_186972_);
|
||
|
Climate.RTree.Leaf<T> leaf = p_186973_;
|
||
|
|
||
|
for (Climate.RTree.Node<T> node : this.children) {
|
||
|
long j = p_186974_.distance(node, p_186972_);
|
||
|
if (i > j) {
|
||
|
Climate.RTree.Leaf<T> leaf1 = node.search(p_186972_, leaf, p_186974_);
|
||
|
long k = node == leaf1 ? j : p_186974_.distance(leaf1, p_186972_);
|
||
|
if (i > k) {
|
||
|
i = k;
|
||
|
leaf = leaf1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return leaf;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public record Sampler(
|
||
|
DensityFunction temperature,
|
||
|
DensityFunction humidity,
|
||
|
DensityFunction continentalness,
|
||
|
DensityFunction erosion,
|
||
|
DensityFunction depth,
|
||
|
DensityFunction weirdness,
|
||
|
List<Climate.ParameterPoint> spawnTarget
|
||
|
) {
|
||
|
public Climate.TargetPoint sample(int p_186975_, int p_186976_, int p_186977_) {
|
||
|
int i = QuartPos.toBlock(p_186975_);
|
||
|
int j = QuartPos.toBlock(p_186976_);
|
||
|
int k = QuartPos.toBlock(p_186977_);
|
||
|
DensityFunction.SinglePointContext densityfunction$singlepointcontext = new DensityFunction.SinglePointContext(i, j, k);
|
||
|
return Climate.target(
|
||
|
(float)this.temperature.compute(densityfunction$singlepointcontext),
|
||
|
(float)this.humidity.compute(densityfunction$singlepointcontext),
|
||
|
(float)this.continentalness.compute(densityfunction$singlepointcontext),
|
||
|
(float)this.erosion.compute(densityfunction$singlepointcontext),
|
||
|
(float)this.depth.compute(densityfunction$singlepointcontext),
|
||
|
(float)this.weirdness.compute(densityfunction$singlepointcontext)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public BlockPos findSpawnPosition() {
|
||
|
return this.spawnTarget.isEmpty() ? BlockPos.ZERO : Climate.findSpawnPosition(this.spawnTarget, this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static class SpawnFinder {
|
||
|
private static final long MAX_RADIUS = 2048L;
|
||
|
Climate.SpawnFinder.Result result;
|
||
|
|
||
|
SpawnFinder(List<Climate.ParameterPoint> p_207872_, Climate.Sampler p_207873_) {
|
||
|
this.result = getSpawnPositionAndFitness(p_207872_, p_207873_, 0, 0);
|
||
|
this.radialSearch(p_207872_, p_207873_, 2048.0F, 512.0F);
|
||
|
this.radialSearch(p_207872_, p_207873_, 512.0F, 32.0F);
|
||
|
}
|
||
|
|
||
|
private void radialSearch(List<Climate.ParameterPoint> p_207875_, Climate.Sampler p_207876_, float p_207877_, float p_207878_) {
|
||
|
float f = 0.0F;
|
||
|
float f1 = p_207878_;
|
||
|
BlockPos blockpos = this.result.location();
|
||
|
|
||
|
while (f1 <= p_207877_) {
|
||
|
int i = blockpos.getX() + (int)(Math.sin(f) * f1);
|
||
|
int j = blockpos.getZ() + (int)(Math.cos(f) * f1);
|
||
|
Climate.SpawnFinder.Result climate$spawnfinder$result = getSpawnPositionAndFitness(p_207875_, p_207876_, i, j);
|
||
|
if (climate$spawnfinder$result.fitness() < this.result.fitness()) {
|
||
|
this.result = climate$spawnfinder$result;
|
||
|
}
|
||
|
|
||
|
f += p_207878_ / f1;
|
||
|
if (f > Math.PI * 2) {
|
||
|
f = 0.0F;
|
||
|
f1 += p_207878_;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static Climate.SpawnFinder.Result getSpawnPositionAndFitness(List<Climate.ParameterPoint> p_207880_, Climate.Sampler p_207881_, int p_207882_, int p_207883_) {
|
||
|
Climate.TargetPoint climate$targetpoint = p_207881_.sample(QuartPos.fromBlock(p_207882_), 0, QuartPos.fromBlock(p_207883_));
|
||
|
Climate.TargetPoint climate$targetpoint1 = new Climate.TargetPoint(
|
||
|
climate$targetpoint.temperature(),
|
||
|
climate$targetpoint.humidity(),
|
||
|
climate$targetpoint.continentalness(),
|
||
|
climate$targetpoint.erosion(),
|
||
|
0L,
|
||
|
climate$targetpoint.weirdness()
|
||
|
);
|
||
|
long i = Long.MAX_VALUE;
|
||
|
|
||
|
for (Climate.ParameterPoint climate$parameterpoint : p_207880_) {
|
||
|
i = Math.min(i, climate$parameterpoint.fitness(climate$targetpoint1));
|
||
|
}
|
||
|
|
||
|
long k = Mth.square(p_207882_) + Mth.square(p_207883_);
|
||
|
long j = i * Mth.square(2048L) + k;
|
||
|
return new Climate.SpawnFinder.Result(new BlockPos(p_207882_, 0, p_207883_), j);
|
||
|
}
|
||
|
|
||
|
record Result(BlockPos location, long fitness) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public record TargetPoint(long temperature, long humidity, long continentalness, long erosion, long depth, long weirdness) {
|
||
|
@VisibleForTesting
|
||
|
protected long[] toParameterArray() {
|
||
|
return new long[]{this.temperature, this.humidity, this.continentalness, this.erosion, this.depth, this.weirdness, 0L};
|
||
|
}
|
||
|
}
|
||
|
}
|