mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
More more more more more more more more more more more more more more more more more work
This commit is contained in:
parent
8c6927e39d
commit
a39e11bdf3
12 changed files with 875 additions and 84 deletions
|
@ -18,8 +18,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+import java.util.Map;
|
+import java.util.Map;
|
||||||
+import java.util.WeakHashMap;
|
+import java.util.WeakHashMap;
|
||||||
+import java.util.jar.Manifest;
|
+import java.util.jar.Manifest;
|
||||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
+
|
||||||
+import org.jetbrains.annotations.ApiStatus;
|
+import org.jetbrains.annotations.ApiStatus;
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+import org.jetbrains.annotations.Nullable;
|
||||||
+
|
+
|
||||||
+@ApiStatus.Internal
|
+@ApiStatus.Internal
|
||||||
+public final class JarManifests {
|
+public final class JarManifests {
|
||||||
|
@ -28,7 +30,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+
|
+
|
||||||
+ private static final Map<ClassLoader, Manifest> MANIFESTS = Collections.synchronizedMap(new WeakHashMap<>());
|
+ private static final Map<ClassLoader, Manifest> MANIFESTS = Collections.synchronizedMap(new WeakHashMap<>());
|
||||||
+
|
+
|
||||||
+ public static Manifest manifest(final ClassLoader loader) {
|
+ public static @NotNull Manifest manifest(final @NotNull ClassLoader loader) {
|
||||||
+ return MANIFESTS.computeIfAbsent(loader, classLoader -> {
|
+ return MANIFESTS.computeIfAbsent(loader, classLoader -> {
|
||||||
+ final @Nullable InputStream stream = classLoader.getResourceAsStream("META-INF/MANIFEST.MF");
|
+ final @Nullable InputStream stream = classLoader.getResourceAsStream("META-INF/MANIFEST.MF");
|
||||||
+ if (stream == null) {
|
+ if (stream == null) {
|
||||||
|
|
|
@ -29,8 +29,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
||||||
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
|
||||||
|
|
||||||
|
public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
||||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||||
+ public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event
|
+ public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event
|
||||||
|
|
||||||
|
|
|
@ -28,39 +28,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
|
|
||||||
public static DamageSource sting(LivingEntity attacker) {
|
public static DamageSource sting(LivingEntity attacker) {
|
||||||
return new EntityDamageSource("sting", attacker);
|
return new EntityDamageSource("sting", attacker);
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
|
|
||||||
return this.hasEffect(MobEffects.JUMP) ? (double) (0.1F * (float) (this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ protected long lastJumpTime = 0L; // Paper - add critical damage API
|
|
||||||
protected void jumpFromGround() {
|
|
||||||
double d0 = (double) this.getJumpPower() + this.getJumpBoostPower();
|
|
||||||
Vec3 vec3d = this.getDeltaMovement();
|
|
||||||
+ // Paper start - add critical damage API
|
|
||||||
+ long time = System.nanoTime();
|
|
||||||
+ boolean canCrit = true;
|
|
||||||
+ if (this instanceof net.minecraft.world.entity.player.Player) {
|
|
||||||
+ canCrit = false;
|
|
||||||
+ if (time - this.lastJumpTime > (long)(0.250e9)) {
|
|
||||||
+ this.lastJumpTime = time;
|
|
||||||
+ canCrit = true;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end - add critical damage API
|
|
||||||
|
|
||||||
this.setDeltaMovement(vec3d.x, d0, vec3d.z);
|
|
||||||
if (this.isSprinting()) {
|
|
||||||
float f = this.getYRot() * 0.017453292F;
|
|
||||||
|
|
||||||
- this.setDeltaMovement(this.getDeltaMovement().add((double) (-Mth.sin(f) * 0.2F), 0.0D, (double) (Mth.cos(f) * 0.2F)));
|
|
||||||
+ if (canCrit) this.setDeltaMovement(this.getDeltaMovement().add((double) (-Mth.sin(f) * 0.2F), 0.0D, (double) (Mth.cos(f) * 0.2F))); // Paper - add critical damage API
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hasImpulse = true;
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
|
|
@ -8,9 +8,9 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
@@ -0,0 +0,0 @@ import net.minecraft.network.syncher.SynchedEntityData;
|
@@ -0,0 +0,0 @@ import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MCUtil;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
+import net.minecraft.server.level.ServerChunkCache;
|
+import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
|
|
@ -21,6 +21,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
this.lastGoodX = this.awaitingPositionFromClient.x;
|
this.lastGoodX = this.awaitingPositionFromClient.x;
|
||||||
this.lastGoodY = this.awaitingPositionFromClient.y;
|
this.lastGoodY = this.awaitingPositionFromClient.y;
|
||||||
this.lastGoodZ = this.awaitingPositionFromClient.z;
|
this.lastGoodZ = this.awaitingPositionFromClient.z;
|
||||||
|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
this.awaitingTeleportTime = this.tickCount;
|
||||||
|
- this.player.absMoveTo(d0, d1, d2, f, f1);
|
||||||
|
+ this.player.moveTo(d0, d1, d2, f, f1); // Paper - use proper setPositionRotation for teleportation
|
||||||
|
this.player.connection.send(new ClientboundPlayerPositionPacket(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag));
|
||||||
|
}
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
|
|
@ -15,9 +15,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
||||||
|
return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this));
|
||||||
}
|
}
|
||||||
// Paper end
|
// Paper end - optimise entity tracking
|
||||||
|
|
||||||
+ // Paper start - make end portalling safe
|
+ // Paper start - make end portalling safe
|
||||||
+ public BlockPos portalBlock;
|
+ public BlockPos portalBlock;
|
||||||
+ public ServerLevel portalWorld;
|
+ public ServerLevel portalWorld;
|
||||||
|
@ -48,10 +48,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ this.teleportTo(worldserver, null);
|
+ this.teleportTo(worldserver, null);
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - make end portalling safe
|
+ // Paper end - make end portalling safe
|
||||||
+
|
|
||||||
public Entity(EntityType<?> type, Level world) {
|
public Entity(EntityType<?> type, Level world) {
|
||||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||||
this.passengers = ImmutableList.of();
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -542,7 +542,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||||
public boolean runAllUpdates(ChunkMap chunkStorage) {
|
public boolean runAllUpdates(ChunkMap chunkStorage) {
|
||||||
this.naturalSpawnChunkCounter.runAllUpdates();
|
//this.f.a(); // Paper - no longer used
|
||||||
this.tickingTicketsTracker.runAllUpdates();
|
this.tickingTicketsTracker.runAllUpdates();
|
||||||
+ org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper
|
+ org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper
|
||||||
this.playerTicketManager.runAllUpdates();
|
this.playerTicketManager.runAllUpdates();
|
||||||
|
@ -1127,19 +1127,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Comparator<T> comparator;
|
private final Comparator<T> comparator;
|
||||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
this.awaitingTeleportTime = this.tickCount;
|
|
||||||
- this.player.absMoveTo(d0, d1, d2, f, f1);
|
|
||||||
+ this.player.moveTo(d0, d1, d2, f, f1); // Paper - use proper setPositionRotation for teleportation
|
|
||||||
this.player.connection.send(new ClientboundPlayerPositionPacket(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||||
|
|
|
@ -13,9 +13,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||||
this.setTicketLevel(level);
|
long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos);
|
||||||
this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()];
|
this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
|
||||||
this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper
|
this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
|
||||||
+ // Paper start - optimise checkDespawn
|
+ // Paper start - optimise checkDespawn
|
||||||
+ LevelChunk chunk = this.getFullChunkUnchecked();
|
+ LevelChunk chunk = this.getFullChunkUnchecked();
|
||||||
+ if (chunk != null) {
|
+ if (chunk != null) {
|
||||||
|
@ -23,53 +23,57 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - optimise checkDespawn
|
+ // Paper end - optimise checkDespawn
|
||||||
}
|
}
|
||||||
|
// Paper end - optimise isOutsideOfRange
|
||||||
|
|
||||||
// CraftBukkit start
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper
|
int viewDistance;
|
||||||
// Paper start - distance maps
|
public final com.destroystokyo.paper.util.PlayerMobDistanceMap playerMobDistanceMap; // Paper
|
||||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
|
||||||
+ // Paper start - optimise checkDespawn
|
+ // Paper start - optimise checkDespawn
|
||||||
+ public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40;
|
+ public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40;
|
||||||
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1);
|
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1);
|
||||||
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE;
|
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE;
|
||||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap;
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap;
|
||||||
+ // Paper end - optimise checkDespawn
|
+ // Paper end - optimise checkDespawn
|
||||||
|
+
|
||||||
void addPlayerToDistanceMaps(ServerPlayer player) {
|
// CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback()
|
||||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
public final CallbackExecutor callbackExecutor = new CallbackExecutor();
|
||||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
|
||||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
+ // Paper start - optimise checkDespawn
|
this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
||||||
+ this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS);
|
this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
||||||
+ // Paper end - optimise checkDespawn
|
// Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
||||||
}
|
}
|
||||||
|
|
||||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
+ // Paper start - optimise checkDespawn
|
this.playerMobSpawnMap.remove(player);
|
||||||
+ this.playerGeneralAreaMap.remove(player);
|
this.playerChunkTickRangeMap.remove(player);
|
||||||
+ // Paper end - optimise checkDespawn
|
// Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ this.playerGeneralAreaMap.remove(player); // Paper - optimise checkDespawns
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMaps(ServerPlayer player) {
|
void updateMaps(ServerPlayer player) {
|
||||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
|
||||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
|
||||||
+ // Paper start - optimise checkDespawn
|
}
|
||||||
+ this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS);
|
- // Paper end - use distance map to optimise entity tracker
|
||||||
+ // Paper end - optimise checkDespawn
|
+ // Paper end - use distance map to optimise entity trackerD
|
||||||
|
this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
||||||
}
|
}
|
||||||
// Paper end
|
// Paper end
|
||||||
// Paper start
|
// Paper start
|
||||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
this.regionManagers.add(this.dataRegionManager);
|
}
|
||||||
// Paper end
|
});
|
||||||
this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper
|
// Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
+ // Paper start - optimise checkDespawn
|
+ // Paper start - optimise checkDespawn
|
||||||
+ this.playerGeneralAreaMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
+ this.playerGeneralAreaMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Thu, 16 Apr 2020 16:13:59 -0700
|
||||||
|
Subject: [PATCH] Optimize ServerLevels chunk level checking methods
|
||||||
|
|
||||||
|
These can be hot functions (i.e entity ticking and block ticking),
|
||||||
|
so inline where possible, and avoid the abstraction of the
|
||||||
|
Either class.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) {
|
||||||
|
- return this.areEntitiesLoaded(chunkPos) && this.chunkSource.isPositionTicking(chunkPos);
|
||||||
|
+ // Paper start - optimize is ticking ready type functions
|
||||||
|
+ ChunkHolder chunkHolder = this.chunkSource.chunkMap.getVisibleChunkIfPresent(chunkPos);
|
||||||
|
+ return chunkHolder != null && chunkHolder.isTickingReady() && this.areEntitiesLoaded(chunkPos);
|
||||||
|
+ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPositionEntityTicking(BlockPos pos) {
|
||||||
|
- return this.entityManager.isPositionTicking(pos);
|
||||||
|
+ return this.entityManager.isPositionTicking(ChunkPos.asLong(pos)); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPositionEntityTicking(ChunkPos pos) {
|
||||||
|
- return this.entityManager.isPositionTicking(pos);
|
||||||
|
+ return this.entityManager.isPositionTicking(pos.toLong()); // Paper
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class EntityCallbacks implements LevelCallback<Entity> {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/ChunkPos.java b/src/main/java/net/minecraft/world/level/ChunkPos.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/ChunkPos.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/ChunkPos.java
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkPos {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long asLong(BlockPos pos) {
|
||||||
|
- return asLong(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
|
||||||
|
+ return (((long)pos.getX() >> 4) & 4294967295L) | ((((long)pos.getZ() >> 4) & 4294967295L) << 32); // Paper - inline
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getX(long pos) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||||
|
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||||
|
public LevelEntityGetter<T> getEntityGetter() {
|
||||||
|
return this.entityGetter;
|
||||||
|
}
|
||||||
|
+ // Paper start
|
||||||
|
+ public final boolean isPositionTicking(long position) {
|
||||||
|
+ return this.chunkVisibility.get(position).isTicking();
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
public boolean isPositionTicking(BlockPos pos) {
|
||||||
|
return ((Visibility) this.chunkVisibility.get(ChunkPos.asLong(pos))).isTicking();
|
|
@ -0,0 +1,318 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Tue, 5 May 2020 20:40:53 -0700
|
||||||
|
Subject: [PATCH] Optimize isOutsideRange to use distance maps
|
||||||
|
|
||||||
|
Use a distance map to find the players in range quickly
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||||
|
boolean isUpdateQueued = false; // Paper
|
||||||
|
private final ChunkMap chunkMap; // Paper
|
||||||
|
|
||||||
|
+ // Paper start - optimise isOutsideOfRange
|
||||||
|
+ // cached here to avoid a map lookup
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange;
|
||||||
|
+
|
||||||
|
+ void updateRanges() {
|
||||||
|
+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos);
|
||||||
|
+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
|
||||||
|
+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
|
||||||
|
+ }
|
||||||
|
+ // Paper end - optimise isOutsideOfRange
|
||||||
|
+
|
||||||
|
public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
|
||||||
|
this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
|
||||||
|
this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||||
|
this.setTicketLevel(level);
|
||||||
|
this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()];
|
||||||
|
this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper
|
||||||
|
+ this.updateRanges(); // Paper - optimise isOutsideOfRange
|
||||||
|
}
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper
|
||||||
|
// Paper start - distance maps
|
||||||
|
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||||
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ // A note about the naming used here:
|
||||||
|
+ // Previously, mojang used a "spawn range" of 8 for controlling both ticking and
|
||||||
|
+ // mob spawn range. However, spigot makes the spawn range configurable by
|
||||||
|
+ // checking if the chunk is in the tick range (8) and the spawn range
|
||||||
|
+ // obviously this means a spawn range > 8 cannot be implemented
|
||||||
|
+
|
||||||
|
+ // these maps are named after spigot's uses
|
||||||
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
|
||||||
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
|
||||||
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
|
||||||
|
void addPlayerToDistanceMaps(ServerPlayer player) {
|
||||||
|
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||||
|
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||||
|
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||||
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
||||||
|
+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
||||||
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
}
|
||||||
|
|
||||||
|
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||||
|
-
|
||||||
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ this.playerMobSpawnMap.remove(player);
|
||||||
|
+ this.playerChunkTickRangeMap.remove(player);
|
||||||
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMaps(ServerPlayer player) {
|
||||||
|
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||||
|
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||||
|
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||||
|
+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
// Paper start
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
this.regionManagers.add(this.dataRegionManager);
|
||||||
|
// Paper end
|
||||||
|
this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper
|
||||||
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||||
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||||
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||||
|
+ if (playerChunk != null) {
|
||||||
|
+ playerChunk.playersInChunkTickRange = newState;
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||||
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||||
|
+ if (playerChunk != null) {
|
||||||
|
+ playerChunk.playersInChunkTickRange = newState;
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||||
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||||
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||||
|
+ if (playerChunk != null) {
|
||||||
|
+ playerChunk.playersInMobSpawnRange = newState;
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||||
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
||||||
|
+ if (playerChunk != null) {
|
||||||
|
+ playerChunk.playersInMobSpawnRange = newState;
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ChunkGenerator generator() {
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
} else {
|
||||||
|
if (holder != null) {
|
||||||
|
holder.setTicketLevel(level);
|
||||||
|
+ holder.updateRanges(); // Paper - optimise isOutsideOfRange
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holder != null) {
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
return this.anyPlayerCloseEnoughForSpawning(pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
- boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
|
||||||
|
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||||
|
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||||
|
- chunkRange = (chunkRange > 8) ? 8 : chunkRange;
|
||||||
|
-
|
||||||
|
- final int finalChunkRange = chunkRange; // Paper for lambda below
|
||||||
|
- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
|
||||||
|
- double blockRange = 16384.0D; // Paper
|
||||||
|
- // Spigot end
|
||||||
|
- long i = chunkcoordintpair.toLong();
|
||||||
|
+ // Paper start - optimise isOutsideOfRange
|
||||||
|
+ final boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
|
||||||
|
+ return this.anyPlayerCloseEnoughForSpawning(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- if (!this.distanceManager.hasPlayersNearby(i)) {
|
||||||
|
+ final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) {
|
||||||
|
+ // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance
|
||||||
|
+ // tested and confirmed via System.nanoTime()
|
||||||
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
|
||||||
|
+ if (playersInRange == null) {
|
||||||
|
return false;
|
||||||
|
- } else {
|
||||||
|
- Iterator iterator = this.playerMap.getPlayers(i).iterator();
|
||||||
|
-
|
||||||
|
- ServerPlayer entityplayer;
|
||||||
|
+ }
|
||||||
|
+ Object[] backingSet = playersInRange.getBackingSet();
|
||||||
|
|
||||||
|
- do {
|
||||||
|
- if (!iterator.hasNext()) {
|
||||||
|
- return false;
|
||||||
|
+ if (reducedRange) {
|
||||||
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||||
|
+ Object raw = backingSet[i];
|
||||||
|
+ if (!(raw instanceof ServerPlayer player)) {
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- entityplayer = (ServerPlayer) iterator.next();
|
||||||
|
- // Paper start - add PlayerNaturallySpawnCreaturesEvent
|
||||||
|
- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
|
||||||
|
- blockRange = 16384.0D;
|
||||||
|
- if (reducedRange) {
|
||||||
|
- event = entityplayer.playerNaturallySpawnedEvent;
|
||||||
|
- if (event == null || event.isCancelled()) return false;
|
||||||
|
- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
|
||||||
|
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
||||||
|
+ if (this.playerIsCloseEnoughForSpawning(player, chunkcoordintpair, player.lastEntitySpawnRadiusSquared)) {
|
||||||
|
+ return true; // in range
|
||||||
|
}
|
||||||
|
- // Paper end
|
||||||
|
- } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot
|
||||||
|
-
|
||||||
|
- return true;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.MOB_SPAWN_RANGE * 16);
|
||||||
|
+ // before spigot, mob spawn range was actually mob spawn range + tick range, but it was split
|
||||||
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||||
|
+ Object raw = backingSet[i];
|
||||||
|
+ if (!(raw instanceof ServerPlayer player)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
||||||
|
+ if (this.playerIsCloseEnoughForSpawning(player, chunkcoordintpair, range)) {
|
||||||
|
+ return true; // in range
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
+ // no players in range
|
||||||
|
+ return false;
|
||||||
|
+ // Paper end - optimise isOutsideOfRange
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos pos) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||||
|
final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
|
||||||
|
public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
|
||||||
|
private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker();
|
||||||
|
- private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
|
||||||
|
+ public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
|
||||||
|
private final TickingTracker tickingTicketsTracker = new TickingTracker();
|
||||||
|
private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33);
|
||||||
|
// Paper start use a queue, but still keep unique requirement
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||||
|
protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k);
|
||||||
|
|
||||||
|
public boolean runAllUpdates(ChunkMap chunkStorage) {
|
||||||
|
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||||
|
+ //this.f.a(); // Paper - no longer used
|
||||||
|
this.tickingTicketsTracker.runAllUpdates();
|
||||||
|
this.playerTicketManager.runAllUpdates();
|
||||||
|
int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE);
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||||
|
((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> {
|
||||||
|
return new ObjectOpenHashSet();
|
||||||
|
})).add(player);
|
||||||
|
- this.naturalSpawnChunkCounter.update(i, 0, true);
|
||||||
|
+ //this.f.update(i, 0, true); // Paper - no longer used
|
||||||
|
this.playerTicketManager.update(i, 0, true);
|
||||||
|
this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair);
|
||||||
|
}
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||||
|
if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully.
|
||||||
|
if (objectset == null || objectset.isEmpty()) { // Paper
|
||||||
|
this.playersPerChunk.remove(i);
|
||||||
|
- this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
||||||
|
+ //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
||||||
|
this.playerTicketManager.update(i, Integer.MAX_VALUE, false);
|
||||||
|
this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair);
|
||||||
|
}
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNaturalSpawnChunkCount() {
|
||||||
|
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||||
|
- return this.naturalSpawnChunkCounter.chunks.size();
|
||||||
|
+ // Paper start - use distance map to implement
|
||||||
|
+ // note: this is the spawn chunk count
|
||||||
|
+ return this.chunkMap.playerChunkTickRangeMap.size();
|
||||||
|
+ // Paper end - use distance map to implement
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPlayersNearby(long chunkPos) {
|
||||||
|
- this.naturalSpawnChunkCounter.runAllUpdates();
|
||||||
|
- return this.naturalSpawnChunkCounter.chunks.containsKey(chunkPos);
|
||||||
|
+ // Paper start - use distance map to implement
|
||||||
|
+ // note: this is the is spawn chunk method
|
||||||
|
+ return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(chunkPos) != null;
|
||||||
|
+ // Paper end - use distance map to implement
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDebugStatus() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
|
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||||
|
|
||||||
|
//Collections.shuffle(list); // Paper - no... just no...
|
||||||
|
- // Paper start - call player naturally spawn event
|
||||||
|
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||||
|
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||||
|
- chunkRange = Math.min(chunkRange, 8);
|
||||||
|
- for (ServerPlayer entityPlayer : this.level.players()) {
|
||||||
|
- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
|
||||||
|
- entityPlayer.playerNaturallySpawnedEvent.callEvent();
|
||||||
|
- };
|
||||||
|
- // Paper end
|
||||||
|
+ // Paper - moved natural spawn event up
|
||||||
|
Iterator iterator1 = list.iterator();
|
||||||
|
|
||||||
|
while (iterator1.hasNext()) {
|
||||||
|
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
|
LevelChunk chunk1 = chunkproviderserver_a.chunk;
|
||||||
|
ChunkPos chunkcoordintpair = chunk1.getPos();
|
||||||
|
|
||||||
|
- if (this.level.isPositionEntityTicking(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) {
|
||||||
|
+ if (this.level.isPositionEntityTicking(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange
|
||||||
|
chunk1.incrementInhabitedTime(j);
|
||||||
|
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && !this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot
|
||||||
|
+ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && !this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise isOutsideOfRange
|
||||||
|
NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
||||||
|
// CraftBukkit end
|
||||||
|
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
||||||
|
|
||||||
|
+ public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
||||||
|
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||||
|
|
||||||
|
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) {
|
|
@ -0,0 +1,38 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||||
|
Date: Thu, 25 Nov 2021 10:25:09 +0100
|
||||||
|
Subject: [PATCH] Prevent excessive velocity through repeated crits
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
|
||||||
|
return this.hasEffect(MobEffects.JUMP) ? (double) (0.1F * (float) (this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ protected long lastJumpTime = 0L; // Paper
|
||||||
|
protected void jumpFromGround() {
|
||||||
|
double d0 = (double) this.getJumpPower() + this.getJumpBoostPower();
|
||||||
|
Vec3 vec3d = this.getDeltaMovement();
|
||||||
|
+ // Paper start
|
||||||
|
+ long time = System.nanoTime();
|
||||||
|
+ boolean canCrit = true;
|
||||||
|
+ if (this instanceof net.minecraft.world.entity.player.Player) {
|
||||||
|
+ canCrit = false;
|
||||||
|
+ if (time - this.lastJumpTime > (long)(0.250e9)) {
|
||||||
|
+ this.lastJumpTime = time;
|
||||||
|
+ canCrit = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
this.setDeltaMovement(vec3d.x, d0, vec3d.z);
|
||||||
|
if (this.isSprinting()) {
|
||||||
|
float f = this.getYRot() * 0.017453292F;
|
||||||
|
|
||||||
|
+ if (canCrit) // Paper
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().add((double) (-Mth.sin(f) * 0.2F), 0.0D, (double) (Mth.cos(f) * 0.2F)));
|
||||||
|
}
|
||||||
|
|
403
patches/server/Use-distance-map-to-optimise-entity-tracker.patch
Normal file
403
patches/server/Use-distance-map-to-optimise-entity-tracker.patch
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -0,0 +0,0 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
|
||||||
|
import net.minecraft.network.protocol.game.DebugPackets;
|
||||||
|
import net.minecraft.server.MCUtil;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
|
import net.minecraft.server.network.ServerPlayerConnection;
|
||||||
|
import net.minecraft.util.CsvOutput;
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
|
||||||
|
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
|
||||||
|
// Paper end - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
+ // 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 MinecraftServer.getServer().getScaledTrackingDistance(vanilla);
|
||||||
|
+ }
|
||||||
|
+ // Paper end - use distance map to optimise tracker
|
||||||
|
|
||||||
|
void addPlayerToDistanceMaps(ServerPlayer player) {
|
||||||
|
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||||
|
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||||
|
+ // 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
|
||||||
|
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||||
|
// Paper start - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
void removePlayerFromDistanceMaps(ServerPlayer 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
|
||||||
|
// Paper start - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
this.playerMobSpawnMap.remove(player);
|
||||||
|
this.playerChunkTickRangeMap.remove(player);
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||||
|
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||||
|
// 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
|
||||||
|
this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
this.regionManagers.add(this.dataRegionManager);
|
||||||
|
// Paper end
|
||||||
|
this.playerMobDistanceMap = this.level.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.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;
|
||||||
|
+ 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 - optimise PlayerChunkMap#isOutsideRange
|
||||||
|
this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||||
|
(ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||||
|
@@ -0,0 +0,0 @@ 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
|
||||||
|
|
||||||
|
int i = SectionPos.blockToSectionCoord(player.getBlockX());
|
||||||
|
int j = SectionPos.blockToSectionCoord(player.getBlockZ());
|
||||||
|
@@ -0,0 +0,0 @@ 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;
|
||||||
|
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
entity.tracker = null; // Paper - We're no longer tracked
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // 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();
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos());
|
||||||
|
List<Entity> list = Lists.newArrayList();
|
||||||
|
List<Entity> list1 = Lists.newArrayList();
|
||||||
|
- ObjectIterator objectiterator = this.entityMap.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 == player) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ ChunkMap.TrackedEntity tracker = this.entityMap.get(entity.getId());
|
||||||
|
+ if (tracker != null) { // dumb plugins... move on...
|
||||||
|
+ tracker.updatePlayer(player);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- while (objectiterator.hasNext()) {
|
||||||
|
- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
|
||||||
|
- Entity entity = playerchunkmap_entitytracker.entity;
|
||||||
|
+ // 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 != player && entity.chunkPosition().equals(chunk.getPos())) {
|
||||||
|
- playerchunkmap_entitytracker.updatePlayer(player);
|
||||||
|
- if (entity instanceof Mob && ((Mob) entity).getLeashHolder() != null) {
|
||||||
|
- list.add(entity);
|
||||||
|
- }
|
||||||
|
+ if (entity instanceof Mob && ((Mob)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;
|
||||||
|
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
this.lastSectionPos = SectionPos.of(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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -0,0 +0,0 @@ import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
+import net.minecraft.server.MCUtil;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
+ // 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 Entity(EntityType<?> type, Level world) {
|
||||||
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||||
|
this.passengers = ImmutableList.of();
|
||||||
|
diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/TrackingRange.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/TrackingRange.java
|
||||||
|
@@ -0,0 +0,0 @@ import net.minecraft.world.entity.ExperienceOrb;
|
||||||
|
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||||
|
import net.minecraft.world.entity.decoration.Painting;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
|
+import net.minecraft.world.entity.monster.Ghast;
|
||||||
|
|
||||||
|
public class TrackingRange
|
||||||
|
{
|
||||||
|
@@ -0,0 +0,0 @@ public class TrackingRange
|
||||||
|
{
|
||||||
|
return defaultRange;
|
||||||
|
}
|
||||||
|
+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return defaultRange; // Paper - enderdragon is exempt
|
||||||
|
SpigotWorldConfig config = entity.level.spigotConfig;
|
||||||
|
if ( entity instanceof ServerPlayer )
|
||||||
|
{
|
||||||
|
@@ -0,0 +0,0 @@ public class TrackingRange
|
||||||
|
return config.miscTrackingRange;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
- if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return ((net.minecraft.server.level.ServerLevel)(entity.getCommandSenderWorld())).getChunkSource().chunkMap.getEffectiveViewDistance(); // 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 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
|
||||||
|
+ {
|
||||||
|
+ return TrackingRangeType.OTHER;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static enum TrackingRangeType {
|
||||||
|
+ PLAYER,
|
||||||
|
+ ANIMAL,
|
||||||
|
+ MONSTER,
|
||||||
|
+ MISC,
|
||||||
|
+ OTHER,
|
||||||
|
+ ENDERDRAGON;
|
||||||
|
+ }
|
||||||
|
+ // Paper end - optimise entity tracking
|
||||||
|
}
|
Loading…
Reference in a new issue