From d72abafa8f899aa941069a66420eff7ebed624f8 Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 18 Mar 2016 23:55:31 -0400 Subject: [PATCH] Optimized Light Level Comparisons Use an optimized method to test if a block position meets a desired light level. This method benefits from returning as soon as the desired light level matches. Also Optimize Grass more --- .../Add-World-Util-Methods.patch | 95 +++++++++++++ .../Optimized-Light-Level-Comparisons.patch | 133 ++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 Spigot-Server-Patches/Add-World-Util-Methods.patch create mode 100644 Spigot-Server-Patches/Optimized-Light-Level-Comparisons.patch diff --git a/Spigot-Server-Patches/Add-World-Util-Methods.patch b/Spigot-Server-Patches/Add-World-Util-Methods.patch new file mode 100644 index 000000000..3cd2a5ec4 --- /dev/null +++ b/Spigot-Server-Patches/Add-World-Util-Methods.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 18 Mar 2016 20:16:03 -0400 +Subject: [PATCH] Add World Util Methods + +Methods that can be used for other patches to help improve logic. + +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { + return (CraftServer) Bukkit.getServer(); + } + ++ // Paper start ++ public Chunk getChunkIfLoaded(BlockPosition blockposition) { ++ return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); ++ } ++ // Paper end ++ + public Chunk getChunkIfLoaded(int x, int z) { + return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z); + } +@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { + } + } + ++ // Paper start - test if meets light level, return faster ++ // logic copied from below ++ public boolean isLightLevel(BlockPosition blockposition, int level) { ++ if (isValidLocation(blockposition)) { ++ if (this.getType(blockposition).f()) { ++ if (this.c(blockposition.up(), false) >= level) { ++ return true; ++ } ++ if (this.c(blockposition.east(), false) >= level) { ++ return true; ++ } ++ if (this.c(blockposition.west(), false) >= level) { ++ return true; ++ } ++ if (this.c(blockposition.south(), false) >= level) { ++ return true; ++ } ++ if (this.c(blockposition.north(), false) >= level) { ++ return true; ++ } ++ return false; ++ } else { ++ if (blockposition.getY() >= 256) { ++ blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ()); ++ } ++ ++ Chunk chunk = this.getChunkAtWorldCoords(blockposition); ++ return chunk.a(blockposition, this.J) >= level; ++ } ++ } else { ++ return true; ++ } ++ } ++ // Paper end ++ + public int getLightLevel(BlockPosition blockposition) { + return this.c(blockposition, true); + } +@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { + return this.worldProvider.n()[this.getLightLevel(blockposition)]; + } + ++ // Paper start - reduces need to do isLoaded before getType ++ public IBlockData getTypeIfLoaded(BlockPosition blockposition) { ++ // CraftBukkit start - tree generation ++ if (captureTreeGeneration) { ++ Iterator it = capturedBlockStates.iterator(); ++ while (it.hasNext()) { ++ BlockState previous = it.next(); ++ if (previous.getX() == blockposition.getX() && previous.getY() == blockposition.getY() && previous.getZ() == blockposition.getZ()) { ++ return CraftMagicNumbers.getBlock(previous.getTypeId()).fromLegacyData(previous.getRawData()); ++ } ++ } ++ } ++ // CraftBukkit end ++ Chunk chunk = this.getChunkIfLoaded(blockposition); ++ if (chunk != null) { ++ return this.isValidLocation(blockposition) ? chunk.getBlockData(blockposition) : Blocks.AIR.getBlockData(); ++ } ++ return null; ++ } ++ // Paper end ++ + public IBlockData getType(BlockPosition blockposition) { + // CraftBukkit start - tree generation + if (captureTreeGeneration) { +-- \ No newline at end of file diff --git a/Spigot-Server-Patches/Optimized-Light-Level-Comparisons.patch b/Spigot-Server-Patches/Optimized-Light-Level-Comparisons.patch new file mode 100644 index 000000000..c80913125 --- /dev/null +++ b/Spigot-Server-Patches/Optimized-Light-Level-Comparisons.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Fri, 18 Mar 2016 21:22:56 -0400 +Subject: [PATCH] Optimized Light Level Comparisons + +Use an optimized method to test if a block position meets a desired light level. + +This method benefits from returning as soon as the desired light level matches. + +diff --git a/src/main/java/net/minecraft/server/BlockCrops.java b/src/main/java/net/minecraft/server/BlockCrops.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/BlockCrops.java ++++ b/src/main/java/net/minecraft/server/BlockCrops.java +@@ -0,0 +0,0 @@ public class BlockCrops extends BlockPlant implements IBlockFragilePlantElement + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + super.b(world, blockposition, iblockdata, random); +- if (world.getLightLevel(blockposition.up()) >= 9) { ++ if (world.isLightLevel(blockposition.up(), 9)) { // Paper + int i = this.x(iblockdata); + + if (i < this.g()) { +diff --git a/src/main/java/net/minecraft/server/BlockGrass.java b/src/main/java/net/minecraft/server/BlockGrass.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/BlockGrass.java ++++ b/src/main/java/net/minecraft/server/BlockGrass.java +@@ -0,0 +0,0 @@ public class BlockGrass extends Block implements IBlockFragilePlantElement { + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (!world.isClientSide) { +- if (world.getLightLevel(blockposition.up()) < 4 && world.getType(blockposition.up()).c() > 2) { ++ int lightLevel = -1; // Paper ++ if (world.getType(blockposition.up()).c() > 2 && (lightLevel = world.getLightLevel(blockposition.up())) < 4) { // Paper - move light check to end to avoid unneeded light lookups + // CraftBukkit start + // world.setTypeUpdate(blockposition, Blocks.DIRT.getBlockData()); + org.bukkit.World bworld = world.getWorld(); +@@ -0,0 +0,0 @@ public class BlockGrass extends Block implements IBlockFragilePlantElement { + } + // CraftBukkit end + } else { +- if (world.getLightLevel(blockposition.up()) >= 9) { ++ // Paper start ++ // If light was calculated above, reuse it, else grab it ++ if (lightLevel == -1) { ++ lightLevel = world.getLightLevel(blockposition.up()); ++ } ++ if (lightLevel >= 9) { ++ // Paper end + for (int i = 0; i < 4; ++i) { + BlockPosition blockposition1 = blockposition.a(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); + +- if (blockposition1.getY() >= 0 && blockposition1.getY() < 256 && !world.isLoaded(blockposition1)) { ++ IBlockData iblockdata2 = world.getTypeIfLoaded(blockposition1); // Paper - moved up ++ if (iblockdata2 == null) { // Paper + return; + } + + IBlockData iblockdata1 = world.getType(blockposition1.up()); +- IBlockData iblockdata2 = world.getType(blockposition1); ++ //IBlockData iblockdata2 = world.getTypeIfLoaded(blockposition1); // Paper - moved up + +- if (iblockdata2.getBlock() == Blocks.DIRT && iblockdata2.get(BlockDirt.VARIANT) == BlockDirt.EnumDirtVariant.DIRT && world.getLightLevel(blockposition1.up()) >= 4 && iblockdata1.c() <= 2) { ++ if (iblockdata2.getBlock() == Blocks.DIRT && iblockdata2.get(BlockDirt.VARIANT) == BlockDirt.EnumDirtVariant.DIRT && iblockdata1.c() <= 2 && world.isLightLevel(blockposition1.up(), 4)) { // Paper - move last check before isLightLevel to avoid unneeded light checks + // CraftBukkit start + // world.setTypeUpdate(blockposition1, Blocks.GRASS.getBlockData()); + org.bukkit.World bworld = world.getWorld(); +diff --git a/src/main/java/net/minecraft/server/BlockSapling.java b/src/main/java/net/minecraft/server/BlockSapling.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/BlockSapling.java ++++ b/src/main/java/net/minecraft/server/BlockSapling.java +@@ -0,0 +0,0 @@ public class BlockSapling extends BlockPlant implements IBlockFragilePlantElemen + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + if (!world.isClientSide) { + super.b(world, blockposition, iblockdata, random); +- if (world.getLightLevel(blockposition.up()) >= 9 && random.nextInt(Math.max(2, (int) (((100 / world.spigotConfig.saplingModifier) * 7) + 0.5F))) == 0) { // Spigot ++ if (world.isLightLevel(blockposition.up(), 9) && random.nextInt(Math.max(2, (int) (((100 / world.spigotConfig.saplingModifier) * 7) + 0.5F))) == 0) { // Spigot // Paper + // CraftBukkit start + world.captureTreeGeneration = true; + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/server/BlockStem.java b/src/main/java/net/minecraft/server/BlockStem.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/BlockStem.java ++++ b/src/main/java/net/minecraft/server/BlockStem.java +@@ -0,0 +0,0 @@ public class BlockStem extends BlockPlant implements IBlockFragilePlantElement { + + public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) { + super.b(world, blockposition, iblockdata, random); +- if (world.getLightLevel(blockposition.up()) >= 9) { ++ if (world.isLightLevel(blockposition.up(), 9)) { // Paper + float f = BlockCrops.a((Block) this, world, blockposition); + + if (random.nextInt((int) ((100 / (this == Blocks.PUMPKIN_STEM ? world.spigotConfig.pumpkinModifier : world.spigotConfig.melonModifier)) * (25.0F / f)) + 1) == 0) { // Spigot +diff --git a/src/main/java/net/minecraft/server/EntityMonster.java b/src/main/java/net/minecraft/server/EntityMonster.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/EntityMonster.java ++++ b/src/main/java/net/minecraft/server/EntityMonster.java +@@ -0,0 +0,0 @@ public abstract class EntityMonster extends EntityCreature implements IMonster { + if (this.world.b(EnumSkyBlock.SKY, blockposition) > this.random.nextInt(32)) { + return false; + } else { +- int i = this.world.getLightLevel(blockposition); +- ++ //int i = this.world.getLightLevel(blockposition); // Paper ++ boolean passes; // Paper + if (this.world.V()) { + int j = this.world.af(); + + this.world.c(10); +- i = this.world.getLightLevel(blockposition); ++ passes = world.isLightLevel(blockposition, this.random.nextInt(8)); // Paper + this.world.c(j); +- } ++ } else { passes = world.isLightLevel(blockposition, this.random.nextInt(8)); } // Paper + +- return i <= this.random.nextInt(8); ++ return passes; // Paper + } + } + +diff --git a/src/main/java/net/minecraft/server/EntityZombie.java b/src/main/java/net/minecraft/server/EntityZombie.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/EntityZombie.java ++++ b/src/main/java/net/minecraft/server/EntityZombie.java +@@ -0,0 +0,0 @@ public class EntityZombie extends EntityMonster { + int j1 = j + MathHelper.nextInt(this.random, 7, 40) * MathHelper.nextInt(this.random, -1, 1); + int k1 = k + MathHelper.nextInt(this.random, 7, 40) * MathHelper.nextInt(this.random, -1, 1); + +- if (this.world.getType(new BlockPosition(i1, j1 - 1, k1)).q() && this.world.getLightLevel(new BlockPosition(i1, j1, k1)) < 10) { ++ if (this.world.getType(new BlockPosition(i1, j1 - 1, k1)).q() && !this.world.isLightLevel(new BlockPosition(i1, j1, k1), 10)) { // Paper + entityzombie.setPosition((double) i1, (double) j1, (double) k1); + if (!this.world.isPlayerNearby((double) i1, (double) j1, (double) k1, 7.0D) && this.world.a(entityzombie.getBoundingBox(), (Entity) entityzombie) && this.world.getCubes(entityzombie, entityzombie.getBoundingBox()).isEmpty() && !this.world.containsLiquid(entityzombie.getBoundingBox())) { + this.world.addEntity(entityzombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit +-- \ No newline at end of file