From 6b0484122e145d85b7f339460565119d71d42cb3 Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Mon, 29 Nov 2021 09:28:19 +1100 Subject: [PATCH] SPIGOT-6814: (Chunk) PersistentData is lost after restart By: DerFrZocker --- .../minecraft/world/level/chunk/Chunk.patch | 28 ++++++++------- .../world/level/chunk/IChunkAccess.patch | 21 ++++++++--- .../chunk/storage/ChunkRegionLoader.patch | 35 ++++++++++--------- .../CraftPersistentDataContainer.java | 21 +++++++++++ 4 files changed, 71 insertions(+), 34 deletions(-) diff --git a/paper-server/nms-patches/net/minecraft/world/level/chunk/Chunk.patch b/paper-server/nms-patches/net/minecraft/world/level/chunk/Chunk.patch index ce267e5dd6..2805678fa2 100644 --- a/paper-server/nms-patches/net/minecraft/world/level/chunk/Chunk.patch +++ b/paper-server/nms-patches/net/minecraft/world/level/chunk/Chunk.patch @@ -18,7 +18,7 @@ this.gameEventDispatcherSections = new Int2ObjectOpenHashMap(); HeightMap.Type[] aheightmap_type = HeightMap.Type.values(); int j = aheightmap_type.length; -@@ -110,8 +110,22 @@ +@@ -110,8 +110,20 @@ this.postLoad = chunk_c; this.blockTicks = levelchunkticks; this.fluidTicks = levelchunkticks1; @@ -34,22 +34,24 @@ + public boolean mustNotSave; + public boolean needsDecoration; + -+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); -+ public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(DATA_TYPE_REGISTRY); + // CraftBukkit end + public Chunk(WorldServer worldserver, ProtoChunk protochunk, @Nullable Chunk.c chunk_c) { this(worldserver, protochunk.getPos(), protochunk.getUpgradeData(), protochunk.unpackBlockTicks(), protochunk.unpackFluidTicks(), protochunk.getInhabitedTime(), protochunk.getSections(), chunk_c, protochunk.getBlendingData()); Iterator iterator = protochunk.getBlockEntities().values().iterator(); -@@ -142,6 +156,7 @@ +@@ -142,6 +154,11 @@ this.setLightCorrect(protochunk.isLightCorrect()); this.unsaved = true; + this.needsDecoration = true; // CraftBukkit ++ // CraftBukkit start ++ this.persistentDataContainer = protochunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading. ++ this.persistentDataContainer.setCallback(() -> setUnsaved(true)); // SPIGOT-6814: Handle cases were only persistentData is saved ++ // CraftBukkit end } @Override -@@ -238,9 +253,16 @@ +@@ -238,9 +255,16 @@ } } @@ -66,7 +68,7 @@ int i = blockposition.getY(); ChunkSection chunksection = this.getSection(this.getSectionIndex(i)); boolean flag1 = chunksection.hasOnlyAir(); -@@ -279,7 +301,8 @@ +@@ -279,7 +303,8 @@ if (!chunksection.getBlockState(j, k, l).is(block)) { return null; } else { @@ -76,7 +78,7 @@ iblockdata.onPlace(this.level, blockposition, iblockdata1, flag); } -@@ -324,7 +347,12 @@ +@@ -324,7 +349,12 @@ @Nullable public TileEntity getBlockEntity(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) { @@ -90,7 +92,7 @@ if (tileentity == null) { NBTTagCompound nbttagcompound = (NBTTagCompound) this.pendingBlockEntities.remove(blockposition); -@@ -395,6 +423,13 @@ +@@ -395,6 +425,13 @@ tileentity1.setRemoved(); } @@ -104,7 +106,7 @@ } } -@@ -424,6 +459,12 @@ +@@ -424,6 +461,12 @@ if (this.isInLevel()) { TileEntity tileentity = (TileEntity) this.blockEntities.remove(blockposition); @@ -117,7 +119,7 @@ if (tileentity != null) { this.removeGameEventListener(tileentity); tileentity.setRemoved(); -@@ -471,6 +512,55 @@ +@@ -471,6 +514,55 @@ } @@ -173,7 +175,7 @@ public boolean isEmpty() { return false; } -@@ -659,7 +749,7 @@ +@@ -659,7 +751,7 @@ private void updateBlockEntityTicker(T t0) { IBlockData iblockdata = t0.getBlockState(); @@ -182,7 +184,7 @@ if (blockentityticker == null) { this.removeBlockEntityTicker(t0.getBlockPos()); -@@ -752,7 +842,7 @@ +@@ -752,7 +844,7 @@ private boolean loggedInvalidBlockState; a(TileEntity tileentity, BlockEntityTicker blockentityticker) { @@ -191,7 +193,7 @@ this.ticker = blockentityticker; } -@@ -775,7 +865,7 @@ +@@ -775,7 +867,7 @@ this.loggedInvalidBlockState = true; Chunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new org.apache.logging.log4j.util.Supplier[]{this::getType, this::getPos, () -> { return iblockdata; diff --git a/paper-server/nms-patches/net/minecraft/world/level/chunk/IChunkAccess.patch b/paper-server/nms-patches/net/minecraft/world/level/chunk/IChunkAccess.patch index d8b1d5e239..2117da323b 100644 --- a/paper-server/nms-patches/net/minecraft/world/level/chunk/IChunkAccess.patch +++ b/paper-server/nms-patches/net/minecraft/world/level/chunk/IChunkAccess.patch @@ -1,18 +1,31 @@ --- a/net/minecraft/world/level/chunk/IChunkAccess.java +++ b/net/minecraft/world/level/chunk/IChunkAccess.java -@@ -94,7 +94,11 @@ +@@ -77,6 +77,11 @@ + protected final LevelHeightAccessor levelHeightAccessor; + protected final ChunkSection[] sections; + ++ // CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading. ++ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); ++ public org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(DATA_TYPE_REGISTRY); ++ // CraftBukkit end ++ + public IChunkAccess(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter, LevelHeightAccessor levelheightaccessor, IRegistry iregistry, long i, @Nullable ChunkSection[] achunksection, @Nullable BlendingData blendingdata) { + this.chunkPos = chunkcoordintpair; + this.upgradeData = chunkconverter; +@@ -94,7 +99,12 @@ } replaceMissingSections(levelheightaccessor, iregistry, this.sections); + // CraftBukkit start + this.biomeRegistry = iregistry; ++ this.persistentDataContainer.setCallback(() -> setUnsaved(true)); // CraftBukkit - SPIGOT-6814: Handle cases were only persistentData is saved } + public final IRegistry biomeRegistry; + // CraftBukkit end private static void replaceMissingSections(LevelHeightAccessor levelheightaccessor, IRegistry iregistry, ChunkSection[] achunksection) { for (int i = 0; i < achunksection.length; ++i) { -@@ -394,6 +398,27 @@ +@@ -394,6 +404,27 @@ } } @@ -40,7 +53,7 @@ public void fillBiomesFromNoise(BiomeResolver biomeresolver, Climate.Sampler climate_sampler) { ChunkCoordIntPair chunkcoordintpair = this.getPos(); int i = QuartPos.fromBlock(chunkcoordintpair.getMinBlockX()); -@@ -425,8 +450,10 @@ +@@ -425,8 +456,10 @@ return this; } @@ -52,7 +65,7 @@ private final SerializableTickContainer blocks; private final SerializableTickContainer fluids; -@@ -442,5 +469,7 @@ +@@ -442,5 +475,7 @@ public SerializableTickContainer fluids() { return this.fluids; } diff --git a/paper-server/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch b/paper-server/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch index c4affbde21..fa3f814bc7 100644 --- a/paper-server/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch +++ b/paper-server/nms-patches/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.patch @@ -9,7 +9,21 @@ Objects.requireNonNull(protochunk); optional.ifPresent(protochunk::setBelowZeroRetrogen); -@@ -321,7 +321,7 @@ +@@ -219,6 +219,13 @@ + } + } + ++ // CraftBukkit start - load chunk persistent data from nbt - SPIGOT-6814: Already load PDC here to account for 1.17 to 1.18 chunk upgrading. ++ net.minecraft.nbt.NBTBase persistentBase = nbttagcompound.get("ChunkBukkitValues"); ++ if (persistentBase instanceof NBTTagCompound) { ++ ((IChunkAccess) object).persistentDataContainer.putAll((NBTTagCompound) persistentBase); ++ } ++ // CraftBukkit end ++ + ((IChunkAccess) object).setLightCorrect(flag); + NBTTagCompound nbttagcompound2 = nbttagcompound.getCompound("Heightmaps"); + EnumSet enumset = EnumSet.noneOf(HeightMap.Type.class); +@@ -321,7 +328,7 @@ nbttagcompound.putLong("InhabitedTime", ichunkaccess.getInhabitedTime()); nbttagcompound.putString("Status", ichunkaccess.getStatus().getName()); BlendingData blendingdata = ichunkaccess.getBlendingData(); @@ -18,28 +32,15 @@ Logger logger; if (blendingdata != null) { -@@ -452,6 +452,11 @@ +@@ -452,6 +459,11 @@ nbttagcompound.put("Heightmaps", nbttagcompound3); nbttagcompound.put("structures", packStructureData(StructurePieceSerializationContext.fromLevel(worldserver), chunkcoordintpair, ichunkaccess.getAllStarts(), ichunkaccess.getAllReferences())); + // CraftBukkit start - store chunk persistent data in nbt -+ if (ichunkaccess instanceof Chunk && !((Chunk) ichunkaccess).persistentDataContainer.isEmpty()) { -+ nbttagcompound.put("ChunkBukkitValues", ((Chunk) ichunkaccess).persistentDataContainer.toTagCompound()); ++ if (!ichunkaccess.persistentDataContainer.isEmpty()) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading. ++ nbttagcompound.put("ChunkBukkitValues", ichunkaccess.persistentDataContainer.toTagCompound()); + } + // CraftBukkit end return nbttagcompound; } -@@ -498,6 +503,12 @@ - } - } - -+ // CraftBukkit start - load chunk persistent data from nbt -+ net.minecraft.nbt.NBTBase persistentBase = nbttagcompound.get("ChunkBukkitValues"); -+ if (persistentBase instanceof NBTTagCompound) { -+ chunk.persistentDataContainer.putAll((NBTTagCompound) persistentBase); -+ } -+ // CraftBukkit end - }; - } - diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java index 88fa07e48b..8958e92bd7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java @@ -17,9 +17,11 @@ import org.bukkit.persistence.PersistentDataType; public final class CraftPersistentDataContainer implements PersistentDataContainer { + private static final Callback EMPTY = () -> { }; private final Map customDataTags = new HashMap<>(); private final CraftPersistentDataTypeRegistry registry; private final CraftPersistentDataAdapterContext adapterContext; + private Callback callback = EMPTY; public CraftPersistentDataContainer(Map customTags, CraftPersistentDataTypeRegistry registry) { this(registry); @@ -31,6 +33,15 @@ public final class CraftPersistentDataContainer implements PersistentDataContain this.adapterContext = new CraftPersistentDataAdapterContext(this.registry); } + public void setCallback(Callback callback) { + if (callback == null) { + this.callback = EMPTY; + return; + } + + this.callback = callback; + } + @Override public void set(NamespacedKey key, PersistentDataType type, Z value) { Validate.notNull(key, "The provided key for the custom value was null"); @@ -38,6 +49,7 @@ public final class CraftPersistentDataContainer implements PersistentDataContain Validate.notNull(value, "The provided value for the custom value was null"); this.customDataTags.put(key.toString(), registry.wrap(type.getPrimitiveType(), type.toPrimitive(value, adapterContext))); + callback.onValueChange(); } @Override @@ -91,6 +103,7 @@ public final class CraftPersistentDataContainer implements PersistentDataContain Validate.notNull(key, "The provided key for the custom value was null"); this.customDataTags.remove(key.toString()); + callback.onValueChange(); } @Override @@ -125,16 +138,19 @@ public final class CraftPersistentDataContainer implements PersistentDataContain public void put(String key, NBTBase base) { this.customDataTags.put(key, base); + callback.onValueChange(); } public void putAll(Map map) { this.customDataTags.putAll(map); + callback.onValueChange(); } public void putAll(NBTTagCompound compound) { for (String key : compound.getAllKeys()) { this.customDataTags.put(key, compound.get(key)); } + callback.onValueChange(); } public Map getRaw() { @@ -155,4 +171,9 @@ public final class CraftPersistentDataContainer implements PersistentDataContain public Map serialize() { return (Map) CraftNBTTagConfigSerializer.serialize(toTagCompound()); } + + @FunctionalInterface + public interface Callback { + void onValueChange(); + } }