Skip to content

Commit

Permalink
Backport changes
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Jikoo committed Feb 16, 2024
1 parent 79328d8 commit 35076d1
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,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.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<String> 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);
}
Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -111,8 +141,8 @@ private <T extends Tag> 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;
}

Expand All @@ -121,9 +151,12 @@ private <T extends Tag> void copyValue(
}

private <T extends Tag> @Nullable T getTag(
@NotNull CompoundTag container,
@Nullable CompoundTag container,
@NotNull String key,
@NotNull Class<T> dataType) {
if (container == null) {
return null;
}
Tag value = container.get(key);
if (value == null || !dataType.isAssignableFrom(value.getClass())) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> 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);
}
Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -105,8 +136,8 @@ private <T extends Tag> 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;
}

Expand All @@ -115,9 +146,12 @@ private <T extends Tag> void copyValue(
}

private <T extends Tag> @Nullable T getTag(
@NotNull CompoundTag container,
@Nullable CompoundTag container,
@NotNull String key,
@NotNull Class<T> dataType) {
if (container == null) {
return null;
}
Tag value = container.get(key);
if (value == null || !dataType.isAssignableFrom(value.getClass())) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 35076d1

Please sign in to comment.