Refactor offline player data access

- Class that handle all Bukkit/NBT conversion of player data
- Ability to read and save the player inventory (more to come later)
This commit is contained in:
2023-02-18 21:32:12 +01:00
parent fb4c62a0bc
commit bf59617e19
8 changed files with 613 additions and 70 deletions

View File

@@ -2,19 +2,18 @@ package fr.pandacube.lib.paper.players;
import com.google.common.io.Files;
import fr.pandacube.lib.paper.reflect.util.PrimaryWorlds;
import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftItemStack;
import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.ListTag;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.NbtIo;
import fr.pandacube.lib.paper.util.PlayerDataWrapper;
import fr.pandacube.lib.paper.util.WorldUtil;
import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.scoreboard.Team;
import java.io.File;
@@ -164,6 +163,16 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
.getPlayerData(getUniqueId().toString());
}
/**
* Gets a wrapper for the NBT data from the playerdata file.
* It will not work if the player is online, because the data on the file are not synchronized with real-time values.
* @return the NBT data from the playerdata file.
* @throws IllegalStateException if the player is online.
*/
default PlayerDataWrapper getPlayerDataWrapper() {
return new PlayerDataWrapper(getPlayerData());
}
/**
* Saves the provided NBT data to the playerdata file.
* It will not work if the player is online, because the provided data will be lost when the player disconnects.
@@ -171,14 +180,14 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
* @throws IllegalStateException if the player is online.
* @throws IOException if an IO error occurs.
*/
default void savePlayerData(CompoundTag data) throws IOException {
default void savePlayerData(PlayerDataWrapper data) throws IOException {
if (isOnline())
throw new IllegalStateException("Cannot write data file of " + getName() + " because theyre online.");
File file = getPlayerDataFile(false);
File old = getPlayerDataFile(true);
old.delete();
Files.move(file, old);
NbtIo.writeCompressed(data, file);
NbtIo.writeCompressed(data.data, file);
}
/**
@@ -192,60 +201,19 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
}
/**
* Gets the content of the players inventory.
* @return the content of the players inventory.
* Gets the players inventory.
* @return the players inventory.
*/
default ItemStack[] getInventoryContent() {
ItemStack[] content = new ItemStack[InventoryType.PLAYER.getDefaultSize()];
CompoundTag playerData = getPlayerData();
if (playerData == null)
return content;
ListTag nbttaglist = playerData.getList("Inventory", 10); // type of list element 10 is CompoundTag
if (nbttaglist == null)
return content;
// cat nbEl NBTslot bukkitSlot NBT->Bukkit
// items 36el 0-35 ==
// armor 4el start 100 36-39 -100 + 36
// offhnd 1el start 150 40 -150 + 40
for (int i = 0; i < nbttaglist.size(); i++) {
CompoundTag itemTag = nbttaglist.getCompound(i);
ItemStack is = CraftItemStack.asCraftMirror(itemTag);
if (is != null && !is.getType().isAir()) {
int nbtSlot = itemTag.getByte("Slot") & 255;
int bukkitSlot = nbtSlot < 36 ? nbtSlot
: (nbtSlot >= 100 && nbtSlot < 104) ? nbtSlot - 100 + 36
: nbtSlot == 150 ? 40
: -1;
if (bukkitSlot >= 0)
content[bukkitSlot] = is;
}
}
return content;
default PlayerInventory getInventory() {
return getPlayerDataWrapper().getInventory();
}
/**
* Gets the content of the players enderchest.
* @return the content of the players enderchest.
* Gets the players enderchest.
* @return the players enderchest.
*/
default ItemStack[] getEnderchestContent() {
ItemStack[] content = new ItemStack[InventoryType.ENDER_CHEST.getDefaultSize()];
CompoundTag playerData = getPlayerData();
if (playerData == null || !playerData.contains("EnderItems", 9)) // type 9 is list
return content;
ListTag nbtList = playerData.getList("EnderItems", 10); // type of list element 10 is CompoundTag
if (nbtList == null)
return content;
for (int i = 0; i < nbtList.size(); i++) {
CompoundTag itemTag = nbtList.getCompound(i);
int nbtSlot = itemTag.getByte("Slot") & 255;
ItemStack is = CraftItemStack.asCraftMirror(itemTag);
if (nbtSlot < content.length && is != null && !is.getType().isAir()) {
content[nbtSlot] = CraftItemStack.asCraftMirror(itemTag);
}
}
return content;
default Inventory getEnderChest() {
return getPlayerDataWrapper().getEnderChest();
}
}

View File

@@ -5,7 +5,6 @@ import com.destroystokyo.paper.ClientOption.ChatVisibility;
import com.destroystokyo.paper.SkinParts;
import fr.pandacube.lib.paper.players.PlayerNonPersistentConfig.Expiration;
import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftPlayer;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
import net.kyori.adventure.audience.MessageType;
@@ -20,8 +19,9 @@ import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.Sound;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.MainHand;
import org.bukkit.inventory.PlayerInventory;
import java.util.Locale;
import java.util.UUID;
@@ -324,20 +324,13 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer
*/
@Override
default CompoundTag getPlayerData() {
CompoundTag tag = new CompoundTag();
getWrappedCraftPlayer().getHandle().serializeEntity(tag);
return tag;
default PlayerInventory getInventory() {
return getBukkitPlayer().getInventory();
}
@Override
default ItemStack[] getInventoryContent() {
return getBukkitPlayer().getInventory().getContents();
}
@Override
default ItemStack[] getEnderchestContent() {
return getBukkitPlayer().getEnderChest().getContents();
default Inventory getEnderChest() {
return getBukkitPlayer().getEnderChest();
}