From 73d96d0bb72d7190ff4a6c5c89d798e06aff092f Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Sun, 19 Feb 2023 16:11:04 +0100 Subject: [PATCH] Improved offline playerdata manipulation - Ability to change player experience and score - Handle upgrade of player data (from older Mc version) --- .../lib/paper/players/PaperOffPlayer.java | 15 ++++- .../paper/reflect/PandalibPaperReflect.java | 10 +++ .../dataconverter/MCDataConverter.java | 24 +++++++ .../wrapper/dataconverter/MCDataType.java | 15 +++++ .../wrapper/dataconverter/MCTypeRegistry.java | 24 +++++++ .../wrapper/minecraft/GameVersion.java | 28 ++++++++ .../wrapper/minecraft/WorldVersion.java | 2 +- .../lib/paper/util/PlayerDataWrapper.java | 64 +++++++++++++++---- 8 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataConverter.java create mode 100644 pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataType.java create mode 100644 pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCTypeRegistry.java create mode 100644 pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/GameVersion.java diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/players/PaperOffPlayer.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/players/PaperOffPlayer.java index 114c0e1..a674522 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/players/PaperOffPlayer.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/players/PaperOffPlayer.java @@ -3,6 +3,9 @@ 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.CraftServer; +import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCDataConverter; +import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCTypeRegistry; +import fr.pandacube.lib.paper.reflect.wrapper.minecraft.SharedConstants; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.NbtIo; import fr.pandacube.lib.paper.util.PlayerDataWrapper; @@ -150,17 +153,23 @@ public interface PaperOffPlayer extends AbstractOffPlayer { /** * Gets 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. + * @param convertTag true to convert the data to the current MC version, false to keep the saved version * @return the NBT data from the playerdata file. * @throws IllegalStateException if the player is online. */ - default CompoundTag getPlayerData() { + default CompoundTag getPlayerData(boolean convertTag) { if (isOnline()) throw new IllegalStateException("Cannot access data file of " + getName() + " because they’re online."); - return ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class) + CompoundTag data = ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class) .getServer() .getPlayerList() .playerIo() .getPlayerData(getUniqueId().toString()); + if (convertTag) { + int i = data.contains("DataVersion", 3) ? data.getInt("DataVersion") : -1; + data = MCDataConverter.convertTag(MCTypeRegistry.PLAYER(), data, i, SharedConstants.getCurrentVersion().getWorldVersion()); + } + return data; } /** @@ -170,7 +179,7 @@ public interface PaperOffPlayer extends AbstractOffPlayer { * @throws IllegalStateException if the player is online. */ default PlayerDataWrapper getPlayerDataWrapper() { - return new PlayerDataWrapper(getPlayerData()); + return new PlayerDataWrapper(getPlayerData(true)); } /** diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java index a711c0a..ee54dfa 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java @@ -10,7 +10,11 @@ import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftVector; import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftWorld; import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.RenderData; import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.VanillaCommandWrapper; +import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCDataConverter; +import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCDataType; +import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCTypeRegistry; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.DetectedVersion; +import fr.pandacube.lib.paper.reflect.wrapper.minecraft.GameVersion; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.SharedConstants; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.WorldVersion; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.BlockPosArgument; @@ -107,6 +111,11 @@ public class PandalibPaperReflect { initWrapper(RenderData.class, RenderData.REFLECT.get()); initWrapper(VanillaCommandWrapper.class, VanillaCommandWrapper.REFLECT.get()); + // dataconverter + initWrapper(MCDataConverter.class, MCDataConverter.REFLECT.get()); + initWrapper(MCDataType.class, MCDataType.REFLECT.get()); + initWrapper(MCTypeRegistry.class, MCTypeRegistry.REFLECT.get()); + // minecraft.commands initWrapper(BlockPosArgument.class, BlockPosArgument.MAPPING.runtimeClass()); initWrapper(Commands.class, Commands.MAPPING.runtimeClass()); @@ -170,6 +179,7 @@ public class PandalibPaperReflect { initWrapper(VoxelShape.class, VoxelShape.MAPPING.runtimeClass()); // minecraft initWrapper(DetectedVersion.class, DetectedVersion.MAPPING.runtimeClass()); + initWrapper(GameVersion.class, GameVersion.REFLECT.get()); initWrapper(SharedConstants.class, SharedConstants.MAPPING.runtimeClass()); initWrapper(WorldVersion.class, WorldVersion.MAPPING.runtimeClass()); diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataConverter.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataConverter.java new file mode 100644 index 0000000..aeb091e --- /dev/null +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataConverter.java @@ -0,0 +1,24 @@ +package fr.pandacube.lib.paper.reflect.wrapper.dataconverter; + +import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; +import fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.chat.Component; +import fr.pandacube.lib.reflect.Reflect; +import fr.pandacube.lib.reflect.ReflectClass; +import fr.pandacube.lib.reflect.ReflectMethod; +import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; + +import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; +import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; + +public class MCDataConverter extends ReflectWrapper { + public static final ReflectClass REFLECT = wrapEx(() -> Reflect.ofClass("ca.spottedleaf.dataconverter.minecraft.MCDataConverter")); + private static final ReflectMethod convertTag = wrapEx(() -> REFLECT.method("convertTag", Component.MAPPING.runtimeClass())); + + public static CompoundTag convertTag(MCDataType type, CompoundTag data, int fromVersion, int toVersion) { + return wrap(wrapReflectEx(() -> convertTag.invokeStatic(unwrap(type), unwrap(data), fromVersion, toVersion)), CompoundTag.class); + } + + protected MCDataConverter(Object obj) { + super(obj); + } +} diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataType.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataType.java new file mode 100644 index 0000000..3c96e05 --- /dev/null +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCDataType.java @@ -0,0 +1,15 @@ +package fr.pandacube.lib.paper.reflect.wrapper.dataconverter; + +import fr.pandacube.lib.reflect.Reflect; +import fr.pandacube.lib.reflect.ReflectClass; +import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; + +import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; + +public class MCDataType extends ReflectWrapper { + public static final ReflectClass REFLECT = wrapEx(() -> Reflect.ofClass("ca.spottedleaf.dataconverter.minecraft.datatypes.MCDataType")); + + protected MCDataType(Object obj) { + super(obj); + } +} diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCTypeRegistry.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCTypeRegistry.java new file mode 100644 index 0000000..a48dcf9 --- /dev/null +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/dataconverter/MCTypeRegistry.java @@ -0,0 +1,24 @@ +package fr.pandacube.lib.paper.reflect.wrapper.dataconverter; + +import fr.pandacube.lib.reflect.Reflect; +import fr.pandacube.lib.reflect.ReflectClass; +import fr.pandacube.lib.reflect.ReflectField; +import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; + +import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; +import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; + +public class MCTypeRegistry extends ReflectWrapper { + public static final ReflectClass REFLECT = wrapEx(() -> Reflect.ofClass("ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry")); + private static final ReflectField _PLAYER = wrapEx(() -> REFLECT.field("PLAYER")); + + public static MCDataType PLAYER() { + return wrap(wrapReflectEx(_PLAYER::getStaticValue), MCDataType.class); + } + + + + protected MCTypeRegistry(Object obj) { + super(obj); + } +} diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/GameVersion.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/GameVersion.java new file mode 100644 index 0000000..70b0b2b --- /dev/null +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/GameVersion.java @@ -0,0 +1,28 @@ +package fr.pandacube.lib.paper.reflect.wrapper.minecraft; + +import fr.pandacube.lib.reflect.Reflect; +import fr.pandacube.lib.reflect.ReflectClass; +import fr.pandacube.lib.reflect.ReflectMethod; +import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; +import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; +import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; + +import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; +import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; + +@ConcreteWrapper(GameVersion.__concrete.class) +public interface GameVersion extends ReflectWrapperI { + public static final ReflectClass REFLECT = wrapEx(() -> Reflect.ofClass("com.mojang.bridge.game.GameVersion")); + public static final ReflectMethod getWorldVersion = wrapEx(() -> REFLECT.method("getWorldVersion")); + + default int getWorldVersion() { + return (int) wrapReflectEx(() -> getWorldVersion.invoke(__getRuntimeInstance())); + } + + + class __concrete extends ReflectWrapper implements GameVersion { + private __concrete(Object obj) { + super(obj); + } + } +} diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/WorldVersion.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/WorldVersion.java index d1aefcd..6f58c43 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/WorldVersion.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/wrapper/minecraft/WorldVersion.java @@ -9,7 +9,7 @@ import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; @ConcreteWrapper(WorldVersion.__concrete.class) -public interface WorldVersion extends ReflectWrapperI { +public interface WorldVersion extends GameVersion { ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.WorldVersion")); diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/util/PlayerDataWrapper.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/util/PlayerDataWrapper.java index 6ac9d5a..5146ab7 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/util/PlayerDataWrapper.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/util/PlayerDataWrapper.java @@ -91,20 +91,6 @@ public class PlayerDataWrapper { - - - private int getHeldItemSlot() { - if (!data.contains("SelectedItemSlot")) - return 0; - return data.getInt("SelectedItemSlot"); - } - - private void setHeldItemSlot(int slot) { - data.putInt("SelectedItemSlot", slot); - } - - - private Inventory getBukkitInventory(String nbtKey, InventoryType bukkitType, IntUnaryOperator nbtToBukkitSlotConverter) { Map stacks = getRawInvontoryContent(nbtKey); Inventory inv = Bukkit.createInventory(null, bukkitType); @@ -169,6 +155,56 @@ public class PlayerDataWrapper { + + private int getHeldItemSlot() { + if (!data.contains("SelectedItemSlot")) + return 0; + return data.getInt("SelectedItemSlot"); + } + + private void setHeldItemSlot(int slot) { + data.putInt("SelectedItemSlot", slot); + } + + + + + + public int getScore() { + if (!data.contains("Score")) + return 0; + return data.getInt("Score"); + + } + + public void setScore(int score) { + data.putInt("Score", score); + } + + + + public int getTotalExperience() { + if (!data.contains("XpTotal")) + return 0; + return data.getInt("XpTotal"); + } + + public void setTotalExperience(int xp) { + data.putInt("XpTotal", xp); + double levelAndExp = ExperienceUtil.getLevelFromExp(xp); + int level = (int) levelAndExp; + double expProgress = levelAndExp - level; + data.putInt("XPLevel", level); + data.putFloat("XpP", (float) expProgress); + } + + + + + + + + private static class DummyPlayerInventory extends InventoryWrapper implements PlayerInventory { private int heldItemSlot;