2015-05-25 12:37:24 +02:00
|
|
|
--- a/net/minecraft/server/ChunkRegionLoader.java
|
|
|
|
+++ b/net/minecraft/server/ChunkRegionLoader.java
|
2018-07-15 02:00:00 +02:00
|
|
|
@@ -34,7 +34,7 @@
|
|
|
|
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-07-22 04:00:00 +02:00
|
|
|
@@ -45,20 +45,56 @@
|
|
|
|
private synchronized NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException {
|
|
|
|
NBTTagCompound nbttagcompound = (NBTTagCompound) this.b.get(new ChunkCoordIntPair(i, j));
|
2018-07-15 02:00:00 +02:00
|
|
|
|
2018-07-22 04:00:00 +02:00
|
|
|
- return nbttagcompound != null ? nbttagcompound : this.a(generatoraccess.o().getDimensionManager(), generatoraccess.s_(), i, j);
|
|
|
|
+ return nbttagcompound != null ? nbttagcompound : this.a(generatoraccess.o().getDimensionManager(), generatoraccess.s_(), i, j, generatoraccess); // CraftBukkit
|
|
|
|
+ }
|
|
|
|
+
|
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
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (RegionFileCache.chunkExists(this.c, 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-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 {
|
|
|
|
- DataInputStream datainputstream = RegionFileCache.read(this.c, i, j);
|
|
|
|
+ private NBTTagCompound a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection, int i, int j, @Nullable GeneratorAccess generatoraccess) throws IOException {
|
|
|
|
+ NBTTagCompound nbttagcompound = RegionFileCache.read(this.c, i, j);
|
2018-07-15 02:00:00 +02:00
|
|
|
|
|
|
|
- if (datainputstream == null) {
|
|
|
|
+ if (nbttagcompound == null) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
- NBTTagCompound nbttagcompound = NBTCompressedStreamTools.a(datainputstream);
|
2018-07-22 04:00:00 +02:00
|
|
|
-
|
|
|
|
- datainputstream.close();
|
2018-07-15 02:00:00 +02:00
|
|
|
+ // CraftBukkit end
|
|
|
|
int k = nbttagcompound.hasKeyOfType("DataVersion", 99) ? nbttagcompound.getInt("DataVersion") : -1;
|
2018-07-19 06:19:12 +02:00
|
|
|
+ // CraftBukkit start
|
|
|
|
+ if (k < 1466) {
|
|
|
|
+ NBTTagCompound level = nbttagcompound.getCompound("Level");
|
|
|
|
+ if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) {
|
2018-07-22 04:00:00 +02:00
|
|
|
+ ChunkProviderServer cps = (generatoraccess == null) ? null : ((WorldServer) generatoraccess).getChunkProviderServer();
|
2018-07-19 06:19:12 +02:00
|
|
|
+ if (check(cps, i - 1, j) && check(cps, i - 1, j - 1) && check(cps, i, j - 1)) {
|
|
|
|
+ level.setBoolean("LightPopulated", true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // CraftBukkit end
|
2018-07-15 02:00:00 +02:00
|
|
|
|
|
|
|
if (k < 1493) {
|
2018-07-19 06:19:12 +02:00
|
|
|
nbttagcompound = GameProfileSerializer.a(this.d, DataFixTypes.CHUNK, nbttagcompound, k, 1493);
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -81,13 +117,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-07-15 02:00:00 +02:00
|
|
|
public synchronized Chunk a(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException {
|
|
|
|
+ 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-07-15 02:00:00 +02:00
|
|
|
+ public synchronized 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-07-22 04:00:00 +02:00
|
|
|
@@ -96,6 +148,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-07-22 04:00:00 +02:00
|
|
|
@@ -124,7 +179,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-07-22 04:00:00 +02:00
|
|
|
@@ -143,10 +198,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-07-22 04:00:00 +02:00
|
|
|
@@ -161,7 +234,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-07-22 04:00:00 +02:00
|
|
|
@@ -209,19 +282,30 @@
|
2016-08-27 07:51:54 +02:00
|
|
|
}
|
|
|
|
|
2018-07-15 02:00:00 +02:00
|
|
|
public synchronized boolean a() {
|
2016-08-27 07:51:54 +02:00
|
|
|
- if (this.b.isEmpty()) {
|
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
|
|
|
- if (this.f) {
|
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);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private synchronized boolean processSaveQueueEntry(boolean logCompletion) {
|
2016-08-27 07:51:54 +02:00
|
|
|
+ Iterator<Map.Entry<ChunkCoordIntPair, NBTTagCompound>> iter = this.b.entrySet().iterator();
|
|
|
|
+ if (!iter.hasNext()) {
|
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
|
|
|
+ if (logCompletion) {
|
|
|
|
+ // CraftBukkit end
|
2018-07-15 02:00:00 +02:00
|
|
|
ChunkRegionLoader.a.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.c.getName());
|
2016-08-27 07:51:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
- ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) this.b.keySet().iterator().next();
|
|
|
|
+ // CraftBukkit start
|
|
|
|
+ Map.Entry<ChunkCoordIntPair, NBTTagCompound> entry = iter.next();
|
|
|
|
+ ChunkCoordIntPair chunkcoordintpair = entry.getKey();
|
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
|
|
|
+ NBTTagCompound nbttagcompound = entry.getValue();
|
2016-08-27 07:51:54 +02:00
|
|
|
+ // CraftBukkit end
|
|
|
|
|
|
|
|
boolean flag;
|
|
|
|
|
|
|
|
try {
|
2018-07-15 02:00:00 +02:00
|
|
|
- NBTTagCompound nbttagcompound = (NBTTagCompound) this.b.get(chunkcoordintpair);
|
|
|
|
+ // NBTTagCompound nbttagcompound = (NBTTagCompound) this.b.get(chunkcoordintpair); // CraftBukkit
|
2016-08-27 07:51:54 +02:00
|
|
|
|
|
|
|
if (nbttagcompound != null) {
|
|
|
|
try {
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -233,7 +317,7 @@
|
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
|
|
|
|
|
|
|
flag = true;
|
|
|
|
} finally {
|
2018-07-15 02:00:00 +02:00
|
|
|
- this.b.remove(chunkcoordintpair);
|
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.b.remove(chunkcoordintpair, nbttagcompound); // CraftBukkit
|
|
|
|
}
|
|
|
|
|
|
|
|
return flag;
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -253,10 +337,14 @@
|
2016-06-12 11:28:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void b(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException {
|
2018-07-22 04:00:00 +02:00
|
|
|
- DataOutputStream dataoutputstream = RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z);
|
2016-06-12 11:28:27 +02:00
|
|
|
+ // CraftBukkit start
|
2018-07-22 04:00:00 +02:00
|
|
|
+ RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z, nbttagcompound);
|
2016-06-12 11:28:27 +02:00
|
|
|
|
|
|
|
+ /*
|
|
|
|
NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream);
|
|
|
|
dataoutputstream.close();
|
|
|
|
+ */
|
|
|
|
+ // CraftBukkit end
|
2018-07-15 02:00:00 +02:00
|
|
|
if (this.e != null) {
|
|
|
|
this.e.a(chunkcoordintpair.a());
|
|
|
|
}
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -269,15 +357,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
|
|
|
|
|
|
|
public void c() {
|
|
|
|
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-07-22 04:00:00 +02:00
|
|
|
@@ -306,7 +395,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
|
|
|
|
if (abiomebase != null) {
|
|
|
|
for (int k = 0; k < abiomebase.length; ++k) {
|
|
|
|
- aint[k] = BiomeBase.REGISTRY_ID.a((Object) abiomebase[k]);
|
|
|
|
+ aint[k] = BiomeBase.REGISTRY_ID.a(abiomebase[k]); // CraftBukkit - decompile error
|
|
|
|
}
|
2014-11-25 22:32:16 +01:00
|
|
|
}
|
2015-02-26 23:41:06 +01:00
|
|
|
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -388,7 +477,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) {
|
|
|
|
- aint[i] = BiomeBase.REGISTRY_ID.a((Object) abiomebase[i]);
|
|
|
|
+ aint[i] = BiomeBase.REGISTRY_ID.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-07-22 04:00:00 +02:00
|
|
|
@@ -490,7 +579,7 @@
|
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();
|
|
|
|
};
|
|
|
|
RegistryBlocks registryblocks = Block.REGISTRY;
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -502,7 +591,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
Block.REGISTRY.getClass();
|
|
|
|
ProtoChunkTickList protochunkticklist = new ProtoChunkTickList(predicate, function, registryblocks1::get, new ChunkCoordIntPair(i, j));
|
|
|
|
|
|
|
|
- predicate = (fluidtype) -> {
|
|
|
|
+ Predicate<FluidType> predicate1 = (fluidtype) -> { // CraftBukkit - decompile error
|
|
|
|
return fluidtype == FluidTypes.a;
|
|
|
|
};
|
|
|
|
registryblocks = FluidType.c;
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -510,7 +599,7 @@
|
2018-07-15 02:00:00 +02:00
|
|
|
function = registryblocks::b;
|
|
|
|
registryblocks1 = FluidType.c;
|
|
|
|
FluidType.c.getClass();
|
|
|
|
- ProtoChunkTickList protochunkticklist1 = new ProtoChunkTickList(predicate, function, registryblocks1::get, new ChunkCoordIntPair(i, j));
|
|
|
|
+ ProtoChunkTickList protochunkticklist1 = new ProtoChunkTickList(predicate1, function, registryblocks1::get, new ChunkCoordIntPair(i, j)); // CraftBukkit - decompile error
|
|
|
|
long i1 = nbttagcompound.getLong("InhabitedTime");
|
|
|
|
Chunk chunk = new Chunk(generatoraccess.getMinecraftWorld(), i, j, abiomebase, chunkconverter, protochunkticklist, protochunkticklist1, i1);
|
|
|
|
|
2018-07-22 04:00:00 +02:00
|
|
|
@@ -853,17 +942,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-07-22 04:00:00 +02:00
|
|
|
@@ -877,8 +978,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-07-22 04:00:00 +02:00
|
|
|
@@ -894,7 +1001,7 @@
|
|
|
|
boolean flag = false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
- this.a(dimensionmanager, persistentcollection, chunkcoordintpair.x, chunkcoordintpair.z);
|
|
|
|
+ this.a(dimensionmanager, persistentcollection, chunkcoordintpair.x, chunkcoordintpair.z, null); // CraftBukkit
|
|
|
|
|
|
|
|
while (!this.b.isEmpty()) {
|
|
|
|
this.a();
|