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 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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ConcreteWrapper(WorldVersion.__concrete.class)
|
||||
public interface WorldVersion extends ReflectWrapperI {
|
||||
public interface WorldVersion extends GameVersion {
|
||||
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) {
|
||||
Map<Integer, ItemStack> 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;
|
||||
|
Loading…
Reference in New Issue
Block a user