Move patches around

This commit is contained in:
MiniDigger 2021-06-11 14:02:28 +02:00
parent 73bcb74f23
commit 4d225813a1
1895 changed files with 212111 additions and 0 deletions

View file

@ -0,0 +1,61 @@
From 656824f3d0c0f73417897c1ce3391a91849ec476 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Tue, 1 Mar 2016 14:27:13 -0600
Subject: [PATCH] Configurable speed for water flowing over lava
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 4da846719..d3484489b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -123,4 +123,10 @@ public class PaperWorldConfig {
if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf);
if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf);
}
+
+ public int waterOverLavaFlowSpeed;
+ private void waterOverLawFlowSpeed() {
+ waterOverLavaFlowSpeed = getInt("water-over-lava-flow-speed", 5);
+ log("Water over lava flow speed: " + waterOverLavaFlowSpeed);
+ }
}
diff --git a/src/main/java/net/minecraft/server/BlockFlowing.java b/src/main/java/net/minecraft/server/BlockFlowing.java
index 7b74df5b9..62234a7c9 100644
--- a/src/main/java/net/minecraft/server/BlockFlowing.java
+++ b/src/main/java/net/minecraft/server/BlockFlowing.java
@@ -30,7 +30,7 @@ public class BlockFlowing extends BlockFluids {
b0 = 2;
}
- int j = this.a(world);
+ int j = this.getFlowSpeed(world, blockposition); // Paper
int k;
if (i > 0) {
@@ -261,8 +261,22 @@ public class BlockFlowing extends BlockFluids {
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
if (!this.e(world, blockposition, iblockdata)) {
- world.a(blockposition, (Block) this, this.a(world));
+ world.a(blockposition, (Block) this, this.getFlowSpeed(world, blockposition)); // Paper
}
}
+
+ /**
+ * Paper - Get flow speed. Throttle if its water and flowing adjacent to lava
+ */
+ public int getFlowSpeed(World world, BlockPosition blockposition) {
+ if (this.material == Material.WATER && (
+ world.getType(blockposition.north(1)).getBlock().material == Material.LAVA ||
+ world.getType(blockposition.south(1)).getBlock().material == Material.LAVA ||
+ world.getType(blockposition.west(1)).getBlock().material == Material.LAVA ||
+ world.getType(blockposition.east(1)).getBlock().material == Material.LAVA)) {
+ return world.paperConfig.waterOverLavaFlowSpeed;
+ }
+ return super.a(world);
+ }
}
--
2.18.0

View file

