GenerationChunkHolder.java

net.minecraft.server.level.GenerationChunkHolder

信息

  • 全限定名:net.minecraft.server.level.GenerationChunkHolder
  • 类型:public abstract class
  • 包:net.minecraft.server.level
  • 源码路径:src/main/java/net/minecraft/server/level/GenerationChunkHolder.java
  • 起始行号:L23
  • 职责:

    TODO

字段/常量

  • CHUNK_STATUSES

    • 类型: List<ChunkStatus>
    • 修饰符: private static final
    • 源码定位: L24
    • 说明:

      TODO

  • NOT_DONE_YET

    • 类型: ChunkResult<ChunkAccess>
    • 修饰符: private static final
    • 源码定位: L25
    • 说明:

      TODO

  • UNLOADED_CHUNK

    • 类型: ChunkResult<ChunkAccess>
    • 修饰符: public static final
    • 源码定位: L26
    • 说明:

      TODO

  • UNLOADED_CHUNK_FUTURE

    • 类型: CompletableFuture<ChunkResult<ChunkAccess>>
    • 修饰符: public static final
    • 源码定位: L27
    • 说明:

      TODO

  • pos

    • 类型: ChunkPos
    • 修饰符: protected final
    • 源码定位: L28
    • 说明:

      TODO

  • highestAllowedStatus

    • 类型: ChunkStatus
    • 修饰符: private volatile
    • 源码定位: L29
    • 说明:

      TODO

  • startedWork

    • 类型: AtomicReference<ChunkStatus>
    • 修饰符: private final
    • 源码定位: L30
    • 说明:

      TODO

  • futures

    • 类型: AtomicReferenceArray<CompletableFuture<ChunkResult<ChunkAccess>>>
    • 修饰符: private final
    • 源码定位: L31
    • 说明:

      TODO

  • task

    • 类型: AtomicReference<ChunkGenerationTask>
    • 修饰符: private final
    • 源码定位: L32
    • 说明:

      TODO

  • generationRefCount

    • 类型: AtomicInteger
    • 修饰符: private final
    • 源码定位: L33
    • 说明:

      TODO

  • generationSaveSyncFuture

    • 类型: CompletableFuture<Void>
    • 修饰符: private volatile
    • 源码定位: L34
    • 说明:

      TODO

内部类/嵌套类型

构造器

public GenerationChunkHolder(ChunkPos pos) @ L36

  • 构造器名:GenerationChunkHolder
  • 源码定位:L36
  • 修饰符:public

参数:

  • pos: ChunkPos

说明:

TODO

方法

下面的方法块按源码顺序生成。

public CompletableFuture<ChunkResult<ChunkAccess>> scheduleChunkGenerationTask(ChunkStatus status, ChunkMap scheduler) @ L43

  • 方法名:scheduleChunkGenerationTask
  • 源码定位:L43
  • 返回类型:CompletableFuture<ChunkResult>
  • 修饰符:public

参数:

  • status: ChunkStatus
  • scheduler: ChunkMap

说明:

TODO

CompletableFuture<ChunkResult<ChunkAccess>> applyStep(ChunkStep step, GeneratingChunkMap chunkMap, StaticCache2D<GenerationChunkHolder> cache) @ L61

  • 方法名:applyStep
  • 源码定位:L61
  • 返回类型:CompletableFuture<ChunkResult>
  • 修饰符:package-private

参数:

  • step: ChunkStep
  • chunkMap: GeneratingChunkMap
  • cache: StaticCache2D

说明:

TODO

protected void updateHighestAllowedStatus(ChunkMap scheduler) @ L78

  • 方法名:updateHighestAllowedStatus
  • 源码定位:L78
  • 返回类型:void
  • 修饰符:protected

参数:

  • scheduler: ChunkMap

说明:

TODO

public void replaceProtoChunk(ImposterProtoChunk chunk) @ L91

  • 方法名:replaceProtoChunk
  • 源码定位:L91
  • 返回类型:void
  • 修饰符:public

参数:

  • chunk: ImposterProtoChunk

说明:

TODO

void removeTask(ChunkGenerationTask task) @ L108

  • 方法名:removeTask
  • 源码定位:L108
  • 返回类型:void
  • 修饰符:package-private

参数:

  • task: ChunkGenerationTask

说明:

TODO

