From b1d7824a630c9c5222a447420d60dc5b7a971deb Mon Sep 17 00:00:00 2001 From: Boy Date: Fri, 11 Aug 2023 11:30:35 +0200 Subject: [PATCH] add methods for getting OfflinePlayer PDCs --- .../idofront/nms/nbt/OfflinePDC.kt | 53 +++++++++++++++++++ .../idofront/nms/nbt/WrappedPDC.kt | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/OfflinePDC.kt diff --git a/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/OfflinePDC.kt b/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/OfflinePDC.kt new file mode 100644 index 0000000..f168a31 --- /dev/null +++ b/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/OfflinePDC.kt @@ -0,0 +1,53 @@ +package com.mineinabyss.idofront.nms.nbt + +import jdk.jfr.internal.management.ManagementSupport.logError +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.NbtIo +import org.bukkit.Bukkit +import org.bukkit.OfflinePlayer +import org.bukkit.craftbukkit.v1_20_R1.CraftServer +import java.io.File +import java.nio.file.Files +import java.util.* + +/** + * Gets the PlayerData from file for this UUID. + */ +fun UUID.getOfflinePlayerData(): CompoundTag? = (Bukkit.getServer() as CraftServer).handle.playerIo.getPlayerData(this.toString()) + +/** + * Gets a copy of the WrappedPDC for this OfflinePlayer. + * Care should be taken to ensure that the player is not online when this is called. + */ +fun OfflinePlayer.getOfflinePDC() : WrappedPDC? { + if (isOnline) return null + val baseTag = uniqueId.getOfflinePlayerData()?.getCompound("BukkitValues") ?: return null + return WrappedPDC(baseTag) +} + +/** + * Saves the given WrappedPDC to the OfflinePlayer's PlayerData file. + * Care should be taken to ensure that the player is not online when this is called. + * @return true if successful, false otherwise. + */ +fun OfflinePlayer.saveOfflinePDC(pdc: WrappedPDC): Boolean { + if (isOnline) return false + val worldNBTStorage = (Bukkit.getServer() as CraftServer).server.playerDataStorage + val tempFile = File(worldNBTStorage.playerDir, "$uniqueId.dat.tmp") + val playerFile = File(worldNBTStorage.playerDir, "$uniqueId.dat") + + val mainPDc = uniqueId.getOfflinePlayerData() ?: return false + mainPDc.put("BukkitValues", pdc.compoundTag) ?: return false + runCatching { + Files.newOutputStream(tempFile.toPath()).use { outStream -> + NbtIo.writeCompressed(mainPDc, outStream) + if (playerFile.exists() && !playerFile.delete()) logError("Failed to delete player file $uniqueId") + if (!tempFile.renameTo(playerFile)) logError("Failed to rename player file $uniqueId") + } + }.onFailure { + logError("Failed to save player file $uniqueId") + it.printStackTrace() + return false + } + return true +} diff --git a/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/WrappedPDC.kt b/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/WrappedPDC.kt index 9c7621a..e4f1f29 100644 --- a/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/WrappedPDC.kt +++ b/idofront-nms/src/main/kotlin/com/mineinabyss/idofront/nms/nbt/WrappedPDC.kt @@ -66,7 +66,7 @@ class WrappedPDC( } } - override fun readFromBytes(bytes: ByteArray?, clear: Boolean) { + override fun readFromBytes(bytes: ByteArray, clear: Boolean) { if (clear) compoundTag.tags.clear() DataInputStream(ByteArrayInputStream(bytes)).use { dataInput -> val compound = NbtIo.read(dataInput)