Files
Purpur/patches/server/0170-Add-unsafe-Entity-serialization-API.patch
BillyGalbreath 2d4611b790 Updated Upstream (Paper)
Upstream has released updates that appear to apply and compile correctly

Paper Changes:
453c7f05c Add ItemStack#displayName to get the formatted display name of an ItemStack (#5628)
4efe8b498 Update Java version warning (#5621)
e0a021ccc Add ItemStack#getTranslationKey() (#5616)
53d71b717 Add setPotionUseTimeLeft to Witch (#5597)
239935d18 Add Inventory#close (#5610)
29bf6cd41 Updated Upstream (CraftBukkit)
ad45f316c Add raw address to AsyncPlayerPreLoginEvent (#5614)
28865335a [Auto] Updated Upstream (CraftBukkit)
2021-05-13 14:58:16 -05:00

130 lines
7.6 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mariell Hoversholm <proximyst@proximyst.com>
Date: Sat, 9 Jan 2021 21:22:58 +0100
Subject: [PATCH] Add unsafe Entity serialization API
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/EntityTypes.java b/src/main/java/net/minecraft/world/entity/EntityTypes.java
index e1ef642f06078202fb782ac16b268e6429c5e202..778c981d4458957533fc3ac44095051b279c74e3 100644
--- a/src/main/java/net/minecraft/world/entity/EntityTypes.java
+++ b/src/main/java/net/minecraft/world/entity/EntityTypes.java
@@ -534,6 +534,7 @@ public class EntityTypes<T extends Entity> {
return this.bf.create(this, world);
}
+ public static Optional<Entity> loadEntityFixedData(NBTTagCompound nbtTagCompound, World world) { return a(nbtTagCompound, world); } // Purpur - OBFHELPER
public static Optional<Entity> a(NBTTagCompound nbttagcompound, World world) {
return SystemUtils.a(a(nbttagcompound).map((entitytypes) -> {
return entitytypes.a(world);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 4a70d657fd83627e8d66b52cb5f87381b43ad76a..af69023b241560031f6aa116561d7407b2502578 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1196,5 +1196,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public boolean isRidableInWater() {
return getHandle().isRidableInWater();
}
+
+ @Override
+ public boolean spawnAt(Location location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+ entity.world = ((CraftWorld) location.getWorld()).getHandle();
+ entity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ return !entity.valid && entity.world.addEntity(entity, spawnReason);
+ }
// Purpur end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index ed290f61ec5adcb3033c7cb7e0fcca8d9722c234..2ccceec865a44edfe606beac06508c30a5e398f0 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -410,9 +410,14 @@ public final class CraftMagicNumbers implements UnsafeValues {
Preconditions.checkNotNull(item, "null cannot be serialized");
Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized");
+ // Purpur start - rework NBT <-> bytes
+ return serializeNbtToBytes(CraftItemStack.asNMSCopy(item).save(new NBTTagCompound()), true);
+ }
+
+ public byte[] serializeNbtToBytes(NBTTagCompound compound, boolean addDataVersion) {
+ if (addDataVersion) compound.setInt("DataVersion", getDataVersion());
java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
- NBTTagCompound compound = (item instanceof CraftItemStack ? ((CraftItemStack) item).getHandle() : CraftItemStack.asNMSCopy(item)).save(new NBTTagCompound());
- compound.setInt("DataVersion", getDataVersion());
+ // Purpur end
try {
net.minecraft.nbt.NBTCompressedStreamTools.writeNBT(
compound,
@@ -425,26 +430,58 @@ public final class CraftMagicNumbers implements UnsafeValues {
return outputStream.toByteArray();
}
+ public static DynamicOpsNBT getDynamicOpsNbtInstance() { return DynamicOpsNBT.a; } // Purpur - OBFHELPER - keeping out of the class because it's FULL of decompile errors
@Override
public ItemStack deserializeItem(byte[] data) {
Preconditions.checkNotNull(data, "null cannot be deserialized");
Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing");
+ // Purpur start - rework NBT <-> bytes
+ NBTTagCompound compound = deserializeNbtFromBytes(data, true);
+ Dynamic<NBTBase> converted = DataConverterRegistry.getDataFixer().update(DataConverterTypes.ITEM_STACK, new Dynamic<>(getDynamicOpsNbtInstance(), compound), compound.getInt("DataVersion"), getDataVersion()); // TODO: obfhelper
+ return net.minecraft.world.item.ItemStack.fromCompound((NBTTagCompound) converted.getValue()).asBukkitMirror();
+ }
+
+ public NBTTagCompound deserializeNbtFromBytes(byte[] data, boolean verifyDataVersion) {
+ // Purpur end
try {
NBTTagCompound compound = net.minecraft.nbt.NBTCompressedStreamTools.readNBT(
new java.io.ByteArrayInputStream(data)
);
+ if (verifyDataVersion) { // Purpur
int dataVersion = compound.getInt("DataVersion");
Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!");
- Dynamic<NBTBase> converted = DataConverterRegistry.getDataFixer().update(DataConverterTypes.ITEM_STACK, new Dynamic<NBTBase>(DynamicOpsNBT.a, compound), dataVersion, getDataVersion());
- return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.fromCompound((NBTTagCompound) converted.getValue()));
+ } // Purpur
+ return compound; // Purpur
} catch (IOException ex) {
com.destroystokyo.paper.util.SneakyThrow.sneaky(ex);
throw new RuntimeException();
}
}
+ // Purpur start
+ @Override
+ public byte[] serializeEntity(org.bukkit.entity.Entity entity) {
+ Preconditions.checkNotNull(entity, "null cannot be serialized");
+ Preconditions.checkArgument(entity instanceof org.bukkit.craftbukkit.entity.CraftEntity, "non-CraftEntity cannot be serialized");
+ NBTTagCompound compound = new NBTTagCompound();
+ compound.setString("id", ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getMinecraftKeyString());
+ return serializeNbtToBytes(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().save(compound), true);
+ }
+
+ @Override
+ public org.bukkit.entity.Entity deserializeEntity(byte[] data, org.bukkit.World world) {
+ NBTTagCompound compound = deserializeNbtFromBytes(data, true);
+ Dynamic<NBTBase> converted = DataConverterRegistry.getDataFixer().update(DataConverterTypes.ENTITY, new Dynamic<>(getDynamicOpsNbtInstance(), compound), compound.getInt("DataVersion"), getDataVersion());
+ compound = (NBTTagCompound) converted.getValue();
+ compound.remove("UUID"); // Make the server make a new UUID for this entity; makes entities always spawnable.
+ return net.minecraft.world.entity.EntityTypes.loadEntityFixedData(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle())
+ .orElseThrow(() -> new IllegalArgumentException("unknown ID was found for the data; did you downgrade?"))
+ .getBukkitEntity();
+ }
+ // Pupur end
+
@Override
public String getTranslationKey(Material mat) {
if (mat.isBlock()) {