geforkt von Mirrors/Paper
ac554ad46d
Updated Upstream (Bukkit/CraftBukkit) Upstream has released updates that appear 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: fa99e752 PR-1007: Add ItemMeta#getAsComponentString() 94a91782 Fix copy-pasted BlockType.Typed documentation 9b34ac8c Largely restore deprecated PotionData API 51a6449b PR-1008: Deprecate ITEMS_TOOLS, removed in 1.20.5 702d15fe Fix Javadoc reference 42f6cdf4 PR-919: Add internal ItemType and BlockType, delegate Material methods to them 237bb37b SPIGOT-1166, SPIGOT-7647: Expose Damager BlockState in EntityDamageByBlockEvent 035ea146 SPIGOT-6993: Allow #setVelocity to change the speed of a fireball and add a note to #setDirection about it 8c7880fb PR-1004: Improve field rename handling and centralize conversion between bukkit and string more 87c90e93 SPIGOT-7650: Add DamageSource for EntityDeathEvent and PlayerDeathEvent CraftBukkit Changes: 4af0f22e8 SPIGOT-7664: Item meta should prevail over block states c2ccc46ec SPIGOT-7666: Fix access to llama and horse special slot 124ac66d7 SPIGOT-7665: Fix ThrownPotion#getEffects() implementation only bringing custom effects 66f1f439a Restore null page behaviour of signed books even though not strictly allowed by API 6118e5398 Fix regression listening to minecraft:brand custom payloads c1a26b366 Fix unnecessary and potential not thread-safe chat visibility check 12360a7ec Remove unused imports 147b098b4 PR-1397: Add ItemMeta#getAsComponentString() 428aefe0e Largely restore deprecated PotionData API afe5b5ee9 PR-1275: Add internal ItemType and BlockType, delegate Material methods to them 8afeafa7d SPIGOT-1166, SPIGOT-7647: Expose Damager BlockState in EntityDamageByBlockEvent 4e7d749d4 SPIGOT-6993: Allow #setVelocity to change the speed of a fireball and add a note to #setDirection about it 441880757 Support both entity_data and bucket_entity_data on axolotl/fish buckets 0e22fdd1e Fix custom direct BlockState being not correctly set in DamageSource f2182ed47 SPIGOT-7659: TropicalFishBucketMeta should use BUCKET_ENTITY_DATA 2a6207fe1 PR-1393: Improve field rename handling and centralize conversion between bukkit and string more c024a5039 SPIGOT-7650: Add DamageSource for EntityDeathEvent and PlayerDeathEvent 741b84480 PR-1390: Improve internal handling of damage sources 0364df4e1 SPIGOT-7657: Error when loading angry entities
342 Zeilen
17 KiB
Diff
342 Zeilen
17 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/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 4621c33ed73b0db64e78e7b9be7013a2ba7393c8..48f7997e8a20f5a5a77516cbde990d0aacc2078a 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -149,6 +149,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
// Paper start - distance maps
|
|
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> 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();
|
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap[] playerEntityTrackerTrackMaps;
|
|
+ final int[] entityTrackerTrackRanges;
|
|
+ public final int getEntityTrackerRange(final int ordinal) {
|
|
+ return this.entityTrackerTrackRanges[ordinal];
|
|
+ }
|
|
+
|
|
+ private int convertSpigotRangeToVanilla(final int vanilla) {
|
|
+ return net.minecraft.server.MinecraftServer.getServer().getScaledTrackingDistance(vanilla);
|
|
+ }
|
|
+ // Paper end - use distance map to optimise tracker
|
|
|
|
void addPlayerToDistanceMaps(ServerPlayer player) {
|
|
int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
|
|
@@ -156,6 +173,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Note: players need to be explicitly added to distance maps before they can be updated
|
|
this.nearbyPlayers.addPlayer(player);
|
|
this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader
|
|
+ // 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, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player)));
|
|
+ }
|
|
+ // Paper end - use distance map to optimise entity tracker
|
|
}
|
|
|
|
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
|
@@ -164,6 +189,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Note: players need to be explicitly added to distance maps before they can be updated
|
|
this.nearbyPlayers.removePlayer(player);
|
|
this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader
|
|
+ // 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(ServerPlayer player) {
|
|
@@ -172,6 +202,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Note: players need to be explicitly added to distance maps before they can be updated
|
|
this.nearbyPlayers.tickPlayer(player);
|
|
this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader
|
|
+ // 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, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player)));
|
|
+ }
|
|
+ // Paper end - use distance map to optimise entity tracker
|
|
}
|
|
// Paper end
|
|
// Paper start
|
|
@@ -258,6 +296,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.regionManagers.add(this.dataRegionManager);
|
|
this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level);
|
|
// Paper end
|
|
+ // 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.level.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 = EntityType.ENDER_DRAGON.clientTrackingRange() * 16;
|
|
+ break;
|
|
+ case DISPLAY:
|
|
+ configuredSpigotValue = spigotWorldConfig.displayTrackingRange;
|
|
+ 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
|
|
}
|
|
|
|
// Paper start
|
|
@@ -951,17 +1031,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
|
|
public void move(ServerPlayer player) {
|
|
- ObjectIterator objectiterator = this.entityMap.values().iterator();
|
|
-
|
|
- while (objectiterator.hasNext()) {
|
|
- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
|
|
-
|
|
- if (playerchunkmap_entitytracker.entity == player) {
|
|
- playerchunkmap_entitytracker.updatePlayers(this.level.players());
|
|
- } else {
|
|
- playerchunkmap_entitytracker.updatePlayer(player);
|
|
- }
|
|
- }
|
|
+ // Paper - delay this logic for the entity tracker tick, no need to duplicate it
|
|
|
|
SectionPos sectionposition = player.getLastSectionPos();
|
|
SectionPos sectionposition1 = SectionPos.of((EntityAccess) player);
|
|
@@ -1038,7 +1108,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
|
|
this.entityMap.put(entity.getId(), playerchunkmap_entitytracker);
|
|
- playerchunkmap_entitytracker.updatePlayers(this.level.players());
|
|
+ playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players
|
|
if (entity instanceof ServerPlayer) {
|
|
ServerPlayer entityplayer = (ServerPlayer) entity;
|
|
|
|
@@ -1080,9 +1150,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
entity.tracker = null; // Paper - We're no longer tracked
|
|
}
|
|
|
|
- protected void tick() {
|
|
- // Paper - replaced by PlayerChunkLoader
|
|
+ // Paper start - optimised tracker
|
|
+ private final void processTrackQueue() {
|
|
+ this.level.timings.tracker1.startTiming();
|
|
+ try {
|
|
+ for (TrackedEntity tracker : this.entityMap.values()) {
|
|
+ // update tracker entry
|
|
+ tracker.updatePlayers(tracker.entity.getPlayersInTrackRange());
|
|
+ }
|
|
+ } finally {
|
|
+ this.level.timings.tracker1.stopTiming();
|
|
+ }
|
|
+
|
|
+
|
|
+ this.level.timings.tracker2.startTiming();
|
|
+ try {
|
|
+ for (TrackedEntity tracker : this.entityMap.values()) {
|
|
+ tracker.serverEntity.sendChanges();
|
|
+ }
|
|
+ } finally {
|
|
+ this.level.timings.tracker2.stopTiming();
|
|
+ }
|
|
+ }
|
|
+ // Paper end - optimised tracker
|
|
|
|
+ protected void tick() {
|
|
+ // Paper start - optimized tracker
|
|
+ if (true) {
|
|
+ this.processTrackQueue();
|
|
+ return;
|
|
+ }
|
|
+ // Paper end - optimized tracker
|
|
List<ServerPlayer> list = Lists.newArrayList();
|
|
List<ServerPlayer> list1 = this.level.players();
|
|
ObjectIterator objectiterator = this.entityMap.values().iterator();
|
|
@@ -1230,6 +1328,42 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.lastSectionPos = SectionPos.of((EntityAccess) entity);
|
|
}
|
|
|
|
+ // 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) {
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> 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 ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ ServerPlayer player = (ServerPlayer)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 (ServerPlayerConnection conn : this.seenBy.toArray(new ServerPlayerConnection[0])) { // avoid CME
|
|
+ if (newTrackerCandidates == null || !newTrackerCandidates.contains(conn.getPlayer())) {
|
|
+ this.updatePlayer(conn.getPlayer());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end - use distance map to optimise tracker
|
|
+
|
|
public boolean equals(Object object) {
|
|
return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
index b57644317b5085d74d11ac6ba858c3747d703a47..257943b4c984d6faee29eca17c8f951e7f43168b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
@@ -59,6 +59,7 @@ import net.minecraft.network.syncher.SyncedDataHolder;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
+import io.papermc.paper.util.MCUtil;
|
|
import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
@@ -471,6 +472,38 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
this.teleportTo(worldserver, null);
|
|
}
|
|
// Paper end - make end portalling safe
|
|
+ // Paper start - optimise entity tracking
|
|
+ final org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = org.spigotmc.TrackingRange.getTrackingRangeType(this);
|
|
+
|
|
+ public boolean isLegacyTrackingEntity = false;
|
|
+
|
|
+ public final void setLegacyTrackingEntity(final boolean isLegacyTrackingEntity) {
|
|
+ this.isLegacyTrackingEntity = isLegacyTrackingEntity;
|
|
+ }
|
|
+
|
|
+ public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> getPlayersInTrackRange() {
|
|
+ // determine highest range of passengers
|
|
+ if (this.passengers.isEmpty()) {
|
|
+ return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()]
|
|
+ .getObjectsInRange(MCUtil.getCoordinateKey(this));
|
|
+ }
|
|
+ Iterable<Entity> passengers = this.getIndirectPassengers();
|
|
+ net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap;
|
|
+ org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType;
|
|
+ int range = chunkMap.getEntityTrackerRange(type.ordinal());
|
|
+
|
|
+ for (Entity passenger : passengers) {
|
|
+ org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType;
|
|
+ int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal());
|
|
+ if (passengerRange > range) {
|
|
+ type = passengerType;
|
|
+ range = passengerRange;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this));
|
|
+ }
|
|
+ // Paper end - optimise entity tracking
|
|
public float getBukkitYaw() {
|
|
return this.yRot;
|
|
}
|
|
diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
|
|
index bb06f89a29f30144e7e2113e088a503db006a83c..e4425b242fe73d1fd2bd10c313aa16925432329f 100644
|
|
--- a/src/main/java/org/spigotmc/TrackingRange.java
|
|
+++ b/src/main/java/org/spigotmc/TrackingRange.java
|
|
@@ -55,4 +55,48 @@ 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 net.minecraft.world.entity.boss.enderdragon.EnderDragon) return TrackingRangeType.ENDERDRAGON; // Paper - enderdragon is exempt
|
|
+ if ( entity instanceof ServerPlayer )
|
|
+ {
|
|
+ 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 ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
|
|
+ // Paper end
|
|
+ {
|
|
+ return TrackingRangeType.MISC;
|
|
+ } else if (entity instanceof Display) {
|
|
+ return TrackingRangeType.DISPLAY;
|
|
+ } else
|
|
+ {
|
|
+ return TrackingRangeType.OTHER;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static enum TrackingRangeType {
|
|
+ PLAYER,
|
|
+ ANIMAL,
|
|
+ MONSTER,
|
|
+ MISC,
|
|
+ OTHER,
|
|
+ ENDERDRAGON,
|
|
+ DISPLAY;
|
|
+ }
|
|
+ // Paper end - optimise entity tracking
|
|
}
|