3
0
Mirror von https://github.com/PaperMC/Paper.git synchronisiert 2024-12-15 11:00:06 +01:00
Paper/Spigot-Server-Patches/0502-Use-distance-map-to-optimise-entity-tracker.patch
Aikar 4ae089597b
Fix collision checks on spawning hanging entities and null on async chunk loads
getCubes will now always load chunks
getChunk with gen false will now not throw error

Fixes #3368
Fixes #3364
2020-05-14 05:05:13 -04:00

367 Zeilen
18 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 5 May 2020 20:18:05 -0700
Subject: [PATCH] Use distance map to optimise entity tracker
Use the distance map to find candidate players for tracking.
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 6dea557fa32fd44674bf01e2f7429c9691c315b8..c005734f835fd07b121fdb885d981e55f8be81b4 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -245,6 +245,21 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
}
// Paper end
+ // Paper start - optimise entity tracking
+ final org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = org.spigotmc.TrackingRange.getTrackingRangeType(this);
+
+ boolean isLegacyTrackingEntity = false;
+
+ public final void setLegacyTrackingEntity(final boolean isLegacyTrackingEntity) {
+ this.isLegacyTrackingEntity = isLegacyTrackingEntity;
+ }
+
+ final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> getPlayersInTrackRange() {
+ return ((WorldServer)this.world).getChunkProvider().playerChunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()]
+ .getObjectsInRange(MCUtil.getCoordinateKey(this));
+ }
+ // Paper end - optimise entity tracking
+
public Entity(EntityTypes<?> entitytypes, World world) {
this.id = Entity.entityCount.incrementAndGet();
this.passengers = Lists.newArrayList();
diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
index 3a88c9a67062eb73ad8257ea786efca7e7e99f65..6d3b34ead9cc95dcc1152dffa8c6c4a8c7f1d58b 100644
--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java
+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
@@ -70,6 +70,7 @@ public class EntityTrackerEntry {
this.r = entity.onGround;
}
+ public final void tick() { this.a(); } // Paper - OBFHELPER
public void a() {
List<Entity> list = this.tracker.getPassengers();
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index bdf835397aa691c41280f65a7785e777791b2891..3d31f00a22233bd885496d7aac34eb2b634c40e8 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -120,21 +120,51 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
// Paper start - distance maps
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<EntityPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
+ // Paper start - use distance map to optimise tracker
+ public static boolean isLegacyTrackingEntity(Entity entity) {
+ return entity.isLegacyTrackingEntity;
+ }
+
+ // inlined EnumMap, TrackingRange.TrackingRangeType
+ static final org.spigotmc.TrackingRange.TrackingRangeType[] TRACKING_RANGE_TYPES = org.spigotmc.TrackingRange.TrackingRangeType.values();
+ final com.destroystokyo.paper.util.misc.PlayerAreaMap[] playerEntityTrackerTrackMaps;
+ final int[] entityTrackerTrackRanges;
+ // Paper end - use distance map to optimise tracker
void addPlayerToDistanceMaps(EntityPlayer player) {
int chunkX = MCUtil.getChunkCoordinate(player.locX());
int chunkZ = MCUtil.getChunkCoordinate(player.locZ());
// Note: players need to be explicitly added to distance maps before they can be updated
+ // Paper start - use distance map to optimise entity tracker
+ for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
+ com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i];
+ int trackRange = this.entityTrackerTrackRanges[i];
+
+ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
+ }
+ // Paper end - use distance map to optimise entity tracker
}
void removePlayerFromDistanceMaps(EntityPlayer player) {
-
+ // Paper start - use distance map to optimise tracker
+ for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
+ this.playerEntityTrackerTrackMaps[i].remove(player);
+ }
+ // Paper end - use distance map to optimise tracker
}
void updateMaps(EntityPlayer player) {
int chunkX = MCUtil.getChunkCoordinate(player.locX());
int chunkZ = MCUtil.getChunkCoordinate(player.locZ());
// Note: players need to be explicitly added to distance maps before they can be updated
+ // Paper start - use distance map to optimise entity tracker
+ for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
+ com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i];
+ int trackRange = this.entityTrackerTrackRanges[i];
+
+ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
+ }
+ // Paper end - use distance map to optimise entity tracker
}
@@ -172,6 +202,44 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
this.m = new VillagePlace(new File(this.w, "poi"), datafixer, this.world); // Paper
this.setViewDistance(i);
this.playerMobDistanceMap = this.world.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper
+ // Paper start - use distance map to optimise entity tracker
+ this.playerEntityTrackerTrackMaps = new com.destroystokyo.paper.util.misc.PlayerAreaMap[TRACKING_RANGE_TYPES.length];
+ this.entityTrackerTrackRanges = new int[TRACKING_RANGE_TYPES.length];
+
+ org.spigotmc.SpigotWorldConfig spigotWorldConfig = this.world.spigotConfig;
+
+ for (int ordinal = 0, len = TRACKING_RANGE_TYPES.length; ordinal < len; ++ordinal) {
+ org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = TRACKING_RANGE_TYPES[ordinal];
+ int configuredSpigotValue;
+ switch (trackingRangeType) {
+ case PLAYER:
+ configuredSpigotValue = spigotWorldConfig.playerTrackingRange;
+ break;
+ case ANIMAL:
+ configuredSpigotValue = spigotWorldConfig.animalTrackingRange;
+ break;
+ case MONSTER:
+ configuredSpigotValue = spigotWorldConfig.monsterTrackingRange;
+ break;
+ case MISC:
+ configuredSpigotValue = spigotWorldConfig.miscTrackingRange;
+ break;
+ case OTHER:
+ configuredSpigotValue = spigotWorldConfig.otherTrackingRange;
+ break;
+ case ENDERDRAGON:
+ configuredSpigotValue = 10 * 16; // default is 10 chunk range // TODO check on update
+ break;
+ default:
+ throw new IllegalStateException("Missing case for enum " + trackingRangeType);
+ }
+
+ 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);
+ }
+ // Paper end - use distance map to optimise entity tracker
}
public void updatePlayerMobTypeMap(Entity entity) {
@@ -1423,17 +1491,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}
public void movePlayer(EntityPlayer entityplayer) {
- ObjectIterator objectiterator = this.trackedEntities.values().iterator();
-
- while (objectiterator.hasNext()) {
- PlayerChunkMap.EntityTracker playerchunkmap_entitytracker = (PlayerChunkMap.EntityTracker) objectiterator.next();
-
- if (playerchunkmap_entitytracker.tracker == entityplayer) {
- playerchunkmap_entitytracker.track(this.world.getPlayers());
- } else {
- playerchunkmap_entitytracker.updatePlayer(entityplayer);
- }
- }
+ // Paper - delay this logic for the entity tracker tick, no need to duplicate it
int i = MathHelper.floor(entityplayer.locX()) >> 4;
int j = MathHelper.floor(entityplayer.locZ()) >> 4;
@@ -1550,7 +1608,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
this.trackedEntities.put(entity.getId(), playerchunkmap_entitytracker);
- playerchunkmap_entitytracker.track(this.world.getPlayers());
+ playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players
if (entity instanceof EntityPlayer) {
EntityPlayer entityplayer = (EntityPlayer) entity;
@@ -1594,7 +1652,37 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
entity.tracker = null; // Paper - We're no longer tracked
}
+ // Paper start - optimised tracker
+ private final void processTrackQueue() {
+ this.world.timings.tracker1.startTiming();
+ try {
+ for (EntityTracker tracker : this.trackedEntities.values()) {
+ // update tracker entry
+ tracker.updatePlayers(tracker.tracker.getPlayersInTrackRange());
+ }
+ } finally {
+ this.world.timings.tracker1.stopTiming();
+ }
+
+
+ this.world.timings.tracker2.startTiming();
+ try {
+ for (EntityTracker tracker : this.trackedEntities.values()) {
+ tracker.trackerEntry.tick();
+ }
+ } finally {
+ this.world.timings.tracker2.stopTiming();
+ }
+ }
+ // Paper end - optimised tracker
+
protected void g() {
+ // Paper start - optimized tracker
+ if (true) {
+ this.processTrackQueue();
+ return;
+ }
+ // Paper end - optimized tracker
List<EntityPlayer> list = Lists.newArrayList();
List<EntityPlayer> list1 = this.world.getPlayers();
@@ -1662,23 +1750,31 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
PacketDebug.a(this.world, chunk.getPos());
List<Entity> list = Lists.newArrayList();
List<Entity> list1 = Lists.newArrayList();
- ObjectIterator objectiterator = this.trackedEntities.values().iterator();
+ // Paper start - optimise entity tracker
+ // use the chunk entity list, not the whole trackedEntities map...
+ Entity[] entities = chunk.entities.getRawData();
+ for (int i = 0, size = chunk.entities.size(); i < size; ++i) {
+ Entity entity = entities[i];
+ if (entity == entityplayer) {
+ continue;
+ }
+ PlayerChunkMap.EntityTracker tracker = this.trackedEntities.get(entity.getId());
+ if (tracker != null) { // dumb plugins... move on...
+ tracker.updatePlayer(entityplayer);
+ }
- while (objectiterator.hasNext()) {
- PlayerChunkMap.EntityTracker playerchunkmap_entitytracker = (PlayerChunkMap.EntityTracker) objectiterator.next();
- Entity entity = playerchunkmap_entitytracker.tracker;
+ // keep the vanilla logic here - this is REQUIRED or else passengers and their vehicles disappear!
+ // (and god knows what the leash thing is)
- if (entity != entityplayer && entity.chunkX == chunk.getPos().x && entity.chunkZ == chunk.getPos().z) {
- playerchunkmap_entitytracker.updatePlayer(entityplayer);
- if (entity instanceof EntityInsentient && ((EntityInsentient) entity).getLeashHolder() != null) {
- list.add(entity);
- }
+ if (entity instanceof EntityInsentient && ((EntityInsentient)entity).getLeashHolder() != null) {
+ list.add(entity);
+ }
- if (!entity.getPassengers().isEmpty()) {
- list1.add(entity);
- }
+ if (!entity.getPassengers().isEmpty()) {
+ list1.add(entity);
}
}
+ // Paper end - optimise entity tracker
Iterator iterator;
Entity entity1;
@@ -1716,7 +1812,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
public class EntityTracker {
- private final EntityTrackerEntry trackerEntry;
+ final EntityTrackerEntry trackerEntry; // Paper - private -> package private
private final Entity tracker;
private final int trackingDistance;
private SectionPosition e;
@@ -1733,6 +1829,42 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
this.e = SectionPosition.a(entity);
}
+ // 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) {
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> oldTrackerCandidates = this.lastTrackerCandidates;
+ this.lastTrackerCandidates = newTrackerCandidates;
+
+ if (newTrackerCandidates != null) {
+ Object[] rawData = newTrackerCandidates.getBackingSet();
+ for (int i = 0, len = rawData.length; i < len; ++i) {
+ Object raw = rawData[i];
+ if (!(raw instanceof EntityPlayer)) {
+ continue;
+ }
+ EntityPlayer player = (EntityPlayer)raw;
+ this.updatePlayer(player);
+ }
+ }
+
+ if (oldTrackerCandidates == newTrackerCandidates) {
+ // this is likely the case.
+ // means there has been no range changes, so we can just use the above for tracking.
+ return;
+ }
+
+ // stuff could have been removed, so we need to check the trackedPlayers set
+ // for players that were removed
+
+ for (EntityPlayer player : this.trackedPlayers.toArray(new EntityPlayer[0])) { // avoid CME
+ if (newTrackerCandidates == null || !newTrackerCandidates.contains(player)) {
+ this.updatePlayer(player);
+ }
+ }
+ }
+ // Paper end - use distance map to optimise tracker
+
public boolean equals(Object object) {
return object instanceof PlayerChunkMap.EntityTracker ? ((PlayerChunkMap.EntityTracker) object).tracker.getId() == this.tracker.getId() : false;
}
@@ -1829,7 +1961,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
int j = entity.getEntityType().getChunkRange() * 16;
j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper
- if (j > i) {
+ if (j < i) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic
i = j;
}
}
diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
index 765bdaf9b525a989ec8d37a2fe856dcfcbd06782..43b5ed8e396e5312f7de1f160f596f58baead28a 100644
--- a/src/main/java/org/spigotmc/TrackingRange.java
+++ b/src/main/java/org/spigotmc/TrackingRange.java
@@ -49,4 +49,43 @@ public class TrackingRange
return config.otherTrackingRange;
}
}
+
+ // Paper start - optimise entity tracking
+ // copied from above, TODO check on update
+ public static TrackingRangeType getTrackingRangeType(Entity entity)
+ {
+ if ( entity instanceof EntityPlayer )
+ {
+ return TrackingRangeType.PLAYER;
+ // Paper start - Simplify and set water mobs to animal tracking range
+ }
+ switch (entity.activationType) {
+ case RAIDER:
+ case MONSTER:
+ return TrackingRangeType.MONSTER;
+ case WATER:
+ case ANIMAL:
+ return TrackingRangeType.ANIMAL;
+ case MISC:
+ }
+ if ( entity instanceof EntityItemFrame || entity instanceof EntityPainting || entity instanceof EntityItem || entity instanceof EntityExperienceOrb )
+ // Paper end
+ {
+ return TrackingRangeType.MISC;
+ } else
+ {
+ if (entity instanceof EntityEnderDragon) return TrackingRangeType.ENDERDRAGON; // Paper - enderdragon is exempt
+ return TrackingRangeType.OTHER;
+ }
+ }
+
+ public static enum TrackingRangeType {
+ PLAYER,
+ ANIMAL,
+ MONSTER,
+ MISC,
+ OTHER,
+ ENDERDRAGON;
+ }
+ // Paper end - optimise entity tracking
}