#EntityMetadata packet and data watchers

1 messages · Page 1 of 1 (latest)

stable mango
#

I'd like to change some entity metadata (custom name visible) and send it to only one client using a packet. I'm aware that the packet constructor takes a data watcher object and there is a static field in the Entity.class

My question is how do I get a fresh data watcher? Something like this would actually modify the entity which I don't want:java DataWatcher dw = ((CraftEntity) entity).getHandle().getDataWatcher(); dw.set(...)(oh, and, I've wanted to see how setCustomNameVisible method works, but there's no source code I can see for some reason)

astral cliff
#

DataWatcher? Are you using an ancient version, or not using mojang maps?

stable mango
#

eh, I guess I'm screwed

#

1.16.5

#

maybe it's called SynchedEntityData for yall

astral cliff
#

yeah can't you just create a new instance of that?

stable mango
#

it takes the entity as a constructor
wouldn't that make the data watcher modify the entity too?

astral cliff
#

maybe, I'm not sure, but it's worth a try

stable mango
#

I actually managed to pull out the DataWatcher.Item that i'm looking for```java
List<DataWatcher.Item<?>> items = ((CraftLivingEntity) entity).getHandle().getDataWatcher().c(); // .getAll()
if (items != null) {
for (DataWatcher.Item<?> item : items) {
// index 3 is "is custom name visible"
if (item.a().a() == 3) { // item.getAccessor().getId()
// this is unchecked cast, but sure works because entity is LivingEntity
DataWatcher.Item<Boolean> newItem = (DataWatcher.Item<Boolean>) item.d(); // item.copy()
newItem.a(false); // item.setValue(false)

            PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadata();
            FieldUtils.writeField(packet, "a", entity.getEntityId(), true);
            FieldUtils.writeField(packet, "b", List.of(newItem), true);
            ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
            player.sendMessage("Sent packet to hide name for entity " + entity.getEntityId());
            set.remove(entity.getEntityId());
            return;
        }
    }
}```
#

but yeah I'll try instantiating a new one

#

do you by any chance know why doesn't the decompiler show code for craftbukkit methods?

#
  // IntelliJ API Decompiler stub source generated from a class file
  // Implementation of methods is not available```
astral cliff
#

hm it works fine for me

stable mango
#

that's nms

#

try
org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity (it's abstract class, but go under setCustomNameVisible and look for implementations)

astral cliff
#

works fine too

stable mango
#

🤨

astral cliff
#

no idea why it doesn't work for you :/

#

have you tried to disable the mc dev plugin lol

#

that causes 99% of issues in IJ

stable mango
#

wait i forgot i even have it

#

(updated to 2023.2 few days ago)

#

yeah it shows the code now lmao

#

ty

stable mango
stable mango
#

unfortunately it doesn't hide the custom name

DataWatcherObject<Boolean> dwobj = (DataWatcherObject<Boolean>) FieldUtils.readStaticField(net.minecraft.server.v1_16_R3.Entity.class, "ar");
        
DataWatcher dwNew = new DataWatcher(((CraftLivingEntity) entity).getHandle());
dwNew.register(dwobj, true);
dwNew.set(dwobj, true);
PacketPlayOutEntityMetadata pckt = new PacketPlayOutEntityMetadata(entity.getEntityId(), dwNew, true);
((CraftPlayer) player).getHandle().playerConnection.sendPacket(pckt);
set.add(entity.getEntityId()); // keeps track of which entities'custom names are visible to the player
player.sendMessage("Sent packet to show entity " + entity.getEntityId());```
#

i'm now trying to get the DataWatcherObject<Boolean> directly from the entity class but struggling with reflection: java.lang.IllegalArgumentException: Cannot locate field ar on class net.minecraft.server.v1_16_R3.Entity

astral cliff
#

hm sorry no clue

stable mango
#

its alright

#

could you by any chance spot the issue here?

astral cliff
#

in theory... you can ofc always construct the packet from the FriendlyByteBuf

stable mango
#
DataWatcherObject<Boolean> dwobj = (DataWatcherObject<Boolean>) FieldUtils.readStaticField(net.minecraft.server.v1_16_R3.Entity.class, "ar");```
astral cliff
#

then check wiki.vg for the actual fields required

stable mango
#

you mean convert bytes into the packet?

astral cliff
#

yeah well, one sec

stable mango
#

that works too

#

(i was in doubt of that because of encryption and stuff)

astral cliff
#

basiucally this. you'd create a FriendlyByteBuf or whatever it's called, then you write the first field (writeByte(0) for the animation or what's it called), then you write an int for the air ticks, etc. the fourth field is "isCustomNameVisible"

#

that way you don't need any actual entity data whatsoever

#

ofc that's going to be a bit annoying but this would definitely work

stable mango
astral cliff
stable mango
#

so i believe this would be packet id, then entity id as a varint, then 3 (for that property), then 7 (meaning that it's a boolean), then 1 (probably??) and then 0xff stating it's the end

stable mango
#

how would I get the raw bytes of a packet? (ik each packet has methods for that)

astral cliff
#

actually the opposite seems to be true, the constructor that takes in a bytebuf puts it back together in a List<DataValue>

stable mango
#

yeah, for me I have to use an empty constructor and then call one of these (it's a friendlybytebuf)

#

it doesn't include the packet id anywhere though

#

one sec

astral cliff
#

the id is coming from the packet's id() method

#

you get the whole bytes from a packet through the write(FriendlyByteBuf) method

stable mango
#

it's the entity id not packet id

#

I'm confused

#

what do I pass to the constructor of FriendlyByteBuf?

astral cliff
#

oh yikes I'm stupid

stable mango
#

it has to be io.netty.ByteBuf and copilot autocompleted to this java new PacketDataSerializer(Unpooled.buffer());

astral cliff
#

the packet ID is extracted in Connection#sendPacket through ConnectionProtocol#getProtocolForPacket

stable mango
stable mango
# astral cliff

so while the packet serializer won't give me packet length and packet id, I don't need them, right?

astral cliff
#

correct

stable mango
#

okay, i'll now test with protocollib what does the data look like

#

ah io.netty.handler.codec.DecoderException: ByteArray with size 181 is bigger than allowed 65 at net.minecraft.server.v1_16_R3.PacketDataSerializer.b(PacketDataSerializer.java:101) ~[patched_1.16.5.jar:git-Purpur-1171] at net.minecraft.server.v1_16_R3.PacketDataSerializer.a(PacketDataSerializer.java:94) ~[patched_1.16.5.jar:git-Purpur-1171]``````java PacketDataSerializer friendlybytebuf = new PacketDataSerializer(Unpooled.buffer()); packet.b(friendlybytebuf); String rawPacketData = ABCUtils.bytesToHex(friendlybytebuf.a());I still do believe the problem is in how i'm handling the friendly bytebuf

#

alright I found out about the existence of ByteBufUtil and got the data of this packet that changes, the bytes 03 07 01 ff are correct, time to get this done now