geforkt von Mirrors/Paper
rewrite chunk system checkpoint
Dieser Commit ist enthalten in:
Ursprung
0c4a1c4496
Commit
819facd7c4
18241
patches/server/0019-Rewrite-chunk-system.patch
Normale Datei
18241
patches/server/0019-Rewrite-chunk-system.patch
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
2367
patches/server/0021-New-player-chunk-loader-system.patch
Normale Datei
2367
patches/server/0021-New-player-chunk-loader-system.patch
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -0,0 +1,397 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 16 Feb 2023 16:50:05 -0800
|
||||
Subject: [PATCH] Make ChunkStatus.EMPTY not rely on the main thread for
|
||||
completion
|
||||
|
||||
In order to do this, we need to push the POI consistency checks
|
||||
to a later status. Since FULL is the only other status that
|
||||
uses the main thread, it can go there.
|
||||
|
||||
The consistency checks are only really for when a desync occurs,
|
||||
and so that delaying the check only matters when the chunk data
|
||||
has desync'd. As long as the desync is sorted before the
|
||||
chunk is full loaded (i.e before setBlock can occur on
|
||||
a chunk), it should not matter.
|
||||
|
||||
This change is primarily due to behavioural changes
|
||||
in the chunk task queue brought by region threading -
|
||||
which is to split the queue into separate regions. As such,
|
||||
it is required that in order for the sync load to complete
|
||||
that the region owning the chunk drain and execute the task
|
||||
while ticking. However, that is not always possible in
|
||||
region threading. Thus, removing the main thread reliance allows
|
||||
the chunk to progress without requiring a tick thread.
|
||||
Specifically, this allows far sync loads (outside of a specific
|
||||
regions bounds) to occur without issue - namely with structure
|
||||
searching.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java
|
||||
index fb42d776f15f735fb59e972e00e2b512c23a8387..300700477ee34bc22b31315825c0e40f61070cd5 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java
|
||||
@@ -2,6 +2,8 @@ package io.papermc.paper.chunk.system.scheduling;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
|
||||
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
|
||||
+import com.mojang.logging.LogUtils;
|
||||
+import io.papermc.paper.chunk.system.poi.PoiChunk;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
@@ -9,10 +11,13 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
+import org.slf4j.Logger;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
public final class ChunkFullTask extends ChunkProgressionTask implements Runnable {
|
||||
|
||||
+ private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
+
|
||||
protected final NewChunkHolder chunkHolder;
|
||||
protected final ChunkAccess fromChunk;
|
||||
protected final PrioritisedExecutor.PrioritisedTask convertToFullTask;
|
||||
@@ -35,6 +40,15 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
|
||||
// See Vanilla protoChunkToFullChunk for what this function should be doing
|
||||
final LevelChunk chunk;
|
||||
try {
|
||||
+ // moved from the load from nbt stage into here
|
||||
+ final PoiChunk poiChunk = this.chunkHolder.getPoiChunk();
|
||||
+ if (poiChunk == null) {
|
||||
+ LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString());
|
||||
+ } else {
|
||||
+ poiChunk.load();
|
||||
+ this.world.getPoiManager().checkConsistency(this.fromChunk);
|
||||
+ }
|
||||
+
|
||||
if (this.fromChunk instanceof ImposterProtoChunk wrappedFull) {
|
||||
chunk = wrappedFull.getWrapped();
|
||||
} else {
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java
|
||||
index be6f3f6a57668a9bd50d0ea5f2dd2335355b69d6..1f7c146ff0b2a835c818f49da6c1f1411f26aa39 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java
|
||||
@@ -25,6 +25,7 @@ import org.slf4j.Logger;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
@@ -34,9 +35,11 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
private final NewChunkHolder chunkHolder;
|
||||
private final ChunkDataLoadTask loadTask;
|
||||
|
||||
- private boolean cancelled;
|
||||
+ private volatile boolean cancelled;
|
||||
private NewChunkHolder.GenericDataLoadTaskCallback entityLoadTask;
|
||||
private NewChunkHolder.GenericDataLoadTaskCallback poiLoadTask;
|
||||
+ private GenericDataLoadTask.TaskResult<ChunkAccess, Throwable> loadResult;
|
||||
+ private final AtomicInteger taskCountToComplete = new AtomicInteger(3); // one for poi, one for entity, and one for chunk data
|
||||
|
||||
protected ChunkLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ,
|
||||
final NewChunkHolder chunkHolder, final PrioritisedExecutor.Priority priority) {
|
||||
@@ -44,10 +47,18 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
this.chunkHolder = chunkHolder;
|
||||
this.loadTask = new ChunkDataLoadTask(scheduler, world, chunkX, chunkZ, priority);
|
||||
this.loadTask.addCallback((final GenericDataLoadTask.TaskResult<ChunkAccess, Throwable> result) -> {
|
||||
- ChunkLoadTask.this.complete(result == null ? null : result.left(), result == null ? null : result.right());
|
||||
+ ChunkLoadTask.this.loadResult = result; // must be before getAndDecrement
|
||||
+ ChunkLoadTask.this.tryCompleteLoad();
|
||||
});
|
||||
}
|
||||
|
||||
+ private void tryCompleteLoad() {
|
||||
+ if (this.taskCountToComplete.decrementAndGet() == 0) {
|
||||
+ final GenericDataLoadTask.TaskResult<ChunkAccess, Throwable> result = this.cancelled ? null : this.loadResult; // only after the getAndDecrement
|
||||
+ ChunkLoadTask.this.complete(result == null ? null : result.left(), result == null ? null : result.right());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public ChunkStatus getTargetStatus() {
|
||||
return ChunkStatus.EMPTY;
|
||||
@@ -65,11 +76,8 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
final NewChunkHolder.GenericDataLoadTaskCallback entityLoadTask;
|
||||
final NewChunkHolder.GenericDataLoadTaskCallback poiLoadTask;
|
||||
|
||||
- final AtomicInteger count = new AtomicInteger();
|
||||
final Consumer<GenericDataLoadTask.TaskResult<?, ?>> scheduleLoadTask = (final GenericDataLoadTask.TaskResult<?, ?> result) -> {
|
||||
- if (count.decrementAndGet() == 0) {
|
||||
- ChunkLoadTask.this.loadTask.schedule(false);
|
||||
- }
|
||||
+ ChunkLoadTask.this.tryCompleteLoad();
|
||||
};
|
||||
|
||||
// NOTE: it is IMPOSSIBLE for getOrLoadEntityData/getOrLoadPoiData to complete synchronously, because
|
||||
@@ -85,16 +93,16 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
}
|
||||
if (!this.chunkHolder.isEntityChunkNBTLoaded()) {
|
||||
entityLoadTask = this.chunkHolder.getOrLoadEntityData((Consumer)scheduleLoadTask);
|
||||
- count.setPlain(count.getPlain() + 1);
|
||||
} else {
|
||||
entityLoadTask = null;
|
||||
+ this.taskCountToComplete.getAndDecrement(); // we know the chunk load is not done here, as it is not scheduled
|
||||
}
|
||||
|
||||
if (!this.chunkHolder.isPoiChunkLoaded()) {
|
||||
poiLoadTask = this.chunkHolder.getOrLoadPoiData((Consumer)scheduleLoadTask);
|
||||
- count.setPlain(count.getPlain() + 1);
|
||||
} else {
|
||||
poiLoadTask = null;
|
||||
+ this.taskCountToComplete.getAndDecrement(); // we know the chunk load is not done here, as it is not scheduled
|
||||
}
|
||||
|
||||
this.entityLoadTask = entityLoadTask;
|
||||
@@ -107,14 +115,11 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
entityLoadTask.schedule();
|
||||
}
|
||||
|
||||
- if (poiLoadTask != null) {
|
||||
+ if (poiLoadTask != null) {
|
||||
poiLoadTask.schedule();
|
||||
}
|
||||
|
||||
- if (entityLoadTask == null && poiLoadTask == null) {
|
||||
- // no need to wait on those, we can schedule now
|
||||
- this.loadTask.schedule(false);
|
||||
- }
|
||||
+ this.loadTask.schedule(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,15 +134,20 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
|
||||
/*
|
||||
Note: The entityLoadTask/poiLoadTask do not complete when cancelled,
|
||||
- but this is fine because if they are successfully cancelled then
|
||||
- we will successfully cancel the load task, which will complete when cancelled
|
||||
+ so we need to manually try to complete in those cases
|
||||
+ It is also important to note that we set the cancelled field first, just in case
|
||||
+ the chunk load task attempts to complete with a non-null value
|
||||
*/
|
||||
|
||||
if (this.entityLoadTask != null) {
|
||||
- this.entityLoadTask.cancel();
|
||||
+ if (this.entityLoadTask.cancel()) {
|
||||
+ this.tryCompleteLoad();
|
||||
+ }
|
||||
}
|
||||
if (this.poiLoadTask != null) {
|
||||
- this.poiLoadTask.cancel();
|
||||
+ if (this.poiLoadTask.cancel()) {
|
||||
+ this.tryCompleteLoad();
|
||||
+ }
|
||||
}
|
||||
this.loadTask.cancel();
|
||||
}
|
||||
@@ -249,7 +259,7 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
}
|
||||
}
|
||||
|
||||
- public final class ChunkDataLoadTask extends CallbackDataLoadTask<ChunkSerializer.InProgressChunkHolder, ChunkAccess> {
|
||||
+ public static final class ChunkDataLoadTask extends CallbackDataLoadTask<ChunkAccess, ChunkAccess> {
|
||||
protected ChunkDataLoadTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX,
|
||||
final int chunkZ, final PrioritisedExecutor.Priority priority) {
|
||||
super(scheduler, world, chunkX, chunkZ, RegionFileIOThread.RegionFileType.CHUNK_DATA, priority);
|
||||
@@ -262,7 +272,7 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
|
||||
@Override
|
||||
protected boolean hasOnMain() {
|
||||
- return true;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -272,35 +282,30 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
|
||||
@Override
|
||||
protected PrioritisedExecutor.PrioritisedTask createOnMain(final Runnable run, final PrioritisedExecutor.Priority priority) {
|
||||
- return this.scheduler.createChunkTask(this.chunkX, this.chunkZ, run, priority);
|
||||
+ throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected TaskResult<ChunkAccess, Throwable> completeOnMainOffMain(final ChunkSerializer.InProgressChunkHolder data, final Throwable throwable) {
|
||||
- if (data != null) {
|
||||
- return null;
|
||||
- }
|
||||
-
|
||||
- final PoiChunk poiChunk = ChunkLoadTask.this.chunkHolder.getPoiChunk();
|
||||
- if (poiChunk == null) {
|
||||
- LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString());
|
||||
- } else if (!poiChunk.isLoaded()) {
|
||||
- // need to call poiChunk.load() on main
|
||||
- return null;
|
||||
- }
|
||||
+ protected TaskResult<ChunkAccess, Throwable> completeOnMainOffMain(final ChunkAccess data, final Throwable throwable) {
|
||||
+ throw new UnsupportedOperationException();
|
||||
+ }
|
||||
|
||||
- return new TaskResult<>(this.getEmptyChunk(), null);
|
||||
+ private ProtoChunk getEmptyChunk() {
|
||||
+ return new ProtoChunk(
|
||||
+ new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world,
|
||||
+ this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null
|
||||
+ );
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected TaskResult<ChunkSerializer.InProgressChunkHolder, Throwable> runOffMain(final CompoundTag data, final Throwable throwable) {
|
||||
+ protected TaskResult<ChunkAccess, Throwable> runOffMain(final CompoundTag data, final Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
LOGGER.error("Failed to load chunk data for task: " + this.toString() + ", chunk data will be lost", throwable);
|
||||
- return new TaskResult<>(null, null);
|
||||
+ return new TaskResult<>(this.getEmptyChunk(), null);
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
- return new TaskResult<>(null, null);
|
||||
+ return new TaskResult<>(this.getEmptyChunk(), null);
|
||||
}
|
||||
|
||||
// need to convert data, and then deserialize it
|
||||
@@ -319,53 +324,18 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
this.world, chunkMap.getPoiManager(), chunkPos, converted, true
|
||||
);
|
||||
|
||||
- return new TaskResult<>(chunkHolder, null);
|
||||
+ return new TaskResult<>(chunkHolder.protoChunk, null);
|
||||
} catch (final ThreadDeath death) {
|
||||
throw death;
|
||||
} catch (final Throwable thr2) {
|
||||
LOGGER.error("Failed to parse chunk data for task: " + this.toString() + ", chunk data will be lost", thr2);
|
||||
- return new TaskResult<>(null, thr2);
|
||||
+ return new TaskResult<>(this.getEmptyChunk(), null);
|
||||
}
|
||||
}
|
||||
|
||||
- private ProtoChunk getEmptyChunk() {
|
||||
- return new ProtoChunk(
|
||||
- new ChunkPos(this.chunkX, this.chunkZ), UpgradeData.EMPTY, this.world,
|
||||
- this.world.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData)null
|
||||
- );
|
||||
- }
|
||||
-
|
||||
@Override
|
||||
- protected TaskResult<ChunkAccess, Throwable> runOnMain(final ChunkSerializer.InProgressChunkHolder data, final Throwable throwable) {
|
||||
- final PoiChunk poiChunk = ChunkLoadTask.this.chunkHolder.getPoiChunk();
|
||||
- if (poiChunk == null) {
|
||||
- LOGGER.error("Expected poi chunk to be loaded with chunk for task " + this.toString());
|
||||
- } else {
|
||||
- poiChunk.load();
|
||||
- }
|
||||
-
|
||||
- if (data == null || data.protoChunk == null) {
|
||||
- // throwable could be non-null, but the off-main task will print its exceptions - so we don't need to care,
|
||||
- // it's handled already
|
||||
-
|
||||
- return new TaskResult<>(this.getEmptyChunk(), null);
|
||||
- }
|
||||
-
|
||||
- // have tasks to run (at this point, it's just the POI consistency checking)
|
||||
- try {
|
||||
- if (data.tasks != null) {
|
||||
- for (int i = 0, len = data.tasks.size(); i < len; ++i) {
|
||||
- data.tasks.poll().run();
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return new TaskResult<>(data.protoChunk, null);
|
||||
- } catch (final ThreadDeath death) {
|
||||
- throw death;
|
||||
- } catch (final Throwable thr2) {
|
||||
- LOGGER.error("Failed to parse main tasks for task " + this.toString() + ", chunk data will be lost", thr2);
|
||||
- return new TaskResult<>(this.getEmptyChunk(), null);
|
||||
- }
|
||||
+ protected TaskResult<ChunkAccess, Throwable> runOnMain(final ChunkAccess data, final Throwable throwable) {
|
||||
+ throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
index f10ba4211cbdcc4f4ce3585c7cb3f80185e13b73..6f2c7baea0d1ac7813c7b85e1f5558573745762c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
@@ -310,6 +310,17 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ public void checkConsistency(net.minecraft.world.level.chunk.ChunkAccess chunk) {
|
||||
+ int chunkX = chunk.getPos().x;
|
||||
+ int chunkZ = chunk.getPos().z;
|
||||
+ int minY = io.papermc.paper.util.WorldUtil.getMinSection(chunk);
|
||||
+ int maxY = io.papermc.paper.util.WorldUtil.getMaxSection(chunk);
|
||||
+ LevelChunkSection[] sections = chunk.getSections();
|
||||
+ for (int section = minY; section <= maxY; ++section) {
|
||||
+ this.checkConsistencyWithBlocks(SectionPos.of(chunkX, section, chunkZ), sections[section - minY]);
|
||||
+ }
|
||||
+ }
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection chunkSection) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 55da32077d1db81ba197da0be5896da694f4bfa9..a7ee469bb2880a78540b79ae691ea449dfe22ce4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -98,13 +98,11 @@ public class ChunkSerializer {
|
||||
public static final class InProgressChunkHolder {
|
||||
|
||||
public final ProtoChunk protoChunk;
|
||||
- public final java.util.ArrayDeque<Runnable> tasks;
|
||||
|
||||
public CompoundTag poiData;
|
||||
|
||||
- public InProgressChunkHolder(final ProtoChunk protoChunk, final java.util.ArrayDeque<Runnable> tasks) {
|
||||
+ public InProgressChunkHolder(final ProtoChunk protoChunk) {
|
||||
this.protoChunk = protoChunk;
|
||||
- this.tasks = tasks;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
@@ -112,12 +110,10 @@ public class ChunkSerializer {
|
||||
public static ProtoChunk read(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt) {
|
||||
// Paper start - add variant for async calls
|
||||
InProgressChunkHolder holder = loadChunk(world, poiStorage, chunkPos, nbt, true);
|
||||
- holder.tasks.forEach(Runnable::run);
|
||||
return holder.protoChunk;
|
||||
}
|
||||
|
||||
public static InProgressChunkHolder loadChunk(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt, boolean distinguish) {
|
||||
- java.util.ArrayDeque<Runnable> tasksToExecuteOnMain = new java.util.ArrayDeque<>();
|
||||
// Paper end
|
||||
ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos"));
|
||||
|
||||
@@ -184,9 +180,7 @@ public class ChunkSerializer {
|
||||
achunksection[k] = chunksection;
|
||||
SectionPos sectionposition = SectionPos.of(chunkPos, b0);
|
||||
|
||||
- tasksToExecuteOnMain.add(() -> { // Paper - delay this task since we're executing off-main
|
||||
- poiStorage.checkConsistencyWithBlocks(sectionposition, chunksection);
|
||||
- }); // Paper - delay this task since we're executing off-main
|
||||
+ // Paper - rewrite chunk system - moved to final load stage
|
||||
}
|
||||
|
||||
boolean flag3 = nbttagcompound1.contains("BlockLight", 7);
|
||||
@@ -332,7 +326,7 @@ public class ChunkSerializer {
|
||||
}
|
||||
|
||||
if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) {
|
||||
- return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false), tasksToExecuteOnMain); // Paper - Async chunk loading
|
||||
+ return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false)); // Paper - Async chunk loading
|
||||
} else {
|
||||
ProtoChunk protochunk1 = (ProtoChunk) object1;
|
||||
|
||||
@@ -360,7 +354,7 @@ public class ChunkSerializer {
|
||||
protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound5.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight()));
|
||||
}
|
||||
|
||||
- return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading
|
||||
+ return new InProgressChunkHolder(protochunk1); // Paper - Async chunk loading
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,999 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 26 Feb 2023 23:42:29 -0800
|
||||
Subject: [PATCH] Increase parallelism for neighbour writing chunk statuses
|
||||
|
||||
Namely, everything after FEATURES. By creating a dependency
|
||||
chain indicating what chunks are in use, we can safely
|
||||
schedule completely independent tasks in parallel. This
|
||||
will allow the chunk system to scale beyond 10 threads
|
||||
per world.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java
|
||||
index cf7610b3396d03bf79a899d5d9cfc6debb5b90be..48bfee5b9db501fcdba4ddb1e4bff2718956a680 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java
|
||||
@@ -286,7 +286,92 @@ public class RegionizedPlayerChunkLoader {
|
||||
}
|
||||
}
|
||||
|
||||
- return chunks.toLongArray();
|
||||
+ // to increase generation parallelism, we want to space the chunks out so that they are not nearby when generating
|
||||
+ // this also means we are minimising locality
|
||||
+ // but, we need to maintain sorted order by manhatten distance
|
||||
+
|
||||
+ // first, build a map of manhatten distance -> chunks
|
||||
+ final java.util.List<LongArrayList> byDistance = new java.util.ArrayList<>();
|
||||
+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = chunks.iterator(); iterator.hasNext();) {
|
||||
+ final long chunkKey = iterator.nextLong();
|
||||
+
|
||||
+ final int chunkX = CoordinateUtils.getChunkX(chunkKey);
|
||||
+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey);
|
||||
+
|
||||
+ final int dist = Math.abs(chunkX) + Math.abs(chunkZ);
|
||||
+ if (dist == byDistance.size()) {
|
||||
+ final LongArrayList list = new LongArrayList();
|
||||
+ list.add(chunkKey);
|
||||
+ byDistance.add(list);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ byDistance.get(dist).add(chunkKey);
|
||||
+ }
|
||||
+
|
||||
+ // per distance we transform the chunk list so that each element is maximally spaced out from each other
|
||||
+ for (int i = 0, len = byDistance.size(); i < len; ++i) {
|
||||
+ final LongArrayList notAdded = byDistance.get(i).clone();
|
||||
+ final LongArrayList added = new LongArrayList();
|
||||
+
|
||||
+ while (!notAdded.isEmpty()) {
|
||||
+ if (added.isEmpty()) {
|
||||
+ added.add(notAdded.removeLong(notAdded.size() - 1));
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ long maxChunk = -1L;
|
||||
+ int maxDist = 0;
|
||||
+
|
||||
+ // select the chunk from the not yet added set that has the largest minimum distance from
|
||||
+ // the current set of added chunks
|
||||
+
|
||||
+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = notAdded.iterator(); iterator.hasNext();) {
|
||||
+ final long chunkKey = iterator.nextLong();
|
||||
+ final int chunkX = CoordinateUtils.getChunkX(chunkKey);
|
||||
+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey);
|
||||
+
|
||||
+ int minDist = Integer.MAX_VALUE;
|
||||
+
|
||||
+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator2 = added.iterator(); iterator2.hasNext();) {
|
||||
+ final long addedKey = iterator2.nextLong();
|
||||
+ final int addedX = CoordinateUtils.getChunkX(addedKey);
|
||||
+ final int addedZ = CoordinateUtils.getChunkZ(addedKey);
|
||||
+
|
||||
+ // here we use square distance because chunk generation uses neighbours in a square radius
|
||||
+ final int dist = Math.max(Math.abs(addedX - chunkX), Math.abs(addedZ - chunkZ));
|
||||
+
|
||||
+ if (dist < minDist) {
|
||||
+ minDist = dist;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (minDist > maxDist) {
|
||||
+ maxDist = minDist;
|
||||
+ maxChunk = chunkKey;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // move the selected chunk from the not added set to the added set
|
||||
+
|
||||
+ if (!notAdded.rem(maxChunk)) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+
|
||||
+ added.add(maxChunk);
|
||||
+ }
|
||||
+
|
||||
+ byDistance.set(i, added);
|
||||
+ }
|
||||
+
|
||||
+ // now, rebuild the list so that it still maintains manhatten distance order
|
||||
+ final LongArrayList ret = new LongArrayList(chunks.size());
|
||||
+
|
||||
+ for (final LongArrayList dist : byDistance) {
|
||||
+ ret.addAll(dist);
|
||||
+ }
|
||||
+
|
||||
+ return ret.toLongArray();
|
||||
}
|
||||
|
||||
public static final class PlayerChunkLoaderData {
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java
|
||||
index 0b7a2b0ead4f3bc07bfd9a38c2b7cf024bd140c6..36e93fefdfbebddce4c153974c7cd81af3cb92e9 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java
|
||||
@@ -4,7 +4,6 @@ import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
|
||||
import ca.spottedleaf.starlight.common.light.BlockStarLightEngine;
|
||||
import ca.spottedleaf.starlight.common.light.SkyStarLightEngine;
|
||||
import ca.spottedleaf.starlight.common.light.StarLightInterface;
|
||||
-import io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler;
|
||||
import io.papermc.paper.util.CoordinateUtils;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.shorts.ShortCollection;
|
||||
@@ -13,6 +12,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
+import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -201,7 +201,10 @@ public final class LightQueue {
|
||||
this.chunkCoordinate = chunkCoordinate;
|
||||
this.lightEngine = lightEngine;
|
||||
this.queue = queue;
|
||||
- this.task = queue.world.chunkTaskScheduler.lightExecutor.createTask(this, priority);
|
||||
+ this.task = queue.world.chunkTaskScheduler.radiusAwareScheduler.createTask(
|
||||
+ CoordinateUtils.getChunkX(chunkCoordinate), CoordinateUtils.getChunkZ(chunkCoordinate),
|
||||
+ ChunkStatus.LIGHT.writeRadius, this, priority
|
||||
+ );
|
||||
}
|
||||
|
||||
public void schedule() {
|
||||
@@ -230,23 +233,23 @@ public final class LightQueue {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
- final SkyStarLightEngine skyEngine = this.lightEngine.getSkyLightEngine();
|
||||
- final BlockStarLightEngine blockEngine = this.lightEngine.getBlockLightEngine();
|
||||
- try {
|
||||
- synchronized (this.queue) {
|
||||
- this.queue.chunkTasks.remove(this.chunkCoordinate);
|
||||
- }
|
||||
+ synchronized (this.queue) {
|
||||
+ this.queue.chunkTasks.remove(this.chunkCoordinate);
|
||||
+ }
|
||||
|
||||
- boolean litChunk = false;
|
||||
- if (this.lightTasks != null) {
|
||||
- for (final BooleanSupplier run : this.lightTasks) {
|
||||
- if (run.getAsBoolean()) {
|
||||
- litChunk = true;
|
||||
- break;
|
||||
- }
|
||||
+ boolean litChunk = false;
|
||||
+ if (this.lightTasks != null) {
|
||||
+ for (final BooleanSupplier run : this.lightTasks) {
|
||||
+ if (run.getAsBoolean()) {
|
||||
+ litChunk = true;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
+ }
|
||||
|
||||
+ final SkyStarLightEngine skyEngine = this.lightEngine.getSkyLightEngine();
|
||||
+ final BlockStarLightEngine blockEngine = this.lightEngine.getBlockLightEngine();
|
||||
+ try {
|
||||
final long coordinate = this.chunkCoordinate;
|
||||
final int chunkX = CoordinateUtils.getChunkX(coordinate);
|
||||
final int chunkZ = CoordinateUtils.getChunkZ(coordinate);
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
index ce26fdfa1afc74ba93d19157042f6c55778011e1..718c1dd7b52fb9a501d552fdbcb3f9ff79d127d8 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
@@ -1022,17 +1022,23 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
public Boolean tryDrainTicketUpdates() {
|
||||
- final boolean acquired = this.ticketLock.tryLock();
|
||||
- try {
|
||||
- if (!acquired) {
|
||||
- return null;
|
||||
- }
|
||||
+ boolean ret = false;
|
||||
+ for (;;) {
|
||||
+ final boolean acquired = this.ticketLock.tryLock();
|
||||
+ try {
|
||||
+ if (!acquired) {
|
||||
+ return ret ? Boolean.TRUE : null;
|
||||
+ }
|
||||
|
||||
- return Boolean.valueOf(this.drainTicketUpdates());
|
||||
- } finally {
|
||||
- if (acquired) {
|
||||
- this.ticketLock.unlock();
|
||||
+ ret |= this.drainTicketUpdates();
|
||||
+ } finally {
|
||||
+ if (acquired) {
|
||||
+ this.ticketLock.unlock();
|
||||
+ }
|
||||
}
|
||||
+ if (this.delayedTicketUpdates.isEmpty()) {
|
||||
+ return Boolean.valueOf(ret);
|
||||
+ } // else: try to re-acquire
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java
|
||||
index 84d6af5c28cd0e81d50701bebe122f462720fbf8..d2bb266a5ed344507058778a94a8a4dcac61ba17 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java
|
||||
@@ -2,9 +2,9 @@ package io.papermc.paper.chunk.system.scheduling;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
|
||||
import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadPool;
|
||||
-import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadedTaskQueue;
|
||||
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
|
||||
import com.mojang.logging.LogUtils;
|
||||
+import io.papermc.paper.chunk.system.scheduling.queue.RadiusAwarePrioritisedExecutor;
|
||||
import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
import io.papermc.paper.util.CoordinateUtils;
|
||||
import io.papermc.paper.util.TickThread;
|
||||
@@ -21,7 +21,6 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
-import org.bukkit.Bukkit;
|
||||
import org.slf4j.Logger;
|
||||
import java.io.File;
|
||||
import java.util.ArrayDeque;
|
||||
@@ -34,7 +33,6 @@ import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
-import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ChunkTaskScheduler {
|
||||
@@ -108,9 +106,9 @@ public final class ChunkTaskScheduler {
|
||||
|
||||
public final ServerLevel world;
|
||||
public final PrioritisedThreadPool workers;
|
||||
- public final PrioritisedThreadPool.PrioritisedPoolExecutor lightExecutor;
|
||||
- public final PrioritisedThreadPool.PrioritisedPoolExecutor genExecutor;
|
||||
+ public final RadiusAwarePrioritisedExecutor radiusAwareScheduler;
|
||||
public final PrioritisedThreadPool.PrioritisedPoolExecutor parallelGenExecutor;
|
||||
+ private final PrioritisedThreadPool.PrioritisedPoolExecutor radiusAwareGenExecutor;
|
||||
public final PrioritisedThreadPool.PrioritisedPoolExecutor loadExecutor;
|
||||
|
||||
private final PrioritisedThreadedTaskQueue mainThreadExecutor = new PrioritisedThreadedTaskQueue();
|
||||
@@ -191,12 +189,11 @@ public final class ChunkTaskScheduler {
|
||||
this.workers = workers;
|
||||
|
||||
final String worldName = world.getWorld().getName();
|
||||
- this.genExecutor = workers.createExecutor("Chunk single-threaded generation executor for world '" + worldName + "'", 1);
|
||||
- // same as genExecutor, as there are race conditions between updating blocks in FEATURE status while lighting chunks
|
||||
- this.lightExecutor = this.genExecutor;
|
||||
- this.parallelGenExecutor = newChunkSystemGenParallelism <= 1 ? this.genExecutor
|
||||
- : workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", newChunkSystemGenParallelism);
|
||||
+ this.parallelGenExecutor = workers.createExecutor("Chunk parallel generation executor for world '" + worldName + "'", Math.max(1, newChunkSystemGenParallelism));
|
||||
+ this.radiusAwareGenExecutor =
|
||||
+ newChunkSystemGenParallelism <= 1 ? this.parallelGenExecutor : workers.createExecutor("Chunk radius aware generator for world '" + worldName + "'", newChunkSystemGenParallelism);
|
||||
this.loadExecutor = workers.createExecutor("Chunk load executor for world '" + worldName + "'", newChunkSystemLoadParallelism);
|
||||
+ this.radiusAwareScheduler = new RadiusAwarePrioritisedExecutor(this.radiusAwareGenExecutor, Math.max(1, newChunkSystemGenParallelism));
|
||||
this.chunkHolderManager = new ChunkHolderManager(world, this);
|
||||
}
|
||||
|
||||
@@ -688,16 +685,14 @@ public final class ChunkTaskScheduler {
|
||||
}
|
||||
|
||||
public boolean halt(final boolean sync, final long maxWaitNS) {
|
||||
- this.lightExecutor.halt();
|
||||
- this.genExecutor.halt();
|
||||
+ this.radiusAwareGenExecutor.halt();
|
||||
this.parallelGenExecutor.halt();
|
||||
this.loadExecutor.halt();
|
||||
final long time = System.nanoTime();
|
||||
if (sync) {
|
||||
for (long failures = 9L;; failures = ConcurrentUtil.linearLongBackoff(failures, 500_000L, 50_000_000L)) {
|
||||
if (
|
||||
- !this.lightExecutor.isActive() &&
|
||||
- !this.genExecutor.isActive() &&
|
||||
+ !this.radiusAwareGenExecutor.isActive() &&
|
||||
!this.parallelGenExecutor.isActive() &&
|
||||
!this.loadExecutor.isActive()
|
||||
) {
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java
|
||||
index 73ce0909bd89244835a0d0f2030a25871461f1e0..ecc366a4176b2efadc46aa91aa21621f0fc6abe9 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java
|
||||
@@ -39,8 +39,11 @@ public final class ChunkUpgradeGenericStatusTask extends ChunkProgressionTask im
|
||||
this.fromStatus = chunk.getStatus();
|
||||
this.toStatus = toStatus;
|
||||
this.neighbours = neighbours;
|
||||
- this.generateTask = (this.toStatus.isParallelCapable ? this.scheduler.parallelGenExecutor : this.scheduler.genExecutor)
|
||||
- .createTask(this, priority);
|
||||
+ if (this.toStatus.isParallelCapable) {
|
||||
+ this.generateTask = this.scheduler.parallelGenExecutor.createTask(this, priority);
|
||||
+ } else {
|
||||
+ this.generateTask = this.scheduler.radiusAwareScheduler.createTask(chunkX, chunkZ, this.toStatus.writeRadius, this, priority);
|
||||
+ }
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3272f73013ea7d4efdd0ae2903925cc543be7075
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/queue/RadiusAwarePrioritisedExecutor.java
|
||||
@@ -0,0 +1,668 @@
|
||||
+package io.papermc.paper.chunk.system.scheduling.queue;
|
||||
+
|
||||
+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
|
||||
+import io.papermc.paper.util.CoordinateUtils;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Comparator;
|
||||
+import java.util.List;
|
||||
+import java.util.PriorityQueue;
|
||||
+
|
||||
+public class RadiusAwarePrioritisedExecutor {
|
||||
+
|
||||
+ private static final Comparator<DependencyNode> DEPENDENCY_NODE_COMPARATOR = (final DependencyNode t1, final DependencyNode t2) -> {
|
||||
+ return Long.compare(t1.id, t2.id);
|
||||
+ };
|
||||
+
|
||||
+ private final DependencyTree[] queues = new DependencyTree[PrioritisedExecutor.Priority.TOTAL_SCHEDULABLE_PRIORITIES];
|
||||
+ private static final int NO_TASKS_QUEUED = -1;
|
||||
+ private int selectedQueue = NO_TASKS_QUEUED;
|
||||
+ private boolean canQueueTasks = true;
|
||||
+
|
||||
+ public RadiusAwarePrioritisedExecutor(final PrioritisedExecutor executor, final int maxToSchedule) {
|
||||
+ for (int i = 0; i < this.queues.length; ++i) {
|
||||
+ this.queues[i] = new DependencyTree(this, executor, maxToSchedule, i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private boolean canQueueTasks() {
|
||||
+ return this.canQueueTasks;
|
||||
+ }
|
||||
+
|
||||
+ private List<PrioritisedExecutor.PrioritisedTask> treeFinished() {
|
||||
+ this.canQueueTasks = true;
|
||||
+ for (int priority = 0; priority < this.queues.length; ++priority) {
|
||||
+ final DependencyTree queue = this.queues[priority];
|
||||
+ if (queue.hasWaitingTasks()) {
|
||||
+ final List<PrioritisedExecutor.PrioritisedTask> ret = queue.tryPushTasks();
|
||||
+
|
||||
+ if (ret == null || ret.isEmpty()) {
|
||||
+ // this happens when the tasks in the wait queue were purged
|
||||
+ // in this case, the queue was actually empty, we just had to purge it
|
||||
+ // if we set the selected queue without scheduling any tasks, the queue will never be unselected
|
||||
+ // as that requires a scheduled task completing...
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.selectedQueue = priority;
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.selectedQueue = NO_TASKS_QUEUED;
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private List<PrioritisedExecutor.PrioritisedTask> queue(final Task task, final PrioritisedExecutor.Priority priority) {
|
||||
+ final int priorityId = priority.priority;
|
||||
+ final DependencyTree queue = this.queues[priorityId];
|
||||
+
|
||||
+ final DependencyNode node = new DependencyNode(task, queue);
|
||||
+
|
||||
+ if (task.dependencyNode != null) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ task.dependencyNode = node;
|
||||
+
|
||||
+ queue.pushNode(node);
|
||||
+
|
||||
+ if (this.selectedQueue == NO_TASKS_QUEUED) {
|
||||
+ this.canQueueTasks = true;
|
||||
+ this.selectedQueue = priorityId;
|
||||
+ return queue.tryPushTasks();
|
||||
+ }
|
||||
+
|
||||
+ if (!this.canQueueTasks) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (PrioritisedExecutor.Priority.isHigherPriority(priorityId, this.selectedQueue)) {
|
||||
+ // prevent the lower priority tree from queueing more tasks
|
||||
+ this.canQueueTasks = false;
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ // priorityId != selectedQueue: lower priority, don't care - treeFinished will pick it up
|
||||
+ return priorityId == this.selectedQueue ? queue.tryPushTasks() : null;
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius,
|
||||
+ final Runnable run, final PrioritisedExecutor.Priority priority) {
|
||||
+ if (radius < 0) {
|
||||
+ throw new IllegalArgumentException("Radius must be > 0: " + radius);
|
||||
+ }
|
||||
+ return new Task(this, chunkX, chunkZ, radius, run, priority);
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask createTask(final int chunkX, final int chunkZ, final int radius,
|
||||
+ final Runnable run) {
|
||||
+ return this.createTask(chunkX, chunkZ, radius, run, PrioritisedExecutor.Priority.NORMAL);
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius,
|
||||
+ final Runnable run, final PrioritisedExecutor.Priority priority) {
|
||||
+ final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run, priority);
|
||||
+
|
||||
+ ret.queue();
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask queueTask(final int chunkX, final int chunkZ, final int radius,
|
||||
+ final Runnable run) {
|
||||
+ final PrioritisedExecutor.PrioritisedTask ret = this.createTask(chunkX, chunkZ, radius, run);
|
||||
+
|
||||
+ ret.queue();
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) {
|
||||
+ return new Task(this, 0, 0, -1, run, priority);
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask createInfiniteRadiusTask(final Runnable run) {
|
||||
+ return this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL);
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run, final PrioritisedExecutor.Priority priority) {
|
||||
+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, priority);
|
||||
+
|
||||
+ ret.queue();
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask queueInfiniteRadiusTask(final Runnable run) {
|
||||
+ final PrioritisedExecutor.PrioritisedTask ret = this.createInfiniteRadiusTask(run, PrioritisedExecutor.Priority.NORMAL);
|
||||
+
|
||||
+ ret.queue();
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ // all accesses must be synchronised by the radius aware object
|
||||
+ private static final class DependencyTree {
|
||||
+
|
||||
+ private final RadiusAwarePrioritisedExecutor scheduler;
|
||||
+ private final PrioritisedExecutor executor;
|
||||
+ private final int maxToSchedule;
|
||||
+ private final int treeIndex;
|
||||
+
|
||||
+ private int currentlyExecuting;
|
||||
+ private long idGenerator;
|
||||
+
|
||||
+ private final PriorityQueue<DependencyNode> awaiting = new PriorityQueue<>(DEPENDENCY_NODE_COMPARATOR);
|
||||
+
|
||||
+ private final PriorityQueue<DependencyNode> infiniteRadius = new PriorityQueue<>(DEPENDENCY_NODE_COMPARATOR);
|
||||
+ private boolean isInfiniteRadiusScheduled;
|
||||
+
|
||||
+ private final Long2ReferenceOpenHashMap<DependencyNode> nodeByPosition = new Long2ReferenceOpenHashMap<>();
|
||||
+
|
||||
+ public DependencyTree(final RadiusAwarePrioritisedExecutor scheduler, final PrioritisedExecutor executor,
|
||||
+ final int maxToSchedule, final int treeIndex) {
|
||||
+ this.scheduler = scheduler;
|
||||
+ this.executor = executor;
|
||||
+ this.maxToSchedule = maxToSchedule;
|
||||
+ this.treeIndex = treeIndex;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasWaitingTasks() {
|
||||
+ return !this.awaiting.isEmpty() || !this.infiniteRadius.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ private long nextId() {
|
||||
+ return this.idGenerator++;
|
||||
+ }
|
||||
+
|
||||
+ private boolean isExecutingAnyTasks() {
|
||||
+ return this.currentlyExecuting != 0;
|
||||
+ }
|
||||
+
|
||||
+ private void pushNode(final DependencyNode node) {
|
||||
+ if (!node.task.isFiniteRadius()) {
|
||||
+ this.infiniteRadius.add(node);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // set up dependency for node
|
||||
+ final Task task = node.task;
|
||||
+
|
||||
+ final int centerX = task.chunkX;
|
||||
+ final int centerZ = task.chunkZ;
|
||||
+ final int radius = task.radius;
|
||||
+
|
||||
+ final int minX = centerX - radius;
|
||||
+ final int maxX = centerX + radius;
|
||||
+
|
||||
+ final int minZ = centerZ - radius;
|
||||
+ final int maxZ = centerZ + radius;
|
||||
+
|
||||
+ ReferenceOpenHashSet<DependencyNode> parents = null;
|
||||
+ for (int currZ = minZ; currZ <= maxZ; ++currZ) {
|
||||
+ for (int currX = minX; currX <= maxX; ++currX) {
|
||||
+ final DependencyNode dependency = this.nodeByPosition.put(CoordinateUtils.getChunkKey(currX, currZ), node);
|
||||
+ if (dependency != null) {
|
||||
+ if (parents == null) {
|
||||
+ parents = new ReferenceOpenHashSet<>();
|
||||
+ }
|
||||
+ if (parents.add(dependency)) {
|
||||
+ // added a dependency, so we need to add as a child to the dependency
|
||||
+ if (dependency.children == null) {
|
||||
+ dependency.children = new ArrayList<>();
|
||||
+ }
|
||||
+ dependency.children.add(node);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (parents == null) {
|
||||
+ // no dependencies, add straight to awaiting
|
||||
+ this.awaiting.add(node);
|
||||
+ } else {
|
||||
+ node.parents = parents;
|
||||
+ // we will be added to awaiting once we have no parents
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // called only when a node is returned after being executed
|
||||
+ private List<PrioritisedExecutor.PrioritisedTask> returnNode(final DependencyNode node) {
|
||||
+ final Task task = node.task;
|
||||
+
|
||||
+ // now that the task is completed, we can push its children to the awaiting queue
|
||||
+ this.pushChildren(node);
|
||||
+
|
||||
+ if (task.isFiniteRadius()) {
|
||||
+ // remove from dependency map
|
||||
+ this.removeNodeFromMap(node);
|
||||
+ } else {
|
||||
+ // mark as no longer executing infinite radius
|
||||
+ if (!this.isInfiniteRadiusScheduled) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ this.isInfiniteRadiusScheduled = false;
|
||||
+ }
|
||||
+
|
||||
+ // decrement executing count, we are done executing this task
|
||||
+ --this.currentlyExecuting;
|
||||
+
|
||||
+ if (this.currentlyExecuting == 0) {
|
||||
+ return this.scheduler.treeFinished();
|
||||
+ }
|
||||
+
|
||||
+ return this.scheduler.canQueueTasks() ? this.tryPushTasks() : null;
|
||||
+ }
|
||||
+
|
||||
+ private List<PrioritisedExecutor.PrioritisedTask> tryPushTasks() {
|
||||
+ // tasks are not queued, but only created here - we do hold the lock for the map
|
||||
+ List<PrioritisedExecutor.PrioritisedTask> ret = null;
|
||||
+ PrioritisedExecutor.PrioritisedTask pushedTask;
|
||||
+ while ((pushedTask = this.tryPushTask()) != null) {
|
||||
+ if (ret == null) {
|
||||
+ ret = new ArrayList<>();
|
||||
+ }
|
||||
+ ret.add(pushedTask);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ private void removeNodeFromMap(final DependencyNode node) {
|
||||
+ final Task task = node.task;
|
||||
+
|
||||
+ final int centerX = task.chunkX;
|
||||
+ final int centerZ = task.chunkZ;
|
||||
+ final int radius = task.radius;
|
||||
+
|
||||
+ final int minX = centerX - radius;
|
||||
+ final int maxX = centerX + radius;
|
||||
+
|
||||
+ final int minZ = centerZ - radius;
|
||||
+ final int maxZ = centerZ + radius;
|
||||
+
|
||||
+ for (int currZ = minZ; currZ <= maxZ; ++currZ) {
|
||||
+ for (int currX = minX; currX <= maxX; ++currX) {
|
||||
+ this.nodeByPosition.remove(CoordinateUtils.getChunkKey(currX, currZ), node);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void pushChildren(final DependencyNode node) {
|
||||
+ // add all the children that we can into awaiting
|
||||
+ final List<DependencyNode> children = node.children;
|
||||
+ if (children != null) {
|
||||
+ for (int i = 0, len = children.size(); i < len; ++i) {
|
||||
+ final DependencyNode child = children.get(i);
|
||||
+ if (!child.parents.remove(node)) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ if (child.parents.isEmpty()) {
|
||||
+ // no more dependents, we can push to awaiting
|
||||
+ child.parents = null;
|
||||
+ // even if the child is purged, we need to push it so that its children will be pushed
|
||||
+ this.awaiting.add(child);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private DependencyNode pollAwaiting() {
|
||||
+ final DependencyNode ret = this.awaiting.poll();
|
||||
+ if (ret == null) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (ret.parents != null) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+
|
||||
+ if (ret.purged) {
|
||||
+ // need to manually remove from state here
|
||||
+ this.pushChildren(ret);
|
||||
+ this.removeNodeFromMap(ret);
|
||||
+ } // else: delay children push until the task has finished
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ private DependencyNode pollInfinite() {
|
||||
+ return this.infiniteRadius.poll();
|
||||
+ }
|
||||
+
|
||||
+ public PrioritisedExecutor.PrioritisedTask tryPushTask() {
|
||||
+ if (this.currentlyExecuting >= this.maxToSchedule || this.isInfiniteRadiusScheduled) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ DependencyNode firstInfinite;
|
||||
+ while ((firstInfinite = this.infiniteRadius.peek()) != null && firstInfinite.purged) {
|
||||
+ this.pollInfinite();
|
||||
+ }
|
||||
+
|
||||
+ DependencyNode firstAwaiting;
|
||||
+ while ((firstAwaiting = this.awaiting.peek()) != null && firstAwaiting.purged) {
|
||||
+ this.pollAwaiting();
|
||||
+ }
|
||||
+
|
||||
+ if (firstInfinite == null && firstAwaiting == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ // firstAwaiting compared to firstInfinite
|
||||
+ final int compare;
|
||||
+
|
||||
+ if (firstAwaiting == null) {
|
||||
+ // we choose first infinite, or infinite < awaiting
|
||||
+ compare = 1;
|
||||
+ } else if (firstInfinite == null) {
|
||||
+ // we choose first awaiting, or awaiting < infinite
|
||||
+ compare = -1;
|
||||
+ } else {
|
||||
+ compare = DEPENDENCY_NODE_COMPARATOR.compare(firstAwaiting, firstInfinite);
|
||||
+ }
|
||||
+
|
||||
+ if (compare >= 0) {
|
||||
+ if (this.currentlyExecuting != 0) {
|
||||
+ // don't queue infinite task while other tasks are executing in parallel
|
||||
+ return null;
|
||||
+ }
|
||||
+ ++this.currentlyExecuting;
|
||||
+ this.pollInfinite();
|
||||
+ this.isInfiniteRadiusScheduled = true;
|
||||
+ return firstInfinite.task.pushTask(this.executor);
|
||||
+ } else {
|
||||
+ ++this.currentlyExecuting;
|
||||
+ this.pollAwaiting();
|
||||
+ return firstAwaiting.task.pushTask(this.executor);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static final class DependencyNode {
|
||||
+
|
||||
+ private final Task task;
|
||||
+ private final DependencyTree tree;
|
||||
+
|
||||
+ // dependency tree fields
|
||||
+ // (must hold lock on the scheduler to use)
|
||||
+ // null is the same as empty, we just use it so that we don't allocate the set unless we need to
|
||||
+ private List<DependencyNode> children;
|
||||
+ // null is the same as empty, indicating that this task is considered "awaiting"
|
||||
+ private ReferenceOpenHashSet<DependencyNode> parents;
|
||||
+ // false -> scheduled and not cancelled
|
||||
+ // true -> scheduled but cancelled
|
||||
+ private boolean purged;
|
||||
+ private final long id;
|
||||
+
|
||||
+ public DependencyNode(final Task task, final DependencyTree tree) {
|
||||
+ this.task = task;
|
||||
+ this.id = tree.nextId();
|
||||
+ this.tree = tree;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static final class Task implements PrioritisedExecutor.PrioritisedTask, Runnable {
|
||||
+
|
||||
+ // task specific fields
|
||||
+ private final RadiusAwarePrioritisedExecutor scheduler;
|
||||
+ private final int chunkX;
|
||||
+ private final int chunkZ;
|
||||
+ private final int radius;
|
||||
+ private Runnable run;
|
||||
+ private PrioritisedExecutor.Priority priority;
|
||||
+
|
||||
+ private DependencyNode dependencyNode;
|
||||
+ private PrioritisedExecutor.PrioritisedTask queuedTask;
|
||||
+
|
||||
+ private Task(final RadiusAwarePrioritisedExecutor scheduler, final int chunkX, final int chunkZ, final int radius,
|
||||
+ final Runnable run, final PrioritisedExecutor.Priority priority) {
|
||||
+ this.scheduler = scheduler;
|
||||
+ this.chunkX = chunkX;
|
||||
+ this.chunkZ = chunkZ;
|
||||
+ this.radius = radius;
|
||||
+ this.run = run;
|
||||
+ this.priority = priority;
|
||||
+ }
|
||||
+
|
||||
+ private boolean isFiniteRadius() {
|
||||
+ return this.radius >= 0;
|
||||
+ }
|
||||
+
|
||||
+ private PrioritisedExecutor.PrioritisedTask pushTask(final PrioritisedExecutor executor) {
|
||||
+ return this.queuedTask = executor.createTask(this, this.priority);
|
||||
+ }
|
||||
+
|
||||
+ private void executeTask() {
|
||||
+ final Runnable run = this.run;
|
||||
+ this.run = null;
|
||||
+ run.run();
|
||||
+ }
|
||||
+
|
||||
+ private static void scheduleTasks(final List<PrioritisedExecutor.PrioritisedTask> toSchedule) {
|
||||
+ if (toSchedule != null) {
|
||||
+ for (int i = 0, len = toSchedule.size(); i < len; ++i) {
|
||||
+ toSchedule.get(i).queue();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void returnNode() {
|
||||
+ final List<PrioritisedExecutor.PrioritisedTask> toSchedule;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ final DependencyNode node = this.dependencyNode;
|
||||
+ this.dependencyNode = null;
|
||||
+ toSchedule = node.tree.returnNode(node);
|
||||
+ }
|
||||
+
|
||||
+ scheduleTasks(toSchedule);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ final Runnable run = this.run;
|
||||
+ this.run = null;
|
||||
+ try {
|
||||
+ run.run();
|
||||
+ } finally {
|
||||
+ this.returnNode();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean queue() {
|
||||
+ final List<PrioritisedExecutor.PrioritisedTask> toSchedule;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if (this.queuedTask != null || this.dependencyNode != null || this.priority == PrioritisedExecutor.Priority.COMPLETING) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ toSchedule = this.scheduler.queue(this, this.priority);
|
||||
+ }
|
||||
+
|
||||
+ scheduleTasks(toSchedule);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean cancel() {
|
||||
+ final PrioritisedExecutor.PrioritisedTask task;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if ((task = this.queuedTask) == null) {
|
||||
+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ this.priority = PrioritisedExecutor.Priority.COMPLETING;
|
||||
+ if (this.dependencyNode != null) {
|
||||
+ this.dependencyNode.purged = true;
|
||||
+ this.dependencyNode = null;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (task.cancel()) {
|
||||
+ // must manually return the node
|
||||
+ this.run = null;
|
||||
+ this.returnNode();
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean execute() {
|
||||
+ final PrioritisedExecutor.PrioritisedTask task;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if ((task = this.queuedTask) == null) {
|
||||
+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ this.priority = PrioritisedExecutor.Priority.COMPLETING;
|
||||
+ if (this.dependencyNode != null) {
|
||||
+ this.dependencyNode.purged = true;
|
||||
+ this.dependencyNode = null;
|
||||
+ }
|
||||
+ // fall through to execution logic
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (task != null) {
|
||||
+ // will run the return node logic automatically
|
||||
+ return task.execute();
|
||||
+ } else {
|
||||
+ // don't run node removal/insertion logic, we aren't actually removed from the dependency tree
|
||||
+ this.executeTask();
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public PrioritisedExecutor.Priority getPriority() {
|
||||
+ final PrioritisedExecutor.PrioritisedTask task;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if ((task = this.queuedTask) == null) {
|
||||
+ return this.priority;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return task.getPriority();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean setPriority(final PrioritisedExecutor.Priority priority) {
|
||||
+ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
|
||||
+ throw new IllegalArgumentException("Invalid priority " + priority);
|
||||
+ }
|
||||
+
|
||||
+ final PrioritisedExecutor.PrioritisedTask task;
|
||||
+ List<PrioritisedExecutor.PrioritisedTask> toSchedule = null;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if ((task = this.queuedTask) == null) {
|
||||
+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (this.priority == priority) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ this.priority = priority;
|
||||
+ if (this.dependencyNode != null) {
|
||||
+ // need to re-insert node
|
||||
+ this.dependencyNode.purged = true;
|
||||
+ this.dependencyNode = null;
|
||||
+ toSchedule = this.scheduler.queue(this, priority);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (task != null) {
|
||||
+ return task.setPriority(priority);
|
||||
+ }
|
||||
+
|
||||
+ scheduleTasks(toSchedule);
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean raisePriority(final PrioritisedExecutor.Priority priority) {
|
||||
+ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
|
||||
+ throw new IllegalArgumentException("Invalid priority " + priority);
|
||||
+ }
|
||||
+
|
||||
+ final PrioritisedExecutor.PrioritisedTask task;
|
||||
+ List<PrioritisedExecutor.PrioritisedTask> toSchedule = null;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if ((task = this.queuedTask) == null) {
|
||||
+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (this.priority.isHigherOrEqualPriority(priority)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ this.priority = priority;
|
||||
+ if (this.dependencyNode != null) {
|
||||
+ // need to re-insert node
|
||||
+ this.dependencyNode.purged = true;
|
||||
+ this.dependencyNode = null;
|
||||
+ toSchedule = this.scheduler.queue(this, priority);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (task != null) {
|
||||
+ return task.raisePriority(priority);
|
||||
+ }
|
||||
+
|
||||
+ scheduleTasks(toSchedule);
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean lowerPriority(final PrioritisedExecutor.Priority priority) {
|
||||
+ if (!PrioritisedExecutor.Priority.isValidPriority(priority)) {
|
||||
+ throw new IllegalArgumentException("Invalid priority " + priority);
|
||||
+ }
|
||||
+
|
||||
+ final PrioritisedExecutor.PrioritisedTask task;
|
||||
+ List<PrioritisedExecutor.PrioritisedTask> toSchedule = null;
|
||||
+ synchronized (this.scheduler) {
|
||||
+ if ((task = this.queuedTask) == null) {
|
||||
+ if (this.priority == PrioritisedExecutor.Priority.COMPLETING) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (this.priority.isLowerOrEqualPriority(priority)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ this.priority = priority;
|
||||
+ if (this.dependencyNode != null) {
|
||||
+ // need to re-insert node
|
||||
+ this.dependencyNode.purged = true;
|
||||
+ this.dependencyNode = null;
|
||||
+ toSchedule = this.scheduler.queue(this, priority);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (task != null) {
|
||||
+ return task.lowerPriority(priority);
|
||||
+ }
|
||||
+
|
||||
+ scheduleTasks(toSchedule);
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
|
||||
index c709e27a00d8617f9a3346f85bd88ce47baa9c76..b4be02ec4bb77059f79d3e4d6a6f1ee4843a01f9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
|
||||
@@ -94,7 +94,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
|
||||
++totalChunks;
|
||||
}
|
||||
|
||||
- this.chunkMap.level.chunkTaskScheduler.lightExecutor.queueRunnable(() -> { // Paper - rewrite chunk system
|
||||
+ this.chunkMap.level.chunkTaskScheduler.radiusAwareScheduler.queueInfiniteRadiusTask(() -> { // Paper - rewrite chunk system
|
||||
this.theLightEngine.relightChunks(chunks, (ChunkPos chunkPos) -> {
|
||||
chunkLightCallback.accept(chunkPos);
|
||||
((java.util.concurrent.Executor)((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().mainThreadProcessor).execute(() -> {
|
@ -0,0 +1,71 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 15 May 2023 12:24:17 -0700
|
||||
Subject: [PATCH] Properly cancel chunk load tasks that were not scheduled
|
||||
|
||||
Since the chunk load task was not scheduled, the entity/poi load
|
||||
task fields will not be set, but the task complete counter
|
||||
will not be adjusted. Thus, the chunk load task will not complete.
|
||||
|
||||
To resolve this, detect when the entity/poi tasks were not scheduled
|
||||
and decrement the task complete counter in such cases.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java
|
||||
index 1f7c146ff0b2a835c818f49da6c1f1411f26aa39..34dc2153e90a29bc9102d9497c3c53b5de15508e 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java
|
||||
@@ -25,7 +25,6 @@ import org.slf4j.Logger;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
-import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
@@ -125,8 +124,12 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
@Override
|
||||
public void cancel() {
|
||||
// must be before load task access, so we can synchronise with the writes to the fields
|
||||
+ final boolean scheduled;
|
||||
this.scheduler.schedulingLock.lock();
|
||||
try {
|
||||
+ // fix cancellation of chunk load task - must read field here, as it may be written later conucrrently -
|
||||
+ // we need to know if we scheduled _before_ cancellation
|
||||
+ scheduled = this.scheduled;
|
||||
this.cancelled = true;
|
||||
} finally {
|
||||
this.scheduler.schedulingLock.unlock();
|
||||
@@ -139,15 +142,26 @@ public final class ChunkLoadTask extends ChunkProgressionTask {
|
||||
the chunk load task attempts to complete with a non-null value
|
||||
*/
|
||||
|
||||
- if (this.entityLoadTask != null) {
|
||||
- if (this.entityLoadTask.cancel()) {
|
||||
- this.tryCompleteLoad();
|
||||
+ if (scheduled) {
|
||||
+ // since we scheduled, we need to cancel the tasks
|
||||
+ if (this.entityLoadTask != null) {
|
||||
+ if (this.entityLoadTask.cancel()) {
|
||||
+ this.tryCompleteLoad();
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
- if (this.poiLoadTask != null) {
|
||||
- if (this.poiLoadTask.cancel()) {
|
||||
- this.tryCompleteLoad();
|
||||
+ if (this.poiLoadTask != null) {
|
||||
+ if (this.poiLoadTask.cancel()) {
|
||||
+ this.tryCompleteLoad();
|
||||
+ }
|
||||
}
|
||||
+ } else {
|
||||
+ // since nothing was scheduled, we need to decrement the task count here ourselves
|
||||
+
|
||||
+ // for entity load task
|
||||
+ this.tryCompleteLoad();
|
||||
+
|
||||
+ // for poi load task
|
||||
+ this.tryCompleteLoad();
|
||||
}
|
||||
this.loadTask.cancel();
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 15 May 2023 11:34:28 -0700
|
||||
Subject: [PATCH] Mark POI/Entity load tasks as completed before releasing
|
||||
scheduling lock
|
||||
|
||||
It must be marked as completed during that lock hold since the
|
||||
waiters field is set to null. Thus, any other thread attempting
|
||||
a cancellation will fail to remove from waiters. Also, any
|
||||
other thread attempting to cancel may set the completed field
|
||||
to true which would cause accept() to fail as well.
|
||||
|
||||
Completion was always designed to happen while holding the
|
||||
scheduling lock to prevent these race conditions. The code
|
||||
was originally set up to complete while not holding the
|
||||
scheduling lock to avoid invoking callbacks while holding the
|
||||
lock, however the access to the completion field was not
|
||||
considered.
|
||||
|
||||
Resolve this by marking the callback as completed during the
|
||||
lock, but invoking the accept() function after releasing
|
||||
the lock. This will prevent any cancellation attempts to be
|
||||
blocked, and allow the current thread to complete the callback
|
||||
without any issues.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java
|
||||
index 8013dd333e27aa5fd0beb431fa32491eec9f5246..efc9b7a304f10b6a23a36cffb0a4aaea6ab71129 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java
|
||||
@@ -156,6 +156,12 @@ public final class NewChunkHolder {
|
||||
LOGGER.error("Unhandled entity data load exception, data data will be lost: ", result.right());
|
||||
}
|
||||
|
||||
+ // Folia start - mark these tasks as completed before releasing the scheduling lock
|
||||
+ for (final GenericDataLoadTaskCallback callback : waiters) {
|
||||
+ callback.markCompleted();
|
||||
+ }
|
||||
+ // Folia end - mark these tasks as completed before releasing the scheduling lock
|
||||
+
|
||||
completeWaiters = waiters;
|
||||
} else {
|
||||
// cancelled
|
||||
@@ -187,7 +193,7 @@ public final class NewChunkHolder {
|
||||
// avoid holding the scheduling lock while completing
|
||||
if (completeWaiters != null) {
|
||||
for (final GenericDataLoadTaskCallback callback : completeWaiters) {
|
||||
- callback.accept(result);
|
||||
+ callback.acceptCompleted(result); // Folia - mark these tasks as completed before releasing the scheduling lock
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +279,12 @@ public final class NewChunkHolder {
|
||||
LOGGER.error("Unhandled poi load exception, poi data will be lost: ", result.right());
|
||||
}
|
||||
|
||||
+ // Folia start - mark these tasks as completed before releasing the scheduling lock
|
||||
+ for (final GenericDataLoadTaskCallback callback : waiters) {
|
||||
+ callback.markCompleted();
|
||||
+ }
|
||||
+ // Folia end - mark these tasks as completed before releasing the scheduling lock
|
||||
+
|
||||
completeWaiters = waiters;
|
||||
} else {
|
||||
// cancelled
|
||||
@@ -304,7 +316,7 @@ public final class NewChunkHolder {
|
||||
// avoid holding the scheduling lock while completing
|
||||
if (completeWaiters != null) {
|
||||
for (final GenericDataLoadTaskCallback callback : completeWaiters) {
|
||||
- callback.accept(result);
|
||||
+ callback.acceptCompleted(result); // Folia - mark these tasks as completed before releasing the scheduling lock
|
||||
}
|
||||
}
|
||||
this.scheduler.schedulingLock.lock();
|
||||
@@ -357,7 +369,7 @@ public final class NewChunkHolder {
|
||||
}
|
||||
}
|
||||
|
||||
- public static abstract class GenericDataLoadTaskCallback implements Cancellable, Consumer<GenericDataLoadTask.TaskResult<?, Throwable>> {
|
||||
+ public static abstract class GenericDataLoadTaskCallback implements Cancellable { // Folia - mark callbacks as completed before unlocking scheduling lock
|
||||
|
||||
protected final Consumer<GenericDataLoadTask.TaskResult<?, Throwable>> consumer;
|
||||
protected final NewChunkHolder chunkHolder;
|
||||
@@ -393,13 +405,23 @@ public final class NewChunkHolder {
|
||||
return this.completed = true;
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public void accept(final GenericDataLoadTask.TaskResult<?, Throwable> result) {
|
||||
+ // Folia start - mark callbacks as completed before unlocking scheduling lock
|
||||
+ // must hold scheduling lock
|
||||
+ void markCompleted() {
|
||||
+ if (this.completed) {
|
||||
+ throw new IllegalStateException("May not be completed here");
|
||||
+ }
|
||||
+ this.completed = true;
|
||||
+ }
|
||||
+ // Folia end - mark callbacks as completed before unlocking scheduling lock
|
||||
+
|
||||
+ // Folia - mark callbacks as completed before unlocking scheduling lock
|
||||
+ void acceptCompleted(final GenericDataLoadTask.TaskResult<?, Throwable> result) {
|
||||
if (result != null) {
|
||||
- if (this.setCompleted()) {
|
||||
+ if (this.completed) { // Folia - mark callbacks as completed before unlocking scheduling lock
|
||||
this.consumer.accept(result);
|
||||
} else {
|
||||
- throw new IllegalStateException("Cannot be cancelled at this point");
|
||||
+ throw new IllegalStateException("Cannot be uncompleted at this point"); // Folia - mark callbacks as completed before unlocking scheduling lock
|
||||
}
|
||||
} else {
|
||||
throw new NullPointerException("Result cannot be null (cancelled)");
|
@ -5,7 +5,7 @@ Subject: [PATCH] Allow for toggling of spawn chunks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index d87f02c748fe2e5b4ea251f6691e8907a152cb6d..f21ba175538436e59c45d5350ef7b2605ed96775 100644
|
||||
index 5988c0847af4e8f0094328e91f736f25d567db60..fb78a91d1ab77f909823422c6d4e2ef7ed10c9c3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -261,6 +261,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
119
patches/server/0031-Cache-whether-region-files-do-not-exist.patch
Normale Datei
119
patches/server/0031-Cache-whether-region-files-do-not-exist.patch
Normale Datei
@ -0,0 +1,119 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 2 Mar 2023 23:19:04 -0800
|
||||
Subject: [PATCH] Cache whether region files do not exist
|
||||
|
||||
The repeated I/O of creating the directory for the regionfile
|
||||
or for checking if the file exists can be heavy in
|
||||
when pushing chunk generation extremely hard - as each chunk gen
|
||||
request may effectively go through to the I/O thread.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java
|
||||
index a08cde4eefe879adcee7c4118bc38f98c5097ed0..8a11e10b01fa012b2f98b1c193c53251e848f909 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java
|
||||
@@ -819,8 +819,14 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread {
|
||||
return file.hasChunk(chunkPos) ? Boolean.TRUE : Boolean.FALSE;
|
||||
});
|
||||
} else {
|
||||
+ // first check if the region file for sure does not exist
|
||||
+ if (taskController.doesRegionFileNotExist(chunkX, chunkZ)) {
|
||||
+ return Boolean.FALSE;
|
||||
+ } // else: it either exists or is not known, fall back to checking the loaded region file
|
||||
+
|
||||
return taskController.computeForRegionFileIfLoaded(chunkX, chunkZ, (final RegionFile file) -> {
|
||||
if (file == null) { // null if not loaded
|
||||
+ // not sure at this point, let the I/O thread figure it out
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
@@ -1116,6 +1122,10 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread {
|
||||
return !this.tasks.isEmpty();
|
||||
}
|
||||
|
||||
+ public boolean doesRegionFileNotExist(final int chunkX, final int chunkZ) {
|
||||
+ return this.getCache().doesRegionFileNotExistNoIO(new ChunkPos(chunkX, chunkZ));
|
||||
+ }
|
||||
+
|
||||
public <T> T computeForRegionFile(final int chunkX, final int chunkZ, final boolean existingOnly, final Function<RegionFile, T> function) {
|
||||
final RegionFileStorage cache = this.getCache();
|
||||
final RegionFile regionFile;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 18ef7025f7f4dc2a4aff85ca65ff5a2d35a1ef06..fe8bb0037bb7f317fc32ac34461f4eb3a1f397f2 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -24,6 +24,35 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
private final Path folder;
|
||||
private final boolean sync;
|
||||
|
||||
+ // Paper start - cache regionfile does not exist state
|
||||
+ static final int MAX_NON_EXISTING_CACHE = 1024 * 64;
|
||||
+ private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet();
|
||||
+ private synchronized boolean doesRegionFilePossiblyExist(long position) {
|
||||
+ if (this.nonExistingRegionFiles.contains(position)) {
|
||||
+ this.nonExistingRegionFiles.addAndMoveToFirst(position);
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private synchronized void createRegionFile(long position) {
|
||||
+ this.nonExistingRegionFiles.remove(position);
|
||||
+ }
|
||||
+
|
||||
+ private synchronized void markNonExisting(long position) {
|
||||
+ if (this.nonExistingRegionFiles.addAndMoveToFirst(position)) {
|
||||
+ while (this.nonExistingRegionFiles.size() >= MAX_NON_EXISTING_CACHE) {
|
||||
+ this.nonExistingRegionFiles.removeLastLong();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public synchronized boolean doesRegionFileNotExistNoIO(ChunkPos pos) {
|
||||
+ long key = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ());
|
||||
+ return !this.doesRegionFilePossiblyExist(key);
|
||||
+ }
|
||||
+ // Paper end - cache regionfile does not exist state
|
||||
+
|
||||
protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor
|
||||
this.folder = directory;
|
||||
this.sync = dsync;
|
||||
@@ -45,7 +74,7 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException {
|
||||
// Paper end
|
||||
- long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ());
|
||||
+ long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); final long regionPos = i; // Paper - OBFHELPER
|
||||
RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i);
|
||||
|
||||
if (regionfile != null) {
|
||||
@@ -57,15 +86,27 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
// Paper end
|
||||
return regionfile;
|
||||
} else {
|
||||
+ // Paper start - cache regionfile does not exist state
|
||||
+ if (existingOnly && !this.doesRegionFilePossiblyExist(regionPos)) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - cache regionfile does not exist state
|
||||
if (this.regionCache.size() >= 256) {
|
||||
((RegionFile) this.regionCache.removeLast()).close();
|
||||
}
|
||||
|
||||
- FileUtil.createDirectoriesSafe(this.folder);
|
||||
+ // Paper - only create directory if not existing only - moved down
|
||||
Path path = this.folder;
|
||||
int j = chunkcoordintpair.getRegionX();
|
||||
Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
|
||||
- if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit
|
||||
+ if (existingOnly && !java.nio.file.Files.exists(path1)) { // Paper start - cache regionfile does not exist state
|
||||
+ this.markNonExisting(regionPos);
|
||||
+ return null; // CraftBukkit
|
||||
+ } else {
|
||||
+ this.createRegionFile(regionPos);
|
||||
+ }
|
||||
+ // Paper end - cache regionfile does not exist state
|
||||
+ FileUtil.createDirectoriesSafe(this.folder); // Paper - only create directory if not existing only - moved from above
|
||||
RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
|
||||
|
||||
this.regionCache.putAndMoveToFirst(i, regionfile1);
|
@ -6,10 +6,10 @@ Subject: [PATCH] Show 'Paper' in client crashes, server lists, and Mojang
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 96897d883671e018bae5f71545c5f7af205e309c..ff3073b6780c04f5f11b5384bb6b6289eafd0c4f 100644
|
||||
index 164ce278f2696d4be6b57404648cb0e856464589..4d5a8c051ab7746ed40d5b79558e86238618827c 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1466,7 +1466,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1460,7 +1460,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@DontObfuscate
|
||||
public String getServerModName() {
|
||||
@ -19,7 +19,7 @@ index 96897d883671e018bae5f71545c5f7af205e309c..ff3073b6780c04f5f11b5384bb6b6289
|
||||
|
||||
public SystemReport fillSystemReport(SystemReport details) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 7912cf0e4cab7d6c99106d43b2cdc4f4e80aebac..a79ae43bffcd23b5639cdc179f129b1879a5a779 100644
|
||||
index 0a4b2529034b85609b2f8d3f3f633e8f6adbe34f..31085570f31a5de308cb1d767472ea130193e3cf 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -260,7 +260,7 @@ import org.yaml.snakeyaml.error.MarkedYAMLException;
|
||||
@ -63,10 +63,10 @@ index 47c3c7484687b808341937f7e4ef1c0c410fa59f..a20eaa9b1d030ccd7e1fc49df47acee4
|
||||
net.minecraft.server.Main.main(options);
|
||||
} catch (Throwable t) {
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 335120afc88a8fc1543c2e6df516fd728e3ab032..d5863b0b06384b25eaa33572fa02649795463ed8 100644
|
||||
index f1194eb6fdfba60959e00080d0562f2820d13b27..11d7ede26b46d0bf9cced65e8c3bcc41c8b66dbf 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -19,7 +19,7 @@ public class WatchdogThread extends Thread
|
||||
@@ -19,7 +19,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
|
||||
private WatchdogThread(long timeoutTime, boolean restart)
|
||||
{
|
||||
@ -75,7 +75,7 @@ index 335120afc88a8fc1543c2e6df516fd728e3ab032..d5863b0b06384b25eaa33572fa026497
|
||||
this.timeoutTime = timeoutTime;
|
||||
this.restart = restart;
|
||||
}
|
||||
@@ -65,14 +65,14 @@ public class WatchdogThread extends Thread
|
||||
@@ -65,14 +65,14 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
{
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
@ -93,12 +93,12 @@ index 335120afc88a8fc1543c2e6df516fd728e3ab032..d5863b0b06384b25eaa33572fa026497
|
||||
//
|
||||
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
|
||||
{
|
||||
@@ -82,7 +82,7 @@ public class WatchdogThread extends Thread
|
||||
@@ -82,7 +82,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
}
|
||||
//
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" );
|
||||
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
@ -201,7 +201,7 @@ index 0000000000000000000000000000000000000000..aac3f66cb23d260729c2a48d8710a9de
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 51eac8b7177db66c005e4eaca689cf96d10edeaa..6f64d98021e842905cdd6410ec355a6f136ec18f 100644
|
||||
index 4f55f04812fe0306acfc4be45189f1f679e18e63..049f7dc31576980007eb8f0caab926bb58fead78 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -189,6 +189,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
@ -100,10 +100,10 @@ index 8d60b430357a1b761de325a21e1c52639a049403..213fed3a2b32226fc128d213ee3e9fa3
|
||||
|
||||
public void clientTick(Level world, BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||
index 127c4ebedb94631ceac92dbdcd465e904217d715..5e19b91e6fb7e5e354f55ea206b3d59e8767e714 100644
|
||||
index be6e3e21ad62da01e5e2dd78e300cbc8efdbeb42..ea98625fe7c00743b8df74a24e6d4b75df4189a5 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
|
||||
@@ -70,6 +70,11 @@ public interface EntityGetter {
|
||||
@@ -82,6 +82,11 @@ public interface EntityGetter {
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ index 127c4ebedb94631ceac92dbdcd465e904217d715..5e19b91e6fb7e5e354f55ea206b3d59e
|
||||
@Nullable
|
||||
default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
|
||||
double d = -1.0D;
|
||||
@@ -99,6 +104,20 @@ public interface EntityGetter {
|
||||
@@ -111,6 +116,20 @@ public interface EntityGetter {
|
||||
return this.getNearestPlayer(x, y, z, maxDistance, predicate);
|
||||
}
|
||||
|
||||
@ -137,10 +137,10 @@ index 127c4ebedb94631ceac92dbdcd465e904217d715..5e19b91e6fb7e5e354f55ea206b3d59e
|
||||
for(Player player : this.players()) {
|
||||
if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 5afdada0d56c2f9af431ea6485faa277229befa9..1098c95f8f27e0ff3cf593a4f0dfde0dbe4d3152 100644
|
||||
index 976eadd8200b2f4811d57b3c7fbd68cff1333924..dd65045f52da395bd3d106065b7390d3925bf96f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2169,8 +2169,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -2211,8 +2211,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@Override
|
||||
public String getLocale() {
|
||||
return this.getHandle().locale;
|
@ -12,7 +12,7 @@ Previous implementation did not calculate TPS correctly.
|
||||
Switch to a realistic rolling average and factor in std deviation as an extra reporting variable
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index ff3073b6780c04f5f11b5384bb6b6289eafd0c4f..2aeeffe6d011a1ecc848b80f0236c8a3f871a01c 100644
|
||||
index 4d5a8c051ab7746ed40d5b79558e86238618827c..92eb6e80e3b6f74dd32a878e5436d338c89ea60e 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -285,7 +285,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@ -33,7 +33,7 @@ index ff3073b6780c04f5f11b5384bb6b6289eafd0c4f..2aeeffe6d011a1ecc848b80f0236c8a3
|
||||
public final double[] recentTps = new double[ 3 ];
|
||||
// Spigot end
|
||||
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations;
|
||||
@@ -973,6 +973,57 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -954,6 +954,57 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
{
|
||||
return ( avg * exp ) + ( tps * ( 1 - exp ) );
|
||||
}
|
||||
@ -90,8 +90,8 @@ index ff3073b6780c04f5f11b5384bb6b6289eafd0c4f..2aeeffe6d011a1ecc848b80f0236c8a3
|
||||
+ // Paper End
|
||||
// Spigot End
|
||||
|
||||
protected void runServer() {
|
||||
@@ -987,9 +1038,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public static volatile RuntimeException chunkSystemCrash; // Paper - rewrite chunk system
|
||||
@@ -970,7 +1021,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
// Spigot start
|
||||
Arrays.fill( recentTps, 20 );
|
||||
@ -99,12 +99,18 @@ index ff3073b6780c04f5f11b5384bb6b6289eafd0c4f..2aeeffe6d011a1ecc848b80f0236c8a3
|
||||
+ long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
|
||||
+ lastTick = start - TICK_TIME; // Paper
|
||||
while (this.running) {
|
||||
// Paper start - rewrite chunk system
|
||||
// guarantee that nothing can stop the server from halting if it can at least still tick
|
||||
@@ -978,7 +1030,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
throw this.chunkSystemCrash;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
- long i = (curTime = Util.getMillis()) - this.nextTickTime;
|
||||
+ long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - this.nextTickTime; // Paper
|
||||
|
||||
if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L) { // CraftBukkit
|
||||
long j = i / 50L;
|
||||
@@ -1001,12 +1053,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -990,12 +1042,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
++MinecraftServer.currentTickLong; // Paper
|
||||
@ -128,7 +134,7 @@ index ff3073b6780c04f5f11b5384bb6b6289eafd0c4f..2aeeffe6d011a1ecc848b80f0236c8a3
|
||||
tickSection = curTime;
|
||||
}
|
||||
// Spigot end
|
||||
@@ -1016,7 +1074,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1005,7 +1063,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount);
|
||||
}
|
||||
|
||||
@ -139,7 +145,7 @@ index ff3073b6780c04f5f11b5384bb6b6289eafd0c4f..2aeeffe6d011a1ecc848b80f0236c8a3
|
||||
this.startMetricsRecordingTick();
|
||||
this.profiler.push("tick");
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index a79ae43bffcd23b5639cdc179f129b1879a5a779..17056a7ea6c6a3a671872d2be603d7dd60ae04e9 100644
|
||||
index 31085570f31a5de308cb1d767472ea130193e3cf..fb6ea46609489d802ed4b76b4074734dd3e3886f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2437,6 +2437,17 @@ public final class CraftServer implements Server {
|
@ -5,10 +5,10 @@ Subject: [PATCH] Only refresh abilities if needed
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 1098c95f8f27e0ff3cf593a4f0dfde0dbe4d3152..f4ec1141f13135286077875177de672905c8898a 100644
|
||||
index dd65045f52da395bd3d106065b7390d3925bf96f..65d13b47b3af69e2256f7000b4634e8c688e22d8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -1838,12 +1838,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -1880,12 +1880,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public void setFlying(boolean value) {
|
@ -5,10 +5,10 @@ Subject: [PATCH] Entity Origin API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 7cb5abfa89f842194325d26c6e95b49460c5968f..871234c2c381c6ff7a2a27a8542bbd498c1aec03 100644
|
||||
index 62a95a0fac59683948f34b202e6e3859b6652d6d..d47e99ac96e622296d045cfcf93b53dddd314827 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2116,6 +2116,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -2282,6 +2282,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
||||
entity.valid = true; // CraftBukkit
|
||||
@ -25,7 +25,7 @@ index 7cb5abfa89f842194325d26c6e95b49460c5968f..871234c2c381c6ff7a2a27a8542bbd49
|
||||
|
||||
public void onTrackingEnd(Entity entity) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index f668a80c6bff67bf766207985c1af73f09e1bd1c..06d8211ef27a21da66d4622795cbcc8b37d2ce4e 100644
|
||||
index 7f6a90fab14d6880f2784e1c62eb2f3c9da404b5..193b466e5dc52b9ecc878c4a680f88b8ce05e632 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -312,7 +312,27 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@ -56,7 +56,7 @@ index f668a80c6bff67bf766207985c1af73f09e1bd1c..06d8211ef27a21da66d4622795cbcc8b
|
||||
public float getBukkitYaw() {
|
||||
return this.yRot;
|
||||
}
|
||||
@@ -2010,6 +2030,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@@ -2062,6 +2082,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.bukkitEntity.storeBukkitValues(nbt);
|
||||
}
|
||||
// CraftBukkit end
|
||||
@ -72,7 +72,7 @@ index f668a80c6bff67bf766207985c1af73f09e1bd1c..06d8211ef27a21da66d4622795cbcc8b
|
||||
return nbt;
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
|
||||
@@ -2137,6 +2166,20 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@@ -2189,6 +2218,20 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
@ -5,10 +5,10 @@ Subject: [PATCH] Prevent tile entity and entity crashes
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index f21ba175538436e59c45d5350ef7b2605ed96775..627f80e726f306edc765be5e6ac59ca73aade10b 100644
|
||||
index fb78a91d1ab77f909823422c6d4e2ef7ed10c9c3..a022d009b72e366ed69d05087457b712970c0b84 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -723,11 +723,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@@ -728,11 +728,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
@ -44,10 +44,10 @@ index b300d12e9e00519028b53aca9c3fb01f589eaa91..63acd109a79ed752a05df3d4f1b99309
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 09999a3f523ce6d652799215d3418284a69042c1..8e1ca484356a7eddcdb37ef7ec01dea9864eec70 100644
|
||||
index 3da04db71d6f33b2f466c11e031e0a11c298379b..5d7290216d3a6ddb8e345a5b05da21ef28ed2307 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1057,11 +1057,11 @@ public class LevelChunk extends ChunkAccess {
|
||||
@@ -1146,11 +1146,11 @@ public class LevelChunk extends ChunkAccess {
|
||||
|
||||
gameprofilerfiller.pop();
|
||||
} catch (Throwable throwable) {
|
@ -6,10 +6,10 @@ Subject: [PATCH] Configurable top of nether void damage
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 06d8211ef27a21da66d4622795cbcc8b37d2ce4e..7358b918d03b0dee0541843a952d6b8bf939d877 100644
|
||||
index 193b466e5dc52b9ecc878c4a680f88b8ce05e632..3088cdbb55b3054394fd3405797539f58a46f70c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -663,7 +663,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@@ -715,7 +715,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public void checkBelowWorld() {
|
@ -5,7 +5,7 @@ Subject: [PATCH] Always tick falling blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index 3e5d541d3d7fc3956b2fc68da9f22a0ab0367ce9..66dbfabdb104d272d48588a4773d198d3938f1ef 100644
|
||||
index b47b740186c200c420dcb4d1537a93c743a887c1..a526816f261de2a75a04be82596a7d8d674ead4a 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
@@ -89,6 +89,7 @@ public class ActivationRange
|
@ -5,10 +5,10 @@ Subject: [PATCH] Configurable end credits
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 5872ead2fe3a64f02f8bc36603fbb856728fd255..eb42e0ce8e2698973307e2b6774cbbd79c1d6457 100644
|
||||
index 32ef9f1ae0c35e927133572ebb6fbf50b0729a63..e42c07dfba3c18464f1f8e35fbd764812d8c4e50 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1024,6 +1024,7 @@ public class ServerPlayer extends Player {
|
||||
@@ -1066,6 +1066,7 @@ public class ServerPlayer extends Player {
|
||||
this.unRide();
|
||||
this.serverLevel().removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
|
||||
if (!this.wonGame) {
|
@ -10,10 +10,10 @@ This patch adds a per-tick cache that is used for storing and retrieving
|
||||
an entity's exposure during an explosion.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 2aeeffe6d011a1ecc848b80f0236c8a3f871a01c..d5ad3368a397e9fc02506187ccb1c386afd9ce2b 100644
|
||||
index 92eb6e80e3b6f74dd32a878e5436d338c89ea60e..821725460b62ebadedb789f4408ef172416c2092 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1412,6 +1412,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1406,6 +1406,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
this.profiler.pop();
|
||||
this.profiler.pop();
|
||||
@ -120,7 +120,7 @@ index e360022498b91a8371b33d84bf6fff96c503999d..925d37ca684e7e6a3ad88e6e040f3599
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 627f80e726f306edc765be5e6ac59ca73aade10b..0a7a354c085655c243fdf94c7dc82cdc95b3987a 100644
|
||||
index a022d009b72e366ed69d05087457b712970c0b84..da553430864689c426ad2c1dd74ad7d1134ffbae 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -167,6 +167,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
@ -5,10 +5,10 @@ Subject: [PATCH] Disable thunder
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 871234c2c381c6ff7a2a27a8542bbd498c1aec03..fdb2996562010fa6dd43b6a79b707cb86146bb48 100644
|
||||
index d47e99ac96e622296d045cfcf93b53dddd314827..2df6cc14176465dcdc7cfc8d12382bf7edc49666 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -603,7 +603,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -752,7 +752,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
gameprofilerfiller.push("thunder");
|
||||
BlockPos blockposition;
|
||||
|
@ -5,10 +5,10 @@ Subject: [PATCH] Disable ice and snow
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index fdb2996562010fa6dd43b6a79b707cb86146bb48..ef48e76ca18576e631d5d2f1652d3449d558a582 100644
|
||||
index 2df6cc14176465dcdc7cfc8d12382bf7edc49666..feee30aa0bccfa40765f1c4a179ba04907b11433 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -634,7 +634,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -783,7 +783,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
int l;
|
||||
int i1;
|
||||
|
@ -5,10 +5,10 @@ Subject: [PATCH] Implement PlayerLocaleChangeEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index eb42e0ce8e2698973307e2b6774cbbd79c1d6457..e448641f3e64114a6ff986990fc7bdaa28736129 100644
|
||||
index e42c07dfba3c18464f1f8e35fbd764812d8c4e50..ee422a97a63749172f9f9643513ae9ab111c2400 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1811,7 +1811,7 @@ public class ServerPlayer extends Player {
|
||||
@@ -1853,7 +1853,7 @@ public class ServerPlayer extends Player {
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ index eb42e0ce8e2698973307e2b6774cbbd79c1d6457..e448641f3e64114a6ff986990fc7bdaa
|
||||
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
|
||||
public void updateOptions(ServerboundClientInformationPacket packet) {
|
||||
// CraftBukkit start
|
||||
@@ -1819,9 +1819,10 @@ public class ServerPlayer extends Player {
|
||||
@@ -1861,9 +1861,10 @@ public class ServerPlayer extends Player {
|
||||
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
|
||||
this.server.server.getPluginManager().callEvent(event);
|
||||
}
|
||||
@ -30,10 +30,10 @@ index eb42e0ce8e2698973307e2b6774cbbd79c1d6457..e448641f3e64114a6ff986990fc7bdaa
|
||||
this.locale = packet.language;
|
||||
// Paper start
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index f4ec1141f13135286077875177de672905c8898a..484fab5eeeb92407ded625b96678c9aa93199d70 100644
|
||||
index 65d13b47b3af69e2256f7000b4634e8c688e22d8..4061b68edb8f501eea71ba009214ac3808506ec7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2169,8 +2169,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -2211,8 +2211,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public String getLocale() {
|
@ -5,7 +5,7 @@ Subject: [PATCH] Configurable container update tick rate
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index e448641f3e64114a6ff986990fc7bdaa28736129..95d9824ad7a00e8d75ce243403004193d0bee605 100644
|
||||
index ee422a97a63749172f9f9643513ae9ab111c2400..321d14f241df1246061ba73b2488f5ab5326a734 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -241,6 +241,7 @@ public class ServerPlayer extends Player {
|
||||
@ -16,7 +16,7 @@ index e448641f3e64114a6ff986990fc7bdaa28736129..95d9824ad7a00e8d75ce243403004193
|
||||
|
||||
// CraftBukkit start
|
||||
public String displayName;
|
||||
@@ -630,7 +631,12 @@ public class ServerPlayer extends Player {
|
||||
@@ -672,7 +673,12 @@ public class ServerPlayer extends Player {
|
||||
--this.invulnerableTime;
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ Subject: [PATCH] Disable spigot tick limiters
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0a7a354c085655c243fdf94c7dc82cdc95b3987a..42e81640354c2679570823347b28ee1155e7a00e 100644
|
||||
index da553430864689c426ad2c1dd74ad7d1134ffbae..78041052d7ab2e6b60405ce7e02468458650db22 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -689,9 +689,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@@ -694,9 +694,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// Spigot start
|
||||
// Iterator iterator = this.blockEntityTickers.iterator();
|
||||
int tilesThisCycle = 0;
|
@ -12,7 +12,7 @@ improve setPosition to use raw
|
||||
public net.minecraft.world.entity.Entity setRot(FF)V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 90c73b9075489242556a7ba749618e20c0ed0c4d..2a905bc0c177fb7ad5464fb99682d475f42c0c85 100644
|
||||
index 0338a6b245ee482d470f5a80da712679ab9890fa..f03058205342f06c1dfbf38313e7d2088327b104 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -240,7 +240,7 @@ public abstract class PlayerList {
|
@ -21,10 +21,10 @@ character.
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 403f7c7f31e0072b0cad0706bc981ece24733a1d..42a44820a3c13e2b0e29e02ed384c1918c9a0b17 100644
|
||||
index d72e8df4f99b6219ea305742f0cf8d1c1985ffd6..ddd437906801973e11386294e7e3f6846cc11cbc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2034,7 +2034,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@@ -2041,7 +2041,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ index 403f7c7f31e0072b0cad0706bc981ece24733a1d..42a44820a3c13e2b0e29e02ed384c191
|
||||
for (int i = 0; i < message.length(); ++i) {
|
||||
if (!SharedConstants.isAllowedChatCharacter(message.charAt(i))) {
|
||||
return true;
|
||||
@@ -2051,7 +2051,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@@ -2058,7 +2058,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
OutgoingChatMessage outgoing = OutgoingChatMessage.create(original);
|
||||
|
||||
@ -42,7 +42,7 @@ index 403f7c7f31e0072b0cad0706bc981ece24733a1d..42a44820a3c13e2b0e29e02ed384c191
|
||||
this.handleCommand(s);
|
||||
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
|
||||
// Do nothing, this is coming from a plugin
|
||||
@@ -2141,7 +2141,29 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@@ -2148,7 +2148,29 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ index 403f7c7f31e0072b0cad0706bc981ece24733a1d..42a44820a3c13e2b0e29e02ed384c191
|
||||
if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot
|
||||
this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 17056a7ea6c6a3a671872d2be603d7dd60ae04e9..6e488fe34231afa20d0f8f62299bb631359ee51c 100644
|
||||
index fb6ea46609489d802ed4b76b4074734dd3e3886f..dd3935eeceba456b37a5fbcb874c1073bb76d473 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -875,6 +875,28 @@ public final class CraftServer implements Server {
|
||||
@ -107,10 +107,10 @@ index 17056a7ea6c6a3a671872d2be603d7dd60ae04e9..6e488fe34231afa20d0f8f62299bb631
|
||||
return true;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 484fab5eeeb92407ded625b96678c9aa93199d70..b8fc2196b8f77b826d229265e96b5cce1e5301cb 100644
|
||||
index 4061b68edb8f501eea71ba009214ac3808506ec7..37ffadacbfd49743dac8739b74def818a351e563 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -437,7 +437,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -479,7 +479,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
public void chat(String msg) {
|
||||
if (this.getHandle().connection == null) return;
|
||||
|
||||
@ -145,7 +145,7 @@ index 19c44daaa407b7c1c7a7ffe56fef8c8814c6d5b2..6a073a9dc44d93eba296a0e18a9c7be8
|
||||
} finally {
|
||||
try {
|
||||
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||
index 78669fa035b7537ff7e533cf32aaf2995625424f..7585a30e8f063ac2656b5de519b1e9edaceffbc7 100644
|
||||
index 05e94702e42b8f5c35d2a112c486d57948a3acba..5409f230fdd53b70fc03c58177438534731ad4e6 100644
|
||||
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
|
||||
@@ -6,6 +6,7 @@ public class AsyncCatcher
|
@ -18,10 +18,10 @@ index 23cb972ca3fde409be0d6517ef8f1c58dab47ff4..476a9b2db5deac803f1cb3c2cbe88b69
|
||||
if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
|
||||
return checkMobSpawnRules(type, world, spawnReason, pos, random);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
index bf4b2f89d3a7133155c6272379c742318b2c1514..f07a6b1d782426581c84ffa19447c1375c4cbc07 100644
|
||||
index 33677ec811ceab939c419bf7d31b99585e9a1ef1..8ae78690748b2cb5d5186d8859871c1630e10130 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -213,7 +213,7 @@ public class CraftChunk implements Chunk {
|
||||
@@ -169,7 +169,7 @@ public class CraftChunk implements Chunk {
|
||||
@Override
|
||||
public boolean isSlimeChunk() {
|
||||
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
|
@ -5,7 +5,7 @@ Subject: [PATCH] Expose server CommandMap
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 6e488fe34231afa20d0f8f62299bb631359ee51c..7681198cbc8f36b9e860182a1f3541a4b22fc82e 100644
|
||||
index dd3935eeceba456b37a5fbcb874c1073bb76d473..9c80c55e8c15aa847aea134dd8121ee9d0c24d1c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2012,6 +2012,7 @@ public final class CraftServer implements Server {
|
@ -63,7 +63,7 @@ index bd808eb312ade7122973a47f4b96505829511da5..bf0f9cab7c66c089f35b851e799ba4a4
|
||||
// Paper end
|
||||
buf.writeComponent(this.text);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index b8fc2196b8f77b826d229265e96b5cce1e5301cb..bd811f33bb2df565d876bc3433b1ce9ce58acba4 100644
|
||||
index 37ffadacbfd49743dac8739b74def818a351e563..c6ceb5044e3dcf5f512dc1efc04e0785b1caadb0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -1,5 +1,6 @@
|
||||
@ -73,7 +73,7 @@ index b8fc2196b8f77b826d229265e96b5cce1e5301cb..bd811f33bb2df565d876bc3433b1ce9c
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
@@ -283,6 +284,100 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -325,6 +326,100 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ Subject: [PATCH] Add configurable portal search radius
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 7358b918d03b0dee0541843a952d6b8bf939d877..4d12403d8ae7c620e169e87b0a0ab48e28251811 100644
|
||||
index 3088cdbb55b3054394fd3405797539f58a46f70c..756b8be27488c81172fe05fa0361ef3866f99bee 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -3122,7 +3122,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@@ -3174,7 +3174,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
double d0 = DimensionType.getTeleportationScale(this.level().dimensionType(), destination.dimensionType());
|
||||
BlockPos blockposition = worldborder.clampToBounds(this.getX() * d0, this.getY(), this.getZ() * d0);
|
||||
// CraftBukkit start
|
@ -5,7 +5,7 @@ Subject: [PATCH] Add velocity warnings
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 7681198cbc8f36b9e860182a1f3541a4b22fc82e..6be92dea5f2c042a427de77b6ae5b9e45a662388 100644
|
||||
index 9c80c55e8c15aa847aea134dd8121ee9d0c24d1c..1cca43506306994e740278a581b0d33924d08491 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -296,6 +296,7 @@ public final class CraftServer implements Server {
|
||||
@ -62,10 +62,10 @@ index 0a6926f9b6be67d4d710d2fbc6bd2b1fcb0677a0..c9275f73be7332f79312037954f9685f
|
||||
public double getHeight() {
|
||||
return this.getHandle().getBbHeight();
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index d5863b0b06384b25eaa33572fa02649795463ed8..2693cc933d746e40d8a47d96c6cb6799f0a2472f 100644
|
||||
index 11d7ede26b46d0bf9cced65e8c3bcc41c8b66dbf..3ad14bf0697e682a2e777baa8faeb323d127fb13 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -80,7 +80,19 @@ public class WatchdogThread extends Thread
|
||||
@@ -80,7 +80,19 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" );
|
||||
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
|
||||
}
|
||||
@ -85,4 +85,4 @@ index d5863b0b06384b25eaa33572fa02649795463ed8..2693cc933d746e40d8a47d96c6cb6799
|
||||
+ // Paper end
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
|
@ -16,10 +16,10 @@ The wanted destination was on top of the emerald block however the player ended
|
||||
This only is the case if the player is teleporting between worlds.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index bd811f33bb2df565d876bc3433b1ce9ce58acba4..db7063bb4dddcf485f9e57505ae2bd31ade5376e 100644
|
||||
index c6ceb5044e3dcf5f512dc1efc04e0785b1caadb0..8f5d6d4ea4a8a7de95c755594ba5ec3fd3902158 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -1140,7 +1140,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -1182,7 +1182,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
entity.connection.teleport(to);
|
||||
} else {
|
||||
// The respawn reason should never be used if the passed location is non null.
|
@ -88,7 +88,7 @@ index c6fb4c33d7ea52b88d8fc0d90748cbab7387c565..fed09b886f4fa0006d160e5f2abb00df
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 42e81640354c2679570823347b28ee1155e7a00e..a7fb12648c2e655e191d8c805753ae0c05421d17 100644
|
||||
index 78041052d7ab2e6b60405ce7e02468458650db22..8149286827d9b609be47a4ded0413ca11f7858de 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1,5 +1,10 @@
|
||||
@ -102,7 +102,7 @@ index 42e81640354c2679570823347b28ee1155e7a00e..a7fb12648c2e655e191d8c805753ae0c
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.serialization.Codec;
|
||||
import java.io.IOException;
|
||||
@@ -725,6 +730,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@@ -730,6 +735,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// Paper start - Prevent tile entity and entity crashes
|
||||
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
|
||||
MinecraftServer.LOGGER.error(msg, throwable);
|
||||
@ -131,7 +131,7 @@ index f1675e35be0ab7670c875c6b0d1e982a3ae09d1e..b2bb9bbd3af414c50ec3f8e3e171a679
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 8e1ca484356a7eddcdb37ef7ec01dea9864eec70..2006760ff24ec9ce5f71c107ddf942e550d03589 100644
|
||||
index 5d7290216d3a6ddb8e345a5b05da21ef28ed2307..fe6b2ade9f167c36cbac594a25ad36ee14208fa0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1,6 +1,7 @@
|
||||
@ -163,7 +163,7 @@ index 8e1ca484356a7eddcdb37ef7ec01dea9864eec70..2006760ff24ec9ce5f71c107ddf942e5
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
||||
@@ -1060,6 +1067,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
@@ -1149,6 +1156,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
// Paper start - Prevent tile entity and entity crashes
|
||||
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
||||
@ -172,10 +172,10 @@ index 8e1ca484356a7eddcdb37ef7ec01dea9864eec70..2006760ff24ec9ce5f71c107ddf942e5
|
||||
// Paper end
|
||||
// Spigot start
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index d9daf07132c46548964a75588b69d7a74680e917..67a2f3c02aa4983b3ec2df073821190ddb36543c 100644
|
||||
index e68205fe7169c7c5b7c6fdada2ee97d86107ca97..aa8972fd1a1fade05d60ab69efb8ff24f344508a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -274,6 +274,7 @@ public class RegionFile implements AutoCloseable {
|
||||
@@ -275,6 +275,7 @@ public class RegionFile implements AutoCloseable {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
@ -183,7 +183,7 @@ index d9daf07132c46548964a75588b69d7a74680e917..67a2f3c02aa4983b3ec2df073821190d
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -355,6 +356,7 @@ public class RegionFile implements AutoCloseable {
|
||||
@@ -356,6 +357,7 @@ public class RegionFile implements AutoCloseable {
|
||||
((java.nio.Buffer) buf).position(5); // CraftBukkit - decompile error
|
||||
filechannel.write(buf);
|
||||
} catch (Throwable throwable) {
|
@ -11,10 +11,10 @@ So avoid looking up scoreboards and short circuit to the "not on a team"
|
||||
logic which is most likely to be true.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 4d12403d8ae7c620e169e87b0a0ab48e28251811..bb8de860d826e4c92ffdbd7ef2675458d372bbdf 100644
|
||||
index 756b8be27488c81172fe05fa0361ef3866f99bee..194c0f9e8b537d415d7cdedf9cd5d4870b60fb08 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2753,6 +2753,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@@ -2805,6 +2805,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
|
||||
@Nullable
|
||||
public Team getTeam() {
|
@ -5,10 +5,10 @@ Subject: [PATCH] Complete resource pack API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 42a44820a3c13e2b0e29e02ed384c1918c9a0b17..94636c92758568051f829aed59aab8728e7e7252 100644
|
||||
index ddd437906801973e11386294e7e3f6846cc11cbc..a91cc53f9d601bbc51988b2b7855c6ebcc68d780 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1748,8 +1748,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@@ -1755,8 +1755,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName());
|
||||
this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
|
||||
}
|
||||
@ -23,7 +23,7 @@ index 42a44820a3c13e2b0e29e02ed384c1918c9a0b17..94636c92758568051f829aed59aab872
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index db7063bb4dddcf485f9e57505ae2bd31ade5376e..04e9a84b36f7f702e34216513348a0871ade22e5 100644
|
||||
index 8f5d6d4ea4a8a7de95c755594ba5ec3fd3902158..f6006f696550126d1ba78fdc49821e20cd19b1f3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -178,6 +178,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@ -37,7 +37,7 @@ index db7063bb4dddcf485f9e57505ae2bd31ade5376e..04e9a84b36f7f702e34216513348a087
|
||||
|
||||
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||
super(server, entity);
|
||||
@@ -2292,6 +2296,45 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -2334,6 +2338,45 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
public boolean getAffectsSpawning() {
|
||||
return this.getHandle().affectsSpawning;
|
||||
}
|
@ -16,7 +16,7 @@ modify that. Under the previous logic, plugins were unable (cleanly) override pe
|
||||
A config option has been added for those who depend on the previous behavior, but I don't expect that.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 6be92dea5f2c042a427de77b6ae5b9e45a662388..4edf6a317ba5ce46e098c4ce1836c147853eadb1 100644
|
||||
index 1cca43506306994e740278a581b0d33924d08491..e509ab35bf8ffba3c1e04f1236f98c24c1e010f4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -457,6 +457,7 @@ public final class CraftServer implements Server {
|
@ -6,7 +6,7 @@ Subject: [PATCH] Allow Reloading of Custom Permissions
|
||||
https://github.com/PaperMC/Paper/issues/49
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 4edf6a317ba5ce46e098c4ce1836c147853eadb1..2fa6753e7bd9c1a6c08b467fe6d2d7ca3943f0a7 100644
|
||||
index e509ab35bf8ffba3c1e04f1236f98c24c1e010f4..dea53897919d46b90c99577fbb1985b2d0c65b5e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2603,5 +2603,23 @@ public final class CraftServer implements Server {
|
@ -7,7 +7,7 @@ Metadata is not meant to persist reload as things break badly with non primitive
|
||||
This will remove metadata on reload so it does not crash everything if a plugin uses it.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 2fa6753e7bd9c1a6c08b467fe6d2d7ca3943f0a7..0953f4555bc18176f35d91754ad308143899a8a7 100644
|
||||
index dea53897919d46b90c99577fbb1985b2d0c65b5e..dbad9e72121562d22f8476bade4032661e280066 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -962,8 +962,16 @@ public final class CraftServer implements Server {
|
@ -6,7 +6,7 @@ Subject: [PATCH] Add World Util Methods
|
||||
Methods that can be used for other patches to help improve logic.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index ef48e76ca18576e631d5d2f1652d3449d558a582..71be3d403dc0c345b447685fa339cb1c455dd2a8 100644
|
||||
index feee30aa0bccfa40765f1c4a179ba04907b11433..4598ca4cd9da931db33ca26576bfbcdf7df99094 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -221,7 +221,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@ -19,7 +19,7 @@ index ef48e76ca18576e631d5d2f1652d3449d558a582..71be3d403dc0c345b447685fa339cb1c
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index a7fb12648c2e655e191d8c805753ae0c05421d17..5e4b102e747a053280871879c3c18fc3d3d2d18a 100644
|
||||
index 8149286827d9b609be47a4ded0413ca11f7858de..809f7db469583ea90fbb165cf180dc87055c6105 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -342,6 +342,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
@ -44,10 +44,10 @@ index 1238da8b035a0b0dd3d00557ca0de7a82f5fdf53..5e40ee2695b7ed50fddc0e8226f0b1b4
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 04e9a84b36f7f702e34216513348a0871ade22e5..877f82735c407c1d567628fafc7c7fd6adebb410 100644
|
||||
index f6006f696550126d1ba78fdc49821e20cd19b1f3..af7f97b605b81a0b2dd812f491b6e324660fe260 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2096,6 +2096,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -2138,6 +2138,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
|
||||
public void setRealHealth(double health) {
|
@ -6,7 +6,7 @@ Subject: [PATCH] Use a Shared Random for Entities
|
||||
Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index bb8de860d826e4c92ffdbd7ef2675458d372bbdf..09cf1125221bdbebddabfc46095c3dbd153714c1 100644
|
||||
index 194c0f9e8b537d415d7cdedf9cd5d4870b60fb08..3f8b0124e5c2a01f1cf3a344b8dd4075817cb001 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -162,6 +162,79 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@ -89,7 +89,7 @@ index bb8de860d826e4c92ffdbd7ef2675458d372bbdf..09cf1125221bdbebddabfc46095c3dbd
|
||||
private CraftEntity bukkitEntity;
|
||||
|
||||
public CraftEntity getBukkitEntity() {
|
||||
@@ -354,7 +427,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
@@ -406,7 +479,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.bb = Entity.INITIAL_AABB;
|
||||
this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
this.nextStep = 1.0F;
|
@ -5,10 +5,10 @@ Subject: [PATCH] Configurable spawn chances for skeleton horses
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 71be3d403dc0c345b447685fa339cb1c455dd2a8..16e0887abe2643b13f7fefd986783e88d37fbdfb 100644
|
||||
index 4598ca4cd9da931db33ca26576bfbcdf7df99094..f6be0fefb461c1b5fd0feb5553d36b5817b96e3a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -607,7 +607,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -756,7 +756,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
||||
if (this.isRainingAt(blockposition)) {
|
||||
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
|
@ -29,7 +29,7 @@ index 1b29c6872ebe54351f28c1f1f38b22561ba785ee..40950db0c242c65dfd4de247c8624935
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 5e4b102e747a053280871879c3c18fc3d3d2d18a..dcf1894ed6939b47cd8323421d5734fd5af6dedb 100644
|
||||
index 809f7db469583ea90fbb165cf180dc87055c6105..e5194f0650af2bce8aac24e34752b21015b92d4e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -284,7 +284,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@ -88,7 +88,7 @@ index 60e760b42dd6471a229dfd45490dcf8c51979d35..4a3ac7dedf5cb1e76f16ec4f18e82afc
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 2006760ff24ec9ce5f71c107ddf942e550d03589..b7e03ac0e07a48c5d3a401a918ab6cc2a7daafec 100644
|
||||
index fe6b2ade9f167c36cbac594a25ad36ee14208fa0..4e93e9ce7a7f939f802e51072efd389a86b42fc4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -295,12 +295,29 @@ public class LevelChunk extends ChunkAccess {
|
@ -6,10 +6,10 @@ Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener
|
||||
Saves on some object allocation and processing when no plugin listens to this
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index d5ad3368a397e9fc02506187ccb1c386afd9ce2b..7fca70658ecdc89b79381ca2ab33b931ce6871ae 100644
|
||||
index 821725460b62ebadedb789f4408ef172416c2092..81abb732e2bb3bca683028d505e7485052c0ec8d 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1373,6 +1373,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1367,6 +1367,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
@ -18,7 +18,7 @@ index d5ad3368a397e9fc02506187ccb1c386afd9ce2b..7fca70658ecdc89b79381ca2ab33b931
|
||||
this.profiler.push(() -> {
|
||||
return worldserver + " " + worldserver.dimension().location();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 16e0887abe2643b13f7fefd986783e88d37fbdfb..5c2ca51139b0647a2c7ae1b268b6d151dc884eca 100644
|
||||
index f6be0fefb461c1b5fd0feb5553d36b5817b96e3a..33c6a673d98323a3790b3e494841dffa9ce5f4f5 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -220,6 +220,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@ -30,10 +30,10 @@ index 16e0887abe2643b13f7fefd986783e88d37fbdfb..5c2ca51139b0647a2c7ae1b268b6d151
|
||||
@Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
|
||||
return this.chunkSource.getChunk(x, z, false);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index dcf1894ed6939b47cd8323421d5734fd5af6dedb..fc48c03fa4f3c7e2463ef2ce477ce1e71d1e3faf 100644
|
||||
index e5194f0650af2bce8aac24e34752b21015b92d4e..127f4e98e11a57eb3dddbc8efdb0aa33fda37924 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -491,7 +491,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@@ -496,7 +496,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// CraftBukkit start
|
||||
iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam
|
||||
CraftWorld world = ((ServerLevel) this).getWorld();
|
@ -5,10 +5,10 @@ Subject: [PATCH] Entity AddTo/RemoveFrom World Events
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 5c2ca51139b0647a2c7ae1b268b6d151dc884eca..79b572c8e3481ea4a6ac523c0a2f25204cf44e2d 100644
|
||||
index 33c6a673d98323a3790b3e494841dffa9ce5f4f5..507cab9d689b774b320fac00f7760c4143957b67 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2126,6 +2126,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -2292,6 +2292,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
|
||||
}
|
||||
// Paper end
|
||||
@ -16,7 +16,7 @@ index 5c2ca51139b0647a2c7ae1b268b6d151dc884eca..79b572c8e3481ea4a6ac523c0a2f2520
|
||||
}
|
||||
|
||||
public void onTrackingEnd(Entity entity) {
|
||||
@@ -2201,6 +2202,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -2367,6 +2368,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
@ -11,7 +11,7 @@ For people who want all chunks to be treated equally, you can chose a fixed valu
|
||||
This allows to fine-tune vanilla gameplay.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index b7e03ac0e07a48c5d3a401a918ab6cc2a7daafec..419125e865cb086f0ef75f69749cc03a178d9a41 100644
|
||||
index 4e93e9ce7a7f939f802e51072efd389a86b42fc4..becec8ded3f7ed53998b55523793e6e9cd05d492 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -280,6 +280,13 @@ public class LevelChunk extends ChunkAccess {
|
@ -11,13 +11,13 @@ The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap).
|
||||
The maximum size of the RegionFileCache is also made configurable.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index b9b50c56e79297bb824a92355f437a5d4d7e6760..e4c706d553a3d7058a32409ec7af8771c92d9777 100644
|
||||
index fe8bb0037bb7f317fc32ac34461f4eb3a1f397f2..8bff53217d087a9d53aa3738660dde563ee125f1 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -36,7 +36,7 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
if (regionfile != null) {
|
||||
return regionfile;
|
||||
} else {
|
||||
@@ -91,7 +91,7 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
return null;
|
||||
}
|
||||
// Paper end - cache regionfile does not exist state
|
||||
- if (this.regionCache.size() >= 256) {
|
||||
+ if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable
|
||||
((RegionFile) this.regionCache.removeLast()).close();
|
@ -22,10 +22,10 @@ index a5d57cc862036012d83b090bb1b3ccf4115a88b3..21068f766b75c414d5818073b7dca083
|
||||
static final ServerboundInteractPacket.Action ATTACK_ACTION = new ServerboundInteractPacket.Action() {
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 94636c92758568051f829aed59aab8728e7e7252..c65282a85e2822b86f56c528ab838e628ea27411 100644
|
||||
index a91cc53f9d601bbc51988b2b7855c6ebcc68d780..2b1311185bb08592038e256d860a722fbd4d9ffc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2534,8 +2534,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@@ -2541,8 +2541,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
});
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@ Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 79b572c8e3481ea4a6ac523c0a2f25204cf44e2d..6896ead71f87989c2fa90d0339eedfd08ac49dd1 100644
|
||||
index 507cab9d689b774b320fac00f7760c4143957b67..508c1f2874db3add98aad29bd4eee6c9f5d58006 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1366,6 +1366,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -1517,6 +1517,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
@Override
|
||||
public void updateNeighborsAt(BlockPos pos, Block sourceBlock) {
|
@ -18,7 +18,7 @@ index 1294b38262505b0d54089e428df9b363219de1f0..ee37ec0de1ca969144824427ae42b0c8
|
||||
buf.writeComponent(this.playerPrefix);
|
||||
buf.writeComponent(this.playerSuffix);
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 7fca70658ecdc89b79381ca2ab33b931ce6871ae..feee1da3091fdbcef0336ab0ab85fd9f52ccac4b 100644
|
||||
index 81abb732e2bb3bca683028d505e7485052c0ec8d..d2b07b5f0ff7466f22f2c25c7e0cb9a00b25f4f0 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -589,6 +589,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@ -43,7 +43,7 @@ index 7fca70658ecdc89b79381ca2ab33b931ce6871ae..feee1da3091fdbcef0336ab0ab85fd9f
|
||||
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
|
||||
this.connection.acceptConnections();
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 2a905bc0c177fb7ad5464fb99682d475f42c0c85..ebbe5fb5d22cc6a7a2f131ab8fa209ff47c0c92a 100644
|
||||
index f03058205342f06c1dfbf38313e7d2088327b104..05dd9e618336c5a8e44e20b97d9a7fd0fb5b3002 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -99,6 +99,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
|
@ -6,7 +6,7 @@ Subject: [PATCH] remove null possibility for getServer singleton
|
||||
to stop IDE complaining about potential NPE
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index feee1da3091fdbcef0336ab0ab85fd9f52ccac4b..ac0a6cfb6fb7d9fa696b1e35ebdfb37935b74048 100644
|
||||
index d2b07b5f0ff7466f22f2c25c7e0cb9a00b25f4f0..8e3ff6870daff6dee7e38f72d1e37e9aa58dab35 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -193,6 +193,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
|
||||
@ -25,7 +25,7 @@ index feee1da3091fdbcef0336ab0ab85fd9f52ccac4b..ac0a6cfb6fb7d9fa696b1e35ebdfb379
|
||||
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
|
||||
this.profiler = this.metricsRecorder.getProfiler();
|
||||
this.onMetricsRecordingStopped = (methodprofilerresults) -> {
|
||||
@@ -2332,9 +2334,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2326,9 +2328,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return false;
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ custom renderers are in use, defaulting to the much simpler Vanilla system.
|
||||
Additionally, numerous issues to player position tracking on maps has been fixed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 6896ead71f87989c2fa90d0339eedfd08ac49dd1..99a7fadf87b0b081a1f5ab15a8eeb1b0cb8572fe 100644
|
||||
index 508c1f2874db3add98aad29bd4eee6c9f5d58006..90c19a08b51dee98701fc397ab95bf93cb1a2102 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2147,6 +2147,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -2313,6 +2313,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
{
|
||||
if ( iter.next().player == entity )
|
||||
{
|
@ -490,7 +490,7 @@ index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fa
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 09cf1125221bdbebddabfc46095c3dbd153714c1..49f465d0009b084be2a8e809c53126af1ad72cd2 100644
|
||||
index 3f8b0124e5c2a01f1cf3a344b8dd4075817cb001..f331c9ff4cc341c981515210d3f4bd92faa8fdc9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -235,6 +235,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
@ -5,10 +5,10 @@ Subject: [PATCH] System property for disabling watchdoge
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 2693cc933d746e40d8a47d96c6cb6799f0a2472f..6e1fa4f0616ccfd258acd1b4f5b08fc0ad4c9529 100644
|
||||
index 3ad14bf0697e682a2e777baa8faeb323d127fb13..a9897c494b3dc56d900356d74030359832febbaa 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -61,7 +61,7 @@ public class WatchdogThread extends Thread
|
||||
@@ -61,7 +61,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
while ( !this.stopping )
|
||||
{
|
||||
//
|
@ -5,10 +5,10 @@ Subject: [PATCH] Async GameProfileCache saving
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index ac0a6cfb6fb7d9fa696b1e35ebdfb37935b74048..857cc4fcc586f7a8ea5baeeae69da62ebfdac77a 100644
|
||||
index 8e3ff6870daff6dee7e38f72d1e37e9aa58dab35..14edacfd5cc77cc85dc84e3fdad94be8c8932dc6 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -954,7 +954,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -935,7 +935,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
} catch (java.lang.InterruptedException ignored) {} // Paper
|
||||
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
|
||||
MinecraftServer.LOGGER.info("Saving usercache.json");
|
||||
@ -16,9 +16,9 @@ index ac0a6cfb6fb7d9fa696b1e35ebdfb37935b74048..857cc4fcc586f7a8ea5baeeae69da62e
|
||||
+ this.getProfileCache().save(false); // Paper
|
||||
}
|
||||
// Spigot end
|
||||
|
||||
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 6f64d98021e842905cdd6410ec355a6f136ec18f..a9cf8960d487ee71385341285a4b1618007d06dc 100644
|
||||
index 049f7dc31576980007eb8f0caab926bb58fead78..81a0a897a1fd2a408bfe43f24ed5e5f4bbefe161 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -242,7 +242,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
@ -6,7 +6,7 @@ Subject: [PATCH] Faster redstone torch rapid clock removal
|
||||
Only resize the the redstone torch list once, since resizing arrays / lists is costly
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index fc48c03fa4f3c7e2463ef2ce477ce1e71d1e3faf..15cb9a1dc2426dd87dc4bc4961812523ed9f639f 100644
|
||||
index 127f4e98e11a57eb3dddbc8efdb0aa33fda37924..df194067094dd89423251207e62f477db6546264 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -173,6 +173,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
@ -43,7 +43,7 @@ index da98f074ccd5a40c635824112c97fd174c393cb1..6599f874d9f97e9ef4862039ecad7277
|
||||
} else {
|
||||
String[] astring1 = astring;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 0953f4555bc18176f35d91754ad308143899a8a7..bbc9f231d658dfe8cb62a6c632e5373c97ac2a75 100644
|
||||
index dbad9e72121562d22f8476bade4032661e280066..d83942d7f7260073e1c60e125eed6312ff89e434 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1735,7 +1735,7 @@ public final class CraftServer implements Server {
|
@ -5,10 +5,10 @@ Subject: [PATCH] Configurable packet in spam threshold
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index c65282a85e2822b86f56c528ab838e628ea27411..96e38a914db34ed165bd5071585bc7e5ec7fb41d 100644
|
||||
index 2b1311185bb08592038e256d860a722fbd4d9ffc..28ec3530a5c3df8e0c629228f80c0130cb65cc27 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1588,13 +1588,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@@ -1595,13 +1595,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
// Spigot start - limit place/interactions
|
||||
private int limitedPackets;
|
||||
private long lastLimitedPacket = -1;
|
@ -5,7 +5,7 @@ Subject: [PATCH] Configurable flying kick messages
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 96e38a914db34ed165bd5071585bc7e5ec7fb41d..590880b71c3c1930eb84538af5f6c3b690bb690f 100644
|
||||
index 28ec3530a5c3df8e0c629228f80c0130cb65cc27..6017d2d5378f1d6c2a258469cc24c51e7a4ab4b6 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -355,7 +355,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
@ -6,7 +6,7 @@ Subject: [PATCH] Allow Reloading of Command Aliases
|
||||
Reload the aliases stored in commands.yml
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index bbc9f231d658dfe8cb62a6c632e5373c97ac2a75..3fff803c44c013dbcc2e639a08067d7ba3576a6d 100644
|
||||
index d83942d7f7260073e1c60e125eed6312ff89e434..1889db501bb91671eac8b8672531427d7325f35e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2629,5 +2629,24 @@ public final class CraftServer implements Server {
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren