Improved offline playerdata manipulation
- Ability to change player experience and score - Handle upgrade of player data (from older Mc version)
This commit is contained in:
parent
bf59617e19
commit
73d96d0bb7
@ -3,6 +3,9 @@ package fr.pandacube.lib.paper.players;
|
|||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import fr.pandacube.lib.paper.reflect.util.PrimaryWorlds;
|
import fr.pandacube.lib.paper.reflect.util.PrimaryWorlds;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer;
|
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.CompoundTag;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.NbtIo;
|
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.NbtIo;
|
||||||
import fr.pandacube.lib.paper.util.PlayerDataWrapper;
|
import fr.pandacube.lib.paper.util.PlayerDataWrapper;
|
||||||
@ -150,17 +153,23 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
|||||||
/**
|
/**
|
||||||
* Gets the NBT data from the playerdata file.
|
* 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.
|
* 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.
|
* @return the NBT data from the playerdata file.
|
||||||
* @throws IllegalStateException if the player is online.
|
* @throws IllegalStateException if the player is online.
|
||||||
*/
|
*/
|
||||||
default CompoundTag getPlayerData() {
|
default CompoundTag getPlayerData(boolean convertTag) {
|
||||||
if (isOnline())
|
if (isOnline())
|
||||||
throw new IllegalStateException("Cannot access data file of " + getName() + " because they’re online.");
|
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()
|
.getServer()
|
||||||
.getPlayerList()
|
.getPlayerList()
|
||||||
.playerIo()
|
.playerIo()
|
||||||
.getPlayerData(getUniqueId().toString());
|
.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.
|
* @throws IllegalStateException if the player is online.
|
||||||
*/
|
*/
|
||||||
default PlayerDataWrapper getPlayerDataWrapper() {
|
default PlayerDataWrapper getPlayerDataWrapper() {
|
||||||
return new PlayerDataWrapper(getPlayerData());
|
return new PlayerDataWrapper(getPlayerData(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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.CraftWorld;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.RenderData;
|
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.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.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.SharedConstants;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.WorldVersion;
|
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.WorldVersion;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.BlockPosArgument;
|
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.BlockPosArgument;
|
||||||
@ -107,6 +111,11 @@ public class PandalibPaperReflect {
|
|||||||
initWrapper(RenderData.class, RenderData.REFLECT.get());
|
initWrapper(RenderData.class, RenderData.REFLECT.get());
|
||||||
initWrapper(VanillaCommandWrapper.class, VanillaCommandWrapper.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
|
// minecraft.commands
|
||||||
initWrapper(BlockPosArgument.class, BlockPosArgument.MAPPING.runtimeClass());
|
initWrapper(BlockPosArgument.class, BlockPosArgument.MAPPING.runtimeClass());
|
||||||
initWrapper(Commands.class, Commands.MAPPING.runtimeClass());
|
initWrapper(Commands.class, Commands.MAPPING.runtimeClass());
|
||||||
@ -170,6 +179,7 @@ public class PandalibPaperReflect {
|
|||||||
initWrapper(VoxelShape.class, VoxelShape.MAPPING.runtimeClass());
|
initWrapper(VoxelShape.class, VoxelShape.MAPPING.runtimeClass());
|
||||||
// minecraft
|
// minecraft
|
||||||
initWrapper(DetectedVersion.class, DetectedVersion.MAPPING.runtimeClass());
|
initWrapper(DetectedVersion.class, DetectedVersion.MAPPING.runtimeClass());
|
||||||
|
initWrapper(GameVersion.class, GameVersion.REFLECT.get());
|
||||||
initWrapper(SharedConstants.class, SharedConstants.MAPPING.runtimeClass());
|
initWrapper(SharedConstants.class, SharedConstants.MAPPING.runtimeClass());
|
||||||
initWrapper(WorldVersion.class, WorldVersion.MAPPING.runtimeClass());
|
initWrapper(WorldVersion.class, WorldVersion.MAPPING.runtimeClass());
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI;
|
|||||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||||
|
|
||||||
@ConcreteWrapper(WorldVersion.__concrete.class)
|
@ConcreteWrapper(WorldVersion.__concrete.class)
|
||||||
public interface WorldVersion extends ReflectWrapperI {
|
public interface WorldVersion extends GameVersion {
|
||||||
ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.WorldVersion"));
|
ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.WorldVersion"));
|
||||||
|
|
||||||
|
|
||||||
|
@ -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) {
|
private Inventory getBukkitInventory(String nbtKey, InventoryType bukkitType, IntUnaryOperator nbtToBukkitSlotConverter) {
|
||||||
Map<Integer, ItemStack> stacks = getRawInvontoryContent(nbtKey);
|
Map<Integer, ItemStack> stacks = getRawInvontoryContent(nbtKey);
|
||||||
Inventory inv = Bukkit.createInventory(null, bukkitType);
|
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 static class DummyPlayerInventory extends InventoryWrapper implements PlayerInventory {
|
||||||
|
|
||||||
private int heldItemSlot;
|
private int heldItemSlot;
|
||||||
|
Loading…
Reference in New Issue
Block a user