Update reflection in NMS/OBC

This commit is contained in:
Marc Baloup 2024-06-15 13:15:50 +02:00
parent 7f56645ba5
commit cef4af80f0
10 changed files with 110 additions and 53 deletions

View File

@ -2,12 +2,8 @@ package fr.pandacube.lib.paper.players;
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.reflect.wrapper.minecraft.nbt.Tag;
import fr.pandacube.lib.paper.util.PlayerDataWrapper; import fr.pandacube.lib.paper.util.PlayerDataWrapper;
import fr.pandacube.lib.paper.world.WorldUtil; import fr.pandacube.lib.paper.world.WorldUtil;
import fr.pandacube.lib.players.standalone.AbstractOffPlayer; import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
@ -154,29 +150,17 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
/** /**
* Gets the NBT data from the player-data file. * Gets the NBT data from the player-data 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 player-data file, or null if the file does not exist.
* @return the NBT data from the player-data file, or null if the file does not exists.
* @throws IllegalStateException if the player is online. * @throws IllegalStateException if the player is online.
* @throws IOException if an error occurs reading the data.
*/ */
default CompoundTag getPlayerData(boolean convertTag) throws IOException { default CompoundTag getPlayerData() {
if (isOnline()) if (isOnline())
throw new IllegalStateException("Cannot access data file of " + getName() + " because theyre online."); throw new IllegalStateException("Cannot access data file of " + getName() + " because theyre online.");
CompoundTag data = ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class) return ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class)
.getServer() .getServer()
.getPlayerList() .getPlayerList()
.playerIo() .playerIo()
.getPlayerData(getUniqueId().toString()); .load(getName(), getUniqueId().toString()).orElse(null);
if (data != null && convertTag) {
int srcVersion = data.contains("DataVersion", Tag.TAG_ANY_NUMERIC()) ? data.getInt("DataVersion") : -1;
int destVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion();
try {
data = MCDataConverter.convertTag(MCTypeRegistry.PLAYER(), data, srcVersion, destVersion);
} catch (Exception e) {
throw new IOException("Unable to upgrade data format of player " + getName() + " (" + getUniqueId() + ") from version " + destVersion + " to " + destVersion);
}
}
return data;
} }
/** /**
@ -184,10 +168,9 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
* 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.
* @return the NBT data from the player-data file. * @return the NBT data from the player-data file.
* @throws IllegalStateException if the player is online. * @throws IllegalStateException if the player is online.
* @throws IOException if an error occurs reading the data.
*/ */
default PlayerDataWrapper getPlayerDataWrapper() throws IOException { default PlayerDataWrapper getPlayerDataWrapper() {
return new PlayerDataWrapper(getPlayerData(true)); return new PlayerDataWrapper(getPlayerData());
} }
/** /**
@ -213,25 +196,23 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
* @return the file where the player-data is stored. * @return the file where the player-data is stored.
*/ */
default File getPlayerDataFile(boolean old) { default File getPlayerDataFile(boolean old) {
File playerDataDir = new File(WorldUtil.worldDir(PrimaryWorlds.PRIMARY_WORLDS.get(0)), "playerdata"); File playerDataDir = new File(WorldUtil.worldDir(PrimaryWorlds.PRIMARY_WORLDS.getFirst()), "playerdata");
return new File(playerDataDir, getUniqueId() + (old ? ".dat_old" : ".dat")); return new File(playerDataDir, getUniqueId() + (old ? ".dat_old" : ".dat"));
} }
/** /**
* Gets the players inventory. * Gets the players inventory.
* @return the players inventory. * @return the players inventory.
* @throws IOException if an error occurs reading the data.
*/ */
default PlayerInventory getInventory() throws IOException { default PlayerInventory getInventory() {
return getPlayerDataWrapper().getInventory(); return getPlayerDataWrapper().getInventory();
} }
/** /**
* Gets the players enderchest. * Gets the players enderchest.
* @return the players enderchest. * @return the players enderchest.
* @throws IOException if an error occurs reading the data.
*/ */
default Inventory getEnderChest() throws IOException { default Inventory getEnderChest() {
return getPlayerDataWrapper().getEnderChest(); return getPlayerDataWrapper().getEnderChest();
} }

View File

