aboutsummaryrefslogtreecommitdiffhomepage
path: root/Spigot-Server-Patches/0035-Optimize-explosions.patch
blob: 584cc7adbc8ae3ab9c64d9d982d1ad4a5ae45651 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
From 428b111b0dd4542d55db721110adf33e7feead76 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 7525bcb..ca0ac9b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -194,4 +194,10 @@ public class PaperWorldConfig {
         generateVillage = getBoolean("generator-settings.village", true);
         generateFlatBedrock = getBoolean("generator-settings.flat-bedrock", 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 f4765d3..caf29c7 100644
--- a/src/main/java/net/minecraft/server/Explosion.java
+++ b/src/main/java/net/minecraft/server/Explosion.java
@@ -129,7 +129,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
@@ -296,4 +296,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 d0060d0..d1d268f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -872,6 +872,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, 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 672167a..e8cfe2b 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;
@@ -135,6 +136,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.10.0.windows.1