Skip to content

Commit

Permalink
feat: do not wait for chunk loads when calling (#2912)
Browse files Browse the repository at this point in the history
* feat: do not wait for chunk loads when calling

* Add comment

* It's ugly but it stops OOM

* Fix copykey

* Apply to all versions

* Add config options

* feat: add configurable per-thread target-size with programmatic default

* Add for 1.21.3

* Abstractify bukkit get blocks a bit

* Clean up some more duplication
  • Loading branch information
dordsor21 authored Jan 26, 2025
1 parent 40d0422 commit d73ff19
Show file tree
Hide file tree
Showing 37 changed files with 2,988 additions and 3,246 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
Expand Down Expand Up @@ -273,7 +275,7 @@ public int[] getHeightMap(HeightMapType type) {
}

@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R2.CraftChunk;

import javax.annotation.Nonnull;
Expand All @@ -79,9 +78,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.IntFunction;

import static java.lang.invoke.MethodType.methodType;
Expand Down Expand Up @@ -276,12 +274,49 @@ static DelegateSemaphore applyLock(LevelChunkSection section) {
}
}
} catch (Throwable e) {
e.printStackTrace();
LOGGER.error("Error apply DelegateSemaphore", e);
throw new RuntimeException(e);
}
}

public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
public static CompletableFuture<LevelChunk> ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
LevelChunk levelChunk = getChunkImmediatelyAsync(serverLevel, chunkX, chunkZ);
if (levelChunk != null) {
return CompletableFuture.completedFuture(levelChunk);
}
if (PaperLib.isPaper()) {
CompletableFuture<LevelChunk> future = serverLevel
.getWorld()
.getChunkAtAsync(chunkX, chunkZ, true, true)
.thenApply(chunk -> {
addTicket(serverLevel, chunkX, chunkZ);
try {
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
} catch (Throwable e) {
LOGGER.error("Could not asynchronously load chunk at {},{}", chunkX, chunkZ, e);
return null;
}
});
try {
if (!future.isCompletedExceptionally() || (future.isDone() && future.get() != null)) {
return future;
}
Throwable t = future.exceptionNow();
LOGGER.error("Asynchronous chunk load at {},{} exceptionally completed immediately", chunkX, chunkZ, t);
} catch (InterruptedException | ExecutionException e) {
LOGGER.error(
"Unexpected error when getting completed future at chunk {},{}. Returning to default.",
chunkX,
chunkZ,
e
);
}
}
return CompletableFuture.supplyAsync(() -> TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)));
}


public static @Nullable LevelChunk getChunkImmediatelyAsync(ServerLevel serverLevel, int chunkX, int chunkZ) {
if (!PaperLib.isPaper()) {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
if (nmsChunk != null) {
Expand All @@ -290,6 +325,7 @@ public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int c
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
return null;
} else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
Expand All @@ -305,30 +341,8 @@ public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int c
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try {
CraftChunk chunk;
try {
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
String world = serverLevel.getWorld().getName();
// We've already taken 10 seconds we can afford to wait a little here.
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
if (loaded) {
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
// Retry chunk load
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
} else {
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
}
}
addTicket(serverLevel, chunkX, chunkZ);
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
}

private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
Expand Down Expand Up @@ -672,7 +686,7 @@ static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
}
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) {
throwable.printStackTrace();
LOGGER.error("Error removing beacon", throwable);
}
}

Expand Down
Loading

0 comments on commit d73ff19

Please sign in to comment.