Cannot get Bukkit entity from EntityEgg exception in WrappedDataWatcher.deepClone()
bo3tools opened this issue ยท 2 comments
Describe the bug
An exception is thrown when a deepClone method is called on a WrappedDataWatcher.
[ERROR]: [ProtocolPlugin] Unhandled exception occured in onPacketSending(PacketEvent) for ProtocolPlugin
java.lang.IllegalArgumentException: Cannot get Bukkit entity from EntityEgg['Thrown Egg'/126, uuid='b5a2a865-e43c-4ed1-848e-56b115e8b7ae', l='~NULL~', x=0.00, y=0.00, z=0.00, cx=0, cz=0, tl=0, v=false, d=false]
at com.comphenix.protocol.utility.MinecraftReflection.getBukkitEntity(MinecraftReflection.java:370) ~[?:?]
at com.comphenix.protocol.wrappers.WrappedDataWatcher.getEntity(WrappedDataWatcher.java:572) ~[?:?]
at com.comphenix.protocol.wrappers.WrappedDataWatcher.deepClone(WrappedDataWatcher.java:532) ~[?:?]
...
Caused by: java.lang.RuntimeException: An internal error occured.
at com.comphenix.protocol.reflect.accessors.DefaultMethodAccessor.invoke(DefaultMethodAccessor.java:20) ~[?:?]
at com.comphenix.protocol.utility.MinecraftReflection.getBukkitEntity(MinecraftReflection.java:368) ~[?:?]
...
Caused by: java.lang.NullPointerException
at net.minecraft.server.v1_16_R1.Entity.getBukkitEntity(Entity.java:88) ~[patched_1.16.1.jar:git-Paper-68]
at jdk.internal.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at com.comphenix.protocol.reflect.accessors.DefaultMethodAccessor.invoke(DefaultMethodAccessor.java:16) ~[?:?]
at com.comphenix.protocol.utility.MinecraftReflection.getBukkitEntity(MinecraftReflection.java:368) ~[?:?]
...
[ERROR]: Parameters:
net.minecraft.server.v1_16_R1.PacketPlayOutEntityMetadata@68208ba2[
a=74
b=[net.minecraft.server.v1_16_R1.DataWatcher$Item@69f29af5, net.minecraft.server.v1_16_R1.DataWatcher$Item@5159daca, net.minecraft.server.v1_16_R1.DataWatcher$Item@55a83fd6, net.minecraft.server.v1_16_R1.DataWatcher$Item@7366068a, net.minecraft.server.v1_16_R1.DataWatcher$Item@e3e0f21, net.minecraft.server.v1_16_R1.DataWatcher$Item@112e1ba6, net.minecraft.server.v1_16_R1.DataWatcher$Item@56cc0da, net.minecraft.server.v1_16_R1.DataWatcher$Item@46fdc4ab]
]
To Reproduce
Use the following example, then observe a dropped item.
protocolManager.addPacketListener(new PacketAdapter(params) {
@Override
public void onPacketSending(PacketEvent event) {
PacketContainer packet = event.getPacket();
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
Entity entity = packet.getEntityModifier(event).read(0);
if (entity.getType() == EntityType.DROPPED_ITEM) {
WrappedDataWatcher watcher = new WrappedDataWatcher(packet.getWatchableCollectionModifier().read(0));
ItemStack itemStack = watcher.getItemStack(7);
if (itemStack != null) {
watcher.deepClone();
// ...
}
}
}
}
}
Expected behavior
The exception to not be thrown.
Version Info
https://pastebin.com/82UCAPNV
Does this happen with entities other than eggs? or other dropped items? What about in 1.15?
Does this happen with entities other than eggs? or other dropped items? What about in 1.15?
This happens regardless of the item or entity whenever a WrappedDataWatcher is deepCloned. I believe the egg comes from this implementation:
Which is then used here:
For context, I wanted to make dropped items appear differently on the client side but I've encountered an issue where different clients see how items appear for other clients -- let's say I'm "disguising" a specific item type, stick, as an apple for client A, as a melon for client B; and other clients are unaffected.
I've noticed that sometimes client B sees an apple instead of a melon even though the information deciding what item type you're getting is calculated separately. My guess is that behind the scenes the server only generates one packet per update and it passes it for every client:
clients = [a, b, c, d]
on update:
packet = new_metadata_packet(...)
for (client in clients):
client.send_packet(packet)
instead of
on update:
for (client in clients):
packet = new_metadata_packet(...)
client.send_packet(packet)
I think this should be fixed by deepCloning the PacketContainer but this doesn't help. Instead I found this example by comphenix where he solves exactly my problem.
Here he clones the DataWatcher instead:
// Note: See https://gist.github.com/aadnk/7420881
// See if we are modifying an item stack
if (packet.getEntityModifier(event).read(0) instanceof Item) {
WrappedDataWatcher watcher = new WrappedDataWatcher(packet.getWatchableCollectionModifier().read(0));
ItemStack stack = watcher.getItemStack(10);
if (stack != null) {
// You have to clone the watcher, unfortunately
watcher = watcher.deepClone();
watcher.removeObject(10); // Not needed after build #148
watcher.setObject(10, processItemStack(stack));
// Save the modification
packet.getWatchableCollectionModifier().write(0, watcher.getWatchableObjects());
}
}
I tried to use it but it generates an exception in the current version.