@ -24,6 +24,8 @@ import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.GameProfileArgu
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.ResourceLocationArgument; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.ResourceLocationArgument;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Vec3Argument; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Vec3Argument;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.BlockPos; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.BlockPos;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.HolderLookupProvider;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.RegistryAccess;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.Vec3i; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.Vec3i;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CollectionTag; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CollectionTag;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
@ -130,6 +132,8 @@ public class PandalibPaperReflect {
thAcc.catchThrowable(() -> initWrapper(Vec3Argument.class, Vec3Argument.REFLECT.get())); thAcc.catchThrowable(() -> initWrapper(Vec3Argument.class, Vec3Argument.REFLECT.get()));
// minecraft.core // minecraft.core
thAcc.catchThrowable(() -> initWrapper(BlockPos.class, BlockPos.REFLECT.get())); thAcc.catchThrowable(() -> initWrapper(BlockPos.class, BlockPos.REFLECT.get()));
thAcc.catchThrowable(() -> initWrapper(HolderLookupProvider.class, HolderLookupProvider.REFLECT.get()));
thAcc.catchThrowable(() -> initWrapper(RegistryAccess.class, RegistryAccess.REFLECT.get()));
thAcc.catchThrowable(() -> initWrapper(Vec3i.class, Vec3i.REFLECT.get())); thAcc.catchThrowable(() -> initWrapper(Vec3i.class, Vec3i.REFLECT.get()));
// minecraft.nbt // minecraft.nbt
thAcc.catchThrowable(() -> initWrapper(CollectionTag.class, CollectionTag.REFLECT.get())); thAcc.catchThrowable(() -> initWrapper(CollectionTag.class, CollectionTag.REFLECT.get()));

View File

@ -1,7 +1,6 @@
package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit; package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit;
import fr.pandacube.lib.paper.reflect.OBCReflect; import fr.pandacube.lib.paper.reflect.OBCReflect;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
import fr.pandacube.lib.reflect.ReflectClass; import fr.pandacube.lib.reflect.ReflectClass;
import fr.pandacube.lib.reflect.ReflectMethod; import fr.pandacube.lib.reflect.ReflectMethod;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped;
@ -20,11 +19,6 @@ public class CraftItemStack extends ReflectWrapperTyped<ItemStack> {
} }
public static ItemStack asCraftMirror(CompoundTag nbt) {
return asCraftMirror(fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.of(nbt));
}
public static fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack asNMSCopy(ItemStack original) { public static fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack asNMSCopy(ItemStack original) {
return wrap(wrapReflectEx(() -> asNMSCopy.invokeStatic(original)), fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.class); return wrap(wrapReflectEx(() -> asNMSCopy.invokeStatic(original)), fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.class);
} }

View File

@ -0,0 +1,18 @@
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core;
import fr.pandacube.lib.reflect.Reflect;
import fr.pandacube.lib.reflect.ReflectClass;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI;
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
public interface HolderLookupProvider extends ReflectWrapperI {
ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.core.HolderLookup.Provider"));
class __concrete extends ReflectWrapper implements HolderLookupProvider {
protected __concrete(Object obj) {
super(obj);
}
}
}

View File

@ -0,0 +1,18 @@
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom.CustomPacketPayload;
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 interface RegistryAccess extends HolderLookupProvider {
ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.core.RegistryAccess"));
class __concrete extends ReflectWrapper implements RegistryAccess {
protected __concrete(Object obj) {
super(obj);
}
}
}

View File