@ -0,0 +1,312 @@
From e894331adaa569423be8472929da3a809c4106bb Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 02:17:54 -0600
Subject: [PATCH] Generator Settings
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index db09711e4..7e5cd8042 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -147,4 +147,34 @@ public class PaperWorldConfig {
disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false);
log("End credits disabled: " + disableEndCredits);
}
+
+ public boolean generateCanyon;
+ public boolean generateCaves;
+ public boolean generateDungeon;
+ public boolean generateFortress;
+ public boolean generateMineshaft;
+ public boolean generateMonument;
+ public boolean generateStronghold;
+ public boolean generateTemple;
+ public boolean generateVillage;
+ public boolean generateFlatBedrock;
+ public boolean disableExtremeHillsEmeralds;
+ public boolean disableExtremeHillsMonsterEggs;
+ public boolean disableMesaAdditionalGold;
+
+ private void generatorSettings() {
+ generateCanyon = getBoolean("generator-settings.canyon", true);
+ generateCaves = getBoolean("generator-settings.caves", true);
+ generateDungeon = getBoolean("generator-settings.dungeon", true);
+ generateFortress = getBoolean("generator-settings.fortress", true);
+ generateMineshaft = getBoolean("generator-settings.mineshaft", true);
+ generateMonument = getBoolean("generator-settings.monument", true);
+ generateStronghold = getBoolean("generator-settings.stronghold", true);
+ generateTemple = getBoolean("generator-settings.temple", true);
+ generateVillage = getBoolean("generator-settings.village", true);
+ generateFlatBedrock = getBoolean("generator-settings.flat-bedrock", false);
+ disableExtremeHillsEmeralds = getBoolean("generator-settings.disable-extreme-hills-emeralds", false);
+ disableExtremeHillsMonsterEggs = getBoolean("generator-settings.disable-extreme-hills-monster-eggs", false);
+ disableMesaAdditionalGold = getBoolean("generator-settings.disable-mesa-additional-gold", false);
+ }
}
diff --git a/src/main/java/net/minecraft/server/BiomeBase.java b/src/main/java/net/minecraft/server/BiomeBase.java
index 1b7599769..ab6db7468 100644
--- a/src/main/java/net/minecraft/server/BiomeBase.java
+++ b/src/main/java/net/minecraft/server/BiomeBase.java
@@ -176,7 +176,7 @@ public abstract class BiomeBase {
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
for (int l1 = 255; l1 >= 0; --l1) {
- if (l1 <= random.nextInt(5)) {
+ if (l1 <= (world.paperConfig.generateFlatBedrock ? 0 : random.nextInt(5))) { // Paper - Configurable flat bedrock
chunksnapshot.a(k1, l1, j1, BiomeBase.c);
} else {
IBlockData iblockdata2 = chunksnapshot.a(k1, l1, j1);
diff --git a/src/main/java/net/minecraft/server/BiomeBigHills.java b/src/main/java/net/minecraft/server/BiomeBigHills.java
index 9c39bf7af..61680ab50 100644
--- a/src/main/java/net/minecraft/server/BiomeBigHills.java
+++ b/src/main/java/net/minecraft/server/BiomeBigHills.java
@@ -32,6 +32,9 @@ public class BiomeBigHills extends BiomeBase {
int k;
int l;
+ // Paper start - Disable extreme hills emeralds
+ if (!world.paperConfig.disableExtremeHillsEmeralds) {
+
for (j = 0; j < i; ++j) {
k = random.nextInt(16);
l = random.nextInt(28) + 4;
@@ -43,6 +46,12 @@ public class BiomeBigHills extends BiomeBase {
}
}
+ }
+ // Paper end block
+
+ // Paper start - Disable extreme hills monster eggs
+ if (!world.paperConfig.disableExtremeHillsMonsterEggs) {
+
for (i = 0; i < 7; ++i) {
j = random.nextInt(16);
k = random.nextInt(64);
@@ -50,6 +59,9 @@ public class BiomeBigHills extends BiomeBase {
this.x.generate(world, random, blockposition.a(j, k, l));
}
+ }
+ // Paper end block
+
}
public void a(World world, Random random, ChunkSnapshot chunksnapshot, int i, int j, double d0) {
diff --git a/src/main/java/net/minecraft/server/BiomeMesa.java b/src/main/java/net/minecraft/server/BiomeMesa.java
index f2dd96a32..67f8ad8ed 100644
--- a/src/main/java/net/minecraft/server/BiomeMesa.java
+++ b/src/main/java/net/minecraft/server/BiomeMesa.java
@@ -99,7 +99,7 @@ public class BiomeMesa extends BiomeBase {
chunksnapshot.a(l, i2, k, BiomeMesa.a);
}
- if (i2 <= random.nextInt(5)) {
+ if (i2 <= (world.paperConfig.generateFlatBedrock ? 0 : random.nextInt(5))) { // Paper - Configurable flat bedrock
chunksnapshot.a(l, i2, k, BiomeMesa.c);
} else if (l1 < 15 || this.I) {
IBlockData iblockdata2 = chunksnapshot.a(l, i2, k);
@@ -259,6 +259,7 @@ public class BiomeMesa extends BiomeBase {
protected void a(World world, Random random) {
super.a(world, random);
+ if (world.paperConfig.disableMesaAdditionalGold) return; // Paper
this.a(world, random, 20, this.n, 32, 80);
}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderFlat.java b/src/main/java/net/minecraft/server/ChunkProviderFlat.java
index 1452ff657..8b1b79380 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderFlat.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderFlat.java
@@ -26,7 +26,7 @@ public class ChunkProviderFlat implements ChunkGenerator {
if (flag) {
Map map = this.d.b();
- if (map.containsKey("village")) {
+ if (map.containsKey("village") && world.paperConfig.generateVillage) { // Paper
Map map1 = (Map) map.get("village");
if (!map1.containsKey("size")) {
@@ -36,19 +36,19 @@ public class ChunkProviderFlat implements ChunkGenerator {
this.e.put("Village", new WorldGenVillage(map1));
}
- if (map.containsKey("biome_1")) {
+ if (map.containsKey("biome_1") && world.paperConfig.generateTemple) { // Paper
this.e.put("Temple", new WorldGenLargeFeature((Map) map.get("biome_1")));
}
- if (map.containsKey("mineshaft")) {
+ if (map.containsKey("mineshaft") && world.paperConfig.generateMineshaft) { // Paper
this.e.put("Mineshaft", new WorldGenMineshaft((Map) map.get("mineshaft")));
}
- if (map.containsKey("stronghold")) {
+ if (map.containsKey("stronghold") && world.paperConfig.generateStronghold) { // Paper
this.e.put("Stronghold", new WorldGenStronghold((Map) map.get("stronghold")));
}
- if (map.containsKey("oceanmonument")) {
+ if (map.containsKey("oceanmonument") && world.paperConfig.generateMonument) { // Paper
this.e.put("Monument", new WorldGenMonument((Map) map.get("oceanmonument")));
}
}
@@ -61,7 +61,7 @@ public class ChunkProviderFlat implements ChunkGenerator {
this.i = new WorldGenLakes(Blocks.LAVA);
}
- this.g = this.d.b().containsKey("dungeon");
+ this.g = world.paperConfig.generateDungeon && this.d.b().containsKey("dungeon"); // Paper
int j = 0;
int k = 0;
boolean flag1 = true;
diff --git a/src/main/java/net/minecraft/server/ChunkProviderGenerate.java b/src/main/java/net/minecraft/server/ChunkProviderGenerate.java
index 22a24a39f..ee9e00e64 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderGenerate.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderGenerate.java
@@ -160,32 +160,32 @@ public class ChunkProviderGenerate implements ChunkGenerator {
this.a(i, j, chunksnapshot);
this.D = this.n.getWorldChunkManager().getBiomeBlock(this.D, i * 16, j * 16, 16, 16);
this.a(i, j, chunksnapshot, this.D);
- if (this.s.r) {
+ if (this.s.r && this.n.paperConfig.generateCaves) { // Paper
this.v.a(this.n, i, j, chunksnapshot);
}
- if (this.s.A) {
+ if (this.s.A && this.n.paperConfig.generateCanyon) { // Paper
this.A.a(this.n, i, j, chunksnapshot);
}
if (this.o) {
- if (this.s.w) {
+ if (this.s.w && this.n.paperConfig.generateMineshaft) { // Paper
this.y.a(this.n, i, j, chunksnapshot);
}
- if (this.s.v) {
+ if (this.s.v&& this.n.paperConfig.generateVillage) { // Paper
this.x.a(this.n, i, j, chunksnapshot);
}
- if (this.s.u) {
+ if (this.s.u && this.n.paperConfig.generateStronghold) { // Paper
this.w.a(this.n, i, j, chunksnapshot);
}
- if (this.s.x) {
+ if (this.s.x && this.n.paperConfig.generateTemple) { // Paper
this.z.a(this.n, i, j, chunksnapshot);
}
- if (this.s.y) {
+ if (this.s.y && this.n.paperConfig.generateMonument) { // Paper
this.B.a(this.n, i, j, chunksnapshot);
}
@@ -329,23 +329,23 @@ public class ChunkProviderGenerate implements ChunkGenerator {
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
if (this.o) {
- if (this.s.w) {
+ if (this.s.w && this.n.paperConfig.generateMineshaft) { // Paper
this.y.a(this.n, this.i, chunkcoordintpair);
}
- if (this.s.v) {
+ if (this.s.v && this.n.paperConfig.generateVillage) { // Paper
flag = this.x.a(this.n, this.i, chunkcoordintpair);
}
- if (this.s.u) {
+ if (this.s.u && this.n.paperConfig.generateStronghold) { // Paper
this.w.a(this.n, this.i, chunkcoordintpair);
}
- if (this.s.x) {
+ if (this.s.x && this.n.paperConfig.generateTemple) { // Paper
this.z.a(this.n, this.i, chunkcoordintpair);
}
- if (this.s.y) {
+ if (this.s.y && this.n.paperConfig.generateMonument) { // Paper
this.B.a(this.n, this.i, chunkcoordintpair);
}
@@ -374,7 +374,7 @@ public class ChunkProviderGenerate implements ChunkGenerator {
}
}
- if (this.s.s) {
+ if (this.s.s && this.n.paperConfig.generateDungeon) { // Paper
for (k1 = 0; k1 < this.s.t; ++k1) {
l1 = this.i.nextInt(16) + 8;
i2 = this.i.nextInt(256);
@@ -443,23 +443,23 @@ public class ChunkProviderGenerate implements ChunkGenerator {
public void recreateStructures(Chunk chunk, int i, int j) {
if (this.o) {
- if (this.s.w) {
+ if (this.s.w && this.n.paperConfig.generateMineshaft) { // Paper
this.y.a(this.n, i, j, (ChunkSnapshot) null);
}
- if (this.s.v) {
+ if (this.s.v && this.n.paperConfig.generateVillage) { // Paper
this.x.a(this.n, i, j, (ChunkSnapshot) null);
}
- if (this.s.u) {
+ if (this.s.u && this.n.paperConfig.generateStronghold) { // Paper
this.w.a(this.n, i, j, (ChunkSnapshot) null);
}
- if (this.s.x) {
+ if (this.s.x && this.n.paperConfig.generateTemple) { // Paper
this.z.a(this.n, i, j, (ChunkSnapshot) null);
}
- if (this.s.y) {
+ if (this.s.y && this.n.paperConfig.generateMonument) { // Paper
this.B.a(this.n, i, j, (ChunkSnapshot) null);
}
diff --git a/src/main/java/net/minecraft/server/ChunkProviderHell.java b/src/main/java/net/minecraft/server/ChunkProviderHell.java
index 9f738749f..12bc10ff0 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderHell.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderHell.java
@@ -151,7 +151,10 @@ public class ChunkProviderHell implements ChunkGenerator {
IBlockData iblockdata1 = ChunkProviderHell.b;
for (int l1 = 127; l1 >= 0; --l1) {
- if (l1 < 127 - this.p.nextInt(5) && l1 > this.p.nextInt(5)) {
+ // Paper start - Configurable flat bedrock worldgen
+ if (l1 < 127 - (n.paperConfig.generateFlatBedrock ? 0 : this.p.nextInt(5)) &&
+ l1 > (n.paperConfig.generateFlatBedrock ? 0 : this.p.nextInt(5))) {
+ // Paper end
IBlockData iblockdata2 = chunksnapshot.a(i1, l1, l);
if (iblockdata2.getBlock() != null && iblockdata2.getMaterial() != Material.AIR) {
@@ -384,6 +387,6 @@ public class ChunkProviderHell implements ChunkGenerator {
}
public void recreateStructures(Chunk chunk, int i, int j) {
- this.I.a(this.n, i, j, (ChunkSnapshot) null);
+ if (this.n.paperConfig.generateFortress) this.I.a(this.n, i, j, (ChunkSnapshot) null);
}
}
diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java
index 66a80a776..34fd7edfe 100644
--- a/src/main/java/net/minecraft/server/StructureGenerator.java
+++ b/src/main/java/net/minecraft/server/StructureGenerator.java
@@ -128,6 +128,7 @@ public abstract class StructureGenerator extends WorldGenBase {
}
public boolean a(World world, BlockPosition blockposition) {
+ if (this.g == null) return false; // Paper
this.a(world);
ObjectIterator objectiterator = this.c.values().iterator();
--
2.18.0

View file

@ -0,0 +1,21 @@
From b347181112d7dd6655c11bbd324a2a4c62e9507d Mon Sep 17 00:00:00 2001
From: Iceee <andrew@opticgaming.tv>
Date: Wed, 2 Mar 2016 12:03:23 -0600
Subject: [PATCH] Stop updating flowing block if material has changed
diff --git a/src/main/java/net/minecraft/server/BlockFlowing.java b/src/main/java/net/minecraft/server/BlockFlowing.java
index 62234a7c9..3b47253a4 100644
--- a/src/main/java/net/minecraft/server/BlockFlowing.java
+++ b/src/main/java/net/minecraft/server/BlockFlowing.java
@@ -90,6 +90,7 @@ public class BlockFlowing extends BlockFluids {
this.f(world, blockposition, iblockdata);
}
+ if (world.getType(blockposition).getBlock().getBlockData().getMaterial() != material) return; // Paper - Stop updating flowing block if material has changed
org.bukkit.block.Block source = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); // CraftBukkit
IBlockData iblockdata2 = world.getType(blockposition.down());
--
2.18.0

View file

@ -0,0 +1,113 @@
From 4b300fd41621071f122933ad9400521cb46228a0 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 12:20:52 -0600
Subject: [PATCH] Fast draining
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 15675efbf..dbd82d5a9 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -183,4 +183,11 @@ public class PaperWorldConfig {
optimizeExplosions = getBoolean("optimize-explosions", false);
log("Optimize explosions: " + optimizeExplosions);
}
+
+ public boolean fastDrainLava;
+ public boolean fastDrainWater;
+ private void fastDrain() {
+ fastDrainLava = getBoolean("fast-drain.lava", false);
+ fastDrainWater = getBoolean("fast-drain.water", false);
+ }
}
diff --git a/src/main/java/net/minecraft/server/BlockFlowing.java b/src/main/java/net/minecraft/server/BlockFlowing.java
index 3b47253a4..3aaa19b2f 100644
--- a/src/main/java/net/minecraft/server/BlockFlowing.java
+++ b/src/main/java/net/minecraft/server/BlockFlowing.java
@@ -69,7 +69,7 @@ public class BlockFlowing extends BlockFluids {
}
}
- if (this.material == Material.LAVA && i < 8 && i1 < 8 && i1 > i && random.nextInt(4) != 0) {
+ if (!world.paperConfig.fastDrainLava && this.material == Material.LAVA && i < 8 && i1 < 8 && i1 > i && random.nextInt(4) != 0) { // Paper
j *= 4;
}
@@ -77,7 +77,7 @@ public class BlockFlowing extends BlockFluids {
this.f(world, blockposition, iblockdata);
} else {
i = i1;
- if (i1 < 0) {
+ if (i1 < 0 || canFastDrain(world, blockposition)) { // Paper - Fast draining
world.setAir(blockposition);
} else {
iblockdata = iblockdata.set(BlockFlowing.LEVEL, Integer.valueOf(i1));
@@ -267,6 +267,7 @@ public class BlockFlowing extends BlockFluids {
}
+ // Paper start
/**
* Paper - Get flow speed. Throttle if its water and flowing adjacent to lava
*/
@@ -280,4 +281,57 @@ public class BlockFlowing extends BlockFluids {
}
return super.a(world);
}
+
+ private int getFluidLevel(IBlockAccess iblockaccess, BlockPosition blockposition) {
+ return iblockaccess.getType(blockposition).getMaterial() == this.material ? iblockaccess.getType(blockposition).get(BlockFluids.LEVEL) : -1;
+ }
+
+ /**
+ * Paper - Data check method for fast draining
+ */
+ public int getData(World world, BlockPosition position) {
+ int data = this.getFluidLevel((IBlockAccess) world, position);
+ return data < 8 ? data : 0;
+ }
+
+ /**
+ * Paper - Checks surrounding blocks to determine if block can be fast drained
+ */
+ public boolean canFastDrain(World world, BlockPosition position) {
+ boolean result = false;
+ int data = getData(world, position);
+ if (this.material == Material.WATER) {
+ if (world.paperConfig.fastDrainWater) {
+ result = true;
+ if (getData(world, position.down()) < 0) {
+ result = false;
+ } else if (world.getType(position.north()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.north()) < data) {
+ result = false;
+ } else if (world.getType(position.south()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.south()) < data) {
+ result = false;
+ } else if (world.getType(position.west()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.west()) < data) {
+ result = false;
+ } else if (world.getType(position.east()).getBlock().getBlockData().getMaterial() == Material.WATER && getData(world, position.east()) < data) {
+ result = false;
+ }
+ }
+ } else if (this.material == Material.LAVA) {
+ if (world.paperConfig.fastDrainLava) {
+ result = true;
+ if (getData(world, position.down()) < 0 || world.getType(position.up()).getBlock().getBlockData().getMaterial() != Material.AIR) {
+ result = false;
+ } else if (world.getType(position.north()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.north()) < data) {
+ result = false;
+ } else if (world.getType(position.south()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.south()) < data) {
+ result = false;
+ } else if (world.getType(position.west()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.west()) < data) {
+ result = false;
+ } else if (world.getType(position.east()).getBlock().getBlockData().getMaterial() == Material.LAVA && getData(world, position.east()) < data) {
+ result = false;
+ }
+ }
+ }
+ return result;
+ }
+ // Paper end
}
--
2.18.0

View file

@ -0,0 +1,87 @@
From fe8bd60fe7b27283c696a5b746414187695174b0 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Wed, 2 Mar 2016 23:13:07 -0600
Subject: [PATCH] Send absolute position the first time an entity is seen
diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
index dd6c84b4a2..de0cf6b735 100644
--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java
+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
@@ -41,7 +41,19 @@ public class EntityTrackerEntry {
private boolean x;
private boolean y;
public boolean b;
- public final Set<EntityPlayer> trackedPlayers = Sets.newHashSet();
+ // Paper start
+ // Replace trackedPlayers Set with a Map. The value is true until the player receives
+ // their first update (which is forced to have absolute coordinates), false afterward.
+ public java.util.Map<EntityPlayer, Boolean> trackedPlayerMap = new java.util.HashMap<EntityPlayer, Boolean>();
+ public Set<EntityPlayer> trackedPlayers = trackedPlayerMap.keySet();
+
+ /**
+ * Requested in https://github.com/PaperMC/Paper/issues/1537 to allow intercepting packets
+ */
+ public void sendPlayerPacket(EntityPlayer player, Packet packet) {
+ player.playerConnection.sendPacket(packet);
+ }
+ // Paper end
public EntityTrackerEntry(Entity entity, int i, int j, int k, boolean flag) {
this.tracker = entity;
@@ -142,6 +154,7 @@ public class EntityTrackerEntry {
boolean flag1 = l1 * l1 + i2 * i2 + j2 * j2 >= 128L || this.a % 60 == 0;
boolean flag2 = Math.abs(j1 - this.yRot) >= 1 || Math.abs(k1 - this.xRot) >= 1;
+ if (this.a > 0 || this.tracker instanceof EntityArrow) { // Paper - Moved up
// CraftBukkit start - Code moved from below
if (flag1) {
this.xLoc = k;
@@ -155,7 +168,6 @@ public class EntityTrackerEntry {
}
// CraftBukkit end
- if (this.a > 0 || this.tracker instanceof EntityArrow) {
if (l1 >= -32768L && l1 < 32768L && i2 >= -32768L && i2 < 32768L && j2 >= -32768L && j2 < 32768L && this.v <= 400 && !this.x && this.y == this.tracker.onGround) {
if ((!flag1 || !flag2) && !(this.tracker instanceof EntityArrow)) {
if (flag1) {
@@ -201,7 +213,26 @@ public class EntityTrackerEntry {
}
if (packet1 != null) {
- this.broadcast((Packet) packet1);
+ // Paper start - ensure fresh viewers get an absolute position on their first update,
+ // since we can't be certain what position they received in the spawn packet.
+ if (packet1 instanceof PacketPlayOutEntityTeleport) {
+ this.broadcast((Packet) packet1);
+ } else {
+ PacketPlayOutEntityTeleport teleportPacket = null;
+
+ for (java.util.Map.Entry<EntityPlayer, Boolean> viewer : trackedPlayerMap.entrySet()) {
+ if (viewer.getValue()) {
+ viewer.setValue(false);
+ if (teleportPacket == null) {
+ teleportPacket = new PacketPlayOutEntityTeleport(this.tracker);
+ }
+ sendPlayerPacket(viewer.getKey(), teleportPacket);
+ } else {
+ sendPlayerPacket(viewer.getKey(), (Packet) packet1);
+ }
+ }
+ }
+ // Paper end
}
this.d();
@@ -338,7 +369,7 @@ public class EntityTrackerEntry {
entityplayer.removeQueue.remove(Integer.valueOf(this.tracker.getId()));
// CraftBukkit end
- this.trackedPlayers.add(entityplayer);
+ this.trackedPlayerMap.put(entityplayer, true); // Paper
Packet<?> packet = this.e();
entityplayer.playerConnection.sendPacket(packet);
--
2.21.0

View file

@ -0,0 +1,52 @@
From 8a9b221bcd755747f0e03bb84f9ba7403eaac7fd Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 22:03:09 -0400
Subject: [PATCH] Prevent Waterflow BlockFromToEvent from loading chunks
Many protection plugins would unintentionally trigger chunk loads
by calling .getToBlock() on an unloaded chunk, killing performance.
Simply skip the event call. as CraftBukkit blocks changing the block
of unloaded chunks anyways.
This keeps behavior consistent, vs inconsistent flowing based on plugin triggered loads.
diff --git a/src/main/java/net/minecraft/server/BlockFlowing.java b/src/main/java/net/minecraft/server/BlockFlowing.java
index 739b9aac3..ff90e08eb 100644
--- a/src/main/java/net/minecraft/server/BlockFlowing.java
+++ b/src/main/java/net/minecraft/server/BlockFlowing.java
@@ -96,6 +96,7 @@ public class BlockFlowing extends BlockFluids {
if (this.h(world, blockposition.down(), iblockdata2)) {
// CraftBukkit start
+ if (!canFlowTo(world, source, BlockFace.DOWN)) { return; } // Paper
BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN);
world.getServer().getPluginManager().callEvent(event);
@@ -136,6 +137,7 @@ public class BlockFlowing extends BlockFluids {
EnumDirection enumdirection1 = (EnumDirection) iterator1.next();
// CraftBukkit start
+ if (!canFlowTo(world, source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1))) { continue; } // Paper
BlockFromToEvent event = new BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1));
world.getServer().getPluginManager().callEvent(event);
@@ -148,8 +150,14 @@ public class BlockFlowing extends BlockFluids {
}
+ // Paper start
+ private boolean canFlowTo(World world, org.bukkit.block.Block source, BlockFace face) {
+ return source.getWorld().isChunkLoaded((source.getX() + face.getModX()) >> 4, (source.getZ() + face.getModZ()) >> 4);
+ }
+ // Paper end
+
private void flow(World world, BlockPosition blockposition, IBlockData iblockdata, int i) {
- if (world.isLoaded(blockposition) && this.h(world, blockposition, iblockdata)) { // CraftBukkit - add isLoaded check
+ if (/*world.isLoaded(blockposition) &&*/ this.h(world, blockposition, iblockdata)) { // CraftBukkit - add isLoaded check // Paper - Already checked before we get here for isLoaded
if (iblockdata.getMaterial() != Material.AIR) {
if (this.material == Material.LAVA) {
this.fizz(world, blockposition);
--
2.18.0

View file

@ -0,0 +1,30 @@
From 3f31cdecde77021afea54370f1fb31ef0621b59f Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 14 Apr 2016 17:48:56 -0500
Subject: [PATCH] Water mobs should only spawn in the water
diff --git a/src/main/java/net/minecraft/server/EntityWaterAnimal.java b/src/main/java/net/minecraft/server/EntityWaterAnimal.java
index f430bdeec..0597edad6 100644
--- a/src/main/java/net/minecraft/server/EntityWaterAnimal.java
+++ b/src/main/java/net/minecraft/server/EntityWaterAnimal.java
@@ -11,7 +11,15 @@ public abstract class EntityWaterAnimal extends EntityInsentient implements IAni
}
public boolean P() {
- return true;
+ // Paper start - Don't let water mobs spawn in non-water blocks
+ // Based around EntityAnimal's implementation
+ int i = MathHelper.floor(this.locX);
+ int j = MathHelper.floor(this.getBoundingBox().b); // minY of bounding box
+ int k = MathHelper.floor(this.locZ);
+ Block block = this.world.getType(new BlockPosition(i, j, k)).getBlock();
+
+ return block == Blocks.WATER || block == Blocks.FLOWING_WATER;
+ // Paper end
}
public boolean canSpawn() {
--
2.18.0

View file

@ -0,0 +1,55 @@
From 7e347eb480cfb1eecd76b0c6fbc08090e439f8d5 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sun, 24 Apr 2016 19:49:33 -0500
Subject: [PATCH] SPIGOT-1401: Fix dispenser, dropper, furnace placement
diff --git a/src/main/java/net/minecraft/server/BlockDispenser.java b/src/main/java/net/minecraft/server/BlockDispenser.java
index 8e794976a..539b2b3ce 100644
--- a/src/main/java/net/minecraft/server/BlockDispenser.java
+++ b/src/main/java/net/minecraft/server/BlockDispenser.java
@@ -20,6 +20,9 @@ public class BlockDispenser extends BlockTileEntity {
return 4;
}
+ // Paper start - Removed override of onPlace that was reversing placement direction when
+ // adjacent to another block, which was not consistent with single player block placement
+ /*
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
super.onPlace(world, blockposition, iblockdata);
this.e(world, blockposition, iblockdata);
@@ -49,6 +52,8 @@ public class BlockDispenser extends BlockTileEntity {
world.setTypeAndData(blockposition, iblockdata.set(BlockDispenser.FACING, enumdirection).set(BlockDispenser.TRIGGERED, Boolean.valueOf(false)), 2);
}
}
+ */
+ // Paper end
public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, EnumDirection enumdirection, float f, float f1, float f2) {
if (world.isClientSide) {
diff --git a/src/main/java/net/minecraft/server/BlockFurnace.java b/src/main/java/net/minecraft/server/BlockFurnace.java
index b6834d2d1..dae711708 100644
--- a/src/main/java/net/minecraft/server/BlockFurnace.java
+++ b/src/main/java/net/minecraft/server/BlockFurnace.java
@@ -18,6 +18,9 @@ public class BlockFurnace extends BlockTileEntity {
return Item.getItemOf(Blocks.FURNACE);
}
+ // Paper start - Removed override of onPlace that was reversing placement direction when
+ // adjacent to another block, which was not consistent with single player block placement
+ /*
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
this.e(world, blockposition, iblockdata);
}
@@ -43,6 +46,8 @@ public class BlockFurnace extends BlockTileEntity {
world.setTypeAndData(blockposition, iblockdata.set(BlockFurnace.FACING, enumdirection), 2);
}
}
+ */
+ // Paper end
public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, EnumDirection enumdirection, float f, float f1, float f2) {
if (world.isClientSide) {
--
2.18.0

View file

@ -0,0 +1,83 @@
From cbe35161f2e8a59c22aca9a0d5412674d128df41 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 21 Mar 2018 19:57:10 -0400
Subject: [PATCH] Configurable Unrestricted Signs
Bukkit restricts command execution of signs to test if the sender
has permission to run the specified command. This breaks vanilla
maps that use signs to intentionally run as elevated permission.
Bukkit provides an unrestricted advancements setting, so this setting
compliments that one and allows for unrestricted signs.
We still filter sign update packets to strip out commands at edit phase,
however there is no sanity in ever expecting creative mode to not be
able to create signs with any command.
Creative servers should absolutely never enable this.
Non creative servers, enable at own risk!!!
diff --git a/src/main/java/net/minecraft/server/TileEntitySign.java b/src/main/java/net/minecraft/server/TileEntitySign.java
index 3f2c5b2d5..67bd3bcbe 100644
--- a/src/main/java/net/minecraft/server/TileEntitySign.java
+++ b/src/main/java/net/minecraft/server/TileEntitySign.java
@@ -38,7 +38,7 @@ public class TileEntitySign extends TileEntity {
public void load(NBTTagCompound nbttagcompound) {
this.isEditable = false;
super.load(nbttagcompound);
- ICommandListener icommandlistener = new ICommandListener() {
+ ICommandListener icommandlistener = new ISignCommandListener() { // Paper
public String getName() {
return "Sign";
}
@@ -125,7 +125,7 @@ public class TileEntitySign extends TileEntity {
}
public boolean b(final EntityHuman entityhuman) {
- ICommandListener icommandlistener = new ICommandListener() {
+ ICommandListener icommandlistener = new ISignCommandListener() { // Paper
public String getName() {
return entityhuman.getName();
}
@@ -200,4 +200,5 @@ public class TileEntitySign extends TileEntity {
public CommandObjectiveExecutor f() {
return this.i;
}
+ public interface ISignCommandListener extends ICommandListener {} // Paper
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index e86c16755..6095948e8 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -175,6 +175,7 @@ public final class CraftServer implements Server {
private CraftIconCache icon;
private boolean overrideAllCommandBlockCommands = false;
private boolean unrestrictedAdvancements;
+ private boolean unrestrictedSignCommands; // Paper
private final List<CraftPlayer> playerView;
public int reloadCount;
public static Exception excessiveVelEx; // Paper - Velocity warnings
@@ -253,6 +254,12 @@ public final class CraftServer implements Server {
saveCommandsConfig();
overrideAllCommandBlockCommands = commandsConfiguration.getStringList("command-block-overrides").contains("*");
unrestrictedAdvancements = commandsConfiguration.getBoolean("unrestricted-advancements");
+ // Paper start
+ unrestrictedSignCommands = commandsConfiguration.getBoolean("unrestricted-signs");
+ if (unrestrictedSignCommands) {
+ logger.warning("Warning: Commands are no longer restricted on signs. If you allow players to use Creative Mode, there may be risk of players bypassing permissions. Use this setting at your own risk!!!!");
+ }
+ // Paper end
pluginManager.useTimings(configuration.getBoolean("settings.plugin-profiling"));
monsterSpawn = configuration.getInt("spawn-limits.monsters");
animalSpawn = configuration.getInt("spawn-limits.animals");
@@ -270,6 +277,7 @@ public final class CraftServer implements Server {
listener = ((CommandListenerWrapper) listener).base;
}
+ if (unrestrictedSignCommands && listener instanceof TileEntitySign.ISignCommandListener) return true; // Paper
return unrestrictedAdvancements && listener instanceof AdvancementRewards.AdvancementCommandListener;
}
--
2.18.0

View file

@ -0,0 +1,218 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 25 May 2020 11:02:42 -0400
Subject: [PATCH] Unload leaked Cached Chunks
Due to some complexity in mojangs complicated chain of juggling
whether or not a chunk should be unloaded when the last ticket is
removed, many chunks are remaining around in the cache.
These chunks are never being targetted for unload because they are
vastly out of view distance range and have no reason to be looked at.
This is a huge issue for performance because we have to iterate these
chunks EVERY TICK... This is what's been leading to high SELF time in
Ticking Chunks timings/profiler results.
We will now detect these chunks in that iteration, and automatically
add it to the unload queue when the chunk is found without any tickets.
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
index 9805361e2d49fa1cfecf0c5811187fc503d0ad8e..62ed8e653c2060c314b407f698842e9c7c3312c0 100644
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
@@ -33,7 +33,7 @@ public abstract class ChunkMapDistance {
public final Long2ObjectOpenHashMap<ArraySetSorted<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
private final ChunkMapDistance.a e = new ChunkMapDistance.a();
public static final int MOB_SPAWN_RANGE = 8; //private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
- private final ChunkMapDistance.c g = new ChunkMapDistance.c(33);
+ private final ChunkMapDistance.c g = new ChunkMapDistance.c(33); public final ChunkMapDistance.c getLevelTracker() { return g; } // Paper
// Paper start use a queue, but still keep unique requirement
public final java.util.Queue<PlayerChunk> pendingChunkUpdates = new java.util.ArrayDeque<PlayerChunk>() {
@Override
@@ -478,7 +478,7 @@ public abstract class ChunkMapDistance {
if (flag1) {
ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error
ChunkMapDistance.this.m.execute(() -> {
- if (this.c(this.c(i))) {
+ if (this.c(this.c(i))) { // Paper - diff above isChunkLoaded
ChunkMapDistance.this.addTicket(i, ticket);
ChunkMapDistance.this.l.add(i);
} else {
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 54e89c9cc6c47ff2c4f4dd5d4c22a391f8a3d6e0..144e91b303cbd9c58c9e6d598e9c9334f2a75c73 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -560,6 +560,7 @@ public class ChunkProviderServer extends IChunkProvider {
}
}
// Paper start
+ if (playerchunk != null) playerchunk.lastActivity = world.getTime(); // Paper
CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> future = this.a(playerchunk, l) ? PlayerChunk.UNLOADED_CHUNK_ACCESS_FUTURE : playerchunk.a(chunkstatus, this.playerChunkMap);
if (isUrgent) {
future.thenAccept(either -> this.chunkMapDistance.clearUrgent(chunkcoordintpair));
@@ -812,6 +813,7 @@ public class ChunkProviderServer extends IChunkProvider {
this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings
this.world.getMethodProfiler().exit();
// Paper - replaced by above
+ final long time = world.getTime(); // Paper
final int[] chunksTicked = {0}; this.playerChunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping
Optional<Chunk> optional = ((Either) playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
@@ -897,7 +899,7 @@ public class ChunkProviderServer extends IChunkProvider {
this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper
if (chunksTicked[0]++ % 10 == 0) this.world.getMinecraftServer().midTickLoadChunks(); // Paper
}
- }
+ } else { checkInactiveChunk(playerchunk, time); } // Paper - check inaccessible chunks
});
this.world.getMethodProfiler().enter("customSpawners");
if (flag1) {
@@ -913,6 +915,30 @@ public class ChunkProviderServer extends IChunkProvider {
this.playerChunkMap.g();
}
+ // Paper start - remove inaccessible chunks leaked
+ private void checkInactiveChunk(PlayerChunk playerchunk, long time) {
+ int ticketLevel = playerchunk.getTicketLevel();
+ if (ticketLevel > 33 && ticketLevel == playerchunk.oldTicketLevel &&
+ (playerchunk.lastActivity == 0 || time - playerchunk.lastActivity > 20*120) &&
+ playerchunk.location.pair() % 20 == 0 && playerChunkMap.unloadQueue.size() < 100
+ ) {
+ ChunkStatus chunkHolderStatus = playerchunk.getChunkHolderStatus();
+ ChunkStatus desiredStatus = PlayerChunk.getChunkStatus(ticketLevel);
+ if (chunkHolderStatus != null && !chunkHolderStatus.isAtLeastStatus(desiredStatus)) {
+ return;
+ }
+ if (playerchunk.lastActivity == 0) {
+ playerchunk.lastActivity = time;
+ return;
+ }
+ playerchunk.lastActivity = time;
+ if (playerchunk.shouldBeUnloaded()) {
+ playerChunkMap.unloadQueue.add(playerchunk.location.pair());
+ }
+ }
+ }
+ // Paper end
+
@Override
public String getName() {
return "ServerChunkCache: " + this.h();
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index b8fe42e8123e972b1ec97b048c35d90118076e66..18f9a2590f7fa5dfc9070fc5e13121d77f06e79f 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -44,6 +44,22 @@ public class PlayerChunk {
long lastAutoSaveTime; // Paper - incremental autosave
long inactiveTimeStart; // Paper - incremental autosave
+ // Paper start - unload leaked chunks
+ long lastActivity;
+ java.util.concurrent.ConcurrentHashMap<ChunkCoordIntPair, Boolean> dependendedOnBy = new java.util.concurrent.ConcurrentHashMap<>();
+ public boolean shouldBeUnloaded() {
+ if (!neighborPriorities.isEmpty() || !dependendedOnBy.isEmpty()) {
+ return false;
+ }
+ long key = location.pair();
+ if (chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(key) != null) {
+ return false;
+ }
+ PlayerChunkMap.a distanceManager = chunkMap.chunkDistanceManager;
+ ArraySetSorted<Ticket<?>> tickets = distanceManager.tickets.get(key);
+ return (tickets == null || tickets.isEmpty()) TODO: Figure out level map;
+ }
+ // Paper end
// Paper start - optimise isOutsideOfRange
// cached here to avoid a map lookup
@@ -562,6 +578,7 @@ public class PlayerChunk {
protected void a(PlayerChunkMap playerchunkmap) {
ChunkStatus chunkstatus = getChunkStatus(this.oldTicketLevel);
ChunkStatus chunkstatus1 = getChunkStatus(this.ticketLevel);
+ if (oldTicketLevel != ticketLevel) lastActivity = chunkMap.world.getTime(); // Paper - chunk leak
boolean flag = this.oldTicketLevel <= PlayerChunkMap.GOLDEN_TICKET;
boolean flag1 = this.ticketLevel <= PlayerChunkMap.GOLDEN_TICKET; // Paper - diff on change: (flag1 = new ticket level is in loadable range)
PlayerChunk.State playerchunk_state = getChunkState(this.oldTicketLevel);
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index f42507f5a17f9388db738218f58ca76f863274ff..9ee13c741fdcc6b40d175e375e61bffa4c14f45f 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -639,6 +639,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}
}));
}
+ playerchunk.lastActivity = world.getTime(); // Paper - chunk leak
ChunkStatus chunkstatus = (ChunkStatus) intfunction.apply(j1);
CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture = playerchunk.a(chunkstatus, this);
@@ -646,6 +647,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
if (requestingNeighbor != null && requestingNeighbor != playerchunk && !completablefuture.isDone()) {
requestingNeighbor.onNeighborRequest(playerchunk, chunkstatus);
completablefuture.thenAccept(either -> {
+ playerchunk.lastActivity = world.getTime(); // Paper - chunk leak
requestingNeighbor.onNeighborDone(playerchunk, chunkstatus, either.left().orElse(null));
});
}
@@ -874,6 +876,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
PlayerChunk playerchunk = (PlayerChunk) this.updatingChunks.remove(j);
if (playerchunk != null) {
+ // Paper start - don't unload chunks that should be loaded
+ if (!playerchunk.shouldBeUnloaded()) {
+ this.updatingChunks.put(j, playerchunk);
+ continue;
+ }
+ // Paper end
this.pendingUnload.put(j, playerchunk);
this.updatingChunksModified = true;
this.a(j, playerchunk); // Paper - Move up - don't leak chunks
@@ -1147,9 +1155,27 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return completablefuture.thenComposeAsync((either) -> {
return either.map((list) -> { // Paper - Shut up.
try {
+ // Paper start
+ list.forEach(chunk -> {
+ PlayerChunk updatingChunk = getUpdatingChunk(chunk.getPos().pair());
+ if (updatingChunk != null) {
+ updatingChunk.dependendedOnBy.put(playerchunk.location, true);
+ updatingChunk.lastActivity = world.getTime();
+ }
+ });
+ // Paper end
CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture1 = chunkstatus.a(this.world, this.chunkGenerator, this.definedStructureManager, this.lightEngine, (ichunkaccess) -> {
return this.c(playerchunk);
}, list);
+ // Paper start
+ completablefuture1.whenComplete((unused, unused2) -> list.forEach(chunk -> {
+ PlayerChunk updatingChunk = getUpdatingChunk(chunk.getPos().pair());
+ if (updatingChunk != null) {
+ updatingChunk.dependendedOnBy.remove(playerchunk.location);
+ updatingChunk.lastActivity = world.getTime();
+ }
+ }));
+ // Paper end
this.worldLoadListener.a(chunkcoordintpair, chunkstatus);
return completablefuture1;
@@ -1167,6 +1193,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return CompletableFuture.completedFuture(Either.right(playerchunk_failure));
});
}, (runnable) -> {
+ playerchunk.lastActivity = world.getTime(); // Paper
this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable)); // CraftBukkit - decompile error
});
}
diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java
index acfe732af5b9f63fc2f6b78499defabe2e73ee45..25b19346fc1c702cc37275d0ec16abbbfacfb418 100644
--- a/src/main/java/net/minecraft/server/StructureGenerator.java
+++ b/src/main/java/net/minecraft/server/StructureGenerator.java
@@ -160,7 +160,7 @@ public abstract class StructureGenerator<C extends WorldGenFeatureConfiguration>
while (longiterator.hasNext()) {
long k = longiterator.nextLong();
IChunkAccess ichunkaccess1 = generatoraccess.getChunkAt(ChunkCoordIntPair.getX(k), ChunkCoordIntPair.getZ(k), ChunkStatus.STRUCTURE_STARTS, false); // CraftBukkit - don't load chunks
- StructureStart structurestart = ichunkaccess1.a(this.b());
+ StructureStart structurestart = ichunkaccess1 != null ? ichunkaccess1.a(this.b()) : null; // Paper - make sure not null
if (structurestart != null) {
list.add(structurestart);

View file

@ -0,0 +1,280 @@
From 22baa6be4daa8a11770411b50f1fbf545196407d Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 14:35:27 -0600
Subject: [PATCH] Add player view distance API
diff --git a/src/main/java/net/minecraft/server/EntityHuman.java b/src/main/java/net/minecraft/server/EntityHuman.java
index 58e037e13b..e97bb2305c 100644
--- a/src/main/java/net/minecraft/server/EntityHuman.java
+++ b/src/main/java/net/minecraft/server/EntityHuman.java
@@ -71,6 +71,15 @@ public abstract class EntityHuman extends EntityLiving {
// Paper start
public boolean affectsSpawning = true;
// Paper end
+ // Paper start - Player view distance API
+ private int viewDistance = -1;
+ public int getViewDistance() {
+ return viewDistance == -1 ? ((WorldServer) world).getPlayerChunkMap().getViewDistance() : viewDistance;
+ }
+ public void setViewDistance(int viewDistance) {
+ this.viewDistance = viewDistance;
+ }
+ // Paper end
// CraftBukkit start
public boolean fauxSleeping;
diff --git a/src/main/java/net/minecraft/server/EntityTracker.java b/src/main/java/net/minecraft/server/EntityTracker.java
index 45ab33d1ae..3854ae9769 100644
--- a/src/main/java/net/minecraft/server/EntityTracker.java
+++ b/src/main/java/net/minecraft/server/EntityTracker.java
@@ -200,6 +200,7 @@ public class EntityTracker {
}
+ public void updatePlayer(EntityPlayer entityplayer) { a(entityplayer); } // Paper - OBFHELPER
public void a(EntityPlayer entityplayer) {
Iterator iterator = this.c.iterator();
diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
index d00401ce14..dd6c84b4a2 100644
--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java
+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
@@ -435,7 +435,7 @@ public class EntityTrackerEntry {
public boolean c(EntityPlayer entityplayer) {
double d0 = entityplayer.locX - (double) this.xLoc / 4096.0D;
double d1 = entityplayer.locZ - (double) this.zLoc / 4096.0D;
- int i = Math.min(this.e, this.f);
+ int i = Math.min(this.e, (entityplayer.getViewDistance() - 1) * 16); // Paper - Use player view distance API
return d0 >= (double) (-i) && d0 <= (double) i && d1 >= (double) (-i) && d1 <= (double) i && this.tracker.a(entityplayer);
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index e01222ad2b..55161af9c9 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -33,7 +33,7 @@ public class PlayerChunkMap {
private final List<PlayerChunk> g = Lists.newLinkedList();
private final List<PlayerChunk> h = Lists.newLinkedList();
private final List<PlayerChunk> i = Lists.newArrayList();
- private int j;
+ private int j;public int getViewDistance() { return j; } // Paper OBFHELPER
private long k;
private boolean l = true;
private boolean m = true;
@@ -257,8 +257,11 @@ public class PlayerChunkMap {
// CraftBukkit start - Load nearby chunks first
List<ChunkCoordIntPair> chunkList = new LinkedList<ChunkCoordIntPair>();
- for (int k = i - this.j; k <= i + this.j; ++k) {
- for (int l = j - this.j; l <= j + this.j; ++l) {
+ // Paper start - Player view distance API
+ int viewDistance = entityplayer.getViewDistance();
+ for (int k = i - viewDistance; k <= i + viewDistance; ++k) {
+ for (int l = j - viewDistance; l <= j + viewDistance; ++l) {
+ // Paper end
chunkList.add(new ChunkCoordIntPair(k, l));
}
}
@@ -277,8 +280,11 @@ public class PlayerChunkMap {
int i = (int) entityplayer.d >> 4;
int j = (int) entityplayer.e >> 4;
- for (int k = i - this.j; k <= i + this.j; ++k) {
- for (int l = j - this.j; l <= j + this.j; ++l) {
+ // Paper start - Player view distance API
+ int viewDistance = entityplayer.getViewDistance();
+ for (int k = i - viewDistance; k <= i + viewDistance; ++k) {
+ for (int l = j - viewDistance; l <= j + viewDistance; ++l) {
+ // Paper end
PlayerChunk playerchunk = this.getChunk(k, l);
if (playerchunk != null) {
@@ -308,7 +314,8 @@ public class PlayerChunkMap {
if (d2 >= 64.0D) {
int k = (int) entityplayer.d >> 4;
int l = (int) entityplayer.e >> 4;
- int i1 = this.j;
+ int i1 = entityplayer.getViewDistance(); // Paper - Player view distance API
+
int j1 = i - k;
int k1 = j - l;
@@ -352,6 +359,8 @@ public class PlayerChunkMap {
return playerchunk != null && playerchunk.d(entityplayer) && playerchunk.e();
}
+ public final void setViewDistanceForAll(int viewDistance) { this.a(viewDistance); } // Paper - OBFHELPER
+ // Paper start - Separate into two methods
public void a(int i) {
i = MathHelper.clamp(i, 3, 32);
if (i != this.j) {
@@ -361,36 +370,55 @@ public class PlayerChunkMap {
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
- int k = (int) entityplayer.locX >> 4;
- int l = (int) entityplayer.locZ >> 4;
- int i1;
- int j1;
-
- if (j > 0) {
- for (i1 = k - i; i1 <= k + i; ++i1) {
- for (j1 = l - i; j1 <= l + i; ++j1) {
- PlayerChunk playerchunk = this.c(i1, j1);
-
- if (!playerchunk.d(entityplayer)) {
- playerchunk.a(entityplayer);
- }
+ this.setViewDistance(entityplayer, i, false); // Paper - Split, don't mark sort pending, we'll handle it after
+ }
+
+ this.j = i;
+ this.e();
+ }
+ }
+
+ public void setViewDistance(EntityPlayer entityplayer, int i) {
+ this.setViewDistance(entityplayer, i, true); // Mark sort pending by default so we don't have to remember to do so all the time
+ }
+
+ // Copied from above with minor changes
+ public void setViewDistance(EntityPlayer entityplayer, int i, boolean markSort) {
+ i = MathHelper.clamp(i, 3, 32);
+ int oldViewDistance = entityplayer.getViewDistance();
+ if (i != oldViewDistance) {
+ int j = i - oldViewDistance;
+
+ int k = (int) entityplayer.locX >> 4;
+ int l = (int) entityplayer.locZ >> 4;
+ int i1;
+ int j1;
+
+ if (j > 0) {
+ for (i1 = k - i; i1 <= k + i; ++i1) {
+ for (j1 = l - i; j1 <= l + i; ++j1) {
+ PlayerChunk playerchunk = this.c(i1, j1);
+
+ if (!playerchunk.d(entityplayer)) {
+ playerchunk.a(entityplayer);
}
}
- } else {
- for (i1 = k - this.j; i1 <= k + this.j; ++i1) {
- for (j1 = l - this.j; j1 <= l + this.j; ++j1) {
- if (!this.a(i1, j1, k, l, i)) {
- this.c(i1, j1).b(entityplayer);
- }
+ }
+ } else {
+ for (i1 = k - oldViewDistance; i1 <= k + oldViewDistance; ++i1) {
+ for (j1 = l - oldViewDistance; j1 <= l + oldViewDistance; ++j1) {
+ if (!this.a(i1, j1, k, l, i)) {
+ this.c(i1, j1).b(entityplayer);
}
}
}
+ if (markSort) {
+ this.e();
+ }
}
-
- this.j = i;
- this.e();
}
}
+ // Paper end
private void e() {
this.l = true;
@@ -469,4 +497,32 @@ public class PlayerChunkMap {
}
}
// CraftBukkit end
+
+ // Paper start - Player view distance API
+ public void updateViewDistance(EntityPlayer player, int distanceIn) {
+ final int oldViewDistance = player.getViewDistance();
+
+ // This represents the view distance that we will set on the player
+ // It can exist as a negative value
+ int playerViewDistance = MathHelper.clamp(distanceIn, 3, 32);
+
+ // This value is the one we actually use to update the chunk map
+ // We don't ever want this to be a negative
+ int toSet = playerViewDistance;
+
+ if (distanceIn < 0) {
+ playerViewDistance = -1;
+ toSet = world.getPlayerChunkMap().getViewDistance();
+ }
+
+ if (toSet != oldViewDistance) {
+ // Order matters
+ this.setViewDistance(player, toSet);
+ player.setViewDistance(playerViewDistance);
+
+ //Force update entity trackers
+ this.getWorld().getTracker().updatePlayer(player);
+ }
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java
index 4eaa5d93b4..6720a9648e 100644
--- a/src/main/java/net/minecraft/server/SpawnerCreature.java
+++ b/src/main/java/net/minecraft/server/SpawnerCreature.java
@@ -44,7 +44,7 @@ public final class SpawnerCreature {
boolean flag3 = true;
// Spigot Start
byte b0 = worldserver.spigotConfig.mobSpawnRange;
- b0 = ( b0 > worldserver.spigotConfig.viewDistance ) ? (byte) worldserver.spigotConfig.viewDistance : b0;
+ b0 = ( b0 > entityhuman.getViewDistance() ) ? (byte) entityhuman.getViewDistance() : b0; // Paper - Use player view distance API
b0 = ( b0 > 8 ) ? 8 : b0;
for (int i1 = -b0; i1 <= b0; ++i1) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0ee063bcd3..5496fae409 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1626,6 +1626,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public boolean getAffectsSpawning() {
return this.getHandle().affectsSpawning;
}
+
+ @Override
+ public int getViewDistance() {
+ return getHandle().getViewDistance();
+ }
+
+ @Override
+ public void setViewDistance(int viewDistance) {
+ ((WorldServer) getHandle().world).getPlayerChunkMap().updateViewDistance(getHandle(), viewDistance);
+ }
// Paper end
@Override
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index a95f93eb76..09df00e94b 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -108,13 +108,13 @@ public class ActivationRange
int maxRange = Math.max( monsterActivationRange, animalActivationRange );
maxRange = Math.max( maxRange, miscActivationRange );
- maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange );
+ //maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange ); Paper - Use player view distance API below instead
for ( EntityHuman player : world.players )
{
-
+ int playerMaxRange = maxRange = Math.min( ( player.getViewDistance() << 4 ) - 8, maxRange ); // Paper - Use player view distance API
player.activatedTick = MinecraftServer.currentTick;
- maxBB = player.getBoundingBox().grow( maxRange, 256, maxRange );
+ maxBB = player.getBoundingBox().grow( playerMaxRange, 256, playerMaxRange ); // Paper - Use player view distance API
miscBB = player.getBoundingBox().grow( miscActivationRange, 256, miscActivationRange );
animalBB = player.getBoundingBox().grow( animalActivationRange, 256, animalActivationRange );
monsterBB = player.getBoundingBox().grow( monsterActivationRange, 256, monsterActivationRange );
--
2.21.0

View file

@ -0,0 +1,206 @@
From 208077ba7ae7f41d3bdfcc4f5bc577faa8095905 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 4 Mar 2016 18:18:37 -0600
Subject: [PATCH] Chunk save queue improvements
For some unknown reason, Minecraft is sleeping 10ms between every single chunk being saved to disk.
Under high chunk load/unload activity (lots of movement / teleporting), this causes the chunk unload queue
to build up in size.
This has multiple impacts:
1) Performance of the unload queue itself - The save thread is pretty ineffecient for how it accesses it
By letting the queue get larger, checking and popping work off the queue can get less performant.
2) Performance of chunk loading - As with #1, chunk loads also have to check this queue when loading
chunk data so that it doesn't load stale data if new data is pending write to disk.
3) Memory Usage - The entire chunk has been serialized to NBT, and now sits in this queue. This leads to
elevated memory usage, and then the objects used in the serialization sit around longer than needed,
resulting in promotion to Old Generation instead of dying young.
To optimize this, we change the entire unload queue to be a proper queue. This improves the behavior of popping
the first queued chunk off, instead of abusing iterators like Mojang was doing.
This also improves reliability of chunk saving, as the previous hack job had a race condition that could
fail to save some chunks.
Then finally, Sleeping will by default be removed, but due to known issues with 1.9, a config option was added.
But if sleeps are to remain enabled, we at least lower the sleep interval so it doesn't have as much negative impact.
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index cfcc244672..4e932ea235 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -217,4 +217,10 @@ public class PaperConfig {
" - Interval: " + timeSummary(Timings.getHistoryInterval() / 20) +
" - Length: " + timeSummary(Timings.getHistoryLength() / 20));
}
+
+ public static boolean enableFileIOThreadSleep;
+ private static void enableFileIOThreadSleep() {
+ enableFileIOThreadSleep = getBoolean("settings.sleep-between-chunk-saves", false);
+ if (enableFileIOThreadSleep) Bukkit.getLogger().info("Enabled sleeping between chunk saves, beware of memory issues");
+ }
}
diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
index b0c004b1f2..d2cece2651 100644
--- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
@@ -20,6 +20,7 @@ public class ChunkCoordIntPair {
this.z = (int) (i >> 32);
}
+ public long asLong() { return a(); } // Paper
public long a() {
return a(this.x, this.z);
}
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index 35976a26f3..21ee154a57 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -20,6 +20,7 @@ import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.function.Function;
import javax.annotation.Nullable;
+import java.util.concurrent.ConcurrentLinkedQueue; // Paper
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// Spigot start
@@ -29,8 +30,28 @@ import org.spigotmc.SupplierUtils;
public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
+ // Paper start - Chunk queue improvements
+ private static class QueuedChunk {
+ public ChunkCoordIntPair coords;
+ public Supplier<NBTTagCompound> compoundSupplier;
+ public Runnable onSave;
+
+ public QueuedChunk(Runnable run) {
+ this.coords = null;
+ this.compoundSupplier = null;
+ this.onSave = run;
+ }
+
+ public QueuedChunk(ChunkCoordIntPair coords, Supplier<NBTTagCompound> compoundSupplier) {
+ this.coords = coords;
+ this.compoundSupplier = compoundSupplier;
+ }
+ }
+ final private ConcurrentLinkedQueue<QueuedChunk> queue = new ConcurrentLinkedQueue<>();
+ // Paper end
+
private static final Logger a = LogManager.getLogger();
- private final Map<ChunkCoordIntPair, Supplier<NBTTagCompound>> b = Maps.newHashMap();
+ private final it.unimi.dsi.fastutil.longs.Long2ObjectMap<Supplier<NBTTagCompound>> saveMap = it.unimi.dsi.fastutil.longs.Long2ObjectMaps.synchronize(new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>()); // Paper
private final File c;
private final DataFixer d;
private PersistentStructureLegacy e;
@@ -86,7 +107,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
return null;
}
// CraftBukkit end
- NBTTagCompound nbttagcompound = SupplierUtils.getIfExists(this.b.get(new ChunkCoordIntPair(i, j))); // Spigot
+ NBTTagCompound nbttagcompound = SupplierUtils.getIfExists(this.saveMap.get(ChunkCoordIntPair.asLong(i, j))); // Spigot // Paper
if (nbttagcompound != null) {
return nbttagcompound;
@@ -314,7 +335,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
};
}
- this.a(chunkcoordintpair, SupplierUtils.createUnivaluedSupplier(completion, unloaded && this.b.size() < SAVE_QUEUE_TARGET_SIZE));
+ this.a(chunkcoordintpair, SupplierUtils.createUnivaluedSupplier(completion, unloaded)); // Paper - Remove save queue target size
// Spigot end
} catch (Exception exception) {
ChunkRegionLoader.a.error("Failed to save chunk", exception);
@@ -323,7 +344,8 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
}
protected void a(ChunkCoordIntPair chunkcoordintpair, Supplier<NBTTagCompound> nbttagcompound) { // Spigot
- this.b.put(chunkcoordintpair, nbttagcompound);
+ this.saveMap.put(chunkcoordintpair.asLong(), nbttagcompound); // Paper
+ queue.add(new QueuedChunk(chunkcoordintpair, nbttagcompound)); // Paper - Chunk queue improvements
FileIOThread.a().a(this);
}
@@ -333,20 +355,24 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
}
private boolean processSaveQueueEntry(boolean logCompletion) {
- Iterator<Entry<ChunkCoordIntPair, Supplier<NBTTagCompound>>> iterator = this.b.entrySet().iterator(); // Spigot
-
- if (!iterator.hasNext()) {
+ // Paper start - Chunk queue improvements
+ QueuedChunk chunk = queue.poll();
+ if (chunk == null) {
+ // Paper - end
if (logCompletion) { // CraftBukkit
ChunkRegionLoader.a.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.c.getName());
}
return false;
} else {
- Entry<ChunkCoordIntPair, NBTTagCompound> entry = (Entry) iterator.next();
-
- iterator.remove();
- ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) entry.getKey();
- Supplier<NBTTagCompound> nbttagcompound = (Supplier<NBTTagCompound>) entry.getValue(); // Spigot
+ // Paper start
+ if (chunk.onSave != null) {
+ chunk.onSave.run();
+ return true;
+ }
+ // Paper end
+ ChunkCoordIntPair chunkcoordintpair = chunk.coords; // Paper - Chunk queue improvements
+ Supplier<NBTTagCompound> nbttagcompound = chunk.compoundSupplier; // Spigot // Paper
if (nbttagcompound == null) {
return true;
@@ -355,6 +381,15 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
// CraftBukkit start
RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z, SupplierUtils.getIfExists(nbttagcompound)); // Spigot
+ // Paper start remove from map only if this was the latest version of the chunk
+ synchronized (this.saveMap) {
+ long k = chunkcoordintpair.asLong();
+ // This will not equal if a newer version is still pending - wait until newest is saved to remove
+ if (this.saveMap.get(k) == chunk.compoundSupplier) {
+ this.saveMap.remove(k);
+ }
+ }
+ // Paper end
/*
NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream);
dataoutputstream.close();
diff --git a/src/main/java/net/minecraft/server/FileIOThread.java b/src/main/java/net/minecraft/server/FileIOThread.java
index 8c3537ab8d..3c688f546c 100644
--- a/src/main/java/net/minecraft/server/FileIOThread.java
+++ b/src/main/java/net/minecraft/server/FileIOThread.java
@@ -38,20 +38,21 @@ public class FileIOThread implements Runnable {
IAsyncChunkSaver iasyncchunksaver = (IAsyncChunkSaver) this.c.get(i);
boolean flag;
- synchronized (iasyncchunksaver) {
+ //synchronized (iasyncchunksaver) { // Paper - remove synchronized
flag = iasyncchunksaver.a();
- }
+ //} // Paper
if (!flag) {
this.c.remove(i--);
++this.e;
}
+ if (com.destroystokyo.paper.PaperConfig.enableFileIOThreadSleep) { // Paper
try {
- Thread.sleep(this.f ? 0L : 10L);
+ Thread.sleep(this.f ? 0L : 1L); // Paper
} catch (InterruptedException interruptedexception) {
interruptedexception.printStackTrace();
- }
+ }} // Paper
}
if (this.c.isEmpty()) {
--
2.21.0

View file

@ -0,0 +1,90 @@
From 62de9801d97be7f583f88f20b374660bb4349cc8 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
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 fe0dde1461..9d53f1118c 100644
--- a/src/main/java/net/minecraft/server/BlockCrops.java
+++ b/src/main/java/net/minecraft/server/BlockCrops.java
@@ -44,7 +44,7 @@ public class BlockCrops extends BlockPlant implements IBlockFragilePlantElement
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Random random) {
super.a(iblockdata, world, blockposition, random);
- if (world.getLightLevel(blockposition.up(), 0) >= 9) {
+ if (world.isLightLevel(blockposition.up(), 9)) { // Paper
int i = this.k(iblockdata);
if (i < this.e()) {
diff --git a/src/main/java/net/minecraft/server/BlockSapling.java b/src/main/java/net/minecraft/server/BlockSapling.java
index 81ea9bcb4f..291cc9a398 100644
--- a/src/main/java/net/minecraft/server/BlockSapling.java
+++ b/src/main/java/net/minecraft/server/BlockSapling.java
@@ -30,7 +30,7 @@ public class BlockSapling extends BlockPlant implements IBlockFragilePlantElemen
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Random random) {
super.a(iblockdata, world, blockposition, random);
- if (world.getLightLevel(blockposition.up()) >= 9 && random.nextInt(Math.max(2, (int) (((100.0F / world.spigotConfig.saplingModifier) * 7) + 0.5F))) == 0) { // Spigot
+ if (world.isLightLevel(blockposition.up(), 9) && random.nextInt(Math.max(2, (int) (((100.0F / 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 53f091835c..f8dda1b7a1 100644
--- a/src/main/java/net/minecraft/server/BlockStem.java
+++ b/src/main/java/net/minecraft/server/BlockStem.java
@@ -27,7 +27,7 @@ public class BlockStem extends BlockPlant implements IBlockFragilePlantElement {
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Random random) {
super.a(iblockdata, world, blockposition, random);
- if (world.getLightLevel(blockposition.up(), 0) >= 9) {
+ if (world.isLightLevel(blockposition.up(), 9)) { // Paper
float f = BlockCrops.a((Block) this, (IBlockAccess) world, blockposition);
if (random.nextInt((int) ((100.0F / (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 5ea5170436..dc61263a3f 100644
--- a/src/main/java/net/minecraft/server/EntityMonster.java
+++ b/src/main/java/net/minecraft/server/EntityMonster.java
@@ -66,9 +66,18 @@ public abstract class EntityMonster extends EntityCreature implements IMonster {
if (this.world.getBrightness(EnumSkyBlock.SKY, blockposition) > this.random.nextInt(32)) {
return false;
} else {
- int i = this.world.Y() ? this.world.d(blockposition, 10) : this.world.getLightLevel(blockposition);
-
- return i <= this.random.nextInt(8);
+ // Paper start - optimized light check, returns faster
+ boolean passes;
+ if (this.world.Y()) {
+ final int orig = world.getSkylightSubtracted();
+ world.setSkylightSubtracted(10);
+ passes = !this.world.isLightLevel(blockposition, this.random.nextInt(8));
+ world.setSkylightSubtracted(orig);
+ } else {
+ passes = !this.world.isLightLevel(blockposition, this.random.nextInt(8));
+ }
+ return passes;
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/server/EntityZombie.java b/src/main/java/net/minecraft/server/EntityZombie.java
index 002be7f7be..7a943a6c27 100644
--- a/src/main/java/net/minecraft/server/EntityZombie.java
+++ b/src/main/java/net/minecraft/server/EntityZombie.java
@@ -267,7 +267,7 @@ 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, entityzombie.getBoundingBox()) && this.world.getCubes(entityzombie, entityzombie.getBoundingBox()) && !this.world.containsLiquid(entityzombie.getBoundingBox())) {
this.world.addEntity(entityzombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit
--
2.21.0

View file

@ -0,0 +1,36 @@
From b61f0153ccd138435700cfb4c711f477112574f6 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 19 Mar 2016 15:16:54 -0400
Subject: [PATCH] Pass world to Village creation
fixes NPE bug #95
diff --git a/src/main/java/net/minecraft/server/PersistentVillage.java b/src/main/java/net/minecraft/server/PersistentVillage.java
index 98c6bbc183..7a9fb97530 100644
--- a/src/main/java/net/minecraft/server/PersistentVillage.java
+++ b/src/main/java/net/minecraft/server/PersistentVillage.java
@@ -237,7 +237,7 @@ public class PersistentVillage extends PersistentBase {
for (int i = 0; i < nbttaglist.size(); ++i) {
NBTTagCompound nbttagcompound1 = nbttaglist.getCompound(i);
- Village village = new Village();
+ Village village = new Village(world); // Paper
village.a(nbttagcompound1);
this.villages.add(village);
diff --git a/src/main/java/net/minecraft/server/Village.java b/src/main/java/net/minecraft/server/Village.java
index 68ad7bc213..b794572915 100644
--- a/src/main/java/net/minecraft/server/Village.java
+++ b/src/main/java/net/minecraft/server/Village.java
@@ -24,7 +24,7 @@ public class Village {
private final List<Village.Aggressor> k;
private int l;
- public Village() {
+ private Village() { // Paper - Nothing should call this - world needs to be set.
this.c = BlockPosition.ZERO;
this.d = BlockPosition.ZERO;
this.j = Maps.newHashMap();
--
2.21.0

View file

@ -0,0 +1,125 @@
From 11ab12d6efda726da59ca55d164a9ba49af71e59 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 27 Aug 2015 01:15:02 -0400
Subject: [PATCH] Optimize Chunk Access
getting a loaded chunk is one of the most hottest pieces of code in the game.
getChunkAt is called for the same chunk multiple times in a row, often from getType();
Optimize this look up by using a Last Access cache.
diff --git a/src/main/java/net/minecraft/server/ChunkMap.java b/src/main/java/net/minecraft/server/ChunkMap.java
index 732c8793e5..8b3738c8f7 100644
--- a/src/main/java/net/minecraft/server/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/ChunkMap.java
@@ -15,6 +15,7 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
public Chunk put(long i, Chunk chunk) {
chunk.world.timings.syncChunkLoadPostTimer.startTiming(); // Paper
+ lastChunkByPos = chunk; // Paper
Chunk chunk1 = (Chunk) super.put(i, chunk);
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i);
@@ -22,7 +23,7 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
for (int k = chunkcoordintpair.z - 1; k <= chunkcoordintpair.z + 1; ++k) {
if (j != chunkcoordintpair.x || k != chunkcoordintpair.z) {
long l = ChunkCoordIntPair.a(j, k);
- Chunk chunk2 = (Chunk) this.get(l);
+ Chunk chunk2 = (Chunk) super.get(l); // Paper - use super to avoid polluting last access cache
if (chunk2 != null) {
chunk.H();
@@ -40,7 +41,7 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
continue;
}
- Chunk neighbor = this.get(ChunkCoordIntPair.a(chunkcoordintpair.x + x, chunkcoordintpair.z + z));
+ Chunk neighbor = super.get(ChunkCoordIntPair.a(chunkcoordintpair.x + x, chunkcoordintpair.z + z)); // Paper - use super to avoid polluting last access cache
if (neighbor != null) {
neighbor.setNeighborLoaded(-x, -z);
chunk.setNeighborLoaded(x, z);
@@ -64,7 +65,7 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
for (int j = chunkcoordintpair.x - 1; j <= chunkcoordintpair.x + 1; ++j) {
for (int k = chunkcoordintpair.z - 1; k <= chunkcoordintpair.z + 1; ++k) {
if (j != chunkcoordintpair.x || k != chunkcoordintpair.z) {
- Chunk chunk1 = (Chunk) this.get(ChunkCoordIntPair.a(j, k));
+ Chunk chunk1 = (Chunk) super.get(ChunkCoordIntPair.a(j, k)); // Paper - use super to avoid polluting last access cache
if (chunk1 != null) {
chunk1.I();
@@ -73,8 +74,22 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
}
}
+ // Paper start
+ if (lastChunkByPos != null && i == lastChunkByPos.chunkKey) {
+ lastChunkByPos = null;
+ }
return chunk;
}
+ private Chunk lastChunkByPos = null;
+
+ @Override
+ public Chunk get(long l) {
+ if (lastChunkByPos != null && l == lastChunkByPos.chunkKey) {
+ return lastChunkByPos;
+ }
+ return lastChunkByPos = super.get(l);
+ }
+ // Paper end
public Chunk remove(Object object) {
return this.remove((Long) object);
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 1ed7c7e2c9..c54df45837 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -76,15 +76,16 @@ public class ChunkProviderServer implements IChunkProvider {
Chunk chunk;
synchronized (this.chunkLoader) {
- if (this.lastChunk != null && this.lastChunk.getPos().x == i && this.lastChunk.getPos().z == j) {
+ // Paper start - remove vanilla lastChunk, we do it more accurately
+ /* if (this.lastChunk != null && this.lastChunk.locX == i && this.lastChunk.locZ == j) {
return this.lastChunk;
- }
+ }*/ // Paper end
long k = ChunkCoordIntPair.a(i, j);
chunk = (Chunk) this.chunks.get(k);
if (chunk != null) {
- this.lastChunk = chunk;
+ //this.lastChunk = chunk; // Paper remove vanilla lastChunk
return chunk;
}
@@ -198,7 +199,7 @@ public class ChunkProviderServer implements IChunkProvider {
}
this.chunks.put(k, chunk);
- this.lastChunk = chunk;
+ //this.lastChunk = chunk; // Paper
}
this.asyncTaskHandler.postToMainThread(chunk::addEntities);
@@ -344,7 +345,7 @@ public class ChunkProviderServer implements IChunkProvider {
this.saveChunk(chunk, true); // Spigot
}
this.chunks.remove(chunk.chunkKey);
- this.lastChunk = null;
+ // this.lastChunk = null; // Paper
}
return true;
}
@@ -380,6 +381,6 @@ public class ChunkProviderServer implements IChunkProvider {
}
public boolean isLoaded(int i, int j) {
- return this.chunks.containsKey(ChunkCoordIntPair.a(i, j));
+ return this.chunks.get(ChunkCoordIntPair.asLong(i, j)) != null; // Paper - use get for last access
}
}
--
2.21.0

View file

@ -0,0 +1,34 @@
From 2c462895126242c15395ff2033688c432492ad50 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 5 Apr 2016 19:42:22 -0400
Subject: [PATCH] Don't spam reload spawn chunks in nether/end
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index b595536648..5fc2da0d92 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -2849,6 +2849,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
return this.K;
}
+ public boolean isSpawnChunk(int i, int j) { return e(i, j); } // Paper - OBFHELPER
public boolean e(int i, int j) {
BlockPosition blockposition = this.getSpawn();
int k = i * 16 + 8 - blockposition.getX();
diff --git a/src/main/java/net/minecraft/server/WorldProvider.java b/src/main/java/net/minecraft/server/WorldProvider.java
index 5e87e537e4..3911e4947e 100644
--- a/src/main/java/net/minecraft/server/WorldProvider.java
+++ b/src/main/java/net/minecraft/server/WorldProvider.java
@@ -69,7 +69,7 @@ public abstract class WorldProvider {
public void l() {}
public boolean a(int i, int j) {
- return !this.b.isForceLoaded(i, j);
+ return !this.b.isSpawnChunk(i, j) && !this.b.isForceLoaded(i, j); // Paper - Use spawn chunks check for all worlds
}
protected abstract void m();
--
2.21.0

View file

@ -0,0 +1,103 @@
From 6d6e37ba0e3e91d7a711bc05c53daeeb304b82f4 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 17 Jun 2013 01:24:00 -0400
Subject: [PATCH] Entity Tracking Improvements
If any part of a Vehicle/Passenger relationship is visible to a player,
send all passenger/vehicles to the player in the chain.
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index c9b37727ff..82994db643 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -70,6 +70,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
protected CraftEntity bukkitEntity;
+ EntityTrackerEntry tracker; // Paper
public CraftEntity getBukkitEntity() {
if (bukkitEntity == null) {
bukkitEntity = CraftEntity.getEntity(world.getServer(), this);
diff --git a/src/main/java/net/minecraft/server/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
index de0cf6b735..5629f9909b 100644
--- a/src/main/java/net/minecraft/server/EntityTrackerEntry.java
+++ b/src/main/java/net/minecraft/server/EntityTrackerEntry.java
@@ -56,6 +56,7 @@ public class EntityTrackerEntry {
// Paper end
public EntityTrackerEntry(Entity entity, int i, int j, int k, boolean flag) {
+ entity.tracker = this; // Paper
this.tracker = entity;
this.e = i;
this.f = j;
@@ -453,17 +454,59 @@ public class EntityTrackerEntry {
this.tracker.b(entityplayer);
entityplayer.d(this.tracker);
+ updatePassengers(entityplayer); // Paper
}
} else if (this.trackedPlayers.contains(entityplayer)) {
this.trackedPlayers.remove(entityplayer);
this.tracker.c(entityplayer);
entityplayer.c(this.tracker);
+ updatePassengers(entityplayer); // Paper
}
}
}
public boolean c(EntityPlayer entityplayer) {
+ // Paper start
+ if (tracker.isPassenger()) {
+ return isTrackedBy(tracker.getVehicle(), entityplayer);
+ } else if (hasPassengerInRange(tracker, entityplayer)) {
+ return true;
+ }
+
+ return isInRangeOfPlayer(entityplayer);
+ }
+ private static boolean hasPassengerInRange(Entity entity, EntityPlayer entityplayer) {
+ if (!entity.isVehicle()) {
+ return false;
+ }
+ for (Entity passenger : entity.passengers) {
+ if (passenger.tracker != null && passenger.tracker.isInRangeOfPlayer(entityplayer)) {
+ return true;
+ }
+ if (passenger.isVehicle()) {
+ if (hasPassengerInRange(passenger, entityplayer)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ private static boolean isTrackedBy(Entity entity, EntityPlayer entityplayer) {
+ return entity == entityplayer || entity.tracker != null && entity.tracker.trackedPlayers.contains(entityplayer);
+ }
+ private void updatePassengers(EntityPlayer player) {
+ if (tracker.isVehicle()) {
+ tracker.passengers.forEach((e) -> {
+ if (e.tracker != null) {
+ e.tracker.updatePlayer(player);
+ }
+ });
+ player.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker));
+ }
+ }
+ private boolean isInRangeOfPlayer(EntityPlayer entityplayer) {
+ // Paper end
double d0 = entityplayer.locX - (double) this.xLoc / 4096.0D;
double d1 = entityplayer.locZ - (double) this.zLoc / 4096.0D;
int i = Math.min(this.e, (entityplayer.getViewDistance() - 1) * 16); // Paper - Use player view distance API
@@ -604,6 +647,7 @@ public class EntityTrackerEntry {
this.trackedPlayers.remove(entityplayer);
this.tracker.c(entityplayer);
entityplayer.c(this.tracker);
+ updatePassengers(entityplayer); // Paper
}
}
--
2.21.0

View file

@ -0,0 +1,47 @@
From 036c518050a0972307568a014156d59bb90bf54c Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 27 May 2016 21:41:26 -0400
Subject: [PATCH] Ensure Chunks never ever load async
Safely pushes the operation to main thread, then back to the posting thread
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java
index e4fd9bc604..7ffb8f6172 100644
--- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java
@@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.chunkio;
import net.minecraft.server.Chunk;
import net.minecraft.server.ChunkProviderServer;
import net.minecraft.server.ChunkRegionLoader;
+import net.minecraft.server.MCUtil; // Paper
import net.minecraft.server.World;
import org.bukkit.craftbukkit.util.AsynchronousExecutor;
@@ -13,7 +14,7 @@ public class ChunkIOExecutor {
private static final AsynchronousExecutor<QueuedChunk, Chunk, Runnable, RuntimeException> instance = new AsynchronousExecutor<QueuedChunk, Chunk, Runnable, RuntimeException>(new ChunkIOProvider(), BASE_THREADS);
public static Chunk syncChunkLoad(World world, ChunkRegionLoader loader, ChunkProviderServer provider, int x, int z) {
- return instance.getSkipQueue(new QueuedChunk(x, z, loader, world, provider));
+ return MCUtil.ensureMain("Async Chunk Load", () -> instance.getSkipQueue(new QueuedChunk(x, z, loader, world, provider))); // Paper
}
public static void queueChunkLoad(World world, ChunkRegionLoader loader, ChunkProviderServer provider, int x, int z, Runnable runnable) {
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
index 52a8c48fa4..4cfe24df15 100644
--- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
@@ -35,9 +35,9 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
// sync stuff
public void callStage2(QueuedChunk queuedChunk, Chunk chunk) throws RuntimeException {
- if (chunk == null) {
+ if (chunk == null || queuedChunk.provider.chunks.containsKey(ChunkCoordIntPair.a(queuedChunk.x, queuedChunk.z))) { // Paper - also call original if it was already loaded
// If the chunk loading failed just do it synchronously (may generate)
- // queuedChunk.provider.originalGetChunkAt(queuedChunk.x, queuedChunk.z);
+ queuedChunk.provider.getChunkAt(queuedChunk.x, queuedChunk.z, true, true); // Paper - actually call original if it was already loaded
return;
}
try (Timing ignored = queuedChunk.provider.world.timings.chunkIOStage2.startTimingIfSync()) { // Paper
--
2.21.0

View file

@ -0,0 +1,224 @@
From 2fbf2c556d7840198741959940696a14c7e3c26a Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 18 Jun 2016 23:22:12 -0400
Subject: [PATCH] Delay Chunk Unloads based on Player Movement
When players are moving in the world, doing things such as building or exploring,
they will commonly go back and forth in a small area. This causes a ton of chunk load
and unload activity on the edge chunks of their view distance.
A simple back and forth movement in 6 blocks could spam a chunk to thrash a
loading and unload cycle over and over again.
This is very wasteful. This system introduces a delay of inactivity on a chunk
before it actually unloads, which is maintained separately from ChunkGC.
This allows servers with smaller worlds who do less long distance exploring to stop
wasting cpu cycles on saving/unloading/reloading chunks repeatedly.
This also makes the Chunk GC System useless, by auto scheduling unload as soon as
a spare chunk is added to the server thats outside of view distance.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index bcc2ecaa3a..c70771614d 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -310,4 +310,18 @@ public class PaperWorldConfig {
preventTntFromMovingInWater = getBoolean("prevent-tnt-from-moving-in-water", false);
log("Prevent TNT from moving in water: " + preventTntFromMovingInWater);
}
+
+ public long delayChunkUnloadsBy;
+ private void delayChunkUnloadsBy() {
+ delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "10s"));
+ if (delayChunkUnloadsBy > 0) {
+ log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds");
+ delayChunkUnloadsBy *= 1000;
+ }
+ }
+
+ public boolean skipEntityTickingInChunksScheduledForUnload = true;
+ private void skipEntityTickingInChunksScheduledForUnload() {
+ skipEntityTickingInChunksScheduledForUnload = getBoolean("skip-entity-ticking-in-chunks-scheduled-for-unload", skipEntityTickingInChunksScheduledForUnload);
+ }
}
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index c74176daa5..bdf922db50 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -40,6 +40,7 @@ public class Chunk implements IChunkAccess {
private boolean i;public boolean isLoaded() { return i; } // Paper - OBFHELPER
public final World world;
public final Map<HeightMap.Type, HeightMap> heightMap;
+ public Long scheduledForUnload; // Paper - delay chunk unloads
public final int locX;
public final int locZ;
private boolean l;
diff --git a/src/main/java/net/minecraft/server/ChunkMap.java b/src/main/java/net/minecraft/server/ChunkMap.java
index 8b3738c8f7..2021c0d02e 100644
--- a/src/main/java/net/minecraft/server/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/ChunkMap.java
@@ -48,6 +48,15 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
}
}
}
+ // Paper start - if this is a spare chunk (not part of any players view distance), go ahead and queue it for unload.
+ if (!((WorldServer)chunk.world).getPlayerChunkMap().isChunkInUse(chunk.locX, chunk.locZ)) {
+ if (chunk.world.paperConfig.delayChunkUnloadsBy > 0) {
+ chunk.scheduledForUnload = System.currentTimeMillis();
+ } else {
+ ((WorldServer) chunk.world).getChunkProvider().unload(chunk);
+ }
+ }
+ // Paper end
chunk.world.timings.syncChunkLoadPostTimer.stopTiming(); // Paper
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index c54df45837..d0bf0f72da 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -307,6 +307,19 @@ public class ChunkProviderServer implements IChunkProvider {
}
activityAccountant.endActivity(); // Spigot
}
+ // Paper start - delayed chunk unloads
+ long now = System.currentTimeMillis();
+ long unloadAfter = world.paperConfig.delayChunkUnloadsBy;
+ if (unloadAfter > 0) {
+ //noinspection Convert2streamapi
+ for (Chunk chunk : chunks.values()) {
+ if (chunk.scheduledForUnload != null && now - chunk.scheduledForUnload > unloadAfter) {
+ chunk.scheduledForUnload = null;
+ unload(chunk);
+ }
+ }
+ }
+ // Paper end
this.chunkScheduler.a(booleansupplier);
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index e47aae2f8b..b9d90c4fb8 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -29,8 +29,23 @@ public class PlayerChunk {
chunkproviderserver.a(i, j);
this.chunk = chunkproviderserver.getChunkAt(i, j, true, false);
+ markChunkUsed(); // Paper - delay chunk unloads
}
+ // Paper start
+ private void markChunkUsed() {
+ if (chunk == null) {
+ return;
+ }
+ if (chunkHasPlayers) {
+ chunk.scheduledForUnload = null;
+ } else if (chunk.scheduledForUnload == null) {
+ chunk.scheduledForUnload = System.currentTimeMillis();
+ }
+ }
+ private boolean chunkHasPlayers = false;
+ // Paper end
+
public ChunkCoordIntPair a() {
return this.location;
}
@@ -41,6 +56,8 @@ public class PlayerChunk {
} else {
if (this.players.isEmpty()) {
this.i = this.playerChunkMap.getWorld().getTime();
+ chunkHasPlayers = true; // Paper - delay chunk unloads
+ markChunkUsed(); // Paper - delay chunk unloads
}
this.players.add(entityplayer);
@@ -59,6 +76,8 @@ public class PlayerChunk {
this.players.remove(entityplayer);
if (this.players.isEmpty()) {
+ chunkHasPlayers = false; // Paper - delay chunk unloads
+ markChunkUsed(); // Paper - delay chunk unloads
this.playerChunkMap.b(this);
}
@@ -70,6 +89,7 @@ public class PlayerChunk {
return true;
} else {
this.chunk = this.playerChunkMap.getWorld().getChunkProvider().getChunkAt(this.location.x, this.location.z, true, flag);
+ markChunkUsed(); // Paper - delay chunk unloads
return this.chunk != null;
}
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 2064576501..ab4f3b7223 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -452,7 +452,13 @@ public class PlayerChunkMap {
Chunk chunk = playerchunk.f();
if (chunk != null) {
- this.getWorld().getChunkProvider().unload(chunk);
+ // Paper start - delay chunk unloads
+ if (world.paperConfig.delayChunkUnloadsBy <= 0) {
+ this.getWorld().getChunkProvider().unload(chunk);
+ } else {
+ chunk.scheduledForUnload = System.currentTimeMillis();
+ }
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 32ee298648..dcff6c8d8a 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -1293,7 +1293,13 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
if (!tileentity.x() && tileentity.hasWorld()) {
BlockPosition blockposition = tileentity.getPosition();
- if (this.isLoaded(blockposition) && this.K.a(blockposition)) {
+ // Paper start - Skip ticking in chunks scheduled for unload
+ net.minecraft.server.Chunk chunk = this.getChunkIfLoaded(blockposition);
+ boolean shouldTick = chunk != null;
+ if(this.paperConfig.skipEntityTickingInChunksScheduledForUnload)
+ shouldTick = shouldTick && chunk.scheduledForUnload == null;
+ if (shouldTick && this.K.a(blockposition)) {
+ // Paper end
try {
this.methodProfiler.a(() -> {
return String.valueOf(TileEntityTypes.a(tileentity.C()));
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index a8c7e7931e..f7883e7085 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1772,7 +1772,7 @@ public class CraftWorld implements World {
ChunkProviderServer cps = world.getChunkProvider();
for (net.minecraft.server.Chunk chunk : cps.chunks.values()) {
// If in use, skip it
- if (isChunkInUse(chunk.locX, chunk.locZ)) {
+ if (isChunkInUse(chunk.locX, chunk.locZ) || chunk.scheduledForUnload != null) { // Paper - delayed chunk unloads
continue;
}
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index d08ef3fe10..081789a8fe 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -323,6 +323,11 @@ public class ActivationRange
{
isActive = false;
}
+ // Paper start - Skip ticking in chunks scheduled for unload
+ else if (entity.world.paperConfig.skipEntityTickingInChunksScheduledForUnload && (chunk == null || chunk.scheduledForUnload != null)) {
+ isActive = false;
+ }
+ // Paper end
return isActive;
}
}
--
2.21.0

View file

@ -0,0 +1,58 @@
From 266fe023d1d38728ba461724a7f2a23a2ee07cfd Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Nov 2016 21:52:22 -0400
Subject: [PATCH] Prevent Auto Save if Save Queue is full
If the save queue already has 50 (configurable) of chunks pending,
then avoid processing auto save (which would add more)
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 7e847af00b..9829b3b64b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -341,6 +341,11 @@ public class PaperWorldConfig {
maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24);
}
+ public int queueSizeAutoSaveThreshold = 50;
+ private void queueSizeAutoSaveThreshold() {
+ queueSizeAutoSaveThreshold = getInt("save-queue-limit-for-auto-save", 50);
+ }
+
public boolean removeCorruptTEs = false;
private void removeCorruptTEs() {
removeCorruptTEs = getBoolean("remove-corrupt-tile-entities", false);
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index fbc69b5ba5..9b5908a5b4 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -236,6 +236,13 @@ public class ChunkProviderServer implements IChunkProvider {
synchronized (this.chunkLoader) {
ObjectIterator objectiterator = this.chunks.values().iterator();
+ // Paper start
+ final ChunkRegionLoader chunkLoader = (ChunkRegionLoader) world.getChunkProvider().chunkLoader;
+ final int queueSize = chunkLoader.getQueueSize();
+ if (!flag && queueSize > world.paperConfig.queueSizeAutoSaveThreshold){
+ return false;
+ }
+ // Paper end
while (objectiterator.hasNext()) {
Chunk chunk = (Chunk) objectiterator.next();
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index a144118f66..adfb5d056f 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -156,6 +156,8 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
}
+ public int getQueueSize() { return queue.size(); } // Paper
+
// CraftBukkit start - Add async variant, provide compatibility
@Nullable
public Chunk a(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException {
--
2.21.0

View file

@ -0,0 +1,93 @@
From 8efbb3a0533a16d6c9e3ac27e41cd03bba1e35d8 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 4 Nov 2016 02:12:10 -0400
Subject: [PATCH] Chunk Save Stats Debug Option
Adds a command line flag to enable stats on how chunk saves are processing.
Stats on current queue, how many was processed and how many were queued.
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 9b5908a5b4..2997767282 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -28,6 +28,11 @@ public class ChunkProviderServer implements IChunkProvider {
public final LongSet unloadQueue = new LongOpenHashSet();
public final ChunkGenerator<?> chunkGenerator;
public final IChunkLoader chunkLoader;
+ // Paper start - chunk save stats
+ private long lastQueuedSaves = 0L; // Paper
+ private long lastProcessedSaves = 0L; // Paper
+ private long lastSaveStatPrinted = System.currentTimeMillis();
+ // Paper end
public final Long2ObjectMap<Chunk> chunks = Long2ObjectMaps.synchronize(new ChunkMap(8192));
private Chunk lastChunk;
private final ChunkTaskScheduler chunkScheduler;
@@ -239,6 +244,29 @@ public class ChunkProviderServer implements IChunkProvider {
// Paper start
final ChunkRegionLoader chunkLoader = (ChunkRegionLoader) world.getChunkProvider().chunkLoader;
final int queueSize = chunkLoader.getQueueSize();
+
+ final long now = System.currentTimeMillis();
+ final long timeSince = (now - lastSaveStatPrinted) / 1000;
+ final Integer printRateSecs = Integer.getInteger("printSaveStats");
+ if (printRateSecs != null && timeSince >= printRateSecs) {
+ final String timeStr = "/" + timeSince +"s";
+ final long queuedSaves = chunkLoader.getQueuedSaves();
+ long queuedDiff = queuedSaves - lastQueuedSaves;
+ lastQueuedSaves = queuedSaves;
+
+ final long processedSaves = chunkLoader.getProcessedSaves();
+ long processedDiff = processedSaves - lastProcessedSaves;
+ lastProcessedSaves = processedSaves;
+
+ lastSaveStatPrinted = now;
+ if (processedDiff > 0 || queueSize > 0 || queuedDiff > 0) {
+ System.out.println("[Chunk Save Stats] " + world.worldData.getName() +
+ " - Current: " + queueSize +
+ " - Queued: " + queuedDiff + timeStr +
+ " - Processed: " +processedDiff + timeStr
+ );
+ }
+ }
if (!flag && queueSize > world.paperConfig.queueSizeAutoSaveThreshold){
return false;
}
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index adfb5d056f..0fc4d9f520 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -156,7 +156,13 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
}
- public int getQueueSize() { return queue.size(); } // Paper
+ // Paper start
+ private long queuedSaves = 0;
+ private final java.util.concurrent.atomic.AtomicLong processedSaves = new java.util.concurrent.atomic.AtomicLong(0L);
+ public int getQueueSize() { return queue.size(); }
+ public long getQueuedSaves() { return queuedSaves; }
+ public long getProcessedSaves() { return processedSaves.longValue(); }
+ // Paper end
// CraftBukkit start - Add async variant, provide compatibility
@Nullable
@@ -348,6 +354,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
protected void a(ChunkCoordIntPair chunkcoordintpair, Supplier<NBTTagCompound> nbttagcompound) { // Spigot
this.saveMap.put(chunkcoordintpair.asLong(), nbttagcompound); // Paper
queue.add(new QueuedChunk(chunkcoordintpair, nbttagcompound)); // Paper - Chunk queue improvements
+ queuedSaves++; // Paper
FileIOThread.a().a(this);
}
@@ -375,6 +382,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
// Paper end
ChunkCoordIntPair chunkcoordintpair = chunk.coords; // Paper - Chunk queue improvements
Supplier<NBTTagCompound> nbttagcompound = chunk.compoundSupplier; // Spigot // Paper
+ processedSaves.incrementAndGet(); // Paper
if (nbttagcompound == null) {
return true;
--
2.21.0

View file

@ -0,0 +1,22 @@
From 635cfbbdad0af0805e7eadf3de564462628d732f Mon Sep 17 00:00:00 2001
From: Michael Himing <mhiming@gmail.com>
Date: Sun, 8 Jan 2017 18:50:35 +1100
Subject: [PATCH] Fix block break desync
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
index fd8d30e5cb..b34a0fb350 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -1185,6 +1185,8 @@ public class PlayerConnection implements PacketListenerPlayIn {
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
if (d3 > 36.0D) {
+ if (worldserver.isChunkLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4)) // Paper - Fix block break desync - Don't send for unloaded chunks
+ this.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition)); // Paper - Fix block break desync
return;
} else if (blockposition.getY() >= this.minecraftServer.getMaxBuildHeight()) {
return;
--
2.22.0

View file

@ -0,0 +1,23 @@
From 16ba1e065d52597408a18d8bbb9fa3686271fc6a Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 2 Jan 2017 16:32:56 -0500
Subject: [PATCH] ShulkerBox Dupe Prevention
This ensures that Shulker Boxes can never drop their contents twice, and
that the inventory is cleared incase it some how also got saved to the world.
diff --git a/src/main/java/net/minecraft/server/BlockShulkerBox.java b/src/main/java/net/minecraft/server/BlockShulkerBox.java
index ab0ece557c..997ed795b1 100644
--- a/src/main/java/net/minecraft/server/BlockShulkerBox.java
+++ b/src/main/java/net/minecraft/server/BlockShulkerBox.java
@@ -100,6 +100,7 @@ public class BlockShulkerBox extends BlockTileEntity {
}
a(world, blockposition, itemstack);
+ tileentityshulkerbox.clear(); // Paper - This was intended to be called in Vanilla (is checked in the if statement above if has been called) - Fixes dupe issues
}
}
world.updateAdjacentComparators(blockposition, iblockdata.getBlock());
--
2.21.0

View file

@ -0,0 +1,128 @@
From 1648e767bbdfe53802b2c3a864c74cdaaca6909e Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 5 Jun 2018 00:32:22 -0400
Subject: [PATCH] Configurable Villages loading chunks for door checks
This avoids villages spam loading chunks sync.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 0a270b899d..4727ac6eb5 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -434,4 +434,12 @@ public class PaperWorldConfig {
disableEnderpearlExploit = getBoolean("game-mechanics.disable-unloaded-chunk-enderpearl-exploit", disableEnderpearlExploit);
log("Disable Unloaded Chunk Enderpearl Exploit: " + (disableEnderpearlExploit ? "enabled" : "disabled"));
}
+
+ public boolean villagesLoadChunks = false;
+ private void villagesLoadChunks() {
+ villagesLoadChunks = getBoolean("game-mechanics.villages-load-chunks", false);
+ if (villagesLoadChunks) {
+ log("Villages can load chunks - Warning this can cause intense TPS loss. Strongly consider disabling this.");
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/server/PersistentVillage.java b/src/main/java/net/minecraft/server/PersistentVillage.java
index 7a9fb97530..e40cd41869 100644
--- a/src/main/java/net/minecraft/server/PersistentVillage.java
+++ b/src/main/java/net/minecraft/server/PersistentVillage.java
@@ -136,7 +136,7 @@ public class PersistentVillage extends PersistentBase {
for (int j = -4; j < 4; ++j) {
for (int k = -16; k < 16; ++k) {
blockposition_mutableblockposition.g(blockposition).d(i, j, k);
- IBlockData iblockdata = this.world.getType(blockposition_mutableblockposition);
+ IBlockData iblockdata = this.world.paperConfig.villagesLoadChunks ? this.world.getType(blockposition_mutableblockposition) : this.world.getTypeIfLoaded(blockposition_mutableblockposition); // Paper
if (this.a(iblockdata)) {
VillageDoor villagedoor = this.c(blockposition_mutableblockposition);
@@ -228,7 +228,7 @@ public class PersistentVillage extends PersistentBase {
}
private boolean a(IBlockData iblockdata) {
- return iblockdata.getBlock() instanceof BlockDoor && iblockdata.getMaterial() == Material.WOOD;
+ return iblockdata != null && iblockdata.getBlock() instanceof BlockDoor && iblockdata.getMaterial() == Material.WOOD; // Paper
}
public void a(NBTTagCompound nbttagcompound) {
diff --git a/src/main/java/net/minecraft/server/Village.java b/src/main/java/net/minecraft/server/Village.java
index b794572915..1363c53ff0 100644
--- a/src/main/java/net/minecraft/server/Village.java
+++ b/src/main/java/net/minecraft/server/Village.java
@@ -11,10 +11,10 @@ import javax.annotation.Nullable;
public class Village {
- private World a;
+ private World a; private World getWorld() { return a; } // Paper - OBFHELPER
private final List<VillageDoor> b = Lists.newArrayList();
private BlockPosition c;
- private BlockPosition d;
+ private BlockPosition d;private BlockPosition getCenter() { return d; } // Paper - OBFHELPER
private int e;
private int f;
private int g;
@@ -44,6 +44,12 @@ public class Village {
}
public void a(int i) {
+ // Paper - don't tick village if chunk isn't loaded
+ Chunk chunk = getWorld().getChunkIfLoaded(getCenter());
+ if (chunk == null || !chunk.areNeighborsLoaded(1)) {
+ return;
+ }
+ // Paper end
this.g = i;
this.m();
this.l();
@@ -292,6 +298,12 @@ public class Village {
while (iterator.hasNext()) {
VillageDoor villagedoor = (VillageDoor) iterator.next();
+ // Paper start - don't remove doors from unloaded chunks
+ if (!getWorld().isLoaded(villagedoor.getPosition())) {
+ villagedoor.setLastSeen(villagedoor.getLastSeen() + 1);
+ continue;
+ }
+ // Paper end
if (flag1) {
villagedoor.a();
@@ -312,7 +324,9 @@ public class Village {
}
private boolean g(BlockPosition blockposition) {
- IBlockData iblockdata = this.a.getType(blockposition);
+ IBlockData iblockdata = this.a.paperConfig.villagesLoadChunks ? this.a.getType(blockposition) : this.a.getTypeIfLoaded(blockposition); // Paper
+ if (iblockdata == null) return false; // Paper
+
Block block = iblockdata.getBlock();
return block instanceof BlockDoor ? iblockdata.getMaterial() == Material.WOOD : false;
diff --git a/src/main/java/net/minecraft/server/VillageDoor.java b/src/main/java/net/minecraft/server/VillageDoor.java
index 33ad5faa3e..1edffc4629 100644
--- a/src/main/java/net/minecraft/server/VillageDoor.java
+++ b/src/main/java/net/minecraft/server/VillageDoor.java
@@ -55,6 +55,7 @@ public class VillageDoor {
return this.f;
}
+ public BlockPosition getPosition() { return d(); } // Paper - OBFHELPER
public BlockPosition d() {
return this.a;
}
@@ -71,10 +72,12 @@ public class VillageDoor {
return this.c.getAdjacentZ() * 2;
}
+ public int getLastSeen() { return h(); } // Paper - OBFHELPER
public int h() {
return this.d;
}
+ public void setLastSeen(int i) { a(i); } // Paper - OBFHELPER
public void a(int i) {
this.d = i;
}
--
2.21.0

View file

@ -0,0 +1,51 @@
From 8a4b7bff6950703ef13ea7ce72e80af4cee67d13 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 10 Jun 2018 20:04:42 -0400
Subject: [PATCH] Properly remove entities on dimension teleport
To teleport an entity between dimensions, the server makes a copy
and puts the copy in the new location, and marks the old one dead.
If this method got called for the same world in the same tick,
the entity would not have been removed from the UUID map, and the
world readd would fail.
This can be triggered even with a plugin if the entity is teleported
twice in the same tick, from world A to B, then back from B to A.
The re-add to A will fail to add the entity to the world. It will
actually be there, but it will not be visible on the client until
the server is restarted to re-try the add to world process again.
This bug was unlikely to be seen by many due to the double teleport
requirement, but plugins (such as my own) use this method to
trigger a "reload" of the entity on the client.
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 92a15ba947..debab1a715 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -2611,7 +2611,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
}
// CraftBukkit end */
- this.world.kill(this);
+ this.world.removeEntity(this); // Paper - Fully remove entity, can't have dupes in the UUID map
this.dead = false;
this.world.methodProfiler.enter("reposition");
/* CraftBukkit start - Handled in calculateTarget
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index e4730352d3..c08ee62e84 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -997,6 +997,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
}
protected void c(Entity entity) {
+ if (!this.entitiesByUUID.containsKey(entity.getUniqueID()) && !entity.valid) return; // Paper - Already removed, dont fire twice - this looks like it can happen even without our changes
super.c(entity);
this.entitiesById.d(entity.getId());
this.entitiesByUUID.remove(entity.getUniqueID());
--
2.21.0

View file

@ -0,0 +1,29 @@
From 349376a18c6a86ab6bb07513849d403ab6c71669 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 19 Jul 2018 01:23:00 -0400
Subject: [PATCH] Don't process despawn if entity is in a chunk scheduled for
unload
This won't happen anyways if the user has
"skip ticking for entities in chunks scheduled for unload" turned on,
but if they don't, protect from this instant killing the entity to
keep it vanilla in behavior
a player may teleport away, and trigger instant despawn
diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java
index 98e214cdd6..ee5078370c 100644
--- a/src/main/java/net/minecraft/server/EntityInsentient.java
+++ b/src/main/java/net/minecraft/server/EntityInsentient.java
@@ -634,6 +634,8 @@ public abstract class EntityInsentient extends EntityLiving {
if (this.persistent) {
this.ticksFarFromPlayer = 0;
} else {
+ Chunk currentChunk = getChunkAtLocation(); // Paper
+ if (currentChunk != null && currentChunk.scheduledForUnload != null) return; // Paper
EntityHuman entityhuman = this.world.findNearbyPlayer(this, -1.0D);
if (entityhuman != null && entityhuman.affectsSpawning) { // Paper - Affects Spawning API
--
2.21.0

View file

@ -0,0 +1,81 @@
From c630ddd10b4711ffcd5318829821fb44f48294df Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 29 Aug 2018 21:59:22 -0400
Subject: [PATCH] Optimize getChunkIfLoaded type calls
Uses optimized check to avoid major locks and large method.
Will improve inlining across many hot methods.
Improve getBrightness to not do double chunk map lookups.
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 41926a361b..186cfda7e4 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -379,7 +379,7 @@ public class ChunkProviderServer implements IChunkProvider {
continue;
}
- Chunk neighbor = this.getChunkAt(chunk.locX + x, chunk.locZ + z, false, false);
+ Chunk neighbor = this.chunks.get(chunk.chunkKey); // Paper
if (neighbor != null) {
neighbor.setNeighborUnloaded(-x, -z);
chunk.setNeighborUnloaded(x, z);
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 14f419deb8..630ebfb37c 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -162,7 +162,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
}
public Chunk getChunkIfLoaded(int x, int z) {
- return ((ChunkProviderServer) this.chunkProvider).getChunkAt(x, z, false, false);
+ return ((ChunkProviderServer) this.chunkProvider).chunks.get(ChunkCoordIntPair.a(x, z)); // Paper - optimize getChunkIfLoaded
}
protected World(IDataManager idatamanager, @Nullable PersistentCollection persistentcollection, WorldData worlddata, WorldProvider worldprovider, MethodProfiler methodprofiler, boolean flag, ChunkGenerator gen, org.bukkit.World.Environment env) {
@@ -724,7 +724,8 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
blockposition = new BlockPosition(blockposition.getX(), 0, blockposition.getZ());
}
- return !blockposition.isValidLocation() ? enumskyblock.c : (!this.isLoaded(blockposition) ? enumskyblock.c : this.getChunkAtWorldCoords(blockposition).getBrightness(enumskyblock, blockposition)); // Paper
+ Chunk chunk; // Paper
+ return !blockposition.isValidLocation() ? enumskyblock.c : ((chunk = this.getChunkIfLoaded(blockposition)) == null ? enumskyblock.c : chunk.getBrightness(enumskyblock, blockposition)); // Paper - optimize ifChunkLoaded
}
public void a(EnumSkyBlock enumskyblock, BlockPosition blockposition, int i) {
@@ -1959,7 +1960,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
if (blockposition.isInvalidYLocation()) { // Paper
return false;
} else {
- Chunk chunk = this.chunkProvider.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4, false, false);
+ Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); // Paper - optimize ifLoaded
return chunk != null && !chunk.isEmpty();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 72eb8ed4f4..7e52859c1d 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -218,7 +218,7 @@ public class CraftWorld implements World {
return false;
}
- net.minecraft.server.Chunk chunk = world.getChunkProvider().getChunkAt(x, z, false, false);
+ net.minecraft.server.Chunk chunk = world.getChunkIfLoaded(x, z); // Paper - optimize ifLaoded
if (chunk != null) {
world.getChunkProvider().unload(chunk);
}
@@ -237,7 +237,7 @@ public class CraftWorld implements World {
private boolean unloadChunk0(int x, int z, boolean save) {
Boolean result = MCUtil.ensureMain("Unload Chunk", () -> { // Paper - Ensure never async
- net.minecraft.server.Chunk chunk = world.getChunkProvider().getChunkAt(x, z, false, false);
+ net.minecraft.server.Chunk chunk = world.getChunkIfLoaded(x, z); // Paper - optimize ifLoaded
if (chunk == null) {
return true;
}
--
2.21.0

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
From 68d53d355f81300b2cbd41c12ef16efe87a3d8fb Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 28 Sep 2018 20:46:29 -0400
Subject: [PATCH] Optimize Light Recalculations
Optimizes to not repeatedly look up the same chunk for
light lookups.
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 4f64072a7b..966879a894 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -353,7 +353,7 @@ public class Chunk implements IChunkAccess {
private void a(int i, int j, int k, int l) {
if (l > k && this.areNeighborsLoaded(1)) { // Paper
for (int i1 = k; i1 < l; ++i1) {
- this.world.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j));
+ this.world.updateBrightness(EnumSkyBlock.SKY, new BlockPosition(i, i1, j), this); // Paper
}
this.x = true;
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 97a0fbd55c..fb71879ac0 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -591,8 +591,9 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
}
if (this.worldProvider.g()) {
- for (i1 = k; i1 <= l; ++i1) {
- this.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j));
+ Chunk chunk = getChunkIfLoaded(i >> 4, j >> 4); // Paper
+ for (i1 = k; chunk != null && i1 <= l; ++i1) { // Paper
+ this.updateBrightness(EnumSkyBlock.SKY, new BlockPosition(i, i1, j), chunk); // Paper
}
}
@@ -2220,6 +2221,11 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition) {
// CraftBukkit start - Use neighbor cache instead of looking up
Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ // Paper start - optimize light updates where chunk is known
+ return updateBrightness(enumskyblock, blockposition, chunk);
+ }
+ public boolean updateBrightness(EnumSkyBlock enumskyblock, BlockPosition blockposition, Chunk chunk) {
+ // Paper end
if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) {
// CraftBukkit end
return false;
--
2.21.0

View file

@ -0,0 +1,66 @@
From 07a00d527e871eadaf4a96af5ad367ddcbfa9cc3 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 29 Sep 2018 01:18:16 -0400
Subject: [PATCH] Fix Sending Chunks to Client
Vanilla has some screwy logic that doesn't send a chunk until
it has been post processed. This is an issue as post processing
doesn't occur until all neighbor chunks have been loaded.
This can reduce view distance while generating terrain, but also
cause bugs where chunks are never sent to the client.
This fix always sends chunks to the client, and simply updates
the client anytime post processing is triggered with the new chunk data.
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 0d51c1baeb..46804203fe 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -1190,7 +1190,7 @@ public class Chunk implements IChunkAccess {
}
public boolean isReady() {
- return this.C.a(ChunkStatus.POSTPROCESSED);
+ return true; // Paper - Always send chunks
}
public boolean v() {
@@ -1428,6 +1428,13 @@ public class Chunk implements IChunkAccess {
this.h.clear();
this.a(ChunkStatus.POSTPROCESSED);
this.m.a(this);
+ // Paper start - resend chunk after post process
+ PlayerChunk playerChunk = ((WorldServer) world).getPlayerChunkMap().getChunk(locX, locZ);
+ if (playerChunk != null) {
+ playerChunk.done = false;
+ playerChunk.sendAll();
+ }
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index e4cf8548d3..ac5d158093 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -20,7 +20,7 @@ public class PlayerChunk {
private int dirtyCount;
private int h;
private long i;
- private boolean done;
+ boolean done; // Paper - package-private
boolean chunkExists; // Paper
// Paper start
PaperAsyncChunkProvider.CancellableChunkRequest chunkRequest;
@@ -147,6 +147,7 @@ public class PlayerChunk {
}
}
+ public boolean sendAll() { return b(); } // Paper - OBFHELPER
public boolean b() {
if (this.done) {
return true;
--
2.21.0

View file

@ -0,0 +1,35 @@
From 4e5812633b869d071215da93dc3cffd797de9951 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Wed, 3 Oct 2018 19:04:53 +0100
Subject: [PATCH] Fix FileIOThread concurrency issues
FileIOThread was using two volatile counters in order to track if
any pending work was in the queue, this causes potential concurrency
issues when this counter is updated from multiple threads, potentially
causing these counters to desync due to the unsafe volatile update
diff --git a/src/main/java/net/minecraft/server/FileIOThread.java b/src/main/java/net/minecraft/server/FileIOThread.java
index 3c688f546c..570624600d 100644
--- a/src/main/java/net/minecraft/server/FileIOThread.java
+++ b/src/main/java/net/minecraft/server/FileIOThread.java
@@ -10,7 +10,7 @@ public class FileIOThread implements Runnable {
private static final Logger a = LogManager.getLogger();
private static final FileIOThread b = new FileIOThread();
- private final List<IAsyncChunkSaver> c = Collections.synchronizedList(Lists.newArrayList());
+ private final List<IAsyncChunkSaver> c = Collections.synchronizedList(Lists.newArrayList()); private List<IAsyncChunkSaver> getThreadedIOQueue() { return c; } // Paper - OBFHELPER
private volatile long d;
private volatile long e;
private volatile boolean f;
@@ -75,7 +75,7 @@ public class FileIOThread implements Runnable {
public void b() throws InterruptedException {
this.f = true;
- while (this.d != this.e) {
+ while(!this.getThreadedIOQueue().isEmpty()) { // Paper - check actual list size
Thread.sleep(10L);
}
--
2.21.0

View file

@ -0,0 +1,66 @@
From a576811cfbd84b86003b6d81569f8e4399447a10 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 29 Mar 2019 01:25:11 -0400
Subject: [PATCH] Optimize Persistent Data Loading
removes Mineshaft loading legacy as we had pre 1.13.2 to avoid managing
that very large data file from legacy systems.
Previous to 1.13.2 these data files were never loaded to begin with, so they
effectively do not contain valid/relevant data.
These files take a long time to convert on large worlds and crashes the server.
Additionally, cache the result of a file being missing so we don't keep spam checking it.
diff --git a/src/main/java/net/minecraft/server/WorldPersistentData.java b/src/main/java/net/minecraft/server/WorldPersistentData.java
index 00e9a17355..153809432c 100644
--- a/src/main/java/net/minecraft/server/WorldPersistentData.java
+++ b/src/main/java/net/minecraft/server/WorldPersistentData.java
@@ -26,6 +26,7 @@ public class WorldPersistentData {
this.c = datafixer;
this.d = file;
}
+ private static final PersistentBase NO_RESULT = new ForcedChunk(); // Paper
private File a(String s) {
return new File(this.d, s + ".dat");
@@ -46,14 +47,17 @@ public class WorldPersistentData {
@Nullable
public <T extends PersistentBase> T b(Supplier<T> supplier, String s) {
+ if ("Mineshaft_index".equals(s) || "Mineshaft".equals(s)) return null; // Paper - mineshaft is useless data
T persistentbase = (T) this.data.get(s); // Paper - decompile fix
if (persistentbase == null && !this.data.containsKey(s)) {
persistentbase = this.c(supplier, s);
this.data.put(s, persistentbase);
+ } else { // Paper
+ this.data.put(s, NO_RESULT); // Paper
}
- return persistentbase;
+ return persistentbase == NO_RESULT ? null : persistentbase; // Paper
}
@Nullable
@@ -66,7 +70,7 @@ public class WorldPersistentData {
NBTTagCompound nbttagcompound = this.a(s, SharedConstants.a().getWorldVersion());
t0.a(nbttagcompound.getCompound("data"));
- return t0;
+ return t0 == NO_RESULT ? null : t0; // Paper
}
} catch (Exception exception) {
WorldPersistentData.LOGGER.error("Error loading saved data: {}", s, exception);
@@ -80,6 +84,7 @@ public class WorldPersistentData {
}
public NBTTagCompound a(String s, int i) throws IOException {
+ if ("Mineshaft".equals(s) || "Mineshaft_index".equals(s)) return new NBTTagCompound(); // Paper
File file = this.a(s);
PushbackInputStream pushbackinputstream = new PushbackInputStream(new FileInputStream(file), 2);
Throwable throwable = null;
--
2.22.0

View file

@ -0,0 +1,872 @@
From a7f8efc50ad709eeb7991d8a460ed6075115175d Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Thu, 4 Oct 2018 10:08:02 -0500
Subject: [PATCH] Use EntityTypes for living entities
diff --git a/src/main/java/net/minecraft/server/BlockMonsterEggs.java b/src/main/java/net/minecraft/server/BlockMonsterEggs.java
index 5a0cc6d058..d385f647e7 100644
--- a/src/main/java/net/minecraft/server/BlockMonsterEggs.java
+++ b/src/main/java/net/minecraft/server/BlockMonsterEggs.java
@@ -35,7 +35,7 @@ public class BlockMonsterEggs extends Block {
public void dropNaturally(IBlockData iblockdata, World world, BlockPosition blockposition, float f, int i) {
if (!world.isClientSide && world.getGameRules().getBoolean("doTileDrops")) {
- EntitySilverfish entitysilverfish = new EntitySilverfish(world);
+ EntitySilverfish entitysilverfish = EntityTypes.SILVERFISH.create(world); // Paper
entitysilverfish.setPositionRotation((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, 0.0F, 0.0F);
world.addEntity(entitysilverfish, SpawnReason.SILVERFISH_BLOCK); // CraftBukkit - add SpawnReason
diff --git a/src/main/java/net/minecraft/server/BlockPumpkinCarved.java b/src/main/java/net/minecraft/server/BlockPumpkinCarved.java
index 75622fbdf8..2653699840 100644
--- a/src/main/java/net/minecraft/server/BlockPumpkinCarved.java
+++ b/src/main/java/net/minecraft/server/BlockPumpkinCarved.java
@@ -52,7 +52,7 @@ public class BlockPumpkinCarved extends BlockFacingHorizontal {
blockList.setTypeAndData(shapedetectorblock1.getPosition(), Blocks.AIR.getBlockData(), 2); // CraftBukkit
}
- EntitySnowman entitysnowman = new EntitySnowman(world);
+ EntitySnowman entitysnowman = EntityTypes.SNOW_GOLEM.create(world); // Paper
BlockPosition blockposition1 = shapedetector_shapedetectorcollection.a(0, 2, 0).getPosition();
entitysnowman.setPositionRotation((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.05D, (double) blockposition1.getZ() + 0.5D, 0.0F, 0.0F);
@@ -87,7 +87,7 @@ public class BlockPumpkinCarved extends BlockFacingHorizontal {
}
BlockPosition blockposition2 = shapedetector_shapedetectorcollection.a(1, 2, 0).getPosition();
- EntityIronGolem entityirongolem = new EntityIronGolem(world);
+ EntityIronGolem entityirongolem = EntityTypes.IRON_GOLEM.create(world); // Paper
entityirongolem.setPlayerCreated(true);
entityirongolem.setPositionRotation((double) blockposition2.getX() + 0.5D, (double) blockposition2.getY() + 0.05D, (double) blockposition2.getZ() + 0.5D, 0.0F, 0.0F);
diff --git a/src/main/java/net/minecraft/server/BlockTurtleEgg.java b/src/main/java/net/minecraft/server/BlockTurtleEgg.java
index 0f0872c1e0..1c1bf85a0e 100644
--- a/src/main/java/net/minecraft/server/BlockTurtleEgg.java
+++ b/src/main/java/net/minecraft/server/BlockTurtleEgg.java
@@ -94,7 +94,7 @@ public class BlockTurtleEgg extends Block {
if (!world.isClientSide) {
for (int j = 0; j < (Integer) iblockdata.get(BlockTurtleEgg.b); ++j) {
world.triggerEffect(2001, blockposition, Block.getCombinedId(iblockdata));
- EntityTurtle entityturtle = new EntityTurtle(world);
+ EntityTurtle entityturtle = EntityTypes.TURTLE.create(world); // Paper
entityturtle.setAgeRaw(-24000);
entityturtle.g(blockposition);
diff --git a/src/main/java/net/minecraft/server/BlockWitherSkull.java b/src/main/java/net/minecraft/server/BlockWitherSkull.java
index 93bf32dc1a..e6063bb462 100644
--- a/src/main/java/net/minecraft/server/BlockWitherSkull.java
+++ b/src/main/java/net/minecraft/server/BlockWitherSkull.java
@@ -52,7 +52,7 @@ public class BlockWitherSkull extends BlockSkull {
}
BlockPosition blockposition1 = shapedetector_shapedetectorcollection.a(1, 0, 0).getPosition();
- EntityWither entitywither = new EntityWither(world);
+ EntityWither entitywither = EntityTypes.WITHER.create(world); // Paper
BlockPosition blockposition2 = shapedetector_shapedetectorcollection.a(1, 2, 0).getPosition();
entitywither.setPositionRotation((double) blockposition2.getX() + 0.5D, (double) blockposition2.getY() + 0.55D, (double) blockposition2.getZ() + 0.5D, shapedetector_shapedetectorcollection.getFacing().k() == EnumDirection.EnumAxis.X ? 0.0F : 90.0F, 0.0F);
diff --git a/src/main/java/net/minecraft/server/EnderDragonBattle.java b/src/main/java/net/minecraft/server/EnderDragonBattle.java
index aad7ce93f6..09eabf1235 100644
--- a/src/main/java/net/minecraft/server/EnderDragonBattle.java
+++ b/src/main/java/net/minecraft/server/EnderDragonBattle.java
@@ -412,7 +412,7 @@ public class EnderDragonBattle {
private EntityEnderDragon n() {
this.d.getChunkAtWorldCoords(new BlockPosition(0, 128, 0));
- EntityEnderDragon entityenderdragon = new EntityEnderDragon(this.d);
+ EntityEnderDragon entityenderdragon = EntityTypes.ENDER_DRAGON.create(this.d); // Paper
entityenderdragon.getDragonControllerManager().setControllerPhase(DragonControllerPhase.HOLDING_PATTERN);
entityenderdragon.setPositionRotation(0.0D, 128.0D, 0.0D, this.d.random.nextFloat() * 360.0F, 0.0F);
diff --git a/src/main/java/net/minecraft/server/EntityChicken.java b/src/main/java/net/minecraft/server/EntityChicken.java
index ee159e0a81..070a9e7b14 100644
--- a/src/main/java/net/minecraft/server/EntityChicken.java
+++ b/src/main/java/net/minecraft/server/EntityChicken.java
@@ -96,7 +96,7 @@ public class EntityChicken extends EntityAnimal {
}
public EntityChicken createChild(EntityAgeable entityageable) {
- return new EntityChicken(this.world);
+ return EntityTypes.CHICKEN.create(world); // Paper
}
public boolean f(ItemStack itemstack) {
diff --git a/src/main/java/net/minecraft/server/EntityCow.java b/src/main/java/net/minecraft/server/EntityCow.java
index 5874d2993c..cc53e915d7 100644
--- a/src/main/java/net/minecraft/server/EntityCow.java
+++ b/src/main/java/net/minecraft/server/EntityCow.java
@@ -88,7 +88,7 @@ public class EntityCow extends EntityAnimal {
}
public EntityCow createChild(EntityAgeable entityageable) {
- return new EntityCow(this.world);
+ return EntityTypes.COW.create(world); // Paper
}
public float getHeadHeight() {
diff --git a/src/main/java/net/minecraft/server/EntityEnderPearl.java b/src/main/java/net/minecraft/server/EntityEnderPearl.java
index 961afa5c42..a372f6508f 100644
--- a/src/main/java/net/minecraft/server/EntityEnderPearl.java
+++ b/src/main/java/net/minecraft/server/EntityEnderPearl.java
@@ -74,7 +74,7 @@ public class EntityEnderPearl extends EntityProjectile {
if (!teleEvent.isCancelled() && !entityplayer.playerConnection.isDisconnected()) {
if (this.random.nextFloat() < 0.05F && this.world.getGameRules().getBoolean("doMobSpawning")) {
- EntityEndermite entityendermite = new EntityEndermite(this.world);
+ EntityEndermite entityendermite = EntityTypes.ENDERMITE.create(world); // Paper
entityendermite.setPlayerSpawned(true);
entityendermite.setPositionRotation(entityliving.locX, entityliving.locY, entityliving.locZ, entityliving.yaw, entityliving.pitch);
diff --git a/src/main/java/net/minecraft/server/EntityEvoker.java b/src/main/java/net/minecraft/server/EntityEvoker.java
index 963b6fbb9c..fc20bbe272 100644
--- a/src/main/java/net/minecraft/server/EntityEvoker.java
+++ b/src/main/java/net/minecraft/server/EntityEvoker.java
@@ -188,8 +188,7 @@ public class EntityEvoker extends EntityIllagerWizard {
protected void j() {
for (int i = 0; i < 3; ++i) {
BlockPosition blockposition = (new BlockPosition(EntityEvoker.this)).a(-2 + EntityEvoker.this.random.nextInt(5), 1, -2 + EntityEvoker.this.random.nextInt(5));
- EntityVex entityvex = new EntityVex(EntityEvoker.this.world);
-
+ EntityVex entityvex = EntityTypes.VEX.create(EntityEvoker.this.world); // Paper
entityvex.setPositionRotation(blockposition, 0.0F, 0.0F);
entityvex.prepare(EntityEvoker.this.world.getDamageScaler(blockposition), (GroupDataEntity) null, (NBTTagCompound) null);
entityvex.a((EntityInsentient) EntityEvoker.this);
diff --git a/src/main/java/net/minecraft/server/EntityHorse.java b/src/main/java/net/minecraft/server/EntityHorse.java
index 4e8a97c557..1b9425f3e6 100644
--- a/src/main/java/net/minecraft/server/EntityHorse.java
+++ b/src/main/java/net/minecraft/server/EntityHorse.java
@@ -208,11 +208,11 @@ public class EntityHorse extends EntityHorseAbstract {
Object object;
if (entityageable instanceof EntityHorseDonkey) {
- object = new EntityHorseMule(this.world);
+ object = EntityTypes.MULE.create(world); // Paper
} else {
EntityHorse entityhorse = (EntityHorse) entityageable;
- object = new EntityHorse(this.world);
+ object = EntityTypes.HORSE.create(world); // Paper
int i = this.random.nextInt(9);
int j;
diff --git a/src/main/java/net/minecraft/server/EntityHorseDonkey.java b/src/main/java/net/minecraft/server/EntityHorseDonkey.java
index 72eed22eb9..65c40e72bf 100644
--- a/src/main/java/net/minecraft/server/EntityHorseDonkey.java
+++ b/src/main/java/net/minecraft/server/EntityHorseDonkey.java
@@ -33,7 +33,7 @@ public class EntityHorseDonkey extends EntityHorseChestedAbstract {
}
public EntityAgeable createChild(EntityAgeable entityageable) {
- Object object = entityageable instanceof EntityHorse ? new EntityHorseMule(this.world) : new EntityHorseDonkey(this.world);
+ Object object = entityageable instanceof EntityHorse ? EntityTypes.MULE.create(world) : EntityTypes.DONKEY.create(world); // Paper
this.a(entityageable, (EntityHorseAbstract) object);
return (EntityAgeable) object;
diff --git a/src/main/java/net/minecraft/server/EntityHorseSkeleton.java b/src/main/java/net/minecraft/server/EntityHorseSkeleton.java
index eae2b26655..0a092acdfe 100644
--- a/src/main/java/net/minecraft/server/EntityHorseSkeleton.java
+++ b/src/main/java/net/minecraft/server/EntityHorseSkeleton.java
@@ -134,7 +134,7 @@ public class EntityHorseSkeleton extends EntityHorseAbstract {
@Nullable
public EntityAgeable createChild(EntityAgeable entityageable) {
- return new EntityHorseSkeleton(this.world);
+ return EntityTypes.SKELETON_HORSE.create(world); // Paper
}
public boolean a(EntityHuman entityhuman, EnumHand enumhand) {
diff --git a/src/main/java/net/minecraft/server/EntityHorseZombie.java b/src/main/java/net/minecraft/server/EntityHorseZombie.java
index c23bc72fc8..a1873f557c 100644
--- a/src/main/java/net/minecraft/server/EntityHorseZombie.java
+++ b/src/main/java/net/minecraft/server/EntityHorseZombie.java
@@ -41,7 +41,7 @@ public class EntityHorseZombie extends EntityHorseAbstract {
@Nullable
public EntityAgeable createChild(EntityAgeable entityageable) {
- return new EntityHorseZombie(this.world);
+ return EntityTypes.ZOMBIE_HORSE.create(world); // Paper
}
public boolean a(EntityHuman entityhuman, EnumHand enumhand) {
diff --git a/src/main/java/net/minecraft/server/EntityLlama.java b/src/main/java/net/minecraft/server/EntityLlama.java
index 5e19768710..82a32c61ed 100644
--- a/src/main/java/net/minecraft/server/EntityLlama.java
+++ b/src/main/java/net/minecraft/server/EntityLlama.java
@@ -285,7 +285,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn
}
public EntityLlama createChild(EntityAgeable entityageable) {
- EntityLlama entityllama = new EntityLlama(this.world);
+ EntityLlama entityllama = EntityTypes.LLAMA.create(world); // Paper
this.a(entityageable, (EntityHorseAbstract) entityllama);
EntityLlama entityllama1 = (EntityLlama) entityageable;
diff --git a/src/main/java/net/minecraft/server/EntityMushroomCow.java b/src/main/java/net/minecraft/server/EntityMushroomCow.java
index dde9f1e61e..638dbe978d 100644
--- a/src/main/java/net/minecraft/server/EntityMushroomCow.java
+++ b/src/main/java/net/minecraft/server/EntityMushroomCow.java
@@ -40,7 +40,7 @@ public class EntityMushroomCow extends EntityCow {
this.world.addParticle(Particles.u, this.locX, this.locY + (double) (this.length / 2.0F), this.locZ, 0.0D, 0.0D, 0.0D);
if (!this.world.isClientSide) {
// this.die(); // CraftBukkit - moved down
- EntityCow entitycow = new EntityCow(this.world);
+ EntityCow entitycow = EntityTypes.COW.create(world); // Paper
entitycow.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, this.pitch);
entitycow.setHealth(this.getHealth());
@@ -74,7 +74,7 @@ public class EntityMushroomCow extends EntityCow {
}
public EntityMushroomCow createChild(EntityAgeable entityageable) {
- return new EntityMushroomCow(this.world);
+ return EntityTypes.MOOSHROOM.create(world); // Paper
}
@Nullable
diff --git a/src/main/java/net/minecraft/server/EntityOcelot.java b/src/main/java/net/minecraft/server/EntityOcelot.java
index ba074c10c6..13c84bda84 100644
--- a/src/main/java/net/minecraft/server/EntityOcelot.java
+++ b/src/main/java/net/minecraft/server/EntityOcelot.java
@@ -154,7 +154,7 @@ public class EntityOcelot extends EntityTameableAnimal {
}
public EntityOcelot createChild(EntityAgeable entityageable) {
- EntityOcelot entityocelot = new EntityOcelot(this.world);
+ EntityOcelot entityocelot = EntityTypes.OCELOT.create(world); // Paper
if (this.isTamed()) {
entityocelot.setOwnerUUID(this.getOwnerUUID());
@@ -237,7 +237,7 @@ public class EntityOcelot extends EntityTameableAnimal {
groupdataentity = super.prepare(difficultydamagescaler, groupdataentity, nbttagcompound);
if (spawnBonus && this.getCatType() == 0 && this.world.random.nextInt(7) == 0) { // Spigot
for (int i = 0; i < 2; ++i) {
- EntityOcelot entityocelot = new EntityOcelot(this.world);
+ EntityOcelot entityocelot = EntityTypes.OCELOT.create(world); // Paper
entityocelot.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F);
entityocelot.setAgeRaw(-24000);
diff --git a/src/main/java/net/minecraft/server/EntityPig.java b/src/main/java/net/minecraft/server/EntityPig.java
index 9dc2d8be27..d1689dc33a 100644
--- a/src/main/java/net/minecraft/server/EntityPig.java
+++ b/src/main/java/net/minecraft/server/EntityPig.java
@@ -153,7 +153,7 @@ public class EntityPig extends EntityAnimal {
public void onLightningStrike(EntityLightning entitylightning) {
if (!this.world.isClientSide && !this.dead) {
- EntityPigZombie entitypigzombie = new EntityPigZombie(this.world);
+ EntityPigZombie entitypigzombie = EntityTypes.ZOMBIE_PIGMAN.create(world); // Paper
entitypigzombie.setSlot(EnumItemSlot.MAINHAND, new ItemStack(Items.GOLDEN_SWORD));
entitypigzombie.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, this.pitch);
@@ -242,7 +242,7 @@ public class EntityPig extends EntityAnimal {
}
public EntityPig createChild(EntityAgeable entityageable) {
- return new EntityPig(this.world);
+ return EntityTypes.PIG.create(world); // Paper
}
public boolean f(ItemStack itemstack) {
diff --git a/src/main/java/net/minecraft/server/EntityPolarBear.java b/src/main/java/net/minecraft/server/EntityPolarBear.java
index a02020d5fc..dbb534c9cd 100644
--- a/src/main/java/net/minecraft/server/EntityPolarBear.java
+++ b/src/main/java/net/minecraft/server/EntityPolarBear.java
@@ -18,7 +18,7 @@ public class EntityPolarBear extends EntityAnimal {
}
public EntityAgeable createChild(EntityAgeable entityageable) {
- return new EntityPolarBear(this.world);
+ return EntityTypes.POLAR_BEAR.create(world); // Paper
}
public boolean f(ItemStack itemstack) {
diff --git a/src/main/java/net/minecraft/server/EntityRabbit.java b/src/main/java/net/minecraft/server/EntityRabbit.java
index e545b1c9b3..d6bac06a7a 100644
--- a/src/main/java/net/minecraft/server/EntityRabbit.java
+++ b/src/main/java/net/minecraft/server/EntityRabbit.java
@@ -251,7 +251,7 @@ public class EntityRabbit extends EntityAnimal {
}
public EntityRabbit createChild(EntityAgeable entityageable) {
- EntityRabbit entityrabbit = new EntityRabbit(this.world);
+ EntityRabbit entityrabbit = EntityTypes.RABBIT.create(world); // Paper
int i = this.dJ();
if (this.random.nextInt(20) != 0) {
diff --git a/src/main/java/net/minecraft/server/EntitySheep.java b/src/main/java/net/minecraft/server/EntitySheep.java
index f7a25c1483..c35d1eef43 100644
--- a/src/main/java/net/minecraft/server/EntitySheep.java
+++ b/src/main/java/net/minecraft/server/EntitySheep.java
@@ -247,7 +247,7 @@ public class EntitySheep extends EntityAnimal {
public EntitySheep createChild(EntityAgeable entityageable) {
EntitySheep entitysheep = (EntitySheep) entityageable;
- EntitySheep entitysheep1 = new EntitySheep(this.world);
+ EntitySheep entitysheep1 = EntityTypes.SHEEP.create(world); // Paper
entitysheep1.setColor(this.a((EntityAnimal) this, (EntityAnimal) entitysheep));
return entitysheep1;
diff --git a/src/main/java/net/minecraft/server/EntitySpider.java b/src/main/java/net/minecraft/server/EntitySpider.java
index a42b8d554f..9ef1c9baf2 100644
--- a/src/main/java/net/minecraft/server/EntitySpider.java
+++ b/src/main/java/net/minecraft/server/EntitySpider.java
@@ -111,7 +111,7 @@ public class EntitySpider extends EntityMonster {
Object object = super.prepare(difficultydamagescaler, groupdataentity, nbttagcompound);
if (this.world.random.nextInt(100) == 0) {
- EntitySkeleton entityskeleton = new EntitySkeleton(this.world);
+ EntitySkeleton entityskeleton = EntityTypes.SKELETON.create(world); // Paper
entityskeleton.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F);
entityskeleton.prepare(difficultydamagescaler, (GroupDataEntity) null, (NBTTagCompound) null);
diff --git a/src/main/java/net/minecraft/server/EntityTurtle.java b/src/main/java/net/minecraft/server/EntityTurtle.java
index a533e0eb5b..270b950820 100644
--- a/src/main/java/net/minecraft/server/EntityTurtle.java
+++ b/src/main/java/net/minecraft/server/EntityTurtle.java
@@ -218,7 +218,7 @@ public class EntityTurtle extends EntityAnimal {
@Nullable
public EntityAgeable createChild(EntityAgeable entityageable) {
- return new EntityTurtle(this.world);
+ return EntityTypes.TURTLE.create(world); // Paper
}
public boolean f(ItemStack itemstack) {
diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java
index d74bfa1201..24ca351194 100644
--- a/src/main/java/net/minecraft/server/EntityTypes.java
+++ b/src/main/java/net/minecraft/server/EntityTypes.java
@@ -269,6 +269,7 @@ public class EntityTypes<T extends Entity> {
return this.aX;
}
+ @Nullable public T create(World world) { return a(world); } // Paper - OBFHELPER
@Nullable
public T a(World world) {
return this.aT.apply(world); // CraftBukkit - decompile error
diff --git a/src/main/java/net/minecraft/server/EntityVillager.java b/src/main/java/net/minecraft/server/EntityVillager.java
index f01e776fe5..40b3ffd8ca 100644
--- a/src/main/java/net/minecraft/server/EntityVillager.java
+++ b/src/main/java/net/minecraft/server/EntityVillager.java
@@ -592,7 +592,7 @@ public class EntityVillager extends EntityAgeable implements NPC, IMerchant {
}
public EntityVillager createChild(EntityAgeable entityageable) {
- EntityVillager entityvillager = new EntityVillager(this.world);
+ EntityVillager entityvillager = EntityTypes.VILLAGER.create(world); // Paper
entityvillager.prepare(this.world.getDamageScaler(new BlockPosition(entityvillager)), (GroupDataEntity) null, (NBTTagCompound) null);
return entityvillager;
@@ -604,7 +604,7 @@ public class EntityVillager extends EntityAgeable implements NPC, IMerchant {
public void onLightningStrike(EntityLightning entitylightning) {
if (!this.world.isClientSide && !this.dead) {
- EntityWitch entitywitch = new EntityWitch(this.world);
+ EntityWitch entitywitch = EntityTypes.WITCH.create(world); // Paper
// Paper start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityZapEvent(this, entitylightning, entitywitch).isCancelled()) {
diff --git a/src/main/java/net/minecraft/server/EntityWolf.java b/src/main/java/net/minecraft/server/EntityWolf.java
index 4f1696d018..46d8e0a1f4 100644
--- a/src/main/java/net/minecraft/server/EntityWolf.java
+++ b/src/main/java/net/minecraft/server/EntityWolf.java
@@ -342,7 +342,7 @@ public class EntityWolf extends EntityTameableAnimal {
}
public EntityWolf createChild(EntityAgeable entityageable) {
- EntityWolf entitywolf = new EntityWolf(this.world);
+ EntityWolf entitywolf = EntityTypes.WOLF.create(world); // Paper
UUID uuid = this.getOwnerUUID();
if (uuid != null) {
diff --git a/src/main/java/net/minecraft/server/EntityZombie.java b/src/main/java/net/minecraft/server/EntityZombie.java
index 7998b80c17..81cc0c3b33 100644
--- a/src/main/java/net/minecraft/server/EntityZombie.java
+++ b/src/main/java/net/minecraft/server/EntityZombie.java
@@ -208,7 +208,7 @@ public class EntityZombie extends EntityMonster {
}
protected void dE() {
- this.a((EntityZombie) (new EntityDrowned(this.world)));
+ this.a((EntityZombie) EntityTypes.DROWNED.create(world)); // Paper
this.world.a((EntityHuman) null, 1040, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0);
}
@@ -261,7 +261,7 @@ public class EntityZombie extends EntityMonster {
int i = MathHelper.floor(this.locX);
int j = MathHelper.floor(this.locY);
int k = MathHelper.floor(this.locZ);
- EntityZombie entityzombie = new EntityZombie(this.world);
+ EntityZombie entityzombie = EntityTypes.ZOMBIE.create(world); // Paper
for (int l = 0; l < 50; ++l) {
int i1 = i + MathHelper.nextInt(this.random, 7, 40) * MathHelper.nextInt(this.random, -1, 1);
@@ -385,7 +385,7 @@ public class EntityZombie extends EntityMonster {
}
EntityVillager entityvillager = (EntityVillager) entityliving;
- EntityZombieVillager entityzombievillager = new EntityZombieVillager(this.world);
+ EntityZombieVillager entityzombievillager = EntityTypes.ZOMBIE_VILLAGER.create(world); // Paper
entityzombievillager.u(entityvillager);
// this.world.kill(entityvillager); // CraftBukkit - moved down
@@ -450,7 +450,7 @@ public class EntityZombie extends EntityMonster {
this.startRiding(entitychicken);
}
} else if ((double) this.world.random.nextFloat() < 0.05D) {
- EntityChicken entitychicken1 = new EntityChicken(this.world);
+ EntityChicken entitychicken1 = EntityTypes.CHICKEN.create(world); // Paper
entitychicken1.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, 0.0F);
entitychicken1.prepare(difficultydamagescaler, (GroupDataEntity) null, (NBTTagCompound) null);
diff --git a/src/main/java/net/minecraft/server/EntityZombieHusk.java b/src/main/java/net/minecraft/server/EntityZombieHusk.java
index 85d402965b..0cca7b6d51 100644
--- a/src/main/java/net/minecraft/server/EntityZombieHusk.java
+++ b/src/main/java/net/minecraft/server/EntityZombieHusk.java
@@ -54,7 +54,7 @@ public class EntityZombieHusk extends EntityZombie {
}
protected void dE() {
- this.a(new EntityZombie(this.world));
+ this.a(EntityTypes.ZOMBIE.create(world)); // Paper
this.world.a((EntityHuman) null, 1041, new BlockPosition((int) this.locX, (int) this.locY, (int) this.locZ), 0);
}
diff --git a/src/main/java/net/minecraft/server/EntityZombieVillager.java b/src/main/java/net/minecraft/server/EntityZombieVillager.java
index 359ac8b88c..96a1b1d3f2 100644
--- a/src/main/java/net/minecraft/server/EntityZombieVillager.java
+++ b/src/main/java/net/minecraft/server/EntityZombieVillager.java
@@ -119,7 +119,7 @@ public class EntityZombieVillager extends EntityZombie {
}
protected void dJ() {
- EntityVillager entityvillager = new EntityVillager(this.world);
+ EntityVillager entityvillager = EntityTypes.VILLAGER.create(world); // Paper
entityvillager.u(this);
entityvillager.setProfession(this.getProfession());
diff --git a/src/main/java/net/minecraft/server/ItemArmorStand.java b/src/main/java/net/minecraft/server/ItemArmorStand.java
index 576b3c5650..4dd0e39ec3 100644
--- a/src/main/java/net/minecraft/server/ItemArmorStand.java
+++ b/src/main/java/net/minecraft/server/ItemArmorStand.java
@@ -34,7 +34,7 @@ public class ItemArmorStand extends Item {
if (!world.isClientSide) {
world.setAir(blockposition);
world.setAir(blockposition1);
- EntityArmorStand entityarmorstand = new EntityArmorStand(world, d0 + 0.5D, d1, d2 + 0.5D);
+ EntityArmorStand entityarmorstand = EntityTypes.ARMOR_STAND.create(world); // Paper
float f = (float) MathHelper.d((MathHelper.g(itemactioncontext.h() - 180.0F) + 22.5F) / 45.0F) * 45.0F;
entityarmorstand.setPositionRotation(d0 + 0.5D, d1, d2 + 0.5D, f, 0.0F);
diff --git a/src/main/java/net/minecraft/server/MobSpawnerPhantom.java b/src/main/java/net/minecraft/server/MobSpawnerPhantom.java
index 5ddf66eef5..bb7e072ee1 100644
--- a/src/main/java/net/minecraft/server/MobSpawnerPhantom.java
+++ b/src/main/java/net/minecraft/server/MobSpawnerPhantom.java
@@ -59,7 +59,7 @@ public class MobSpawnerPhantom {
continue;
}
// Paper end
- EntityPhantom entityphantom = new EntityPhantom(world);
+ EntityPhantom entityphantom = EntityTypes.PHANTOM.create(world); // Paper
entityphantom.spawningEntity = entityhuman.uniqueID; // Paper
entityphantom.setPositionRotation(blockposition1, 0.0F, 0.0F);
groupdataentity = entityphantom.prepare(difficultydamagescaler, groupdataentity, (NBTTagCompound) null);
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalHorseTrap.java b/src/main/java/net/minecraft/server/PathfinderGoalHorseTrap.java
index d4fdcbdfd6..887e4461f3 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalHorseTrap.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalHorseTrap.java
@@ -36,7 +36,7 @@ public class PathfinderGoalHorseTrap extends PathfinderGoal {
}
private EntityHorseAbstract a(DifficultyDamageScaler difficultydamagescaler) {
- EntityHorseSkeleton entityhorseskeleton = new EntityHorseSkeleton(this.a.world);
+ EntityHorseSkeleton entityhorseskeleton = EntityTypes.SKELETON_HORSE.create(a.world); // Paper
entityhorseskeleton.prepare(difficultydamagescaler, (GroupDataEntity) null, (NBTTagCompound) null);
entityhorseskeleton.setPosition(this.a.locX, this.a.locY, this.a.locZ);
@@ -49,7 +49,7 @@ public class PathfinderGoalHorseTrap extends PathfinderGoal {
}
private EntitySkeleton a(DifficultyDamageScaler difficultydamagescaler, EntityHorseAbstract entityhorseabstract) {
- EntitySkeleton entityskeleton = new EntitySkeleton(entityhorseabstract.world);
+ EntitySkeleton entityskeleton = EntityTypes.SKELETON.create(entityhorseabstract.world); // Paper
entityskeleton.prepare(difficultydamagescaler, (GroupDataEntity) null, (NBTTagCompound) null);
entityskeleton.setPosition(entityhorseabstract.locX, entityhorseabstract.locY, entityhorseabstract.locZ);
diff --git a/src/main/java/net/minecraft/server/VillageSiege.java b/src/main/java/net/minecraft/server/VillageSiege.java
index 0ac1fb53a4..509d62f6b6 100644
--- a/src/main/java/net/minecraft/server/VillageSiege.java
+++ b/src/main/java/net/minecraft/server/VillageSiege.java
@@ -134,7 +134,7 @@ public class VillageSiege {
EntityZombie entityzombie;
try {
- entityzombie = new EntityZombie(this.a);
+ entityzombie = EntityTypes.ZOMBIE.create(this.a); // Paper
entityzombie.prepare(this.a.getDamageScaler(new BlockPosition(entityzombie)), (GroupDataEntity) null, (NBTTagCompound) null);
} catch (Exception exception) {
exception.printStackTrace();
diff --git a/src/main/java/net/minecraft/server/WorldGenEndCityPieces.java b/src/main/java/net/minecraft/server/WorldGenEndCityPieces.java
index 94b21693e2..0a223cfe5a 100644
--- a/src/main/java/net/minecraft/server/WorldGenEndCityPieces.java
+++ b/src/main/java/net/minecraft/server/WorldGenEndCityPieces.java
@@ -270,7 +270,7 @@ public class WorldGenEndCityPieces {
TileEntityLootable.a(generatoraccess, random, blockposition1, LootTables.c);
}
} else if (s.startsWith("Sentry")) {
- EntityShulker entityshulker = new EntityShulker(generatoraccess.getMinecraftWorld());
+ EntityShulker entityshulker = EntityTypes.SHULKER.create(generatoraccess.getMinecraftWorld()); // Paper
entityshulker.setPosition((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D);
entityshulker.g(blockposition);
diff --git a/src/main/java/net/minecraft/server/WorldGenFeatureOceanRuinPieces.java b/src/main/java/net/minecraft/server/WorldGenFeatureOceanRuinPieces.java
index 2def56b067..abeb4aa025 100644
--- a/src/main/java/net/minecraft/server/WorldGenFeatureOceanRuinPieces.java
+++ b/src/main/java/net/minecraft/server/WorldGenFeatureOceanRuinPieces.java
@@ -154,8 +154,7 @@ public class WorldGenFeatureOceanRuinPieces {
((TileEntityChest) tileentity).setLootTable(this.h ? LootTables.q : LootTables.p, random.nextLong());
}
} else if ("drowned".equals(s)) {
- EntityDrowned entitydrowned = new EntityDrowned(generatoraccess.getMinecraftWorld());
-
+ EntityDrowned entitydrowned = EntityTypes.DROWNED.create(generatoraccess.getMinecraftWorld()); // Paper
entitydrowned.di();
entitydrowned.setPositionRotation(blockposition, 0.0F, 0.0F);
entitydrowned.prepare(generatoraccess.getDamageScaler(blockposition), (GroupDataEntity) null, (NBTTagCompound) null);
diff --git a/src/main/java/net/minecraft/server/WorldGenMonumentPieces.java b/src/main/java/net/minecraft/server/WorldGenMonumentPieces.java
index 0e7aed09d1..493a86e1bf 100644
--- a/src/main/java/net/minecraft/server/WorldGenMonumentPieces.java
+++ b/src/main/java/net/minecraft/server/WorldGenMonumentPieces.java
@@ -1800,7 +1800,7 @@ public class WorldGenMonumentPieces {
protected static final IBlockData d = WorldGenMonumentPieces.WorldGenMonumentPiece.b;
protected static final IBlockData e = Blocks.SEA_LANTERN.getBlockData();
protected static final IBlockData f = Blocks.WATER.getBlockData();
- protected static final Set<Block> g = ImmutableSet.builder().add(Blocks.ICE).add(Blocks.PACKED_ICE).add(Blocks.BLUE_ICE).add(WorldGenMonumentPieces.WorldGenMonumentPiece.f.getBlock()).build();
+ protected static final Set<Block> g = ImmutableSet.<Block>builder().add(Blocks.ICE).add(Blocks.PACKED_ICE).add(Blocks.BLUE_ICE).add(WorldGenMonumentPieces.WorldGenMonumentPiece.f.getBlock()).build(); // Paper - decompile fix
protected static final int h = b(2, 0, 0);
protected static final int i = b(2, 2, 0);
protected static final int j = b(0, 1, 0);
@@ -1923,7 +1923,7 @@ public class WorldGenMonumentPieces {
int j1 = this.b(i, k);
if (structureboundingbox.b((BaseBlockPosition) (new BlockPosition(l, i1, j1)))) {
- EntityGuardianElder entityguardianelder = new EntityGuardianElder(generatoraccess.getMinecraftWorld());
+ EntityGuardianElder entityguardianelder = EntityTypes.ELDER_GUARDIAN.create(generatoraccess.getMinecraftWorld()); // Paper
entityguardianelder.heal(entityguardianelder.getMaxHealth());
entityguardianelder.setPositionRotation((double) l + 0.5D, (double) i1, (double) j1 + 0.5D, 0.0F, 0.0F);
diff --git a/src/main/java/net/minecraft/server/WorldGenVillagePieces.java b/src/main/java/net/minecraft/server/WorldGenVillagePieces.java
index 5fa2987d2a..967e33b3d7 100644
--- a/src/main/java/net/minecraft/server/WorldGenVillagePieces.java
+++ b/src/main/java/net/minecraft/server/WorldGenVillagePieces.java
@@ -1640,7 +1640,7 @@ public class WorldGenVillagePieces {
++this.a;
if (this.h) {
- EntityZombieVillager entityzombievillager = new EntityZombieVillager(generatoraccess.getMinecraftWorld());
+ EntityZombieVillager entityzombievillager = EntityTypes.ZOMBIE_VILLAGER.create(generatoraccess.getMinecraftWorld()); // Paper
entityzombievillager.setPositionRotation((double) j1 + 0.5D, (double) k1, (double) l1 + 0.5D, 0.0F, 0.0F);
entityzombievillager.prepare(generatoraccess.getDamageScaler(new BlockPosition(entityzombievillager)), (GroupDataEntity) null, (NBTTagCompound) null);
@@ -1648,7 +1648,7 @@ public class WorldGenVillagePieces {
entityzombievillager.di();
generatoraccess.addEntity(entityzombievillager, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit - add SpawnReason
} else {
- EntityVillager entityvillager = new EntityVillager(generatoraccess.getMinecraftWorld());
+ EntityVillager entityvillager = EntityTypes.VILLAGER.create(generatoraccess.getMinecraftWorld()); // Paper
entityvillager.setPositionRotation((double) j1 + 0.5D, (double) k1, (double) l1 + 0.5D, 0.0F, 0.0F);
entityvillager.setProfession(this.c(i1, generatoraccess.m().nextInt(6)));
diff --git a/src/main/java/net/minecraft/server/WorldGenWitchHut.java b/src/main/java/net/minecraft/server/WorldGenWitchHut.java
index efb0379ce3..3d8193c477 100644
--- a/src/main/java/net/minecraft/server/WorldGenWitchHut.java
+++ b/src/main/java/net/minecraft/server/WorldGenWitchHut.java
@@ -81,7 +81,7 @@ public class WorldGenWitchHut extends WorldGenScatteredPiece {
if (structureboundingbox.b((BaseBlockPosition) (new BlockPosition(j, i, k)))) {
this.e = true;
- EntityWitch entitywitch = new EntityWitch(generatoraccess.getMinecraftWorld());
+ EntityWitch entitywitch = EntityTypes.WITCH.create(generatoraccess.getMinecraftWorld()); // Paper
entitywitch.di();
entitywitch.setPositionRotation((double) j + 0.5D, (double) i, (double) k + 0.5D, 0.0F, 0.0F);
diff --git a/src/main/java/net/minecraft/server/WorldGenWoodlandMansionPieces.java b/src/main/java/net/minecraft/server/WorldGenWoodlandMansionPieces.java
index 11010d8e12..4eb746ebb0 100644
--- a/src/main/java/net/minecraft/server/WorldGenWoodlandMansionPieces.java
+++ b/src/main/java/net/minecraft/server/WorldGenWoodlandMansionPieces.java
@@ -23,14 +23,14 @@ public class WorldGenWoodlandMansionPieces {
static class h extends WorldGenWoodlandMansionPieces.f {
private h() {
- super(null);
+ super(); // Paper - decompile fix
}
}
static class f extends WorldGenWoodlandMansionPieces.b {
private f() {
- super(null);
+ super(); // Paper - decompile fix
}
public String a(Random random) {
@@ -65,7 +65,7 @@ public class WorldGenWoodlandMansionPieces {
static class a extends WorldGenWoodlandMansionPieces.b {
private a() {
- super(null);
+ super(); // Paper - decompile fix
}
public String a(Random random) {
@@ -1065,15 +1065,13 @@ public class WorldGenWoodlandMansionPieces {
this.a(generatoraccess, structureboundingbox, random, blockposition, LootTables.o, iblockdata);
} else if ("Mage".equals(s)) {
- EntityEvoker entityevoker = new EntityEvoker(generatoraccess.getMinecraftWorld());
-
+ EntityEvoker entityevoker = EntityTypes.EVOKER.create(generatoraccess.getMinecraftWorld()); // Paper
entityevoker.di();
entityevoker.setPositionRotation(blockposition, 0.0F, 0.0F);
generatoraccess.addEntity(entityevoker);
generatoraccess.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 2);
} else if ("Warrior".equals(s)) {
- EntityVindicator entityvindicator = new EntityVindicator(generatoraccess.getMinecraftWorld());
-
+ EntityVindicator entityvindicator = EntityTypes.VINDICATOR.create(generatoraccess.getMinecraftWorld()); // Paper
entityvindicator.di();
entityvindicator.setPositionRotation(blockposition, 0.0F, 0.0F);
entityvindicator.prepare(generatoraccess.getDamageScaler(new BlockPosition(entityvindicator)), (GroupDataEntity) null, (NBTTagCompound) null);
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 53e7834cca..5c2421ac38 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -495,7 +495,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
boolean flag2 = this.getGameRules().getBoolean("doMobSpawning") && this.random.nextDouble() < (double) difficultydamagescaler.b() * paperConfig.skeleHorseSpawnChance; // Paper
if (flag2) {
- EntityHorseSkeleton entityhorseskeleton = new EntityHorseSkeleton(this);
+ EntityHorseSkeleton entityhorseskeleton = EntityTypes.SKELETON_HORSE.create(this); // Paper
entityhorseskeleton.s(true);
entityhorseskeleton.setAgeRaw(0);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 7c0a530533..40ee34675c 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1181,153 +1181,153 @@ public class CraftWorld implements World {
entity.setPositionRotation(x, y, z, 0, 0);
} else if (LivingEntity.class.isAssignableFrom(clazz)) {
if (Chicken.class.isAssignableFrom(clazz)) {
- entity = new EntityChicken(world);
+ entity = EntityTypes.CHICKEN.create(world); // Paper
} else if (Cow.class.isAssignableFrom(clazz)) {
if (MushroomCow.class.isAssignableFrom(clazz)) {
- entity = new EntityMushroomCow(world);
+ entity = EntityTypes.MOOSHROOM.create(world); // Paper
} else {
- entity = new EntityCow(world);
+ entity = EntityTypes.COW.create(world); // Paper
}
} else if (Golem.class.isAssignableFrom(clazz)) {
if (Snowman.class.isAssignableFrom(clazz)) {
- entity = new EntitySnowman(world);
+ entity = EntityTypes.SNOW_GOLEM.create(world); // Paper
} else if (IronGolem.class.isAssignableFrom(clazz)) {
- entity = new EntityIronGolem(world);
+ entity = EntityTypes.IRON_GOLEM.create(world); // Paper
} else if (Shulker.class.isAssignableFrom(clazz)) {
- entity = new EntityShulker(world);
+ entity = EntityTypes.SHULKER.create(world); // Paper
}
} else if (Creeper.class.isAssignableFrom(clazz)) {
- entity = new EntityCreeper(world);
+ entity = EntityTypes.CREEPER.create(world); // Paper
} else if (Ghast.class.isAssignableFrom(clazz)) {
- entity = new EntityGhast(world);
+ entity = EntityTypes.GHAST.create(world); // Paper
} else if (Pig.class.isAssignableFrom(clazz)) {
- entity = new EntityPig(world);
+ entity = EntityTypes.PIG.create(world); // Paper
} else if (Player.class.isAssignableFrom(clazz)) {
// need a net server handler for this one
} else if (Sheep.class.isAssignableFrom(clazz)) {
- entity = new EntitySheep(world);
+ entity = EntityTypes.SHEEP.create(world); // Paper
} else if (AbstractHorse.class.isAssignableFrom(clazz)) {
if (ChestedHorse.class.isAssignableFrom(clazz)) {
if (Donkey.class.isAssignableFrom(clazz)) {
- entity = new EntityHorseDonkey(world);
+ entity = EntityTypes.DONKEY.create(world); // Paper
} else if (Mule.class.isAssignableFrom(clazz)) {
- entity = new EntityHorseMule(world);
+ entity = EntityTypes.MULE.create(world); // Paper
} else if (Llama.class.isAssignableFrom(clazz)) {
- entity = new EntityLlama(world);
+ entity = EntityTypes.LLAMA.create(world); // Paper
}
} else if (SkeletonHorse.class.isAssignableFrom(clazz)) {
- entity = new EntityHorseSkeleton(world);
+ entity = EntityTypes.SKELETON_HORSE.create(world); // Paper
} else if (ZombieHorse.class.isAssignableFrom(clazz)) {
- entity = new EntityHorseZombie(world);
+ entity = EntityTypes.ZOMBIE_HORSE.create(world); // Paper
} else {
- entity = new EntityHorse(world);
+ entity = EntityTypes.HORSE.create(world); // Paper
}
} else if (Skeleton.class.isAssignableFrom(clazz)) {
if (Stray.class.isAssignableFrom(clazz)){
- entity = new EntitySkeletonStray(world);
+ entity = EntityTypes.STRAY.create(world); // Paper
} else if (WitherSkeleton.class.isAssignableFrom(clazz)) {
- entity = new EntitySkeletonWither(world);
+ entity = EntityTypes.WITHER_SKELETON.create(world); // Paper
} else {
- entity = new EntitySkeleton(world);
+ entity = EntityTypes.SKELETON.create(world); // Paper
}
} else if (Slime.class.isAssignableFrom(clazz)) {
if (MagmaCube.class.isAssignableFrom(clazz)) {
- entity = new EntityMagmaCube(world);
+ entity = EntityTypes.MAGMA_CUBE.create(world); // Paper
} else {
- entity = new EntitySlime(world);
+ entity = EntityTypes.SLIME.create(world); // Paper
}
} else if (Spider.class.isAssignableFrom(clazz)) {
if (CaveSpider.class.isAssignableFrom(clazz)) {
- entity = new EntityCaveSpider(world);
+ entity = EntityTypes.CAVE_SPIDER.create(world); // Paper
} else {
- entity = new EntitySpider(world);
+ entity = EntityTypes.SPIDER.create(world); // Paper
}
} else if (Squid.class.isAssignableFrom(clazz)) {
- entity = new EntitySquid(world);
+ entity = EntityTypes.SQUID.create(world); // Paper
} else if (Tameable.class.isAssignableFrom(clazz)) {
if (Wolf.class.isAssignableFrom(clazz)) {
- entity = new EntityWolf(world);
+ entity = EntityTypes.WOLF.create(world); // Paper
} else if (Ocelot.class.isAssignableFrom(clazz)) {
- entity = new EntityOcelot(world);
+ entity = EntityTypes.OCELOT.create(world); // Paper
} else if (Parrot.class.isAssignableFrom(clazz)) {
- entity = new EntityParrot(world);
+ entity = EntityTypes.PARROT.create(world); // Paper
}
} else if (PigZombie.class.isAssignableFrom(clazz)) {
- entity = new EntityPigZombie(world);
+ entity = EntityTypes.ZOMBIE_PIGMAN.create(world); // Paper
} else if (Zombie.class.isAssignableFrom(clazz)) {
if (Husk.class.isAssignableFrom(clazz)) {
- entity = new EntityZombieHusk(world);
+ entity = EntityTypes.HUSK.create(world); // Paper
} else if (ZombieVillager.class.isAssignableFrom(clazz)) {
- entity = new EntityZombieVillager(world);
+ entity = EntityTypes.ZOMBIE_VILLAGER.create(world); // Paper
} else if (Drowned.class.isAssignableFrom(clazz)) {
- entity = new EntityDrowned(world);
+ entity = EntityTypes.DROWNED.create(world); // Paper
} else {
- entity = new EntityZombie(world);
+ entity = EntityTypes.ZOMBIE.create(world); // Paper
}
} else if (Giant.class.isAssignableFrom(clazz)) {
- entity = new EntityGiantZombie(world);
+ entity = EntityTypes.GIANT.create(world); // Paper
} else if (Silverfish.class.isAssignableFrom(clazz)) {
- entity = new EntitySilverfish(world);
+ entity = EntityTypes.SILVERFISH.create(world); // Paper
} else if (Enderman.class.isAssignableFrom(clazz)) {
- entity = new EntityEnderman(world);
+ entity = EntityTypes.ENDERMAN.create(world); // Paper
} else if (Blaze.class.isAssignableFrom(clazz)) {
- entity = new EntityBlaze(world);
+ entity = EntityTypes.BLAZE.create(world); // Paper
} else if (Villager.class.isAssignableFrom(clazz)) {
- entity = new EntityVillager(world);
+ entity = EntityTypes.VILLAGER.create(world); // Paper
} else if (Witch.class.isAssignableFrom(clazz)) {
- entity = new EntityWitch(world);
+ entity = EntityTypes.WITCH.create(world); // Paper
} else if (Wither.class.isAssignableFrom(clazz)) {
- entity = new EntityWither(world);
+ entity = EntityTypes.WITHER.create(world); // Paper
} else if (ComplexLivingEntity.class.isAssignableFrom(clazz)) {
if (EnderDragon.class.isAssignableFrom(clazz)) {
- entity = new EntityEnderDragon(world);
+ entity = EntityTypes.ENDER_DRAGON.create(world); // Paper
}
} else if (Ambient.class.isAssignableFrom(clazz)) {
if (Bat.class.isAssignableFrom(clazz)) {
- entity = new EntityBat(world);
+ entity = EntityTypes.BAT.create(world); // Paper
}
} else if (Rabbit.class.isAssignableFrom(clazz)) {
- entity = new EntityRabbit(world);
+ entity = EntityTypes.RABBIT.create(world); // Paper
} else if (Endermite.class.isAssignableFrom(clazz)) {
- entity = new EntityEndermite(world);
+ entity = EntityTypes.ENDERMITE.create(world); // Paper
} else if (Guardian.class.isAssignableFrom(clazz)) {
if (ElderGuardian.class.isAssignableFrom(clazz)){
- entity = new EntityGuardianElder(world);
+ entity = EntityTypes.ELDER_GUARDIAN.create(world); // Paper
} else {
- entity = new EntityGuardian(world);
+ entity = EntityTypes.GUARDIAN.create(world); // Paper
}
} else if (ArmorStand.class.isAssignableFrom(clazz)) {
- entity = new EntityArmorStand(world, x, y, z);
+ entity = EntityTypes.ARMOR_STAND.create(world); // Paper
} else if (PolarBear.class.isAssignableFrom(clazz)) {
- entity = new EntityPolarBear(world);
+ entity = EntityTypes.POLAR_BEAR.create(world); // Paper
} else if (Vex.class.isAssignableFrom(clazz)) {
- entity = new EntityVex(world);
+ entity = EntityTypes.VEX.create(world); // Paper
} else if (Illager.class.isAssignableFrom(clazz)) {
if (Spellcaster.class.isAssignableFrom(clazz)) {
if (Evoker.class.isAssignableFrom(clazz)) {
- entity = new EntityEvoker(world);
+ entity = EntityTypes.EVOKER.create(world); // Paper
} else if (Illusioner.class.isAssignableFrom(clazz)) {
- entity = new EntityIllagerIllusioner(world);
+ entity = EntityTypes.ILLUSIONER.create(world); // Paper
}
} else if (Vindicator.class.isAssignableFrom(clazz)) {
- entity = new EntityVindicator(world);
+ entity = EntityTypes.VINDICATOR.create(world); // Paper
}
} else if (Turtle.class.isAssignableFrom(clazz)) {
- entity = new EntityTurtle(world);
+ entity = EntityTypes.TURTLE.create(world); // Paper
} else if (Phantom.class.isAssignableFrom(clazz)) {
- entity = new EntityPhantom(world);
+ entity = EntityTypes.PHANTOM.create(world); // Paper
} else if (Fish.class.isAssignableFrom(clazz)) {
if (Cod.class.isAssignableFrom(clazz)) {
- entity = new EntityCod(world);
+ entity = EntityTypes.COD.create(world); // Paper
} else if (PufferFish.class.isAssignableFrom(clazz)) {
- entity = new EntityPufferFish(world);
+ entity = EntityTypes.PUFFERFISH.create(world); // Paper
} else if (Salmon.class.isAssignableFrom(clazz)) {
- entity = new EntitySalmon(world);
+ entity = EntityTypes.SALMON.create(world); // Paper
} else if (TropicalFish.class.isAssignableFrom(clazz)) {
- entity = new EntityTropicalFish(world);
+ entity = EntityTypes.TROPICAL_FISH.create(world); // Paper
}
} else if (Dolphin.class.isAssignableFrom(clazz)) {
- entity = new EntityDolphin(world);
+ entity = EntityTypes.DOLPHIN.create(world); // Paper
}
if (entity != null) {
--
2.21.0

View file

@ -0,0 +1,35 @@
From a55362012ae6439bd007bf980dc0e094b7e9257a Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Tue, 13 Nov 2018 14:01:00 +0000
Subject: [PATCH] limit the range at which we'll consider an attackable target
This patch aims to ensure that MCP World#getNearestAttackablePlayer
will not trigger chunk loads due to PathfinderGoalNearestAttackableTarget
performing a ray trace operation by pre-checking the maximum limit;
Given that the implementation shows that the limit should only ever
decrease when set, allowing us to skip further checks earlier on
when looking for an attackable entity
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 645af17a58..7721dfee65 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -2721,8 +2721,13 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
for (int i = 0; i < this.players.size(); ++i) {
EntityHuman entityhuman1 = (EntityHuman) this.players.get(i);
+ // Paper start
+ // move distance check up, if set, check distance^2 is less than XZlimit^2, continue
+ // 4th method param is XZlimit (at least at the time of commit)
+ double d6 = entityhuman1.d(d0, entityhuman1.locY, d2);
+ if (d3 < 0.0D || d6 < d3 * d3)
if (!entityhuman1.abilities.isInvulnerable && entityhuman1.isAlive() && !entityhuman1.isSpectator() && (predicate == null || predicate.test(entityhuman1))) {
- double d6 = entityhuman1.d(d0, entityhuman1.locY, d2);
+ // Paper end
double d7 = d3;
if (entityhuman1.isSneaking()) {
--
2.21.0

View file

@ -0,0 +1,52 @@
From 299ea42df7d2ad51015e65dbbf5bb77a3d4f4e09 Mon Sep 17 00:00:00 2001
From: Antony Riley <antony@cyberiantiger.org>
Date: Tue, 29 Mar 2016 06:56:23 +0300
Subject: [PATCH] Reduce IO ops opening a new region file.
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
index fb529eac9..faf425588 100644
--- a/src/main/java/net/minecraft/server/RegionFile.java
+++ b/src/main/java/net/minecraft/server/RegionFile.java
@@ -26,7 +26,7 @@ public class RegionFile implements AutoCloseable {
private final File file;
// Spigot end
private static final byte[] a = new byte[4096];
- private final RandomAccessFile b; // PAIL dataFile
+ private final RandomAccessFile b; private RandomAccessFile getDataFile() { return this.b; } // Paper - OBFHELPER // PAIL dataFile
private final int[] c = new int[1024];
private final int[] d = new int[1024];
private final List<Boolean> e; // PAIL freeSectors
@@ -59,10 +59,19 @@ public class RegionFile implements AutoCloseable {
this.e.set(1, false);
this.b.seek(0L);
+ // Paper Start
+ java.nio.ByteBuffer header = java.nio.ByteBuffer.allocate(8192);
+ while (header.hasRemaining()) {
+ if (this.getDataFile().getChannel().read(header) == -1) throw new java.io.EOFException();
+ }
+ ((java.nio.Buffer) header).clear();
+ java.nio.IntBuffer headerAsInts = header.asIntBuffer();
+ // Paper End
+
int k;
for (j = 0; j < 1024; ++j) {
- k = this.b.readInt();
+ k = headerAsInts.get(); // Paper
this.c[j] = k;
// Spigot start
int length = k & 255;
@@ -88,7 +97,7 @@ public class RegionFile implements AutoCloseable {
}
for (j = 0; j < 1024; ++j) {
- k = this.b.readInt();
+ k = headerAsInts.get(); // Paper
this.d[j] = k;
}
--
2.22.0

View file

@ -0,0 +1,23 @@
From 317532f24f529ff717533f65beadc821a7a62bc7 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 31 Mar 2016 19:17:58 -0400
Subject: [PATCH] Do not load chunks for light checks
Should only happen for blocks on the edge that uses neighbors light level
(certain blocks). In that case, there will be 3-4 other neighbors to get a light level from.
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 1ffa8b42b..35fb686d8 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -592,6 +592,7 @@ public abstract class World implements IIBlockAccess, GeneratorAccess, AutoClose
if (blockposition.getY() >= 256) {
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
}
+ if (!this.isLoaded(blockposition)) return 0; // Paper
return this.getChunkAtWorldCoords(blockposition).a(blockposition, i);
}
--
2.22.0

View file

@ -0,0 +1,230 @@
From 9c38be60e37133286ee35635cdc44ac7a4eb555e Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 29 Jul 2018 15:48:50 -0400
Subject: [PATCH] Provide option to use a versioned world folder for testing
This should not ever be used in production!!
This setting is intended for testing so you can try out converting your world
without actually modifying the world files.
This will add some additional overhead to your world, but you're
just testing anyways so that's not a big deal :)
Will store in a folder named after the current version.
PlayerData and Data folders are copied on server start, so there
may be some delay there, but region files are only copied on demand.
This is highly experiemental so backup your world before relying on this to not modify it
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index eeef7d330b..dfdc7c384d 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -13,6 +13,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
+import java.util.logging.Logger;
import java.util.regex.Pattern;
import com.google.common.collect.Lists;
@@ -287,4 +288,27 @@ public class PaperConfig {
Bukkit.getLogger().log(Level.INFO, "Using Aikar's Alternative Luck Formula to apply Luck attribute to all loot pool calculations. See https://luckformula.emc.gs");
}
}
+
+ public static boolean useVersionedWorld = false;
+ private static void useVersionedWorld() {
+ useVersionedWorld = getBoolean("settings.use-versioned-world", false);
+ if (useVersionedWorld) {
+ Logger logger = Bukkit.getLogger();
+ String ver = MinecraftServer.getServer().getVersion();
+ logger.log(Level.INFO, "******************************************************");
+ logger.log(Level.INFO, "*** Using a versioned world folder. Your world will be saved");
+ logger.log(Level.INFO, "*** to into the " + ver + " folder, but copied from your current world.");
+ logger.log(Level.INFO, "*** ");
+ logger.log(Level.INFO, "*** This setting should not be used in your real world!!!");
+ logger.log(Level.INFO, "*** If you want to retain the new world, you need to move ");
+ logger.log(Level.INFO, "*** the folders out of the " + ver + " folder and overwrite existing");
+ logger.log(Level.INFO, "*** ");
+ logger.log(Level.INFO, "*** Deleting the " + ver + " folder will cause it to recreate again");
+ logger.log(Level.INFO, "*** from your unversioned world files.");
+ logger.log(Level.INFO, "*** ");
+ logger.log(Level.INFO, "*** You should backup your original world files incase something goes");
+ logger.log(Level.INFO, "*** wrong with this system! This is not a backup system.");
+ logger.log(Level.INFO, "******************************************************");
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java
index 21b3b06f53..8718811655 100644
--- a/src/main/java/net/minecraft/server/RegionFileCache.java
+++ b/src/main/java/net/minecraft/server/RegionFileCache.java
@@ -10,13 +10,41 @@ import java.io.IOException;
import javax.annotation.Nullable;
import com.destroystokyo.paper.PaperConfig; // Paper
+import org.apache.logging.log4j.LogManager;
+
public abstract class RegionFileCache implements AutoCloseable {
public final Long2ObjectLinkedOpenHashMap<RegionFile> cache = new Long2ObjectLinkedOpenHashMap();
private final File a;
+ // Paper start
+ private final File templateWorld;
+ private final File actualWorld;
+ private boolean useAltWorld;
+ // Paper end
+
protected RegionFileCache(File file) {
this.a = file;
+ // Paper end
+
+ this.actualWorld = file;
+ if (com.destroystokyo.paper.PaperConfig.useVersionedWorld) {
+ this.useAltWorld = true;
+ String name = file.getName();
+ File container = file.getParentFile().getParentFile();
+ if (name.equals("DIM-1") || name.equals("DIM1")) {
+ container = container.getParentFile();
+ }
+ this.templateWorld = new File(container, name);
+ File region = new File(file, "region");
+ if (!region.exists()) {
+ region.mkdirs();
+ }
+ } else {
+ this.useAltWorld = false;
+ this.templateWorld = file;
+ }
+ // Paper start
}
private RegionFile a(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
@@ -34,6 +62,7 @@ public abstract class RegionFileCache implements AutoCloseable {
this.a.mkdirs();
}
+ copyIfNeeded(chunkcoordintpair.x, chunkcoordintpair.z); // Paper
File file = new File(this.a, "r." + chunkcoordintpair.getRegionX() + "." + chunkcoordintpair.getRegionZ() + ".mca");
if (existingOnly && !file.exists()) return null; // CraftBukkit
RegionFile regionfile1 = new RegionFile(file);
@@ -43,6 +72,15 @@ public abstract class RegionFileCache implements AutoCloseable {
}
}
+ public static File getRegionFileName(File file, int i, int j) {
+ File file1 = new File(file, "region");
+ return new File(file1, "r." + (i >> 5) + "." + (j >> 5) + ".mca");
+ }
+ public synchronized boolean hasRegionFile(File file, int i, int j) {
+ return cache.containsKey(ChunkCoordIntPair.pair(i, j));
+ }
+ // Paper End
+
@Nullable
public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException {
RegionFile regionfile = this.a(chunkcoordintpair, false); // CraftBukkit
@@ -132,9 +170,33 @@ public abstract class RegionFileCache implements AutoCloseable {
// CraftBukkit start
public boolean chunkExists(ChunkCoordIntPair pos) throws IOException {
+ copyIfNeeded(pos.x, pos.z); // Paper
RegionFile regionfile = a(pos, true);
return regionfile != null ? regionfile.d(pos) : false;
}
// CraftBukkit end
+
+ private void copyIfNeeded(int x, int z) {
+ if (!useAltWorld) {
+ return;
+ }
+ synchronized (RegionFileCache.class) {
+ if (hasRegionFile(this.actualWorld, x, z)) {
+ return;
+ }
+ File actual = RegionFileCache.getRegionFileName(this.actualWorld, x, z);
+ File template = RegionFileCache.getRegionFileName(this.templateWorld, x, z);
+ if (!actual.exists() && template.exists()) {
+ try {
+ net.minecraft.server.MinecraftServer.LOGGER.info("Copying" + template + " to " + actual);
+ java.nio.file.Files.copy(template.toPath(), actual.toPath(), java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
+ } catch (IOException e1) {
+ LogManager.getLogger().error("Error copying " + template + " to " + actual, e1);
+ MinecraftServer.getServer().safeShutdown(false);
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(e1);
+ }
+ }
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/server/WorldNBTStorage.java b/src/main/java/net/minecraft/server/WorldNBTStorage.java
index 350ac42d6b..eaae446861 100644
--- a/src/main/java/net/minecraft/server/WorldNBTStorage.java
+++ b/src/main/java/net/minecraft/server/WorldNBTStorage.java
@@ -31,6 +31,58 @@ public class WorldNBTStorage implements IPlayerFileData {
public WorldNBTStorage(File file, String s, @Nullable MinecraftServer minecraftserver, DataFixer datafixer) {
this.a = datafixer;
+ // Paper start
+ if (com.destroystokyo.paper.PaperConfig.useVersionedWorld) {
+ File origBaseDir = new File(file, s);
+ final String currentVersion = MinecraftServer.getServer().getVersion();
+ file = new File(file, currentVersion);
+ File baseDir = new File(file, s);
+
+ if (!baseDir.exists() && origBaseDir.exists() && !baseDir.mkdirs()) {
+ LogManager.getLogger().error("Could not create world directory for " + file);
+ System.exit(1);
+ }
+
+ try {
+ boolean printedHeader = false;
+ String[] dirs = {"advancements", "data", "datapacks", "playerdata", "stats"};
+ for (String dir : dirs) {
+ File origPlayerData = new File(origBaseDir, dir);
+ File targetPlayerData = new File(baseDir, dir);
+ if (origPlayerData.exists() && !targetPlayerData.exists()) {
+ if (!printedHeader) {
+ LogManager.getLogger().info("**** VERSIONED WORLD - Copying files");
+ printedHeader = true;
+ }
+ LogManager.getLogger().info("- Copying: " + dir);
+ org.apache.commons.io.FileUtils.copyDirectory(origPlayerData, targetPlayerData);
+ }
+ }
+
+ String[] files = {"level.dat", "level.dat_old", "session.lock", "uid.dat"};
+ for (String fileName : files) {
+ File origPlayerData = new File(origBaseDir, fileName);
+ File targetPlayerData = new File(baseDir, fileName);
+ if (origPlayerData.exists() && !targetPlayerData.exists()) {
+ if (!printedHeader) {
+ LogManager.getLogger().info("- Copying files");
+ printedHeader = true;
+ }
+ LogManager.getLogger().info("- Copying: " + fileName);
+ org.apache.commons.io.FileUtils.copyFile(origPlayerData, targetPlayerData);
+
+ }
+ }
+ if (printedHeader) {
+ LogManager.getLogger().info("**** VERSIONED WORLD - Copying DONE");
+ }
+ } catch (IOException e) {
+ LogManager.getLogger().error("Error copying versioned world data for " + origBaseDir + " to " + baseDir, e);
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(e);
+ }
+
+ }
+ // Paper end
this.baseDir = new File(file, s);
this.baseDir.mkdirs();
this.playerDir = new File(this.baseDir, "playerdata");
--
2.22.0

View file

@ -0,0 +1,115 @@
From a1683b33a2ec42ca595cd7182ffdf5b376c844be Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 11 Aug 2018 00:49:20 -0400
Subject: [PATCH] Detect and repair corrupt Region Files
If the file has partial data written but not the full 8192 bytes,
then the server will be unable to load that region file...
I don't know why mojang only checks for 4096, when anything less than 8192 is a crash.
But to be safe, it will attempt to back up the file.
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
index 3aeac69c26..17648c1c04 100644
--- a/src/main/java/net/minecraft/server/RegionFile.java
+++ b/src/main/java/net/minecraft/server/RegionFile.java
@@ -27,13 +27,13 @@ public class RegionFile implements AutoCloseable {
// Spigot end
private static final byte[] a = new byte[4096];
private final RandomAccessFile b; private RandomAccessFile getDataFile() { return this.b; } // Paper - OBFHELPER // PAIL dataFile
- private final int[] c = new int[1024];
- private final int[] d = new int[1024];
+ private final int[] c = new int[1024]; private final int[] offsets = c; // Paper - OBFHELPER
+ private final int[] d = new int[1024]; private final int[] timestamps = d; // Paper - OBFHELPER
private final List<Boolean> e; // PAIL freeSectors
public RegionFile(File file) throws IOException {
this.b = new RandomAccessFile(file, "rw");
- if (this.b.length() < 4096L) {
+ if (this.b.length() < 8192L) { // Paper - headers should be 8192
this.b.write(RegionFile.a);
this.b.write(RegionFile.a);
}
@@ -83,7 +83,7 @@ public class RegionFile implements AutoCloseable {
this.b.seek(j * 4 + 4); // Go back to where we were
}
}
- if (k != 0 && (k >> 8) + (length) <= this.e.size()) {
+ if (k > 0 && (k >> 8) > 1 && (k >> 8) + (k & 255) <= this.e.size()) { // Paper >= 1 as 0/1 are the headers, and negative isnt valid
for (int l = 0; l < (length); ++l) {
// Spigot end
this.e.set((k >> 8) + l, false);
@@ -92,13 +92,14 @@ public class RegionFile implements AutoCloseable {
// Spigot start
else if (length > 0) {
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Length: {3} runs off end file. {4}", new Object[]{j % 32, (int) (j / 32), k >> 8, length, file});
+ deleteChunk(j); // Paper
}
// Spigot end
}
for (j = 0; j < 1024; ++j) {
k = headerAsInts.get(); // Paper
- this.d[j] = k;
+ if (this.offsets[j] != 0) this.timestamps[j] = k; // Paper - don't set timestamp if it got 0'd above due to corruption
}
this.file = file; // Spigot
@@ -349,6 +350,53 @@ public class RegionFile implements AutoCloseable {
}
// Spigot end
+ // Paper start
+ public synchronized void deleteChunk(int j1) {
+ backup();
+ int k = offsets[j1];
+ int x = j1 & 1024;
+ int z = j1 >> 2;
+ int offset = (k >> 8);
+ int len = (k & 255);
+ String debug = "idx:" + + j1 + " - " + x + "," + z + " - offset: " + offset + " - len: " + len;
+ try {
+ timestamps[j1] = 0;
+ offsets[j1] = 0;
+ RandomAccessFile file = getDataFile();
+ file.seek(j1 * 4);
+ file.writeInt(0);
+ // clear the timestamp
+ file.seek(4096 + j1 * 4);
+ file.writeInt(0);
+ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Deleted corrupt chunk (" + debug + ") " + this.file.getAbsolutePath(), e);
+ } catch (IOException e) {
+
+ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Error deleting corrupt chunk (" + debug + ") " + this.file.getAbsolutePath(), e);
+ }
+ }
+ private boolean backedUp = false;
+ private synchronized void backup() {
+ if (backedUp) {
+ return;
+ }
+ backedUp = true;
+ java.text.DateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd");
+ java.util.Date today = new java.util.Date();
+ File corrupt = new File(file.getParentFile(), file.getName() + "." + formatter.format(today) + ".corrupt");
+ if (corrupt.exists()) {
+ return;
+ }
+ org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger();
+ logger.error("Region file " + file.getAbsolutePath() + " was corrupt. Backing up to " + corrupt.getAbsolutePath() + " and repairing");
+ try {
+ java.nio.file.Files.copy(file.toPath(), corrupt.toPath());
+
+ } catch (IOException e) {
+ logger.error("Error backing up corrupt file" + file.getAbsolutePath(), e);
+ }
+ }
+ // Paper end
+
class ChunkBuffer extends ByteArrayOutputStream {
private final ChunkCoordIntPair b;
--
2.22.0

View file

@ -0,0 +1,63 @@
From b03aa2b2428cf6e504fe4f069f208679e666676f Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Mon, 15 Apr 2019 02:24:52 +0100
Subject: [PATCH] Handle bad chunks more gracefully
Prior to this change the server would crash when attempting to load a
chunk from a region with bad data.
After this change the server will defer back to vanilla behavior. At
this time, that means attempting to generate a chunk in its place
(and occasionally just not generating anything and leaving small
holes in the world (This statement might not be accurate as of 1.13.x)).
Should Mojang choose to alter this behavior in the future, this change
will simply defer to whatever that new behavior is.
diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java
index c53518a47..6f34d8aea 100644
--- a/src/main/java/net/minecraft/server/RegionFileCache.java
+++ b/src/main/java/net/minecraft/server/RegionFileCache.java
@@ -171,8 +171,21 @@ public abstract class RegionFileCache implements AutoCloseable {
private static NBTTagCompound readOversizedChunk(RegionFile regionfile, ChunkCoordIntPair chunkCoordinate) throws IOException {
synchronized (regionfile) {
try (DataInputStream datainputstream = regionfile.getReadStream(chunkCoordinate)) {
- NBTTagCompound oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
- NBTTagCompound chunk = NBTCompressedStreamTools.readNBT(datainputstream);
+ // Paper start - Handle bad chunks more gracefully - also handle similarly with oversized data
+ NBTTagCompound oversizedData = null;
+
+ try {
+ oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
+ } catch (Exception ex) {}
+
+ NBTTagCompound chunk;
+
+ try {
+ chunk = NBTCompressedStreamTools.readNBT(datainputstream);
+ } catch (final Exception ex) {
+ return null;
+ }
+ // Paper end
if (oversizedData == null) {
return chunk;
}
@@ -231,8 +244,13 @@ public abstract class RegionFileCache implements AutoCloseable {
try {
if (datainputstream != null) {
- nbttagcompound = NBTCompressedStreamTools.a(datainputstream);
- return nbttagcompound;
+ // Paper start - Handle bad chunks more gracefully
+ try {
+ return NBTCompressedStreamTools.a(datainputstream);
+ } catch (Exception ex) {
+ return null;
+ }
+ // Paper end
}
nbttagcompound = null;
--
2.23.0

View file

@ -0,0 +1,23 @@
From 98e10786918880c728f3afc751290cdf5eb14cf5 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 5 Aug 2019 08:24:01 -0700
Subject: [PATCH] Preserve old flush on save flag for reliable regionfiles
Originally this patch was in paper
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
index b487e8060..a8c8ace46 100644
--- a/src/main/java/net/minecraft/server/RegionFile.java
+++ b/src/main/java/net/minecraft/server/RegionFile.java
@@ -349,7 +349,7 @@ public class RegionFile implements AutoCloseable {
}
// Spigot start - Make region files reliable
- private static final boolean FLUSH_ON_SAVE = Boolean.getBoolean("spigot.flush-on-save");
+ private static final boolean FLUSH_ON_SAVE = Boolean.getBoolean("spigot.flush-on-save") || Boolean.getBoolean("paper.flush-on-save"); // Paper - preserve old flag
private void syncRegionFile() throws IOException {
if (!FLUSH_ON_SAVE) {
return;
--
2.23.0

View file

@ -0,0 +1,30 @@
From cf3689f611fad7d903831b63086deefad3cd8e92 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 19 Aug 2019 06:33:17 -0700
Subject: [PATCH] Improve POI data saving logic
- Do not unload data if world saving is disabled
- Aggressively target unloading
diff --git a/src/main/java/net/minecraft/server/VillagePlace.java b/src/main/java/net/minecraft/server/VillagePlace.java
index 0e98b7803..fb99b4306 100644
--- a/src/main/java/net/minecraft/server/VillagePlace.java
+++ b/src/main/java/net/minecraft/server/VillagePlace.java
@@ -132,9 +132,12 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
// Paper start - async chunk io
if (this.world == null) {
super.a(booleansupplier);
- } else {
+ } else if (!this.world.isSavingDisabled()) { // Paper - only save if saving is enabled
//super.a(booleansupplier); // re-implement below
- while (!((RegionFileSection)this).d.isEmpty() && booleansupplier.getAsBoolean()) {
+ // Paper start - target unloading aggressively
+ int queueTarget = Math.min(this.d.size() - 100, (int)(this.d.size() * 0.96));
+ while (!((RegionFileSection)this).d.isEmpty() && (this.d.size() > queueTarget || booleansupplier.getAsBoolean())) {
+ // Paper end
ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(((RegionFileSection)this).d.firstLong()).u();
NBTTagCompound data;
--
2.23.0

View file

@ -0,0 +1,75 @@
From 95da400b09518a7f98754568f41aca73afddb92a Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 4 Jul 2018 03:39:51 -0400
Subject: [PATCH] Avoid Chunk Lookups for Entity/TileEntity Current Chunk
SPECIAL 1.14.1 NOTE:
This patch caused a memory leak since the tile entity's chunk was set to null
before it was removed. Ensure this issue is resolved!
In many places where we simply want the current chunk the entity
is in, instead of doing a hashmap lookup for it, we now have access
to the object directly on the Entity/TileEntity object we can directly grab.
Use that local value instead to reduce lookups in many hot places.
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 2c92d3390a..3c3a504991 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -789,7 +789,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
if (!tileentity.isRemoved() && tileentity.hasWorld()) {
BlockPosition blockposition = tileentity.getPosition();
- if (this.chunkProvider.a(blockposition) && this.getWorldBorder().a(blockposition)) {
+ if (tileentity.getCurrentChunk() != null && this.getWorldBorder().a(blockposition)) { // Paper
try {
gameprofilerfiller.a(() -> {
return String.valueOf(TileEntityTypes.a(tileentity.getTileType()));
@@ -828,8 +828,11 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
this.tileEntityListTick.remove(tileTickPosition--);
// Spigot end
//this.tileEntityList.remove(tileentity); // Paper - remove unused list
- if (this.isLoaded(tileentity.getPosition())) {
- this.getChunkAtWorldCoords(tileentity.getPosition()).removeTileEntity(tileentity.getPosition());
+ // Paper start - use local chunk reference
+ Chunk chunk = tileentity.getCurrentChunk();
+ if (chunk != null) {
+ chunk.removeTileEntity(tileentity.getPosition());
+ // Paper end
}
}
}
@@ -849,8 +852,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
}
// CraftBukkit end */
- if (this.isLoaded(tileentity1.getPosition())) {
- Chunk chunk = this.getChunkAtWorldCoords(tileentity1.getPosition());
+ Chunk chunk = tileentity1.getCurrentChunk(); // Paper
+ if (chunk != null) { // Paper
IBlockData iblockdata = chunk.getType(tileentity1.getPosition());
chunk.setTileEntity(tileentity1.getPosition(), tileentity1);
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 3739a95c5a..1e00908671 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -1390,9 +1390,12 @@ public class WorldServer extends World {
}
private void removeEntityFromChunk(Entity entity) {
- IChunkAccess ichunkaccess = this.getChunkAt(entity.chunkX, entity.chunkZ, ChunkStatus.FULL, false);
+ // Paper start
+ if (!entity.inChunk) return;
+ IChunkAccess ichunkaccess = this.getChunkIfLoaded(entity.chunkX, entity.chunkZ);
+ // Paper start
- if (ichunkaccess instanceof Chunk) {
+ if (ichunkaccess != null) { // Paper
((Chunk) ichunkaccess).b(entity);
}
--
2.24.1

View file

@ -0,0 +1,159 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 4 Jul 2018 15:22:06 -0400
Subject: [PATCH] Configurable Bed Search Radius
Allows you to increase how far to check for a safe place to respawn
a player near their bed, allowing a better chance to respawn the
player at their bed should it of became obstructed.
Defaults to vanilla 1.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 6352051ab937d4d365e823a7112e76dc3ec34225..d6a3d882e375ac5a2b6ec8920532db615f4fe4ef 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -372,4 +372,15 @@ public class PaperWorldConfig {
private void scanForLegacyEnderDragon() {
scanForLegacyEnderDragon = getBoolean("game-mechanics.scan-for-legacy-ender-dragon", true);
}
+
+ public int bedSearchRadius = 1;
+ private void bedSearchRadius() {
+ bedSearchRadius = getInt("bed-search-radius", 1);
+ if (bedSearchRadius < 1) {
+ bedSearchRadius = 1;
+ }
+ if (bedSearchRadius > 1) {
+ log("Bed Search Radius: " + bedSearchRadius);
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/server/BlockBed.java b/src/main/java/net/minecraft/server/BlockBed.java
index 7604d79468ce8d7d1a4f45872a5db0c700419029..e7bd9061cceba284443b75cc5506e1b9f2ef42e8 100644
--- a/src/main/java/net/minecraft/server/BlockBed.java
+++ b/src/main/java/net/minecraft/server/BlockBed.java
@@ -199,6 +199,8 @@ public class BlockBed extends BlockFacingHorizontal implements ITileEntity {
public static Optional<Vec3D> a(EntityTypes<?> entitytypes, IWorldReader iworldreader, BlockPosition blockposition, int i) {
EnumDirection enumdirection = (EnumDirection) iworldreader.getType(blockposition).get(BlockBed.FACING);
+ // Paper start - configurable bed search radius
+ if (entitytypes == EntityTypes.PLAYER) return findSafePosition(entitytypes, (World) iworldreader, enumdirection, blockposition);
int j = blockposition.getX();
int k = blockposition.getY();
int l = blockposition.getZ();
@@ -228,7 +230,104 @@ public class BlockBed extends BlockFacingHorizontal implements ITileEntity {
return Optional.empty();
}
- public static Optional<Vec3D> a(EntityTypes<?> entitytypes, IWorldReader iworldreader, BlockPosition blockposition) {
+ private static Optional<Vec3D> findSafePosition(EntityTypes<?> entitytypes, World world, EnumDirection updirection, BlockPosition blockposition){
+ int radius = world.paperConfig.bedSearchRadius;
+ double angle = Math.PI / 2;
+ int tmpX = (int)(updirection.getAdjacentX() * Math.cos(angle) - updirection.getAdjacentZ() * Math.sin(angle));
+ int tmpZ = (int)(updirection.getAdjacentX() * Math.sin(angle) + updirection.getAdjacentZ() * Math.cos(angle));
+
+ EnumDirection rightDirection = EnumDirection.a(tmpX, 0, tmpZ);
+ EnumDirection downDirection = updirection.opposite();
+ EnumDirection leftDirection = rightDirection.opposite();
+
+ EnumDirection[] corePositionOutDirection = new EnumDirection[6];
+ corePositionOutDirection[0] = updirection;
+ corePositionOutDirection[1] = leftDirection;
+ corePositionOutDirection[2] = leftDirection;
+ corePositionOutDirection[3] = downDirection;
+ corePositionOutDirection[4] = rightDirection;
+ corePositionOutDirection[5] = rightDirection;
+
+ BlockPosition[] corePosition = new BlockPosition[6];
+ corePosition[0] = blockposition.add(updirection.getAdjacentX(), 0, updirection.getAdjacentZ());
+ corePosition[1] = blockposition.add(leftDirection.getAdjacentX(), 0, leftDirection.getAdjacentZ());
+ corePosition[2] = corePosition[1].add(downDirection.getAdjacentX(), 0, downDirection.getAdjacentZ());
+ corePosition[3] = blockposition.add(2 * downDirection.getAdjacentX(), 0, 2 * downDirection.getAdjacentZ());
+ corePosition[5] = blockposition.add(rightDirection.getAdjacentX(), 0, rightDirection.getAdjacentZ());
+ corePosition[4] = corePosition[5].add(downDirection.getAdjacentX(), 0, downDirection.getAdjacentZ());
+
+ BlockPosition[] tmpPosition = new BlockPosition[8];
+ EnumDirection[] tmpPositionDirection = new EnumDirection[8];
+ tmpPositionDirection[0] = rightDirection;
+ tmpPositionDirection[1] = leftDirection;
+ tmpPositionDirection[2] = updirection;
+ tmpPositionDirection[3] = downDirection;
+ tmpPositionDirection[4] = leftDirection;
+ tmpPositionDirection[5] = rightDirection;
+ tmpPositionDirection[6] = downDirection;
+ tmpPositionDirection[7] = updirection;
+
+ BlockPosition pos;
+ Optional<Vec3D> vector;
+ for (int r = 1; r <= radius; r++) {
+ int h = 0;
+ while (h <= 1) {
+ int numIterated = 0;
+ for (int index = (int)(Math.random() * corePosition.length); numIterated < corePosition.length; index = (index+1) % corePosition.length) {
+ numIterated++;
+
+ pos = corePosition[index].add(0, h, 0);
+ vector = isSafeRespawn(entitytypes, world, pos, 0);
+ if (vector.isPresent()) {
+ return vector;
+ }
+ }
+ tmpPosition[0] = corePosition[0].add(0, h, 0);
+ tmpPosition[1] = corePosition[0].add(0, h, 0);
+ tmpPosition[2] = corePosition[1].add(0, h, 0);
+ tmpPosition[3] = corePosition[2].add(0, h, 0);
+ tmpPosition[4] = corePosition[3].add(0, h, 0);
+ tmpPosition[5] = corePosition[3].add(0, h, 0);
+ tmpPosition[6] = corePosition[4].add(0, h, 0);
+ tmpPosition[7] = corePosition[5].add(0, h, 0);
+ for (int rr = 1; rr <= r; rr++){
+ numIterated = 0;
+ for (int index = (int)(Math.random() * tmpPosition.length); numIterated < tmpPosition.length; index = (index+1) % tmpPosition.length) {
+ numIterated++;
+ tmpPosition[index] = tmpPosition[index].add(tmpPositionDirection[index].getAdjacentX(), 0, tmpPositionDirection[index].getAdjacentZ());
+ pos = tmpPosition[index];
+
+ vector = isSafeRespawn(entitytypes, world, pos, 0);
+ if (vector.isPresent()) {
+ return vector;
+ }
+ }
+ }
+ switch (h) {
+ case 0:
+ h = -1;
+ break;
+ case -1:
+ h = -2;
+ break;
+ case -2:
+ h = Integer.MAX_VALUE;
+ break;
+ }
+ }
+ for (int index = 0; index < corePosition.length; index++) {
+ EnumDirection tmp = corePositionOutDirection[index];
+ corePosition[index] = corePosition[index].add(tmp.getAdjacentX(), 0, tmp.getAdjacentZ());
+ }
+ }
+ return Optional.empty();
+ }
+ // Paper end
+
+ // Paper start -- add maxBelow param
+ public static Optional<Vec3D> a(EntityTypes<?> entitytypes, IWorldReader iworldreader, BlockPosition blockposition) { return isSafeRespawn(entitytypes, iworldreader, blockposition, 2); }
+ public static Optional<Vec3D> isSafeRespawn(EntityTypes<?> entitytypes, IWorldReader iworldreader, BlockPosition blockposition, int maxBelow) {
+ // Paper end
VoxelShape voxelshape = iworldreader.getType(blockposition).getCollisionShape(iworldreader, blockposition);
if (voxelshape.c(EnumDirection.EnumAxis.Y) > 0.4375D) {
@@ -236,7 +335,7 @@ public class BlockBed extends BlockFacingHorizontal implements ITileEntity {
} else {
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = blockposition.i();
- while (blockposition_mutableblockposition.getY() >= 0 && blockposition.getY() - blockposition_mutableblockposition.getY() <= 2 && iworldreader.getType(blockposition_mutableblockposition).getCollisionShape(iworldreader, blockposition_mutableblockposition).isEmpty()) {
+ while (blockposition_mutableblockposition.getY() >= 0 && blockposition.getY() - blockposition_mutableblockposition.getY() <= maxBelow && iworldreader.getType(blockposition_mutableblockposition).getCollisionShape(iworldreader, blockposition_mutableblockposition).isEmpty()) { // Paper -- configurable max distance to search below
blockposition_mutableblockposition.c(EnumDirection.DOWN);
}

View file

@ -0,0 +1,99 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 17 Sep 2018 23:05:31 -0400
Subject: [PATCH] Support Overriding World Seeds
Allows you to add to paper.yml
seed-overrides:
world_name: some seed value
This will ignore every where a seed is set/created/loaded and force
a world to use the specified seed.
This seed will end up being saved to the world data file, so it is
a permanent change in that it won't go back if you remove it from paper.yml
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index 214b577b326bc794fa3721deb6171228dd4f25e6..559e6b42ba5bf0ea92cccbabd2ef1d4c27b03064 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -11,6 +11,7 @@ import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.regex.Pattern;
@@ -19,6 +20,7 @@ import com.google.common.collect.Lists;
import net.minecraft.server.MinecraftServer;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
+import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import co.aikar.timings.Timings;
@@ -310,4 +312,23 @@ public class PaperConfig {
}
tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit);
}
+
+ public static Map<String, Long> seedOverride = new java.util.HashMap<>();
+ private static void worldSeedOverrides() {
+ ConfigurationSection seeds = config.getConfigurationSection("seed-overrides");
+ if (seeds != null) {
+ TimingsManager.hiddenConfigs.add("seed-overrides");
+ for (String key : seeds.getKeys(false)) {
+ String seedString = seeds.getString(key);
+ long seed;
+ try {
+ seed = Long.parseLong(seedString);
+ } catch (Exception e) {
+ seed = (long) seedString.hashCode();
+ }
+ log("Seed Override: " + key + " => " + seed);
+ seedOverride.put(key, seed);
+ }
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 3b89f62ab0522d23f47fd59c2f06fa7d0eacb7af..85f989829b5ad1d7681b57cf68519a4806b26ea1 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -378,7 +378,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
this.convertWorld(name); // Run conversion now
org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name);
- WorldSettings worldsettings = new WorldSettings(i, this.getGamemode(), this.getGenerateStructures(), this.isHardcore(), worldtype);
+ WorldSettings worldsettings = new WorldSettings(com.destroystokyo.paper.PaperConfig.seedOverride.getOrDefault(name, i), this.getGamemode(), this.getGenerateStructures(), this.isHardcore(), worldtype); // Paper
worldsettings.setGeneratorSettings(jsonelement);
if (j == 0) {
diff --git a/src/main/java/net/minecraft/server/WorldData.java b/src/main/java/net/minecraft/server/WorldData.java
index 561b6d94696eebc255279f45d2ca6b88b2490f78..95518e54d1fd7ada51df1cdc3562affccd48bfcb 100644
--- a/src/main/java/net/minecraft/server/WorldData.java
+++ b/src/main/java/net/minecraft/server/WorldData.java
@@ -127,7 +127,7 @@ public class WorldData {
this.d = nbttagcompound2.getBoolean("Snapshot");
}
- this.e = nbttagcompound.getLong("RandomSeed");
+ this.e = com.destroystokyo.paper.PaperConfig.seedOverride.getOrDefault(nbttagcompound.getString("LevelName"), nbttagcompound.getLong("RandomSeed")); // Paper
if (nbttagcompound.hasKeyOfType("generatorName", 8)) {
String s = nbttagcompound.getString("generatorName");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index d15a857b30511bda9bbeddf651b4633e4bea473d..011d0927da7a2a67dcd6d75e3af07d38f30acf81 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1016,7 +1016,7 @@ public final class CraftServer implements Server {
WorldSettings worldSettings;
// See MinecraftServer.a(String, String, long, WorldType, JsonElement)
if (worlddata == null) {
- worldSettings = new WorldSettings(creator.seed(), EnumGamemode.getById(getDefaultGameMode().getValue()), generateStructures, hardcore, type);
+ worldSettings = new WorldSettings(com.destroystokyo.paper.PaperConfig.seedOverride.getOrDefault(name, creator.seed()), EnumGamemode.getById(getDefaultGameMode().getValue()), generateStructures, hardcore, type); // Paper
JsonElement parsedSettings = new JsonParser().parse(creator.generatorSettings());
if (parsedSettings.isJsonObject()) {
worldSettings.setGeneratorSettings(parsedSettings.getAsJsonObject());

View file

@ -0,0 +1,101 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JellySquid <jellysquid+atwork@protonmail.com>
Date: Sat, 9 May 2020 16:25:21 -0400
Subject: [PATCH] Implement JellySquid's Entity Collision optimisations patch
Optimizes Full Block voxel collisions, and removes streams from Entity collisions
Original code by JellySquid, licensed under GNU Lesser General Public License v3.0
you can find the original code on https://github.com/jellysquid3/lithium-fabric/tree/1.15.x/fabric (Yarn mappings)
diff --git a/src/main/java/net/minecraft/server/ICollisionAccess.java b/src/main/java/net/minecraft/server/ICollisionAccess.java
index 3eefbf4d5f10b53f930759a0afa5661253b92c60..5e20dba0d011d20b714d784cb4a545a05bbf6f9c 100644
--- a/src/main/java/net/minecraft/server/ICollisionAccess.java
+++ b/src/main/java/net/minecraft/server/ICollisionAccess.java
@@ -115,11 +115,24 @@ public interface ICollisionAccess extends IBlockAccess {
if ((j2 != 1 || iblockdata.f()) && (j2 != 2 || iblockdata.getBlock() == Blocks.MOVING_PISTON)) {
VoxelShape voxelshape2 = iblockdata.b((IBlockAccess) ICollisionAccess.this, blockposition_mutableblockposition, voxelshapecollision);
- VoxelShape voxelshape3 = voxelshape2.a((double) k1, (double) l1, (double) i2);
- if (VoxelShapes.c(voxelshape, voxelshape3, OperatorBoolean.AND)) {
- consumer.accept(voxelshape3);
- return true;
+ // Paper start - Lithium Collision Optimizations
+ if (voxelshape2 == VoxelShapes.empty()) {
+ continue;
+ }
+
+ if (voxelshape2 == VoxelShapes.fullCube()) {
+ if (axisalignedbb.intersects(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D)) {
+ consumer.accept(voxelshape2.offset(x, y, z));
+ return true;
+ }
+ } else {
+ VoxelShape shape = voxelshape2.offset(x, y, z);
+ if (VoxelShapes.applyOperation(shape, voxelshape, OperatorBoolean.AND)) {
+ consumer.accept(shape);
+ return true;
+ }
+ // Paper end
}
}
}
diff --git a/src/main/java/net/minecraft/server/IEntityAccess.java b/src/main/java/net/minecraft/server/IEntityAccess.java
index 5135308fb6137a34ed6fd061f0a210de6de4e81c..d434aaaaf0ab6a18ab0fe5ad0bf8ed4662f49120 100644
--- a/src/main/java/net/minecraft/server/IEntityAccess.java
+++ b/src/main/java/net/minecraft/server/IEntityAccess.java
@@ -52,20 +52,41 @@ public interface IEntityAccess {
// Paper end - optimise hard collision
default Stream<VoxelShape> b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set) {
- if (axisalignedbb.a() < 1.0E-7D) {
+ // Paper start - remove streams from entity collision
+ if (axisalignedbb.getAverageSideLength() < 1.0E-7D) {
return Stream.empty();
- } else {
- AxisAlignedBB axisalignedbb1 = axisalignedbb.g(1.0E-7D);
- Stream<AxisAlignedBB> stream = ((entity != null && entity.hardCollides()) ? this.getEntities(entity, axisalignedbb) : this.getHardCollidingEntities(entity, axisalignedbb1)).stream().filter((entity1) -> { // Paper - decompile fix // Paper - optimise hard collision
- return !set.contains(entity1);
- }).filter((entity1) -> {
- return entity == null || !entity.isSameVehicle(entity1);
- }).flatMap((entity1) -> {
- return Stream.of(entity1.au(), entity == null ? null : entity.j(entity1)); // Paper - optimise hard collision - diff on change, these are the methods that only hard colliding entities override
- }).filter(Objects::nonNull);
-
- return stream.filter(axisalignedbb1::c).map(VoxelShapes::a);
+
}
+ AxisAlignedBB selection = axisalignedbb.grow(1.0E-7D);
+ List<Entity> entities = entity != null && entity.hardCollides() ? getEntities(entity, selection) : getHardCollidingEntities(entity, selection);
+ List<VoxelShape> shapes = new java.util.ArrayList<>();
+
+ for (Entity otherEntity : entities) {
+ if (!set.isEmpty() && set.contains(otherEntity)) {
+ continue;
+ }
+
+ if (entity != null && entity.isSameVehicle(otherEntity)) {
+ continue;
+ }
+
+ AxisAlignedBB otherEntityBox = otherEntity.getCollisionBox();
+
+ if (otherEntityBox != null && selection.intersects(otherEntityBox)) {
+ shapes.add(VoxelShapes.of(otherEntityBox));
+ }
+
+ if (entity != null) {
+ AxisAlignedBB otherEntityHardBox = entity.getHardCollisionBox(otherEntity);
+
+ if (otherEntityHardBox != null && selection.intersects(otherEntityHardBox)) {
+ shapes.add(VoxelShapes.of(otherEntityHardBox));
+ }
+ }
+ }
+
+ return shapes.stream();
+ // Paper end
}
@Nullable

View file

@ -0,0 +1,178 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 9 May 2020 18:36:27 -0400
Subject: [PATCH] Remove some Streams usage in Entity Collision
While there is more down the collision system, remove some of the wrapping
Spliterator stuff as even this wrapper stream has shown up in profiling.
With other collision optimizations, we might also even avoid inner streams too.
diff --git a/src/main/java/net/minecraft/server/GeneratorAccess.java b/src/main/java/net/minecraft/server/GeneratorAccess.java
index e865a5694f78fb9273a0625ab2c30b87d0711a90..5648ba73c533f622c35c808decdb305f8a1cf6b0 100644
--- a/src/main/java/net/minecraft/server/GeneratorAccess.java
+++ b/src/main/java/net/minecraft/server/GeneratorAccess.java
@@ -52,6 +52,7 @@ public interface GeneratorAccess extends IEntityAccess, IWorldReader, VirtualLev
this.a((EntityHuman) null, i, blockposition, j);
}
+ @Override default java.util.List<VoxelShape> getEntityCollisions(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set, boolean returnFast) {return IEntityAccess.super.getEntityCollisions(entity, axisalignedbb, set, returnFast); } // Paper
@Override
default Stream<VoxelShape> b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set) {
return IEntityAccess.super.b(entity, axisalignedbb, set);
diff --git a/src/main/java/net/minecraft/server/ICollisionAccess.java b/src/main/java/net/minecraft/server/ICollisionAccess.java
index 5e20dba0d011d20b714d784cb4a545a05bbf6f9c..5a21205a49606b294de4cd27b60438c6a5b3c526 100644
--- a/src/main/java/net/minecraft/server/ICollisionAccess.java
+++ b/src/main/java/net/minecraft/server/ICollisionAccess.java
@@ -44,19 +44,40 @@ public interface ICollisionAccess extends IBlockAccess {
default boolean a(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set) {
try { if (entity != null) entity.collisionLoadChunks = true; // Paper
- return this.c(entity, axisalignedbb, set).allMatch(VoxelShape::isEmpty);
+ // Paper start - reduce stream usage
+ java.util.List<VoxelShape> blockCollisions = getBlockCollision(entity, axisalignedbb, true);
+ for (int i = 0; i < blockCollisions.size(); i++) {
+ VoxelShape blockCollision = blockCollisions.get(i);
+ if (!blockCollision.isEmpty()) {
+ return false;
+ }
+ }
+ return getEntityCollisions(entity, axisalignedbb, set, true).isEmpty();
+ // Paper end
} finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
}
+ default java.util.List<VoxelShape> getEntityCollisions(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set, boolean returnFast) { return java.util.Collections.emptyList(); } // Paper
default Stream<VoxelShape> b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set) {
return Stream.empty();
}
default Stream<VoxelShape> c(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set) {
- return Streams.concat(new Stream[]{this.b(entity, axisalignedbb), this.b(entity, axisalignedbb, set)});
+ // Paper start - reduce stream usage
+ java.util.List<VoxelShape> blockCollisions = getBlockCollision(entity, axisalignedbb, false);
+ java.util.List<VoxelShape> entityCollisions = getEntityCollisions(entity, axisalignedbb, set, false);
+ return Stream.concat(blockCollisions.stream(), entityCollisions.stream());
+ // Paper end
}
default Stream<VoxelShape> b(@Nullable final Entity entity, AxisAlignedBB axisalignedbb) {
+ // Paper start - reduce stream usage
+ java.util.List<VoxelShape> collision = getBlockCollision(entity, axisalignedbb, false);
+ return !collision.isEmpty() ? collision.stream() : Stream.empty();
+ }
+
+ default java.util.List<VoxelShape> getBlockCollision(@Nullable final Entity entity, AxisAlignedBB axisalignedbb, boolean returnFast) {
+ // Paper end
int i = MathHelper.floor(axisalignedbb.minX - 1.0E-7D) - 1;
int j = MathHelper.floor(axisalignedbb.maxX + 1.0E-7D) + 1;
int k = MathHelper.floor(axisalignedbb.minY - 1.0E-7D) - 1;
@@ -68,19 +89,19 @@ public interface ICollisionAccess extends IBlockAccess {
final BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
final VoxelShape voxelshape = VoxelShapes.a(axisalignedbb);
- return StreamSupport.stream(new AbstractSpliterator<VoxelShape>(Long.MAX_VALUE, 1280) {
- boolean a = entity == null;
-
- public boolean tryAdvance(Consumer<? super VoxelShape> consumer) {
- if (!this.a) {
- this.a = true;
+ // Paper start - reduce stream usage (this part done by Aikar)
+ java.util.List<VoxelShape> collisions = new java.util.ArrayList<>();
+ if (true) {//return StreamSupport.stream(new AbstractSpliterator<VoxelShape>(Long.MAX_VALUE, 1280) {
+ if (true) { //public boolean tryAdvance(Consumer<? super VoxelShape> consumer) {*/ // Paper
+ if (entity != null) {
+ // Paper end
VoxelShape voxelshape1 = ICollisionAccess.this.getWorldBorder().a();
boolean flag = VoxelShapes.c(voxelshape1, VoxelShapes.a(entity.getBoundingBox().shrink(1.0E-7D)), OperatorBoolean.AND);
boolean flag1 = VoxelShapes.c(voxelshape1, VoxelShapes.a(entity.getBoundingBox().g(1.0E-7D)), OperatorBoolean.AND);
if (!flag && flag1) {
- consumer.accept(voxelshape1);
- return true;
+ collisions.add(voxelshape1);// Paper
+ if (returnFast) return collisions;
}
}
@@ -104,9 +125,8 @@ public interface ICollisionAccess extends IBlockAccess {
);
if (iblockdata == null) {
if (!(entity instanceof EntityPlayer) || entity.world.paperConfig.preventMovingIntoUnloadedChunks) {
- VoxelShape voxelshape3 = VoxelShapes.of(far ? entity.getBoundingBox() : new AxisAlignedBB(new BlockPosition(x, y, z)));
- consumer.accept(voxelshape3);
- return true;
+ collisions.add(VoxelShapes.of(far ? entity.getBoundingBox() : new AxisAlignedBB(new BlockPosition(x, y, z))));
+ if (returnFast) return collisions;
}
} else {
//blockposition_mutableblockposition.d(k1, l1, i2); // moved up
@@ -123,14 +143,14 @@ public interface ICollisionAccess extends IBlockAccess {
if (voxelshape2 == VoxelShapes.fullCube()) {
if (axisalignedbb.intersects(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D)) {
- consumer.accept(voxelshape2.offset(x, y, z));
- return true;
+ collisions.add(voxelshape2.offset(x, y, z));
+ if (returnFast) return collisions;
}
} else {
VoxelShape shape = voxelshape2.offset(x, y, z);
if (VoxelShapes.applyOperation(shape, voxelshape, OperatorBoolean.AND)) {
- consumer.accept(shape);
- return true;
+ collisions.add(shape);
+ if (returnFast) return collisions;
}
// Paper end
}
@@ -139,8 +159,9 @@ public interface ICollisionAccess extends IBlockAccess {
}
}
- return false;
+ //return false; // Paper
}
- }, false);
+ } //}, false);
+ return collisions; // Paper
}
}
diff --git a/src/main/java/net/minecraft/server/IEntityAccess.java b/src/main/java/net/minecraft/server/IEntityAccess.java
index d434aaaaf0ab6a18ab0fe5ad0bf8ed4662f49120..3bc57ef91d557383178533b0cc87a71a521d6b3e 100644
--- a/src/main/java/net/minecraft/server/IEntityAccess.java
+++ b/src/main/java/net/minecraft/server/IEntityAccess.java
@@ -55,8 +55,10 @@ public interface IEntityAccess {
// Paper start - remove streams from entity collision
if (axisalignedbb.getAverageSideLength() < 1.0E-7D) {
return Stream.empty();
-
}
+ return getEntityCollisions(entity, axisalignedbb, set, false).stream();
+ }
+ default List<VoxelShape> getEntityCollisions(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set<Entity> set, boolean returnFast) {
AxisAlignedBB selection = axisalignedbb.grow(1.0E-7D);
List<Entity> entities = entity != null && entity.hardCollides() ? getEntities(entity, selection) : getHardCollidingEntities(entity, selection);
List<VoxelShape> shapes = new java.util.ArrayList<>();
@@ -74,6 +76,7 @@ public interface IEntityAccess {
if (otherEntityBox != null && selection.intersects(otherEntityBox)) {
shapes.add(VoxelShapes.of(otherEntityBox));
+ if (returnFast) return shapes;
}
if (entity != null) {
@@ -81,11 +84,12 @@ public interface IEntityAccess {
if (otherEntityHardBox != null && selection.intersects(otherEntityHardBox)) {
shapes.add(VoxelShapes.of(otherEntityHardBox));
+ if (returnFast) return shapes;
}
}
}
- return shapes.stream();
+ return shapes;
// Paper end
}

View file

@ -0,0 +1,273 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 26 May 2020 21:32:05 -0400
Subject: [PATCH] Optimize Villagers
This change reimplements the entire BehaviorFindPosition method to
get rid of all of the streams, and implement the logic in a more sane way.
We keep vanilla behavior 100% the same with this change, just wrote more
optimal, as we can abort iterating POI's as soon as we find a match....
One slight change is that Minecraft adds a random delay before a POI is
attempted again. I've increased the amount of that delay based on the distance
to said POI, so farther POI's will not be attempted as often.
Additionally, we spiral out, so we favor local POI's before we ever favor farther POI's.
We also try to pathfind 1 POI at a time instead of collecting multiple POI's then tossing them
all to the pathfinder, so that once we get a match we can return before even looking at other
POI's.
This benefits us in that ideally, a villager will constantly find the near POI's and
not even try to pathfind to the farther POI. Trying to pathfind to distant POI's is
what causes significant lag.
Other improvements here is to stop spamming the POI manager with empty nullables.
Vanilla used them to represent if they needed to load POI data off disk or not.
Well, we load POI data async on chunk load, so we have it, and we surely do not ever
want to load POI data sync either for unloaded chunks!
So this massively reduces object count in the POI hashmaps, resulting in less hash collions,
and also less memory use.
Additionally, unemployed villagers were using significant time due to major ineffeciency in
the code rebuilding data that is static every single invocation for every POI type...
So we cache that and only rebuild it if professions change, which should be never unless
a plugin manipulates and adds custom professions, which it will handle by rebuilding.
diff --git a/src/main/java/net/minecraft/server/BehaviorFindPosition.java b/src/main/java/net/minecraft/server/BehaviorFindPosition.java
index 35eb3a5a61145e94d5b0c77c0eb13bfa46fac23b..6861b1a345496a83900b0ef702ba34315a030ef6 100644
--- a/src/main/java/net/minecraft/server/BehaviorFindPosition.java
+++ b/src/main/java/net/minecraft/server/BehaviorFindPosition.java
@@ -29,8 +29,55 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
protected void a(WorldServer worldserver, EntityCreature entitycreature, long i) {
this.f = 0;
- this.d = worldserver.getTime() + (long) worldserver.getRandom().nextInt(20);
+ this.d = worldserver.getTime() + (long) java.util.concurrent.ThreadLocalRandom.current().nextInt(20); // Paper
VillagePlace villageplace = worldserver.B();
+
+ // Paper start - replace implementation completely
+ BlockPosition blockposition2 = new BlockPosition(entitycreature);
+ int dist = 48;
+ int requiredDist = dist * dist;
+ int cdist = Math.floorDiv(dist, 16);
+ Predicate<VillagePlaceType> predicate = this.a.c();
+ int maxPoiAttempts = 4;
+ int poiAttempts = 0;
+ OUT:
+ for (ChunkCoordIntPair chunkcoordintpair : MCUtil.getSpiralOutChunks(blockposition2, cdist)) {
+ for (int i1 = 0; i1 < 16; i1++) {
+ java.util.Optional<VillagePlaceSection> section = villageplace.getSection(SectionPosition.a(chunkcoordintpair, i1).v());
+ if (section == null || !section.isPresent()) continue;
+ for (java.util.Map.Entry<VillagePlaceType, java.util.Set<VillagePlaceRecord>> e : section.get().getRecords().entrySet()) {
+ if (!predicate.test(e.getKey())) continue;
+ for (VillagePlaceRecord record : e.getValue()) {
+ if (!record.hasVacancy()) continue;
+
+ BlockPosition pos = record.getPosition();
+ long key = pos.asLong();
+ if (this.e.containsKey(key)) {
+ continue;
+ }
+ double poiDist = pos.distanceSquared(blockposition2);
+ if (poiDist <= (double) requiredDist) {
+ this.e.put(key, (long) (this.d + Math.sqrt(poiDist) * 4)); // use dist instead of 40 to blacklist longer if farther distance
+ ++poiAttempts;
+ PathEntity pathentity = entitycreature.getNavigation().a(com.google.common.collect.ImmutableSet.of(pos), 8, false, this.a.d());
+
+ if (pathentity != null && pathentity.h()) {
+ record.decreaseVacancy();
+ GlobalPos globalPos = GlobalPos.create(worldserver.getWorldProvider().getDimensionManager(), pos);
+ entitycreature.getBehaviorController().setMemory(this.b, globalPos);
+ break OUT;
+ }
+ if (poiAttempts >= maxPoiAttempts) {
+ break OUT;
+ }
+ }
+ }
+ }
+ }
+ }
+ // Clean up - vanilla does this only when it runs out, but that would push it to try farther POI's...
+ this.e.long2LongEntrySet().removeIf((entry) -> entry.getLongValue() < this.d);
+ /*
Predicate<BlockPosition> predicate = (blockposition) -> {
long j = blockposition.asLong();
@@ -61,6 +108,6 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
return entry.getLongValue() < this.d;
});
}
-
+ */ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/server/RegionFileSection.java b/src/main/java/net/minecraft/server/RegionFileSection.java
index a6d8ef5eb44f3f851a3a1be4032ca21ab1d7f2b2..c3e8a0145d63843736d2060f978cdf38df359563 100644
--- a/src/main/java/net/minecraft/server/RegionFileSection.java
+++ b/src/main/java/net/minecraft/server/RegionFileSection.java
@@ -51,29 +51,15 @@ public class RegionFileSection<R extends MinecraftSerializable> extends RegionFi
@Nullable
protected Optional<R> c(long i) {
- return (Optional) this.c.get(i);
+ return this.c.getOrDefault(i, Optional.empty()); // Paper
}
+ protected final Optional<R> getSection(long i) { return d(i); } // Paper - OBFHELPER
protected Optional<R> d(long i) {
- SectionPosition sectionposition = SectionPosition.a(i);
-
- if (this.b(sectionposition)) {
- return Optional.empty();
- } else {
- Optional<R> optional = this.c(i);
-
- if (optional != null) {
- return optional;
- } else {
- this.b(sectionposition.u());
- optional = this.c(i);
- if (optional == null) {
- throw (IllegalStateException) SystemUtils.c(new IllegalStateException());
- } else {
- return optional;
- }
- }
- }
+ // Paper start - replace method - never load POI data sync, we load this in chunk load already, reduce ops
+ // If it's an unloaded chunk, well too bad.
+ return this.c(i);
+ // Paper end
}
protected boolean b(SectionPosition sectionposition) {
@@ -117,7 +103,7 @@ public class RegionFileSection<R extends MinecraftSerializable> extends RegionFi
private <T> void a(ChunkCoordIntPair chunkcoordintpair, DynamicOps<T> dynamicops, @Nullable T t0) {
if (t0 == null) {
for (int i = 0; i < 16; ++i) {
- this.c.put(SectionPosition.a(chunkcoordintpair, i).v(), Optional.empty());
+ //this.c.put(SectionPosition.a(chunkcoordintpair, i).v(), Optional.empty()); // Paper - NO!!!
}
} else {
Dynamic<T> dynamic = new Dynamic(dynamicops, t0);
@@ -135,7 +121,7 @@ public class RegionFileSection<R extends MinecraftSerializable> extends RegionFi
}, dynamic2);
});
- this.c.put(i1, optional);
+ if (optional.isPresent()) this.c.put(i1, optional); // Paper - NO!!!
optional.ifPresent((minecraftserializable) -> {
this.b(i1);
if (flag) {
@@ -199,7 +185,7 @@ public class RegionFileSection<R extends MinecraftSerializable> extends RegionFi
if (optional != null && optional.isPresent()) {
this.d.add(i);
} else {
- RegionFileSection.LOGGER.warn("No data for position: {}", SectionPosition.a(i));
+ //RegionFileSection.LOGGER.warn("No data for position: {}", SectionPosition.a(i)); // Paper - hush
}
}
diff --git a/src/main/java/net/minecraft/server/VillagePlaceRecord.java b/src/main/java/net/minecraft/server/VillagePlaceRecord.java
index 1e9d7a3f902eb4571b93bb0e58cba966365f07b8..44535a3e2c3320aac472c5a7ee557fac7bab2530 100644
--- a/src/main/java/net/minecraft/server/VillagePlaceRecord.java
+++ b/src/main/java/net/minecraft/server/VillagePlaceRecord.java
@@ -32,6 +32,7 @@ public class VillagePlaceRecord implements MinecraftSerializable {
return dynamicops.createMap(ImmutableMap.of(dynamicops.createString("pos"), this.a.a(dynamicops), dynamicops.createString("type"), dynamicops.createString(IRegistry.POINT_OF_INTEREST_TYPE.getKey(this.b).toString()), dynamicops.createString("free_tickets"), dynamicops.createInt(this.c)));
}
+ protected final boolean decreaseVacancy() { return b(); } // Paper - OBFHELPER
protected boolean b() {
if (this.c <= 0) {
return false;
@@ -42,6 +43,7 @@ public class VillagePlaceRecord implements MinecraftSerializable {
}
}
+ protected final boolean increaseVacancy() { return c(); } // Paper - OBFHELPER
protected boolean c() {
if (this.c >= this.b.b()) {
return false;
@@ -52,14 +54,17 @@ public class VillagePlaceRecord implements MinecraftSerializable {
}
}
+ public final boolean hasVacancy() { return d(); } // Paper - OBFHELPER
public boolean d() {
return this.c > 0;
}
+ public final boolean isOccupied() { return e(); } // Paper - OBFHELPER
public boolean e() {
return this.c != this.b.b();
}
+ public final BlockPosition getPosition() { return f(); } // Paper
public BlockPosition f() {
return this.a;
}
diff --git a/src/main/java/net/minecraft/server/VillagePlaceSection.java b/src/main/java/net/minecraft/server/VillagePlaceSection.java
index 3f2602dbe0995f8d01d4a1428d919405d711a205..436b064c3b277143075386fc9a71027fb5962681 100644
--- a/src/main/java/net/minecraft/server/VillagePlaceSection.java
+++ b/src/main/java/net/minecraft/server/VillagePlaceSection.java
@@ -23,7 +23,7 @@ public class VillagePlaceSection implements MinecraftSerializable {
private static final Logger LOGGER = LogManager.getLogger();
private final Short2ObjectMap<VillagePlaceRecord> b = new Short2ObjectOpenHashMap();
- private final Map<VillagePlaceType, Set<VillagePlaceRecord>> c = Maps.newHashMap();
+ private final Map<VillagePlaceType, Set<VillagePlaceRecord>> c = Maps.newHashMap(); public final Map<VillagePlaceType, Set<VillagePlaceRecord>> getRecords() { return c; } // Paper - OBFHELPER
private final Runnable d;
private boolean e;
diff --git a/src/main/java/net/minecraft/server/VillagePlaceType.java b/src/main/java/net/minecraft/server/VillagePlaceType.java
index ab3e054cd2f38756a5d802d4d981022318ab047d..c1f293fc98d3efb4665cfb9036f208b842fc8e36 100644
--- a/src/main/java/net/minecraft/server/VillagePlaceType.java
+++ b/src/main/java/net/minecraft/server/VillagePlaceType.java
@@ -12,8 +12,14 @@ import java.util.stream.Stream;
public class VillagePlaceType {
+ static Set<VillagePlaceType> professionCache; // Paper
private static final Predicate<VillagePlaceType> v = (villageplacetype) -> {
- return ((Set) IRegistry.VILLAGER_PROFESSION.d().map(VillagerProfession::b).collect(Collectors.toSet())).contains(villageplacetype);
+ // Paper start
+ if (professionCache == null) {
+ professionCache = IRegistry.VILLAGER_PROFESSION.d().map(VillagerProfession::b).collect(Collectors.toSet());
+ }
+ return professionCache.contains(villageplacetype);
+ // Paper end
};
public static final Predicate<VillagePlaceType> a = (villageplacetype) -> {
return true;
@@ -89,11 +95,11 @@ public class VillagePlaceType {
}
private static VillagePlaceType a(String s, Set<IBlockData> set, int i, int j) {
- return a((VillagePlaceType) IRegistry.POINT_OF_INTEREST_TYPE.a(new MinecraftKey(s), (Object) (new VillagePlaceType(s, set, i, j))));
+ return a((VillagePlaceType) IRegistry.POINT_OF_INTEREST_TYPE.a(new MinecraftKey(s), (new VillagePlaceType(s, set, i, j)))); // Paper - decompile error
}
private static VillagePlaceType a(String s, Set<IBlockData> set, int i, Predicate<VillagePlaceType> predicate, int j) {
- return a((VillagePlaceType) IRegistry.POINT_OF_INTEREST_TYPE.a(new MinecraftKey(s), (Object) (new VillagePlaceType(s, set, i, predicate, j))));
+ return a((VillagePlaceType) IRegistry.POINT_OF_INTEREST_TYPE.a(new MinecraftKey(s), (new VillagePlaceType(s, set, i, predicate, j)))); // Paper - decompile error
}
private static VillagePlaceType a(VillagePlaceType villageplacetype) {
diff --git a/src/main/java/net/minecraft/server/VillagerProfession.java b/src/main/java/net/minecraft/server/VillagerProfession.java
index c38296165b33698bc15fe49a2de0d0d19cfb910a..f9d7a16c79a4e3ffe8b6e7ed469236a93892f01d 100644
--- a/src/main/java/net/minecraft/server/VillagerProfession.java
+++ b/src/main/java/net/minecraft/server/VillagerProfession.java
@@ -61,6 +61,7 @@ public class VillagerProfession {
}
static VillagerProfession a(String s, VillagePlaceType villageplacetype, ImmutableSet<Item> immutableset, ImmutableSet<Block> immutableset1, @Nullable SoundEffect soundeffect) {
+ VillagePlaceType.professionCache = null; // Paper
return (VillagerProfession) IRegistry.a((IRegistry) IRegistry.VILLAGER_PROFESSION, new MinecraftKey(s), (Object) (new VillagerProfession(s, villageplacetype, immutableset, immutableset1, soundeffect)));
}
}

View file

@ -0,0 +1,82 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mystiflow <mystiflow@gmail.com>
Date: Fri, 6 Jul 2018 13:21:30 +0100
Subject: [PATCH] Send nearby packets from world player list not server list
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index 939cec9121c051c5459084e4078740a7607803f3..917ea676d9ce2ea0b10e3a75b7f35f011c3599f6 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -910,8 +910,25 @@ public abstract class PlayerList {
}
public void sendPacketNearby(@Nullable EntityHuman entityhuman, double d0, double d1, double d2, double d3, DimensionManager dimensionmanager, Packet<?> packet) {
- for (int i = 0; i < this.players.size(); ++i) {
- EntityPlayer entityplayer = (EntityPlayer) this.players.get(i);
+ // Paper start - Use world list instead of server list where preferable
+ sendPacketNearby(entityhuman, d0, d1, d2, d3, dimensionmanager, null, packet); // Retained for compatibility
+ }
+
+ public void sendPacketNearby(@Nullable EntityHuman entityhuman, double d0, double d1, double d2, double d3, WorldServer world, Packet<?> packet) {
+ sendPacketNearby(entityhuman, d0, d1, d2, d3, world.worldProvider.getDimensionManager(), world, packet);
+ }
+
+ public void sendPacketNearby(@Nullable EntityHuman entityhuman, double d0, double d1, double d2, double d3, DimensionManager dimensionmanager, @Nullable WorldServer world, Packet<?> packet) {
+ if (world == null && entityhuman != null && entityhuman.world instanceof WorldServer) {
+ world = (WorldServer) entityhuman.world;
+ }
+
+ List<? extends EntityHuman> players1 = world == null ? players : world.players;
+ for (int j = 0; j < players1.size(); ++j) {
+ EntityHuman entity = players1.get(j);
+ if (!(entity instanceof EntityPlayer)) continue;
+ EntityPlayer entityplayer = (EntityPlayer) entity;
+ // Paper end
// CraftBukkit start - Test if player receiving packet can see the source of the packet
if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) {
@@ -919,7 +936,7 @@ public abstract class PlayerList {
}
// CraftBukkit end
- if (entityplayer != entityhuman && entityplayer.dimension == dimensionmanager) {
+ if (entityplayer != entityhuman && (world != null || entityplayer.dimension == dimensionmanager)) { // Paper
double d4 = d0 - entityplayer.locX();
double d5 = d1 - entityplayer.locY();
double d6 = d2 - entityplayer.locZ();
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 3067ab76d94c58fbfd52fac6754bf6d6d7f01d09..6e878c9b9dee511812df5ea2491d953f677c3f58 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -1276,7 +1276,7 @@ public class WorldServer extends World {
}
// CraftBukkit end
this.globalEntityList.add(entitylightning);
- this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entitylightning.locX(), entitylightning.locY(), entitylightning.locZ(), 512.0D, this.worldProvider.getDimensionManager(), new PacketPlayOutSpawnEntityWeather(entitylightning));
+ this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entitylightning.locX(), entitylightning.locY(), entitylightning.locZ(), 512.0D, this, new PacketPlayOutSpawnEntityWeather(entitylightning)); // Paper - use world instead of dimension
}
@Override
@@ -1408,7 +1408,7 @@ public class WorldServer extends World {
BlockActionData blockactiondata = (BlockActionData) this.I.removeFirst();
if (this.a(blockactiondata)) {
- this.server.getPlayerList().sendPacketNearby((EntityHuman) null, (double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, this.worldProvider.getDimensionManager(), new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.b(), blockactiondata.c(), blockactiondata.d()));
+ this.server.getPlayerList().sendPacketNearby((EntityHuman) null, (double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, this, new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.b(), blockactiondata.c(), blockactiondata.d()));
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 6c3cd51d92d2271cd216c42c18733d549fbe668d..ad951812835b1fa786e964c533efc4547c57b7a2 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -2122,7 +2122,7 @@ public class CraftWorld implements World {
double z = loc.getZ();
PacketPlayOutCustomSoundEffect packet = new PacketPlayOutCustomSoundEffect(new MinecraftKey(sound), SoundCategory.valueOf(category.name()), new Vec3D(x, y, z), volume, pitch);
- world.getMinecraftServer().getPlayerList().sendPacketNearby(null, x, y, z, volume > 1.0F ? 16.0F * volume : 16.0D, this.world.getWorldProvider().getDimensionManager(), packet);
+ world.getMinecraftServer().getPlayerList().sendPacketNearby(null, x, y, z, volume > 1.0F ? 16.0F * volume : 16.0D, this.world, packet); // Paper - this.world.dimension -> this.world
}
private static Map<String, GameRules.GameRuleKey<?>> gamerules;

View file

@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brokkonaut <hannos17@gmx.de>
Date: Tue, 25 Sep 2018 06:53:43 +0200
Subject: [PATCH] Avoid dimension id collisions
getDimensionId() returns the dimension id - 1. So without this patch
we would reuse an existing dimension id, if some other dimension was
unloaded before.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 011d0927da7a2a67dcd6d75e3af07d38f30acf81..3c43f318c4cff914128e2f7060516ce7ebb6e1c9 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1002,7 +1002,7 @@ public final class CraftServer implements Server {
boolean used = false;
do {
for (WorldServer server : console.getWorlds()) {
- used = server.getWorldProvider().getDimensionManager().getDimensionID() == dimension;
+ used = server.getWorldProvider().getDimensionManager().getDimensionID() + 1 == dimension; // Paper - getDimensionID returns the dimension - 1, so we have to add 1
if (used) {
dimension++;
break;

View file

@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Fri, 19 Oct 2018 19:38:45 -0500
Subject: [PATCH] Fix MC-93764
diff --git a/src/main/java/net/minecraft/server/WorldProviderTheEnd.java b/src/main/java/net/minecraft/server/WorldProviderTheEnd.java
index 9d4fcf8bcfdc5c09fe0a7ba18a229be3b0e7115c..4b9760709df89ab8378184cb643a9079685b6230 100644
--- a/src/main/java/net/minecraft/server/WorldProviderTheEnd.java
+++ b/src/main/java/net/minecraft/server/WorldProviderTheEnd.java
@@ -27,7 +27,7 @@ public class WorldProviderTheEnd extends WorldProvider {
@Override
public float a(long i, float f) {
- return 0.0F;
+ return 0.5F; // Paper - fix MC-93764
}
@Override

View file

@ -0,0 +1,223 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Fri, 24 May 2019 07:53:16 +0100
Subject: [PATCH] Fix some generation concurrency issues
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index a59a965104a2c2977fa3b3d0a199913df268bbd3..69db339c29c8f06026f05b0b5bb8019099af3fdf 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -86,6 +86,23 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
private int tileTickPosition;
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
public java.util.ArrayDeque<BlockRedstoneTorch.RedstoneUpdateInfo> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
+ // Paper start - yes this is hacky as shit
+ RegionLimitedWorldAccess regionLimited;
+ World originalWorld;
+ public World regionLimited(RegionLimitedWorldAccess limitedWorldAccess) {
+ try {
+ World clone = (World) super.clone();
+ clone.regionLimited = limitedWorldAccess;
+ clone.originalWorld = this;
+ return clone;
+ } catch (CloneNotSupportedException e1) {
+ }
+ return null;
+ }
+ ChunkCoordIntPair[] strongholdCoords;
+ List<StructureStart> strongholdStuctures = Lists.newArrayList();
+ final java.lang.Object stuctureLock = new Object();
+ // Paper end
public CraftWorld getWorld() {
return this.world;
diff --git a/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java b/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java
index 22e14fe1e98c8439f8db74c9464137a497fdaf7c..e2af6d43b2eafeecad8fd070fc70195c7b0bb93f 100644
--- a/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java
+++ b/src/main/java/net/minecraft/server/WorldGenFeatureStateProviderWeighted.java
@@ -23,18 +23,18 @@ public class WorldGenFeatureStateProviderWeighted extends WorldGenFeatureStatePr
this(new WeightedList<>(dynamic.get("entries").orElseEmptyList(), IBlockData::a));
}
- public WorldGenFeatureStateProviderWeighted a(IBlockData iblockdata, int i) {
+ public synchronized WorldGenFeatureStateProviderWeighted a(IBlockData iblockdata, int i) { // Paper
this.b.a(iblockdata, i);
return this;
}
@Override
- public IBlockData a(Random random, BlockPosition blockposition) {
+ public synchronized IBlockData a(Random random, BlockPosition blockposition) { // Paper
return (IBlockData) this.b.b(random);
}
@Override
- public <T> T a(DynamicOps<T> dynamicops) {
+ public synchronized <T> T a(DynamicOps<T> dynamicops) { // Paper
Builder<T, T> builder = ImmutableMap.builder();
builder.put(dynamicops.createString("type"), dynamicops.createString(IRegistry.t.getKey(this.a).toString())).put(dynamicops.createString("entries"), this.b.a(dynamicops, (iblockdata) -> {
diff --git a/src/main/java/net/minecraft/server/WorldGenStronghold.java b/src/main/java/net/minecraft/server/WorldGenStronghold.java
index fc4348b60242e4a9d8612c3b8ce01711c32f4b1c..44be7169ffd5961df28d21a319d2cc7569662baf 100644
--- a/src/main/java/net/minecraft/server/WorldGenStronghold.java
+++ b/src/main/java/net/minecraft/server/WorldGenStronghold.java
@@ -10,10 +10,12 @@ import javax.annotation.Nullable;
public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyConfiguration> {
+ /* // Paper start - no shared state
private boolean a;
private ChunkCoordIntPair[] aq;
private final List<StructureStart> ar = Lists.newArrayList();
private long as;
+ */
public WorldGenStronghold(Function<Dynamic<?>, ? extends WorldGenFeatureEmptyConfiguration> function) {
super(function);
@@ -21,16 +23,22 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
@Override
public boolean a(BiomeManager biomemanager, ChunkGenerator<?> chunkgenerator, Random random, int i, int j, BiomeBase biomebase) {
+ // Paper start
+ /*
if (this.as != chunkgenerator.getSeed()) {
this.d();
}
+ */
+ final World world = chunkgenerator.getWorld();
- if (!this.a) {
+ synchronized (world.stuctureLock) {
+ if ( world.strongholdCoords == null) {
this.a(chunkgenerator);
- this.a = true;
- }
+ // this.a = true;
+ }}
+ // Paper end
- ChunkCoordIntPair[] achunkcoordintpair = this.aq;
+ ChunkCoordIntPair[] achunkcoordintpair = world.strongholdCoords; // Paper
int k = achunkcoordintpair.length;
for (int l = 0; l < k; ++l) {
@@ -45,9 +53,11 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
}
private void d() {
+ /* // Paper
this.a = false;
this.aq = null;
this.ar.clear();
+ */ // Paper
}
@Override
@@ -65,25 +75,32 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
return 8;
}
+
@Nullable
@Override
public synchronized BlockPosition getNearestGeneratedFeature(World world, ChunkGenerator<? extends GeneratorSettingsDefault> chunkgenerator, BlockPosition blockposition, int i, boolean flag) {
if (!chunkgenerator.getWorldChunkManager().a(this)) {
return null;
} else {
+ // Paper start - no shared state
+ /*
if (this.as != world.getSeed()) {
this.d();
}
+ */
- if (!this.a) {
- this.a(chunkgenerator);
- this.a = true;
+ synchronized (world.stuctureLock) {
+ if ( world.strongholdCoords == null) {
+ this.a(chunkgenerator);
+ //this.a = true;
+ }
}
+ // Paper end
BlockPosition blockposition1 = null;
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
double d0 = Double.MAX_VALUE;
- ChunkCoordIntPair[] achunkcoordintpair = this.aq;
+ ChunkCoordIntPair[] achunkcoordintpair = world.strongholdCoords; // Paper
int j = achunkcoordintpair.length;
for (int k = 0; k < j; ++k) {
@@ -106,7 +123,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
}
private void a(ChunkGenerator<?> chunkgenerator) {
- this.as = chunkgenerator.getSeed();
+ //this.as = chunkgenerator.getSeed(); // Paper
List<BiomeBase> list = Lists.newArrayList();
Iterator iterator = IRegistry.BIOME.iterator();
@@ -122,15 +139,15 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
int j = chunkgenerator.getSettings().f();
int k = chunkgenerator.getSettings().g();
- this.aq = new ChunkCoordIntPair[j];
+ ChunkCoordIntPair[] strongholdCoords = chunkgenerator.getWorld().strongholdCoords = new ChunkCoordIntPair[j]; // Paper
int l = 0;
- Iterator iterator1 = this.ar.iterator();
+ Iterator iterator1 = chunkgenerator.getWorld().strongholdStuctures.iterator(); // Paper
while (iterator1.hasNext()) {
StructureStart structurestart = (StructureStart) iterator1.next();
- if (l < this.aq.length) {
- this.aq[l++] = new ChunkCoordIntPair(structurestart.f(), structurestart.g());
+ if (l < strongholdCoords.length) { // Paper
+ strongholdCoords[l++] = new ChunkCoordIntPair(structurestart.f(), structurestart.g()); // Paper
}
}
@@ -140,11 +157,11 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
double d0 = random.nextDouble() * 3.141592653589793D * 2.0D;
int i1 = l;
- if (l < this.aq.length) {
+ if (l < strongholdCoords.length) { // Paper
int j1 = 0;
int k1 = 0;
- for (int l1 = 0; l1 < this.aq.length; ++l1) {
+ for (int l1 = 0; l1 < strongholdCoords.length; ++l1) { // Paper
double d1 = (double) (4 * i + i * k1 * 6) + (random.nextDouble() - 0.5D) * (double) i * 2.5D;
int i2 = (int) Math.round(Math.cos(d0) * d1);
int j2 = (int) Math.round(Math.sin(d0) * d1);
@@ -156,7 +173,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
}
if (l1 >= i1) {
- this.aq[l1] = new ChunkCoordIntPair(i2, j2);
+ strongholdCoords[l1] = new ChunkCoordIntPair(i2, j2); // Paper
}
d0 += 6.283185307179586D / (double) k;
@@ -165,7 +182,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
++k1;
j1 = 0;
k += 2 * k / (k1 + 1);
- k = Math.min(k, this.aq.length - l1);
+ k = Math.min(k, strongholdCoords.length - l1); // Paper
d0 += random.nextDouble() * 3.141592653589793D * 2.0D;
}
}
@@ -207,7 +224,7 @@ public class WorldGenStronghold extends StructureGenerator<WorldGenFeatureEmptyC
this.a(chunkgenerator.getSeaLevel(), this.d, 10);
} while (this.b.isEmpty() || worldgenstrongholdpieces_worldgenstrongholdstart.b == null);
- ((WorldGenStronghold) this.l()).ar.add(this);
+ chunkgenerator.getWorld().strongholdStuctures.add(this); // Paper - this worries me, this is never cleared, even in vanilla (world seed never changes "world", and that appears to be the only relevant world)
}
}
}

View file

@ -0,0 +1,96 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Phoenix616 <mail@moep.tv>
Date: Sun, 15 Sep 2019 11:32:32 -0500
Subject: [PATCH] Fix zero-tick instant grow farms MC-113809
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 62fe175dc4f00cc9cab6cbd828b57e25740b3793..f6f5f9dea6284582e9a175c0875273ee1db76076 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -552,6 +552,11 @@ public class PaperWorldConfig {
disableRelativeProjectileVelocity = getBoolean("game-mechanics.disable-relative-projectile-velocity", false);
}
+ public boolean fixZeroTickInstantGrowFarms = true;
+ private void fixZeroTickInstantGrowFarms() {
+ fixZeroTickInstantGrowFarms = getBoolean("fix-zero-tick-instant-grow-farms", fixZeroTickInstantGrowFarms);
+ }
+
public boolean altItemDespawnRateEnabled;
public Map<Material, Integer> altItemDespawnRateMap;
private void altItemDespawnRate() {
diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java
index 540fcce1dd4d64dee51e2594f2199fac5299c6a0..e29ec958b3519d92cda215a50e97e6852d71c684 100644
--- a/src/main/java/net/minecraft/server/Block.java
+++ b/src/main/java/net/minecraft/server/Block.java
@@ -46,6 +46,7 @@ public class Block implements IMaterial {
private final float g;
protected final BlockStateList<Block, IBlockData> blockStateList;
private IBlockData blockData;
+ public boolean randomTick = false; // Paper - fix MC-113809
protected final boolean v;
private final boolean i;
private final boolean j;
diff --git a/src/main/java/net/minecraft/server/BlockBamboo.java b/src/main/java/net/minecraft/server/BlockBamboo.java
index c482aad3e3e255dfe13b622859ed61b780a9e08e..02c548dd9c9a97bfb55d39ba2f6d4ab85ada0573 100644
--- a/src/main/java/net/minecraft/server/BlockBamboo.java
+++ b/src/main/java/net/minecraft/server/BlockBamboo.java
@@ -85,6 +85,7 @@ public class BlockBamboo extends Block implements IBlockFragilePlantElement {
if (!iblockdata.canPlace(worldserver, blockposition)) {
worldserver.b(blockposition, true);
} else if ((Integer) iblockdata.get(BlockBamboo.f) == 0) {
+ if (worldserver.paperConfig.fixZeroTickInstantGrowFarms && !randomTick) return; // Paper - fix MC-113809
if (random.nextInt(Math.max(1, (int) (100.0F / worldserver.spigotConfig.bambooModifier) * 3)) == 0 && worldserver.isEmpty(blockposition.up()) && worldserver.getLightLevel(blockposition.up(), 0) >= 9) { // Spigot
int i = this.b(worldserver, blockposition) + 1;
diff --git a/src/main/java/net/minecraft/server/BlockCactus.java b/src/main/java/net/minecraft/server/BlockCactus.java
index e0974e256f0f10e047b9eb8e362982c6578d2d98..3524fcb927865d7b8754d9fbf85b853f09b94bb8 100644
--- a/src/main/java/net/minecraft/server/BlockCactus.java
+++ b/src/main/java/net/minecraft/server/BlockCactus.java
@@ -21,6 +21,7 @@ public class BlockCactus extends Block {
if (!iblockdata.canPlace(worldserver, blockposition)) {
worldserver.b(blockposition, true);
} else {
+ if (worldserver.paperConfig.fixZeroTickInstantGrowFarms && !randomTick) return; // Paper - fix MC-113809
BlockPosition blockposition1 = blockposition.up();
if (worldserver.isEmpty(blockposition1)) {
diff --git a/src/main/java/net/minecraft/server/BlockChorusFlower.java b/src/main/java/net/minecraft/server/BlockChorusFlower.java
index d70b52cadf1b76eff7984127837b0a3aa36f6a0e..b624cf38047e242569d30ee4e3ad971455b5ff0a 100644
--- a/src/main/java/net/minecraft/server/BlockChorusFlower.java
+++ b/src/main/java/net/minecraft/server/BlockChorusFlower.java
@@ -22,6 +22,7 @@ public class BlockChorusFlower extends Block {
if (!iblockdata.canPlace(worldserver, blockposition)) {
worldserver.b(blockposition, true);
} else {
+ if (worldserver.paperConfig.fixZeroTickInstantGrowFarms && !randomTick) return; // Paper - fix MC-113809
BlockPosition blockposition1 = blockposition.up();
if (worldserver.isEmpty(blockposition1) && blockposition1.getY() < 256) {
diff --git a/src/main/java/net/minecraft/server/BlockReed.java b/src/main/java/net/minecraft/server/BlockReed.java
index 55b07444e1d769952f2a411b1b5d1032565af8a1..3bc3c5aa29f45cd2ee1c0401b1ee1b1d49e81926 100644
--- a/src/main/java/net/minecraft/server/BlockReed.java
+++ b/src/main/java/net/minecraft/server/BlockReed.java
@@ -23,6 +23,7 @@ public class BlockReed extends Block {
if (!iblockdata.canPlace(worldserver, blockposition)) {
worldserver.b(blockposition, true);
} else if (worldserver.isEmpty(blockposition.up())) {
+ if (worldserver.paperConfig.fixZeroTickInstantGrowFarms && !randomTick) return; // Paper - fix MC-113809
int i;
for (i = 1; worldserver.getType(blockposition.down(i)).getBlock() == this; ++i) {
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 80e2a15bebe93939dc7b43b17b8116965438c062..3ecc73d021c09fbcad74dd62aced460771f86038 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -589,7 +589,9 @@ public class WorldServer extends World {
IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k);
if (iblockdata.q()) {
+ iblockdata.getBlock().randomTick = true; // Paper - fix MC-113809
iblockdata.b(this, blockposition2, this.random);
+ iblockdata.getBlock().randomTick = false; // Paper - fix MC-113809
}
Fluid fluid = iblockdata.getFluid();

View file

@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sun, 15 Dec 2019 19:41:28 +0000
Subject: [PATCH] Fix spawn radius being treated as 0
Not needed anymore?
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index 81f00141776a1767b907d14ef04f60b576110128..86bbbbaefca9ace5327d8bc2456939eb9ae8966a 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -129,7 +129,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
public final BlockPosition getSpawnPoint(WorldServer worldserver) {
BlockPosition blockposition = worldserver.getSpawn();
- if (worldserver.worldProvider.g() && worldserver.getWorldData().getGameType() != EnumGamemode.ADVENTURE) {
+ if (worldserver.worldProvider.f() && worldserver.getWorldData().getGameType() != EnumGamemode.ADVENTURE) { // Paper
int i = Math.max(0, this.server.a(worldserver));
int j = MathHelper.floor(worldserver.getWorldBorder().b((double) blockposition.getX(), (double) blockposition.getZ()));

View file

@ -0,0 +1,110 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Phoenix616 <mail@moep.tv>
Date: Mon, 13 Jan 2020 15:40:32 +0100
Subject: [PATCH] Seed based feature search
This fixes the issue where the server will load surrounding chunks up to
a radius of 100 chunks in order to search for features e.g. when running
the /locate command or for treasure maps (issue #2312).
This is done by using the same seed checking functionality that is used
by the server when generating these features before actually attempting
to load the chunk to check if a feature is available in it.
The only downside of this is that it breaks once the seed or generator
changes but this should usually not happen. A config option to disable
this improvement is added though in case that should ever be necessary.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index cab503bd5c34d12b38a2f5deed6d3feb9287b370..2ab810f71beaa608af2194165696817a2cde4b92 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -357,6 +357,12 @@ public class PaperWorldConfig {
}
}
+ public boolean seedBasedFeatureSearch = true;
+ private void seedBasedFeatureSearch() {
+ seedBasedFeatureSearch = getBoolean("seed-based-feature-search", seedBasedFeatureSearch);
+ log("Feature search is based on seed: " + seedBasedFeatureSearch);
+ }
+
public int maxCollisionsPerEntity;
private void maxEntityCollision() {
maxCollisionsPerEntity = getInt( "max-entity-collisions", this.spigotConfig.getInt("max-entity-collisions", 8) );
diff --git a/src/main/java/net/minecraft/server/BiomeManager.java b/src/main/java/net/minecraft/server/BiomeManager.java
index e96f544f126371f6f629a20ba3c99ba42d31e04a..68423645df3aa08d4c5126ff068d5e566927f744 100644
--- a/src/main/java/net/minecraft/server/BiomeManager.java
+++ b/src/main/java/net/minecraft/server/BiomeManager.java
@@ -12,10 +12,12 @@ public class BiomeManager {
this.c = genlayerzoomer;
}
+ public BiomeManager withProvider(WorldChunkManager worldchunkmanager) { return a(worldchunkmanager); } // Paper - OBFHELPER
public BiomeManager a(WorldChunkManager worldchunkmanager) {
return new BiomeManager(worldchunkmanager, this.b, this.c);
}
+ public BiomeBase getBiome(BlockPosition blockposition) { return a(blockposition); } // Paper - OBFHELPER
public BiomeBase a(BlockPosition blockposition) {
return this.c.a(this.b, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.a);
}
diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
index 5a975f6bc60922ac872ec9c00c9150ce7dcad046..f617636a22167b06ac8073aa25efd8c7099155f0 100644
--- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
+++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java
@@ -68,10 +68,12 @@ public class ChunkCoordIntPair {
}
}
+ public int getBlockX() { return d(); } // Paper - OBFHELPER
public int d() {
return this.x << 4;
}
+ public int getBlockZ() { return e(); } // Paper - OBFHELPER
public int e() {
return this.z << 4;
}
diff --git a/src/main/java/net/minecraft/server/StructureGenerator.java b/src/main/java/net/minecraft/server/StructureGenerator.java
index e8ce2ecf23e58d82febf6b9441e0004e69cdc858..acfe732af5b9f63fc2f6b78499defabe2e73ee45 100644
--- a/src/main/java/net/minecraft/server/StructureGenerator.java
+++ b/src/main/java/net/minecraft/server/StructureGenerator.java
@@ -109,6 +109,15 @@ public abstract class StructureGenerator<C extends WorldGenFeatureConfiguration>
if (flag1 || flag2) {
ChunkCoordIntPair chunkcoordintpair = this.a(chunkgenerator, seededrandom, j, k, i1, j1);
if (!world.getWorldBorder().isChunkInBounds(chunkcoordintpair.x, chunkcoordintpair.z)) { continue; } // Paper
+ // Paper start - seed based feature search
+ if (world.paperConfig.seedBasedFeatureSearch) {
+ BiomeManager biomeManager = world.getBiomeManager().withProvider(chunkgenerator.getWorldChunkManager());
+ BiomeBase biomeBase = biomeManager.getBiome(new BlockPosition(chunkcoordintpair.getBlockX() + 9, 0, chunkcoordintpair.getBlockZ() + 9));
+ if (!shouldGenerate(biomeManager, chunkgenerator, seededrandom, chunkcoordintpair.x, chunkcoordintpair.z, biomeBase)) {
+ continue;
+ }
+ }
+ // Paper end
StructureStart structurestart = world.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, ChunkStatus.STRUCTURE_STARTS).a(this.b());
if (structurestart != null && structurestart.e()) {
@@ -165,6 +174,7 @@ public abstract class StructureGenerator<C extends WorldGenFeatureConfiguration>
return new ChunkCoordIntPair(i + k, j + l);
}
+ public boolean shouldGenerate(BiomeManager biomemanager, ChunkGenerator<?> chunkgenerator, Random random, int chunkX, int chunkZ, BiomeBase biomebase) { return a(biomemanager, chunkgenerator, random, chunkX, chunkZ, biomebase); } // Paper - OBFHELPER
public abstract boolean a(BiomeManager biomemanager, ChunkGenerator<?> chunkgenerator, Random random, int i, int j, BiomeBase biomebase);
public abstract StructureGenerator.a a();
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 0fa2b335db297c6270090d3dd24ced92eab12825..d7ac4c86d170a8d7d816f86ac691c3b5129a20ba 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -1570,8 +1570,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
return this.methodProfiler;
}
- @Override
- public BiomeManager d() {
+ public BiomeManager getBiomeManager() { return d(); } // Paper - OBFHELPER
+ @Override public BiomeManager d() {
return this.biomeManager;
}
}

View file

@ -0,0 +1,195 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Callahan <mr.callahhh@gmail.com>
Date: Wed, 8 Apr 2020 18:00:17 -0500
Subject: [PATCH] Port 20w15a Villager AI optimizations - DROP 1.16
diff --git a/src/main/java/net/minecraft/server/BehaviorController.java b/src/main/java/net/minecraft/server/BehaviorController.java
index 7c6e687707cdf32638eee41e549818a494cd45ab..396b64ea0fc8a04d9e0aac289033d3d82385b86e 100644
--- a/src/main/java/net/minecraft/server/BehaviorController.java
+++ b/src/main/java/net/minecraft/server/BehaviorController.java
@@ -38,30 +38,22 @@ public class BehaviorController<E extends EntityLiving> implements MinecraftSeri
this.g = Sets.newHashSet();
this.h = Activity.IDLE;
this.i = -9999L;
- collection.forEach((memorymoduletype) -> {
- Optional optional = (Optional) this.memories.put(memorymoduletype, Optional.empty());
- });
- collection1.forEach((sensortype) -> {
- Sensor sensor = (Sensor) this.sensors.put(sensortype, sensortype.a());
- });
- this.sensors.values().forEach((sensor) -> {
- Iterator iterator = sensor.a().iterator();
-
- while (iterator.hasNext()) {
- MemoryModuleType<?> memorymoduletype = (MemoryModuleType) iterator.next();
-
- this.memories.put(memorymoduletype, Optional.empty());
+ // Paper start - Port 20w15a pathfinder optimizations
+ for (final MemoryModuleType<?> memoryModuleType : collection) {
+ this.memories.put(memoryModuleType, Optional.empty());
+ }
+ for (final SensorType<? extends Sensor<? super E>> sensorType : collection1) {
+ this.sensors.put(sensorType, sensorType.a());
+ }
+ for (final Sensor<? super E> sensor : this.sensors.values()) {
+ for (final MemoryModuleType<?> memoryModuleType : sensor.a()) {
+ this.memories.put(memoryModuleType, Optional.empty());
}
-
- });
- Iterator iterator = dynamic.get("memories").asMap(Function.identity(), Function.identity()).entrySet().iterator();
-
- while (iterator.hasNext()) {
- Entry<Dynamic<T>, Dynamic<T>> entry = (Entry) iterator.next();
-
- this.a((MemoryModuleType) IRegistry.MEMORY_MODULE_TYPE.get(new MinecraftKey(((Dynamic) entry.getKey()).asString(""))), (Dynamic) entry.getValue());
}
-
+ for (final Map.Entry<Dynamic<T>, Dynamic<T>> entry : dynamic.get("memories").asMap(Function.identity(), Function.identity()).entrySet()) {
+ this.a((MemoryModuleType) IRegistry.MEMORY_MODULE_TYPE.get(new MinecraftKey((entry.getKey()).asString(""))), entry.getValue());
+ }
+ // Paper end - Port 20w15a pathfinder optimizations
}
public boolean hasMemory(MemoryModuleType<?> memorymoduletype) {
@@ -69,7 +61,7 @@ public class BehaviorController<E extends EntityLiving> implements MinecraftSeri
}
private <T, U> void a(MemoryModuleType<U> memorymoduletype, Dynamic<T> dynamic) {
- this.setMemory(memorymoduletype, ((Function) memorymoduletype.getSerializer().orElseThrow(RuntimeException::new)).apply(dynamic));
+ this.setMemory(memorymoduletype, (memorymoduletype.getSerializer().orElseThrow(RuntimeException::new)).apply(dynamic)); // Paper - decompile fix
}
public <U> void removeMemory(MemoryModuleType<U> memorymoduletype) {
@@ -113,13 +105,21 @@ public class BehaviorController<E extends EntityLiving> implements MinecraftSeri
this.f = set;
}
+ // Paper start - Port 20w15a pathfinder optimizations
@Deprecated
- public Stream<Behavior<? super E>> d() {
- return this.c.values().stream().flatMap((map) -> {
- return map.values().stream();
- }).flatMap(Collection::stream).filter((behavior) -> {
- return behavior.a() == Behavior.Status.RUNNING;
- });
+ public java.util.List<Behavior<? super E>> d() {
+ final java.util.List<Behavior<? super E>> behaviorList = (java.util.List<Behavior<? super E>>) new it.unimi.dsi.fastutil.objects.ObjectArrayList();
+ for (final Map<Activity, Set<Behavior<? super E>>> map : this.c.values()) {
+ for (final Set<Behavior<? super E>> set : map.values()) {
+ for (final Behavior<? super E> behavior : set) {
+ if (behavior.a() == Behavior.Status.RUNNING) {
+ behaviorList.add(behavior);
+ }
+ }
+ }
+ }
+ return behaviorList;
+ // Paper end - Port 20w15a pathfinder optimizations
}
public void a(Activity activity) {
@@ -168,12 +168,14 @@ public class BehaviorController<E extends EntityLiving> implements MinecraftSeri
public BehaviorController<E> f() {
BehaviorController<E> behaviorcontroller = new BehaviorController<>(this.memories.keySet(), this.sensors.keySet(), new Dynamic(DynamicOpsNBT.a, new NBTTagCompound()));
-
- this.memories.forEach((memorymoduletype, optional) -> {
- optional.ifPresent((object) -> {
- Optional optional1 = (Optional) behaviorcontroller.memories.put(memorymoduletype, Optional.of(object));
- });
- });
+ // Paper start - Port 20w15a pathfinder optimizations
+ for (final Entry<MemoryModuleType<?>, Optional<?>> entry : this.memories.entrySet()) {
+ final MemoryModuleType<?> memoryModuleType = entry.getKey();
+ if (entry.getValue().isPresent()) {
+ behaviorcontroller.memories.put(memoryModuleType, entry.getValue());
+ }
+ }
+ // Paper end - Port 20w15a pathfinder optimizations
return behaviorcontroller;
}
@@ -186,14 +188,14 @@ public class BehaviorController<E extends EntityLiving> implements MinecraftSeri
public void b(WorldServer worldserver, E e0) {
long i = e0.world.getTime();
- this.d().forEach((behavior) -> {
+ for(Behavior<? super E> behavior : this.d()) { // Paper - Port 20w15a pathfinder optimizations
behavior.e(worldserver, e0, i);
- });
+ }
}
@Override
public <T> T a(DynamicOps<T> dynamicops) {
- T t0 = dynamicops.createMap((Map) this.memories.entrySet().stream().filter((entry) -> {
+ T t0 = dynamicops.createMap(this.memories.entrySet().stream().filter((entry) -> { // Paper - decompile fix
return ((MemoryModuleType) entry.getKey()).getSerializer().isPresent() && ((Optional) entry.getValue()).isPresent();
}).map((entry) -> {
return Pair.of(dynamicops.createString(IRegistry.MEMORY_MODULE_TYPE.getKey(entry.getKey()).toString()), ((MinecraftSerializable) ((Optional) entry.getValue()).get()).a(dynamicops));
@@ -210,33 +212,45 @@ public class BehaviorController<E extends EntityLiving> implements MinecraftSeri
private void d(WorldServer worldserver, E e0) {
long i = worldserver.getTime();
-
- this.c.values().stream().flatMap((map) -> {
- return map.entrySet().stream();
- }).filter((entry) -> {
- return this.g.contains(entry.getKey());
- }).map(Entry::getValue).flatMap(Collection::stream).filter((behavior) -> {
- return behavior.a() == Behavior.Status.STOPPED;
- }).forEach((behavior) -> {
- behavior.b(worldserver, e0, i);
- });
+ // Paper start - Port 20w15a pathfinder optimizations
+ for (final Map<Activity, Set<Behavior<? super E>>> map : this.c.values()) {
+ for (final Map.Entry<Activity, Set<Behavior<? super E>>> entry : map.entrySet()) {
+ final Activity activity = entry.getKey();
+ if (this.g.contains(activity)) {
+ final Set<Behavior<? super E>> set = entry.getValue();
+ for (final Behavior<? super E> behavior : set) {
+ if (behavior.a() == Behavior.Status.STOPPED) {
+ behavior.b(worldserver, e0, i);
+ }
+ }
+ }
+ }
+ }
+ // Paper end - Port 20w15a pathfinder optimizations
}
private void e(WorldServer worldserver, E e0) {
long i = worldserver.getTime();
- this.d().forEach((behavior) -> {
+ for (final Behavior<? super E> behavior : this.d()) { // Paper - Port 20w15a pathfinder optimizations
behavior.c(worldserver, e0, i);
- });
+ }
}
private boolean d(Activity activity) {
- return ((Set) this.e.get(activity)).stream().allMatch((pair) -> {
- MemoryModuleType<?> memorymoduletype = (MemoryModuleType) pair.getFirst();
- MemoryStatus memorystatus = (MemoryStatus) pair.getSecond();
-
- return this.a(memorymoduletype, memorystatus);
- });
+ // Paper start - Port 20w15a pathfinder optimizations
+ if (!this.e.containsKey(activity)) {
+ return false;
+ }
+ for (final Pair<MemoryModuleType<?>, MemoryStatus> pair : this.e.get(activity)) {
+ MemoryModuleType<?> memorymoduletype = pair.getFirst();
+ MemoryStatus memorystatus = pair.getSecond();
+ if (!this.a(memorymoduletype, memorystatus)) {
+ return false;
+ }
+ }
+ return true;
+ // Paper end - Port 20w15a pathfinder optimizations
}
private boolean a(Object object) {

View file

@ -0,0 +1,31 @@
diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutTitle.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutTitle.java
index fff22c40ba38575951e8e4821ade22b29d580a89..c397c52e8e24b85d892e4906178720cc70edc143 100644
--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutTitle.java
+++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutTitle.java
@@ -47,6 +47,17 @@ public class PacketPlayOutTitle implements Packet<PacketListenerPlayOut> {
}
}
+ // Paper start
+ public net.md_5.bungee.api.chat.BaseComponent[] components;
+
+ public PacketPlayOutTitle(EnumTitleAction action, net.md_5.bungee.api.chat.BaseComponent[] components, int fadeIn, int stay, int fadeOut) {
+ this.a = action;
+ this.components = components;
+ this.c = fadeIn;
+ this.d = stay;
+ this.e = fadeOut;
+ }
+ // Paper end
@Override
public void b(PacketDataSerializer packetdataserializer) throws IOException {
@@ -55,6 +66,8 @@ public class PacketPlayOutTitle implements Packet<PacketListenerPlayOut> {
// Paper start
if (this.adventure$text != null) {
packetdataserializer.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ packetdataserializer.writeComponent(this.components);
} else
// Paper end
packetdataserializer.a(this.b);

View file

@ -0,0 +1,75 @@
From 5b7fa8b79798a56e956c7b5011c3298bc0de2a3c Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 1 Sep 2018 12:19:19 -0400
Subject: [PATCH 1/2] scheduler decompile fox
---
.../java/net/minecraft/server/Scheduler.java | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/main/java/net/minecraft/server/Scheduler.java b/src/main/java/net/minecraft/server/Scheduler.java
index ed155c8b30..1c327c58e7 100644
--- a/src/main/java/net/minecraft/server/Scheduler.java
+++ b/src/main/java/net/minecraft/server/Scheduler.java
@@ -27,8 +27,8 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
private final ExecutorService c;
private final AtomicInteger d = new AtomicInteger(1);
private final List<CompletableFuture<R>> e = Lists.newArrayList();
- private CompletableFuture<R> f = CompletableFuture.completedFuture((Object)null);
- private CompletableFuture<R> g = CompletableFuture.completedFuture((Object)null);
+ private CompletableFuture<R> f = CompletableFuture.completedFuture(null); // Paper - decompile fix
+ private CompletableFuture<R> g = CompletableFuture.completedFuture(null); // Paper - decompile fix
private final Supplier<Map<T, CompletableFuture<R>>> h;
private final Supplier<Map<T, CompletableFuture<Void>>> i;
private final T j;
@@ -121,12 +121,12 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
private final K c;
private final R d;
- public a(Object object, Object object1, SchedulerTask schedulertask) {
+ public a(Object object, Object object1, T schedulertask) { // Paper - decompile fix
this.b = (Map)Scheduler.this.h.get();
this.c = (K)object;
for(this.d = (R)object1; schedulertask != null; schedulertask = schedulertask.a()) {
- this.b.put(schedulertask, CompletableFuture.completedFuture(object1));
+ this.b.put(schedulertask, CompletableFuture.completedFuture((R)object1));// Paper - decompile fix
}
}
@@ -136,18 +136,18 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
}
private CompletableFuture<R> a(CompletableFuture<R> completablefuture, T schedulertask) {
- ConcurrentHashMap concurrenthashmap = new ConcurrentHashMap();
- return (CompletableFuture)this.b.computeIfAbsent(schedulertask, (var4) -> {
+ ConcurrentHashMap<K, CompletableFuture<R>> concurrenthashmap = new ConcurrentHashMap(); // Paper - decompile fix
+ return (CompletableFuture<R>)this.b.computeIfAbsent(schedulertask, (var4) -> { // Paper - decompile fix
if (schedulertask.a() == null) {
return CompletableFuture.completedFuture(this.d);
} else {
schedulertask.a(this.c, (object, schedulertask2) -> {
- CompletableFuture completablefuture4 = (CompletableFuture)concurrenthashmap.put(object, Scheduler.this.a(object, Scheduler.this.b(object)).a(completablefuture, schedulertask2));
+ CompletableFuture<R> completablefuture4 = (CompletableFuture)concurrenthashmap.put(object, Scheduler.this.a(object, Scheduler.this.b(object)).a(completablefuture, schedulertask2)); // Paper - decompile fix
});
- CompletableFuture[] acompletablefuture = (CompletableFuture[])Streams.concat(new Stream[]{Stream.of(completablefuture), concurrenthashmap.values().stream()}).toArray((i) -> {
+ CompletableFuture<R>[] acompletablefuture = (CompletableFuture[])Streams.concat(new Stream[]{Stream.of(completablefuture), concurrenthashmap.values().stream()}).toArray((i) -> { // Paper - decompile fix
return new CompletableFuture[i];
});
- CompletableFuture completablefuture2 = CompletableFuture.allOf(acompletablefuture).thenApplyAsync((var3) -> {
+ CompletableFuture<R> completablefuture2 = CompletableFuture.allOf(acompletablefuture).thenApplyAsync((var3) -> { // Paper - decompile fix
return Scheduler.this.a(this.c, schedulertask, Maps.transformValues(concurrenthashmap, (completablefuture3) -> {
try {
return completablefuture3.get();
@@ -156,7 +156,7 @@ public abstract class Scheduler<K, T extends SchedulerTask<K, T>, R> {
}
}));
}, Scheduler.this.c).thenApplyAsync((object) -> {
- for(Object object1 : concurrenthashmap.keySet()) {
+ for(K object1 : concurrenthashmap.keySet()) { // Paper - decompile fix
Scheduler.this.b(object1, Scheduler.this.b(object1));
}
--
2.18.0