mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-28 03:19:21 +00:00
optimize entity despawn (#409)
* Reapply "optimize despawn (#399)"
This reverts commit 7992f91631.
* log FMA and Vector API
* axis order XYZ to XZY
* cleanup
* fix pivot at offset + median not included & fix simd min mask
This commit is contained in:
@@ -5,48 +5,125 @@ Subject: [PATCH] optimize mob despawn
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index 97408ce24313ff26347ff434ab6460e9971c3598..af190cb959478cde3fa9011df85032dbab60ce56 100644
|
index 7fb763e89e43698bfb2b9fcf6296705384e8624a..91752678f887559132921cff61697478e5f44e3d 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -797,6 +797,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -797,13 +797,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
}
|
}
|
||||||
|
|
||||||
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
||||||
+
|
+
|
||||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizeDespawn.enabled) despawnMap.prepare(this); // Leaf - optimize despawn
|
+ if (org.dreeam.leaf.config.modules.opt.OptimizeDespawn.enabled && tickRateManager.runsNormally()) { despawnMap.tick(this, this.entityTickList); } // Leaf - optimize despawn
|
||||||
this.entityTickList
|
this.entityTickList
|
||||||
.forEach(
|
.forEach(
|
||||||
entity -> {
|
entity -> {
|
||||||
@@ -832,6 +834,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
entity.activatedPriorityReset = false; // Pufferfish - DAB
|
||||||
}
|
if (!entity.isRemoved()) {
|
||||||
}
|
if (!tickRateManager.isEntityFrozen(entity)) {
|
||||||
);
|
- entity.checkDespawn();
|
||||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizeDespawn.enabled) despawnMap.reset(); // Leaf - optimize despawn
|
+ // Leaf start - optimize despawn
|
||||||
this.tickBlockEntities();
|
+ if (!org.dreeam.leaf.config.modules.opt.OptimizeDespawn.enabled) {
|
||||||
}
|
+ entity.checkDespawn();
|
||||||
// Paper - rewrite chunk system
|
+ }
|
||||||
@@ -945,6 +948,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
+ // Leaf end - optimize despawn
|
||||||
|
if (true) { // Paper - rewrite chunk system
|
||||||
|
Entity vehicle = entity.getVehicle();
|
||||||
|
if (vehicle != null) {
|
||||||
|
@@ -945,6 +951,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
|
||||||
private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking
|
private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking
|
||||||
|
|
||||||
+ public final org.dreeam.leaf.world.DespawnMap despawnMap = new org.dreeam.leaf.world.DespawnMap(); // Leaf - optimize despawn
|
+ public final org.dreeam.leaf.world.DespawnMap despawnMap = new org.dreeam.leaf.world.DespawnMap(paperConfig()); // Leaf - optimize despawn
|
||||||
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||||
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
|
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
|
||||||
ChunkPos pos = chunk.getPos();
|
ChunkPos pos = chunk.getPos();
|
||||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||||
index 867353500482247bbec79f407246902c79a3d14a..173ec6919cef2aa90c40d3bf33d927a2db7b4922 100644
|
index 129248da7e1bfa5edc1c1a43c98a400f697e735f..b17dca64375039bea3dc3f26b5965865a0a9200a 100644
|
||||||
--- a/net/minecraft/world/entity/Mob.java
|
--- a/net/minecraft/world/entity/Entity.java
|
||||||
+++ b/net/minecraft/world/entity/Mob.java
|
+++ b/net/minecraft/world/entity/Entity.java
|
||||||
@@ -722,6 +722,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
@@ -5132,6 +5132,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||||
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
public void checkDespawn() {
|
||||||
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
}
|
||||||
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
|
|
||||||
+ // Leaf start - optimize despawn
|
+ // Leaf start - optimize despawn
|
||||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizeDespawn.enabled) {
|
+ public void leafCheckDespawn() {
|
||||||
+ ((ServerLevel) level()).despawnMap.checkDespawn(this);
|
|
||||||
+ return;
|
|
||||||
+ }
|
+ }
|
||||||
+ // Leaf end - optimize despawn
|
+ // Leaf end - optimize despawn
|
||||||
Entity nearestPlayer = this.level().findNearbyPlayer(this, -1.0, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API
|
+
|
||||||
if (nearestPlayer != null) {
|
public Vec3[] getQuadLeashHolderOffsets() {
|
||||||
// Paper start - Configurable despawn distances
|
return Leashable.createQuadLeashOffsets(this, 0.0, 0.5, 0.5, 0.0);
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||||
|
index 867353500482247bbec79f407246902c79a3d14a..7caf9ea3792089dcf890c2af0ac17ee1d5c85c16 100644
|
||||||
|
--- a/net/minecraft/world/entity/Mob.java
|
||||||
|
+++ b/net/minecraft/world/entity/Mob.java
|
||||||
|
@@ -751,6 +751,22 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Leaf start - optimize despawn
|
||||||
|
+ @Override
|
||||||
|
+ public void leafCheckDespawn() {
|
||||||
|
+ if (isRemoved()) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
||||||
|
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||||
|
+ } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
|
||||||
|
+ ((ServerLevel) level()).despawnMap.checkDespawn(this);
|
||||||
|
+ } else {
|
||||||
|
+ this.noActionTime = 0;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Leaf end - optimize despawn
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
protected final void serverAiStep() {
|
||||||
|
this.noActionTime++;
|
||||||
|
diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java
|
||||||
|
index 0613d80561f50e32dc4d1c471521f001659d017d..021c609b689e5a08e60c54f360c4c5dbb9de987f 100644
|
||||||
|
--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java
|
||||||
|
+++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java
|
||||||
|
@@ -695,6 +695,21 @@ public class WitherBoss extends Monster implements RangedAttackMob {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+
|
||||||
|
+ // Leaf start - optimize despawn
|
||||||
|
+ @Override
|
||||||
|
+ public void leafCheckDespawn() {
|
||||||
|
+ if (isRemoved()) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
||||||
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||||
|
+ } else {
|
||||||
|
+ this.noActionTime = 0;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Leaf end - optimize despawn
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity) {
|
||||||
|
return false;
|
||||||
|
diff --git a/net/minecraft/world/entity/projectile/ShulkerBullet.java b/net/minecraft/world/entity/projectile/ShulkerBullet.java
|
||||||
|
index 00154ba80175bcb07b3378f19514fec1700c94e9..46d30c3273d31dbda06275ad098c6c2b9b2eed14 100644
|
||||||
|
--- a/net/minecraft/world/entity/projectile/ShulkerBullet.java
|
||||||
|
+++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java
|
||||||
|
@@ -197,6 +197,16 @@ public class ShulkerBullet extends Projectile {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+
|
||||||
|
+ // Leaf start - optimize despawn
|
||||||
|
+ @Override
|
||||||
|
+ public void leafCheckDespawn() {
|
||||||
|
+ if (!isRemoved() && this.level().getDifficulty() == Difficulty.PEACEFUL) {
|
||||||
|
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Leaf end - optimize despawn
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
protected double getDefaultGravity() {
|
||||||
|
return 0.04;
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ index 8f41326fda8c5f9f6926038508be6c6529b051bc..46e171ca454253c32e22c0c18587e9a7
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index af190cb959478cde3fa9011df85032dbab60ce56..bc9cf4aa9b1e71e03100a10c45ef9fc23ee5ae9f 100644
|
index 5b7b05ab3224e3dbc0957589e8d9bb20cd2e0158..c181fc4f895d0ea1e7b61919cc5e6fe90d6a62ae 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -180,7 +180,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -180,7 +180,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
@@ -610,7 +610,7 @@ index af190cb959478cde3fa9011df85032dbab60ce56..bc9cf4aa9b1e71e03100a10c45ef9fc2
|
|||||||
int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
|
int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
|
||||||
if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { // Purpur - Config for skipping night
|
if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { // Purpur - Config for skipping night
|
||||||
// Paper start - create time skip event - move up calculations
|
// Paper start - create time skip event - move up calculations
|
||||||
@@ -1308,9 +1441,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1311,9 +1444,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
fluidState.tick(this, pos, blockState);
|
fluidState.tick(this, pos, blockState);
|
||||||
}
|
}
|
||||||
// Paper start - rewrite chunk system
|
// Paper start - rewrite chunk system
|
||||||
@@ -625,7 +625,7 @@ index af190cb959478cde3fa9011df85032dbab60ce56..bc9cf4aa9b1e71e03100a10c45ef9fc2
|
|||||||
// Paper end - rewrite chunk system
|
// Paper end - rewrite chunk system
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1321,9 +1457,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1324,9 +1460,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
blockState.tick(this, pos, this.random);
|
blockState.tick(this, pos, this.random);
|
||||||
}
|
}
|
||||||
// Paper start - rewrite chunk system
|
// Paper start - rewrite chunk system
|
||||||
@@ -640,7 +640,7 @@ index af190cb959478cde3fa9011df85032dbab60ce56..bc9cf4aa9b1e71e03100a10c45ef9fc2
|
|||||||
// Paper end - rewrite chunk system
|
// Paper end - rewrite chunk system
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1588,6 +1727,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1591,6 +1730,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPlayer(ServerPlayer player) {
|
private void addPlayer(ServerPlayer player) {
|
||||||
@@ -649,7 +649,7 @@ index af190cb959478cde3fa9011df85032dbab60ce56..bc9cf4aa9b1e71e03100a10c45ef9fc2
|
|||||||
Entity entity = this.getEntity(player.getUUID());
|
Entity entity = this.getEntity(player.getUUID());
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
|
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
|
||||||
@@ -1600,7 +1741,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1603,7 +1744,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
|
||||||
// CraftBukkit start
|
// CraftBukkit start
|
||||||
private boolean addEntity(Entity entity, @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
private boolean addEntity(Entity entity, @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
||||||
@@ -719,7 +719,7 @@ index 567187499c29fbd159b472278665a824dbb1cfd6..4b359856e2981cfb52f43bab8c088e0e
|
|||||||
// Paper end - Inventory close reason
|
// Paper end - Inventory close reason
|
||||||
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
||||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||||
index 9dbc73b7d5406c7e82b8f1dd2d60d144d24d5220..283115b85ba910f7b155354dd536146bb57e378e 100644
|
index ff3798fd384679fd8324d4d47e71095024209fe2..8b72f2612c6968c4602a4cb72f3d1160d9679e36 100644
|
||||||
--- a/net/minecraft/server/players/PlayerList.java
|
--- a/net/minecraft/server/players/PlayerList.java
|
||||||
+++ b/net/minecraft/server/players/PlayerList.java
|
+++ b/net/minecraft/server/players/PlayerList.java
|
||||||
@@ -251,6 +251,8 @@ public abstract class PlayerList {
|
@@ -251,6 +251,8 @@ public abstract class PlayerList {
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ Leaf: ~48ms (-36%)
|
|||||||
This should help drastically on the farms that use actively changing fluids.
|
This should help drastically on the farms that use actively changing fluids.
|
||||||
|
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index bbe2a420193d15874a4dd384ddb3e24ee2d62420..2ded2c36adc079b9bd3ab4857fb4043f92f52378 100644
|
index f20d7591e473a37a0f5b97c60c2eb9974980b41e..4df5bf806b84d03b2aed13fcf6ab2c00a6698d86 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -1440,6 +1440,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1443,6 +1443,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
this.emptyTime = 0;
|
this.emptyTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ Subject: [PATCH] Micro optimizations for random tick
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index 2ded2c36adc079b9bd3ab4857fb4043f92f52378..65f6cd4508c41f14930f768575fe26dc80c9a2fa 100644
|
index 4df5bf806b84d03b2aed13fcf6ab2c00a6698d86..ab509260d536dfb5cb0268c20abf445498602fff 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -1038,7 +1038,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1041,7 +1041,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
// Paper start - optimise random ticking
|
// Paper start - optimise random ticking
|
||||||
private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) {
|
private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) {
|
||||||
final LevelChunkSection[] sections = chunk.getSections();
|
final LevelChunkSection[] sections = chunk.getSections();
|
||||||
@@ -17,7 +17,7 @@ index 2ded2c36adc079b9bd3ab4857fb4043f92f52378..65f6cd4508c41f14930f768575fe26dc
|
|||||||
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Leaf - Faster random generator - upcasting
|
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Leaf - Faster random generator - upcasting
|
||||||
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
|
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
|
||||||
|
|
||||||
@@ -1047,41 +1047,41 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1050,41 +1050,41 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
final int offsetZ = cpos.z << 4;
|
final int offsetZ = cpos.z << 4;
|
||||||
|
|
||||||
for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) {
|
for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ index 9b8d119116b0c3a51d3fe2ff7efb33cc39627cc4..436e73086678e4afbf94f1b7bca9b0c7
|
|||||||
|
|
||||||
// Gale start - Pufferfish - SIMD support
|
// Gale start - Pufferfish - SIMD support
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index 68bba7703ffcbeb1bf18d7dfdba9dbb21fe9d4b5..cc88326fc1017605c65b32a7a124cc8734281a86 100644
|
index ab509260d536dfb5cb0268c20abf445498602fff..da0ce01e3359686c7360367c3af9c79ad8e51aa4 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -175,7 +175,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -175,7 +175,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
@@ -195,7 +195,7 @@ index 6d9d8f85bf6936eee76c3d790dd676aa309a1d46..b19d2066b921d27f03b2c0af06fbf76f
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||||
index 173ec6919cef2aa90c40d3bf33d927a2db7b4922..e99fd3cd5ca6863facd189bf9cd4a3d5c102424a 100644
|
index 7caf9ea3792089dcf890c2af0ac17ee1d5c85c16..3882bc7a8d1684b91876eb7c6799949071e72626 100644
|
||||||
--- a/net/minecraft/world/entity/Mob.java
|
--- a/net/minecraft/world/entity/Mob.java
|
||||||
+++ b/net/minecraft/world/entity/Mob.java
|
+++ b/net/minecraft/world/entity/Mob.java
|
||||||
@@ -138,6 +138,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
@@ -138,6 +138,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||||
@@ -223,7 +223,7 @@ index 173ec6919cef2aa90c40d3bf33d927a2db7b4922..e99fd3cd5ca6863facd189bf9cd4a3d5
|
|||||||
}
|
}
|
||||||
// Paper end
|
// Paper end
|
||||||
|
|
||||||
@@ -782,6 +793,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
@@ -792,6 +803,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||||
if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||||
this.goalSelector.tick();
|
this.goalSelector.tick();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Generally faster than the non-async approach
|
|||||||
iterate over all entities, get their chunk, and increment the count
|
iterate over all entities, get their chunk, and increment the count
|
||||||
|
|
||||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||||
index 5913c41711e8226550aa65828380e31f295eddb2..ed8f53f4394d98f0b56bfb6d9e8b24d8636d55d2 100644
|
index 5c369b3d94e369c3f240821ad90b9d96223f24ca..9803c395fce103cb7bc746f43a017ff9ed99728c 100644
|
||||||
--- a/net/minecraft/server/level/ChunkMap.java
|
--- a/net/minecraft/server/level/ChunkMap.java
|
||||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||||
@@ -278,6 +278,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
@@ -278,6 +278,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
@@ -192,13 +192,13 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..43156ecde8bb86c77f3b13c17b3330ea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index ccb0913370e862e936f2a23289d4d49ce8773759..3621e23f98847801b230f181712d1686f1617918 100644
|
index eb5e1e67db2ee1bdbedfa244088fcb7a9356bae3..5e1f29af864df93856eabccde05a98f5acbdd505 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -1105,6 +1105,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1108,6 +1108,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking
|
private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking
|
||||||
|
|
||||||
public final org.dreeam.leaf.world.DespawnMap despawnMap = new org.dreeam.leaf.world.DespawnMap(); // Leaf - optimize despawn
|
public final org.dreeam.leaf.world.DespawnMap despawnMap = new org.dreeam.leaf.world.DespawnMap(paperConfig()); // Leaf - optimize despawn
|
||||||
+ public final org.dreeam.leaf.world.NatureSpawnChunkMap natureSpawnChunkMap = new org.dreeam.leaf.world.NatureSpawnChunkMap(); // Leaf - optimize mob spawning
|
+ public final org.dreeam.leaf.world.NatureSpawnChunkMap natureSpawnChunkMap = new org.dreeam.leaf.world.NatureSpawnChunkMap(); // Leaf - optimize mob spawning
|
||||||
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||||
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
|
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ index 43156ecde8bb86c77f3b13c17b3330eae95efcc3..ba0f66b5089e252e5d532cb4b94c6246
|
|||||||
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index 3621e23f98847801b230f181712d1686f1617918..23ff9783e6544af21c14aab7713f0255e4c04b1d 100644
|
index 5e1f29af864df93856eabccde05a98f5acbdd505..964c97a394122083a2f3c77b8ca529592c826080 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -1106,6 +1106,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1109,6 +1109,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
|
||||||
public final org.dreeam.leaf.world.DespawnMap despawnMap = new org.dreeam.leaf.world.DespawnMap(); // Leaf - optimize despawn
|
public final org.dreeam.leaf.world.DespawnMap despawnMap = new org.dreeam.leaf.world.DespawnMap(paperConfig()); // Leaf - optimize despawn
|
||||||
public final org.dreeam.leaf.world.NatureSpawnChunkMap natureSpawnChunkMap = new org.dreeam.leaf.world.NatureSpawnChunkMap(); // Leaf - optimize mob spawning
|
public final org.dreeam.leaf.world.NatureSpawnChunkMap natureSpawnChunkMap = new org.dreeam.leaf.world.NatureSpawnChunkMap(); // Leaf - optimize mob spawning
|
||||||
+ public final org.dreeam.leaf.world.RandomTickSystem randomTickSystem = new org.dreeam.leaf.world.RandomTickSystem(); // Leaf - optimize random tick
|
+ public final org.dreeam.leaf.world.RandomTickSystem randomTickSystem = new org.dreeam.leaf.world.RandomTickSystem(); // Leaf - optimize random tick
|
||||||
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||||
|
|||||||
@@ -100,10 +100,10 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194
|
|||||||
- // Paper end - detailed watchdog information
|
- // Paper end - detailed watchdog information
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
index 23ff9783e6544af21c14aab7713f0255e4c04b1d..5eb8ee3ef0273b58acbf31768e16fb707436aa12 100644
|
index 0709922df9b1dcef1010de725bf132d194e29aad..e39c3b7cea5de9a2e6d5e2256617c969d41a55c8 100644
|
||||||
--- a/net/minecraft/server/level/ServerLevel.java
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -1509,13 +1509,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1512,13 +1512,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
// Paper end - log detailed entity tick information
|
// Paper end - log detailed entity tick information
|
||||||
|
|
||||||
public void tickNonPassenger(Entity entity) {
|
public void tickNonPassenger(Entity entity) {
|
||||||
@@ -117,7 +117,7 @@ index 23ff9783e6544af21c14aab7713f0255e4c04b1d..5eb8ee3ef0273b58acbf31768e16fb70
|
|||||||
entity.setOldPosAndRot();
|
entity.setOldPosAndRot();
|
||||||
entity.tickCount++;
|
entity.tickCount++;
|
||||||
entity.totalEntityAge++; // Paper - age-like counter for all entities
|
entity.totalEntityAge++; // Paper - age-like counter for all entities
|
||||||
@@ -1528,13 +1522,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
@@ -1531,13 +1525,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
for (Entity entity1 : entity.getPassengers()) {
|
for (Entity entity1 : entity.getPassengers()) {
|
||||||
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,3 +17,18 @@ index ed687b0ab589fd2ddb8bf77f42ba42cf8b1c2ea7..5d075f51baeaf775a458f459b762bf62
|
|||||||
public DespawnRange.Shape despawnRangeShape = DespawnRange.Shape.ELLIPSOID;
|
public DespawnRange.Shape despawnRangeShape = DespawnRange.Shape.ELLIPSOID;
|
||||||
@MergeMap
|
@MergeMap
|
||||||
public Reference2IntMap<MobCategory> ticksPerSpawn = Util.make(new Reference2IntOpenHashMap<>(NaturalSpawner.SPAWNING_CATEGORIES.length), map -> Arrays.stream(NaturalSpawner.SPAWNING_CATEGORIES).forEach(mobCategory -> map.put(mobCategory, -1)));
|
public Reference2IntMap<MobCategory> ticksPerSpawn = Util.make(new Reference2IntOpenHashMap<>(NaturalSpawner.SPAWNING_CATEGORIES.length), map -> Arrays.stream(NaturalSpawner.SPAWNING_CATEGORIES).forEach(mobCategory -> map.put(mobCategory, -1)));
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/configuration/type/DespawnRange.java b/src/main/java/io/papermc/paper/configuration/type/DespawnRange.java
|
||||||
|
index 7779edcbbce36d7da177a92807dac73fbe24c9fa..093638ded4e35a33f34ef3d0e0fc2175efc5efaf 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/configuration/type/DespawnRange.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/configuration/type/DespawnRange.java
|
||||||
|
@@ -20,8 +20,8 @@ public final class DespawnRange {
|
||||||
|
|
||||||
|
public static final TypeSerializer<DespawnRange> SERIALIZER = new Serializer();
|
||||||
|
|
||||||
|
- private final IntOr.Default horizontalLimit;
|
||||||
|
- private final IntOr.Default verticalLimit;
|
||||||
|
+ public final IntOr.Default horizontalLimit; // Leaf - optimize despawn
|
||||||
|
+ public final IntOr.Default verticalLimit; // Leaf - optimize despawn
|
||||||
|
private final boolean wasDefinedViaLongSyntax;
|
||||||
|
|
||||||
|
// cached values
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.dreeam.leaf.config.modules.opt;
|
package org.dreeam.leaf.config.modules.opt;
|
||||||
|
|
||||||
|
import gg.pufferfish.pufferfish.simd.SIMDDetection;
|
||||||
|
import org.dreeam.leaf.LeafBootstrap;
|
||||||
import org.dreeam.leaf.config.ConfigModules;
|
import org.dreeam.leaf.config.ConfigModules;
|
||||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||||
import org.dreeam.leaf.config.annotations.Experimental;
|
import org.dreeam.leaf.config.annotations.Experimental;
|
||||||
@@ -15,5 +17,11 @@ public class OptimizeDespawn extends ConfigModules {
|
|||||||
@Override
|
@Override
|
||||||
public void onLoaded() {
|
public void onLoaded() {
|
||||||
enabled = config.getBoolean(getBasePath(), enabled);
|
enabled = config.getBoolean(getBasePath(), enabled);
|
||||||
|
if (enabled) {
|
||||||
|
gg.pufferfish.pufferfish.simd.SIMDDetection.initialize();
|
||||||
|
if (!LeafBootstrap.enableFMA || !SIMDDetection.isEnabled()) {
|
||||||
|
LOGGER.info("NOTE: Recommend enabling FMA and Vector API to work with optimize-mob-despawn.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +1,362 @@
|
|||||||
package org.dreeam.leaf.world;
|
package org.dreeam.leaf.world;
|
||||||
|
|
||||||
|
import gg.pufferfish.pufferfish.simd.SIMDDetection;
|
||||||
import io.papermc.paper.configuration.WorldConfiguration;
|
import io.papermc.paper.configuration.WorldConfiguration;
|
||||||
import io.papermc.paper.configuration.type.DespawnRange;
|
import it.unimi.dsi.fastutil.doubles.DoubleArrays;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrays;
|
import it.unimi.dsi.fastutil.longs.LongArrays;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntitySelector;
|
import net.minecraft.world.entity.EntitySelector;
|
||||||
import net.minecraft.world.entity.Mob;
|
import net.minecraft.world.entity.Mob;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.entity.EntityTickList;
|
||||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||||
|
import org.dreeam.leaf.LeafBootstrap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
public final class DespawnMap {
|
public final class DespawnMap {
|
||||||
private static final ServerPlayer[] EMPTY_PLAYER_ARRAY = {};
|
private static final ServerPlayer[] EMPTY_PLAYERS = {};
|
||||||
|
private static final double[] EMPTY_DOUBLES = {};
|
||||||
|
private static final long[] EMPTY_LONGS = {};
|
||||||
|
private static final int[] EMPTY_INTS = {};
|
||||||
|
static final boolean FMA = LeafBootstrap.enableFMA;
|
||||||
|
private static final boolean SIMD = SIMDDetection.isEnabled();
|
||||||
|
private static final int LEAF_THRESHOLD = SIMD ? DespawnVectorAPI.DOUBLE_VECTOR_LENGTH : 4;
|
||||||
|
private static final int INITIAL_CAP = 8;
|
||||||
|
private static final int INSERTION_SORT = 16;
|
||||||
|
static final long LEAF = -1L;
|
||||||
|
static final long AXIS_X = 0L;
|
||||||
|
static final long AXIS_Y = 1L;
|
||||||
|
static final long AXIS_Z = 2L;
|
||||||
|
static final long LEFT_MASK = 0xfffffffcL;
|
||||||
|
static final long RIGHT_MASK = 0x3fffffff00000000L;
|
||||||
|
static final long AXIS_MASK = 0b11L;
|
||||||
|
static final long SIGN_BIT = 0x8000_0000_0000_0000L;
|
||||||
|
|
||||||
private ServerPlayer[] players = EMPTY_PLAYER_ARRAY;
|
/// Stack for tree construction
|
||||||
private double[] pos = {};
|
private final Stack stack = new Stack(INITIAL_CAP);
|
||||||
|
/// Stack for tree traversal
|
||||||
|
private int[] search = EMPTY_INTS;
|
||||||
|
|
||||||
public void prepare(ServerLevel world) {
|
private int nodeLen = 0;
|
||||||
this.players = world.players().toArray(EMPTY_PLAYER_ARRAY);
|
private int bucketLen = 0;
|
||||||
|
|
||||||
List<ServerPlayer> playerList = world.players();
|
/// Node coordinate for each internal node
|
||||||
ServerPlayer[] list = new ServerPlayer[playerList.size()];
|
private double[] nsl = EMPTY_DOUBLES;
|
||||||
|
/// Offsets(32) Lengths(32) for each player list of leaf nodes
|
||||||
|
private long[] nbl = EMPTY_LONGS;
|
||||||
|
/// Left(30) Right(30) Axis(2) for each internal node
|
||||||
|
private long[] nll = EMPTY_LONGS;
|
||||||
|
/// Nested player X coordinates of leaf nodes
|
||||||
|
private double[] bxl = EMPTY_DOUBLES;
|
||||||
|
/// Nested player Y coordinates of leaf nodes
|
||||||
|
private double[] byl = EMPTY_DOUBLES;
|
||||||
|
/// Nested player Z coordinates of leaf nodes
|
||||||
|
private double[] bzl = EMPTY_DOUBLES;
|
||||||
|
|
||||||
|
private final double[] hard;
|
||||||
|
private final double[] sort;
|
||||||
|
|
||||||
|
public DespawnMap(WorldConfiguration worldConfiguration) {
|
||||||
|
MobCategory[] caps = MobCategory.values();
|
||||||
|
hard = new double[caps.length];
|
||||||
|
sort = new double[caps.length];
|
||||||
|
for (int i = 0; i < caps.length; i++) {
|
||||||
|
sort[i] = caps[i].getNoDespawnDistance();
|
||||||
|
hard[i] = caps[i].getDespawnDistance();
|
||||||
|
}
|
||||||
|
for (Map.Entry<MobCategory, WorldConfiguration.Entities.Spawning.DespawnRangePair> e : worldConfiguration.entities.spawning.despawnRanges.entrySet()) {
|
||||||
|
OptionalInt a = e.getValue().soft().verticalLimit.value();
|
||||||
|
OptionalInt b = e.getValue().soft().horizontalLimit.value();
|
||||||
|
OptionalInt c = e.getValue().hard().verticalLimit.value();
|
||||||
|
OptionalInt d = e.getValue().hard().horizontalLimit.value();
|
||||||
|
if (a.isPresent() && b.isPresent() && a.getAsInt() == b.getAsInt()) {
|
||||||
|
sort[e.getKey().ordinal()] = a.getAsInt();
|
||||||
|
}
|
||||||
|
if (c.isPresent() && d.isPresent() && c.getAsInt() == d.getAsInt()) {
|
||||||
|
hard[e.getKey().ordinal()] = c.getAsInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < caps.length; i++) {
|
||||||
|
if (sort[i] > 0.0) {
|
||||||
|
sort[i] = sort[i] * sort[i];
|
||||||
|
}
|
||||||
|
if (hard[i] > 0.0) {
|
||||||
|
hard[i] = hard[i] * hard[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void build(double[] coordX, double[] coordY, double[] coordZ) {
|
||||||
|
final double[][] map = {coordX, coordY, coordZ};
|
||||||
|
final int[] data = new int[coordX.length];
|
||||||
|
for (int i = 0; i < coordX.length; i++) {
|
||||||
|
data[i] = i;
|
||||||
|
}
|
||||||
|
stack.push(new Node(-1, false, 0, data.length, 0));
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
grow();
|
||||||
|
|
||||||
|
final Node n = stack.pop();
|
||||||
|
final int depth = n.depth;
|
||||||
|
final int offset = n.offset;
|
||||||
|
final int len = n.length;
|
||||||
|
final int curr = nodeLen++;
|
||||||
|
if (len <= LEAF_THRESHOLD) {
|
||||||
|
|
||||||
|
nll[curr] = LEAF;
|
||||||
|
nbl[curr] = (long) bucketLen << 32 | (long) len;
|
||||||
|
|
||||||
|
growBucket(len);
|
||||||
|
for (int i = offset, end = offset + len; i < end; i++) {
|
||||||
|
bxl[bucketLen] = coordX[data[i]];
|
||||||
|
byl[bucketLen] = coordY[data[i]];
|
||||||
|
bzl[bucketLen] = coordZ[data[i]];
|
||||||
|
bucketLen++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
final int axis = depth % 3 == 0 ? (int) AXIS_X : depth % 3 == 1 ? (int) AXIS_Z : (int) AXIS_Y;
|
||||||
|
final int median = (len - 1) / 2;
|
||||||
|
quickSelect(data, map[axis], offset, offset + len - 1, offset + median);
|
||||||
|
final int pivot = data[offset + median];
|
||||||
|
nsl[curr] = axis == AXIS_X ? coordX[pivot] : axis == AXIS_Y ? coordY[pivot] : coordZ[pivot];
|
||||||
|
nll[curr] = LEFT_MASK | RIGHT_MASK | (long) axis;
|
||||||
|
|
||||||
|
stack.push(new Node(curr, false, offset + median + 1, len - median - 1, depth + 1));
|
||||||
|
stack.push(new Node(curr, true, offset, median + 1, depth + 1));
|
||||||
|
}
|
||||||
|
if (n.parent >= 0) {
|
||||||
|
if (n.left) {
|
||||||
|
nll[n.parent] &= AXIS_MASK | RIGHT_MASK;
|
||||||
|
nll[n.parent] |= (long) curr << 2;
|
||||||
|
} else {
|
||||||
|
nll[n.parent] &= AXIS_MASK | LEFT_MASK;
|
||||||
|
nll[n.parent] |= (long) curr << 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertionSort(int[] indices, double[] coord, int left, int right) {
|
||||||
|
for (int i = left + 1; i <= right; i++) {
|
||||||
|
int key = indices[i];
|
||||||
|
double val = coord[key];
|
||||||
|
int j = i - 1;
|
||||||
|
|
||||||
|
while (j >= left && coord[indices[j]] > val) {
|
||||||
|
indices[j + 1] = indices[j];
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
indices[j + 1] = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void quickSelect(int[] indices, double[] coord, int left, int right, int k) {
|
||||||
|
while (left < right) {
|
||||||
|
if (right - left < INSERTION_SORT) {
|
||||||
|
insertionSort(indices, coord, left, right);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int mid = left + (right - left) / 2;
|
||||||
|
int a = indices[left], b = indices[mid], c = indices[right];
|
||||||
|
double va = coord[a], vb = coord[b], vc = coord[c];
|
||||||
|
int pivotIdx = (va < vb)
|
||||||
|
? (vb < vc ? mid : (va < vc ? right : left))
|
||||||
|
: (va < vc ? left : (vb < vc ? right : mid));
|
||||||
|
swap(indices, pivotIdx, left);
|
||||||
|
double pivot = coord[indices[left]];
|
||||||
|
|
||||||
|
int i = left;
|
||||||
|
int j = right + 1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while (++i <= right && coord[indices[i]] < pivot) ;
|
||||||
|
while (--j > left && coord[indices[j]] > pivot) ;
|
||||||
|
if (i >= j) break;
|
||||||
|
swap(indices, i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(indices, left, j);
|
||||||
|
int p = j;
|
||||||
|
if (p == k) {
|
||||||
|
return;
|
||||||
|
} else if (k < p) {
|
||||||
|
right = p - 1;
|
||||||
|
} else {
|
||||||
|
left = p + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap(int[] a, int i, int j) {
|
||||||
|
int tmp = a[i];
|
||||||
|
a[i] = a[j];
|
||||||
|
a[j] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
nodeLen = 0;
|
||||||
|
bucketLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void grow() {
|
||||||
|
int capacity = nodeLen + 1;
|
||||||
|
if (capacity < nsl.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
capacity += capacity >> 1;
|
||||||
|
if (capacity < INITIAL_CAP) {
|
||||||
|
capacity = INITIAL_CAP;
|
||||||
|
}
|
||||||
|
nsl = DoubleArrays.forceCapacity(nsl, capacity, nodeLen);
|
||||||
|
nll = LongArrays.forceCapacity(nll, capacity, nodeLen);
|
||||||
|
nbl = LongArrays.forceCapacity(nbl, capacity, nodeLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void growBucket(int capacity) {
|
||||||
|
capacity = bucketLen + capacity;
|
||||||
|
if (capacity < bxl.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
capacity += capacity >> 1;
|
||||||
|
if (capacity < INITIAL_CAP) {
|
||||||
|
capacity = INITIAL_CAP;
|
||||||
|
}
|
||||||
|
bxl = DoubleArrays.forceCapacity(bxl, capacity, bucketLen);
|
||||||
|
byl = DoubleArrays.forceCapacity(byl, capacity, bucketLen);
|
||||||
|
bzl = DoubleArrays.forceCapacity(bzl, capacity, bucketLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double nearest(final double tx, final double ty, final double tz, double dist) {
|
||||||
|
if (nodeLen == 0) {
|
||||||
|
return Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
if (search.length < Math.max(64, nodeLen * 4)) {
|
||||||
|
search = new int[Math.max(64, nodeLen * 4)];
|
||||||
|
}
|
||||||
|
if (SIMD) {
|
||||||
|
return DespawnVectorAPI.nearest(search, nsl, nll, nbl, bxl, byl, bzl, tx, ty, tz, dist);
|
||||||
|
}
|
||||||
|
final int[] stack = this.search;
|
||||||
|
final double[] nsl = this.nsl;
|
||||||
|
final long[] nll = this.nll;
|
||||||
|
final double[] bxl = this.bxl;
|
||||||
|
final double[] byl = this.byl;
|
||||||
|
final double[] bzl = this.bzl;
|
||||||
|
final long[] nbl = this.nbl;
|
||||||
|
int i = 0;
|
||||||
|
stack[i++] = 0;
|
||||||
|
while (i != 0) {
|
||||||
|
final int idx = stack[--i];
|
||||||
|
final long data = nll[idx];
|
||||||
|
if (data != LEAF) {
|
||||||
|
final long axis = data & AXIS_MASK;
|
||||||
|
final double delta = (axis == AXIS_X ? tx : axis == AXIS_Y ? ty : tz) - nsl[idx];
|
||||||
|
final long sign = Double.doubleToRawLongBits(delta) & SIGN_BIT;
|
||||||
|
final long sMask = sign >> 63; // -1L or 0L
|
||||||
|
final boolean leftValid = (data & LEFT_MASK) != LEFT_MASK;
|
||||||
|
final boolean rightValid = (data & RIGHT_MASK) != RIGHT_MASK;
|
||||||
|
final boolean pushNode = (sign == SIGN_BIT & leftValid) | ((sign == 0L) & rightValid);
|
||||||
|
final boolean pushOther = ((sign == 0L) & leftValid) | (sign == SIGN_BIT & rightValid);
|
||||||
|
final long node = (sMask & ((data & LEFT_MASK) >>> 2)) | (~sMask & (data >>> 32));
|
||||||
|
final long other = (sMask & (data >>> 32)) | (~sMask & ((data & LEFT_MASK) >>> 2));
|
||||||
|
if (pushNode) {
|
||||||
|
stack[i++] = (int) node;
|
||||||
|
}
|
||||||
|
if (pushOther && delta * delta < dist) {
|
||||||
|
stack[i++] = (int) other;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final long bucket = nbl[idx];
|
||||||
|
int start = (int) (bucket >>> 32);
|
||||||
|
final int end = start + (int) (bucket & 0xffffffffL);
|
||||||
|
for (; start < end; start++) {
|
||||||
|
final double dx = bxl[start] - tx;
|
||||||
|
final double dy = byl[start] - ty;
|
||||||
|
final double dz = bzl[start] - tz;
|
||||||
|
final double d2 = FMA ? Math.fma(dz, dz, Math.fma(dy, dy, dx * dx)) : dx * dx + dy * dy + dz * dz;
|
||||||
|
dist = Math.min(dist, d2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Node(int parent, boolean left, int offset, int length, int depth) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Stack {
|
||||||
|
|
||||||
|
private Node[] a;
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
private Stack(int capacity) {
|
||||||
|
a = new Node[capacity];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmpty() {
|
||||||
|
return i == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void push(Node value) {
|
||||||
|
if (i == a.length) {
|
||||||
|
grow();
|
||||||
|
}
|
||||||
|
a[i++] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node pop() {
|
||||||
|
return a[--i];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void grow() {
|
||||||
|
Node[] b = new Node[a.length << 1];
|
||||||
|
System.arraycopy(a, 0, b, 0, i);
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick(ServerLevel world, EntityTickList entityTickList) {
|
||||||
|
final ServerPlayer[] playerArr = world.players().toArray(EMPTY_PLAYERS);
|
||||||
|
final ServerPlayer[] list = new ServerPlayer[playerArr.length];
|
||||||
int newSize = 0;
|
int newSize = 0;
|
||||||
for (ServerPlayer player1 : playerList) {
|
for (ServerPlayer player1 : playerArr) {
|
||||||
if (EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player1)) {
|
if (EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player1)) {
|
||||||
list[newSize++] = player1;
|
list[newSize++] = player1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list = ObjectArrays.trim(list, newSize);
|
double[] pxl = new double[newSize];
|
||||||
this.players = list;
|
double[] pyl = new double[newSize];
|
||||||
this.pos = new double[this.players.length * 3];
|
double[] pzl = new double[newSize];
|
||||||
for (int i = 0; i < players.length; i++) {
|
for (int i = 0; i < newSize; i++) {
|
||||||
this.pos[i * 3] = this.players[i].getX();
|
pxl[i] = list[i].getX();
|
||||||
this.pos[i * 3 + 1] = this.players[i].getY();
|
pyl[i] = list[i].getY();
|
||||||
this.pos[i * 3 + 2] = this.players[i].getZ();
|
pzl[i] = list[i].getZ();
|
||||||
}
|
}
|
||||||
}
|
build(pxl, pyl, pzl);
|
||||||
|
entityTickList.forEach(Entity::leafCheckDespawn);
|
||||||
public void reset() {
|
reset();
|
||||||
this.players = EMPTY_PLAYER_ARRAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkDespawn(Mob mob) {
|
public void checkDespawn(Mob mob) {
|
||||||
double x = mob.getX();
|
final double x = mob.getX();
|
||||||
double y = mob.getY();
|
final double y = mob.getY();
|
||||||
double z = mob.getZ();
|
final double z = mob.getZ();
|
||||||
double distance = Double.MAX_VALUE;
|
final int i = mob.getType().getCategory().ordinal();
|
||||||
Player nearestPlayer = null;
|
final double dist = nearest(x, y, z, hard[i]);
|
||||||
for (int i = 0, playersSize = players.length; i < playersSize; i++) {
|
if (dist == Double.POSITIVE_INFINITY) {
|
||||||
final double dx = this.pos[i * 3] - x;
|
|
||||||
final double dy = this.pos[i * 3 + 1] - y;
|
|
||||||
final double dz = this.pos[i * 3 + 2] - z;
|
|
||||||
double d1 = dx * dx + dy * dy + dz * dz;
|
|
||||||
if (d1 < distance) {
|
|
||||||
distance = d1;
|
|
||||||
nearestPlayer = players[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nearestPlayer == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Level world = mob.level();
|
|
||||||
final WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = world.paperConfig().entities.spawning.despawnRanges.get(mob.getType().getCategory());
|
if (dist >= hard[i] && mob.removeWhenFarAway(dist)) {
|
||||||
final DespawnRange.Shape shape = world.paperConfig().entities.spawning.despawnRangeShape;
|
|
||||||
final double dy = Math.abs(nearestPlayer.getY() - y);
|
|
||||||
final double dySqr = Mth.square(dy);
|
|
||||||
final double dxSqr = Mth.square(nearestPlayer.getX() - x);
|
|
||||||
final double dzSqr = Mth.square(nearestPlayer.getZ() - z);
|
|
||||||
final double distanceSquared = dxSqr + dzSqr + dySqr;
|
|
||||||
if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && mob.removeWhenFarAway(distanceSquared)) {
|
|
||||||
mob.discard(EntityRemoveEvent.Cause.DESPAWN);
|
mob.discard(EntityRemoveEvent.Cause.DESPAWN);
|
||||||
} else if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) {
|
} else if (dist > sort[i]) {
|
||||||
if (mob.getNoActionTime() > 600 && mob.random.nextInt(800) == 0 && mob.removeWhenFarAway(distanceSquared)) {
|
if (mob.getNoActionTime() > 600 && mob.random.nextInt(800) == 0 && mob.removeWhenFarAway(dist)) {
|
||||||
mob.discard(EntityRemoveEvent.Cause.DESPAWN);
|
mob.discard(EntityRemoveEvent.Cause.DESPAWN);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package org.dreeam.leaf.world;
|
||||||
|
import jdk.incubator.vector.*;
|
||||||
|
|
||||||
|
import static org.dreeam.leaf.world.DespawnMap.*;
|
||||||
|
|
||||||
|
public final class DespawnVectorAPI {
|
||||||
|
|
||||||
|
private DespawnVectorAPI() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final VectorSpecies<Double> DOUBLE_SPECIES = DoubleVector.SPECIES_PREFERRED;
|
||||||
|
static final int DOUBLE_VECTOR_LENGTH = DOUBLE_SPECIES.length();
|
||||||
|
|
||||||
|
static double nearest(final int[] stack,
|
||||||
|
final double[] nsl,
|
||||||
|
final long[] nll,
|
||||||
|
final long[] nbl,
|
||||||
|
final double[] bxl, final double[] byl, final double[] bzl,
|
||||||
|
final double tx, final double ty, final double tz,
|
||||||
|
double dist) {
|
||||||
|
final DoubleVector vtx = DoubleVector.broadcast(DOUBLE_SPECIES, tx);
|
||||||
|
final DoubleVector vty = DoubleVector.broadcast(DOUBLE_SPECIES, ty);
|
||||||
|
final DoubleVector vtz = DoubleVector.broadcast(DOUBLE_SPECIES, tz);
|
||||||
|
int i = 0;
|
||||||
|
stack[i++] = 0;
|
||||||
|
while (i != 0) {
|
||||||
|
final int idx = stack[--i];
|
||||||
|
final long data = nll[idx];
|
||||||
|
if (data != LEAF) {
|
||||||
|
final long axis = data & AXIS_MASK;
|
||||||
|
final double delta = (axis == AXIS_X ? tx : axis == AXIS_Y ? ty : tz) - nsl[idx];
|
||||||
|
final long sign = Double.doubleToRawLongBits(delta) & SIGN_BIT;
|
||||||
|
final long sMask = sign >> 63; // -1L or 0L
|
||||||
|
final boolean leftValid = (data & LEFT_MASK) != LEFT_MASK;
|
||||||
|
final boolean rightValid = (data & RIGHT_MASK) != RIGHT_MASK;
|
||||||
|
final boolean pushNode = (sign == SIGN_BIT & leftValid) | ((sign == 0L) & rightValid);
|
||||||
|
final boolean pushOther = ((sign == 0L) & leftValid) | (sign == SIGN_BIT & rightValid);
|
||||||
|
final long node = (sMask & ((data & LEFT_MASK) >>> 2)) | (~sMask & (data >>> 32));
|
||||||
|
final long other = (sMask & (data >>> 32)) | (~sMask & ((data & LEFT_MASK) >>> 2));
|
||||||
|
if (pushNode) {
|
||||||
|
stack[i++] = (int) node;
|
||||||
|
}
|
||||||
|
if (pushOther && delta * delta < dist) {
|
||||||
|
stack[i++] = (int) other;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final long bucket = nbl[idx];
|
||||||
|
final int start = (int) (bucket >>> 32);
|
||||||
|
final int bucketSize = (int) (bucket & 0xffffffffL);
|
||||||
|
if (DOUBLE_VECTOR_LENGTH == bucketSize) {
|
||||||
|
final DoubleVector vdx = DoubleVector.fromArray(DOUBLE_SPECIES, bxl, start).sub(vtx);
|
||||||
|
final DoubleVector vdy = DoubleVector.fromArray(DOUBLE_SPECIES, byl, start).sub(vty);
|
||||||
|
final DoubleVector vdz = DoubleVector.fromArray(DOUBLE_SPECIES, bzl, start).sub(vtz);
|
||||||
|
final DoubleVector vDist = FMA ?
|
||||||
|
vdz.fma(vdz, vdy.fma(vdy, vdx.mul(vdx))) :
|
||||||
|
vdx.mul(vdx).add(vdy.mul(vdy)).add(vdz.mul(vdz));
|
||||||
|
dist = Math.min(dist, vDist.reduceLanes(VectorOperators.MIN));
|
||||||
|
} else if (DOUBLE_VECTOR_LENGTH > 4 && bucketSize >= 4) {
|
||||||
|
final VectorMask<Double> mask = DOUBLE_SPECIES.indexInRange(0, bucketSize);
|
||||||
|
final DoubleVector vdx = DoubleVector.fromArray(DOUBLE_SPECIES, bxl, start, mask).sub(vtx);
|
||||||
|
final DoubleVector vdy = DoubleVector.fromArray(DOUBLE_SPECIES, byl, start, mask).sub(vty);
|
||||||
|
final DoubleVector vdz = DoubleVector.fromArray(DOUBLE_SPECIES, bzl, start, mask).sub(vtz);
|
||||||
|
final DoubleVector vDist = FMA ?
|
||||||
|
vdz.fma(vdz, vdy.fma(vdy, vdx.mul(vdx))) :
|
||||||
|
vdx.mul(vdx).add(vdy.mul(vdy)).add(vdz.mul(vdz));
|
||||||
|
dist = Math.min(dist, vDist.reduceLanes(VectorOperators.MIN, mask));
|
||||||
|
} else {
|
||||||
|
final int end = start + bucketSize;
|
||||||
|
for (int j = start; j < end; j++) {
|
||||||
|
final double dx = bxl[j] - tx;
|
||||||
|
final double dy = byl[j] - ty;
|
||||||
|
final double dz = bzl[j] - tz;
|
||||||
|
final double d2 = FMA ? Math.fma(dz, dz, Math.fma(dy, dy, dx * dx)) : dx * dx + dy * dy + dz * dz;
|
||||||
|
dist = Math.min(dist, d2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user