mirror of
https://github.com/PaperMC/Folia.git
synced 2024-11-21 11:55:11 +01:00
Make raids thread-safe
We don't need to worry about synchronisation for saving data, as that is currently only done by the shutdown thread - after all regions stop ticking.
This commit is contained in:
parent
36675a1b9f
commit
30d90b4700
@ -4078,10 +4078,10 @@ index 0000000000000000000000000000000000000000..3549e5f3359f38b207e189d895954420
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionisedServer.java b/src/main/java/io/papermc/paper/threadedregions/RegionisedServer.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..16b51ae5bec72f6c85adca3a350f654754990ad0
|
||||
index 0000000000000000000000000000000000000000..269c051e20cd07e692c624a873e4ee2b5ae5589a
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/threadedregions/RegionisedServer.java
|
||||
@@ -0,0 +1,359 @@
|
||||
@@ -0,0 +1,366 @@
|
||||
+package io.papermc.paper.threadedregions;
|
||||
+
|
||||
+import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
|
||||
@ -4403,6 +4403,9 @@ index 0000000000000000000000000000000000000000..16b51ae5bec72f6c85adca3a350f6547
|
||||
+ // sleep status
|
||||
+ this.checkNightSkip(world);
|
||||
+
|
||||
+ // update raids
|
||||
+ this.updateRaids(world);
|
||||
+
|
||||
+ // sky brightness
|
||||
+ this.updateSkyBrightness(world);
|
||||
+
|
||||
@ -4412,6 +4415,10 @@ index 0000000000000000000000000000000000000000..16b51ae5bec72f6c85adca3a350f6547
|
||||
+ world.updateTickData();
|
||||
+ }
|
||||
+
|
||||
+ private void updateRaids(final ServerLevel world) {
|
||||
+ world.getRaids().globalTick();
|
||||
+ }
|
||||
+
|
||||
+ private void checkNightSkip(final ServerLevel world) {
|
||||
+ world.tickSleep();
|
||||
+ }
|
||||
@ -13474,7 +13481,7 @@ index 736f37979c882e41e7571202df38eb6a2923fcb0..06ad3857f04ec073ae753b6569c5ae2c
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 714637cdd9dcdbffa344b19e77944fb3c7541ff7..c05c5fca6aaec891519435a45a39b355fe8369c6 100644
|
||||
index 714637cdd9dcdbffa344b19e77944fb3c7541ff7..61fd4eea649fab254b3b2c0f160257e01d0873ed 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -192,35 +192,34 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@ -13809,7 +13816,7 @@ index 714637cdd9dcdbffa344b19e77944fb3c7541ff7..c05c5fca6aaec891519435a45a39b355
|
||||
public void setWeatherParameters(int clearDuration, int rainDuration, boolean raining, boolean thundering) {
|
||||
this.serverLevelData.setClearWeatherTime(clearDuration);
|
||||
this.serverLevelData.setRainTime(rainDuration);
|
||||
@@ -666,62 +664,38 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
@@ -666,55 +664,31 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return this.structureManager;
|
||||
}
|
||||
|
||||
@ -13877,14 +13884,6 @@ index 714637cdd9dcdbffa344b19e77944fb3c7541ff7..c05c5fca6aaec891519435a45a39b355
|
||||
gameprofilerfiller.pop();
|
||||
}
|
||||
timings.scheduledBlocks.stopTiming(); // Paper
|
||||
|
||||
gameprofilerfiller.popPush("raid");
|
||||
this.timings.raids.startTiming(); // Paper - timings
|
||||
- this.raids.tick();
|
||||
+ if (region == null) this.raids.tick(); // Folia - region threading - TODO fucking RAIDS
|
||||
this.timings.raids.stopTiming(); // Paper - timings
|
||||
gameprofilerfiller.popPush("chunkSource");
|
||||
this.timings.chunkProviderTick.startTiming(); // Paper - timings
|
||||
@@ -731,7 +705,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
timings.doSounds.startTiming(); // Spigot
|
||||
this.runBlockEvents();
|
||||
@ -17717,6 +17716,21 @@ index 25503678e7d049a8b3172cfad8a5606958c32302..13d60258c6c491a7d0ba5cc93934f0c9
|
||||
}
|
||||
|
||||
private static class TurtleMoveControl extends MoveControl {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
index 428523feaa4f30260e32ba03937e88200246c693..5722f1dd949c8ef59379bf4499ec2d77a40df847 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -290,8 +290,10 @@ public class ItemFrame extends HangingEntity {
|
||||
MapItemSavedData worldmap = MapItem.getSavedData(i, this.level);
|
||||
|
||||
if (worldmap != null) {
|
||||
+ synchronized (worldmap) { // Folia - make map data thread-safe
|
||||
worldmap.removedFromFrame(this.pos, this.getId());
|
||||
worldmap.setDirty(true);
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
index eacb8a407fe99af2c13f23c12b5544696bda8890..723d5f44c59a8073040669549d9cab88b45e9a3e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@ -18306,10 +18320,32 @@ index f224ebbc0efefddede43d87f0300c014077b9931..2627610b77e779722bb33eeb1096d862
|
||||
@Override
|
||||
public Entity changeDimension(ServerLevel destination) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java
|
||||
index 08b18428e867baf14f551beb72e3875b0c420639..7ee273a8a7fa72fcdea925be5fa0dd626dc54b71 100644
|
||||
index 08b18428e867baf14f551beb72e3875b0c420639..8a082a24f4aba759826f56aa13d4095ef6914d13 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raid.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java
|
||||
@@ -527,7 +527,7 @@ public class Raid {
|
||||
@@ -108,6 +108,12 @@ public class Raid {
|
||||
private int celebrationTicks;
|
||||
private Optional<BlockPos> waveSpawnPos;
|
||||
|
||||
+ // Folia start - make raids thread-safe
|
||||
+ public boolean ownsRaid() {
|
||||
+ return io.papermc.paper.util.TickThread.isTickThreadFor(this.level, this.getCenter().getX() >> 4, this.getCenter().getZ() >> 4, 8);
|
||||
+ }
|
||||
+ // Folia end - make raids thread-safe
|
||||
+
|
||||
public Raid(int id, ServerLevel world, BlockPos pos) {
|
||||
this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10);
|
||||
this.random = RandomSource.create();
|
||||
@@ -213,7 +219,7 @@ public class Raid {
|
||||
return (entityplayer) -> {
|
||||
BlockPos blockposition = entityplayer.blockPosition();
|
||||
|
||||
- return entityplayer.isAlive() && this.level.getRaidAt(blockposition) == this;
|
||||
+ return io.papermc.paper.util.TickThread.isTickThreadFor(entityplayer) && entityplayer.isAlive() && this.level.getRaidAt(blockposition) == this; // Folia - make raids thread-safe
|
||||
};
|
||||
}
|
||||
|
||||
@@ -527,7 +533,7 @@ public class Raid {
|
||||
boolean flag = true;
|
||||
Collection<ServerPlayer> collection = this.raidEvent.getPlayers();
|
||||
long i = this.random.nextLong();
|
||||
@ -18331,6 +18367,125 @@ index e5ccbaf72f29731f1d1aa939b9297b644a408cd4..1792655d2f0357b388b3c83886cac4bc
|
||||
Raid raid1 = ((ServerLevel) this.level).getRaidAt(this.blockPosition());
|
||||
|
||||
if (raid1 != null && Raids.canJoinRaid(this, raid1)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raids.java b/src/main/java/net/minecraft/world/entity/raid/Raids.java
|
||||
index feb89eb69994bdd1d2f95d2b9992e69251b2bee7..d85dbc87e23ae34a8e3345dc72147979e280a5d3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raids.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raids.java
|
||||
@@ -28,14 +28,14 @@ import net.minecraft.world.phys.Vec3;
|
||||
public class Raids extends SavedData {
|
||||
|
||||
private static final String RAID_FILE_ID = "raids";
|
||||
- public final Map<Integer, Raid> raidMap = Maps.newHashMap();
|
||||
+ public final Map<Integer, Raid> raidMap = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - make raids thread-safe
|
||||
private final ServerLevel level;
|
||||
- private int nextAvailableID;
|
||||
+ private final java.util.concurrent.atomic.AtomicInteger nextAvailableID = new java.util.concurrent.atomic.AtomicInteger(); // Folia - make raids thread-safe
|
||||
private int tick;
|
||||
|
||||
public Raids(ServerLevel world) {
|
||||
this.level = world;
|
||||
- this.nextAvailableID = 1;
|
||||
+ this.nextAvailableID.set(1); // Folia - make raids thread-safe
|
||||
this.setDirty();
|
||||
}
|
||||
|
||||
@@ -43,12 +43,26 @@ public class Raids extends SavedData {
|
||||
return (Raid) this.raidMap.get(id);
|
||||
}
|
||||
|
||||
- public void tick() {
|
||||
+ // Folia start - make raids thread-safe
|
||||
+ public void globalTick() {
|
||||
++this.tick;
|
||||
+ if (this.tick % 200 == 0) {
|
||||
+ this.setDirty();
|
||||
+ }
|
||||
+ }
|
||||
+ // Folia end - make raids thread-safe
|
||||
+
|
||||
+ public void tick() {
|
||||
+ // Folia - make raids thread-safe - move to globalTick()
|
||||
Iterator iterator = this.raidMap.values().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Raid raid = (Raid) iterator.next();
|
||||
+ // Folia start - make raids thread-safe
|
||||
+ if (!raid.ownsRaid()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Folia end - make raids thread-safe
|
||||
|
||||
if (this.level.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) {
|
||||
raid.stop();
|
||||
@@ -62,14 +76,17 @@ public class Raids extends SavedData {
|
||||
}
|
||||
}
|
||||
|
||||
- if (this.tick % 200 == 0) {
|
||||
- this.setDirty();
|
||||
- }
|
||||
+ // Folia - make raids thread-safe - move to globalTick()
|
||||
|
||||
DebugPackets.sendRaids(this.level, this.raidMap.values());
|
||||
}
|
||||
|
||||
public static boolean canJoinRaid(Raider raider, Raid raid) {
|
||||
+ // Folia start - make raids thread-safe
|
||||
+ if (!raid.ownsRaid()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Folia end - make raids thread-safe
|
||||
return raider != null && raid != null && raid.getLevel() != null ? raider.isAlive() && raider.canJoinRaid() && raider.getNoActionTime() <= 2400 && raider.level.dimensionType() == raid.getLevel().dimensionType() : false;
|
||||
}
|
||||
|
||||
@@ -82,7 +99,7 @@ public class Raids extends SavedData {
|
||||
} else {
|
||||
DimensionType dimensionmanager = player.level.dimensionType();
|
||||
|
||||
- if (!dimensionmanager.hasRaids()) {
|
||||
+ if (!dimensionmanager.hasRaids() || !io.papermc.paper.util.TickThread.isTickThreadFor(this.level, player.chunkPosition().x, player.chunkPosition().z, 8)) { // Folia - region threading
|
||||
return null;
|
||||
} else {
|
||||
BlockPos blockposition = player.blockPosition();
|
||||
@@ -162,7 +179,7 @@ public class Raids extends SavedData {
|
||||
public static Raids load(ServerLevel world, CompoundTag nbt) {
|
||||
Raids persistentraid = new Raids(world);
|
||||
|
||||
- persistentraid.nextAvailableID = nbt.getInt("NextAvailableID");
|
||||
+ persistentraid.nextAvailableID.set(nbt.getInt("NextAvailableID")); // Folia - make raids thread-safe
|
||||
persistentraid.tick = nbt.getInt("Tick");
|
||||
ListTag nbttaglist = nbt.getList("Raids", 10);
|
||||
|
||||
@@ -178,7 +195,7 @@ public class Raids extends SavedData {
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
- nbt.putInt("NextAvailableID", this.nextAvailableID);
|
||||
+ nbt.putInt("NextAvailableID", this.nextAvailableID.get()); // Folia - make raids thread-safe
|
||||
nbt.putInt("Tick", this.tick);
|
||||
ListTag nbttaglist = new ListTag();
|
||||
Iterator iterator = this.raidMap.values().iterator();
|
||||
@@ -200,7 +217,7 @@ public class Raids extends SavedData {
|
||||
}
|
||||
|
||||
private int getUniqueId() {
|
||||
- return ++this.nextAvailableID;
|
||||
+ return this.nextAvailableID.incrementAndGet(); // Folia - make raids thread-safe
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -211,6 +228,11 @@ public class Raids extends SavedData {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Raid raid1 = (Raid) iterator.next();
|
||||
+ // Folia start - make raids thread-safe
|
||||
+ if (!io.papermc.paper.util.TickThread.isTickThreadFor(this.level, raid1.getCenter())) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Folia end - make raids thread-safe
|
||||
double d1 = raid1.getCenter().distSqr(pos);
|
||||
|
||||
if (raid1.isActive() && d1 < d0) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
index 70f1916185b79bbb9f033f4ef8119d7b17a13ef8..54d55e8827f4ab286fca722f199aac42cddab8d2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
@ -18458,6 +18613,70 @@ index 6860096cb8c0deecc9c1d87543d1128fb95fd2d4..00cc67322d7de29c30b54aa7da62cc44
|
||||
// CraftBukkit end
|
||||
|
||||
return enuminteractionresult;
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
index 586852e347cfeb6e52d16e51b3f193e814036e81..eacd5b6f649a59f845cc8d9d9373d41ed3757c97 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -103,6 +103,7 @@ public class MapItem extends ComplexItem {
|
||||
}
|
||||
|
||||
public void update(Level world, Entity entity, MapItemSavedData state) {
|
||||
+ synchronized (state) { // Folia - make map data thread-safe
|
||||
if (world.dimension() == state.dimension && entity instanceof Player) {
|
||||
int i = 1 << state.scale;
|
||||
int j = state.centerX;
|
||||
@@ -134,9 +135,9 @@ public class MapItem extends ComplexItem {
|
||||
int j2 = (j / i + k1 - 64) * i;
|
||||
int k2 = (k / i + l1 - 64) * i;
|
||||
Multiset<MaterialColor> multiset = LinkedHashMultiset.create();
|
||||
- LevelChunk chunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2)); // Paper - Maps shouldn't load chunks
|
||||
+ LevelChunk chunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2)); // Paper - Maps shouldn't load chunks // Folia - super important this remains true
|
||||
|
||||
- if (chunk != null && !chunk.isEmpty()) { // Paper - Maps shouldn't load chunks
|
||||
+ if (chunk != null && !chunk.isEmpty() && io.papermc.paper.util.TickThread.isTickThreadFor((ServerLevel)world, chunk.getPos())) { // Paper - Maps shouldn't load chunks // Folia - make sure chunk is owned
|
||||
int l2 = 0;
|
||||
double d1 = 0.0D;
|
||||
int i3;
|
||||
@@ -227,6 +228,7 @@ public class MapItem extends ComplexItem {
|
||||
}
|
||||
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
private BlockState getCorrectStateForFluidBlock(Level world, BlockState state, BlockPos pos) {
|
||||
@@ -243,6 +245,7 @@ public class MapItem extends ComplexItem {
|
||||
MapItemSavedData worldmap = MapItem.getSavedData(map, world);
|
||||
|
||||
if (worldmap != null) {
|
||||
+ synchronized (worldmap) { // Folia - make map data thread-safe
|
||||
if (world.dimension() == worldmap.dimension) {
|
||||
int i = 1 << worldmap.scale;
|
||||
int j = worldmap.centerX;
|
||||
@@ -317,6 +320,7 @@ public class MapItem extends ComplexItem {
|
||||
}
|
||||
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +330,7 @@ public class MapItem extends ComplexItem {
|
||||
MapItemSavedData worldmap = MapItem.getSavedData(stack, world);
|
||||
|
||||
if (worldmap != null) {
|
||||
+ synchronized (worldmap) { // Folia - region threading
|
||||
if (entity instanceof Player) {
|
||||
Player entityhuman = (Player) entity;
|
||||
|
||||
@@ -335,6 +340,7 @@ public class MapItem extends ComplexItem {
|
||||
if (!worldmap.locked && (selected || entity instanceof Player && ((Player) entity).getOffhandItem() == stack)) {
|
||||
this.update(world, entity, worldmap);
|
||||
}
|
||||
+ } // Folia - region threading
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java
|
||||
index c6d2f764efa9b8bec730bbe757d480e365b25ccc..af9313a3b3aaa0af4f2a2f4fb2424dc3e9140d9c 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MinecartItem.java
|
||||
@ -20737,11 +20956,100 @@ index b1c594dc6a6b8a6c737b99272acab9e7dbd0ed63..7c1768452fa0f7278ccc84470ef0965a
|
||||
boolean bl = this.count > 0;
|
||||
boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates;
|
||||
++this.count;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
index c8cdcf40e45f5c6270f9b124f0333643266e2858..b370ba924b03cc0a36666ee6ed26be06a6affaa7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
@@ -10,7 +10,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public abstract class SavedData {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private boolean dirty;
|
||||
+ private volatile boolean dirty; // Folia - make map data thread-safe
|
||||
|
||||
public abstract CompoundTag save(CompoundTag nbt);
|
||||
|
||||
@@ -28,6 +28,7 @@ public abstract class SavedData {
|
||||
|
||||
public void save(File file) {
|
||||
if (this.isDirty()) {
|
||||
+ this.setDirty(false); // Folia - make map data thread-safe - move before save, so that any changes after are not lost
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.put("data", this.save(new CompoundTag()));
|
||||
compoundTag.putInt("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion());
|
||||
@@ -38,7 +39,7 @@ public abstract class SavedData {
|
||||
LOGGER.error("Could not save data {}", this, var4);
|
||||
}
|
||||
|
||||
- this.setDirty(false);
|
||||
+ // Folia - make map data thread-safe - move before save, so that any changes after are not lost
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
index 9b2948b5150c8f039ca667a50765109721b93947..1b76e4edce628f2b25815e28cd4cb7504a83a00f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
@@ -27,17 +27,21 @@ public class MapIndex extends SavedData {
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
+ synchronized (this.usedAuxIds) { // Folia - make map data thread-safe
|
||||
for(Object2IntMap.Entry<String> entry : this.usedAuxIds.object2IntEntrySet()) {
|
||||
nbt.putInt(entry.getKey(), entry.getIntValue());
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public int getFreeAuxValueForMap() {
|
||||
+ synchronized (this.usedAuxIds) { // Folia - make map data thread-safe
|
||||
int i = this.usedAuxIds.getInt("map") + 1;
|
||||
this.usedAuxIds.put("map", i);
|
||||
this.setDirty();
|
||||
return i;
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
index b2845ed8d28627178589da3d2224cd9edd29c31e..9df7c7e44e9a75187bd1e3e8f7e6bc5d385b0733 100644
|
||||
index b2845ed8d28627178589da3d2224cd9edd29c31e..5121569f389ee4a50273432a9a272a936542fa12 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
@@ -368,7 +368,7 @@ public class MapItemSavedData extends SavedData {
|
||||
@@ -185,7 +185,7 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public CompoundTag save(CompoundTag nbt) {
|
||||
+ public synchronized CompoundTag save(CompoundTag nbt) { // Folia - make map data thread-safe
|
||||
DataResult<Tag> dataresult = ResourceLocation.CODEC.encodeStart(NbtOps.INSTANCE, this.dimension.location()); // CraftBukkit - decompile error
|
||||
Logger logger = MapItemSavedData.LOGGER;
|
||||
|
||||
@@ -242,7 +242,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return nbt;
|
||||
}
|
||||
|
||||
- public MapItemSavedData locked() {
|
||||
+ public synchronized MapItemSavedData locked() { // Folia - make map data thread-safe
|
||||
MapItemSavedData worldmap = new MapItemSavedData(this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension);
|
||||
|
||||
worldmap.bannerMarkers.putAll(this.bannerMarkers);
|
||||
@@ -253,11 +253,12 @@ public class MapItemSavedData extends SavedData {
|
||||
return worldmap;
|
||||
}
|
||||
|
||||
- public MapItemSavedData scaled(int zoomOutScale) {
|
||||
+ public synchronized MapItemSavedData scaled(int zoomOutScale) { // Folia - make map data thread-safe
|
||||
return MapItemSavedData.createFresh((double) this.centerX, (double) this.centerZ, (byte) Mth.clamp(this.scale + zoomOutScale, (int) 0, (int) 4), this.trackingPosition, this.unlimitedTracking, this.dimension);
|
||||
}
|
||||
|
||||
- public void tickCarriedBy(Player player, ItemStack stack) {
|
||||
+ public synchronized void tickCarriedBy(Player player, ItemStack stack) { // Folia - make map data thread-safe
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread(player, "Ticking map player in incorrect region"); // Folia - region threading
|
||||
if (!this.carriedByPlayers.containsKey(player)) {
|
||||
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player);
|
||||
|
||||
@@ -368,7 +369,7 @@ public class MapItemSavedData extends SavedData {
|
||||
rotation += rotation < 0.0D ? -8.0D : 8.0D;
|
||||
b2 = (byte) ((int) (rotation * 16.0D / 360.0D));
|
||||
if (this.dimension == Level.NETHER && world != null) {
|
||||
@ -20750,6 +21058,168 @@ index b2845ed8d28627178589da3d2224cd9edd29c31e..9df7c7e44e9a75187bd1e3e8f7e6bc5d
|
||||
|
||||
b2 = (byte) (j * j * 34187121 + j * 121 >> 15 & 15);
|
||||
}
|
||||
@@ -427,14 +428,14 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- public Packet<?> getUpdatePacket(int id, Player player) {
|
||||
+ public synchronized Packet<?> getUpdatePacket(int id, Player player) { // Folia - make map data thread-safe
|
||||
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player);
|
||||
|
||||
return worldmap_worldmaphumantracker == null ? null : worldmap_worldmaphumantracker.nextUpdatePacket(id);
|
||||
}
|
||||
|
||||
- public void setColorsDirty(int x, int z) {
|
||||
- this.setDirty();
|
||||
+ public synchronized void setColorsDirty(int x, int z) { // Folia - make map data thread-safe
|
||||
+ // Folia - make dirty only after updating data - moved down
|
||||
Iterator iterator = this.carriedBy.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -442,15 +443,16 @@ public class MapItemSavedData extends SavedData {
|
||||
|
||||
worldmap_worldmaphumantracker.markColorsDirty(x, z);
|
||||
}
|
||||
-
|
||||
+ this.setDirty(); // Folia - make dirty only after updating data - moved from above
|
||||
}
|
||||
|
||||
- public void setDecorationsDirty() {
|
||||
- this.setDirty();
|
||||
+ public synchronized void setDecorationsDirty() { // Folia - make map data thread-safe
|
||||
+ // Folia - make dirty only after updating data - moved down
|
||||
this.carriedBy.forEach(MapItemSavedData.HoldingPlayer::markDecorationsDirty);
|
||||
+ this.setDirty(); // Folia - make dirty only after updating data - moved from above
|
||||
}
|
||||
|
||||
- public MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) {
|
||||
+ public synchronized MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) { // Folia - make map data thread-safe
|
||||
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player);
|
||||
|
||||
if (worldmap_worldmaphumantracker == null) {
|
||||
@@ -462,7 +464,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return worldmap_worldmaphumantracker;
|
||||
}
|
||||
|
||||
- public boolean toggleBanner(LevelAccessor world, BlockPos pos) {
|
||||
+ public synchronized boolean toggleBanner(LevelAccessor world, BlockPos pos) { // Folia - make map data thread-safe
|
||||
double d0 = (double) pos.getX() + 0.5D;
|
||||
double d1 = (double) pos.getZ() + 0.5D;
|
||||
int i = 1 << this.scale;
|
||||
@@ -471,7 +473,7 @@ public class MapItemSavedData extends SavedData {
|
||||
boolean flag = true;
|
||||
|
||||
if (d2 >= -63.0D && d3 >= -63.0D && d2 <= 63.0D && d3 <= 63.0D) {
|
||||
- MapBanner mapiconbanner = MapBanner.fromWorld(world, pos);
|
||||
+ MapBanner mapiconbanner = world.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null || !io.papermc.paper.util.TickThread.isTickThreadFor(world.getMinecraftWorld(), pos) ? null : MapBanner.fromWorld(world, pos); // Folia - make map data thread-safe - don't sync load or read data we do not own
|
||||
|
||||
if (mapiconbanner == null) {
|
||||
return false;
|
||||
@@ -492,7 +494,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return false;
|
||||
}
|
||||
|
||||
- public void checkBanners(BlockGetter world, int x, int z) {
|
||||
+ public synchronized void checkBanners(BlockGetter world, int x, int z) { // Folia - make map data thread-safe
|
||||
Iterator iterator = this.bannerMarkers.values().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -514,12 +516,12 @@ public class MapItemSavedData extends SavedData {
|
||||
return this.bannerMarkers.values();
|
||||
}
|
||||
|
||||
- public void removedFromFrame(BlockPos pos, int id) {
|
||||
+ public synchronized void removedFromFrame(BlockPos pos, int id) { // Folia - make map data thread-safe
|
||||
this.removeDecoration("frame-" + id);
|
||||
this.frameMarkers.remove(MapFrame.frameId(pos));
|
||||
}
|
||||
|
||||
- public boolean updateColor(int x, int z, byte color) {
|
||||
+ public synchronized boolean updateColor(int x, int z, byte color) { // Folia - make map data thread-safe
|
||||
byte b1 = this.colors[x + z * 128];
|
||||
|
||||
if (b1 != color) {
|
||||
@@ -530,12 +532,12 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
}
|
||||
|
||||
- public void setColor(int x, int z, byte color) {
|
||||
+ public synchronized void setColor(int x, int z, byte color) { // Folia - make map data thread-safe
|
||||
this.colors[x + z * 128] = color;
|
||||
this.setColorsDirty(x, z);
|
||||
}
|
||||
|
||||
- public boolean isExplorationMap() {
|
||||
+ public synchronized boolean isExplorationMap() { // Folia - make map data thread-safe
|
||||
Iterator iterator = this.decorations.values().iterator();
|
||||
|
||||
MapDecoration mapicon;
|
||||
@@ -570,7 +572,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return this.decorations.values();
|
||||
}
|
||||
|
||||
- public boolean isTrackedCountOverLimit(int iconCount) {
|
||||
+ public synchronized boolean isTrackedCountOverLimit(int iconCount) { // Folia - make map data thread-safe
|
||||
return this.trackedDecorationCount >= iconCount;
|
||||
}
|
||||
|
||||
@@ -696,11 +698,13 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
public void applyToMap(MapItemSavedData mapState) {
|
||||
+ synchronized (mapState) { // Folia - make map data thread-safe
|
||||
for (int i = 0; i < this.width; ++i) {
|
||||
for (int j = 0; j < this.height; ++j) {
|
||||
mapState.setColor(this.startX + i, this.startY + j, this.mapColors[i + j * this.width]);
|
||||
}
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
index 2da78bc43af715fe399eac1d83b3bf6e8fb8afac..433a9302f496a297172c02f3fe0404174cc7a8f1 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
@@ -36,6 +36,7 @@ public class DimensionDataStorage {
|
||||
}
|
||||
|
||||
public <T extends SavedData> T computeIfAbsent(Function<CompoundTag, T> readFunction, Supplier<T> supplier, String id) {
|
||||
+ synchronized (this.cache) { // Folia - make map data thread-safe
|
||||
T savedData = this.get(readFunction, id);
|
||||
if (savedData != null) {
|
||||
return savedData;
|
||||
@@ -44,10 +45,12 @@ public class DimensionDataStorage {
|
||||
this.set(id, savedData2);
|
||||
return savedData2;
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends SavedData> T get(Function<CompoundTag, T> readFunction, String id) {
|
||||
+ synchronized (this.cache) { // Folia - make map data thread-safe
|
||||
SavedData savedData = this.cache.get(id);
|
||||
if (savedData == null && !this.cache.containsKey(id)) {
|
||||
savedData = this.readSavedData(readFunction, id);
|
||||
@@ -55,6 +58,7 @@ public class DimensionDataStorage {
|
||||
}
|
||||
|
||||
return (T)savedData;
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -73,7 +77,9 @@ public class DimensionDataStorage {
|
||||
}
|
||||
|
||||
public void set(String id, SavedData state) {
|
||||
+ synchronized (this.cache) { // Folia - make map data thread-safe
|
||||
this.cache.put(id, state);
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
public CompoundTag readTagFromDisk(String id, int dataVersion) throws IOException {
|
||||
diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
|
||||
index ac807277a6b26d140ea9873d17c7aa4fb5fe37b2..e13d8700593f1f486cfc5c96ac25894202c07b71 100644
|
||||
--- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
|
||||
|
@ -1,344 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 27 Feb 2023 08:12:03 -0800
|
||||
Subject: [PATCH] Make map data thread-safe to access
|
||||
|
||||
We can just synchronise on all of the map data accesses, but
|
||||
this means we need to be careful about ensuring that no
|
||||
sync loads occur, otherwise we could block other threads for
|
||||
long periods of time.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
index 428523feaa4f30260e32ba03937e88200246c693..5722f1dd949c8ef59379bf4499ec2d77a40df847 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -290,8 +290,10 @@ public class ItemFrame extends HangingEntity {
|
||||
MapItemSavedData worldmap = MapItem.getSavedData(i, this.level);
|
||||
|
||||
if (worldmap != null) {
|
||||
+ synchronized (worldmap) { // Folia - make map data thread-safe
|
||||
worldmap.removedFromFrame(this.pos, this.getId());
|
||||
worldmap.setDirty(true);
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
index 586852e347cfeb6e52d16e51b3f193e814036e81..eacd5b6f649a59f845cc8d9d9373d41ed3757c97 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -103,6 +103,7 @@ public class MapItem extends ComplexItem {
|
||||
}
|
||||
|
||||
public void update(Level world, Entity entity, MapItemSavedData state) {
|
||||
+ synchronized (state) { // Folia - make map data thread-safe
|
||||
if (world.dimension() == state.dimension && entity instanceof Player) {
|
||||
int i = 1 << state.scale;
|
||||
int j = state.centerX;
|
||||
@@ -134,9 +135,9 @@ public class MapItem extends ComplexItem {
|
||||
int j2 = (j / i + k1 - 64) * i;
|
||||
int k2 = (k / i + l1 - 64) * i;
|
||||
Multiset<MaterialColor> multiset = LinkedHashMultiset.create();
|
||||
- LevelChunk chunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2)); // Paper - Maps shouldn't load chunks
|
||||
+ LevelChunk chunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2)); // Paper - Maps shouldn't load chunks // Folia - super important this remains true
|
||||
|
||||
- if (chunk != null && !chunk.isEmpty()) { // Paper - Maps shouldn't load chunks
|
||||
+ if (chunk != null && !chunk.isEmpty() && io.papermc.paper.util.TickThread.isTickThreadFor((ServerLevel)world, chunk.getPos())) { // Paper - Maps shouldn't load chunks // Folia - make sure chunk is owned
|
||||
int l2 = 0;
|
||||
double d1 = 0.0D;
|
||||
int i3;
|
||||
@@ -227,6 +228,7 @@ public class MapItem extends ComplexItem {
|
||||
}
|
||||
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
private BlockState getCorrectStateForFluidBlock(Level world, BlockState state, BlockPos pos) {
|
||||
@@ -243,6 +245,7 @@ public class MapItem extends ComplexItem {
|
||||
MapItemSavedData worldmap = MapItem.getSavedData(map, world);
|
||||
|
||||
if (worldmap != null) {
|
||||
+ synchronized (worldmap) { // Folia - make map data thread-safe
|
||||
if (world.dimension() == worldmap.dimension) {
|
||||
int i = 1 << worldmap.scale;
|
||||
int j = worldmap.centerX;
|
||||
@@ -317,6 +320,7 @@ public class MapItem extends ComplexItem {
|
||||
}
|
||||
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +330,7 @@ public class MapItem extends ComplexItem {
|
||||
MapItemSavedData worldmap = MapItem.getSavedData(stack, world);
|
||||
|
||||
if (worldmap != null) {
|
||||
+ synchronized (worldmap) { // Folia - region threading
|
||||
if (entity instanceof Player) {
|
||||
Player entityhuman = (Player) entity;
|
||||
|
||||
@@ -335,6 +340,7 @@ public class MapItem extends ComplexItem {
|
||||
if (!worldmap.locked && (selected || entity instanceof Player && ((Player) entity).getOffhandItem() == stack)) {
|
||||
this.update(world, entity, worldmap);
|
||||
}
|
||||
+ } // Folia - region threading
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
index c8cdcf40e45f5c6270f9b124f0333643266e2858..b370ba924b03cc0a36666ee6ed26be06a6affaa7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
@@ -10,7 +10,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public abstract class SavedData {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private boolean dirty;
|
||||
+ private volatile boolean dirty; // Folia - make map data thread-safe
|
||||
|
||||
public abstract CompoundTag save(CompoundTag nbt);
|
||||
|
||||
@@ -28,6 +28,7 @@ public abstract class SavedData {
|
||||
|
||||
public void save(File file) {
|
||||
if (this.isDirty()) {
|
||||
+ this.setDirty(false); // Folia - make map data thread-safe - move before save, so that any changes after are not lost
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.put("data", this.save(new CompoundTag()));
|
||||
compoundTag.putInt("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion());
|
||||
@@ -38,7 +39,7 @@ public abstract class SavedData {
|
||||
LOGGER.error("Could not save data {}", this, var4);
|
||||
}
|
||||
|
||||
- this.setDirty(false);
|
||||
+ // Folia - make map data thread-safe - move before save, so that any changes after are not lost
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
index 9b2948b5150c8f039ca667a50765109721b93947..1b76e4edce628f2b25815e28cd4cb7504a83a00f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
@@ -27,17 +27,21 @@ public class MapIndex extends SavedData {
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
+ synchronized (this.usedAuxIds) { // Folia - make map data thread-safe
|
||||
for(Object2IntMap.Entry<String> entry : this.usedAuxIds.object2IntEntrySet()) {
|
||||
nbt.putInt(entry.getKey(), entry.getIntValue());
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public int getFreeAuxValueForMap() {
|
||||
+ synchronized (this.usedAuxIds) { // Folia - make map data thread-safe
|
||||
int i = this.usedAuxIds.getInt("map") + 1;
|
||||
this.usedAuxIds.put("map", i);
|
||||
this.setDirty();
|
||||
return i;
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
index 9df7c7e44e9a75187bd1e3e8f7e6bc5d385b0733..5121569f389ee4a50273432a9a272a936542fa12 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
@@ -185,7 +185,7 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public CompoundTag save(CompoundTag nbt) {
|
||||
+ public synchronized CompoundTag save(CompoundTag nbt) { // Folia - make map data thread-safe
|
||||
DataResult<Tag> dataresult = ResourceLocation.CODEC.encodeStart(NbtOps.INSTANCE, this.dimension.location()); // CraftBukkit - decompile error
|
||||
Logger logger = MapItemSavedData.LOGGER;
|
||||
|
||||
@@ -242,7 +242,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return nbt;
|
||||
}
|
||||
|
||||
- public MapItemSavedData locked() {
|
||||
+ public synchronized MapItemSavedData locked() { // Folia - make map data thread-safe
|
||||
MapItemSavedData worldmap = new MapItemSavedData(this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension);
|
||||
|
||||
worldmap.bannerMarkers.putAll(this.bannerMarkers);
|
||||
@@ -253,11 +253,12 @@ public class MapItemSavedData extends SavedData {
|
||||
return worldmap;
|
||||
}
|
||||
|
||||
- public MapItemSavedData scaled(int zoomOutScale) {
|
||||
+ public synchronized MapItemSavedData scaled(int zoomOutScale) { // Folia - make map data thread-safe
|
||||
return MapItemSavedData.createFresh((double) this.centerX, (double) this.centerZ, (byte) Mth.clamp(this.scale + zoomOutScale, (int) 0, (int) 4), this.trackingPosition, this.unlimitedTracking, this.dimension);
|
||||
}
|
||||
|
||||
- public void tickCarriedBy(Player player, ItemStack stack) {
|
||||
+ public synchronized void tickCarriedBy(Player player, ItemStack stack) { // Folia - make map data thread-safe
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread(player, "Ticking map player in incorrect region"); // Folia - region threading
|
||||
if (!this.carriedByPlayers.containsKey(player)) {
|
||||
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player);
|
||||
|
||||
@@ -427,14 +428,14 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- public Packet<?> getUpdatePacket(int id, Player player) {
|
||||
+ public synchronized Packet<?> getUpdatePacket(int id, Player player) { // Folia - make map data thread-safe
|
||||
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player);
|
||||
|
||||
return worldmap_worldmaphumantracker == null ? null : worldmap_worldmaphumantracker.nextUpdatePacket(id);
|
||||
}
|
||||
|
||||
- public void setColorsDirty(int x, int z) {
|
||||
- this.setDirty();
|
||||
+ public synchronized void setColorsDirty(int x, int z) { // Folia - make map data thread-safe
|
||||
+ // Folia - make dirty only after updating data - moved down
|
||||
Iterator iterator = this.carriedBy.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -442,15 +443,16 @@ public class MapItemSavedData extends SavedData {
|
||||
|
||||
worldmap_worldmaphumantracker.markColorsDirty(x, z);
|
||||
}
|
||||
-
|
||||
+ this.setDirty(); // Folia - make dirty only after updating data - moved from above
|
||||
}
|
||||
|
||||
- public void setDecorationsDirty() {
|
||||
- this.setDirty();
|
||||
+ public synchronized void setDecorationsDirty() { // Folia - make map data thread-safe
|
||||
+ // Folia - make dirty only after updating data - moved down
|
||||
this.carriedBy.forEach(MapItemSavedData.HoldingPlayer::markDecorationsDirty);
|
||||
+ this.setDirty(); // Folia - make dirty only after updating data - moved from above
|
||||
}
|
||||
|
||||
- public MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) {
|
||||
+ public synchronized MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) { // Folia - make map data thread-safe
|
||||
MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player);
|
||||
|
||||
if (worldmap_worldmaphumantracker == null) {
|
||||
@@ -462,7 +464,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return worldmap_worldmaphumantracker;
|
||||
}
|
||||
|
||||
- public boolean toggleBanner(LevelAccessor world, BlockPos pos) {
|
||||
+ public synchronized boolean toggleBanner(LevelAccessor world, BlockPos pos) { // Folia - make map data thread-safe
|
||||
double d0 = (double) pos.getX() + 0.5D;
|
||||
double d1 = (double) pos.getZ() + 0.5D;
|
||||
int i = 1 << this.scale;
|
||||
@@ -471,7 +473,7 @@ public class MapItemSavedData extends SavedData {
|
||||
boolean flag = true;
|
||||
|
||||
if (d2 >= -63.0D && d3 >= -63.0D && d2 <= 63.0D && d3 <= 63.0D) {
|
||||
- MapBanner mapiconbanner = MapBanner.fromWorld(world, pos);
|
||||
+ MapBanner mapiconbanner = world.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null || !io.papermc.paper.util.TickThread.isTickThreadFor(world.getMinecraftWorld(), pos) ? null : MapBanner.fromWorld(world, pos); // Folia - make map data thread-safe - don't sync load or read data we do not own
|
||||
|
||||
if (mapiconbanner == null) {
|
||||
return false;
|
||||
@@ -492,7 +494,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return false;
|
||||
}
|
||||
|
||||
- public void checkBanners(BlockGetter world, int x, int z) {
|
||||
+ public synchronized void checkBanners(BlockGetter world, int x, int z) { // Folia - make map data thread-safe
|
||||
Iterator iterator = this.bannerMarkers.values().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -514,12 +516,12 @@ public class MapItemSavedData extends SavedData {
|
||||
return this.bannerMarkers.values();
|
||||
}
|
||||
|
||||
- public void removedFromFrame(BlockPos pos, int id) {
|
||||
+ public synchronized void removedFromFrame(BlockPos pos, int id) { // Folia - make map data thread-safe
|
||||
this.removeDecoration("frame-" + id);
|
||||
this.frameMarkers.remove(MapFrame.frameId(pos));
|
||||
}
|
||||
|
||||
- public boolean updateColor(int x, int z, byte color) {
|
||||
+ public synchronized boolean updateColor(int x, int z, byte color) { // Folia - make map data thread-safe
|
||||
byte b1 = this.colors[x + z * 128];
|
||||
|
||||
if (b1 != color) {
|
||||
@@ -530,12 +532,12 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
}
|
||||
|
||||
- public void setColor(int x, int z, byte color) {
|
||||
+ public synchronized void setColor(int x, int z, byte color) { // Folia - make map data thread-safe
|
||||
this.colors[x + z * 128] = color;
|
||||
this.setColorsDirty(x, z);
|
||||
}
|
||||
|
||||
- public boolean isExplorationMap() {
|
||||
+ public synchronized boolean isExplorationMap() { // Folia - make map data thread-safe
|
||||
Iterator iterator = this.decorations.values().iterator();
|
||||
|
||||
MapDecoration mapicon;
|
||||
@@ -570,7 +572,7 @@ public class MapItemSavedData extends SavedData {
|
||||
return this.decorations.values();
|
||||
}
|
||||
|
||||
- public boolean isTrackedCountOverLimit(int iconCount) {
|
||||
+ public synchronized boolean isTrackedCountOverLimit(int iconCount) { // Folia - make map data thread-safe
|
||||
return this.trackedDecorationCount >= iconCount;
|
||||
}
|
||||
|
||||
@@ -696,11 +698,13 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
|
||||
public void applyToMap(MapItemSavedData mapState) {
|
||||
+ synchronized (mapState) { // Folia - make map data thread-safe
|
||||
for (int i = 0; i < this.width; ++i) {
|
||||
for (int j = 0; j < this.height; ++j) {
|
||||
mapState.setColor(this.startX + i, this.startY + j, this.mapColors[i + j * this.width]);
|
||||
}
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
index 2da78bc43af715fe399eac1d83b3bf6e8fb8afac..433a9302f496a297172c02f3fe0404174cc7a8f1 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
@@ -36,6 +36,7 @@ public class DimensionDataStorage {
|
||||
}
|
||||
|
||||
public <T extends SavedData> T computeIfAbsent(Function<CompoundTag, T> readFunction, Supplier<T> supplier, String id) {
|
||||
+ synchronized (this.cache) { // Folia - make map data thread-safe
|
||||
T savedData = this.get(readFunction, id);
|
||||
if (savedData != null) {
|
||||
return savedData;
|
||||
@@ -44,10 +45,12 @@ public class DimensionDataStorage {
|
||||
this.set(id, savedData2);
|
||||
return savedData2;
|
||||
}
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends SavedData> T get(Function<CompoundTag, T> readFunction, String id) {
|
||||
+ synchronized (this.cache) { // Folia - make map data thread-safe
|
||||
SavedData savedData = this.cache.get(id);
|
||||
if (savedData == null && !this.cache.containsKey(id)) {
|
||||
savedData = this.readSavedData(readFunction, id);
|
||||
@@ -55,6 +58,7 @@ public class DimensionDataStorage {
|
||||
}
|
||||
|
||||
return (T)savedData;
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -73,7 +77,9 @@ public class DimensionDataStorage {
|
||||
}
|
||||
|
||||
public void set(String id, SavedData state) {
|
||||
+ synchronized (this.cache) { // Folia - make map data thread-safe
|
||||
this.cache.put(id, state);
|
||||
+ } // Folia - make map data thread-safe
|
||||
}
|
||||
|
||||
public CompoundTag readTagFromDisk(String id, int dataVersion) throws IOException {
|
Loading…
Reference in New Issue
Block a user