private void rescheduleChunkTask(ChunkMap scheduler, ChunkStatus status) @ L112

  • 方法名:rescheduleChunkTask
  • 源码定位:L112
  • 返回类型:void
  • 修饰符:private

参数:

  • scheduler: ChunkMap
  • status: ChunkStatus

说明:

TODO

private CompletableFuture<ChunkResult<ChunkAccess>> getOrCreateFuture(ChunkStatus status) @ L126

  • 方法名:getOrCreateFuture
  • 源码定位:L126
  • 返回类型:CompletableFuture<ChunkResult>
  • 修饰符:private

参数:

  • status: ChunkStatus

说明:

TODO

private void failAndClearPendingFuturesBetween(ChunkStatus fromExclusive, ChunkStatus toInclusive) @ L150

  • 方法名:failAndClearPendingFuturesBetween
  • 源码定位:L150
  • 返回类型:void
  • 修饰符:private

参数:

  • fromExclusive: ChunkStatus
  • toInclusive: ChunkStatus

说明:

TODO

private void failAndClearPendingFuture(int index, CompletableFuture<ChunkResult<ChunkAccess>> previous) @ L162

  • 方法名:failAndClearPendingFuture
  • 源码定位:L162
  • 返回类型:void
  • 修饰符:private

参数:

  • index: int
  • previous: CompletableFuture<ChunkResult>

说明:

TODO

private void completeFuture(ChunkStatus status, ChunkAccess chunk) @ L168

  • 方法名:completeFuture
  • 源码定位:L168
  • 返回类型:void
  • 修饰符:private

参数:

  • status: ChunkStatus
  • chunk: ChunkAccess

说明:

TODO

private ChunkStatus findHighestStatusWithPendingFuture(ChunkStatus newStatus) @ L192

  • 方法名:findHighestStatusWithPendingFuture
  • 源码定位:L192
  • 返回类型:ChunkStatus
  • 修饰符:private

参数:

  • newStatus: ChunkStatus

说明:

TODO

private boolean acquireStatusBump(ChunkStatus status) @ L215

  • 方法名:acquireStatusBump
  • 源码定位:L215
  • 返回类型:boolean
  • 修饰符:private

参数:

  • status: ChunkStatus

说明:

TODO

private boolean isStatusDisallowed(ChunkStatus status) @ L227

  • 方法名:isStatusDisallowed
  • 源码定位:L227
  • 返回类型:boolean
  • 修饰符:private

参数:

  • status: ChunkStatus

说明:

TODO

protected abstract void addSaveDependency(CompletableFuture<?> sync) @ L232

  • 方法名:addSaveDependency
  • 源码定位:L232
  • 返回类型:void
  • 修饰符:protected abstract

参数:

  • sync: CompletableFuture<?>

说明:

TODO

public void increaseGenerationRefCount() @ L234

  • 方法名:increaseGenerationRefCount
  • 源码定位:L234
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void decreaseGenerationRefCount() @ L241

  • 方法名:decreaseGenerationRefCount
  • 源码定位:L241
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public ChunkAccess getChunkIfPresentUnchecked(ChunkStatus status) @ L253

  • 方法名:getChunkIfPresentUnchecked
  • 源码定位:L253
  • 返回类型:ChunkAccess
  • 修饰符:public

参数:

  • status: ChunkStatus

说明:

TODO

public ChunkAccess getChunkIfPresent(ChunkStatus status) @ L258

  • 方法名:getChunkIfPresent
  • 源码定位:L258
  • 返回类型:ChunkAccess
  • 修饰符:public

参数:

  • status: ChunkStatus

说明:

TODO

public ChunkAccess getLatestChunk() @ L262

  • 方法名:getLatestChunk
  • 源码定位:L262
  • 返回类型:ChunkAccess
  • 修饰符:public

参数:

说明:

TODO

public ChunkStatus getPersistedStatus() @ L272

  • 方法名:getPersistedStatus
  • 源码定位:L272
  • 返回类型:ChunkStatus
  • 修饰符:public

参数:

说明:

TODO

public ChunkPos getPos() @ L278

  • 方法名:getPos
  • 源码定位:L278
  • 返回类型:ChunkPos
  • 修饰符:public

参数:

说明:

TODO

public FullChunkStatus getFullStatus() @ L282

  • 方法名:getFullStatus
  • 源码定位:L282
  • 返回类型:FullChunkStatus
  • 修饰符:public

参数:

说明:

