75f3e084ad
1) You will not hold SpigotMC responsible for any losses or damages incurred to you by using this build 2) You will report ALL bugs to SpigotMC and not other parties Thanks for all the support and all parties who made this update possible; especially the awesome Spigot community. Sorry for the delay, but we had to fix some crucial bugs. Regressions in this commit: @mikeprimm's smarter chunk ticking patch has been removed as it prevents proper redstone and other block ticking logic.
1227 lines
58 KiB
Diff
1227 lines
58 KiB
Diff
From fb119d1c590c5394eecadda95eeea26ccffc25be Mon Sep 17 00:00:00 2001
|
|
From: md_5 <md_5@live.com.au>
|
|
Date: Sat, 16 Mar 2013 10:13:29 +1100
|
|
Subject: [PATCH] Spigot changes.
|
|
|
|
---
|
|
.gitignore | 2 +
|
|
src/main/java/net/minecraft/server/Block.java | 12 ++
|
|
.../java/net/minecraft/server/BlockCactus.java | 2 +-
|
|
src/main/java/net/minecraft/server/BlockCrops.java | 2 +-
|
|
src/main/java/net/minecraft/server/BlockGrass.java | 2 +-
|
|
.../java/net/minecraft/server/BlockMushroom.java | 2 +-
|
|
src/main/java/net/minecraft/server/BlockMycel.java | 2 +-
|
|
src/main/java/net/minecraft/server/BlockReed.java | 2 +-
|
|
.../java/net/minecraft/server/BlockSapling.java | 2 +-
|
|
src/main/java/net/minecraft/server/BlockStem.java | 2 +-
|
|
.../net/minecraft/server/ChunkRegionLoader.java | 35 +++--
|
|
.../java/net/minecraft/server/ChunkSection.java | 31 ++++-
|
|
src/main/java/net/minecraft/server/EntityItem.java | 3 +-
|
|
.../java/net/minecraft/server/EntitySquid.java | 4 -
|
|
.../net/minecraft/server/PlayerConnection.java | 18 ++-
|
|
src/main/java/net/minecraft/server/PlayerList.java | 10 +-
|
|
.../net/minecraft/server/ThreadLoginVerifier.java | 21 +++
|
|
src/main/java/net/minecraft/server/World.java | 152 ++++++++++++++++++---
|
|
.../java/net/minecraft/server/WorldServer.java | 36 ++++-
|
|
.../java/org/bukkit/craftbukkit/CraftServer.java | 45 +++---
|
|
.../java/org/bukkit/craftbukkit/CraftWorld.java | 76 ++++++++++-
|
|
src/main/java/org/bukkit/craftbukkit/Spigot.java | 20 +++
|
|
.../craftbukkit/chunkio/ChunkIOProvider.java | 2 +-
|
|
.../org/bukkit/craftbukkit/entity/CraftPlayer.java | 7 +
|
|
.../java/org/bukkit/craftbukkit/util/FlatMap.java | 34 +++++
|
|
.../org/bukkit/craftbukkit/util/LongHashSet.java | 11 +-
|
|
.../bukkit/craftbukkit/util/LongObjectHashMap.java | 5 +
|
|
src/main/resources/configurations/bukkit.yml | 27 ++++
|
|
28 files changed, 488 insertions(+), 79 deletions(-)
|
|
create mode 100644 src/main/java/org/bukkit/craftbukkit/Spigot.java
|
|
create mode 100644 src/main/java/org/bukkit/craftbukkit/util/FlatMap.java
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index a689360..b97a549 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -34,3 +34,5 @@
|
|
|
|
/src/main/resources/achievement
|
|
/src/main/resources/lang
|
|
+
|
|
+/dependency-reduced-pom.xml
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java
|
|
index 4392cb2..8e041c2 100644
|
|
--- a/src/main/java/net/minecraft/server/Block.java
|
|
+++ b/src/main/java/net/minecraft/server/Block.java
|
|
@@ -768,4 +768,16 @@ public class Block {
|
|
return 0;
|
|
}
|
|
// CraftBukkit end
|
|
+
|
|
+ // Spigot start
|
|
+ public static float range(float min, float value, float max) {
|
|
+ if (value < min) {
|
|
+ return min;
|
|
+ }
|
|
+ if (value > max) {
|
|
+ return max;
|
|
+ }
|
|
+ return value;
|
|
+ }
|
|
+ // Spigot end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/BlockCactus.java b/src/main/java/net/minecraft/server/BlockCactus.java
|
|
index 83cc09d..4fb2d87 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockCactus.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockCactus.java
|
|
@@ -23,7 +23,7 @@ public class BlockCactus extends Block {
|
|
if (l < 3) {
|
|
int i1 = world.getData(i, j, k);
|
|
|
|
- if (i1 == 15) {
|
|
+ if (i1 >= (byte) range(3, (world.growthOdds * 100 / world.getWorld().cactusGrowthModifier * 15 / 100F) + 0.5F, 15)) { // Spigot
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, i, j + 1, k, this.id, 0); // CraftBukkit
|
|
world.setData(i, j, k, 0, 4);
|
|
this.doPhysics(world, i, j + 1, k, this.id);
|
|
diff --git a/src/main/java/net/minecraft/server/BlockCrops.java b/src/main/java/net/minecraft/server/BlockCrops.java
|
|
index 14a1c3b..0c6ec6d 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockCrops.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockCrops.java
|
|
@@ -28,7 +28,7 @@ public class BlockCrops extends BlockFlower {
|
|
if (l < 7) {
|
|
float f = this.k(world, i, j, k);
|
|
|
|
- if (random.nextInt((int) (25.0F / f) + 1) == 0) {
|
|
+ if (random.nextInt((int) ((world.growthOdds * 100 / world.getWorld().wheatGrowthModifier / 25.0F) / f) + 1) == 0) { // Spigot
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, i, j, k, this.id, ++l); // CraftBukkit
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/BlockGrass.java b/src/main/java/net/minecraft/server/BlockGrass.java
|
|
index 6f9301d..c78a934 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockGrass.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockGrass.java
|
|
@@ -32,7 +32,7 @@ public class BlockGrass extends Block {
|
|
}
|
|
// CraftBukkit end
|
|
} else if (world.getLightLevel(i, j + 1, k) >= 9) {
|
|
- for (int l = 0; l < 4; ++l) {
|
|
+ for (int l = 0; l < Math.max(4, Math.max(20, (int) (4 * 100F / world.growthOdds))); ++l) { // Spigot
|
|
int i1 = i + random.nextInt(3) - 1;
|
|
int j1 = j + random.nextInt(5) - 3;
|
|
int k1 = k + random.nextInt(3) - 1;
|
|
diff --git a/src/main/java/net/minecraft/server/BlockMushroom.java b/src/main/java/net/minecraft/server/BlockMushroom.java
|
|
index 872ad00..aedcf62 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockMushroom.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockMushroom.java
|
|
@@ -27,7 +27,7 @@ public class BlockMushroom extends BlockFlower {
|
|
|
|
public void a(World world, int i, int j, int k, Random random) {
|
|
final int sourceX = i, sourceY = j, sourceZ = k; // CraftBukkit
|
|
- if (random.nextInt(25) == 0) {
|
|
+ if (random.nextInt((int) (world.growthOdds * 100 / world.getWorld().mushroomGrowthModifier * 25)) == 0) { // Spigot
|
|
byte b0 = 4;
|
|
int l = 5;
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/BlockMycel.java b/src/main/java/net/minecraft/server/BlockMycel.java
|
|
index 1de8c83..522d317 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockMycel.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockMycel.java
|
|
@@ -32,7 +32,7 @@ public class BlockMycel extends Block {
|
|
}
|
|
// CraftBukkit end
|
|
} else if (world.getLightLevel(i, j + 1, k) >= 9) {
|
|
- for (int l = 0; l < 4; ++l) {
|
|
+ for (int l = 0; l < Math.max(4, Math.max(20, (int) (4 * 100F / world.growthOdds))); ++l) { // Spigot
|
|
int i1 = i + random.nextInt(3) - 1;
|
|
int j1 = j + random.nextInt(5) - 3;
|
|
int k1 = k + random.nextInt(3) - 1;
|
|
diff --git a/src/main/java/net/minecraft/server/BlockReed.java b/src/main/java/net/minecraft/server/BlockReed.java
|
|
index 8657860..def38e9 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockReed.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockReed.java
|
|
@@ -23,7 +23,7 @@ public class BlockReed extends Block {
|
|
if (l < 3) {
|
|
int i1 = world.getData(i, j, k);
|
|
|
|
- if (i1 == 15) {
|
|
+ if (i1 >= (byte) range(3, (world.growthOdds * 100 / world.getWorld().sugarGrowthModifier * 15 / 100F) + 0.5F, 15)) { // Spigot
|
|
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, i, j + 1, k, this.id, 0); // CraftBukkit
|
|
world.setData(i, j, k, 0, 4);
|
|
} else {
|
|
diff --git a/src/main/java/net/minecraft/server/BlockSapling.java b/src/main/java/net/minecraft/server/BlockSapling.java
|
|
index 4264630..402647d 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockSapling.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockSapling.java
|
|
@@ -25,7 +25,7 @@ public class BlockSapling extends BlockFlower {
|
|
public void a(World world, int i, int j, int k, Random random) {
|
|
if (!world.isStatic) {
|
|
super.a(world, i, j, k, random);
|
|
- if (world.getLightLevel(i, j + 1, k) >= 9 && random.nextInt(7) == 0) {
|
|
+ if (world.getLightLevel(i, j + 1, k) >= 9 && (random.nextInt(Math.max(2, (int) ((world.growthOdds * 100 / world.getWorld().treeGrowthModifier * 7 / 100F) + 0.5F))) == 0)) { // Spigot
|
|
this.grow(world, i, j, k, random, false, null, null); // CraftBukkit - added bonemeal, player and itemstack
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/BlockStem.java b/src/main/java/net/minecraft/server/BlockStem.java
|
|
index 8339a35..a945ee4 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 BlockFlower {
|
|
if (world.getLightLevel(i, j + 1, k) >= 9) {
|
|
float f = this.m(world, i, j, k);
|
|
|
|
- if (random.nextInt((int) (25.0F / f) + 1) == 0) {
|
|
+ if (random.nextInt((int) ((world.growthOdds * 100 / ((this.id == Block.PUMPKIN_STEM.id) ? world.getWorld().pumpkinGrowthModifier : world.getWorld().melonGrowthModifier) / 25.0F) / f) + 1) == 0) { // Spigot
|
|
int l = world.getData(i, j, k);
|
|
|
|
if (l < 7) {
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
|
index 8f37333..c1f5cc2 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
|
|
@@ -13,8 +13,7 @@ import java.util.Set;
|
|
|
|
public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
|
|
- private List a = new ArrayList();
|
|
- private Set b = new HashSet();
|
|
+ private java.util.LinkedHashMap<ChunkCoordIntPair, PendingChunkToSave> pendingSaves = new java.util.LinkedHashMap<ChunkCoordIntPair, PendingChunkToSave>(); // Spigot
|
|
private Object c = new Object();
|
|
private final File d;
|
|
|
|
@@ -27,15 +26,12 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
|
|
|
|
synchronized (this.c) {
|
|
- if (this.b.contains(chunkcoordintpair)) {
|
|
- for (int k = 0; k < this.a.size(); ++k) {
|
|
- if (((PendingChunkToSave) this.a.get(k)).a.equals(chunkcoordintpair)) {
|
|
- return true;
|
|
- }
|
|
- }
|
|
+ // Spigot start
|
|
+ if (pendingSaves.containsKey(chunkcoordintpair)) {
|
|
+ return true;
|
|
}
|
|
}
|
|
-
|
|
+ // Spigot end
|
|
return RegionFileCache.a(this.d, i, j).chunkExists(i & 31, j & 31);
|
|
}
|
|
// CraftBukkit end
|
|
@@ -60,6 +56,12 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
Object object = this.c;
|
|
|
|
synchronized (this.c) {
|
|
+ // Spigot start
|
|
+ PendingChunkToSave pendingchunktosave = pendingSaves.get(chunkcoordintpair);
|
|
+ if (pendingchunktosave != null) {
|
|
+ nbttagcompound = pendingchunktosave.b;
|
|
+ }
|
|
+ /*
|
|
if (this.b.contains(chunkcoordintpair)) {
|
|
for (int k = 0; k < this.a.size(); ++k) {
|
|
if (((PendingChunkToSave) this.a.get(k)).a.equals(chunkcoordintpair)) {
|
|
@@ -68,6 +70,7 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
}
|
|
}
|
|
}
|
|
+ */// Spigot end
|
|
}
|
|
|
|
if (nbttagcompound == null) {
|
|
@@ -134,6 +137,11 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
Object object = this.c;
|
|
|
|
synchronized (this.c) {
|
|
+ // Spigot start
|
|
+ if (this.pendingSaves.put(chunkcoordintpair, new PendingChunkToSave(chunkcoordintpair, nbttagcompound)) != null) {
|
|
+ return;
|
|
+ }
|
|
+ /*
|
|
if (this.b.contains(chunkcoordintpair)) {
|
|
for (int i = 0; i < this.a.size(); ++i) {
|
|
if (((PendingChunkToSave) this.a.get(i)).a.equals(chunkcoordintpair)) {
|
|
@@ -145,6 +153,7 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
|
|
this.a.add(new PendingChunkToSave(chunkcoordintpair, nbttagcompound));
|
|
this.b.add(chunkcoordintpair);
|
|
+ */// Spigot end
|
|
FileIOThread.a.a(this);
|
|
}
|
|
}
|
|
@@ -154,12 +163,20 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
|
|
Object object = this.c;
|
|
|
|
synchronized (this.c) {
|
|
+ // Spigot start
|
|
+ if (this.pendingSaves.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+ pendingchunktosave = this.pendingSaves.values().iterator().next();
|
|
+ this.pendingSaves.remove(pendingchunktosave.a);
|
|
+ /*
|
|
if (this.a.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
pendingchunktosave = (PendingChunkToSave) this.a.remove(0);
|
|
this.b.remove(pendingchunktosave.a);
|
|
+ */// Spigot end
|
|
}
|
|
|
|
if (pendingchunktosave != null) {
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java
|
|
index 90e0636..051cf6d 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkSection.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkSection.java
|
|
@@ -219,7 +219,7 @@ public class ChunkSection {
|
|
}
|
|
|
|
public void a(byte[] abyte) {
|
|
- this.blockIds = abyte;
|
|
+ this.blockIds = validateByteArray(abyte); // Spigot - validate
|
|
}
|
|
|
|
public void a(NibbleArray nibblearray) {
|
|
@@ -236,19 +236,38 @@ public class ChunkSection {
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
-
|
|
- this.extBlockIds = nibblearray;
|
|
+ this.extBlockIds = validateNibbleArray(nibblearray); // Spigot - validate
|
|
}
|
|
|
|
public void b(NibbleArray nibblearray) {
|
|
- this.blockData = nibblearray;
|
|
+ this.blockData = validateNibbleArray(nibblearray); // Spigot - validate
|
|
}
|
|
|
|
public void c(NibbleArray nibblearray) {
|
|
- this.blockLight = nibblearray;
|
|
+ this.blockLight = validateNibbleArray(nibblearray); // Spigot - validate
|
|
}
|
|
|
|
public void d(NibbleArray nibblearray) {
|
|
- this.skyLight = nibblearray;
|
|
+ this.skyLight = validateNibbleArray(nibblearray); // Spigot - validate
|
|
+ }
|
|
+
|
|
+ // Spigot start - validate/correct nibble array
|
|
+ private static final NibbleArray validateNibbleArray(NibbleArray na) {
|
|
+ if ((na != null) && (na.a.length < 2048)) {
|
|
+ NibbleArray newna = new NibbleArray(4096, 4);
|
|
+ System.arraycopy(na.a, 0, newna.a, 0, na.a.length);
|
|
+ na = newna;
|
|
+ }
|
|
+ return na;
|
|
+ }
|
|
+ // Validate/correct byte array
|
|
+ private static final byte[] validateByteArray(byte[] ba) {
|
|
+ if ((ba != null) && (ba.length < 4096)) {
|
|
+ byte[] newba = new byte[4096];
|
|
+ System.arraycopy(ba, 0, newba, 0, ba.length);
|
|
+ ba = newba;
|
|
+ }
|
|
+ return ba;
|
|
}
|
|
+ // Spigot end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java
|
|
index ee775bf..aa8d83f 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityItem.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityItem.java
|
|
@@ -61,6 +61,7 @@ public class EntityItem extends Entity {
|
|
this.lastTick = currentTick;
|
|
// CraftBukkit end
|
|
|
|
+ if (lastTick % 2 == 0) { // Spigot
|
|
this.lastX = this.locX;
|
|
this.lastY = this.locY;
|
|
this.lastZ = this.locZ;
|
|
@@ -99,7 +100,7 @@ public class EntityItem extends Entity {
|
|
if (this.onGround) {
|
|
this.motY *= -0.5D;
|
|
}
|
|
-
|
|
+ } // Spigot
|
|
++this.age;
|
|
if (!this.world.isStatic && this.age >= 6000) {
|
|
// CraftBukkit start
|
|
diff --git a/src/main/java/net/minecraft/server/EntitySquid.java b/src/main/java/net/minecraft/server/EntitySquid.java
|
|
index 30259de..af42142 100644
|
|
--- a/src/main/java/net/minecraft/server/EntitySquid.java
|
|
+++ b/src/main/java/net/minecraft/server/EntitySquid.java
|
|
@@ -63,10 +63,6 @@ public class EntitySquid extends EntityWaterAnimal {
|
|
// CraftBukkit end
|
|
}
|
|
|
|
- public boolean G() {
|
|
- return this.world.a(this.boundingBox.grow(0.0D, -0.6000000238418579D, 0.0D), Material.WATER, (Entity) this);
|
|
- }
|
|
-
|
|
public void c() {
|
|
super.c();
|
|
this.e = this.d;
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
|
|
index aeca924..b3ff786 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
|
|
@@ -839,8 +839,19 @@ public class PlayerConnection extends Connection {
|
|
|
|
this.chat(s, packet3chat.a_());
|
|
|
|
+ // Spigot start
|
|
+ boolean isCounted = true;
|
|
+ if (server.spamGuardExclusions != null) {
|
|
+ for (String excluded : server.spamGuardExclusions) {
|
|
+ if (s.startsWith(excluded)) {
|
|
+ isCounted = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
// This section stays because it is only applicable to packets
|
|
- if (chatSpamField.addAndGet(this, 20) > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.name)) { // CraftBukkit use thread-safe spam
|
|
+ if (isCounted && chatSpamField.addAndGet(this, 20) > 200 && !this.minecraftServer.getPlayerList().isOp(this.player.name)) { // CraftBukkit use thread-safe spam
|
|
+ // Spigot end
|
|
// CraftBukkit start
|
|
if (packet3chat.a_()) {
|
|
Waitable waitable = new Waitable() {
|
|
@@ -963,7 +974,7 @@ public class PlayerConnection extends Connection {
|
|
}
|
|
|
|
try {
|
|
- this.minecraftServer.getLogger().info(event.getPlayer().getName() + " issued server command: " + event.getMessage()); // CraftBukkit
|
|
+ if (server.logCommands) this.minecraftServer.getLogger().info(event.getPlayer().getName() + " issued server command: " + event.getMessage()); // Spigot
|
|
if (this.server.dispatchCommand(event.getPlayer(), event.getMessage().substring(1))) {
|
|
return;
|
|
}
|
|
@@ -1340,8 +1351,9 @@ public class PlayerConnection extends Connection {
|
|
flag = false;
|
|
} else {
|
|
for (i = 0; i < packet130updatesign.lines[j].length(); ++i) {
|
|
- if (SharedConstants.allowedCharacters.indexOf(packet130updatesign.lines[j].charAt(i)) < 0) {
|
|
+ if (!SharedConstants.isAllowedChatCharacter(packet130updatesign.lines[j].charAt(i))) {
|
|
flag = false;
|
|
+ break;
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
|
|
index 585595d..224c57f 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerList.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerList.java
|
|
@@ -303,7 +303,7 @@ public abstract class PlayerList {
|
|
|
|
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, s1);
|
|
} else if (!this.isWhitelisted(s)) {
|
|
- event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, "You are not white-listed on this server!");
|
|
+ event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, cserver.whitelistMessage); // Spigot
|
|
} else {
|
|
String s2 = socketaddress.toString();
|
|
|
|
@@ -1044,7 +1044,13 @@ public abstract class PlayerList {
|
|
|
|
public void r() {
|
|
while (!this.players.isEmpty()) {
|
|
- ((EntityPlayer) this.players.get(0)).playerConnection.disconnect(this.server.server.getShutdownMessage()); // CraftBukkit - add custom shutdown message
|
|
+ // Spigot start
|
|
+ EntityPlayer p = (EntityPlayer) this.players.get(0);
|
|
+ p.playerConnection.disconnect(this.server.server.getShutdownMessage());
|
|
+ if ((!this.players.isEmpty()) && (this.players.get(0) == p)) {
|
|
+ this.players.remove(0); // Prevent shutdown hang if already disconnected
|
|
+ }
|
|
+ // Spigot end
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/ThreadLoginVerifier.java b/src/main/java/net/minecraft/server/ThreadLoginVerifier.java
|
|
index 0686ba0..c185f64 100644
|
|
--- a/src/main/java/net/minecraft/server/ThreadLoginVerifier.java
|
|
+++ b/src/main/java/net/minecraft/server/ThreadLoginVerifier.java
|
|
@@ -28,6 +28,27 @@ class ThreadLoginVerifier extends Thread {
|
|
|
|
public void run() {
|
|
try {
|
|
+ // Spigot start
|
|
+ if (((CraftServer) org.bukkit.Bukkit.getServer()).ipFilter) {
|
|
+ try {
|
|
+ String ip = this.pendingConnection.getSocket().getInetAddress().getHostAddress();
|
|
+ String[] split = ip.split("\\.");
|
|
+ StringBuilder lookup = new StringBuilder();
|
|
+ for (int i = split.length - 1; i >= 0; i--) {
|
|
+ lookup.append(split[i]);
|
|
+ lookup.append(".");
|
|
+ }
|
|
+ if (!ip.contains("127.0.0.1")) {
|
|
+ lookup.append("xbl.spamhaus.org.");
|
|
+ if (java.net.InetAddress.getByName(lookup.toString()) != null) {
|
|
+ pendingConnection.disconnect("Your IP address (" + ip + ") is flagged as unsafe by spamhaus.org/xbl");
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ } catch (Exception ex) {
|
|
+ }
|
|
+ }
|
|
+ // Spigot end
|
|
String s = (new BigInteger(MinecraftEncryption.a(PendingConnection.a(this.pendingConnection), PendingConnection.b(this.pendingConnection).F().getPublic(), PendingConnection.c(this.pendingConnection)))).toString(16);
|
|
URL url = new URL("http://session.minecraft.net/game/checkserver.jsp?user=" + URLEncoder.encode(PendingConnection.d(this.pendingConnection), "UTF-8") + "&serverId=" + URLEncoder.encode(s, "UTF-8"));
|
|
BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(url.openStream()));
|
|
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
|
index 9c39815..67f2560 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -67,14 +67,27 @@ public abstract class World implements IBlockAccess {
|
|
// CraftBukkit start - public, longhashset
|
|
public boolean allowMonsters = true;
|
|
public boolean allowAnimals = true;
|
|
- protected LongHashSet chunkTickList = new LongHashSet();
|
|
+ protected gnu.trove.map.hash.TLongShortHashMap chunkTickList; // Spigot
|
|
public long ticksPerAnimalSpawns;
|
|
public long ticksPerMonsterSpawns;
|
|
// CraftBukkit end
|
|
private int O;
|
|
int[] H;
|
|
public boolean isStatic;
|
|
+ // Spigot start
|
|
|
|
+ public static long chunkToKey(int x, int z) {
|
|
+ long k = ((((long)x) & 0xFFFF0000L) << 16) | ((((long)x) & 0x0000FFFFL) << 0);
|
|
+ k |= ((((long)z) & 0xFFFF0000L) << 32) | ((((long)z) & 0x0000FFFFL) << 16);
|
|
+ return k;
|
|
+ }
|
|
+ public static int keyToX(long k) {
|
|
+ return (int)(((k >> 16) & 0xFFFF0000) | (k & 0x0000FFFF));
|
|
+ }
|
|
+ public static int keyToZ(long k) {
|
|
+ return (int)(((k >> 32) & 0xFFFF0000L) | ((k >> 16) & 0x0000FFFF));
|
|
+ }
|
|
+ // Spigot end
|
|
public BiomeBase getBiome(int i, int j) {
|
|
if (this.isLoaded(i, 0, j)) {
|
|
Chunk chunk = this.getChunkAtWorldCoords(i, j);
|
|
@@ -100,6 +113,7 @@ public abstract class World implements IBlockAccess {
|
|
int lastXAccessed = Integer.MIN_VALUE;
|
|
int lastZAccessed = Integer.MIN_VALUE;
|
|
final Object chunkLock = new Object();
|
|
+ private byte chunkTickRadius;
|
|
|
|
public CraftWorld getWorld() {
|
|
return this.world;
|
|
@@ -112,11 +126,18 @@ public abstract class World implements IBlockAccess {
|
|
// Changed signature
|
|
public World(IDataManager idatamanager, String s, WorldSettings worldsettings, WorldProvider worldprovider, MethodProfiler methodprofiler, IConsoleLogManager iconsolelogmanager, ChunkGenerator gen, org.bukkit.World.Environment env) {
|
|
this.generator = gen;
|
|
+ this.worldData = idatamanager.getWorldData(); // Spigot
|
|
this.world = new CraftWorld((WorldServer) this, gen, env);
|
|
this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit
|
|
this.ticksPerMonsterSpawns = this.getServer().getTicksPerMonsterSpawns(); // CraftBukkit
|
|
+ this.chunkTickRadius = (byte)((this.getServer().getViewDistance() < 7) ? this.getServer().getViewDistance() : 7); // CraftBukkit - don't tick chunks we don't load for player
|
|
// CraftBukkit end
|
|
|
|
+ // Spigot start
|
|
+ chunkTickList = new gnu.trove.map.hash.TLongShortHashMap(world.growthPerTick * 5, 0.7f, Long.MIN_VALUE, Short.MIN_VALUE);
|
|
+ chunkTickList.setAutoCompactionFactor(0);
|
|
+ // Spigot end
|
|
+
|
|
this.O = this.random.nextInt(12000);
|
|
this.H = new int['\u8000'];
|
|
this.isStatic = false;
|
|
@@ -124,7 +145,7 @@ public abstract class World implements IBlockAccess {
|
|
this.methodProfiler = methodprofiler;
|
|
this.worldMaps = new WorldMapCollection(idatamanager);
|
|
this.logAgent = iconsolelogmanager;
|
|
- this.worldData = idatamanager.getWorldData();
|
|
+ // this.worldData = idatamanager.getWorldData(); Moved up
|
|
if (worldprovider != null) {
|
|
this.worldProvider = worldprovider;
|
|
} else if (this.worldData != null && this.worldData.j() != 0) {
|
|
@@ -925,6 +946,47 @@ public abstract class World implements IBlockAccess {
|
|
event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason);
|
|
} else if (entity instanceof EntityItem) {
|
|
event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity);
|
|
+ // Spigot start
|
|
+ ItemStack item = ((EntityItem) entity).getItemStack();
|
|
+ int maxSize = item.getMaxStackSize();
|
|
+ if (item.count < maxSize) {
|
|
+ double radius = this.getWorld().itemMergeRadius;
|
|
+ if (radius > 0) {
|
|
+ List<Entity> entities = this.getEntities(entity, entity.boundingBox.grow(radius, radius, radius));
|
|
+ for (Entity e : entities) {
|
|
+ if (e instanceof EntityItem) {
|
|
+ EntityItem loopItem = (EntityItem) e;
|
|
+ ItemStack loopStack = loopItem.getItemStack();
|
|
+ if (!loopItem.dead && loopStack.id == item.id && loopStack.getData() == item.getData()) {
|
|
+ if (loopStack.tag == null || item.tag == null || !loopStack.tag.equals(item.tag)) {
|
|
+ int toAdd = Math.min(loopStack.count, maxSize - item.count);
|
|
+ item.count += toAdd;
|
|
+ loopStack.count -= toAdd;
|
|
+ if (loopStack.count <= 0) {
|
|
+ loopItem.die();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ } else if (entity instanceof EntityExperienceOrb) {
|
|
+ EntityExperienceOrb xp = (EntityExperienceOrb) entity;
|
|
+ double radius = this.getWorld().expMergeRadius;
|
|
+ if (radius > 0) {
|
|
+ List<Entity> entities = this.getEntities(entity, entity.boundingBox.grow(radius, radius, radius));
|
|
+ for (Entity e : entities) {
|
|
+ if (e instanceof EntityExperienceOrb) {
|
|
+ EntityExperienceOrb loopItem = (EntityExperienceOrb) e;
|
|
+ if (!loopItem.dead) {
|
|
+ xp.value += loopItem.value;
|
|
+ loopItem.die();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Spigot end
|
|
} else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Projectile) {
|
|
// Not all projectiles extend EntityProjectile, so check for Bukkit interface instead
|
|
event = CraftEventFactory.callProjectileLaunchEvent(entity);
|
|
@@ -1017,6 +1079,39 @@ public abstract class World implements IBlockAccess {
|
|
int i1 = MathHelper.floor(axisalignedbb.c);
|
|
int j1 = MathHelper.floor(axisalignedbb.f + 1.0D);
|
|
|
|
+ // Spigot start
|
|
+ int ystart = ((k - 1) < 0) ? 0 : (k - 1);
|
|
+ for (int chunkx = (i >> 4); chunkx <= ((j - 1) >> 4); chunkx++) {
|
|
+ int cx = chunkx << 4;
|
|
+ for (int chunkz = (i1 >> 4); chunkz <= ((j1 - 1) >> 4); chunkz++) {
|
|
+ if (!this.isChunkLoaded(chunkx, chunkz)) {
|
|
+ continue;
|
|
+ }
|
|
+ int cz = chunkz << 4;
|
|
+ Chunk chunk = this.getChunkAt(chunkx, chunkz);
|
|
+ // Compute ranges within chunk
|
|
+ int xstart = (i < cx) ? cx : i;
|
|
+ int xend = (j < (cx + 16)) ? j : (cx + 16);
|
|
+ int zstart = (i1 < cz) ? cz : i1;
|
|
+ int zend = (j1 < (cz + 16)) ? j1 : (cz + 16);
|
|
+ // Loop through blocks within chunk
|
|
+ for (int x = xstart; x < xend; x++) {
|
|
+ for (int z = zstart; z < zend; z++) {
|
|
+ for (int y = ystart; y < l; y++) {
|
|
+ int blkid = chunk.getTypeId(x - cx, y, z - cz);
|
|
+ if (blkid > 0) {
|
|
+ Block block = Block.byId[blkid];
|
|
+
|
|
+ if (block != null) {
|
|
+ block.a(this, x, y, z, axisalignedbb, this.M, entity);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /*
|
|
for (int k1 = i; k1 < j; ++k1) {
|
|
for (int l1 = i1; l1 < j1; ++l1) {
|
|
if (this.isLoaded(k1, 64, l1)) {
|
|
@@ -1030,6 +1125,7 @@ public abstract class World implements IBlockAccess {
|
|
}
|
|
}
|
|
}
|
|
+ */// Spigot end
|
|
|
|
double d0 = 0.25D;
|
|
List list = this.getEntities(entity, axisalignedbb.grow(d0, d0, d0));
|
|
@@ -1942,6 +2038,11 @@ public abstract class World implements IBlockAccess {
|
|
this.worldData.setWeatherDuration(1);
|
|
}
|
|
|
|
+ // Spigot start
|
|
+ public int aggregateTicks = 1;
|
|
+ protected float modifiedOdds = 100F;
|
|
+ public float growthOdds = 100F;
|
|
+
|
|
protected void A() {
|
|
// this.chunkTickList.clear(); // CraftBukkit - removed
|
|
this.methodProfiler.a("buildList");
|
|
@@ -1951,25 +2052,42 @@ public abstract class World implements IBlockAccess {
|
|
int j;
|
|
int k;
|
|
|
|
+ final int optimalChunks = this.getWorld().growthPerTick;
|
|
+
|
|
+ if (optimalChunks <= 0) return;
|
|
+ if (players.size() == 0) return;
|
|
+ // Keep chunks with growth inside of the optimal chunk range
|
|
+ int chunksPerPlayer = Math.min(200, Math.max(1, (int) (((optimalChunks - players.size()) / (double) players.size()) + 0.5)));
|
|
+ int randRange = 3 + chunksPerPlayer / 30;
|
|
+ if (randRange > chunkTickRadius) { // Limit to normal tick radius - including view distance
|
|
+ randRange = chunkTickRadius;
|
|
+ }
|
|
+ // odds of growth happening vs growth happening in vanilla
|
|
+ final float modifiedOdds = Math.max(35, Math.min(100, ((chunksPerPlayer + 1) * 100F) / 15F));
|
|
+ this.modifiedOdds = modifiedOdds;
|
|
+ this.growthOdds = modifiedOdds;
|
|
+
|
|
for (i = 0; i < this.players.size(); ++i) {
|
|
entityhuman = (EntityHuman) this.players.get(i);
|
|
- j = MathHelper.floor(entityhuman.locX / 16.0D);
|
|
- k = MathHelper.floor(entityhuman.locZ / 16.0D);
|
|
- byte b0 = 7;
|
|
-
|
|
- for (int l = -b0; l <= b0; ++l) {
|
|
- for (int i1 = -b0; i1 <= b0; ++i1) {
|
|
- // CraftBukkit start - don't tick chunks queued for unload
|
|
- ChunkProviderServer chunkProviderServer = ((WorldServer) entityhuman.world).chunkProviderServer;
|
|
- if (chunkProviderServer.unloadQueue.contains(l + j, i1 + k)) {
|
|
- continue;
|
|
- }
|
|
- // CraftBukkit end
|
|
-
|
|
- this.chunkTickList.add(org.bukkit.craftbukkit.util.LongHash.toLong(l + j, i1 + k)); // CraftBukkit
|
|
+ int chunkX = MathHelper.floor(entityhuman.locX / 16.0D);
|
|
+ int chunkZ = MathHelper.floor(entityhuman.locZ / 16.0D);
|
|
+
|
|
+ // Always update the chunk the player is on
|
|
+ long key = chunkToKey(chunkX, chunkZ);
|
|
+ int existingPlayers = Math.max(0, chunkTickList.get(key)); //filter out -1's
|
|
+ chunkTickList.put(key, (short) (existingPlayers + 1));
|
|
+
|
|
+ // Check and see if we update the chunks surrounding the player this tick
|
|
+ for (int chunk = 0; chunk < chunksPerPlayer; chunk++) {
|
|
+ int dx = (random.nextBoolean() ? 1 : -1) * random.nextInt(randRange);
|
|
+ int dz = (random.nextBoolean() ? 1 : -1) * random.nextInt(randRange);
|
|
+ long hash = chunkToKey(dx + chunkX, dz + chunkZ);
|
|
+ if (!chunkTickList.contains(hash) && this.isChunkLoaded(dx + chunkX, dz + chunkZ)) {
|
|
+ chunkTickList.put(hash, (short) -1); //no players
|
|
}
|
|
}
|
|
}
|
|
+ // Spigot End
|
|
|
|
this.methodProfiler.b();
|
|
if (this.O > 0) {
|
|
@@ -1977,7 +2095,7 @@ public abstract class World implements IBlockAccess {
|
|
}
|
|
|
|
this.methodProfiler.a("playerCheckLight");
|
|
- if (!this.players.isEmpty()) {
|
|
+ if (!this.players.isEmpty() && this.getWorld().randomLightingUpdates) { // Spigot
|
|
i = this.random.nextInt(this.players.size());
|
|
entityhuman = (EntityHuman) this.players.get(i);
|
|
j = MathHelper.floor(entityhuman.locX) + this.random.nextInt(11) - 5;
|
|
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
|
|
index d99b6a3..34f7bb1 100644
|
|
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
|
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
|
@@ -1,5 +1,7 @@
|
|
package net.minecraft.server;
|
|
|
|
+import gnu.trove.iterator.TLongShortIterator;
|
|
+
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashSet;
|
|
@@ -12,6 +14,7 @@ import java.util.TreeSet;
|
|
// CraftBukkit start
|
|
import org.bukkit.block.BlockState;
|
|
import org.bukkit.craftbukkit.util.LongHash;
|
|
+import org.bukkit.craftbukkit.util.LongObjectHashMap;
|
|
|
|
import org.bukkit.event.block.BlockFormEvent;
|
|
import org.bukkit.event.weather.LightningStrikeEvent;
|
|
@@ -277,15 +280,30 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
|
}
|
|
|
|
protected void g() {
|
|
+ // Spigot start
|
|
+ this.aggregateTicks--;
|
|
+ if (this.aggregateTicks != 0) return;
|
|
+ aggregateTicks = this.getWorld().aggregateTicks;
|
|
+ // Spigot end
|
|
super.g();
|
|
int i = 0;
|
|
int j = 0;
|
|
// CraftBukkit start
|
|
// Iterator iterator = this.chunkTickList.iterator();
|
|
|
|
- for (long chunkCoord : this.chunkTickList.popAll()) {
|
|
- int chunkX = LongHash.msw(chunkCoord);
|
|
- int chunkZ = LongHash.lsw(chunkCoord);
|
|
+ // Spigot start
|
|
+ for (TLongShortIterator iter = chunkTickList.iterator(); iter.hasNext();) {
|
|
+ iter.advance();
|
|
+ long chunkCoord = iter.key();
|
|
+ int chunkX = World.keyToX(chunkCoord);
|
|
+ int chunkZ = World.keyToZ(chunkCoord);
|
|
+ // If unloaded, or in procedd of being unloaded, drop it
|
|
+ if ((!this.isChunkLoaded(chunkX, chunkZ)) || (this.chunkProviderServer.unloadQueue.contains(chunkX, chunkZ))) {
|
|
+ iter.remove();
|
|
+ continue;
|
|
+ }
|
|
+ int players = iter.value();
|
|
+ // Spigot end
|
|
// ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next();
|
|
int k = chunkX * 16;
|
|
int l = chunkZ * 16;
|
|
@@ -383,7 +401,17 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
|
|
|
if (block != null && block.isTicking()) {
|
|
++i;
|
|
- block.a(this, k2 + k, i3 + chunksection.d(), l2 + l, this.random);
|
|
+ // Spigot start
|
|
+ if (players < 1) {
|
|
+ // grow fast if no players are in this chunk
|
|
+ this.growthOdds = modifiedOdds;
|
|
+ } else {
|
|
+ this.growthOdds = 100;
|
|
+ }
|
|
+ for (int c = 0; c < getWorld().aggregateTicks; c++) {
|
|
+ block.a(this, k2 + k, i3 + chunksection.d(), l2 + l, this.random);
|
|
+ }
|
|
+ // Spigot end
|
|
}
|
|
}
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
index 3775022..8f65601 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -146,7 +146,7 @@ public final class CraftServer implements Server {
|
|
protected final MinecraftServer console;
|
|
protected final DedicatedPlayerList playerList;
|
|
private final Map<String, World> worlds = new LinkedHashMap<String, World>();
|
|
- private YamlConfiguration configuration;
|
|
+ protected YamlConfiguration configuration; // Spigot private -> protected
|
|
private final Yaml yaml = new Yaml(new SafeConstructor());
|
|
private final Map<String, OfflinePlayer> offlinePlayers = new MapMaker().softValues().makeMap();
|
|
private final AutoUpdater updater;
|
|
@@ -166,6 +166,14 @@ public final class CraftServer implements Server {
|
|
private final class BooleanWrapper {
|
|
private boolean value = true;
|
|
}
|
|
+ // Spigot start
|
|
+ public String whitelistMessage = "You are not white-listed on this server!";
|
|
+ public String stopMessage = "Server restarting. Brb";
|
|
+ public boolean logCommands = true;
|
|
+ public boolean ipFilter = false;
|
|
+ public boolean commandComplete = true;
|
|
+ public List<String> spamGuardExclusions;
|
|
+ // Spigot end
|
|
|
|
static {
|
|
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
|
|
@@ -208,12 +216,20 @@ public final class CraftServer implements Server {
|
|
chunkGCLoadThresh = configuration.getInt("chunk-gc.load-threshold");
|
|
|
|
updater = new AutoUpdater(new BukkitDLUpdaterService(configuration.getString("auto-updater.host")), getLogger(), configuration.getString("auto-updater.preferred-channel"));
|
|
- updater.setEnabled(configuration.getBoolean("auto-updater.enabled"));
|
|
+ updater.setEnabled(false);
|
|
updater.setSuggestChannels(configuration.getBoolean("auto-updater.suggest-channels"));
|
|
updater.getOnBroken().addAll(configuration.getStringList("auto-updater.on-broken"));
|
|
updater.getOnUpdate().addAll(configuration.getStringList("auto-updater.on-update"));
|
|
updater.check(serverVersion);
|
|
|
|
+ // Spigot start
|
|
+ Spigot.initialize(this, commandMap, configuration);
|
|
+
|
|
+ try {
|
|
+ configuration.save(getConfigFile());
|
|
+ } catch (IOException e) {
|
|
+ }
|
|
+ // Spigot end
|
|
loadPlugins();
|
|
enablePlugins(PluginLoadOrder.STARTUP);
|
|
}
|
|
@@ -222,7 +238,7 @@ public final class CraftServer implements Server {
|
|
return (File) console.options.valueOf("bukkit-settings");
|
|
}
|
|
|
|
- private void saveConfig() {
|
|
+ public void saveConfig() { // Spigot private -> public
|
|
try {
|
|
configuration.save(getConfigFile());
|
|
} catch (IOException ex) {
|
|
@@ -526,6 +542,7 @@ public final class CraftServer implements Server {
|
|
|
|
((DedicatedServer) console).propertyManager = config;
|
|
|
|
+ ((SimplePluginManager) pluginManager).useTimings(configuration.getBoolean("settings.plugin-profiling")); // Spigot
|
|
boolean animals = config.getBoolean("spawn-animals", console.getSpawnAnimals());
|
|
boolean monsters = config.getBoolean("spawn-monsters", console.worlds.get(0).difficulty > 0);
|
|
int difficulty = config.getInt("difficulty", console.worlds.get(0).difficulty);
|
|
@@ -591,6 +608,7 @@ public final class CraftServer implements Server {
|
|
"This plugin is not properly shutting down its async tasks when it is being reloaded. This may cause conflicts with the newly loaded version of the plugin"
|
|
));
|
|
}
|
|
+ Spigot.initialize(this, commandMap, configuration); // Spigot
|
|
loadPlugins();
|
|
enablePlugins(PluginLoadOrder.STARTUP);
|
|
enablePlugins(PluginLoadOrder.POSTWORLD);
|
|
@@ -1039,11 +1057,8 @@ public final class CraftServer implements Server {
|
|
return count;
|
|
}
|
|
|
|
+ // Spigot start
|
|
public OfflinePlayer getOfflinePlayer(String name) {
|
|
- return getOfflinePlayer(name, true);
|
|
- }
|
|
-
|
|
- public OfflinePlayer getOfflinePlayer(String name, boolean search) {
|
|
OfflinePlayer result = getPlayerExact(name);
|
|
String lname = name.toLowerCase();
|
|
|
|
@@ -1051,17 +1066,7 @@ public final class CraftServer implements Server {
|
|
result = offlinePlayers.get(lname);
|
|
|
|
if (result == null) {
|
|
- if (search) {
|
|
- WorldNBTStorage storage = (WorldNBTStorage) console.worlds.get(0).getDataManager();
|
|
- for (String dat : storage.getPlayerDir().list(new DatFileFilter())) {
|
|
- String datName = dat.substring(0, dat.length() - 4);
|
|
- if (datName.equalsIgnoreCase(name)) {
|
|
- name = datName;
|
|
- break;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
+ // Spigot end
|
|
result = new CraftOfflinePlayer(this, name);
|
|
offlinePlayers.put(lname, result);
|
|
}
|
|
@@ -1199,7 +1204,7 @@ public final class CraftServer implements Server {
|
|
Set<OfflinePlayer> players = new HashSet<OfflinePlayer>();
|
|
|
|
for (String file : files) {
|
|
- players.add(getOfflinePlayer(file.substring(0, file.length() - 4), false));
|
|
+ players.add(getOfflinePlayer(file.substring(0, file.length() - 4))); // Spigot
|
|
}
|
|
players.addAll(Arrays.asList(getOnlinePlayers()));
|
|
|
|
@@ -1305,7 +1310,7 @@ public final class CraftServer implements Server {
|
|
public List<String> tabCompleteCommand(Player player, String message) {
|
|
List<String> completions = null;
|
|
try {
|
|
- completions = getCommandMap().tabComplete(player, message.substring(1));
|
|
+ completions = (commandComplete) ? getCommandMap().tabComplete(player, message.substring(1)) : null; // Spigot
|
|
} catch (CommandException ex) {
|
|
player.sendMessage(ChatColor.RED + "An internal error occurred while attempting to tab-complete this command");
|
|
getLogger().log(Level.SEVERE, "Exception when " + player.getName() + " attempted to tab complete " + message, ex);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index 9218f07..fdef910 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -75,7 +75,81 @@ public class CraftWorld implements World {
|
|
if (server.chunkGCPeriod > 0) {
|
|
chunkGCTickCount = rand.nextInt(server.chunkGCPeriod);
|
|
}
|
|
- }
|
|
+ // Spigot Start
|
|
+ org.bukkit.configuration.file.YamlConfiguration configuration = server.configuration;
|
|
+ String name;
|
|
+ if (world.worldData == null || world.worldData.getName() == null) {
|
|
+ name = "default";
|
|
+ } else {
|
|
+ name = world.worldData.getName().replaceAll(" ", "_");
|
|
+ }
|
|
+
|
|
+ //load defaults first
|
|
+ growthPerTick = configuration.getInt("world-settings.default.growth-chunks-per-tick", growthPerTick);
|
|
+ itemMergeRadius = configuration.getDouble("world-settings.default.item-merge-radius", itemMergeRadius);
|
|
+ expMergeRadius = configuration.getDouble("world-settings.default.exp-merge-radius", expMergeRadius);
|
|
+ randomLightingUpdates = configuration.getBoolean("world-settings.default.random-light-updates", randomLightingUpdates);
|
|
+ mobSpawnRange = configuration.getInt("world-settings.default.mob-spawn-range", mobSpawnRange);
|
|
+ aggregateTicks = Math.max(1, configuration.getInt("world-settings.default.aggregate-chunkticks", aggregateTicks));
|
|
+
|
|
+ wheatGrowthModifier = configuration.getInt("world-settings.default.wheat-growth-modifier", wheatGrowthModifier);
|
|
+ cactusGrowthModifier = configuration.getInt("world-settings.default.cactus-growth-modifier", cactusGrowthModifier);
|
|
+ melonGrowthModifier = configuration.getInt("world-settings.default.melon-growth-modifier", melonGrowthModifier);
|
|
+ pumpkinGrowthModifier = configuration.getInt("world-settings.default.pumpkin-growth-modifier", pumpkinGrowthModifier);
|
|
+ sugarGrowthModifier = configuration.getInt("world-settings.default.sugar-growth-modifier", sugarGrowthModifier);
|
|
+ treeGrowthModifier = configuration.getInt("world-settings.default.tree-growth-modifier", treeGrowthModifier);
|
|
+ mushroomGrowthModifier = configuration.getInt("world-settings.default.mushroom-growth-modifier", mushroomGrowthModifier);
|
|
+
|
|
+ //override defaults with world specific, if they exist
|
|
+ growthPerTick = configuration.getInt("world-settings." + name + ".growth-chunks-per-tick", growthPerTick);
|
|
+ itemMergeRadius = configuration.getDouble("world-settings." + name + ".item-merge-radius", itemMergeRadius);
|
|
+ expMergeRadius = configuration.getDouble("world-settings." + name + ".exp-merge-radius", expMergeRadius);
|
|
+ randomLightingUpdates = configuration.getBoolean("world-settings." + name + ".random-light-updates", randomLightingUpdates);
|
|
+ mobSpawnRange = configuration.getInt("world-settings." + name + ".mob-spawn-range", mobSpawnRange);
|
|
+ aggregateTicks = Math.max(1, configuration.getInt("world-settings." + name + ".aggregate-chunkticks", aggregateTicks));
|
|
+
|
|
+ wheatGrowthModifier = configuration.getInt("world-settings." + name + ".wheat-growth-modifier", wheatGrowthModifier);
|
|
+ cactusGrowthModifier = configuration.getInt("world-settings." + name + ".cactus-growth-modifier", cactusGrowthModifier);
|
|
+ melonGrowthModifier = configuration.getInt("world-settings." + name + ".melon-growth-modifier", melonGrowthModifier);
|
|
+ pumpkinGrowthModifier = configuration.getInt("world-settings." + name + ".pumpkin-growth-modifier", pumpkinGrowthModifier);
|
|
+ sugarGrowthModifier = configuration.getInt("world-settings." + name + ".sugar-growth-modifier", sugarGrowthModifier);
|
|
+ treeGrowthModifier = configuration.getInt("world-settings." + name + ".tree-growth-modifier", treeGrowthModifier);
|
|
+ mushroomGrowthModifier = configuration.getInt("world-settings." + name + ".mushroom-growth-modifier", mushroomGrowthModifier);
|
|
+
|
|
+ server.getLogger().info("-------------- Spigot ----------------");
|
|
+ server.getLogger().info("-------- World Settings For [" + name + "] --------");
|
|
+ server.getLogger().info("Growth Per Chunk: " + growthPerTick);
|
|
+ server.getLogger().info("Item Merge Radius: " + itemMergeRadius);
|
|
+ server.getLogger().info("Experience Merge Radius: " + expMergeRadius);
|
|
+ server.getLogger().info("Random Lighting Updates: " + randomLightingUpdates);
|
|
+ server.getLogger().info("Mob Spawn Range: " + mobSpawnRange);
|
|
+ server.getLogger().info("Aggregate Ticks: " + aggregateTicks);
|
|
+ server.getLogger().info("Wheat Growth Modifier: " + wheatGrowthModifier);
|
|
+ server.getLogger().info("Cactus Growth Modifier: " + cactusGrowthModifier);
|
|
+ server.getLogger().info("Melon Growth Modifier: " + melonGrowthModifier);
|
|
+ server.getLogger().info("Pumpkin Growth Modifier: " + pumpkinGrowthModifier);
|
|
+ server.getLogger().info("Sugar Growth Modifier: " + sugarGrowthModifier);
|
|
+ server.getLogger().info("Tree Growth Modifier: " + treeGrowthModifier);
|
|
+ server.getLogger().info("Mushroom Growth Modifier: " + mushroomGrowthModifier);
|
|
+ server.getLogger().info("-------------------------------------------------");
|
|
+ // Spigot end
|
|
+ }
|
|
+ // Spigot Start
|
|
+ public int growthPerTick = 650;
|
|
+ public double itemMergeRadius = 3;
|
|
+ public double expMergeRadius = 3;
|
|
+ public boolean randomLightingUpdates = false;
|
|
+ public int mobSpawnRange = 4;
|
|
+ public int aggregateTicks = 4;
|
|
+ //Crop growth rates:
|
|
+ public int wheatGrowthModifier = 100;
|
|
+ public int cactusGrowthModifier = 100;
|
|
+ public int melonGrowthModifier = 100;
|
|
+ public int pumpkinGrowthModifier = 100;
|
|
+ public int sugarGrowthModifier = 100;
|
|
+ public int treeGrowthModifier = 100;
|
|
+ public int mushroomGrowthModifier = 100;
|
|
+ // Spigot end
|
|
|
|
public Block getBlockAt(int x, int y, int z) {
|
|
return getChunkAt(x >> 4, z >> 4).getBlock(x & 0xF, y & 0xFF, z & 0xF);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Spigot.java b/src/main/java/org/bukkit/craftbukkit/Spigot.java
|
|
new file mode 100644
|
|
index 0000000..4a4f949
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/Spigot.java
|
|
@@ -0,0 +1,20 @@
|
|
+package org.bukkit.craftbukkit;
|
|
+
|
|
+import org.bukkit.command.SimpleCommandMap;
|
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
|
+
|
|
+public class Spigot {
|
|
+
|
|
+ public static void initialize(CraftServer server, SimpleCommandMap commandMap, YamlConfiguration configuration) {
|
|
+ server.whitelistMessage = configuration.getString("settings.whitelist-message", server.whitelistMessage);
|
|
+ server.stopMessage = configuration.getString("settings.stop-message", server.stopMessage);
|
|
+ server.logCommands = configuration.getBoolean("settings.log-commands", true);
|
|
+ server.ipFilter = configuration.getBoolean("settings.filter-unsafe-ips", false);
|
|
+ server.commandComplete = configuration.getBoolean("settings.command-complete", true);
|
|
+ server.spamGuardExclusions = configuration.getStringList("settings.spam-exclusions");
|
|
+
|
|
+ if (server.chunkGCPeriod == 0) {
|
|
+ server.getLogger().severe("[Spigot] You should not disable chunk-gc, unexpected behaviour may occur!");
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
|
|
index 48cf5ba..1d4764c 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
|
|
@@ -40,7 +40,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
|
|
// See if someone already loaded this chunk while we were working on it (API, etc)
|
|
if (queuedChunk.provider.chunks.containsKey(queuedChunk.coords)) {
|
|
// Make sure it isn't queued for unload, we need it
|
|
- queuedChunk.provider.unloadQueue.remove(queuedChunk.coords);
|
|
+ queuedChunk.provider.unloadQueue.remove(x, z);
|
|
return;
|
|
}
|
|
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
index f8dbbee..c79f352 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
@@ -212,10 +212,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
}
|
|
|
|
public void kickPlayer(String message) {
|
|
+ // Spigot start
|
|
+ kickPlayer(message, false);
|
|
+ }
|
|
+
|
|
+ public void kickPlayer(String message, boolean async){
|
|
if (getHandle().playerConnection == null) return;
|
|
+ if (!async && !Bukkit.isPrimaryThread()) throw new IllegalStateException("Cannot kick player from asynchronous thread!"); // Spigot
|
|
|
|
getHandle().playerConnection.disconnect(message == null ? "" : message);
|
|
}
|
|
+ // Spigot end
|
|
|
|
public void setCompassTarget(Location loc) {
|
|
if (getHandle().playerConnection == null) return;
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/FlatMap.java b/src/main/java/org/bukkit/craftbukkit/util/FlatMap.java
|
|
new file mode 100644
|
|
index 0000000..e8a7725
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/FlatMap.java
|
|
@@ -0,0 +1,34 @@
|
|
+package org.bukkit.craftbukkit.util;
|
|
+
|
|
+public class FlatMap<V> {
|
|
+
|
|
+ private static final int FLAT_LOOKUP_SIZE = 512;
|
|
+ private final Object[][] flatLookup = new Object[FLAT_LOOKUP_SIZE * 2][FLAT_LOOKUP_SIZE * 2];
|
|
+
|
|
+ public void put(long msw, long lsw, V value) {
|
|
+ long acx = Math.abs(msw);
|
|
+ long acz = Math.abs(lsw);
|
|
+ if (acx < FLAT_LOOKUP_SIZE && acz < FLAT_LOOKUP_SIZE) {
|
|
+ flatLookup[(int) (msw + FLAT_LOOKUP_SIZE)][(int) (lsw + FLAT_LOOKUP_SIZE)] = value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void put(long key, V value) {
|
|
+ put(LongHash.msw(key), LongHash.lsw(key), value);
|
|
+
|
|
+ }
|
|
+
|
|
+ public V get(long msw, long lsw) {
|
|
+ long acx = Math.abs(msw);
|
|
+ long acz = Math.abs(lsw);
|
|
+ if (acx < FLAT_LOOKUP_SIZE && acz < FLAT_LOOKUP_SIZE) {
|
|
+ return (V) flatLookup[(int) (msw + FLAT_LOOKUP_SIZE)][(int) (lsw + FLAT_LOOKUP_SIZE)];
|
|
+ } else {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public V get(long key) {
|
|
+ return get(LongHash.msw(key), LongHash.lsw(key));
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java b/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java
|
|
index 22c96c5..3f1617d 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/LongHashSet.java
|
|
@@ -31,6 +31,8 @@ public class LongHashSet {
|
|
private int elements;
|
|
private long[] values;
|
|
private int modCount;
|
|
+ private static final Object PRESENT = new Object();
|
|
+ private final FlatMap<Object> flat = new FlatMap<Object>();
|
|
|
|
public LongHashSet() {
|
|
this(INITIAL_SIZE);
|
|
@@ -56,10 +58,11 @@ public class LongHashSet {
|
|
}
|
|
|
|
public boolean contains(int msw, int lsw) {
|
|
+ if (flat.get(msw, lsw) != null) return true; // Spigot
|
|
return contains(LongHash.toLong(msw, lsw));
|
|
}
|
|
|
|
- public boolean contains(long value) {
|
|
+ private boolean contains(long value) { // Spigot
|
|
int hash = hash(value);
|
|
int index = (hash & 0x7FFFFFFF) % values.length;
|
|
int offset = 1;
|
|
@@ -78,10 +81,11 @@ public class LongHashSet {
|
|
}
|
|
|
|
public boolean add(int msw, int lsw) {
|
|
+ flat.put(msw, lsw, PRESENT); // Spigot
|
|
return add(LongHash.toLong(msw, lsw));
|
|
}
|
|
|
|
- public boolean add(long value) {
|
|
+ private boolean add(long value) { // Spigot
|
|
int hash = hash(value);
|
|
int index = (hash & 0x7FFFFFFF) % values.length;
|
|
int offset = 1;
|
|
@@ -125,10 +129,11 @@ public class LongHashSet {
|
|
}
|
|
|
|
public void remove(int msw, int lsw) {
|
|
+ flat.put(msw, lsw, null); // Spigot
|
|
remove(LongHash.toLong(msw, lsw));
|
|
}
|
|
|
|
- public boolean remove(long value) {
|
|
+ private boolean remove(long value) { // Spigot
|
|
int hash = hash(value);
|
|
int index = (hash & 0x7FFFFFFF) % values.length;
|
|
int offset = 1;
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java b/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java
|
|
index 01861cc..dbd33fa 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/LongObjectHashMap.java
|
|
@@ -28,6 +28,7 @@ public class LongObjectHashMap<V> implements Cloneable, Serializable {
|
|
private transient V[][] values;
|
|
private transient int modCount;
|
|
private transient int size;
|
|
+ private final FlatMap<V> flat = new FlatMap<V>(); // Spigot
|
|
|
|
public LongObjectHashMap() {
|
|
initialize();
|
|
@@ -61,6 +62,8 @@ public class LongObjectHashMap<V> implements Cloneable, Serializable {
|
|
}
|
|
|
|
public V get(long key) {
|
|
+ V val = flat.get(key); // Spigot
|
|
+ if (val != null) return val; // Spigot
|
|
int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1));
|
|
long[] inner = keys[index];
|
|
if (inner == null) return null;
|
|
@@ -78,6 +81,7 @@ public class LongObjectHashMap<V> implements Cloneable, Serializable {
|
|
}
|
|
|
|
public V put(long key, V value) {
|
|
+ flat.put(key, value); // Spigot
|
|
int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1));
|
|
long[] innerKeys = keys[index];
|
|
V[] innerValues = values[index];
|
|
@@ -124,6 +128,7 @@ public class LongObjectHashMap<V> implements Cloneable, Serializable {
|
|
}
|
|
|
|
public V remove(long key) {
|
|
+ flat.put(key, null); // Spigot
|
|
int index = (int) (keyIndex(key) & (BUCKET_SIZE - 1));
|
|
long[] inner = keys[index];
|
|
if (inner == null) {
|
|
diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml
|
|
index 61a95e3..f44d5d0 100644
|
|
--- a/src/main/resources/configurations/bukkit.yml
|
|
+++ b/src/main/resources/configurations/bukkit.yml
|
|
@@ -25,6 +25,33 @@ settings:
|
|
query-plugins: true
|
|
deprecated-verbose: default
|
|
shutdown-message: Server closed
|
|
+ filter-unsafe-ips: false
|
|
+ whitelist-message: You are not white-listed on this server!
|
|
+ log-commands: true
|
|
+ command-complete: true
|
|
+ spam-exclusions:
|
|
+ - /skill
|
|
+world-settings:
|
|
+ default:
|
|
+ growth-chunks-per-tick: 650
|
|
+ mob-spawn-range: 4
|
|
+ item-merge-radius: 3.5
|
|
+ exp-merge-radius: 3.5
|
|
+ random-light-updates: false
|
|
+ aggregate-chunkticks: 4
|
|
+ wheat-growth-modifier: 100
|
|
+ cactus-growth-modifier: 100
|
|
+ melon-growth-modifier: 100
|
|
+ pumpkin-growth-modifier: 100
|
|
+ sugar-growth-modifier: 100
|
|
+ tree-growth-modifier: 100
|
|
+ mushroom-growth-modifier: 100
|
|
+ world:
|
|
+ growth-chunks-per-tick: 1000
|
|
+ world_nether:
|
|
+ growth-chunks-per-tick: 0
|
|
+ random-light-updates: true
|
|
+ water-creatures-per-chunk: 0
|
|
spawn-limits:
|
|
monsters: 70
|
|
animals: 15
|
|
--
|
|
1.8.1-rc2
|
|
|