PaperMC/Spigot-Server-Patches/0034-Optimize-explosions.patch
Aikar 18c3716c49
Current Chunk for Entity and Block Entities, counts by entity type
This enables us a fast reference to the entities current chunk instead
of having to look it up by hashmap lookups.

We also store counts by type to further enable other performance optimizations in later patches.
2018-07-04 03:58:56 -04:00

160 lines
7 KiB
Diff

From 7c6a6c8a4f1efcf9c0319a79cfcc36fc6b700591 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 11:59:48 -0600
Subject: [PATCH] Optimize explosions
The process of determining an entity's exposure from explosions can be
expensive when there are hundreds or more entities in range.
This patch adds a per-tick cache that is used for storing and retrieving
an entity's exposure during an explosion.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 7e5cd8042..15675efbf 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -177,4 +177,10 @@ public class PaperWorldConfig {
disableExtremeHillsMonsterEggs = getBoolean("generator-settings.disable-extreme-hills-monster-eggs", false);
disableMesaAdditionalGold = getBoolean("generator-settings.disable-mesa-additional-gold", false);
}
+
+ public boolean optimizeExplosions;
+ private void optimizeExplosions() {
+ optimizeExplosions = getBoolean("optimize-explosions", false);
+ log("Optimize explosions: " + optimizeExplosions);
+ }
}
diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java
index a1ebcf858..e7f0e84d4 100644
--- a/src/main/java/net/minecraft/server/Explosion.java
+++ b/src/main/java/net/minecraft/server/Explosion.java
@@ -130,7 +130,7 @@ public class Explosion {
d8 /= d11;
d9 /= d11;
d10 /= d11;
- double d12 = (double) this.world.a(vec3d, entity.getBoundingBox());
+ double d12 = this.getBlockDensity(vec3d, entity.getBoundingBox()); // Paper - Optimize explosions
double d13 = (1.0D - d7) * d12;
// CraftBukkit start
@@ -298,4 +298,85 @@ public class Explosion {
public List<BlockPosition> getBlocks() {
return this.blocks;
}
+
+ // Paper start - Optimize explosions
+ private float getBlockDensity(Vec3D vec3d, AxisAlignedBB aabb) {
+ if (!this.world.paperConfig.optimizeExplosions) {
+ return this.world.a(vec3d, aabb);
+ }
+ CacheKey key = new CacheKey(this, aabb);
+ Float blockDensity = this.world.explosionDensityCache.get(key);
+ if (blockDensity == null) {
+ blockDensity = this.world.a(vec3d, aabb);
+ this.world.explosionDensityCache.put(key, blockDensity);
+ }
+
+ return blockDensity;
+ }
+
+ static class CacheKey {
+ private final World world;
+ private final double posX, posY, posZ;
+ private final double minX, minY, minZ;
+ private final double maxX, maxY, maxZ;
+
+ public CacheKey(Explosion explosion, AxisAlignedBB aabb) {
+ this.world = explosion.world;
+ this.posX = explosion.posX;
+ this.posY = explosion.posY;
+ this.posZ = explosion.posZ;
+ this.minX = aabb.a;
+ this.minY = aabb.b;
+ this.minZ = aabb.c;
+ this.maxX = aabb.d;
+ this.maxY = aabb.e;
+ this.maxZ = aabb.f;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CacheKey cacheKey = (CacheKey) o;
+
+ if (Double.compare(cacheKey.posX, posX) != 0) return false;
+ if (Double.compare(cacheKey.posY, posY) != 0) return false;
+ if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
+ if (Double.compare(cacheKey.minX, minX) != 0) return false;
+ if (Double.compare(cacheKey.minY, minY) != 0) return false;
+ if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
+ if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
+ if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
+ if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
+ return world.equals(cacheKey.world);
+ }
+
+ @Override
+ public int hashCode() {
+ int result;
+ long temp;
+ result = world.hashCode();
+ temp = Double.doubleToLongBits(posX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(posY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(posZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index d63a243f3..4e8ce79ff 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -889,6 +889,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
worldserver.getTracker().updatePlayers();
this.methodProfiler.b();
this.methodProfiler.b();
+ worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
// } // CraftBukkit
// this.i[i][this.ticks % 100] = System.nanoTime() - j; // CraftBukkit
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 77ed2d249..fc7315f7d 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -16,6 +16,7 @@ import javax.annotation.Nullable;
// CraftBukkit start
import com.google.common.collect.Maps;
+import java.util.HashMap; // Paper
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.block.BlockState;
@@ -138,6 +139,7 @@ public abstract class World implements IBlockAccess {
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
public CraftWorld getWorld() {
return this.world;
--
2.18.0