TODO

public abstract int getTicketLevel() @ L286

  • 方法名:getTicketLevel
  • 源码定位:L286
  • 返回类型:int
  • 修饰符:public abstract

参数:

说明:

TODO

public abstract int getQueueLevel() @ L288

  • 方法名:getQueueLevel
  • 源码定位:L288
  • 返回类型:int
  • 修饰符:public abstract

参数:

说明:

TODO

public List<Pair<ChunkStatus,CompletableFuture<ChunkResult<ChunkAccess>>>> getAllFutures() @ L290

  • 方法名:getAllFutures
  • 源码定位:L290
  • 返回类型:List<Pair<ChunkStatus,CompletableFuture<ChunkResult>>>
  • 修饰符:public

参数:

说明:

TODO

public ChunkStatus getLatestStatus() @ L301

  • 方法名:getLatestStatus
  • 源码定位:L301
  • 返回类型:ChunkStatus
  • 修饰符:public

参数:

说明:

TODO

代码

public abstract class GenerationChunkHolder {
    private static final List<ChunkStatus> CHUNK_STATUSES = ChunkStatus.getStatusList();
    private static final ChunkResult<ChunkAccess> NOT_DONE_YET = ChunkResult.error("Not done yet");
    public static final ChunkResult<ChunkAccess> UNLOADED_CHUNK = ChunkResult.error("Unloaded chunk");
    public static final CompletableFuture<ChunkResult<ChunkAccess>> UNLOADED_CHUNK_FUTURE = CompletableFuture.completedFuture(UNLOADED_CHUNK);
    protected final ChunkPos pos;
    private volatile @Nullable ChunkStatus highestAllowedStatus;
    private final AtomicReference<@Nullable ChunkStatus> startedWork = new AtomicReference<>();
    private final AtomicReferenceArray<@Nullable CompletableFuture<ChunkResult<ChunkAccess>>> futures = new AtomicReferenceArray<>(CHUNK_STATUSES.size());
    private final AtomicReference<@Nullable ChunkGenerationTask> task = new AtomicReference<>();
    private final AtomicInteger generationRefCount = new AtomicInteger();
    private volatile CompletableFuture<Void> generationSaveSyncFuture = CompletableFuture.completedFuture(null);
 
    public GenerationChunkHolder(ChunkPos pos) {
        this.pos = pos;
        if (!pos.isValid()) {
            throw new IllegalStateException("Trying to create chunk out of reasonable bounds: " + pos);
        }
    }
 
    public CompletableFuture<ChunkResult<ChunkAccess>> scheduleChunkGenerationTask(ChunkStatus status, ChunkMap scheduler) {
        if (this.isStatusDisallowed(status)) {
            return UNLOADED_CHUNK_FUTURE;
        } else {
            CompletableFuture<ChunkResult<ChunkAccess>> future = this.getOrCreateFuture(status);
            if (future.isDone()) {
                return future;
            } else {
                ChunkGenerationTask task = this.task.get();
                if (task == null || status.isAfter(task.targetStatus)) {
                    this.rescheduleChunkTask(scheduler, status);
                }
 
                return future;
            }
        }
    }
 
    CompletableFuture<ChunkResult<ChunkAccess>> applyStep(ChunkStep step, GeneratingChunkMap chunkMap, StaticCache2D<GenerationChunkHolder> cache) {
        if (this.isStatusDisallowed(step.targetStatus())) {
            return UNLOADED_CHUNK_FUTURE;
        } else {
            return this.acquireStatusBump(step.targetStatus()) ? chunkMap.applyStep(this, step, cache).handle((chunk, exception) -> {
                if (exception != null) {
                    CrashReport report = CrashReport.forThrowable(exception, "Exception chunk generation/loading");
                    BlockableEventLoop.relayDelayCrash(report);
                } else {
                    this.completeFuture(step.targetStatus(), chunk);
                }
 
                return ChunkResult.of(chunk);
            }) : this.getOrCreateFuture(step.targetStatus());
        }
    }
 
    protected void updateHighestAllowedStatus(ChunkMap scheduler) {
        ChunkStatus oldStatus = this.highestAllowedStatus;
        ChunkStatus newStatus = ChunkLevel.generationStatus(this.getTicketLevel());
        this.highestAllowedStatus = newStatus;
        boolean statusDropped = oldStatus != null && (newStatus == null || newStatus.isBefore(oldStatus));
        if (statusDropped) {
            this.failAndClearPendingFuturesBetween(newStatus, oldStatus);
            if (this.task.get() != null) {
                this.rescheduleChunkTask(scheduler, this.findHighestStatusWithPendingFuture(newStatus));
            }
        }
    }
 
