mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Split probe helpers
- Move chunk generation and buffer selection into ProbeChunkGenerator - Move measured-window stage and counter lines into ProbeWindowMetrics - Move hydrology pre-planning into ProbeHydrologyPreplan
This commit is contained in:
1 parent
b6b01c88f5
commit
217ed04f45
5 files changed
+298
-202
No files matched your search
@@ -22,26 +22,20 @@ import art.arcane.iris.pack.datapack.DataVersion;
|
|||||||
import art.arcane.iris.pack.loading.IrisData;
|
import art.arcane.iris.pack.loading.IrisData;
|
||||||
import art.arcane.iris.pack.PackValidationResult;
|
import art.arcane.iris.pack.PackValidationResult;
|
||||||
import art.arcane.iris.pack.PackValidator;
|
import art.arcane.iris.pack.PackValidator;
|
||||||
import art.arcane.iris.generation.context.IrisContext;
|
|
||||||
import art.arcane.iris.generation.runtime.IrisEngine;
|
import art.arcane.iris.generation.runtime.IrisEngine;
|
||||||
import art.arcane.iris.generation.runtime.Engine;
|
import art.arcane.iris.generation.runtime.Engine;
|
||||||
import art.arcane.iris.generation.runtime.EngineAssignedComponent;
|
import art.arcane.iris.generation.runtime.EngineAssignedComponent;
|
||||||
import art.arcane.iris.generation.runtime.EngineEffects;
|
import art.arcane.iris.generation.runtime.EngineEffects;
|
||||||
import art.arcane.iris.generation.runtime.EngineEffectsProvider;
|
import art.arcane.iris.generation.runtime.EngineEffectsProvider;
|
||||||
import art.arcane.iris.generation.runtime.EngineMetrics;
|
|
||||||
import art.arcane.iris.generation.runtime.EnginePlatformHooks;
|
import art.arcane.iris.generation.runtime.EnginePlatformHooks;
|
||||||
import art.arcane.iris.generation.runtime.EngineTarget;
|
import art.arcane.iris.generation.runtime.EngineTarget;
|
||||||
import art.arcane.iris.generation.runtime.EngineWorldManager;
|
import art.arcane.iris.generation.runtime.EngineWorldManager;
|
||||||
import art.arcane.iris.generation.runtime.EngineWorldManagerProvider;
|
import art.arcane.iris.generation.runtime.EngineWorldManagerProvider;
|
||||||
import art.arcane.iris.generation.runtime.GenerationCounter;
|
|
||||||
import art.arcane.iris.generation.runtime.GenerationSessionLease;
|
|
||||||
import art.arcane.iris.generation.runtime.MeteredCache;
|
import art.arcane.iris.generation.runtime.MeteredCache;
|
||||||
import art.arcane.iris.generation.runtime.PreservationRegistry;
|
import art.arcane.iris.generation.runtime.PreservationRegistry;
|
||||||
import art.arcane.iris.configuration.IrisSettings;
|
import art.arcane.iris.configuration.IrisSettings;
|
||||||
import art.arcane.iris.generation.concurrent.MultiBurst;
|
import art.arcane.iris.generation.concurrent.MultiBurst;
|
||||||
import art.arcane.iris.generation.hydrology.HydrologyPlannerSettings;
|
|
||||||
import art.arcane.iris.generation.hydrology.HydrologyTileCache;
|
import art.arcane.iris.generation.hydrology.HydrologyTileCache;
|
||||||
import art.arcane.iris.generation.hydrology.HydrologyTileKey;
|
|
||||||
import art.arcane.iris.generation.hydrology.runtime.IrisHydrologyRuntime;
|
import art.arcane.iris.generation.hydrology.runtime.IrisHydrologyRuntime;
|
||||||
import art.arcane.iris.generation.terrain.IrisDimension;
|
import art.arcane.iris.generation.terrain.IrisDimension;
|
||||||
import art.arcane.iris.world.IrisWorld;
|
import art.arcane.iris.world.IrisWorld;
|
||||||
@@ -53,7 +47,6 @@ import art.arcane.iris.spi.IrisPlatforms;
|
|||||||
import art.arcane.iris.spi.IrisServices;
|
import art.arcane.iris.spi.IrisServices;
|
||||||
import art.arcane.volmlib.nativelib.terrain.NativeBiome;
|
import art.arcane.volmlib.nativelib.terrain.NativeBiome;
|
||||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||||
import art.arcane.volmlib.util.cache.CacheContention;
|
|
||||||
import art.arcane.volmlib.util.hunk.Hunk;
|
import art.arcane.volmlib.util.hunk.Hunk;
|
||||||
import art.arcane.volmlib.util.noise.FractalBillowSimplexNoise;
|
import art.arcane.volmlib.util.noise.FractalBillowSimplexNoise;
|
||||||
|
|
||||||
@@ -72,12 +65,12 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public final class GenerationProbe {
|
public final class GenerationProbe {
|
||||||
private static final List<Throwable> REPORTED = Collections.synchronizedList(new ArrayList<>());
|
private static final List<Throwable> REPORTED = Collections.synchronizedList(new ArrayList<>());
|
||||||
@@ -278,29 +271,6 @@ public final class GenerationProbe {
|
|||||||
TimingSummary measuredTimings, String signature) {
|
TimingSummary measuredTimings, String signature) {
|
||||||
}
|
}
|
||||||
|
|
||||||
record WindowMetrics(Map<String, EngineMetrics.StageTotal> stages, Map<String, Long> counters) {
|
|
||||||
static WindowMetrics capture(Engine engine, boolean counters) {
|
|
||||||
return new WindowMetrics(engine.getMetrics().stageTotals(), counters ? counterValues() : Map.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, Long> counterValues() {
|
|
||||||
Map<String, Long> values = new LinkedHashMap<>();
|
|
||||||
for (GenerationCounter counter : GenerationCounter.values()) {
|
|
||||||
values.put(counter.key(), counter.sum());
|
|
||||||
}
|
|
||||||
values.put("cache_duplicate_computations", CacheContention.duplicateComputations());
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record HydrologyPreplan(int tiles, int tileSize, int publicationRadius, int reachChunks, long elapsedNanos) {
|
|
||||||
String machineLine() {
|
|
||||||
return String.format(Locale.ROOT,
|
|
||||||
"IRIS_GENPROBE_HYDROLOGY_PREPLAN version=1 tiles=%d tile_size=%d publication_radius=%d reach_chunks=%d planned_ms=%.3f",
|
|
||||||
tiles, tileSize, publicationRadius, reachChunks, nanosToMillis(elapsedNanos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record ProbeResult(String status, String dimensionKey, int warmupChunks, int measuredChunks, boolean multicore,
|
record ProbeResult(String status, String dimensionKey, int warmupChunks, int measuredChunks, boolean multicore,
|
||||||
boolean studio,
|
boolean studio,
|
||||||
int successfulChunks, int failedChunks, long engineReadyNanos, long firstChunkNanos,
|
int successfulChunks, int failedChunks, long engineReadyNanos, long firstChunkNanos,
|
||||||
@@ -329,51 +299,6 @@ public final class GenerationProbe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static String stagesLine(WindowMetrics start, WindowMetrics end, int chunks, int threads) {
|
|
||||||
StringBuilder line = new StringBuilder(512);
|
|
||||||
line.append("IRIS_GENPROBE_STAGES version=1 chunks=").append(chunks).append(" threads=").append(threads);
|
|
||||||
for (Map.Entry<String, EngineMetrics.StageTotal> entry : end.stages().entrySet()) {
|
|
||||||
EngineMetrics.StageTotal earlier = start.stages().get(entry.getKey());
|
|
||||||
EngineMetrics.StageTotal window = earlier == null ? entry.getValue() : entry.getValue().since(earlier);
|
|
||||||
line.append(' ').append(entry.getKey()).append('=')
|
|
||||||
.append(String.format(Locale.ROOT, "%.3f", window.millis()));
|
|
||||||
}
|
|
||||||
return line.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String countersLine(WindowMetrics start, WindowMetrics end, int chunks) {
|
|
||||||
StringBuilder line = new StringBuilder(256);
|
|
||||||
line.append("IRIS_GENPROBE_COUNTERS version=1 chunks=").append(chunks);
|
|
||||||
for (Map.Entry<String, Long> entry : end.counters().entrySet()) {
|
|
||||||
long window = entry.getValue() - start.counters().getOrDefault(entry.getKey(), 0L);
|
|
||||||
line.append(' ').append(entry.getKey()).append('=').append(window)
|
|
||||||
.append(' ').append(entry.getKey()).append("_per_chunk=")
|
|
||||||
.append(String.format(Locale.ROOT, "%.1f", chunks == 0 ? 0D : window / (double) chunks));
|
|
||||||
}
|
|
||||||
return line.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<HydrologyTileKey> preplanTiles(ProbeConfiguration configuration, int tileSize, int publicationRadius,
|
|
||||||
int reachChunks) {
|
|
||||||
HydrologyTileCache.PregenerationArea area = pregenerationArea(configuration);
|
|
||||||
long reach = (long) reachChunks * 16L + publicationRadius;
|
|
||||||
int minimumX = Math.toIntExact(Math.floorDiv(area.minimumBlockX() - reach, tileSize)) - 1;
|
|
||||||
int minimumZ = Math.toIntExact(Math.floorDiv(area.minimumBlockZ() - reach, tileSize)) - 1;
|
|
||||||
int maximumX = Math.toIntExact(Math.floorDiv(area.maximumBlockX() + reach, tileSize)) + 1;
|
|
||||||
int maximumZ = Math.toIntExact(Math.floorDiv(area.maximumBlockZ() + reach, tileSize)) + 1;
|
|
||||||
int centerX = Math.floorDiv(area.centerBlockX(), tileSize);
|
|
||||||
int centerZ = Math.floorDiv(area.centerBlockZ(), tileSize);
|
|
||||||
List<HydrologyTileKey> keys = new ArrayList<>((maximumX - minimumX + 1) * (maximumZ - minimumZ + 1));
|
|
||||||
for (int tileZ = minimumZ; tileZ <= maximumZ; tileZ++) {
|
|
||||||
for (int tileX = minimumX; tileX <= maximumX; tileX++) {
|
|
||||||
keys.add(new HydrologyTileKey(tileX, tileZ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keys.sort(Comparator.comparingInt((HydrologyTileKey key) ->
|
|
||||||
Math.max(Math.abs(key.tileX() - centerX), Math.abs(key.tileZ() - centerZ))));
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ProbeConfiguration configuration;
|
ProbeConfiguration configuration;
|
||||||
ProbeOptions options;
|
ProbeOptions options;
|
||||||
@@ -508,7 +433,7 @@ public final class GenerationProbe {
|
|||||||
+ " timeMs=" + String.format(Locale.ROOT, "%.3f", nanosToMillis(engineReadyNanos)));
|
+ " timeMs=" + String.format(Locale.ROOT, "%.3f", nanosToMillis(engineReadyNanos)));
|
||||||
System.out.println("IRIS_GENPROBE_MANTLE version=1 radius=" + engine.getMantle().getRadius()
|
System.out.println("IRIS_GENPROBE_MANTLE version=1 radius=" + engine.getMantle().getRadius()
|
||||||
+ " real_radius=" + engine.getMantle().getRealRadius());
|
+ " real_radius=" + engine.getMantle().getRealRadius());
|
||||||
ProbeGenerator generator = new ProbeGenerator(engine, router, options.productionBuffers());
|
ProbeChunkGenerator generator = new ProbeChunkGenerator(engine, router, options.productionBuffers());
|
||||||
long nativeSamplesBefore = FractalBillowSimplexNoise.nativeSampleCount();
|
long nativeSamplesBefore = FractalBillowSimplexNoise.nativeSampleCount();
|
||||||
GenerationResult generation = generateWithProfile(generator, configuration, options);
|
GenerationResult generation = generateWithProfile(generator, configuration, options);
|
||||||
verifyBackend(nativeSamplesBefore);
|
verifyBackend(nativeSamplesBefore);
|
||||||
@@ -598,7 +523,7 @@ public final class GenerationProbe {
|
|||||||
System.out.println("[genprobe] offline pack validation: PASS");
|
System.out.println("[genprobe] offline pack validation: PASS");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GenerationResult generateWithProfile(ProbeGenerator generator, ProbeConfiguration configuration,
|
private static GenerationResult generateWithProfile(ProbeChunkGenerator generator, ProbeConfiguration configuration,
|
||||||
ProbeOptions options) throws Exception {
|
ProbeOptions options) throws Exception {
|
||||||
Engine engine = generator.engine();
|
Engine engine = generator.engine();
|
||||||
if (!options.pregenProfile()) {
|
if (!options.pregenProfile()) {
|
||||||
@@ -621,48 +546,10 @@ public final class GenerationProbe {
|
|||||||
if (!options.hydrologyPreplan()) {
|
if (!options.hydrologyPreplan()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrisHydrologyRuntime hydrology = engine.getComplex().getHydrologyRuntime();
|
Optional<ProbeHydrologyPreplan> preplan = ProbeHydrologyPreplan.run(engine, configuration);
|
||||||
if (hydrology == null) {
|
|
||||||
System.out.println("IRIS_GENPROBE_HYDROLOGY_PREPLAN version=1 tiles=0 skipped=no-hydrology");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
HydrologyPlannerSettings settings = hydrology.settings();
|
|
||||||
int tileSize = settings.routing().tileSize();
|
|
||||||
int publicationRadius = settings.publicationRadius();
|
|
||||||
int reachChunks = Math.max(engine.getMantle().getRadius(), engine.getMantle().getRealRadius());
|
|
||||||
List<HydrologyTileKey> keys = preplanTiles(configuration, tileSize, publicationRadius, reachChunks);
|
|
||||||
long started = System.nanoTime();
|
|
||||||
ExecutorService executor = Executors.newFixedThreadPool(Math.min(keys.size(), 4));
|
|
||||||
try {
|
|
||||||
List<Future<?>> plans = new ArrayList<>(keys.size());
|
|
||||||
for (HydrologyTileKey key : keys) {
|
|
||||||
plans.add(executor.submit(() -> hydrology.tile(key)));
|
|
||||||
}
|
|
||||||
for (Future<?> plan : plans) {
|
|
||||||
awaitPlan(plan);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
executor.shutdown();
|
|
||||||
}
|
|
||||||
HydrologyPreplan preplan = new HydrologyPreplan(keys.size(), tileSize, publicationRadius, reachChunks,
|
|
||||||
System.nanoTime() - started);
|
|
||||||
printDistinctCauses("hydrology preplan reported errors", drainReported());
|
printDistinctCauses("hydrology preplan reported errors", drainReported());
|
||||||
System.out.println(preplan.machineLine());
|
System.out.println(preplan.map(ProbeHydrologyPreplan::machineLine)
|
||||||
}
|
.orElse("IRIS_GENPROBE_HYDROLOGY_PREPLAN version=1 tiles=0 skipped=no-hydrology"));
|
||||||
|
|
||||||
private static void awaitPlan(Future<?> plan) throws Exception {
|
|
||||||
try {
|
|
||||||
plan.get();
|
|
||||||
} catch (ExecutionException failure) {
|
|
||||||
Throwable cause = failure.getCause();
|
|
||||||
if (cause instanceof Error error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
if (cause instanceof Exception exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException(cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HydrologyTileCache.PregenerationArea pregenerationArea(ProbeConfiguration configuration) {
|
static HydrologyTileCache.PregenerationArea pregenerationArea(ProbeConfiguration configuration) {
|
||||||
@@ -708,7 +595,7 @@ public final class GenerationProbe {
|
|||||||
return Math.atan2(coordinate.z() - centerChunkZ, coordinate.x() - centerChunkX);
|
return Math.atan2(coordinate.z() - centerChunkZ, coordinate.x() - centerChunkX);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GenerationResult generate(ProbeGenerator generator, ProbeConfiguration configuration,
|
private static GenerationResult generate(ProbeChunkGenerator generator, ProbeConfiguration configuration,
|
||||||
ProbeOptions options) throws Exception {
|
ProbeOptions options) throws Exception {
|
||||||
Engine engine = generator.engine();
|
Engine engine = generator.engine();
|
||||||
int totalChunks = configuration.warmupChunks() + configuration.measuredChunks();
|
int totalChunks = configuration.warmupChunks() + configuration.measuredChunks();
|
||||||
@@ -727,16 +614,16 @@ public final class GenerationProbe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateSequential(ProbeGenerator generator, ProbeConfiguration configuration,
|
private static void generateSequential(ProbeChunkGenerator generator, ProbeConfiguration configuration,
|
||||||
ProbeOptions options, List<ChunkCoordinate> coordinates,
|
ProbeOptions options, List<ChunkCoordinate> coordinates,
|
||||||
OutcomeSink sink) throws IOException {
|
OutcomeSink sink) throws IOException {
|
||||||
int totalChunks = coordinates.size();
|
int totalChunks = coordinates.size();
|
||||||
long measuredStartEpochMillis = 0L;
|
long measuredStartEpochMillis = 0L;
|
||||||
WindowMetrics measuredStart = null;
|
ProbeWindowMetrics measuredStart = null;
|
||||||
for (int index = 0; index < totalChunks; index++) {
|
for (int index = 0; index < totalChunks; index++) {
|
||||||
if (index == configuration.warmupChunks()) {
|
if (index == configuration.warmupChunks()) {
|
||||||
measuredStartEpochMillis = System.currentTimeMillis();
|
measuredStartEpochMillis = System.currentTimeMillis();
|
||||||
measuredStart = WindowMetrics.capture(generator.engine(), options.counters());
|
measuredStart = ProbeWindowMetrics.capture(generator.engine(), options.counters());
|
||||||
}
|
}
|
||||||
drainReported();
|
drainReported();
|
||||||
ChunkOutcome outcome = generator.generate(index, coordinates.get(index), configuration.multicore());
|
ChunkOutcome outcome = generator.generate(index, coordinates.get(index), configuration.multicore());
|
||||||
@@ -745,14 +632,15 @@ public final class GenerationProbe {
|
|||||||
printProgress(configuration, index + 1, totalChunks);
|
printProgress(configuration, index + 1, totalChunks);
|
||||||
}
|
}
|
||||||
printWindow(measuredStartEpochMillis, System.currentTimeMillis());
|
printWindow(measuredStartEpochMillis, System.currentTimeMillis());
|
||||||
printWindowMetrics(measuredStart, WindowMetrics.capture(generator.engine(), options.counters()),
|
printWindowMetrics(measuredStart, ProbeWindowMetrics.capture(generator.engine(), options.counters()),
|
||||||
configuration.measuredChunks(), options);
|
configuration.measuredChunks(), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printWindowMetrics(WindowMetrics start, WindowMetrics end, int chunks, ProbeOptions options) {
|
private static void printWindowMetrics(ProbeWindowMetrics start, ProbeWindowMetrics end, int chunks,
|
||||||
System.out.println(stagesLine(start, end, chunks, options.threads()));
|
ProbeOptions options) {
|
||||||
|
System.out.println(ProbeWindowMetrics.stagesLine(start, end, chunks, options.threads()));
|
||||||
if (options.counters()) {
|
if (options.counters()) {
|
||||||
System.out.println(countersLine(start, end, chunks));
|
System.out.println(ProbeWindowMetrics.countersLine(start, end, chunks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,7 +649,7 @@ public final class GenerationProbe {
|
|||||||
+ " end_epoch_ms=" + endEpochMillis);
|
+ " end_epoch_ms=" + endEpochMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateParallel(ProbeGenerator generator, ProbeConfiguration configuration,
|
private static void generateParallel(ProbeChunkGenerator generator, ProbeConfiguration configuration,
|
||||||
ProbeOptions options, List<ChunkCoordinate> coordinates,
|
ProbeOptions options, List<ChunkCoordinate> coordinates,
|
||||||
OutcomeSink sink) throws Exception {
|
OutcomeSink sink) throws Exception {
|
||||||
ChunkOutcome[] outcomes = new ChunkOutcome[coordinates.size()];
|
ChunkOutcome[] outcomes = new ChunkOutcome[coordinates.size()];
|
||||||
@@ -784,13 +672,13 @@ public final class GenerationProbe {
|
|||||||
|
|
||||||
List<Integer> measured = spiralOrder(coordinates, configuration.warmupChunks(),
|
List<Integer> measured = spiralOrder(coordinates, configuration.warmupChunks(),
|
||||||
configuration.centerChunkX(), configuration.centerChunkZ());
|
configuration.centerChunkX(), configuration.centerChunkZ());
|
||||||
WindowMetrics measuredStart = WindowMetrics.capture(generator.engine(), options.counters());
|
ProbeWindowMetrics measuredStart = ProbeWindowMetrics.capture(generator.engine(), options.counters());
|
||||||
long measuredStartEpochMillis = System.currentTimeMillis();
|
long measuredStartEpochMillis = System.currentTimeMillis();
|
||||||
long measuredStarted = System.nanoTime();
|
long measuredStarted = System.nanoTime();
|
||||||
runPhase(executor, generator, configuration, coordinates, measured, outcomes);
|
runPhase(executor, generator, configuration, coordinates, measured, outcomes);
|
||||||
measuredWallNanos = System.nanoTime() - measuredStarted;
|
measuredWallNanos = System.nanoTime() - measuredStarted;
|
||||||
printWindow(measuredStartEpochMillis, System.currentTimeMillis());
|
printWindow(measuredStartEpochMillis, System.currentTimeMillis());
|
||||||
printWindowMetrics(measuredStart, WindowMetrics.capture(generator.engine(), options.counters()),
|
printWindowMetrics(measuredStart, ProbeWindowMetrics.capture(generator.engine(), options.counters()),
|
||||||
configuration.measuredChunks(), options);
|
configuration.measuredChunks(), options);
|
||||||
unattributed.addAll(drainReported());
|
unattributed.addAll(drainReported());
|
||||||
System.out.println("[genprobe] measured progress: " + configuration.measuredChunks() + "/"
|
System.out.println("[genprobe] measured progress: " + configuration.measuredChunks() + "/"
|
||||||
@@ -825,7 +713,7 @@ public final class GenerationProbe {
|
|||||||
System.out.println(throughput.machineLine());
|
System.out.println(throughput.machineLine());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void runPhase(ExecutorService executor, ProbeGenerator generator,
|
private static void runPhase(ExecutorService executor, ProbeChunkGenerator generator,
|
||||||
ProbeConfiguration configuration, List<ChunkCoordinate> coordinates,
|
ProbeConfiguration configuration, List<ChunkCoordinate> coordinates,
|
||||||
List<Integer> order, ChunkOutcome[] outcomes) throws Exception {
|
List<Integer> order, ChunkOutcome[] outcomes) throws Exception {
|
||||||
List<Future<ChunkOutcome>> futures = new ArrayList<>(order.size());
|
List<Future<ChunkOutcome>> futures = new ArrayList<>(order.size());
|
||||||
@@ -1057,72 +945,6 @@ public final class GenerationProbe {
|
|||||||
return nanos / 1_000_000D;
|
return nanos / 1_000_000D;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class ProbeGenerator {
|
|
||||||
private final Engine engine;
|
|
||||||
private final GenerationHistoryRuntimeRouter router;
|
|
||||||
private final boolean productionBuffers;
|
|
||||||
private final AtomicInteger expandedBiomeHunks = new AtomicInteger();
|
|
||||||
|
|
||||||
ProbeGenerator(Engine engine, GenerationHistoryRuntimeRouter router, boolean productionBuffers) {
|
|
||||||
this.engine = engine;
|
|
||||||
this.router = router;
|
|
||||||
this.productionBuffers = productionBuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine engine() {
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
int expandedBiomeHunks() {
|
|
||||||
return expandedBiomeHunks.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkOutcome generate(int index, ChunkCoordinate coordinate, boolean multicore) {
|
|
||||||
int height = engine.getTarget().getHeight();
|
|
||||||
List<Throwable> failures = new ArrayList<>();
|
|
||||||
Hunk<NativeBlockState> blocks = newBlocks(height);
|
|
||||||
Hunk<NativeBiome> biomes = newBiomes(height);
|
|
||||||
long started = System.nanoTime();
|
|
||||||
try {
|
|
||||||
generateInto(coordinate.x() << 4, coordinate.z() << 4, blocks, biomes, multicore);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
failures.add(e);
|
|
||||||
}
|
|
||||||
long elapsed = System.nanoTime() - started;
|
|
||||||
if (biomes instanceof ProductionBiomeHunk production && production.expanded()) {
|
|
||||||
expandedBiomeHunks.incrementAndGet();
|
|
||||||
}
|
|
||||||
return new ChunkOutcome(index, coordinate, elapsed, blocks, biomes, failures);
|
|
||||||
}
|
|
||||||
|
|
||||||
Hunk<NativeBlockState> newBlocks(int height) {
|
|
||||||
return productionBuffers ? new ProductionBlockHunk(height) : Hunk.newArrayHunk(16, height, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
Hunk<NativeBiome> newBiomes(int height) {
|
|
||||||
return productionBuffers ? new ProductionBiomeHunk(height, ProbeGenerator::plainsBiome)
|
|
||||||
: Hunk.newArrayHunk(16, height, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateInto(int blockX, int blockZ, Hunk<NativeBlockState> blocks, Hunk<NativeBiome> biomes,
|
|
||||||
boolean multicore) throws Exception {
|
|
||||||
if (router == null) {
|
|
||||||
engine.generate(blockX, blockZ, blocks, biomes, multicore);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try (GenerationHistoryRuntimeRouter.CoordinateScope historyScope = router.openCoordinateScope(blockX, blockZ);
|
|
||||||
GenerationSessionLease lease = engine.acquireGenerationLease("probe_terrain_stage");
|
|
||||||
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
|
||||||
engine.generate(blockX, blockZ, blocks, biomes, multicore);
|
|
||||||
historyScope.claimGeneratedSemantics();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static NativeBiome plainsBiome() {
|
|
||||||
return IrisPlatforms.get().registries().biome("minecraft:plains");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class OutcomeSink implements AutoCloseable {
|
private static final class OutcomeSink implements AutoCloseable {
|
||||||
private final MessageDigest signature = sha256();
|
private final MessageDigest signature = sha256();
|
||||||
private final List<Long> measuredTimings;
|
private final List<Long> measuredTimings;
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Servers
|
||||||
|
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.probe;
|
||||||
|
|
||||||
|
import art.arcane.iris.generation.context.IrisContext;
|
||||||
|
import art.arcane.iris.generation.runtime.Engine;
|
||||||
|
import art.arcane.iris.generation.runtime.GenerationSessionLease;
|
||||||
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
|
import art.arcane.iris.world.history.GenerationHistoryRuntimeRouter;
|
||||||
|
import art.arcane.volmlib.nativelib.terrain.NativeBiome;
|
||||||
|
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||||
|
import art.arcane.volmlib.util.hunk.Hunk;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
final class ProbeChunkGenerator {
|
||||||
|
private final Engine engine;
|
||||||
|
private final GenerationHistoryRuntimeRouter router;
|
||||||
|
private final boolean productionBuffers;
|
||||||
|
private final AtomicInteger expandedBiomeHunks = new AtomicInteger();
|
||||||
|
|
||||||
|
ProbeChunkGenerator(Engine engine, GenerationHistoryRuntimeRouter router, boolean productionBuffers) {
|
||||||
|
this.engine = engine;
|
||||||
|
this.router = router;
|
||||||
|
this.productionBuffers = productionBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine engine() {
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expandedBiomeHunks() {
|
||||||
|
return expandedBiomeHunks.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerationProbe.ChunkOutcome generate(int index, GenerationProbe.ChunkCoordinate coordinate, boolean multicore) {
|
||||||
|
int height = engine.getTarget().getHeight();
|
||||||
|
List<Throwable> failures = new ArrayList<>();
|
||||||
|
Hunk<NativeBlockState> blocks = newBlocks(height);
|
||||||
|
Hunk<NativeBiome> biomes = newBiomes(height);
|
||||||
|
long started = System.nanoTime();
|
||||||
|
try {
|
||||||
|
generateInto(coordinate.x() << 4, coordinate.z() << 4, blocks, biomes, multicore);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
failures.add(e);
|
||||||
|
}
|
||||||
|
long elapsed = System.nanoTime() - started;
|
||||||
|
if (biomes instanceof ProductionBiomeHunk production && production.expanded()) {
|
||||||
|
expandedBiomeHunks.incrementAndGet();
|
||||||
|
}
|
||||||
|
return new GenerationProbe.ChunkOutcome(index, coordinate, elapsed, blocks, biomes, failures);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Hunk<NativeBlockState> newBlocks(int height) {
|
||||||
|
return productionBuffers ? new ProductionBlockHunk(height) : Hunk.newArrayHunk(16, height, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Hunk<NativeBiome> newBiomes(int height) {
|
||||||
|
return productionBuffers ? new ProductionBiomeHunk(height, ProbeChunkGenerator::plainsBiome)
|
||||||
|
: Hunk.newArrayHunk(16, height, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateInto(int blockX, int blockZ, Hunk<NativeBlockState> blocks, Hunk<NativeBiome> biomes,
|
||||||
|
boolean multicore) throws Exception {
|
||||||
|
if (router == null) {
|
||||||
|
engine.generate(blockX, blockZ, blocks, biomes, multicore);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try (GenerationHistoryRuntimeRouter.CoordinateScope historyScope = router.openCoordinateScope(blockX, blockZ);
|
||||||
|
GenerationSessionLease lease = engine.acquireGenerationLease("probe_terrain_stage");
|
||||||
|
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
||||||
|
engine.generate(blockX, blockZ, blocks, biomes, multicore);
|
||||||
|
historyScope.claimGeneratedSemantics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NativeBiome plainsBiome() {
|
||||||
|
return IrisPlatforms.get().registries().biome("minecraft:plains");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Servers
|
||||||
|
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.probe;
|
||||||
|
|
||||||
|
import art.arcane.iris.generation.hydrology.HydrologyPlannerSettings;
|
||||||
|
import art.arcane.iris.generation.hydrology.HydrologyTileCache;
|
||||||
|
import art.arcane.iris.generation.hydrology.HydrologyTileKey;
|
||||||
|
import art.arcane.iris.generation.hydrology.runtime.IrisHydrologyRuntime;
|
||||||
|
import art.arcane.iris.generation.runtime.Engine;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
record ProbeHydrologyPreplan(int tiles, int tileSize, int publicationRadius, int reachChunks, long elapsedNanos) {
|
||||||
|
private static final int PLANNING_THREADS = 4;
|
||||||
|
|
||||||
|
static Optional<ProbeHydrologyPreplan> run(Engine engine, GenerationProbe.ProbeConfiguration configuration)
|
||||||
|
throws Exception {
|
||||||
|
IrisHydrologyRuntime hydrology = engine.getComplex().getHydrologyRuntime();
|
||||||
|
if (hydrology == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
HydrologyPlannerSettings settings = hydrology.settings();
|
||||||
|
int tileSize = settings.routing().tileSize();
|
||||||
|
int publicationRadius = settings.publicationRadius();
|
||||||
|
int reachChunks = Math.max(engine.getMantle().getRadius(), engine.getMantle().getRealRadius());
|
||||||
|
List<HydrologyTileKey> keys = tiles(configuration, tileSize, publicationRadius, reachChunks);
|
||||||
|
long started = System.nanoTime();
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(Math.min(keys.size(), PLANNING_THREADS));
|
||||||
|
try {
|
||||||
|
List<Future<?>> plans = new ArrayList<>(keys.size());
|
||||||
|
for (HydrologyTileKey key : keys) {
|
||||||
|
plans.add(executor.submit(() -> hydrology.tile(key)));
|
||||||
|
}
|
||||||
|
for (Future<?> plan : plans) {
|
||||||
|
await(plan);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
return Optional.of(new ProbeHydrologyPreplan(keys.size(), tileSize, publicationRadius, reachChunks,
|
||||||
|
System.nanoTime() - started));
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<HydrologyTileKey> tiles(GenerationProbe.ProbeConfiguration configuration, int tileSize,
|
||||||
|
int publicationRadius, int reachChunks) {
|
||||||
|
HydrologyTileCache.PregenerationArea area = GenerationProbe.pregenerationArea(configuration);
|
||||||
|
long reach = (long) reachChunks * 16L + publicationRadius;
|
||||||
|
int minimumX = Math.toIntExact(Math.floorDiv(area.minimumBlockX() - reach, tileSize)) - 1;
|
||||||
|
int minimumZ = Math.toIntExact(Math.floorDiv(area.minimumBlockZ() - reach, tileSize)) - 1;
|
||||||
|
int maximumX = Math.toIntExact(Math.floorDiv(area.maximumBlockX() + reach, tileSize)) + 1;
|
||||||
|
int maximumZ = Math.toIntExact(Math.floorDiv(area.maximumBlockZ() + reach, tileSize)) + 1;
|
||||||
|
int centerX = Math.floorDiv(area.centerBlockX(), tileSize);
|
||||||
|
int centerZ = Math.floorDiv(area.centerBlockZ(), tileSize);
|
||||||
|
List<HydrologyTileKey> keys = new ArrayList<>((maximumX - minimumX + 1) * (maximumZ - minimumZ + 1));
|
||||||
|
for (int tileZ = minimumZ; tileZ <= maximumZ; tileZ++) {
|
||||||
|
for (int tileX = minimumX; tileX <= maximumX; tileX++) {
|
||||||
|
keys.add(new HydrologyTileKey(tileX, tileZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keys.sort(Comparator.comparingInt((HydrologyTileKey key) ->
|
||||||
|
Math.max(Math.abs(key.tileX() - centerX), Math.abs(key.tileZ() - centerZ))));
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
String machineLine() {
|
||||||
|
return String.format(Locale.ROOT,
|
||||||
|
"IRIS_GENPROBE_HYDROLOGY_PREPLAN version=1 tiles=%d tile_size=%d publication_radius=%d reach_chunks=%d planned_ms=%.3f",
|
||||||
|
tiles, tileSize, publicationRadius, reachChunks, elapsedNanos / 1_000_000D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void await(Future<?> plan) throws Exception {
|
||||||
|
try {
|
||||||
|
plan.get();
|
||||||
|
} catch (ExecutionException failure) {
|
||||||
|
Throwable cause = failure.getCause();
|
||||||
|
if (cause instanceof Error error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
if (cause instanceof Exception exception) {
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Servers
|
||||||
|
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.probe;
|
||||||
|
|
||||||
|
import art.arcane.iris.generation.runtime.Engine;
|
||||||
|
import art.arcane.iris.generation.runtime.EngineMetrics;
|
||||||
|
import art.arcane.iris.generation.runtime.GenerationCounter;
|
||||||
|
import art.arcane.volmlib.util.cache.CacheContention;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
record ProbeWindowMetrics(Map<String, EngineMetrics.StageTotal> stages, Map<String, Long> counters) {
|
||||||
|
static ProbeWindowMetrics capture(Engine engine, boolean counters) {
|
||||||
|
return new ProbeWindowMetrics(engine.getMetrics().stageTotals(), counters ? counterValues() : Map.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
static String stagesLine(ProbeWindowMetrics start, ProbeWindowMetrics end, int chunks, int threads) {
|
||||||
|
StringBuilder line = new StringBuilder(512);
|
||||||
|
line.append("IRIS_GENPROBE_STAGES version=1 chunks=").append(chunks).append(" threads=").append(threads);
|
||||||
|
for (Map.Entry<String, EngineMetrics.StageTotal> entry : end.stages().entrySet()) {
|
||||||
|
EngineMetrics.StageTotal earlier = start.stages().get(entry.getKey());
|
||||||
|
EngineMetrics.StageTotal window = earlier == null ? entry.getValue() : entry.getValue().since(earlier);
|
||||||
|
line.append(' ').append(entry.getKey()).append('=')
|
||||||
|
.append(String.format(Locale.ROOT, "%.3f", window.millis()));
|
||||||
|
}
|
||||||
|
return line.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String countersLine(ProbeWindowMetrics start, ProbeWindowMetrics end, int chunks) {
|
||||||
|
StringBuilder line = new StringBuilder(256);
|
||||||
|
line.append("IRIS_GENPROBE_COUNTERS version=1 chunks=").append(chunks);
|
||||||
|
for (Map.Entry<String, Long> entry : end.counters().entrySet()) {
|
||||||
|
long window = entry.getValue() - start.counters().getOrDefault(entry.getKey(), 0L);
|
||||||
|
line.append(' ').append(entry.getKey()).append('=').append(window)
|
||||||
|
.append(' ').append(entry.getKey()).append("_per_chunk=")
|
||||||
|
.append(String.format(Locale.ROOT, "%.1f", chunks == 0 ? 0D : window / (double) chunks));
|
||||||
|
}
|
||||||
|
return line.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Long> counterValues() {
|
||||||
|
Map<String, Long> values = new LinkedHashMap<>();
|
||||||
|
for (GenerationCounter counter : GenerationCounter.values()) {
|
||||||
|
values.put(counter.key(), counter.sum());
|
||||||
|
}
|
||||||
|
values.put("cache_duplicate_computations", CacheContention.duplicateComputations());
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -171,8 +171,8 @@ public final class GenerationProbeTest {
|
|||||||
after.put("total", new EngineMetrics.StageTotal(350.25D, 20L));
|
after.put("total", new EngineMetrics.StageTotal(350.25D, 20L));
|
||||||
after.put("context.prefill.height", new EngineMetrics.StageTotal(12.5D, 10L));
|
after.put("context.prefill.height", new EngineMetrics.StageTotal(12.5D, 10L));
|
||||||
|
|
||||||
String line = GenerationProbe.stagesLine(new GenerationProbe.WindowMetrics(before, Map.of()),
|
String line = ProbeWindowMetrics.stagesLine(new ProbeWindowMetrics(before, Map.of()),
|
||||||
new GenerationProbe.WindowMetrics(after, Map.of()), 10, 1);
|
new ProbeWindowMetrics(after, Map.of()), 10, 1);
|
||||||
|
|
||||||
assertEquals("IRIS_GENPROBE_STAGES version=1 chunks=10 threads=1 total=250.250 context.prefill.height=12.500", line);
|
assertEquals("IRIS_GENPROBE_STAGES version=1 chunks=10 threads=1 total=250.250 context.prefill.height=12.500", line);
|
||||||
}
|
}
|
||||||
@@ -186,8 +186,8 @@ public final class GenerationProbeTest {
|
|||||||
after.put("generator_evaluations", 5_000L);
|
after.put("generator_evaluations", 5_000L);
|
||||||
after.put("corner_starcasts", 330L);
|
after.put("corner_starcasts", 330L);
|
||||||
|
|
||||||
String line = GenerationProbe.countersLine(new GenerationProbe.WindowMetrics(Map.of(), before),
|
String line = ProbeWindowMetrics.countersLine(new ProbeWindowMetrics(Map.of(), before),
|
||||||
new GenerationProbe.WindowMetrics(Map.of(), after), 2);
|
new ProbeWindowMetrics(Map.of(), after), 2);
|
||||||
|
|
||||||
assertEquals("IRIS_GENPROBE_COUNTERS version=1 chunks=2 generator_evaluations=4000"
|
assertEquals("IRIS_GENPROBE_COUNTERS version=1 chunks=2 generator_evaluations=4000"
|
||||||
+ " generator_evaluations_per_chunk=2000.0 corner_starcasts=330 corner_starcasts_per_chunk=165.0", line);
|
+ " generator_evaluations_per_chunk=2000.0 corner_starcasts=330 corner_starcasts_per_chunk=165.0", line);
|
||||||
@@ -200,7 +200,7 @@ public final class GenerationProbeTest {
|
|||||||
int tileSize = 512;
|
int tileSize = 512;
|
||||||
int publicationRadius = 96;
|
int publicationRadius = 96;
|
||||||
int reachChunks = 13;
|
int reachChunks = 13;
|
||||||
List<HydrologyTileKey> keys = GenerationProbe.preplanTiles(configuration, tileSize, publicationRadius, reachChunks);
|
List<HydrologyTileKey> keys = ProbeHydrologyPreplan.tiles(configuration, tileSize, publicationRadius, reachChunks);
|
||||||
Set<HydrologyTileKey> planned = new HashSet<>(keys);
|
Set<HydrologyTileKey> planned = new HashSet<>(keys);
|
||||||
|
|
||||||
assertEquals(keys.size(), planned.size());
|
assertEquals(keys.size(), planned.size());
|
||||||
|
|||||||
Reference in new issue
Block a user