From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Byteflux 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/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index b86d8a3756cb8c1adb1aceda57f60b0ccdb3f659..43c7014b51f1f46a0e52f0595e85636767ed92ff 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1611,6 +1611,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions public CraftWorld getWorld() { return this.world; diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java index 0eb25fabfff0e8a050c6dfb8cd24e703f679db76..f4b5c81d0daae24e06ba6409fc4584b4f1406fd2 100644 --- a/src/main/java/net/minecraft/world/level/ServerExplosion.java +++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java @@ -206,7 +206,7 @@ public class ServerExplosion implements Explosion { d3 /= d4; boolean flag = this.damageCalculator.shouldDamageEntity(this, entity); float f1 = this.damageCalculator.getKnockbackMultiplier(entity); - float f2 = !flag && f1 == 0.0F ? 0.0F : ServerExplosion.getSeenPercent(this.center, entity); + float f2 = !flag && f1 == 0.0F ? 0.0F : this.getBlockDensity(this.center, entity); // Paper - Optimize explosions if (flag) { // CraftBukkit start @@ -483,4 +483,85 @@ public class ServerExplosion implements Explosion { } } + + // Paper start - Optimize explosions + private float getBlockDensity(Vec3 vec3d, Entity entity) { + if (!this.level.paperConfig().environment.optimizeExplosions) { + return getSeenPercent(vec3d, entity); + } + CacheKey key = new CacheKey(this, entity.getBoundingBox()); + Float blockDensity = this.level.explosionDensityCache.get(key); + if (blockDensity == null) { + blockDensity = getSeenPercent(vec3d, entity); + this.level.explosionDensityCache.put(key, blockDensity); + } + + return blockDensity; + } + + static class CacheKey { + private final Level world; + private final double posX, posY, posZ; + private final double minX, minY, minZ; + private final double maxX, maxY, maxZ; + + public CacheKey(Explosion explosion, AABB aabb) { + this.world = explosion.level(); + this.posX = explosion.center().x; + this.posY = explosion.center().y; + this.posZ = explosion.center().z; + this.minX = aabb.minX; + this.minY = aabb.minY; + this.minZ = aabb.minZ; + this.maxX = aabb.maxX; + this.maxY = aabb.maxY; + this.maxZ = aabb.maxZ; + } + + @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 }