@ -51,7 +51,7 @@ public class CompoundTag extends ReflectWrapper implements Tag {
private static final ReflectMethod<?> get = wrapEx(() -> REFLECT.method("get", String.class)); private static final ReflectMethod<?> get = wrapEx(() -> REFLECT.method("get", String.class));
private static final ReflectMethod<?> getAllKeys = wrapEx(() -> REFLECT.method("getAllKeys")); private static final ReflectMethod<?> getAllKeys = wrapEx(() -> REFLECT.method("getAllKeys"));
private static final ReflectMethod<?> entries = wrapEx(() -> REFLECT.method("entries")); private static final ReflectMethod<?> entrySet = wrapEx(() -> REFLECT.method("entrySet"));
private static final ReflectMethod<?> size = wrapEx(() -> REFLECT.method("size")); private static final ReflectMethod<?> size = wrapEx(() -> REFLECT.method("size"));
private static final ReflectMethod<?> contains = wrapEx(() -> REFLECT.method("contains", String.class)); private static final ReflectMethod<?> contains = wrapEx(() -> REFLECT.method("contains", String.class));
private static final ReflectMethod<?> containsStringInt = wrapEx(() -> REFLECT.method("contains", String.class, int.class)); private static final ReflectMethod<?> containsStringInt = wrapEx(() -> REFLECT.method("contains", String.class, int.class));
@ -166,9 +166,9 @@ public class CompoundTag extends ReflectWrapper implements Tag {
* The values in the returned Map are not wrapped. * The values in the returned Map are not wrapped.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, ?> entries() { public Set<Map.Entry<String, ?>> entrySet() {
// we cannot easily wrap every value of the map without being able to synchronize the returned map with the wrapped map // we cannot easily wrap every value of the map without being able to synchronize the returned map with the wrapped map
return (Map<String, ?>) wrapReflectEx(() -> entries.invoke(__getRuntimeInstance())); return (Set<Map.Entry<String, ?>>) wrapReflectEx(() -> entrySet.invoke(__getRuntimeInstance()));
} }
public int size() { public int size() {
return (int) wrapReflectEx(() -> size.invoke(__getRuntimeInstance())); return (int) wrapReflectEx(() -> size.invoke(__getRuntimeInstance()));

View File

@ -1,5 +1,6 @@
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server; package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.RegistryAccess;
import fr.pandacube.lib.reflect.Reflect; import fr.pandacube.lib.reflect.Reflect;
import fr.pandacube.lib.reflect.ReflectClass; import fr.pandacube.lib.reflect.ReflectClass;
import fr.pandacube.lib.reflect.ReflectMethod; import fr.pandacube.lib.reflect.ReflectMethod;
@ -11,11 +12,16 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
public class MinecraftServer extends ReflectWrapper { public class MinecraftServer extends ReflectWrapper {
public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.server.MinecraftServer")); public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.server.MinecraftServer"));
private static final ReflectMethod<?> getPlayerList = wrapEx(() -> REFLECT.method("getPlayerList")); private static final ReflectMethod<?> getPlayerList = wrapEx(() -> REFLECT.method("getPlayerList"));
public static final ReflectMethod<?> registryAccess = wrapEx(() -> REFLECT.method("registryAccess"));
public PlayerList getPlayerList() { public PlayerList getPlayerList() {
return wrap(wrapReflectEx(() -> getPlayerList.invoke(__getRuntimeInstance())), PlayerList.class); return wrap(wrapReflectEx(() -> getPlayerList.invoke(__getRuntimeInstance())), PlayerList.class);
} }
public RegistryAccess registryAccess() {
return wrap(wrapReflectEx(() -> registryAccess.invoke(__getRuntimeInstance())), RegistryAccess.class);
}
protected MinecraftServer(Object obj) { protected MinecraftServer(Object obj) {
super(obj); super(obj);
} }

View File

@ -1,21 +1,35 @@
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.world; package fr.pandacube.lib.paper.reflect.wrapper.minecraft.world;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.HolderLookupProvider;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.RegistryAccess;
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.Tag;
import fr.pandacube.lib.reflect.Reflect; import fr.pandacube.lib.reflect.Reflect;
import fr.pandacube.lib.reflect.ReflectClass; import fr.pandacube.lib.reflect.ReflectClass;
import fr.pandacube.lib.reflect.ReflectMethod; import fr.pandacube.lib.reflect.ReflectMethod;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
import org.bukkit.Bukkit;
import java.util.Optional;
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
public class ItemStack extends ReflectWrapper { public class ItemStack extends ReflectWrapper {
public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.world.item.ItemStack")); public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.world.item.ItemStack"));
private static final ReflectMethod<?> of = wrapEx(() -> REFLECT.method("of", CompoundTag.REFLECT.get())); private static final ReflectMethod<?> parse = wrapEx(() -> REFLECT.method("parse", HolderLookupProvider.REFLECT.get(), Tag.REFLECT.get()));
private static final ReflectMethod<?> save = wrapEx(() -> REFLECT.method("save", CompoundTag.REFLECT.get())); private static final ReflectMethod<?> saveWithPrefix = wrapEx(() -> REFLECT.method("save", HolderLookupProvider.REFLECT.get(), Tag.REFLECT.get()));
private static final ReflectMethod<?> save = wrapEx(() -> REFLECT.method("save", HolderLookupProvider.REFLECT.get()));
public static ItemStack of(CompoundTag nbt) { @SuppressWarnings("unchecked")
return wrap(wrapReflectEx(() -> of.invokeStatic(unwrap(nbt))), ItemStack.class); public static Optional<ItemStack> parse(HolderLookupProvider registries, Tag nbt) {
return ((Optional<Object>) wrapReflectEx(() -> parse.invokeStatic(unwrap(registries), unwrap(nbt))))
.map(o -> wrap(o, ItemStack.class));
}
public static Optional<ItemStack> parse(Tag nbt) {
return parse(getRegistries(), nbt);
} }
@ -24,7 +38,26 @@ public class ItemStack extends ReflectWrapper {
} }
public CompoundTag save(CompoundTag nbt) { public Tag save(HolderLookupProvider registries, Tag prefix) {
return wrap(wrapReflectEx(() -> save.invoke(__getRuntimeInstance(), unwrap(nbt))), CompoundTag.class); return wrap(wrapReflectEx(() -> saveWithPrefix.invoke(__getRuntimeInstance(), unwrap(registries), unwrap(prefix))), Tag.class);
}
public Tag save(HolderLookupProvider registries) {
return wrap(wrapReflectEx(() -> save.invoke(__getRuntimeInstance(), unwrap(registries))), Tag.class);
}
public Tag save(Tag prefix) {
return save(getRegistries(), prefix);
}
public Tag save() {
return save(getRegistries());
}
private static RegistryAccess getRegistries() {
return wrap(Bukkit.getServer(), CraftServer.class).getServer().registryAccess();
} }
} }

View File

@ -6,18 +6,23 @@ import fr.pandacube.lib.reflect.ReflectClass;
import fr.pandacube.lib.reflect.ReflectMethod; import fr.pandacube.lib.reflect.ReflectMethod;
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
import java.util.Optional;
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
public class PlayerDataStorage extends ReflectWrapper { public class PlayerDataStorage extends ReflectWrapper {
public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.world.level.storage.PlayerDataStorage")); public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.world.level.storage.PlayerDataStorage"));
public static final ReflectMethod<?> getPlayerData = wrapEx(() -> REFLECT.method("getPlayerData", String.class)); // Craftbukkit method public static final ReflectMethod<?> load = wrapEx(() -> REFLECT.method("load", String.class, String.class));
/** /**
* @param playerName the name of the player: used for loading error message and of offline UUID generation.
* @param playerId UUID of a player as it is used to name the player data file (UUID.toString()) * @param playerId UUID of a player as it is used to name the player data file (UUID.toString())
*/ */
public CompoundTag getPlayerData(String playerId) { @SuppressWarnings("unchecked")
return wrap(wrapReflectEx(() -> getPlayerData.invoke(__getRuntimeInstance(), playerId)), CompoundTag.class); public Optional<CompoundTag> load(String playerName, String playerId) {
return ((Optional<Object>) wrapReflectEx(() -> load.invoke(__getRuntimeInstance(), playerId)))
.map(o -> wrap(o, CompoundTag.class));
} }

View File

@ -116,10 +116,9 @@ public record PlayerDataWrapper(CompoundTag data) {
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
CompoundTag itemTag = list.getCompound(i); CompoundTag itemTag = list.getCompound(i);
int nbtSlot = itemTag.getByte("Slot") & 255; int nbtSlot = itemTag.getByte("Slot") & 255;
ItemStack is = filterStack(CraftItemStack.asCraftMirror(itemTag)); fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.parse(itemTag)
if (is != null) { .map(nms -> filterStack(CraftItemStack.asCraftMirror(nms)))
stacks.put(nbtSlot, CraftItemStack.asCraftMirror(itemTag)); .ifPresent(is -> stacks.put(nbtSlot, is));
}
} }
return stacks; return stacks;
} }
@ -148,9 +147,8 @@ public record PlayerDataWrapper(CompoundTag data) {
if (stack == null) if (stack == null)
continue; continue;
CompoundTag itemTag = new CompoundTag(); CompoundTag itemTag = new CompoundTag();
CraftItemStack.asNMSCopy(is.getValue()).save(itemTag);
itemTag.putByte("Slot", is.getKey().byteValue()); itemTag.putByte("Slot", is.getKey().byteValue());
list.add(list.size(), itemTag); list.add(list.size(), CraftItemStack.asNMSCopy(is.getValue()).save(itemTag));
} }
data.put(key, list); data.put(key, list);
} }