Skip to content

Commit ee34dcf

Browse files
committed
Drastically simplify and document chunk system memory usage patch
1 parent 49d800f commit ee34dcf

1 file changed

Lines changed: 19 additions & 42 deletions

File tree

  • src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/paper_chunk_patches
Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
package org.embeddedt.modernfix.common.mixin.bugfix.paper_chunk_patches;
22

3+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
4+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
35
import com.mojang.datafixers.util.Either;
46
import net.minecraft.server.level.*;
5-
import net.minecraft.server.level.progress.ChunkProgressListener;
67
import net.minecraft.util.thread.BlockableEventLoop;
7-
import net.minecraft.world.level.ChunkPos;
88
import net.minecraft.world.level.chunk.ChunkAccess;
99
import net.minecraft.world.level.chunk.ChunkStatus;
10-
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
1110
import org.spongepowered.asm.mixin.Final;
1211
import org.spongepowered.asm.mixin.Mixin;
1312
import org.spongepowered.asm.mixin.Shadow;
1413
import org.spongepowered.asm.mixin.injection.At;
15-
import org.spongepowered.asm.mixin.injection.Inject;
1614
import org.spongepowered.asm.mixin.injection.ModifyArg;
17-
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
1815

19-
import java.util.Optional;
2016
import java.util.concurrent.CompletableFuture;
2117
import java.util.concurrent.Executor;
2218

@@ -25,18 +21,6 @@
2521
public abstract class ChunkMapMixin {
2622
@Shadow @Final private BlockableEventLoop<Runnable> mainThreadExecutor;
2723

28-
@Shadow @Final private ChunkMap.DistanceManager distanceManager;
29-
30-
@Shadow protected abstract CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> protoChunkToFullChunk(ChunkHolder arg);
31-
32-
@Shadow @Final private ServerLevel level;
33-
@Shadow @Final private ThreadedLevelLightEngine lightEngine;
34-
@Shadow @Final private ChunkProgressListener progressListener;
35-
36-
@Shadow protected abstract CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> scheduleChunkGeneration(ChunkHolder chunkHolder, ChunkStatus chunkStatus);
37-
38-
@Shadow @Final private StructureTemplateManager structureTemplateManager;
39-
4024
/* https://github.com/PaperMC/Paper/blob/ver/1.17.1/patches/server/0752-Fix-chunks-refusing-to-unload-at-low-TPS.patch */
4125
@ModifyArg(method = "prepareAccessibleChunk", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenApplyAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 1)
4226
private Executor useMainThreadExecutor(Executor executor) {
@@ -45,31 +29,24 @@ private Executor useMainThreadExecutor(Executor executor) {
4529

4630
/**
4731
* @author embeddedt
48-
* @reason revert 1.17 chunk system changes, significantly reduces time and RAM needed to load chunks
32+
* @reason 1.17+ uses getNow to check if the parent future is ready, and calls scheduleChunkGeneration as soon as
33+
* it is found to not be ready. In the latter scenario, a massive number of extra CompletableFutures are allocated
34+
* even if they are not actually necessary if the future is waited for. To prevent this, if the parent future
35+
* is not done, we wait for it to complete and then retry schedule(). This will either detect an adequate
36+
* status and return a loading future, or re-enter this injector with the parent future completed, in which case
37+
* we proceed to schedule generation as originally requested.
4938
*/
50-
@Inject(method = "schedule", at = @At("HEAD"), cancellable = true)
51-
private void useLegacySchedulingLogic(ChunkHolder holder, ChunkStatus requiredStatus, CallbackInfoReturnable<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> cir) {
52-
if(requiredStatus != ChunkStatus.EMPTY && !requiredStatus.hasLoadDependencies()) {
53-
ChunkPos chunkpos = holder.getPos();
54-
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = holder.getOrScheduleFuture(requiredStatus.getParent(), (ChunkMap)(Object)this);
55-
cir.setReturnValue(future.thenComposeAsync((either) -> {
56-
Optional<ChunkAccess> optional = either.left();
57-
58-
if (requiredStatus == ChunkStatus.LIGHT) {
59-
this.distanceManager.addTicket(TicketType.LIGHT, chunkpos, 33 + ChunkStatus.getDistance(ChunkStatus.LIGHT), chunkpos);
60-
}
61-
62-
// from original method
63-
if (optional.isPresent() && optional.get().getStatus().isOrAfter(requiredStatus)) {
64-
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = requiredStatus.load(this.level, this.structureTemplateManager, this.lightEngine, (arg2) -> {
65-
return this.protoChunkToFullChunk(holder);
66-
}, (ChunkAccess)optional.get());
67-
this.progressListener.onStatusChange(chunkpos, requiredStatus);
68-
return completablefuture;
69-
} else {
70-
return this.scheduleChunkGeneration(holder, requiredStatus);
71-
}
72-
}, this.mainThreadExecutor).thenComposeAsync(CompletableFuture::completedFuture, this.mainThreadExecutor));
39+
@WrapOperation(method = "schedule", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkMap;scheduleChunkGeneration(Lnet/minecraft/server/level/ChunkHolder;Lnet/minecraft/world/level/chunk/ChunkStatus;)Ljava/util/concurrent/CompletableFuture;"))
40+
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> mfix$avoidSchedulingGenerationPrematurely(ChunkMap map, ChunkHolder holder, ChunkStatus status, Operation<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> original) {
41+
if (!status.hasLoadDependencies()) {
42+
var parentFuture = holder.getOrScheduleFuture(status.getParent(), map);
43+
if (!parentFuture.isDone()) {
44+
return parentFuture.thenComposeAsync(
45+
either -> map.schedule(holder, status),
46+
this.mainThreadExecutor
47+
);
48+
}
7349
}
50+
return original.call(map, holder, status);
7451
}
7552
}

0 commit comments

Comments
 (0)