Limit early owner drafts in pregen

- Pregeneration scope limits the lower-rank neighbour drafts an owner starts early to tiles the area composes from
- Undemanded ring drafts (and the early neighbours they started) are no longer computed; demanded ones still resolve on demand
- r2000 tile set: 80 -> 54 drafts, planning CPU -32%, plans identical
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-28 13:58:58 -04:00
1 parent 08353e3bdd
commit 0ee0f62b9d
4 files changed
+92 -3

No files matched your search

@@ -28,6 +28,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.function.Predicate;
public final class HydrologyPlanner {
static final int ROUTING_CONTEXT_CACHE_SIZE = 64;
@@ -64,6 +65,7 @@ public final class HydrologyPlanner {
final HydrologySegmentBuilder segments;
final HydrologyFeatureSitePlanner featureSites;
final HydrologyRegionalPlanner regional;
private volatile Predicate<HydrologyTileKey> earlyOwnerScope;
public HydrologyPlanner(long worldSeed, HydrologyPlannerSettings settings, HydrologyTerrainSampler sampler) {
this(
@@ -244,6 +246,15 @@ public final class HydrologyPlanner {
return List.copyOf(unique);
}
/**
* Limits the lower-rank neighbour drafts an owner starts before its admission demands them to the
* tiles the scope accepts; null starts all of them. A neighbour that no admission demands and
* nothing plans is a draft computed for nothing, and so are the early neighbours it starts itself.
*/
void limitEarlyOwners(Predicate<HydrologyTileKey> scope) {
earlyOwnerScope = scope;
}
void clearOwnerDrafts() {
resolvedOwners.invalidateAll();
regional.clear();
@@ -751,6 +762,7 @@ public final class HydrologyPlanner {
return;
}
int radius = settings.crossTileColorPeriod() - 1;
Predicate<HydrologyTileKey> scope = earlyOwnerScope;
ArrayList<HydrologyTileKey> candidates = new ArrayList<>();
for (long tileZ = (long) ownerKey.tileZ() - radius; tileZ <= (long) ownerKey.tileZ() + radius; tileZ++) {
for (long tileX = (long) ownerKey.tileX() - radius; tileX <= (long) ownerKey.tileX() + radius; tileX++) {
@@ -759,7 +771,8 @@ public final class HydrologyPlanner {
continue;
}
HydrologyTileKey key = new HydrologyTileKey((int) tileX, (int) tileZ);
if (crossTile.ownerColorRank(key) >= ownerRank || preparedOwners.containsKey(key)
if (crossTile.ownerColorRank(key) >= ownerRank || scope != null && !scope.test(key)
|| preparedOwners.containsKey(key)
|| resolvedOwners.getIfPresent(key) != null || resolvingOwners.containsKey(key)) {
continue;
}
@@ -690,7 +690,7 @@ public final class HydrologyTileCache implements AutoCloseable {
tileCoordinate(Math.addExact(area.maximumBlockZ(), publicationRadius), tileSize));
List<HydrologyTileKey> keys = nearestFirst(required, tileCoordinate(area.centerBlockX(), tileSize),
tileCoordinate(area.centerBlockZ(), tileSize), MAXIMUM_PREGENERATION_TILES);
PregenerationScope scope = new PregenerationScope(bounds);
PregenerationScope scope = new PregenerationScope(bounds, required);
try {
enqueuePrefetchArea(keys, scope);
return scope;
@@ -1082,6 +1082,7 @@ public final class HydrologyTileCache implements AutoCloseable {
scope.previousNeighbourPrefetch = pregenerationScope == null
? neighbourPrefetchEnabled : pregenerationScope.previousNeighbourPrefetch;
pregenerationScope = scope;
planner.limitEarlyOwners(scope.required::contains);
prefetchQueue.removeIf(key -> {
if (!area.contains(key)) {
queuedPrefetches.remove(key);
@@ -1619,12 +1620,19 @@ public final class HydrologyTileCache implements AutoCloseable {
}
}
/**
* Speculative planning during a pregeneration: tiles inside {@code bounds} may be planned ahead of
* generation, and owner drafts start their lower-rank neighbours early only inside {@code required},
* the tiles the area composes from.
*/
public final class PregenerationScope implements AutoCloseable {
private final TileBounds bounds;
private final TileBounds required;
private boolean previousNeighbourPrefetch;
private PregenerationScope(TileBounds bounds) {
private PregenerationScope(TileBounds bounds, TileBounds required) {
this.bounds = bounds;
this.required = required;
}
@Override
@@ -1634,6 +1642,7 @@ public final class HydrologyTileCache implements AutoCloseable {
return;
}
pregenerationScope = null;
planner.limitEarlyOwners(null);
neighbourPrefetchEnabled = previousNeighbourPrefetch;
prefetchQueue.clear();
queuedPrefetches.clear();