use of carpet.fakes.ChunkHolderInterface in project fabric-carpet by gnembon.
the class ChunkMap_scarpetChunkCreationMixin method regenerateChunkRegion.
@Override
public Map<String, Integer> regenerateChunkRegion(final List<ChunkPos> requestedChunksList) {
final Object2IntMap<String> report = new Object2IntOpenHashMap<>();
final Set<ChunkPos> requestedChunks = new HashSet<>(requestedChunksList);
// Load requested chunks
final Set<ChunkPos> existingChunks = this.loadExistingChunks(requestedChunks, report);
// Finish pending generation stages
// This ensures that no generation events will be put back on the main thread after the chunks have been deleted
final Set<ChunkAccess> affectedChunks = new HashSet<>();
for (final ChunkPos pos : existingChunks) affectedChunks.add(this.getCurrentChunk(pos));
report.put("affected_chunks", affectedChunks.size());
// Load neighbors for light removal
final Set<ChunkPos> neighbors = new HashSet<>();
for (final ChunkAccess chunk : affectedChunks) {
final ChunkPos pos = chunk.getPos();
for (int x = -1; x <= 1; ++x) for (int z = -1; z <= 1; ++z) if (x != 0 || z != 0) {
final ChunkPos nPos = new ChunkPos(pos.x + x, pos.z + z);
if (!requestedChunks.contains(nPos))
neighbors.add(nPos);
}
}
this.loadExistingChunks(neighbors);
// Determine affected neighbors
final Set<ChunkAccess> affectedNeighbors = new HashSet<>();
for (final ChunkPos pos : neighbors) {
final ChunkAccess chunk = this.getCurrentChunk(pos);
if (chunk.getStatus().isOrAfter(ChunkStatus.LIGHT.getParent()))
affectedNeighbors.add(chunk);
}
for (final ChunkAccess chunk : affectedChunks) {
final ChunkPos pos = chunk.getPos();
// remove entities
long longPos = pos.toLong();
if (this.entitiesInLevel.contains(longPos) && chunk instanceof LevelChunk)
((SimpleEntityLookupInterface<Entity>) ((ServerWorldInterface) level).getEntityLookupCMPublic()).getChunkEntities(pos).forEach(entity -> {
if (!(entity instanceof Player))
entity.discard();
});
if (chunk instanceof LevelChunk)
((LevelChunk) chunk).setLoaded(false);
if (this.entitiesInLevel.remove(pos.toLong()) && chunk instanceof LevelChunk)
// block entities only
this.level.unload((LevelChunk) chunk);
((ServerLightingProviderInterface) this.lightEngine).invokeUpdateChunkStatus(pos);
((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk);
this.progressListener.onStatusChange(pos, null);
}
for (final ChunkAccess chunk : affectedChunks) {
final ChunkPos cPos = chunk.getPos();
final long pos = cPos.toLong();
final ChunkHolder oldHolder = this.updatingChunkMap.remove(pos);
final ChunkHolder newHolder = new ChunkHolder(cPos, oldHolder.getTicketLevel(), level, this.lightEngine, this.queueSorter, (ChunkHolder.PlayerProvider) this);
// enable chunk blending?
((ChunkHolderInterface) newHolder).setDefaultProtoChunk(cPos, this.mainThreadExecutor, level);
this.updatingChunkMap.put(pos, newHolder);
((ChunkTicketManagerInterface) this.distanceManager).replaceHolder(oldHolder, newHolder);
}
this.modified = true;
this.promoteChunkMap();
for (final ChunkAccess chunk : affectedNeighbors) ((ServerLightingProviderInterface) this.lightEngine).removeLightData(chunk);
for (final ChunkAccess chunk : affectedNeighbors) this.addRelightTicket(chunk.getPos());
this.tickTicketManager();
final List<CompletableFuture<?>> lightFutures = new ArrayList<>();
for (final ChunkAccess chunk : affectedNeighbors) {
final ChunkPos pos = chunk.getPos();
lightFutures.add(this.getChunkRangeFuture(pos, 1, (pos_) -> ChunkStatus.LIGHT).thenCompose(either -> either.map(list -> ((ServerLightingProviderInterface) this.lightEngine).relight(chunk), unloaded -> {
this.releaseRelightTicket(pos);
return CompletableFuture.completedFuture(null);
})));
}
// Force generation to previous states
// This ensures that the world is in a consistent state after this method
// Also, this is needed to ensure chunks are saved to disk
final Map<ChunkPos, ChunkStatus> targetGenerationStatus = affectedChunks.stream().collect(Collectors.toMap(ChunkAccess::getPos, ChunkAccess::getStatus));
for (final Entry<ChunkPos, ChunkStatus> entry : targetGenerationStatus.entrySet()) this.addTicket(entry.getKey(), entry.getValue());
this.tickTicketManager();
final List<Pair<ChunkStatus, CompletableFuture<?>>> targetGenerationFutures = new ArrayList<>();
for (final Entry<ChunkPos, ChunkStatus> entry : targetGenerationStatus.entrySet()) targetGenerationFutures.add(Pair.of(entry.getValue(), this.updatingChunkMap.get(entry.getKey().toLong()).getOrScheduleFuture(entry.getValue(), (ChunkMap) (Object) this)));
final Map<ChunkStatus, List<CompletableFuture<?>>> targetGenerationFuturesGrouped = targetGenerationFutures.stream().collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Entry::getValue, Collectors.toList())));
for (final ChunkStatus status : ChunkStatus.getStatusList()) {
final List<CompletableFuture<?>> futures = targetGenerationFuturesGrouped.get(status);
if (futures == null)
continue;
report.put("layer_count_" + status.getName(), futures.size());
final long start = System.currentTimeMillis();
this.waitFor(futures);
report.put("layer_time_" + status.getName(), (int) (System.currentTimeMillis() - start));
}
report.put("relight_count", lightFutures.size());
final long relightStart = System.currentTimeMillis();
this.waitFor(lightFutures);
report.put("relight_time", (int) (System.currentTimeMillis() - relightStart));
return report;
}
Aggregations