mirror of
https://github.com/Samsuik/Sakura.git
synced 2025-12-20 23:39:32 +00:00
523 lines
29 KiB
Diff
523 lines
29 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Samsuik <kfian294ma4@gmail.com>
|
|
Date: Mon, 27 May 2024 18:02:27 +0100
|
|
Subject: [PATCH] Async Entity Tracking
|
|
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java
|
|
index 41b9405d6759d865e0d14dd4f95163e9690e967d..9767c1fcdbd5737c31e36fd9c39e89631ce8ee1c 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java
|
|
@@ -26,7 +26,7 @@ public abstract class AreaMap<E> {
|
|
|
|
// we use linked for better iteration.
|
|
// map of: coordinate to set of objects in coordinate
|
|
- protected final Long2ObjectOpenHashMap<PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E>> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f);
|
|
+ protected Long2ObjectOpenHashMap<PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E>> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); // Sakura - async entity tracking
|
|
protected final PooledLinkedHashSets<E> pooledHashSets;
|
|
|
|
protected final ChangeCallback<E> addCallback;
|
|
diff --git a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java
|
|
index 46954db7ecd35ac4018fdf476df7c8020d7ce6c8..183c3d13835a4f4bf6e3a4fa6eb2df0f21b8c882 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java
|
|
@@ -5,7 +5,7 @@ import net.minecraft.server.level.ServerPlayer;
|
|
/**
|
|
* @author Spottedleaf
|
|
*/
|
|
-public final class PlayerAreaMap extends AreaMap<ServerPlayer> {
|
|
+public class PlayerAreaMap extends AreaMap<ServerPlayer> { // Sakura - async entity tracking
|
|
|
|
public PlayerAreaMap() {
|
|
super();
|
|
diff --git a/src/main/java/me/samsuik/sakura/player/tracking/AsyncEntityTracker.java b/src/main/java/me/samsuik/sakura/player/tracking/AsyncEntityTracker.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ca24b6fb2d4e8d4ff284f6b19c971f186e00cc38
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/player/tracking/AsyncEntityTracker.java
|
|
@@ -0,0 +1,83 @@
|
|
+package me.samsuik.sakura.player.tracking;
|
|
+
|
|
+import net.minecraft.server.level.ChunkMap;
|
|
+import org.spigotmc.AsyncCatcher;
|
|
+
|
|
+import java.util.*;
|
|
+import java.util.concurrent.ExecutorService;
|
|
+import java.util.concurrent.Executors;
|
|
+import java.util.concurrent.ThreadFactory;
|
|
+
|
|
+public final class AsyncEntityTracker {
|
|
+ private static final int AVAILABLE_THREADS = Math.max(Runtime.getRuntime().availableProcessors() / 5 * 2, 1); // 0.4
|
|
+ private static final ThreadFactory THREAD_FACTORY = EntityTrackerThread::new;
|
|
+ private static ExecutorService TRACKER_EXECUTOR = null;
|
|
+
|
|
+ private final Queue<Runnable> tasks = new ArrayDeque<>();
|
|
+ private final ChunkMap chunkMap;
|
|
+ private volatile boolean processingTick;
|
|
+
|
|
+ public AsyncEntityTracker(ChunkMap chunkMap) {
|
|
+ this.chunkMap = chunkMap;
|
|
+ }
|
|
+
|
|
+ private static void tryStartService() {
|
|
+ if (TRACKER_EXECUTOR == null) {
|
|
+ TRACKER_EXECUTOR = Executors.newFixedThreadPool(AVAILABLE_THREADS, THREAD_FACTORY);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void scheduleForNextCycle(Runnable runnable) {
|
|
+ AsyncCatcher.catchOp("scheduled task off-main");
|
|
+ this.tasks.offer(runnable);
|
|
+ }
|
|
+
|
|
+ private void runScheduledTasks() {
|
|
+ Runnable runnable;
|
|
+ while ((runnable = this.tasks.poll()) != null) {
|
|
+ runnable.run();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void cycle() {
|
|
+ if (this.processingTick) {
|
|
+ // Could this cause issues with players on teleports?
|
|
+ return; // uh oh.
|
|
+ }
|
|
+
|
|
+ tryStartService();
|
|
+ this.processingTick = true;
|
|
+ this.runScheduledTasks();
|
|
+
|
|
+ List<ChunkMap.TrackedEntity> trackedEntities = new ArrayList<>(this.chunkMap.entityMap.values());
|
|
+
|
|
+ TRACKER_EXECUTOR.execute(() -> {
|
|
+ try {
|
|
+ this.processEntities(trackedEntities);
|
|
+ } finally {
|
|
+ this.processingTick = false;
|
|
+ }
|
|
+ });
|
|
+ }
|
|
+
|
|
+ private void processEntities(List<ChunkMap.TrackedEntity> trackedEntities) {
|
|
+ // update players (seenBy)
|
|
+ for (ChunkMap.TrackedEntity tracker : trackedEntities) {
|
|
+ if (!tracker.isActive) continue; // removed entity
|
|
+ synchronized (tracker.entity) {
|
|
+ if (tracker.shouldLookForPlayers()) {
|
|
+ tracker.updatePlayers(tracker.entity.getPlayersInTrackRange());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // send changes
|
|
+ for (ChunkMap.TrackedEntity tracker : trackedEntities) {
|
|
+ if (!tracker.isActive) continue; // removed entity
|
|
+ tracker.seenByLock.readLock().lock();
|
|
+ synchronized (tracker.entity) {
|
|
+ tracker.serverEntity.sendChanges();
|
|
+ }
|
|
+ tracker.seenByLock.readLock().unlock();
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/player/tracking/EntityTrackerThread.java b/src/main/java/me/samsuik/sakura/player/tracking/EntityTrackerThread.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ac95e188335419cb3db37e62a3e83f87ffc8ee9d
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/player/tracking/EntityTrackerThread.java
|
|
@@ -0,0 +1,13 @@
|
|
+package me.samsuik.sakura.player.tracking;
|
|
+
|
|
+import io.papermc.paper.util.TickThread;
|
|
+
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+
|
|
+public final class EntityTrackerThread extends TickThread {
|
|
+ private static final AtomicInteger THREAD_COUNTER = new AtomicInteger(0);
|
|
+
|
|
+ public EntityTrackerThread(Runnable runnable) {
|
|
+ super(runnable, "Entity Tracker Thread " + THREAD_COUNTER.getAndIncrement());
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/me/samsuik/sakura/player/tracking/ThreadSafePlayerAreaMap.java b/src/main/java/me/samsuik/sakura/player/tracking/ThreadSafePlayerAreaMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d4f69edae2c5e2d10bd417ad82f8f1aec5121e2e
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/samsuik/sakura/player/tracking/ThreadSafePlayerAreaMap.java
|
|
@@ -0,0 +1,35 @@
|
|
+package me.samsuik.sakura.player.tracking;
|
|
+
|
|
+import com.destroystokyo.paper.util.misc.PlayerAreaMap;
|
|
+import com.destroystokyo.paper.util.misc.PooledLinkedHashSets;
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+
|
|
+public final class ThreadSafePlayerAreaMap extends PlayerAreaMap {
|
|
+ public ThreadSafePlayerAreaMap(final PooledLinkedHashSets<ServerPlayer> pooledHashSets) {
|
|
+ super(pooledHashSets);
|
|
+ this.areaMap = new SynchronizedLong2ObjectOpenHashMap<>();
|
|
+ }
|
|
+
|
|
+ private static class SynchronizedLong2ObjectOpenHashMap<E> extends Long2ObjectOpenHashMap<PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E>> {
|
|
+ @Override
|
|
+ public synchronized PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E> put(long k, PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E> ePooledObjectLinkedOpenHashSet) {
|
|
+ return super.put(k, ePooledObjectLinkedOpenHashSet);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E> putIfAbsent(long k, PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E> ePooledObjectLinkedOpenHashSet) {
|
|
+ return super.putIfAbsent(k, ePooledObjectLinkedOpenHashSet);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean remove(Object key, Object value) {
|
|
+ return super.remove(key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<E> get(long k) {
|
|
+ return super.get(k);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 64bf4398a8a0b429e5a7483cf8a24a02c58b7fb3..b2ddb8910fe20be83d4b67142854a008fbd26eb0 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -338,7 +338,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
int trackRange = (configuredSpigotValue >>> 4) + ((configuredSpigotValue & 15) != 0 ? 1 : 0);
|
|
this.entityTrackerTrackRanges[ordinal] = trackRange;
|
|
|
|
- this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
|
+ this.playerEntityTrackerTrackMaps[ordinal] = new me.samsuik.sakura.player.tracking.ThreadSafePlayerAreaMap(this.pooledLinkedPlayerHashSets); // Sakura - async entity tracking
|
|
}
|
|
// Paper end - use distance map to optimise entity tracker
|
|
}
|
|
@@ -1095,7 +1095,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
|
|
this.entityMap.put(entity.getId(), playerchunkmap_entitytracker);
|
|
+ // Sakura start - async entity tracking
|
|
+ Runnable updatePlayers = () -> {
|
|
playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players
|
|
+ };
|
|
+ if (this.level.asyncEntityTracking) {
|
|
+ this.asyncEntityTracker.scheduleForNextCycle(updatePlayers);
|
|
+ } else {
|
|
+ updatePlayers.run();
|
|
+ }
|
|
+ // Sakura end - async entity tracking
|
|
if (entity instanceof ServerPlayer) {
|
|
ServerPlayer entityplayer = (ServerPlayer) entity;
|
|
|
|
@@ -1163,8 +1172,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
}
|
|
// Paper end - optimised tracker
|
|
-
|
|
+ // Sakura start - async entity tracking
|
|
+ private final me.samsuik.sakura.player.tracking.AsyncEntityTracker asyncEntityTracker = new me.samsuik.sakura.player.tracking.AsyncEntityTracker(this);
|
|
protected void tick() {
|
|
+ if (this.level.asyncEntityTracking) {
|
|
+ this.asyncEntityTracker.cycle();
|
|
+ return;
|
|
+ }
|
|
+ // Sakura end - async entity tracking
|
|
// Paper start - optimized tracker
|
|
if (true) {
|
|
this.processTrackQueue();
|
|
@@ -1308,12 +1323,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
public class TrackedEntity {
|
|
|
|
public final ServerEntity serverEntity;
|
|
- final Entity entity;
|
|
+ public final Entity entity; // Sakura - package-protected -> public
|
|
private final int range;
|
|
SectionPos lastSectionPos;
|
|
public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
|
private final int playerSearchInterval; // Sakura - reduce entity tracker player updates
|
|
private Vec3 entityPosition; // Sakura - reduce entity tracker player updates
|
|
+ public final java.util.concurrent.locks.ReentrantReadWriteLock seenByLock = new java.util.concurrent.locks.ReentrantReadWriteLock(); // Sakura - async entity tracking
|
|
+ public volatile boolean isActive = true; // Sakura - async entity tracking
|
|
|
|
public TrackedEntity(Entity entity, int i, int j, boolean flag) {
|
|
this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit
|
|
@@ -1343,7 +1360,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Paper start - use distance map to optimise tracker
|
|
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> lastTrackerCandidates;
|
|
|
|
- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) {
|
|
+ public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) { // Sakura - async entity tracking
|
|
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> oldTrackerCandidates = this.lastTrackerCandidates;
|
|
this.lastTrackerCandidates = newTrackerCandidates;
|
|
|
|
@@ -1355,7 +1372,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
continue;
|
|
}
|
|
ServerPlayer player = (ServerPlayer)raw;
|
|
- this.updatePlayer(player);
|
|
+ this.sakura_updatePlayer(player); // Sakura - async entity tracking
|
|
}
|
|
}
|
|
|
|
@@ -1370,7 +1387,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
for (ServerPlayerConnection conn : this.seenBy.toArray(new ServerPlayerConnection[0])) { // avoid CME
|
|
if (newTrackerCandidates == null || !newTrackerCandidates.contains(conn.getPlayer())) {
|
|
- this.updatePlayer(conn.getPlayer());
|
|
+ this.sakura_updatePlayer(conn.getPlayer()); // Sakura - async entity tracking
|
|
}
|
|
}
|
|
}
|
|
@@ -1404,6 +1421,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
|
|
public void broadcastRemoved() {
|
|
+ this.isActive = false; // Sakura - async entity tracking
|
|
+ this.seenByLock.readLock().lock(); // Sakura - async entity tracking
|
|
Iterator iterator = this.seenBy.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -1411,19 +1430,27 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
this.serverEntity.removePairing(serverplayerconnection.getPlayer());
|
|
}
|
|
+ this.seenByLock.readLock().unlock(); // Sakura - async entity tracking
|
|
|
|
}
|
|
|
|
public void removePlayer(ServerPlayer player) {
|
|
org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
|
|
+ this.seenByLock.writeLock().lock(); // Sakura - async entity tracking
|
|
if (this.seenBy.remove(player.connection)) {
|
|
this.serverEntity.removePairing(player);
|
|
}
|
|
+ this.seenByLock.writeLock().unlock(); // Sakura - async entity tracking
|
|
|
|
}
|
|
|
|
public void updatePlayer(ServerPlayer player) {
|
|
org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
|
|
+ // Sakura start - async entity tracking
|
|
+ this.sakura_updatePlayer(player);
|
|
+ }
|
|
+ private void sakura_updatePlayer(ServerPlayer player) {
|
|
+ // Sakura end - async entity tracking
|
|
if (player != this.entity) {
|
|
// Paper start - remove allocation of Vec3D here
|
|
// Vec3 vec3d = player.position().subtract(this.entity.position());
|
|
@@ -1466,6 +1493,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
flag = false;
|
|
}
|
|
// CraftBukkit end
|
|
+ this.seenByLock.writeLock().lock(); // Sakura - async entity tracking
|
|
if (flag) {
|
|
if (this.seenBy.add(player.connection)) {
|
|
// Paper start - entity tracking events
|
|
@@ -1477,6 +1505,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
} else if (this.seenBy.remove(player.connection)) {
|
|
this.serverEntity.removePairing(player);
|
|
}
|
|
+ this.seenByLock.writeLock().unlock(); // Sakura - async entity tracking
|
|
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index 2a9a6a9f00343f614a0d2430095a17088861eb1f..8d27289aa81aa60ba6bdde57b74fc4a0a76df4e5 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -923,7 +923,11 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
// Sakura end
|
|
|
|
gameprofilerfiller.push("tick");
|
|
+ // Sakura start - async entity tracking
|
|
+ synchronized (entity) {
|
|
this.guardEntityTick(this::tickNonPassenger, entity);
|
|
+ }
|
|
+ // Sakura end - async entity tracking
|
|
gameprofilerfiller.pop();
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
index d6e60e4e7b5410f30b47e6b9b57b390837368dfc..3583a897912f4ae15111c909284c9b98aa55954c 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
@@ -335,8 +335,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
this.player.xo = this.player.getX();
|
|
this.player.yo = this.player.getY();
|
|
this.player.zo = this.player.getZ();
|
|
+ synchronized (this.player) { // Sakura - async entity tracking
|
|
this.player.doTick();
|
|
this.player.absMoveTo(this.firstGoodX, this.firstGoodY, this.firstGoodZ, this.player.getYRot(), this.player.getXRot());
|
|
+ } // Sakura - async entity tracking
|
|
++this.tickCount;
|
|
this.knownMovePacketCount = this.receivedMovePacketCount;
|
|
if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) {
|
|
@@ -2090,11 +2092,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
|
|
this.player.disconnect();
|
|
// Paper start - Adventure
|
|
+ synchronized (this.player) { // Sakura - async entity tracking
|
|
quitMessage = quitMessage == null ? this.server.getPlayerList().remove(this.player) : this.server.getPlayerList().remove(this.player, quitMessage); // Paper - pass in quitMessage to fix kick message not being used
|
|
if ((quitMessage != null) && !quitMessage.equals(net.kyori.adventure.text.Component.empty())) {
|
|
this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(quitMessage), false);
|
|
// Paper end
|
|
}
|
|
+ } // Sakura - async entity tracking
|
|
// CraftBukkit end
|
|
this.player.getTextFilter().leave();
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
index 08d33295967f66051b9e846d854ffac6fe885281..febc3242b6aa112b1fad1b5559e5ccf7b50b4adc 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
@@ -3418,7 +3418,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
|
list.add(passenger);
|
|
}
|
|
|
|
+ synchronized (this) { // Sakura - async entity tracking
|
|
this.passengers = ImmutableList.copyOf(list);
|
|
+ } // Sakura - async entity tracking
|
|
}
|
|
|
|
this.gameEvent(GameEvent.ENTITY_MOUNT, passenger);
|
|
@@ -3460,6 +3462,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
|
return false;
|
|
}
|
|
// CraftBukkit end
|
|
+ synchronized (this) { // Sakura - async entity tracking
|
|
if (this.passengers.size() == 1 && this.passengers.get(0) == entity) {
|
|
this.passengers = ImmutableList.of();
|
|
} else {
|
|
@@ -3467,6 +3470,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
|
|
return entity1 != entity;
|
|
}).collect(ImmutableList.toImmutableList());
|
|
}
|
|
+ } // Sakura - async entity tracking
|
|
|
|
entity.boardingCooldown = 60;
|
|
this.gameEvent(GameEvent.ENTITY_DISMOUNT, entity);
|
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
index c2c0d80adb6fa8cb74fa5fe3ce5bc7ac0609abba..7c821e890243d7ab0975a78f29f107cb5199f973 100644
|
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
@@ -466,11 +466,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
return x >= bb.minX && x <= bb.maxX && y >= bb.minY && y <= bb.maxY;
|
|
}
|
|
// Sakura end - physics version api
|
|
+ public final boolean asyncEntityTracking; // Sakura - async entity tracking
|
|
|
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - create paper world config; Async-Anti-Xray: Pass executor
|
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
|
this.sakuraConfig = sakuraWorldConfigCreator.get(); // Sakura
|
|
+ this.asyncEntityTracking = this.sakuraConfig().players.entityTracker.asyncTracking; // Sakura - async entity tracking
|
|
this.generator = gen;
|
|
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
|
index 45269115e63cfc3bd7dc740a5694e2cc7c35bcb1..fd782a72f934e2de943d664568ccc7293b980e69 100644
|
|
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
|
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
|
@@ -63,7 +63,7 @@ public class MapItemSavedData extends SavedData {
|
|
public final List<MapItemSavedData.HoldingPlayer> carriedBy = Lists.newArrayList();
|
|
public final Map<Player, MapItemSavedData.HoldingPlayer> carriedByPlayers = Maps.newHashMap();
|
|
private final Map<String, MapBanner> bannerMarkers = Maps.newHashMap();
|
|
- public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
|
|
+ public final Map<String, MapDecoration> decorations = java.util.Collections.synchronizedMap(Maps.newLinkedHashMap()); // Sakura - async entity tracking
|
|
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
|
|
private int trackedDecorationCount;
|
|
private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
|
|
@@ -584,6 +584,7 @@ public class MapItemSavedData extends SavedData {
|
|
// Paper start
|
|
private void addSeenPlayers(java.util.Collection<MapDecoration> icons) {
|
|
org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity();
|
|
+ synchronized (MapItemSavedData.this.decorations) { // Sakura - async entity tracking
|
|
MapItemSavedData.this.decorations.forEach((name, mapIcon) -> {
|
|
// If this cursor is for a player check visibility with vanish system
|
|
org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot
|
|
@@ -591,6 +592,7 @@ public class MapItemSavedData extends SavedData {
|
|
icons.add(mapIcon);
|
|
}
|
|
});
|
|
+ } // Sakura - async entity tracking
|
|
}
|
|
private boolean shouldUseVanillaMap() {
|
|
return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class;
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
index 4731d10dd5e493af9564d38d8bf1ff223390bd75..b1904549b1b1180ebae822e63871f6e80d9100cc 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
@@ -715,9 +715,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId());
|
|
|
|
if (entityTracker != null) {
|
|
+ entityTracker.seenByLock.readLock().lock(); // Sakura - async entity tracking
|
|
for (ServerPlayerConnection connection : entityTracker.seenBy) {
|
|
players.add(connection.getPlayer().getBukkitEntity());
|
|
}
|
|
+ entityTracker.seenByLock.readLock().unlock(); // Sakura - async entity tracking
|
|
}
|
|
|
|
return players.build();
|
|
@@ -1013,9 +1015,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
}
|
|
|
|
// Paper start, resend possibly desynced entity instead of add entity packet
|
|
+ entityTracker.seenByLock.readLock().lock(); // Sakura - async entity tracking
|
|
for (ServerPlayerConnection playerConnection : entityTracker.seenBy) {
|
|
this.getHandle().getEntityData().resendPossiblyDesyncedEntity(playerConnection.getPlayer());
|
|
}
|
|
+ entityTracker.seenByLock.readLock().unlock(); // Sakura - async entity tracking
|
|
// Paper end
|
|
}
|
|
|
|
@@ -1183,10 +1187,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
return java.util.Collections.emptySet();
|
|
}
|
|
|
|
+ this.entity.tracker.seenByLock.readLock().lock(); // Sakura - async entity tracking
|
|
Set<org.bukkit.entity.Player> set = new java.util.HashSet<>(this.entity.tracker.seenBy.size());
|
|
for (net.minecraft.server.network.ServerPlayerConnection connection : this.entity.tracker.seenBy) {
|
|
set.add(connection.getPlayer().getBukkitEntity().getPlayer());
|
|
}
|
|
+ this.entity.tracker.seenByLock.readLock().unlock(); // Sakura - async entity tracking
|
|
return set;
|
|
}
|
|
// Paper end - tracked players API
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
index 29f0c4c3fd9185bf8768572c135b50a9db34dbbe..cd462589ab90bf8dfd4a213f49c1257c8152e137 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
@@ -2060,9 +2060,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
}
|
|
|
|
ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId());
|
|
+ entry.seenByLock.readLock().lock(); // Sakura - async entity tracking
|
|
if (entry != null && !entry.seenBy.contains(this.getHandle().connection)) {
|
|
entry.updatePlayer(this.getHandle());
|
|
}
|
|
+ entry.seenByLock.readLock().unlock(); // Sakura - async entity tracking
|
|
|
|
this.server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity));
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
|
|
index 15e9dd8844f893de5e8372b847c9e8295d6f69ca..8948474a27b70ed00a2eb0fc6db3beadd2a083ee 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java
|
|
@@ -34,6 +34,7 @@ public class CraftMapRenderer extends MapRenderer {
|
|
cursors.removeCursor(cursors.getCursor(0));
|
|
}
|
|
|
|
+ synchronized (this.worldMap.decorations) { // Sakura - async entity tracking
|
|
for (String key : this.worldMap.decorations.keySet()) {
|
|
// If this cursor is for a player check visibility with vanish system
|
|
Player other = Bukkit.getPlayerExact((String) key);
|
|
@@ -44,6 +45,7 @@ public class CraftMapRenderer extends MapRenderer {
|
|
MapDecoration decoration = this.worldMap.decorations.get(key);
|
|
cursors.addCursor(decoration.x(), decoration.y(), (byte) (decoration.rot() & 15), decoration.type().getIcon(), true, decoration.name() == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(decoration.name())); // Paper
|
|
}
|
|
+ } // Sakura - async entity tracking
|
|
}
|
|
|
|
}
|