mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-27 04:55:47 +01:00
ab347c4c96
Upstream has released updates that appears to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 42d5a714 SPIGOT-5899: Hoglins API similar to Piglins 2c1ee10e SPIGOT-5887: ClickType doesn't include off hand swaps 5ff7c7ce SPIGOT-5886: Missing BlockData CraftBukkit Changes:7560f5f5
SPIGOT-5905: Fix hex colours not being allowed in MOTDd47c47ee
SPIGOT-5889: Villager using composter should call EntityChangeBlockEvent2fe6b4a3
SPIGOT-5899: Hoglins API similar to Piglinse09dbeca
SPIGOT-5887: ClickType doesn't include off hand swaps23aac2a5
SPIGOT-5903: EntityDismountEvent cannot be triggered asynchronously92cbf656
SPIGOT-5884: Tab completions lost on reloadData / minecraft:reloadfb4e54ad
SPIGOT-5902: PlayerRespawnEvent places player at spawn before event is calledaa8f3d5a
SPIGOT-5901: Structures are generated in all worlds based on the setting for the main worlda0c35937
SPIGOT-5895: PlayerChangedWorldEvent#getFrom is incorrect89c0a5c3
SPIGOT-5886: Missing BlockData Spigot Changes: 0287a20d SPIGOT-5903: EntityDismountEvent cannot be triggered asynchronously
391 lines
19 KiB
Diff
391 lines
19 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 449a687399f38d3ef79685ff80531cf1212f054a..3bbacebc3397f2c1d695f64bf3f4eb2b89b112b6 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 9b89c0c8a3f1dada4e9b2aaeed0b92e56229b7ca..0c46297e6ff229538d77b2f481e4ab13ea14c48e 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
|
|
@@ -72,6 +72,7 @@ public class EntityTrackerEntry {
|
|
this.r = entity.isOnGround();
|
|
}
|
|
|
|
+ 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/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index d9ed9df3021dab1f5ee0a51215a002253ac1e34c..b32d41fac5f855e302469209f368c3674b849fe3 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -1526,6 +1526,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
}
|
|
}
|
|
|
|
+ public final int applyTrackingRangeScale(int value) { return this.b(value); } // Paper - OBFHELPER
|
|
public int b(int i) {
|
|
return i;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
index 850602a32d371bd030665732b762b4bcbd49e25e..a7be3f6d2a11c1e1b310f0fcdbe2e485a2113c59 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
@@ -145,21 +145,55 @@ 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;
|
|
+
|
|
+ private int convertSpigotRangeToVanilla(final int vanilla) {
|
|
+ return MinecraftServer.getServer().applyTrackingRangeScale(vanilla);
|
|
+ }
|
|
+ // 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
|
|
}
|
|
// Paper end
|
|
|
|
@@ -196,6 +230,45 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
this.m = new VillagePlace(new File(this.w, "poi"), datafixer, flag, 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);
|
|
+ }
|
|
+ configuredSpigotValue = convertSpigotRangeToVanilla(configuredSpigotValue);
|
|
+
|
|
+ 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) {
|
|
@@ -1432,17 +1505,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;
|
|
@@ -1558,7 +1621,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;
|
|
|
|
@@ -1601,7 +1664,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();
|
|
|
|
@@ -1669,23 +1762,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;
|
|
@@ -1723,7 +1824,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;
|
|
@@ -1740,6 +1841,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;
|
|
}
|
|
@@ -1840,7 +1977,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 03990231a8b6bc6925f054e9033825316abfafcc..627e9a90b3045602bc540a5f3f031aaf3716c942 100644
|
|
--- a/src/main/java/org/spigotmc/TrackingRange.java
|
|
+++ b/src/main/java/org/spigotmc/TrackingRange.java
|
|
@@ -46,8 +46,49 @@ public class TrackingRange
|
|
return config.miscTrackingRange;
|
|
} else
|
|
{
|
|
- if (entity instanceof EntityEnderDragon) return ((WorldServer)(entity.getWorld())).getChunkProvider().playerChunkMap.getLoadViewDistance(); // Paper - enderdragon is exempt
|
|
+ if (entity instanceof EntityEnderDragon) return defaultRange; // Paper - enderdragon is exempt
|
|
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:
|
|
+ case FLYING_MONSTER:
|
|
+ return TrackingRangeType.MONSTER;
|
|
+ case WATER:
|
|
+ case VILLAGER:
|
|
+ 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
|
|
}
|