From 0f2c2749982e55cd496c7a765ddbd1dbc22c904b Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 11 Nov 2017 18:47:30 -0500 Subject: [PATCH] Improve Structures Checking Improves performance by keying every chunk thats part of a structure to a hashmap instead of only the first one. This allows us to avoid iterating the entire structures value set to see if a block position is inside of a structure. This should have pretty decent performance improvement to any standard world that has been around for a whilewith lots of structures due to ineffeciencies in how MC stores structures (even unloaded chunks has structured data loaded) --- Spigot-Server-Patches/0005-MC-Utils.patch | 17 +- Spigot-Server-Patches/0006-Timings-v2.patch | 8 +- ...32-Fix-MC-117075-TE-Unload-Lag-Spike.patch | 16 +- .../0251-Improve-Structures-Checking.patch | 199 ++++++++++++++++++ scripts/importmcdev.sh | 3 + 5 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 Spigot-Server-Patches/0251-Improve-Structures-Checking.patch diff --git a/Spigot-Server-Patches/0005-MC-Utils.patch b/Spigot-Server-Patches/0005-MC-Utils.patch index bec0b6b66..632b0d3f5 100644 --- a/Spigot-Server-Patches/0005-MC-Utils.patch +++ b/Spigot-Server-Patches/0005-MC-Utils.patch @@ -1,4 +1,4 @@ -From 512e126bf403f6ed82dcf54491fe3357a8430464 Mon Sep 17 00:00:00 2001 +From f12d521a85a8487c53f0c0545a7c1aa6fd2953ed Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 28 Mar 2016 20:55:47 -0400 Subject: [PATCH] MC Utils @@ -25,6 +25,19 @@ index 4bbebb25a..c4d9344a7 100644 @Nullable public TileEntity a(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) { // CraftBukkit start +diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java +index 239440888..aafd23beb 100644 +--- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java ++++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java +@@ -15,6 +15,8 @@ public class ChunkCoordIntPair { + this.z = blockposition.getZ() >> 4; + } + ++ public static long asLong(final BlockPosition pos) { return a(pos.getX() >> 4, pos.getZ() >> 4); } // Paper - OBFHELPER ++ public static long asLong(int x, int z) { return a(x, z); } // Paper - OBFHELPER + public static long a(int i, int j) { + return (long) i & 4294967295L | ((long) j & 4294967295L) << 32; + } diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main/java/net/minecraft/server/DataPaletteBlock.java index 1f2fe87b6..2cb462b8e 100644 --- a/src/main/java/net/minecraft/server/DataPaletteBlock.java @@ -299,5 +312,5 @@ index 8cede938a..cd2d58bfb 100644 return System.nanoTime() / 1000000L; } -- -2.14.3 +2.15.0 diff --git a/Spigot-Server-Patches/0006-Timings-v2.patch b/Spigot-Server-Patches/0006-Timings-v2.patch index fff715ad5..a5809ef99 100644 --- a/Spigot-Server-Patches/0006-Timings-v2.patch +++ b/Spigot-Server-Patches/0006-Timings-v2.patch @@ -1,4 +1,4 @@ -From e610c7b15e2671e15ed2c59c617dfe5240fb9c13 Mon Sep 17 00:00:00 2001 +From 456890d91c1d97836f3c67cf40acdfa724ac6745 Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 3 Mar 2016 04:00:11 -0600 Subject: [PATCH] Timings v2 @@ -1086,7 +1086,7 @@ index c00aee885..b3356b40f 100644 public void addWhitelist(GameProfile gameprofile) { diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java -index 74e3f42cd..2580a4cf6 100644 +index 74e3f42cd..66a80a776 100644 --- a/src/main/java/net/minecraft/server/StructureGenerator.java +++ b/src/main/java/net/minecraft/server/StructureGenerator.java @@ -1,5 +1,7 @@ @@ -1107,7 +1107,7 @@ index 74e3f42cd..2580a4cf6 100644 public StructureGenerator() {} -+ public String getName() { return a(); } // Paper // OBF HELPER ++ public String getName() { return a(); } // Paper // OBFHELPER public abstract String a(); protected final synchronized void a(World world, final int i, final int j, int k, int l, ChunkSnapshot chunksnapshot) { @@ -1906,5 +1906,5 @@ index 2bd690fdf..38be7ed71 100644 } } -- -2.14.3 +2.15.0 diff --git a/Spigot-Server-Patches/0232-Fix-MC-117075-TE-Unload-Lag-Spike.patch b/Spigot-Server-Patches/0232-Fix-MC-117075-TE-Unload-Lag-Spike.patch index 3c009f037..5927aa205 100644 --- a/Spigot-Server-Patches/0232-Fix-MC-117075-TE-Unload-Lag-Spike.patch +++ b/Spigot-Server-Patches/0232-Fix-MC-117075-TE-Unload-Lag-Spike.patch @@ -1,21 +1,9 @@ -From 635b62974365f6ae0b039790b1725092c4508043 Mon Sep 17 00:00:00 2001 +From 96892dd268a65e7af2375a9ccd7a2286dcbfa162 Mon Sep 17 00:00:00 2001 From: mezz Date: Wed, 9 Aug 2017 17:51:22 -0500 Subject: [PATCH] Fix MC-117075: TE Unload Lag Spike -diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java -index 239440888..e8d1a1c60 100644 ---- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java -+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java -@@ -15,6 +15,7 @@ public class ChunkCoordIntPair { - this.z = blockposition.getZ() >> 4; - } - -+ public static long asLong(int x, int z) { return a(x, z); } // Paper - OBFHELPER - public static long a(int i, int j) { - return (long) i & 4294967295L | ((long) j & 4294967295L) << 32; - } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 30cf4a251..f690aaa10 100644 --- a/src/main/java/net/minecraft/server/World.java @@ -34,5 +22,5 @@ index 30cf4a251..f690aaa10 100644 this.tileEntityListUnload.clear(); } -- -2.14.2 +2.15.0 diff --git a/Spigot-Server-Patches/0251-Improve-Structures-Checking.patch b/Spigot-Server-Patches/0251-Improve-Structures-Checking.patch new file mode 100644 index 000000000..9a8e77371 --- /dev/null +++ b/Spigot-Server-Patches/0251-Improve-Structures-Checking.patch @@ -0,0 +1,199 @@ +From bbe1d20e6fb529ca5dcf54c45f77894badaf5a1b Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 11 Nov 2017 17:57:39 -0500 +Subject: [PATCH] Improve Structures Checking + +Improves performance by keying every chunk thats part of a structure to a hashmap +instead of only the first one. + +This allows us to avoid iterating the entire structures value set to see +if a block position is inside of a structure. + +This should have pretty decent performance improvement to any standard world +that has been around for a whilewith lots of structures due to ineffeciencies +in how MC stores structures (even unloaded chunks has structured data loaded) + +diff --git a/src/main/java/net/minecraft/server/StructureBoundingBox.java b/src/main/java/net/minecraft/server/StructureBoundingBox.java +index db419cd99..d9329bd42 100644 +--- a/src/main/java/net/minecraft/server/StructureBoundingBox.java ++++ b/src/main/java/net/minecraft/server/StructureBoundingBox.java +@@ -4,12 +4,14 @@ import com.google.common.base.MoreObjects; + + public class StructureBoundingBox { + +- public int a; +- public int b; +- public int c; +- public int d; +- public int e; +- public int f; ++ public int a; // Paper - If changes, verify low/high getters ++ public int b; // Paper - If changes, verify low/high getters ++ public int c; // Paper - If changes, verify low/high getters ++ public int d; // Paper - If changes, verify low/high getters ++ public int e; // Paper - If changes, verify low/high getters ++ public int f; // Paper - If changes, verify low/high getters ++ public BaseBlockPosition getLowPosition() { return new BaseBlockPosition(a, b, c); } // Paper ++ public BaseBlockPosition getHighPosition() { return new BaseBlockPosition(d, e, f); } // Paper + + public StructureBoundingBox() {} + +@@ -114,6 +116,7 @@ public class StructureBoundingBox { + this.f += k; + } + ++ public boolean contains(BaseBlockPosition baseblockposition) { return b(baseblockposition); } // Paper - OBFHELPER + public boolean b(BaseBlockPosition baseblockposition) { + return baseblockposition.getX() >= this.a && baseblockposition.getX() <= this.d && baseblockposition.getZ() >= this.c && baseblockposition.getZ() <= this.f && baseblockposition.getY() >= this.b && baseblockposition.getY() <= this.e; + } +diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java +index e8263baa4..09e49221d 100644 +--- a/src/main/java/net/minecraft/server/StructureGenerator.java ++++ b/src/main/java/net/minecraft/server/StructureGenerator.java +@@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; + import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + import it.unimi.dsi.fastutil.objects.ObjectIterator; + import java.util.Iterator; ++import java.util.List; + import java.util.Random; + import javax.annotation.Nullable; + +@@ -14,6 +15,7 @@ public abstract class StructureGenerator extends WorldGenBase { + private final Timing timing = MinecraftTimings.getStructureTiming(this); // Paper + private PersistentStructure a; + protected Long2ObjectMap c = new Long2ObjectOpenHashMap(1024); ++ protected Long2ObjectMap allStructures = new Long2ObjectOpenHashMap(1024); // Paper - Holds ref to structures for every chunk its part of, where as the one above this only holds the vanilla oriented ones. + + public StructureGenerator() {} + +@@ -29,6 +31,7 @@ public abstract class StructureGenerator extends WorldGenBase { + if (this.a(i, j)) { + StructureStart structurestart = this.b(i, j); + ++ populateStructure(structurestart); // Paper + this.c.put(ChunkCoordIntPair.a(i, j), structurestart); + if (structurestart.a()) { + this.a(i, j, structurestart); +@@ -106,6 +109,19 @@ public abstract class StructureGenerator extends WorldGenBase { + + @Nullable + protected StructureStart c(BlockPosition blockposition) { ++ // Paper start - replace method ++ StructureStart structureStart = allStructures.get(ChunkCoordIntPair.asLong(blockposition)); ++ if (structureStart != null && structureStart.isSizeable() && structureStart.getBoundingBox().contains(blockposition)) { ++ List structurePieces = structureStart.getStructurePieces(); ++ for (StructurePiece piece : structurePieces) { ++ if (piece.getBoundingBox().contains(blockposition)) { ++ return structureStart; ++ } ++ } ++ } ++ ++ return null; ++ /* + ObjectIterator objectiterator = this.c.values().iterator(); + + while (objectiterator.hasNext()) { +@@ -125,11 +141,16 @@ public abstract class StructureGenerator extends WorldGenBase { + } + + return null; ++ */ + } + + public boolean a(World world, BlockPosition blockposition) { + if (this.g == null) return false; // Paper + this.a(world); ++ // Paper start - Replace method ++ StructureStart structureStart = this.allStructures.get(ChunkCoordIntPair.asLong(blockposition)); ++ return structureStart != null && structureStart.isSizeable() && structureStart.getBoundingBox().contains(blockposition); ++ /* // comment out rest + ObjectIterator objectiterator = this.c.values().iterator(); + + StructureStart structurestart; +@@ -142,7 +163,7 @@ public abstract class StructureGenerator extends WorldGenBase { + structurestart = (StructureStart) objectiterator.next(); + } while (!structurestart.a() || !structurestart.b().b((BaseBlockPosition) blockposition)); + +- return true; ++ return true;*/ // Paper end + } + + @Nullable +@@ -177,6 +198,7 @@ public abstract class StructureGenerator extends WorldGenBase { + StructureStart structurestart = WorldGenFactory.a(nbttagcompound1, world); + + if (structurestart != null) { ++ populateStructure(structurestart); // Paper + this.c.put(ChunkCoordIntPair.a(i, j), structurestart); + } + } +@@ -187,6 +209,27 @@ public abstract class StructureGenerator extends WorldGenBase { + + } + ++ // Paper start ++ private void populateStructure(StructureStart structurestart) { ++ for (StructurePiece piece : structurestart.getStructurePieces()) { ++ populateStructure(structurestart, piece.getBoundingBox()); ++ } ++ populateStructure(structurestart, structurestart.getBoundingBox()); ++ } ++ private void populateStructure(StructureStart structurestart, StructureBoundingBox bb) { ++ if (bb == null) { ++ return; ++ } ++ final BaseBlockPosition low = bb.getLowPosition(); ++ final BaseBlockPosition high = bb.getHighPosition(); ++ for (int x = low.getX() >> 4, maxX = high.getX() >> 4; x < maxX; x++) { ++ for (int z = low.getZ() >> 4, maxZ = high.getZ() >> 4; z < maxZ; z++) { ++ allStructures.put(ChunkCoordIntPair.asLong(x, z), structurestart); ++ } ++ } ++ } ++ // Paper end ++ + private void a(int i, int j, StructureStart structurestart) { + this.a.a(structurestart.a(i, j), i, j); + this.a.c(); +diff --git a/src/main/java/net/minecraft/server/StructurePiece.java b/src/main/java/net/minecraft/server/StructurePiece.java +index 93903bc67..fcc13f811 100644 +--- a/src/main/java/net/minecraft/server/StructurePiece.java ++++ b/src/main/java/net/minecraft/server/StructurePiece.java +@@ -53,6 +53,7 @@ public abstract class StructurePiece { + + public abstract boolean a(World world, Random random, StructureBoundingBox structureboundingbox); + ++ public StructureBoundingBox getBoundingBox() { return d(); } // Paper - OBFHELPER + public StructureBoundingBox d() { + return this.l; + } +diff --git a/src/main/java/net/minecraft/server/StructureStart.java b/src/main/java/net/minecraft/server/StructureStart.java +index b6abc74e0..f9bb953d0 100644 +--- a/src/main/java/net/minecraft/server/StructureStart.java ++++ b/src/main/java/net/minecraft/server/StructureStart.java +@@ -19,10 +19,12 @@ public abstract class StructureStart { + this.d = j; + } + ++ public StructureBoundingBox getBoundingBox() { return b(); } // Paper - OBFHELPER + public StructureBoundingBox b() { + return this.b; + } + ++ public List getStructurePieces() { return c(); } // Paper - OBFHELPER + public List c() { + return this.a; + } +@@ -137,7 +139,7 @@ public abstract class StructureStart { + + } + +- public boolean a() { ++ public boolean isSizeable() { return a(); } public boolean a() { // Paper - OBFHELPER + return true; + } + +-- +2.15.0 + diff --git a/scripts/importmcdev.sh b/scripts/importmcdev.sh index 3cfd52184..289fa0958 100755 --- a/scripts/importmcdev.sh +++ b/scripts/importmcdev.sh @@ -93,6 +93,9 @@ import PlayerConnectionUtils import RegionFile import RegistryBlockID import RemoteControlListener +import StructureBoundingBox +import StructurePiece +import StructureStart import TileEntityEnderChest import TileEntityLootable import WorldGenStronghold