mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
* Unify comment format * More configurable * Remove one extra execute mid-tick task call in level tick when PWT is disabled This may cause extremely rare, weird, strange, magic, mysterious issues with plugins, or potentially more. One example is that it may cause boss mob duplication issue when `ONE MOB ONLY` was enabled in plugin SupremeBosses
215 lines
12 KiB
Diff
215 lines
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: hayanesuru <hayanesuru@outlook.jp>
|
|
Date: Sat, 9 Aug 2025 14:52:44 +0900
|
|
Subject: [PATCH] thread unsafe chunk map
|
|
|
|
|
|
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
|
index f1e1e96a425ae0186164b3ae6caca226fdd7e12e..68f31c3f2003afe1096b8eeb26a2d2a64af2a85a 100644
|
|
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
|
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
|
@@ -78,6 +78,7 @@ public final class ChunkHolderManager {
|
|
final ChunkUnloadQueue unloadQueue;
|
|
|
|
private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f);
|
|
+ public final org.dreeam.leaf.world.ChunkCache<NewChunkHolder> chunkHoldersNoSync; // Leaf - thread unsafe chunk map
|
|
private final ServerLevel world;
|
|
private final ChunkTaskScheduler taskScheduler;
|
|
private long currentTick;
|
|
@@ -112,6 +113,7 @@ public final class ChunkHolderManager {
|
|
this.taskScheduler = taskScheduler;
|
|
this.ticketLockArea = new ReentrantAreaLock(taskScheduler.getChunkSystemLockShift());
|
|
this.unloadQueue = new ChunkUnloadQueue(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift());
|
|
+ this.chunkHoldersNoSync = new org.dreeam.leaf.world.ChunkCache<>(world.getChunkSource().mainThread); // Leaf - thread unsafe chunk map
|
|
}
|
|
|
|
public boolean processTicketUpdates(final int chunkX, final int chunkZ) {
|
|
@@ -374,6 +376,7 @@ public final class ChunkHolderManager {
|
|
if (current == null) {
|
|
// must create
|
|
current = ChunkHolderManager.this.createChunkHolder(key);
|
|
+ ChunkHolderManager.this.chunkHoldersNoSync.put(key, current); // Leaf - thread unsafe chunk map
|
|
ChunkHolderManager.this.chunkHolders.put(key, current);
|
|
current.updateTicketLevel(newLevel);
|
|
} else {
|
|
@@ -923,11 +926,24 @@ public final class ChunkHolderManager {
|
|
}
|
|
|
|
public NewChunkHolder getChunkHolder(final int chunkX, final int chunkZ) {
|
|
- return this.chunkHolders.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
|
+ // Leaf start - thread unsafe chunk map
|
|
+ final long position = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
|
+ if (this.chunkHoldersNoSync.isSameThread()) {
|
|
+ return this.chunkHoldersNoSync.get(position);
|
|
+ } else {
|
|
+ return this.chunkHolders.get(position);
|
|
+ }
|
|
+ // Leaf end - thread unsafe chunk map
|
|
}
|
|
|
|
public NewChunkHolder getChunkHolder(final long position) {
|
|
- return this.chunkHolders.get(position);
|
|
+ // Leaf start - thread unsafe chunk map
|
|
+ if (this.chunkHoldersNoSync.isSameThread()) {
|
|
+ return this.chunkHoldersNoSync.get(position);
|
|
+ } else {
|
|
+ return this.chunkHolders.get(position);
|
|
+ }
|
|
+ // Leaf end - thread unsafe chunk map
|
|
}
|
|
|
|
public void raisePriority(final int x, final int z, final Priority priority) {
|
|
@@ -986,6 +1002,7 @@ public final class ChunkHolderManager {
|
|
}
|
|
|
|
current = this.createChunkHolder(position);
|
|
+ this.chunkHoldersNoSync.put(position, current); // Leaf - thread unsafe chunk map
|
|
this.chunkHolders.put(position, current);
|
|
|
|
|
|
@@ -1158,7 +1175,11 @@ public final class ChunkHolderManager {
|
|
holder.onUnload();
|
|
this.autoSaveQueue.remove(holder);
|
|
PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder);
|
|
- this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ));
|
|
+ // Leaf start - thread unsafe chunk map
|
|
+ long position = CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ);
|
|
+ this.chunkHoldersNoSync.remove(position);
|
|
+ this.chunkHolders.remove(position);
|
|
+ // Leaf end - thread unsafe chunk map
|
|
}
|
|
|
|
// note: never call while inside the chunk system, this will absolutely break everything
|
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
|
index 540a1af9f4e0cf69ff987105a34d92a35e669fb0..c7af60b6d1920d8784ec3ff0e6791dcd0708a259 100644
|
|
--- a/net/minecraft/server/MinecraftServer.java
|
|
+++ b/net/minecraft/server/MinecraftServer.java
|
|
@@ -1768,6 +1768,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
serverLevelTickingSemaphore.acquire();
|
|
tasks.add(
|
|
serverLevel.tickExecutor.submit(() -> {
|
|
+ serverLevel.getChunkSource().fullChunksNonSync.setThread(); // Leaf - thread unsafe chunk map
|
|
+ serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.chunkHoldersNoSync.setThread(); // Leaf - thread unsafe chunk map
|
|
ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread currentThread = (ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread) Thread.currentThread();
|
|
currentThread.currentTickingServerLevel = serverLevel;
|
|
|
|
@@ -1786,7 +1788,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
|
|
while (!tasks.isEmpty()) {
|
|
- tasks.pop().get();
|
|
+ ServerLevel serverLevel = tasks.pop().get(); // Leaf - thread unsafe chunk map
|
|
+ serverLevel.getChunkSource().fullChunksNonSync.setThread(); // Leaf - thread unsafe chunk map
|
|
+ serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.chunkHoldersNoSync.setThread(); // Leaf - thread unsafe chunk map
|
|
}
|
|
} catch (java.lang.InterruptedException | java.util.concurrent.ExecutionException e) {
|
|
throw new RuntimeException(e); // Propagate exception
|
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
|
index bd4c98e9ec41a2bd608e2e2245c503be3171ceee..f6bcd33400ccfc146f508ffd7f8b673439eb5211 100644
|
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -77,6 +77,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
private volatile NaturalSpawner.SpawnState lastSpawnState; // Leaf - optimize mob spawning
|
|
// Paper start
|
|
public final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>();
|
|
+ public final org.dreeam.leaf.world.ChunkCache<LevelChunk> fullChunksNonSync; // Leaf - thread unsafe chunk map
|
|
public int getFullChunksCount() {
|
|
return this.fullChunks.size();
|
|
}
|
|
@@ -87,16 +88,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
@Override
|
|
public final void moonrise$setFullChunk(final int chunkX, final int chunkZ, final LevelChunk chunk) {
|
|
final long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
|
+ // Leaf start - thread unsafe chunk map
|
|
if (chunk == null) {
|
|
+ this.fullChunksNonSync.remove(key);
|
|
this.fullChunks.remove(key);
|
|
} else {
|
|
+ this.fullChunksNonSync.put(key,chunk);
|
|
this.fullChunks.put(key, chunk);
|
|
}
|
|
+ // Leaf end - thread unsafe chunk map
|
|
}
|
|
|
|
@Override
|
|
public final LevelChunk moonrise$getFullChunkIfLoaded(final int chunkX, final int chunkZ) {
|
|
- return this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
|
+ // Leaf start - thread unsafe chunk map
|
|
+ long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
|
+ if (this.fullChunksNonSync.isSameThread()) {
|
|
+ return this.fullChunksNonSync.get(key);
|
|
+ } else {
|
|
+ return this.fullChunks.get(key);
|
|
+ }
|
|
+ // Leaf end - thread unsafe chunk map
|
|
}
|
|
|
|
private ChunkAccess syncLoad(final int chunkX, final int chunkZ, final ChunkStatus toStatus) {
|
|
@@ -204,6 +216,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(level);
|
|
this.mainThread = Thread.currentThread();
|
|
Path path = levelStorageAccess.getDimensionPath(level.dimension()).resolve("data");
|
|
+ this.fullChunksNonSync = new org.dreeam.leaf.world.ChunkCache<>(mainThread); // Leaf - thread unsafe chunk map
|
|
|
|
try {
|
|
FileUtil.createDirectoriesSafe(path);
|
|
@@ -283,7 +296,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
|
|
@Nullable
|
|
public LevelChunk getChunkAtIfLoadedImmediately(int x, int z) {
|
|
- return this.fullChunks.get(ChunkPos.asLong(x, z));
|
|
+ // Leaf start - thread unsafe chunk map
|
|
+ long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z);
|
|
+ if (this.fullChunksNonSync.isSameThread()) {
|
|
+ return this.fullChunksNonSync.get(key);
|
|
+ } else {
|
|
+ return this.fullChunks.get(key);
|
|
+ }
|
|
+ // Leaf end - thread unsafe chunk map
|
|
}
|
|
// Paper end
|
|
|
|
@@ -318,7 +338,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk) {
|
|
// Paper start - rewrite chunk system
|
|
if (chunkStatus == ChunkStatus.FULL) {
|
|
- final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z));
|
|
+ long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z); // Leaf - thread unsafe chunk map
|
|
+ final LevelChunk ret = this.fullChunksNonSync.isSameThread() ? this.fullChunksNonSync.get(key) : this.fullChunks.get(key); // Leaf - thread unsafe chunk map
|
|
|
|
if (ret != null) {
|
|
return ret;
|
|
@@ -335,7 +356,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
@Override
|
|
public LevelChunk getChunkNow(int chunkX, int chunkZ) {
|
|
// Paper start - rewrite chunk system
|
|
- final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
|
+ long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ); // Leaf - thread unsafe chunk map
|
|
+ final LevelChunk ret = this.fullChunksNonSync.isSameThread() ? this.fullChunksNonSync.get(key) : this.fullChunks.get(key); // Leaf - thread unsafe chunk map
|
|
if (!ca.spottedleaf.moonrise.common.PlatformHooks.get().hasCurrentlyLoadingChunk()) {
|
|
return ret;
|
|
}
|
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
|
index 28e2c4f211de1a3a9d95342965699917db613782..e900060907ce7612b251bdf6d526ef83ea968a7a 100644
|
|
--- a/net/minecraft/world/level/Level.java
|
|
+++ b/net/minecraft/world/level/Level.java
|
|
@@ -1065,6 +1065,18 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
|
// Paper end - Perf: make sure loaded chunks get the inlined variant of this function
|
|
}
|
|
|
|
+ // Leaf start - thread unsafe chunk map
|
|
+ @Nullable
|
|
+ public final LevelChunk getChunkAtIfLoadedUnchecked(int x, int z) {
|
|
+ return ((ServerLevel) this).chunkSource.fullChunksNonSync.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z));
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public final BlockState getBlockStateIfLoadedUnchecked(int x, int y, int z) {
|
|
+ LevelChunk chunk = ((ServerLevel) this).chunkSource.fullChunksNonSync.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x >> 4, z >> 4));
|
|
+ return chunk == null ? null : chunk.getBlockStateFinal(x, y, z);
|
|
+ }
|
|
+ // Leaf end - thread unsafe chunk map
|
|
// Paper start - if loaded
|
|
@Nullable
|
|
@Override
|