    public void replaceProtoChunk(ImposterProtoChunk chunk) {
        CompletableFuture<ChunkResult<ChunkAccess>> imposterFuture = CompletableFuture.completedFuture(ChunkResult.of(chunk));
 
        for (int i = 0; i < this.futures.length() - 1; i++) {
            CompletableFuture<ChunkResult<ChunkAccess>> future = this.futures.get(i);
            Objects.requireNonNull(future);
            ChunkAccess maybeProtoChunk = future.getNow(NOT_DONE_YET).orElse(null);
            if (!(maybeProtoChunk instanceof ProtoChunk)) {
                throw new IllegalStateException("Trying to replace a ProtoChunk, but found " + maybeProtoChunk);
            }
 
            if (!this.futures.compareAndSet(i, future, imposterFuture)) {
                throw new IllegalStateException("Future changed by other thread while trying to replace it");
            }
        }
    }
 
    void removeTask(ChunkGenerationTask task) {
        this.task.compareAndSet(task, null);
    }
 
    private void rescheduleChunkTask(ChunkMap scheduler, @Nullable ChunkStatus status) {
        ChunkGenerationTask newTask;
        if (status != null) {
            newTask = scheduler.scheduleGenerationTask(status, this.getPos());
        } else {
            newTask = null;
        }
 
        ChunkGenerationTask oldTask = this.task.getAndSet(newTask);
        if (oldTask != null) {
            oldTask.markForCancellation();
        }
    }
 
    private CompletableFuture<ChunkResult<ChunkAccess>> getOrCreateFuture(ChunkStatus status) {
        if (this.isStatusDisallowed(status)) {
            return UNLOADED_CHUNK_FUTURE;
        } else {
            int index = status.getIndex();
            CompletableFuture<ChunkResult<ChunkAccess>> future = this.futures.get(index);
 
            while (future == null) {
                CompletableFuture<ChunkResult<ChunkAccess>> newValue = new CompletableFuture<>();
                future = this.futures.compareAndExchange(index, null, newValue);
                if (future == null) {
                    if (this.isStatusDisallowed(status)) {
                        this.failAndClearPendingFuture(index, newValue);
                        return UNLOADED_CHUNK_FUTURE;
                    }
 
                    return newValue;
                }
            }
 
            return future;
        }
    }
 
    private void failAndClearPendingFuturesBetween(@Nullable ChunkStatus fromExclusive, ChunkStatus toInclusive) {
        int start = fromExclusive == null ? 0 : fromExclusive.getIndex() + 1;
        int end = toInclusive.getIndex();
 
        for (int i = start; i <= end; i++) {
            CompletableFuture<ChunkResult<ChunkAccess>> previous = this.futures.get(i);
            if (previous != null) {
                this.failAndClearPendingFuture(i, previous);
            }
        }
    }
 
    private void failAndClearPendingFuture(int index, CompletableFuture<ChunkResult<ChunkAccess>> previous) {
        if (previous.complete(UNLOADED_CHUNK) && !this.futures.compareAndSet(index, previous, null)) {
            throw new IllegalStateException("Nothing else should replace the future here");
        }
    }
 
    private void completeFuture(ChunkStatus status, ChunkAccess chunk) {
        ChunkResult<ChunkAccess> result = ChunkResult.of(chunk);
        int index = status.getIndex();
 
        while (true) {
            CompletableFuture<ChunkResult<ChunkAccess>> future = this.futures.get(index);
            if (future == null) {
                if (this.futures.compareAndSet(index, null, CompletableFuture.completedFuture(result))) {
                    return;
                }
            } else {
                if (future.complete(result)) {
                    return;
                }
 
                if (future.getNow(NOT_DONE_YET).isSuccess()) {
                    throw new IllegalStateException("Trying to complete a future but found it to be completed successfully already");
                }
 
                Thread.yield();
            }
        }
    }
 
