minecraft-src/net/minecraft/world/level/chunk/status/ChunkStep.java
2025-07-04 01:41:11 +03:00

143 lines
5 KiB
Java

package net.minecraft.world.level.chunk.status;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.util.StaticCache2D;
import net.minecraft.util.profiling.jfr.JvmProfiler;
import net.minecraft.util.profiling.jfr.callback.ProfiledDuration;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import org.jetbrains.annotations.Nullable;
public record ChunkStep(
ChunkStatus targetStatus, ChunkDependencies directDependencies, ChunkDependencies accumulatedDependencies, int blockStateWriteRadius, ChunkStatusTask task
) {
public int getAccumulatedRadiusOf(ChunkStatus status) {
return status == this.targetStatus ? 0 : this.accumulatedDependencies.getRadiusOf(status);
}
public CompletableFuture<ChunkAccess> apply(WorldGenContext worldGenContext, StaticCache2D<GenerationChunkHolder> cache, ChunkAccess chunk) {
if (chunk.getPersistedStatus().isBefore(this.targetStatus)) {
ProfiledDuration profiledDuration = JvmProfiler.INSTANCE.onChunkGenerate(chunk.getPos(), worldGenContext.level().dimension(), this.targetStatus.getName());
return this.task.doWork(worldGenContext, this, cache, chunk).thenApply(chunkAccess -> this.completeChunkGeneration(chunkAccess, profiledDuration));
} else {
return this.task.doWork(worldGenContext, this, cache, chunk);
}
}
private ChunkAccess completeChunkGeneration(ChunkAccess chunk, @Nullable ProfiledDuration duration) {
if (chunk instanceof ProtoChunk protoChunk && protoChunk.getPersistedStatus().isBefore(this.targetStatus)) {
protoChunk.setPersistedStatus(this.targetStatus);
}
if (duration != null) {
duration.finish();
}
return chunk;
}
public static class Builder {
private final ChunkStatus status;
@Nullable
private final ChunkStep parent;
private ChunkStatus[] directDependenciesByRadius;
private int blockStateWriteRadius = -1;
private ChunkStatusTask task = ChunkStatusTasks::passThrough;
protected Builder(ChunkStatus status) {
if (status.getParent() != status) {
throw new IllegalArgumentException("Not starting with the first status: " + status);
} else {
this.status = status;
this.parent = null;
this.directDependenciesByRadius = new ChunkStatus[0];
}
}
protected Builder(ChunkStatus status, ChunkStep parent) {
if (parent.targetStatus.getIndex() != status.getIndex() - 1) {
throw new IllegalArgumentException("Out of order status: " + status);
} else {
this.status = status;
this.parent = parent;
this.directDependenciesByRadius = new ChunkStatus[]{parent.targetStatus};
}
}
public ChunkStep.Builder addRequirement(ChunkStatus status, int radius) {
if (status.isOrAfter(this.status)) {
throw new IllegalArgumentException("Status " + status + " can not be required by " + this.status);
} else {
ChunkStatus[] chunkStatuss = this.directDependenciesByRadius;
int i = radius + 1;
if (i > chunkStatuss.length) {
this.directDependenciesByRadius = new ChunkStatus[i];
Arrays.fill(this.directDependenciesByRadius, status);
}
for (int j = 0; j < Math.min(i, chunkStatuss.length); j++) {
this.directDependenciesByRadius[j] = ChunkStatus.max(chunkStatuss[j], status);
}
return this;
}
}
public ChunkStep.Builder blockStateWriteRadius(int blockStateWriteRadius) {
this.blockStateWriteRadius = blockStateWriteRadius;
return this;
}
public ChunkStep.Builder setTask(ChunkStatusTask task) {
this.task = task;
return this;
}
public ChunkStep build() {
return new ChunkStep(
this.status,
new ChunkDependencies(ImmutableList.copyOf(this.directDependenciesByRadius)),
new ChunkDependencies(ImmutableList.copyOf(this.buildAccumulatedDependencies())),
this.blockStateWriteRadius,
this.task
);
}
private ChunkStatus[] buildAccumulatedDependencies() {
if (this.parent == null) {
return this.directDependenciesByRadius;
} else {
int i = this.getRadiusOfParent(this.parent.targetStatus);
ChunkDependencies chunkDependencies = this.parent.accumulatedDependencies;
ChunkStatus[] chunkStatuss = new ChunkStatus[Math.max(i + chunkDependencies.size(), this.directDependenciesByRadius.length)];
for (int j = 0; j < chunkStatuss.length; j++) {
int k = j - i;
if (k < 0 || k >= chunkDependencies.size()) {
chunkStatuss[j] = this.directDependenciesByRadius[j];
} else if (j >= this.directDependenciesByRadius.length) {
chunkStatuss[j] = chunkDependencies.get(k);
} else {
chunkStatuss[j] = ChunkStatus.max(this.directDependenciesByRadius[j], chunkDependencies.get(k));
}
}
return chunkStatuss;
}
}
private int getRadiusOfParent(ChunkStatus status) {
for (int i = this.directDependenciesByRadius.length - 1; i >= 0; i--) {
if (this.directDependenciesByRadius[i].isOrAfter(status)) {
return i;
}
}
return 0;
}
}
}