mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-17 16:37:43 +01:00
Upstream has released updates that appear to apply and compile correctly Paper Changes: 809466f2e Fix anchor respawn acting as a bed respawn when using the end portal (#5540) d219fd642 [Auto] Updated Upstream (Bukkit/CraftBukkit) db464b099 Implement methods to convert between Component and Brigadier's Message (#5542) 4047cffca Add PlayerBedFailEnterEvent (#4935) 70d697e6e Update Paperpclip 5ed771591 [CI-SKIP] Remove bad null annotation (#5538) 454a4c78e More World API (#3850) 869e02304 Add PlayerDeepSleepEvent (#5525) fb56fc35e fix non-dummy objectives not updating dc859a61f [CI-SKIP] [Auto] Rebuild Patches 7d1689f1a Add missing checkReachable check for shulker boxes (#5453) ba8eb3d4b Add missing Javadoc for COLORABLE MaterialTag (#5376) db801cbf3 Fix PlayerItemHeldEvent firing twice (#5534) 14de2b795 fix PigZombieAngerEvent cancellation (fixes #5319) (v2) (#5329) 86d684ad1 Add get-set drop chance to EntityEquipment (#5528) 33fb8cf63 Add consumeFuel to FurnaceBurnEvent (#5532) 9957f4630 Fix duplicating /give items on item drop cancel (#5536) d94882043 Fix legacyComposer not using AsyncChatEvent messages (#5509) 053bd82cc Don't print spawn load time when not loading spawn (#5467) a6d78caae Add isDeeplySleeping to HumanEntity (#5470) 711b7a80b Expose more Adventure serializers through PaperComponents (#5443) 3f63bde0c Set Area Effect Cloud Rotation (#5462) 3523f0fda Remove useless check on player interact cancellation (#5448) 6574d1aa8 fix #5526 - use correct type when sending message to clients dbfa833ec don't throw when loading TE with invalid keys a9525a6f7 Do not schedule poi task for each block write on chunk gen 39bf5b525 Update teams known as code owners fbae9dbe0 [Auto] Updated Upstream (Bukkit/CraftBukkit) ac4a33aab [Auto] Updated Upstream (Bukkit) c1e07158b [Auto] Updated Upstream (Bukkit/CraftBukkit) 5e4b88e95 Fix dangling sout 23afda179 basic hostname validation 0fb8bdf0e Updated Upstream (Bukkit/CraftBukkit) (#5508) 88ab784da [Auto] Updated Upstream (CraftBukkit) ca7111d5f Fix PlayerItemConsumeEvent cancelling (fixes #4682) (#5383) 06fb560dc Add support for tab completing and highlighting console input from the Brigadier command tree (#5437) 0a9b89c7a Fix occasional light gen issues for neighbor blocks (#5500) Tuinity Changes: b12d0cce3 Replace ticket level propagator 42df8e1e0 Correctly handle recursion for chunkholder updates 73eb2a856 Do not copy visible chunks 8a4f3be69 Do not schedule poi task for each block write on chunk gen 7d36676fc Fix light source locking f1ec0c20d Add concurrency check to ProtoChunk light sources 159d1468f Improvements to chunk loader system 32b4d526b Updated Upstream (Paper) ac5adca33 Make sure lit is set for pre 1.14 chunks Airplane Changes: d8bdbc508 Reduce allocations for fire spreading 41051fd56 Redo reduction of entity chunk ticking check patch 31272d80f Flare Update 8f3271328 Remove criterion patch 0fed2df62 Various patches that need to be reorganized later f78856bde Updated Upstream (Tuinity) f7d6382ad Flare Update 71d079991 Update gradle configuration 0f7977428 Updated Upstream (Tuinity) 3b3cde7b0 Correctly use DEAR values, fix config reloading dd6091981 Updated Upstream (Tuinity) 07897895b Updated Upstream (Tuinity) c1e4d7143 Fluid cache patch
464 lines
23 KiB
Diff
464 lines
23 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Paul Sauve <paul@technove.co>
|
|
Date: Fri, 12 Feb 2021 16:29:41 -0600
|
|
Subject: [PATCH] Multithreaded entity tracking
|
|
|
|
Adds a configuration option to run the tracker on multiple threads.
|
|
This will generally be faster than the single threaded approach,
|
|
unless you don't have a lot of entities/players.
|
|
|
|
Airplane
|
|
Copyright (C) 2020 Technove LLC
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
diff --git a/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java b/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java
|
|
index be408aebbccbda46e8aa82ef337574137cfa0096..739839314fd8a88b5fca8b9678e1df07a166c35d 100644
|
|
--- a/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java
|
|
+++ b/src/main/java/com/tuinity/tuinity/util/maplist/IteratorSafeOrderedReferenceSet.java
|
|
@@ -16,11 +16,11 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
|
|
/* list impl */
|
|
protected E[] listElements;
|
|
- protected int listSize;
|
|
+ protected int listSize; public int getListSize() { return this.listSize; } // Airplane - getter
|
|
|
|
protected final double maxFragFactor;
|
|
|
|
- protected int iteratorCount;
|
|
+ public int iteratorCount; // Airplane - public for debug
|
|
|
|
private final boolean threadRestricted;
|
|
|
|
diff --git a/src/main/java/gg/airplane/AirplaneConfig.java b/src/main/java/gg/airplane/AirplaneConfig.java
|
|
index 7ec84ef1d1cbb1fabf4c590a2f2c1da3cc181010..b9118cc08ac38e0813d0677700d3d7dcf9b74159 100644
|
|
--- a/src/main/java/gg/airplane/AirplaneConfig.java
|
|
+++ b/src/main/java/gg/airplane/AirplaneConfig.java
|
|
@@ -102,4 +102,17 @@ public class AirplaneConfig {
|
|
}
|
|
|
|
|
|
+ public static boolean multithreadedEntityTracker = false;
|
|
+ public static boolean entityTrackerAsyncPackets = false;
|
|
+
|
|
+ private static void entityTracker() {
|
|
+ config.setComment("tracker", "Options to improve the performance of the entity tracker");
|
|
+
|
|
+ multithreadedEntityTracker = config.getBoolean("tracker.multithreaded", multithreadedEntityTracker,
|
|
+ "This enables the multithreading of the tracker.");
|
|
+ entityTrackerAsyncPackets = config.getBoolean("tracker.unsafe-async-packets", entityTrackerAsyncPackets,
|
|
+ "This option can break plugins that assume packets from the",
|
|
+ "entity tracker will be sent sync.");
|
|
+ }
|
|
+
|
|
}
|
|
diff --git a/src/main/java/gg/airplane/commands/AirplaneCommands.java b/src/main/java/gg/airplane/commands/AirplaneCommands.java
|
|
index 66b20250a26d005427601b1cdee43bdd9eba70cc..f84e26b2d8ab9a9b2d9e92e18002483127121135 100644
|
|
--- a/src/main/java/gg/airplane/commands/AirplaneCommands.java
|
|
+++ b/src/main/java/gg/airplane/commands/AirplaneCommands.java
|
|
@@ -2,11 +2,13 @@ package gg.airplane.commands;
|
|
|
|
import gg.airplane.AirplaneCommand;
|
|
import gg.airplane.flare.FlareCommand;
|
|
+import gg.airplane.structs.TrackQueue;
|
|
import net.minecraft.server.MinecraftServer;
|
|
|
|
public class AirplaneCommands {
|
|
public static void init() {
|
|
MinecraftServer.getServer().server.getCommandMap().register("airplane", "Airplane", new AirplaneCommand());
|
|
MinecraftServer.getServer().server.getCommandMap().register("flare", "Airplane", new FlareCommand());
|
|
+ TrackQueue.TrackQueueDebugCommand.register();
|
|
}
|
|
}
|
|
diff --git a/src/main/java/gg/airplane/structs/TrackQueue.java b/src/main/java/gg/airplane/structs/TrackQueue.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4419fbe94041f4b8a0ea848880798289d063b8e2
|
|
--- /dev/null
|
|
+++ b/src/main/java/gg/airplane/structs/TrackQueue.java
|
|
@@ -0,0 +1,109 @@
|
|
+package gg.airplane.structs;
|
|
+
|
|
+import com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet;
|
|
+import net.minecraft.server.level.WorldServer;
|
|
+import net.minecraft.world.level.chunk.Chunk;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.apache.logging.log4j.Level;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.command.CommandSender;
|
|
+
|
|
+import java.util.concurrent.ConcurrentLinkedQueue;
|
|
+import java.util.concurrent.ForkJoinPool;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+
|
|
+/**
|
|
+ * Helper class to handle processing a track queue.
|
|
+ */
|
|
+public class TrackQueue {
|
|
+
|
|
+ public static class TrackQueueDebugCommand extends Command {
|
|
+ protected TrackQueueDebugCommand() {
|
|
+ super("trackqueuedebug");
|
|
+ }
|
|
+
|
|
+ public static void register() {
|
|
+ MinecraftServer.getServer().server.getCommandMap().register("trackqueuedebug", "Airplane", new TrackQueueDebugCommand());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
|
+ if (!sender.isOp()) {
|
|
+ return false;
|
|
+ }
|
|
+ for (WorldServer world : MinecraftServer.getServer().getWorlds()) {
|
|
+ IteratorSafeOrderedReferenceSet<Chunk> chunks = world.getChunkProvider().entityTickingChunks;
|
|
+ sender.sendMessage(world.getWorld().getName() + ": " + chunks.size() + " / " + chunks.getListSize() + " (iterators: " + chunks.iteratorCount + ")");
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private final IteratorSafeOrderedReferenceSet<Chunk> chunks;
|
|
+ private final ForkJoinPool pool = new ForkJoinPool(Math.max(4, Runtime.getRuntime().availableProcessors() >> 2));
|
|
+ private final AtomicInteger taskIndex = new AtomicInteger();
|
|
+
|
|
+ private final ConcurrentLinkedQueue<Runnable> mainThreadTasks;
|
|
+
|
|
+ public TrackQueue(IteratorSafeOrderedReferenceSet<Chunk> chunks, ConcurrentLinkedQueue<Runnable> mainThreadTasks) {
|
|
+ this.chunks = chunks;
|
|
+ this.mainThreadTasks = mainThreadTasks;
|
|
+ }
|
|
+
|
|
+ public void start() {
|
|
+ int iterator = this.chunks.createRawIterator();
|
|
+ if (iterator == -1) {
|
|
+ return;
|
|
+ }
|
|
+ try {
|
|
+ this.taskIndex.set(iterator);
|
|
+
|
|
+ for (int i = 0; i < this.pool.getParallelism(); i++) {
|
|
+ this.pool.execute(this::run);
|
|
+ }
|
|
+
|
|
+ while (this.taskIndex.get() < this.chunks.getListSize()) {
|
|
+ this.runMainThreadTasks();
|
|
+ this.handleTask(); // assist
|
|
+ }
|
|
+ this.runMainThreadTasks(); // finish tasks
|
|
+ } finally {
|
|
+ this.chunks.finishRawIterator();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void runMainThreadTasks() {
|
|
+ Runnable task;
|
|
+ while ((task = this.mainThreadTasks.poll()) != null) {
|
|
+ try {
|
|
+ task.run();
|
|
+ } catch (Throwable t) {
|
|
+ MinecraftServer.LOGGER.log(Level.WARN, "Tasks failed while ticking track queue", t);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ private void run() {
|
|
+ while (handleTask());
|
|
+ }
|
|
+
|
|
+ private boolean handleTask() {
|
|
+ int index;
|
|
+ while ((index = this.taskIndex.getAndIncrement()) < this.chunks.getListSize()) {
|
|
+ Chunk chunk = this.chunks.rawGet(index);
|
|
+ if (chunk != null) {
|
|
+ try {
|
|
+ chunk.entityTracker.run();
|
|
+ } catch (Throwable t) {
|
|
+ MinecraftServer.LOGGER.log(Level.WARN, "Ticking tracker failed", t);
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
|
|
index 207a9c3928aad7c6e89a120b54d87e003ebd232c..424cd048f905cd0ed3f7a4545a26ffde8da1f91f 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
|
|
@@ -388,7 +388,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
}
|
|
|
|
final com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<Chunk> tickingChunks = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true);
|
|
- final com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<Chunk> entityTickingChunks = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true);
|
|
+ public final com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<Chunk> entityTickingChunks = new com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); // Airplane - public for debug
|
|
// Tuinity end
|
|
|
|
public ChunkProviderServer(WorldServer worldserver, Convertable.ConversionSession convertable_conversionsession, DataFixer datafixer, DefinedStructureManager definedstructuremanager, Executor executor, ChunkGenerator chunkgenerator, int i, boolean flag, WorldLoadListener worldloadlistener, Supplier<WorldPersistentData> supplier) {
|
|
diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java
|
|
index fb61b6ac167b34486282a24e598020fb96081f28..b2e21e7034ad83a4ba1c99f860be5a0f5ee6a75f 100644
|
|
--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java
|
|
@@ -182,7 +182,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|
public NetworkManager networkManager; // Paper
|
|
public final MinecraftServer server;
|
|
public final PlayerInteractManager playerInteractManager;
|
|
- public final Deque<Integer> removeQueue = new ArrayDeque<>(); // Paper
|
|
+ public final Deque<Integer> removeQueue = new java.util.concurrent.ConcurrentLinkedDeque<>(); // Paper // Airplane concurrent deque
|
|
private final AdvancementDataPlayer advancementDataPlayer;
|
|
private final ServerStatisticManager serverStatisticManager;
|
|
private float lastHealthScored = Float.MIN_VALUE;
|
|
diff --git a/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java
|
|
index 67ca28463f5add7c18f7f16b918c3f36f8feeeda..37e64e24ca3a90370cdf12e5ff9cd1fceede796b 100644
|
|
--- a/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java
|
|
+++ b/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java
|
|
@@ -75,6 +75,10 @@ public class EntityTrackerEntry {
|
|
* Requested in https://github.com/PaperMC/Paper/issues/1537 to allow intercepting packets
|
|
*/
|
|
public void sendPlayerPacket(EntityPlayer player, Packet packet) {
|
|
+ if (!gg.airplane.AirplaneConfig.entityTrackerAsyncPackets && !org.bukkit.Bukkit.isPrimaryThread()) {
|
|
+ this.b.chunkProvider.playerChunkMap.trackerEnsureMain(() -> sendPlayerPacket(player, packet));
|
|
+ return;
|
|
+ }
|
|
player.playerConnection.sendPacket(packet);
|
|
}
|
|
|
|
@@ -103,7 +107,7 @@ public class EntityTrackerEntry {
|
|
|
|
public final void tick() { this.a(); } // Paper - OBFHELPER
|
|
public void a() {
|
|
- com.tuinity.tuinity.util.TickThread.softEnsureTickThread("Tracker update"); // Tuinity
|
|
+ //com.tuinity.tuinity.util.TickThread.softEnsureTickThread("Tracker update"); // Tuinity // Airplane - allow multithreaded
|
|
List<Entity> list = this.tracker.passengers; // Paper - do not copy list
|
|
|
|
if (!list.equals(this.p)) {
|
|
@@ -116,6 +120,8 @@ public class EntityTrackerEntry {
|
|
ItemStack itemstack = entityitemframe.getItem();
|
|
|
|
if (this.tickCounter % 10 == 0 && itemstack.getItem() instanceof ItemWorldMap) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks
|
|
+ // Airplane start - process maps on main
|
|
+ this.b.chunkProvider.playerChunkMap.trackerEnsureMain(() -> {
|
|
WorldMap worldmap = ItemWorldMap.getSavedMap(itemstack, this.b);
|
|
Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit
|
|
|
|
@@ -129,6 +135,8 @@ public class EntityTrackerEntry {
|
|
entityplayer.playerConnection.sendPacket(packet);
|
|
}
|
|
}
|
|
+ });
|
|
+ // Airplane end
|
|
}
|
|
|
|
this.c();
|
|
@@ -263,18 +271,25 @@ public class EntityTrackerEntry {
|
|
// CraftBukkit start - Create PlayerVelocity event
|
|
boolean cancelled = false;
|
|
|
|
- if (this.tracker instanceof EntityPlayer) {
|
|
+ if (this.tracker instanceof EntityPlayer && PlayerVelocityEvent.getHandlerList().getRegisteredListeners().length > 0) { // Airplane - ensure there's listeners
|
|
+ // Airplane start - run on main thread
|
|
+ this.b.chunkProvider.playerChunkMap.trackerEnsureMain(() -> {
|
|
Player player = (Player) this.tracker.getBukkitEntity();
|
|
org.bukkit.util.Vector velocity = player.getVelocity();
|
|
|
|
PlayerVelocityEvent event = new PlayerVelocityEvent(player, velocity.clone());
|
|
this.tracker.world.getServer().getPluginManager().callEvent(event);
|
|
|
|
- if (event.isCancelled()) {
|
|
- cancelled = true;
|
|
- } else if (!velocity.equals(event.getVelocity())) {
|
|
+ if (!event.isCancelled() && !velocity.equals(event.getVelocity())) {
|
|
player.setVelocity(event.getVelocity());
|
|
}
|
|
+ if (!event.isCancelled()) {
|
|
+ this.broadcastIncludingSelf(new PacketPlayOutEntityVelocity(this.tracker)); // duplicate from !cancelled below
|
|
+ }
|
|
+
|
|
+ });
|
|
+ cancelled = true; // don't broadcast until the event has finished
|
|
+ // Airplane end
|
|
}
|
|
|
|
if (!cancelled) {
|
|
@@ -358,7 +373,9 @@ public class EntityTrackerEntry {
|
|
if (!list.isEmpty()) {
|
|
consumer.accept(new PacketPlayOutEntityEquipment(this.tracker.getId(), list));
|
|
}
|
|
+ this.b.chunkProvider.playerChunkMap.trackerEnsureMain(() -> { // Airplane
|
|
((EntityLiving) this.tracker).updateEquipment(); // CraftBukkit - SPIGOT-3789: sync again immediately after sending
|
|
+ }); // Airplane
|
|
}
|
|
|
|
// CraftBukkit start - Fix for nonsensical head yaw
|
|
@@ -436,6 +453,10 @@ public class EntityTrackerEntry {
|
|
// Paper end
|
|
|
|
private void broadcastIncludingSelf(Packet<?> packet) {
|
|
+ if (!gg.airplane.AirplaneConfig.entityTrackerAsyncPackets && !org.bukkit.Bukkit.isPrimaryThread()) {
|
|
+ this.b.chunkProvider.playerChunkMap.trackerEnsureMain(() -> broadcastIncludingSelf(packet));
|
|
+ return;
|
|
+ }
|
|
this.f.accept(packet);
|
|
if (this.tracker instanceof EntityPlayer) {
|
|
((EntityPlayer) this.tracker).playerConnection.sendPacket(packet);
|
|
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
index 914c7a1b18151f29183cfe9474313ce18e7c4ae2..737851cde7752e7cccf226f1868a38d6411bfb31 100644
|
|
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
@@ -769,6 +769,11 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
return this.updatingChunks.getVisibleAsync(i);
|
|
// Tuinity end - Don't copy
|
|
}
|
|
+ // Airplane start - since neither map can be updated during tracker tick, it's safe to allow direct retrieval here
|
|
+ private PlayerChunk trackerGetVisibleChunk(long i) {
|
|
+ return this.updatingChunks.getVisibleAsync(i);
|
|
+ }
|
|
+ // Airplane end
|
|
|
|
protected final IntSupplier getPrioritySupplier(long i) { return c(i); } // Paper - OBFHELPER
|
|
protected IntSupplier c(long i) {
|
|
@@ -2164,10 +2169,30 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
entity.tracker = null; // Paper - We're no longer tracked
|
|
}
|
|
|
|
+ // Airplane start - tools to ensure main thread
|
|
+ private final java.util.concurrent.ConcurrentLinkedQueue<Runnable> trackerMainQueue = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
|
+ private gg.airplane.structs.TrackQueue trackQueue;
|
|
+
|
|
+ void trackerEnsureMain(Runnable runnable) {
|
|
+ if (this.world.serverThread == Thread.currentThread()) {
|
|
+ runnable.run();
|
|
+ } else {
|
|
+ this.trackerMainQueue.add(runnable);
|
|
+ }
|
|
+ }
|
|
+ // Airplane end
|
|
+
|
|
// Paper start - optimised tracker
|
|
private final void processTrackQueue() {
|
|
this.world.timings.tracker1.startTiming();
|
|
try {
|
|
+ // Airplane start - multithreaded tracker
|
|
+ if (this.trackQueue == null) this.trackQueue = new gg.airplane.structs.TrackQueue(this.world.getChunkProvider().entityTickingChunks, trackerMainQueue);
|
|
+ if (gg.airplane.AirplaneConfig.multithreadedEntityTracker) {
|
|
+ this.trackQueue.start();
|
|
+ return;
|
|
+ }
|
|
+ // Airplane end
|
|
com.tuinity.tuinity.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Chunk> iterator = this.world.getChunkProvider().entityTickingChunks.iterator();
|
|
try {
|
|
while (iterator.hasNext()) {
|
|
@@ -2433,7 +2458,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
|
public class EntityTracker {
|
|
|
|
final EntityTrackerEntry trackerEntry; // Paper - private -> package private
|
|
- private final Entity tracker;
|
|
+ public final Entity tracker; // Airplane - public for chunk
|
|
private final int trackingDistance;
|
|
private SectionPosition e;
|
|
// Paper start
|
|
@@ -2452,7 +2477,9 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
|
// Paper start - use distance map to optimise tracker
|
|
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> lastTrackerCandidates;
|
|
|
|
- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> newTrackerCandidates) {
|
|
+ public synchronized final void tickEntry() { this.trackerEntry.tick(); } // Airplane - move entry tick into sync block
|
|
+
|
|
+ public synchronized final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> newTrackerCandidates) { // Airplane
|
|
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> oldTrackerCandidates = this.lastTrackerCandidates;
|
|
this.lastTrackerCandidates = newTrackerCandidates;
|
|
|
|
@@ -2493,7 +2520,13 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
|
return this.tracker.getId();
|
|
}
|
|
|
|
- public void broadcast(Packet<?> packet) {
|
|
+ public synchronized void broadcast(Packet<?> packet) { // Airplane - synchronized for tracked player
|
|
+ // Airplane start
|
|
+ if (!gg.airplane.AirplaneConfig.entityTrackerAsyncPackets && !org.bukkit.Bukkit.isPrimaryThread()) {
|
|
+ trackerEnsureMain(() -> broadcast(packet));
|
|
+ return;
|
|
+ }
|
|
+ // Airplane end
|
|
Iterator iterator = this.trackedPlayers.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -2505,6 +2538,12 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
|
}
|
|
|
|
public void broadcastIncludingSelf(Packet<?> packet) {
|
|
+ // Airplane start
|
|
+ if (!gg.airplane.AirplaneConfig.entityTrackerAsyncPackets && !org.bukkit.Bukkit.isPrimaryThread()) {
|
|
+ trackerEnsureMain(() -> broadcastIncludingSelf(packet));
|
|
+ return;
|
|
+ }
|
|
+ // Airplane end
|
|
this.broadcast(packet);
|
|
if (this.tracker instanceof EntityPlayer) {
|
|
((EntityPlayer) this.tracker).playerConnection.sendPacket(packet);
|
|
@@ -2531,8 +2570,8 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
|
|
|
}
|
|
|
|
- public void updatePlayer(EntityPlayer entityplayer) {
|
|
- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
|
|
+ public synchronized void updatePlayer(EntityPlayer entityplayer) { // Airplane - sync for access to map
|
|
+ //org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot // Airplane - allow sync for tracker
|
|
if (entityplayer != this.tracker) {
|
|
// Paper start - remove allocation of Vec3D here
|
|
//Vec3D vec3d = entityplayer.getPositionVector().d(this.tracker.getPositionVector()); // MC-155077, SPIGOT-5113
|
|
@@ -2553,7 +2592,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
|
*/
|
|
int x = this.tracker.chunkX, z = this.tracker.chunkZ;
|
|
long chunkcoordintpair = ChunkCoordIntPair.pair(x, z);
|
|
- PlayerChunk playerchunk = PlayerChunkMap.this.getVisibleChunk(chunkcoordintpair);
|
|
+ PlayerChunk playerchunk = PlayerChunkMap.this.trackerGetVisibleChunk(chunkcoordintpair); // Airplane
|
|
|
|
if (playerchunk != null && playerchunk.getSendingChunk() != null && PlayerChunkMap.this.playerChunkManager.isChunkSent(entityplayer, MathHelper.floor(this.tracker.locX()) >> 4, MathHelper.floor(this.tracker.locZ()) >> 4)) { // Paper - no-tick view distance // Tuinity - don't broadcast in chunks the player hasn't received
|
|
flag1 = PlayerChunkMap.someDistanceCalculation(x, z, entityplayer, false) <= PlayerChunkMap.this.viewDistance;
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
|
|
index 9ba7c5080ce0cacf438bdd6e11f75cb34fbc5759..cef0462fadb305ebc2b53d37e0c17514626df99d 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
|
|
@@ -111,6 +111,26 @@ public class Chunk implements IChunkAccess {
|
|
}
|
|
// Airplane end
|
|
|
|
+ // Airplane start - entity tracker runnable
|
|
+ // prevents needing to allocate new lambda in processTrackQueue
|
|
+ public final Runnable entityTracker = new Runnable() {
|
|
+ @Override
|
|
+ public void run() {
|
|
+ Entity[] entities = Chunk.this.entities.getRawData();
|
|
+ for (int i = 0, len = Chunk.this.entities.size(); i < len; ++i) {
|
|
+ Entity entity = entities[i];
|
|
+ if (entity != null) {
|
|
+ PlayerChunkMap.EntityTracker tracker = ((WorldServer) Chunk.this.getWorld()).getChunkProvider().playerChunkMap.trackedEntities.get(entity.getId());
|
|
+ if (tracker != null) {
|
|
+ tracker.updatePlayers(tracker.tracker.getPlayersInTrackRange());
|
|
+ tracker.tickEntry();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+ // Airplane end
|
|
+
|
|
public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeStorage biomestorage) {
|
|
this(world, chunkcoordintpair, biomestorage, ChunkConverter.a, TickListEmpty.b(), TickListEmpty.b(), 0L, (ChunkSection[]) null, (Consumer) null);
|
|
}
|