    private @Nullable ChunkStatus findHighestStatusWithPendingFuture(@Nullable ChunkStatus newStatus) {
        if (newStatus == null) {
            return null;
        } else {
            ChunkStatus highestStatus = newStatus;
 
            for (ChunkStatus alreadyStarted = this.startedWork.get();
                alreadyStarted == null || highestStatus.isAfter(alreadyStarted);
                highestStatus = highestStatus.getParent()
            ) {
                if (this.futures.get(highestStatus.getIndex()) != null) {
                    return highestStatus;
                }
 
                if (highestStatus == ChunkStatus.EMPTY) {
                    break;
                }
            }
 
            return null;
        }
    }
 
    private boolean acquireStatusBump(ChunkStatus status) {
        ChunkStatus parent = status == ChunkStatus.EMPTY ? null : status.getParent();
        ChunkStatus previousStarted = this.startedWork.compareAndExchange(parent, status);
        if (previousStarted == parent) {
            return true;
        } else if (previousStarted != null && !status.isAfter(previousStarted)) {
            return false;
        } else {
            throw new IllegalStateException("Unexpected last startedWork status: " + previousStarted + " while trying to start: " + status);
        }
    }
 
    private boolean isStatusDisallowed(ChunkStatus status) {
        ChunkStatus highestAllowedStatus = this.highestAllowedStatus;
        return highestAllowedStatus == null || status.isAfter(highestAllowedStatus);
    }
 
    protected abstract void addSaveDependency(final CompletableFuture<?> sync);
 
    public void increaseGenerationRefCount() {
        if (this.generationRefCount.getAndIncrement() == 0) {
            this.generationSaveSyncFuture = new CompletableFuture<>();
            this.addSaveDependency(this.generationSaveSyncFuture);
        }
    }
 
    public void decreaseGenerationRefCount() {
        CompletableFuture<Void> future = this.generationSaveSyncFuture;
        int newValue = this.generationRefCount.decrementAndGet();
        if (newValue == 0) {
            future.complete(null);
        }
 
        if (newValue < 0) {
            throw new IllegalStateException("More releases than claims. Count: " + newValue);
        }
    }
 
    public @Nullable ChunkAccess getChunkIfPresentUnchecked(ChunkStatus status) {
        CompletableFuture<ChunkResult<ChunkAccess>> future = this.futures.get(status.getIndex());
        return future == null ? null : future.getNow(NOT_DONE_YET).orElse(null);
    }
 
    public @Nullable ChunkAccess getChunkIfPresent(ChunkStatus status) {
        return this.isStatusDisallowed(status) ? null : this.getChunkIfPresentUnchecked(status);
    }
 
    public @Nullable ChunkAccess getLatestChunk() {
        ChunkStatus status = this.startedWork.get();
        if (status == null) {
            return null;
        } else {
            ChunkAccess chunk = this.getChunkIfPresentUnchecked(status);
            return chunk != null ? chunk : this.getChunkIfPresentUnchecked(status.getParent());
        }
    }
 
    public @Nullable ChunkStatus getPersistedStatus() {
        CompletableFuture<ChunkResult<ChunkAccess>> future = this.futures.get(ChunkStatus.EMPTY.getIndex());
        ChunkAccess chunkAccess = future == null ? null : future.getNow(NOT_DONE_YET).orElse(null);
        return chunkAccess == null ? null : chunkAccess.getPersistedStatus();
    }
 
    public ChunkPos getPos() {
        return this.pos;
    }
 
    public FullChunkStatus getFullStatus() {
        return ChunkLevel.fullStatus(this.getTicketLevel());
    }
 
    public abstract int getTicketLevel();
 
    public abstract int getQueueLevel();
 
    @VisibleForDebug
    public List<Pair<ChunkStatus, @Nullable CompletableFuture<ChunkResult<ChunkAccess>>>> getAllFutures() {
        List<Pair<ChunkStatus, CompletableFuture<ChunkResult<ChunkAccess>>>> result = new ArrayList<>();
 
        for (int i = 0; i < CHUNK_STATUSES.size(); i++) {
            result.add(Pair.of(CHUNK_STATUSES.get(i), this.futures.get(i)));
        }
 
        return result;
    }
 
    @VisibleForDebug
    public @Nullable ChunkStatus getLatestStatus() {
        ChunkStatus status = this.startedWork.get();
        if (status == null) {
            return null;
        } else {
            ChunkAccess chunk = this.getChunkIfPresentUnchecked(status);
            return chunk != null ? status : status.getParent();
        }
    }
}

引用的其他类