From 35076d1f7cd7ac447b1426fb0dd56055b30220eb Mon Sep 17 00:00:00 2001 From: Jikoo Date: Fri, 16 Feb 2024 15:06:04 -0500 Subject: [PATCH] Backport changes Adds backwards compatibility for deleting migrated active effects tag. In the future, these backwards compatibilities will be maintained only for the current supported versions, i.e. when 1.21 comes out, the 1.19 module will be dropped, and 1.21 will not contain 1.19 backwards compatibility. --- .../openinv/internal/v1_19_R3/OpenPlayer.java | 83 ++++++++++++------ .../openinv/internal/v1_20_R2/OpenPlayer.java | 84 +++++++++++++------ .../openinv/internal/v1_20_R3/OpenPlayer.java | 1 + 3 files changed, 118 insertions(+), 50 deletions(-) diff --git a/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/OpenPlayer.java b/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/OpenPlayer.java index 347d9cb9..34c0891f 100644 --- a/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/OpenPlayer.java +++ b/internal/v1_19_R3/src/main/java/com/lishid/openinv/internal/v1_19_R3/OpenPlayer.java @@ -19,7 +19,6 @@ import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerPlayer; @@ -27,13 +26,48 @@ import org.apache.logging.log4j.LogManager; import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.Set; public class OpenPlayer extends CraftPlayer { + private static final Set RESET_TAGS = Set.of( + // net.minecraft.world.Entity#saveWithoutId(CompoundTag) + "CustomName", + "CustomNameVisible", + "Silent", + "NoGravity", + "Glowing", + "TicksFrozen", + "HasVisualFire", + "Tags", + "Passengers", + // net.minecraft.server.level.ServerPlayer#addAdditionalSaveData(CompoundTag) + // Intentional omissions to prevent mount loss: Attach, Entity, and RootVehicle + "warden_spawn_tracker", + "enteredNetherPosition", + "SpawnX", + "SpawnY", + "SpawnZ", + "SpawnForced", + "SpawnAngle", + "SpawnDimension", + // net.minecraft.world.entity.player.Player#addAdditionalSaveData(CompoundTag) + "ShoulderEntityLeft", + "ShoulderEntityRight", + "LastDeathLocation", + // net.minecraft.world.entity.LivingEntity#addAdditionalSaveData(CompoundTag) + "ActiveEffects", + "SleepingX", + "SleepingY", + "SleepingZ", + "Brain" + ); + public OpenPlayer(CraftServer server, ServerPlayer entity) { super(server, entity); } @@ -56,12 +90,13 @@ public void saveData() { try { PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; - CompoundTag playerData = player.saveWithoutId(new CompoundTag()); + CompoundTag oldData = isOnline() ? null : worldNBTStorage.load(player); + CompoundTag playerData = getWritableTag(oldData); + playerData = player.saveWithoutId(playerData); setExtraData(playerData); - if (!isOnline()) { - // Preserve certain data when offline. - CompoundTag oldData = worldNBTStorage.load(player); + if (oldData != null) { + // Revert certain special data values when offline. revertSpecialValues(playerData, oldData); } @@ -75,27 +110,22 @@ public void saveData() { } } - private void revertSpecialValues(@NotNull CompoundTag newData, @Nullable CompoundTag oldData) { + @Contract("null -> new") + private @NotNull CompoundTag getWritableTag(@Nullable CompoundTag oldData) { if (oldData == null) { - return; + return new CompoundTag(); } - // Prevent vehicle deletion. - if (oldData.contains("RootVehicle", Tag.TAG_COMPOUND)) { - // See net.minecraft.server.players.PlayerList#save(ServerPlayer) - // See net.minecraft.server.level.ServerPlayer#addAdditionalSaveData(CompoundTag) - try { - Tag attach = oldData.get("Attach"); - if (attach != null) { - newData.putUUID("Attach", NbtUtils.loadUUID(attach)); - } - } catch (IllegalArgumentException ignored) { - // Likely will not re-mount successfully, but at least the mount will not be deleted. - } - newData.put("Entity", oldData.getCompound("Entity")); - newData.put("RootVehicle", oldData.getCompound("RootVehicle")); - } + // Copy old data. This is a deep clone, so operating on it should be safe. + oldData = oldData.copy(); + + // Remove vanilla/server data that is not written every time. + oldData.getAllKeys().removeIf(key -> RESET_TAGS.contains(key) || key.startsWith("Bukkit")); + return oldData; + } + + private void revertSpecialValues(@NotNull CompoundTag newData, @NotNull CompoundTag oldData) { // Revert automatic updates to play timestamps. copyValue(oldData, newData, "bukkit", "lastPlayed", NumericTag.class); copyValue(oldData, newData, "Paper", "LastSeen", NumericTag.class); @@ -111,8 +141,8 @@ private void copyValue( CompoundTag oldContainer = getTag(source, container, CompoundTag.class); CompoundTag newContainer = getTag(target, container, CompoundTag.class); - // Container being null means the server implementation doesn't store this data. - if (oldContainer == null || newContainer == null) { + // New container being null means the server implementation doesn't store this data. + if (newContainer == null) { return; } @@ -121,9 +151,12 @@ private void copyValue( } private @Nullable T getTag( - @NotNull CompoundTag container, + @Nullable CompoundTag container, @NotNull String key, @NotNull Class dataType) { + if (container == null) { + return null; + } Tag value = container.get(key); if (value == null || !dataType.isAssignableFrom(value.getClass())) { return null; diff --git a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java index 4388d823..33677e0d 100644 --- a/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java +++ b/internal/v1_20_R2/src/main/java/com/lishid/openinv/internal/v1_20_R2/OpenPlayer.java @@ -20,20 +20,55 @@ import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.storage.PlayerDataStorage; import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.Set; public class OpenPlayer extends CraftPlayer { + private static final Set RESET_TAGS = Set.of( + // net.minecraft.world.Entity#saveWithoutId(CompoundTag) + "CustomName", + "CustomNameVisible", + "Silent", + "NoGravity", + "Glowing", + "TicksFrozen", + "HasVisualFire", + "Tags", + "Passengers", + // net.minecraft.server.level.ServerPlayer#addAdditionalSaveData(CompoundTag) + // Intentional omissions to prevent mount loss: Attach, Entity, and RootVehicle + "warden_spawn_tracker", + "enteredNetherPosition", + "SpawnX", + "SpawnY", + "SpawnZ", + "SpawnForced", + "SpawnAngle", + "SpawnDimension", + // net.minecraft.world.entity.player.Player#addAdditionalSaveData(CompoundTag) + "ShoulderEntityLeft", + "ShoulderEntityRight", + "LastDeathLocation", + // net.minecraft.world.entity.LivingEntity#addAdditionalSaveData(CompoundTag) + "ActiveEffects", // Backwards compat: Renamed from 1.19 + "active_effects", + "SleepingX", + "SleepingY", + "SleepingZ", + "Brain" + ); + public OpenPlayer(CraftServer server, ServerPlayer entity) { super(server, entity); } @@ -50,12 +85,13 @@ public void saveData() { try { PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo; - CompoundTag playerData = player.saveWithoutId(new CompoundTag()); + CompoundTag oldData = isOnline() ? null : worldNBTStorage.load(player); + CompoundTag playerData = getWritableTag(oldData); + playerData = player.saveWithoutId(playerData); setExtraData(playerData); - if (!isOnline()) { - // Preserve certain data when offline. - CompoundTag oldData = worldNBTStorage.load(player); + if (oldData != null) { + // Revert certain special data values when offline. revertSpecialValues(playerData, oldData); } @@ -69,27 +105,22 @@ public void saveData() { } } - private void revertSpecialValues(@NotNull CompoundTag newData, @Nullable CompoundTag oldData) { + @Contract("null -> new") + private @NotNull CompoundTag getWritableTag(@Nullable CompoundTag oldData) { if (oldData == null) { - return; + return new CompoundTag(); } - // Prevent vehicle deletion. - if (oldData.contains("RootVehicle", Tag.TAG_COMPOUND)) { - // See net.minecraft.server.players.PlayerList#save(ServerPlayer) - // See net.minecraft.server.level.ServerPlayer#addAdditionalSaveData(CompoundTag) - try { - Tag attach = oldData.get("Attach"); - if (attach != null) { - newData.putUUID("Attach", NbtUtils.loadUUID(attach)); - } - } catch (IllegalArgumentException ignored) { - // Likely will not re-mount successfully, but at least the mount will not be deleted. - } - newData.put("Entity", oldData.getCompound("Entity")); - newData.put("RootVehicle", oldData.getCompound("RootVehicle")); - } + // Copy old data. This is a deep clone, so operating on it should be safe. + oldData = oldData.copy(); + + // Remove vanilla/server data that is not written every time. + oldData.getAllKeys().removeIf(key -> RESET_TAGS.contains(key) || key.startsWith("Bukkit")); + return oldData; + } + + private void revertSpecialValues(@NotNull CompoundTag newData, @NotNull CompoundTag oldData) { // Revert automatic updates to play timestamps. copyValue(oldData, newData, "bukkit", "lastPlayed", NumericTag.class); copyValue(oldData, newData, "Paper", "LastSeen", NumericTag.class); @@ -105,8 +136,8 @@ private void copyValue( CompoundTag oldContainer = getTag(source, container, CompoundTag.class); CompoundTag newContainer = getTag(target, container, CompoundTag.class); - // Container being null means the server implementation doesn't store this data. - if (oldContainer == null || newContainer == null) { + // New container being null means the server implementation doesn't store this data. + if (newContainer == null) { return; } @@ -115,9 +146,12 @@ private void copyValue( } private @Nullable T getTag( - @NotNull CompoundTag container, + @Nullable CompoundTag container, @NotNull String key, @NotNull Class dataType) { + if (container == null) { + return null; + } Tag value = container.get(key); if (value == null || !dataType.isAssignableFrom(value.getClass())) { return null; diff --git a/internal/v1_20_R3/src/main/java/com/lishid/openinv/internal/v1_20_R3/OpenPlayer.java b/internal/v1_20_R3/src/main/java/com/lishid/openinv/internal/v1_20_R3/OpenPlayer.java index 6cf45719..08017f9f 100644 --- a/internal/v1_20_R3/src/main/java/com/lishid/openinv/internal/v1_20_R3/OpenPlayer.java +++ b/internal/v1_20_R3/src/main/java/com/lishid/openinv/internal/v1_20_R3/OpenPlayer.java @@ -62,6 +62,7 @@ public class OpenPlayer extends CraftPlayer { "ShoulderEntityRight", "LastDeathLocation", // net.minecraft.world.entity.LivingEntity#addAdditionalSaveData(CompoundTag) + "ActiveEffects", // Backwards compat: Renamed from 1.19 "active_effects", "SleepingX", "SleepingY",