From 90a3509dd9dc20ea3bcfd3c47128e6bdd75a46dd Mon Sep 17 00:00:00 2001 From: Byteflux Date: Sat, 13 Jun 2015 19:47:27 -0700 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/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java index 364625859..4e5c7a512 100644 --- a/src/main/java/net/minecraft/server/Explosion.java +++ b/src/main/java/net/minecraft/server/Explosion.java @@ -131,7 +131,7 @@ public class Explosion { d0 /= d8; d1 /= d8; d2 /= d8; - double d9 = (double) this.world.a(vec3d, entity.boundingBox); + double d9 = this.getBlockDensity(vec3d, entity.boundingBox); // PaperSpigot - Optimize explosions double d10 = (1.0D - d7) * d9; // CraftBukkit start @@ -274,4 +274,86 @@ public class Explosion { public EntityLiving c() { return this.source == null ? null : (this.source instanceof EntityTNTPrimed ? ((EntityTNTPrimed) this.source).getSource() : (this.source instanceof EntityLiving ? (EntityLiving) this.source : null)); } + + // PaperSpigot start - Optimize explosions + private float getBlockDensity(Vec3D vec3d, AxisAlignedBB aabb) { + if (!this.world.paperSpigotConfig.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; + } + } + // PaperSpigot end } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 878214465..00f397723 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -735,6 +735,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo worldserver.timings.tracker.stopTiming(); // Spigot this.methodProfiler.b(); this.methodProfiler.b(); + worldserver.explosionDensityCache.clear(); // PaperSpigot - Optimize explosions // } // CraftBukkit // this.h[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 51ddb6c50..0c942aab1 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -14,6 +14,8 @@ import java.util.concurrent.Callable; // PaperSpigot start import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.HashMap; +import java.util.Map; import net.minecraft.util.com.google.common.util.concurrent.ThreadFactoryBuilder; import org.bukkit.craftbukkit.CraftChunk; // PaperSpigot end @@ -136,6 +138,7 @@ public abstract class World implements IBlockAccess { return lightingExecutor; } // Poweruser end + public final Map explosionDensityCache = new HashMap(); // PaperSpigot - Optimize explosions public static long chunkToKey(int x, int z) { diff --git a/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java b/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java index 91d4fc2da..ec27f7934 100644 --- a/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java +++ b/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java @@ -259,4 +259,10 @@ public class PaperSpigotWorldConfig { disableEndCredits = getBoolean( "game-mechanics.disable-end-credits", false ); } + + public boolean optimizeExplosions; + private void optimizeExplosions() + { + optimizeExplosions = getBoolean( "optimize-explosions", false ); + } } -- 2.13.3