ProtocolSupport / ProtocolSupportPocketIssues

Issue-tracker for ProtocolSupport pocket edition.
6 stars 0 forks source link

"Sleepwalking" when waiting for all players to sleep #79

Closed magicus closed 5 years ago

magicus commented 5 years ago

When a player clicks on a bed to go to sleep, another player can see how she lies in the bed.

The player herself does not see this, though. The normal "waiting for other people to sleep, wanna chat?" screen is not appearing. Instead, she can walk around in the world, seemingly doing things. However, all changes are just local to the client, and will be lost when finally the other players go to sleep. When this happen, the player is suddenly "teleported" back to her bed.

Apart from this odd behaviour, a more problematic drawback is that there is no way for a PE player to cancel their sleep if not all players go to sleep.

This is not a new issue. It has been this way since my stable build from over a year ago.

magicus commented 5 years ago

I think I've managed to drill down this a bit. At least from the Nukkit code, I see that when a player goes to bed, the server sends a packet to the client. It's packet type 39, what we call SET_ENTITY_DATA. It should have the player's entity ID, and the metadata consisting of the property DATA_PLAYER_FLAGS (with value 26), and the flag field, which is a byte. When the player is sleeping, the bit in DATA_PLAYER_FLAG_SLEEP = 1 should be set to 1. As far as I can tell, the entire byte is 0 otherwise, and reset to zero (?) after waking up, so for all intents and purposes, we just need to send the value 1 for the DATA_PLAYER_FLAGS.

Not sure how to hook this properly into the code, though.

magicus commented 5 years ago

I made some attempt at just pushing a packet like this:

        ClientBoundPacketData serializer = ClientBoundPacketData.create(PEPacketIDs.SET_ENTITY_DATA);
        VarNumberSerializer.writeVarLong(serializer, entity.getId());
        VarNumberSerializer.writeVarInt(serializer, 1);  // size 1
        VarNumberSerializer.writeVarInt(serializer, DATA_PLAYER_FLAGS); // key
        VarNumberSerializer.writeVarInt(serializer, DATA_TYPE_BYTE);
        serializer.writeByte(1); // value == flag with sleeping bit set

at some place in the code, but it did not help. I'm not sure it was sent with the right timing, though.

colinrgodsey commented 5 years ago

think we're probably missing some of these flags: https://github.com/Hydreon/Steadfast2/blob/d5410be933c49ef1a8d4d6548fe8cf40111d0141/src/pocketmine/Player.php#L1110

magicus commented 5 years ago

@colinrgodsey Yes. That was what I based my patch above on. Or rather, the corresponding code in Nukkit. The method names are a bit deceptive, what they end up doing is actually sending the SET_ENTITY_DATA packet, not just setting a property.

Unfortunately, there's no simple way for us to detect that we should start sleeping in PSPE, at least not that I could discover. So I'm beginning to suspect that this will have to be Yet Another hack for PSPS.

Shevchik commented 5 years ago

The use bed java minecraft packet is sent when player should go to bed.

magicus commented 5 years ago

@Shevchik Thanks! That was just the input I needed to be able to pull this off...

magicus commented 5 years ago

Fixed.