2015-05-25 12:37:24 +02:00
|
|
|
--- a/net/minecraft/server/ChunkRegionLoader.java
|
|
|
|
+++ b/net/minecraft/server/ChunkRegionLoader.java
|
2018-09-10 11:13:03 +02:00
|
|
|
@@ -31,7 +31,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
private final File c;
|
|
|
|
private final DataFixer d;
|
|
|
|
private PersistentStructureLegacy e;
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
- private boolean f;
|
2018-07-15 02:00:00 +02:00
|
|
|
+ // private boolean f; // CraftBukkit
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
public ChunkRegionLoader(File file, DataFixer datafixer) {
|
|
|
|
this.c = file;
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -40,25 +40,64 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
@Nullable
|
|
|
|
private NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException {
|
|
|
|
- return this.a(generatoraccess.o().getDimensionManager(), generatoraccess.h(), i, j);
|
|
|
|
+ return this.a(generatoraccess.o().getDimensionManager(), generatoraccess.h(), i, j, generatoraccess); // CraftBukkit
|
2018-07-22 04:00:00 +02:00
|
|
|
+ }
|
|
|
|
+
|
2018-07-19 06:19:12 +02:00
|
|
|
+ // CraftBukkit start
|
|
|
|
+ private boolean check(ChunkProviderServer cps, int x, int z) throws IOException {
|
2018-07-22 04:00:00 +02:00
|
|
|
+ if (cps != null) {
|
|
|
|
+ com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread");
|
|
|
|
+ if (cps.isLoaded(x, z)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
2018-07-19 06:19:12 +02:00
|
|
|
+ }
|
|
|
|
+
|
2018-09-26 09:19:16 +02:00
|
|
|
+ if (this.chunkExists(x, z)) {
|
2018-07-22 04:00:00 +02:00
|
|
|
+ NBTTagCompound nbt = RegionFileCache.read(this.c, x, z);
|
2018-07-19 06:19:12 +02:00
|
|
|
+ if (nbt != null) {
|
|
|
|
+ NBTTagCompound level = nbt.getCompound("Level");
|
|
|
|
+ if (level.getBoolean("TerrainPopulated")) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ChunkStatus status = ChunkStatus.a(level.getString("Status"));
|
|
|
|
+ if (status != null && status.a(ChunkStatus.DECORATED)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
2018-09-26 09:19:16 +02:00
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public boolean chunkExists(int x, int z) {
|
|
|
|
+ return RegionFileCache.chunkExists(this.c, x, z);
|
2018-07-22 04:00:00 +02:00
|
|
|
}
|
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
@Nullable
|
2018-07-22 04:00:00 +02:00
|
|
|
- private NBTTagCompound a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection, int i, int j) throws IOException {
|
|
|
|
+ private NBTTagCompound a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection, int i, int j, @Nullable GeneratorAccess generatoraccess) throws IOException {
|
2018-08-26 04:00:00 +02:00
|
|
|
NBTTagCompound nbttagcompound = (NBTTagCompound) this.b.get(new ChunkCoordIntPair(i, j));
|
2018-07-15 02:00:00 +02:00
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
if (nbttagcompound != null) {
|
|
|
|
return nbttagcompound;
|
2018-07-15 02:00:00 +02:00
|
|
|
} else {
|
2018-08-26 04:00:00 +02:00
|
|
|
- DataInputStream datainputstream = RegionFileCache.read(this.c, i, j);
|
|
|
|
+ NBTTagCompound nbttagcompound1 = RegionFileCache.read(this.c, i, j);
|
|
|
|
|
|
|
|
- if (datainputstream == null) {
|
|
|
|
+ if (nbttagcompound1 == null) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
- NBTTagCompound nbttagcompound1 = NBTCompressedStreamTools.a(datainputstream);
|
2018-07-22 04:00:00 +02:00
|
|
|
-
|
2018-08-26 04:00:00 +02:00
|
|
|
- datainputstream.close();
|
|
|
|
int k = nbttagcompound1.hasKeyOfType("DataVersion", 99) ? nbttagcompound1.getInt("DataVersion") : -1;
|
|
|
|
+ // CraftBukkit start
|
|
|
|
+ if (k < 1466) {
|
|
|
|
+ NBTTagCompound level = nbttagcompound1.getCompound("Level");
|
|
|
|
+ if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) {
|
|
|
|
+ ChunkProviderServer cps = (generatoraccess == null) ? null : ((WorldServer) generatoraccess).getChunkProviderServer();
|
|
|
|
+ if (check(cps, i - 1, j) && check(cps, i - 1, j - 1) && check(cps, i, j - 1)) {
|
|
|
|
+ level.setBoolean("LightPopulated", true);
|
|
|
|
+ }
|
2018-07-19 06:19:12 +02:00
|
|
|
+ }
|
|
|
|
+ }
|
2018-08-26 04:00:00 +02:00
|
|
|
+ // CraftBukkit end
|
|
|
|
|
|
|
|
if (k < 1493) {
|
|
|
|
nbttagcompound1 = GameProfileSerializer.a(this.d, DataFixTypes.CHUNK, nbttagcompound1, k, 1493);
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -86,13 +125,29 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
|
2014-11-25 22:32:16 +01:00
|
|
|
}
|
2015-02-26 23:41:06 +01:00
|
|
|
|
2014-11-25 22:32:16 +01:00
|
|
|
+ // CraftBukkit start - Add async variant, provide compatibility
|
2016-05-10 13:47:39 +02:00
|
|
|
@Nullable
|
2018-08-26 04:00:00 +02:00
|
|
|
public Chunk a(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException {
|
2018-07-15 02:00:00 +02:00
|
|
|
+ Object[] data = loadChunk(generatoraccess, i, j, consumer);
|
2014-11-25 22:32:16 +01:00
|
|
|
+ if (data != null) {
|
|
|
|
+ Chunk chunk = (Chunk) data[0];
|
|
|
|
+ NBTTagCompound nbttagcompound = (NBTTagCompound) data[1];
|
2018-07-15 02:00:00 +02:00
|
|
|
+ consumer.accept(chunk);
|
|
|
|
+ this.loadEntities(nbttagcompound.getCompound("Level"), chunk);
|
2014-11-25 22:32:16 +01:00
|
|
|
+ return chunk;
|
|
|
|
+ }
|
2015-02-26 23:41:06 +01:00
|
|
|
+
|
2014-11-25 22:32:16 +01:00
|
|
|
+ return null;
|
|
|
|
+ }
|
2015-02-26 23:41:06 +01:00
|
|
|
+
|
2018-08-26 04:00:00 +02:00
|
|
|
+ public Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException {
|
2014-11-25 22:32:16 +01:00
|
|
|
+ // CraftBukkit end
|
2018-07-15 02:00:00 +02:00
|
|
|
NBTTagCompound nbttagcompound = this.a(generatoraccess, i, j);
|
2015-05-05 22:43:47 +02:00
|
|
|
|
2016-06-12 11:28:27 +02:00
|
|
|
if (nbttagcompound == null) {
|
2018-07-15 02:00:00 +02:00
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
+ /*
|
|
|
|
Chunk chunk = this.a(generatoraccess, i, j, nbttagcompound);
|
2016-06-12 11:28:27 +02:00
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
if (chunk != null) {
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -101,6 +156,9 @@
|
2016-06-12 11:28:27 +02:00
|
|
|
}
|
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
return chunk;
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ return this.a(generatoraccess, i, j, nbttagcompound);
|
2016-06-12 11:28:27 +02:00
|
|
|
}
|
2018-07-15 02:00:00 +02:00
|
|
|
}
|
2016-06-12 11:28:27 +02:00
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -132,7 +190,7 @@
|
2014-11-25 22:32:16 +01:00
|
|
|
}
|
|
|
|
|
2016-11-17 02:41:03 +01:00
|
|
|
@Nullable
|
2018-07-15 02:00:00 +02:00
|
|
|
- protected Chunk a(GeneratorAccess generatoraccess, int i, int j, NBTTagCompound nbttagcompound) {
|
|
|
|
+ protected Object[] a(GeneratorAccess generatoraccess, int i, int j, NBTTagCompound nbttagcompound) { // CraftBukkit - return Chunk -> Object[]
|
|
|
|
if (nbttagcompound.hasKeyOfType("Level", 10) && nbttagcompound.getCompound("Level").hasKeyOfType("Status", 8)) {
|
|
|
|
ChunkStatus.Type chunkstatus_type = this.a(nbttagcompound);
|
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -151,10 +209,28 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
ChunkRegionLoader.a.error("Chunk file at {},{} is in the wrong location; relocating. (Expected {}, {}, got {}, {})", Integer.valueOf(i), Integer.valueOf(j), Integer.valueOf(i), Integer.valueOf(j), Integer.valueOf(chunk.locX), Integer.valueOf(chunk.locZ));
|
|
|
|
nbttagcompound1.setInt("xPos", i);
|
|
|
|
nbttagcompound1.setInt("zPos", j);
|
2015-02-26 23:41:06 +01:00
|
|
|
+
|
2018-07-15 02:00:00 +02:00
|
|
|
+ // CraftBukkit start - Have to move tile entities since we don't load them at this stage
|
|
|
|
+ NBTTagList tileEntities = nbttagcompound.getCompound("Level").getList("TileEntities", 10);
|
|
|
|
+ if (tileEntities != null) {
|
|
|
|
+ for (int te = 0; te < tileEntities.size(); te++) {
|
|
|
|
+ NBTTagCompound tileEntity = (NBTTagCompound) tileEntities.get(te);
|
|
|
|
+ int x = tileEntity.getInt("x") - chunk.locX * 16;
|
|
|
|
+ int z = tileEntity.getInt("z") - chunk.locZ * 16;
|
|
|
|
+ tileEntity.setInt("x", i * 16 + x);
|
|
|
|
+ tileEntity.setInt("z", j * 16 + z);
|
|
|
|
+ }
|
2015-02-26 23:41:06 +01:00
|
|
|
+ }
|
2018-07-15 02:00:00 +02:00
|
|
|
+ // CraftBukkit end
|
|
|
|
chunk = this.a(generatoraccess, nbttagcompound1);
|
|
|
|
}
|
|
|
|
|
|
|
|
- return chunk;
|
|
|
|
+ // CraftBukkit start
|
|
|
|
+ Object[] data = new Object[2];
|
|
|
|
+ data[0] = chunk;
|
|
|
|
+ data[1] = nbttagcompound;
|
|
|
|
+ return data;
|
2015-02-26 23:41:06 +01:00
|
|
|
+ // CraftBukkit end
|
|
|
|
}
|
2014-11-25 22:32:16 +01:00
|
|
|
}
|
2018-07-15 02:00:00 +02:00
|
|
|
} else {
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -169,7 +245,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
ChunkStatus.Type chunkstatus_type = this.a(nbttagcompound);
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
if (chunkstatus_type == ChunkStatus.Type.LEVELCHUNK) {
|
|
|
|
- return new ProtoChunkExtension(this.a(generatoraccess, i, j, nbttagcompound));
|
|
|
|
+ return new ProtoChunkExtension((IChunkAccess) this.a(generatoraccess, i, j, nbttagcompound)[0]); // CraftBukkit - fix up access
|
|
|
|
} else {
|
|
|
|
NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Level");
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -217,10 +293,14 @@
|
2016-08-27 07:51:54 +02:00
|
|
|
}
|
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
public boolean a() {
|
|
|
|
- Iterator iterator = this.b.entrySet().iterator();
|
2016-08-27 07:51:54 +02:00
|
|
|
+ // CraftBukkit start
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
+ return this.processSaveQueueEntry(false);
|
|
|
|
+ }
|
2016-08-27 07:51:54 +02:00
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
+ private boolean processSaveQueueEntry(boolean logCompletion) {
|
|
|
|
+ Iterator iterator = this.b.entrySet().iterator();
|
|
|
|
if (!iterator.hasNext()) {
|
|
|
|
- if (this.f) {
|
|
|
|
+ if (logCompletion) { // CraftBukkit
|
|
|
|
ChunkRegionLoader.a.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.c.getName());
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
}
|
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -236,10 +316,14 @@
|
2018-08-26 04:00:00 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
- DataOutputStream dataoutputstream = RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z);
|
|
|
|
+ // CraftBukkit start
|
|
|
|
+ RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z, nbttagcompound);
|
2016-06-12 11:28:27 +02:00
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
+ /*
|
|
|
|
NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream);
|
|
|
|
dataoutputstream.close();
|
|
|
|
+ */
|
|
|
|
+ // CraftBukkit end
|
|
|
|
if (this.e != null) {
|
|
|
|
this.e.a(chunkcoordintpair.a());
|
|
|
|
}
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -266,15 +350,16 @@
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
public void b() {
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
try {
|
|
|
|
- this.f = true;
|
|
|
|
+ // this.f = true; // CraftBukkit
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
- if (this.a()) {
|
|
|
|
+ if (this.processSaveQueueEntry(true)) { // CraftBukkit
|
2016-06-18 13:25:50 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
+ break; // CraftBukkit - Fix infinite loop when saving chunks
|
|
|
|
}
|
|
|
|
} finally {
|
Fix a few chunk saving race conditions
* ChunkRegionLoader.c() picks an entry in the save queue, removes that entry from the save queue and then actually writes the entry to the region file. So, between the last two steps, the entry is neither in the save queue nor is it in the region file; if somebody loads the chunk again (with ChunkRegionLoader.loadChunk()) in that gap, they'll get old data. I've delayed the removal until the saving is done.
* ChunkRegionLoader.c() also records the coords of the chunks it's currently saving in this.c. ChunkRegionLoader.a(ChunkCoordIntPair, NBTTagCompound), which adds an entry to the save queue, stops the addition of an entry if its coords are in this.c. Now, I'm guessing that Mojang's intended purpose for this mechanism was to prevent multiple parallel writes for the same chunk. The "stops the addition" bit above should then be something like "block until it's no longer in c"; in fact, the vanilla implementation is "discard the new state of the chunk". I've taken the easy route to solving this, by just making ChunkRegionLoader.c() synchronized (since, in normal use, only the chunk saving thread is in here).
2017-08-11 09:27:33 +02:00
|
|
|
- this.f = false;
|
|
|
|
+ // this.f = false; // CraftBukkit
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -303,7 +388,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
|
|
|
|
if (abiomebase != null) {
|
|
|
|
for (int k = 0; k < abiomebase.length; ++k) {
|
2018-08-26 04:00:00 +02:00
|
|
|
- aint[k] = IRegistry.BIOME.a((Object) abiomebase[k]);
|
|
|
|
+ aint[k] = IRegistry.BIOME.a(abiomebase[k]); // CraftBukkit - decompile error
|
2018-07-15 02:00:00 +02:00
|
|
|
}
|
2014-11-25 22:32:16 +01:00
|
|
|
}
|
2015-02-26 23:41:06 +01:00
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -385,7 +470,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
int[] aint = new int[abiomebase.length];
|
2014-11-25 22:32:16 +01:00
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
for (int i = 0; i < abiomebase.length; ++i) {
|
2018-08-26 04:00:00 +02:00
|
|
|
- aint[i] = IRegistry.BIOME.a((Object) abiomebase[i]);
|
|
|
|
+ aint[i] = IRegistry.BIOME.a(abiomebase[i]); // CraftBukkit - decompile error
|
2014-11-25 22:32:16 +01:00
|
|
|
}
|
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
nbttagcompound.setIntArray("Biomes", aint);
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -487,27 +572,27 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
}
|
2016-02-29 22:32:46 +01:00
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
ChunkConverter chunkconverter = nbttagcompound.hasKeyOfType("UpgradeData", 10) ? new ChunkConverter(nbttagcompound.getCompound("UpgradeData")) : ChunkConverter.a;
|
|
|
|
- Predicate predicate = (block) -> {
|
|
|
|
+ Predicate<Block> predicate = (block) -> { // CraftBukkit - decompile error
|
|
|
|
return block.getBlockData().isAir();
|
|
|
|
};
|
2018-08-26 04:00:00 +02:00
|
|
|
IRegistry iregistry = IRegistry.BLOCK;
|
|
|
|
|
|
|
|
IRegistry.BLOCK.getClass();
|
|
|
|
Function function = iregistry::getKey;
|
|
|
|
- IRegistry iregistry1 = IRegistry.BLOCK;
|
|
|
|
+ IRegistry<Block> iregistry1 = IRegistry.BLOCK; // CraftBukkit - decompile error
|
|
|
|
|
|
|
|
IRegistry.BLOCK.getClass();
|
|
|
|
- ProtoChunkTickList protochunkticklist = new ProtoChunkTickList(predicate, function, iregistry1::getOrDefault, new ChunkCoordIntPair(i, j));
|
|
|
|
+ ProtoChunkTickList protochunkticklist = new ProtoChunkTickList<>(predicate, function, iregistry1::getOrDefault, new ChunkCoordIntPair(i, j)); // CraftBukkit - decompile error
|
2018-07-15 02:00:00 +02:00
|
|
|
|
|
|
|
- predicate = (fluidtype) -> {
|
|
|
|
+ Predicate<FluidType> predicate1 = (fluidtype) -> { // CraftBukkit - decompile error
|
|
|
|
return fluidtype == FluidTypes.a;
|
|
|
|
};
|
2018-08-26 04:00:00 +02:00
|
|
|
iregistry = IRegistry.FLUID;
|
|
|
|
IRegistry.FLUID.getClass();
|
|
|
|
function = iregistry::getKey;
|
|
|
|
- iregistry1 = IRegistry.FLUID;
|
|
|
|
+ IRegistry<FluidType> iregistry2 = IRegistry.FLUID; // CraftBukkit - decompile error
|
|
|
|
IRegistry.FLUID.getClass();
|
|
|
|
- ProtoChunkTickList protochunkticklist1 = new ProtoChunkTickList(predicate, function, iregistry1::getOrDefault, new ChunkCoordIntPair(i, j));
|
|
|
|
+ ProtoChunkTickList protochunkticklist1 = new ProtoChunkTickList<>(predicate1, function, iregistry2::getOrDefault, new ChunkCoordIntPair(i, j)); // CraftBukkit - decompile error
|
2018-07-15 02:00:00 +02:00
|
|
|
long i1 = nbttagcompound.getLong("InhabitedTime");
|
|
|
|
Chunk chunk = new Chunk(generatoraccess.getMinecraftWorld(), i, j, abiomebase, chunkconverter, protochunkticklist, protochunkticklist1, i1);
|
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -850,17 +935,29 @@
|
2016-06-09 03:43:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
+ // CraftBukkit start
|
|
|
|
public static Entity a(NBTTagCompound nbttagcompound, World world, double d0, double d1, double d2, boolean flag) {
|
|
|
|
+ return spawnEntity(nbttagcompound, world, d0, d1, d2, flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Entity spawnEntity(NBTTagCompound nbttagcompound, World world, double d0, double d1, double d2, boolean flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
|
|
+ // CraftBukkit end
|
2018-07-15 02:00:00 +02:00
|
|
|
return a(nbttagcompound, world, (entity) -> {
|
2016-06-09 03:43:49 +02:00
|
|
|
entity.setPositionRotation(d0, d1, d2, entity.yaw, entity.pitch);
|
2018-07-15 02:00:00 +02:00
|
|
|
- return flag && !world.addEntity(entity) ? null : entity;
|
|
|
|
+ return flag && !world.addEntity(entity, spawnReason) ? null : entity;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
+ // CraftBukkit start
|
|
|
|
public static Entity a(NBTTagCompound nbttagcompound, World world, boolean flag) {
|
|
|
|
+ return spawnEntity(nbttagcompound, world, flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Entity spawnEntity(NBTTagCompound nbttagcompound, World world, boolean flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
|
|
+ // CraftBukkit end
|
|
|
|
return a(nbttagcompound, world, (entity) -> {
|
|
|
|
- return flag && !world.addEntity(entity) ? null : entity;
|
|
|
|
+ return flag && !world.addEntity(entity, spawnReason) ? null : entity; // CraftBukkit
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -874,8 +971,14 @@
|
2016-02-29 22:32:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ // CraftBukkit start
|
2018-07-15 02:00:00 +02:00
|
|
|
public static void a(Entity entity, GeneratorAccess generatoraccess) {
|
|
|
|
- if (generatoraccess.addEntity(entity) && entity.isVehicle()) {
|
|
|
|
+ a(entity, generatoraccess, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
|
2016-02-29 22:32:46 +01:00
|
|
|
+ }
|
|
|
|
+
|
2018-07-15 02:00:00 +02:00
|
|
|
+ public static void a(Entity entity, GeneratorAccess generatoraccess, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
|
|
|
|
+ if (generatoraccess.addEntity(entity, reason) && entity.isVehicle()) {
|
2016-02-29 22:32:46 +01:00
|
|
|
+ // CraftBukkit end
|
2018-07-15 02:00:00 +02:00
|
|
|
Iterator iterator = entity.bP().iterator();
|
2016-02-29 22:32:46 +01:00
|
|
|
|
|
|
|
while (iterator.hasNext()) {
|
2018-09-26 09:19:16 +02:00
|
|
|
@@ -891,7 +994,7 @@
|
2018-07-22 04:00:00 +02:00
|
|
|
boolean flag = false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
- this.a(dimensionmanager, persistentcollection, chunkcoordintpair.x, chunkcoordintpair.z);
|
|
|
|
+ this.a(dimensionmanager, persistentcollection, chunkcoordintpair.x, chunkcoordintpair.z, null); // CraftBukkit
|
|
|
|
|
2018-08-26 04:00:00 +02:00
|
|
|
while (this.a()) {
|
|
|
|
flag = true;
|