Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split incoming/outgoing packet registry, transition protocol states correctly #841

Merged
merged 58 commits into from
Oct 8, 2024

Conversation

AlexProgrammerDE
Copy link
Contributor

@AlexProgrammerDE AlexProgrammerDE commented Jul 20, 2024

These changes are necessary to avoid race-conditions in the code and to prepare the codebase for ViaVersion support.

@AlexProgrammerDE AlexProgrammerDE marked this pull request as draft July 20, 2024 20:35
@AlexProgrammerDE AlexProgrammerDE marked this pull request as ready for review July 26, 2024 07:52
@AlexProgrammerDE
Copy link
Contributor Author

PR is ready for review

Copy link
Member

@Konicai Konicai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, especially like the cleanup in the listeners

Comment on lines +182 to +184
// The developer who sends ClientboundStartConfigurationPacket needs to setOutboundState to CONFIGURATION
// after sending the packet. We can't do it in this class because it needs to be a method call right after it was sent.
// Using nettys event loop to change outgoing state may cause differences to vanilla.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we not check for ClientboundStartConfigurationPacket in packetSent, and setOutboundState to CONFIGURATION there? packetSent should be invoked more or less right after the onSent callback would be?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have the developers explicitly switch them like in vanilla. The entire onSent thing is made because of that reason. Stuff in packetSent may be not be handled immediately because packets sometimes get handled on the event loop. However onSent is guaranteed to be handled inside the netty pipeline.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClientboundStartConfigurationPacket is not isPriority
therefore it gets handled on the event loop
so if you
send(ClientboundStartConfigurationPacket)
and
send(SomeConfigurationPacket)
as a developer right after each other, it'll error because the event loop is having a race condition with the netty pipeline
One other fix would be setting ClientboundStartConfigurationPacket as isPriority, but I don't wanna touch that with this PR
onSent allows the dev to change the state the next packets gets decoded with immediately without the chance of race conditions because of off-pipeline processing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry if I don't understand.

Stuff in packetSent may be not be handled immediately because packets sometimes get handled on the event loop. However onSent is guaranteed to be handled inside the netty pipeline.

I read them as being called right after eachother? https://github.com/AlexProgrammerDE/MCProtocolLib/blob/2b310d2618f23127640a85194623126b1eef594b/protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpSession.java#L271-L275

Also, isPriority doesn't seem to apply to outbound packets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah you're right. I was thinking too much from the clients perspective that all packets are in the event loop. Would still be weird though to add back packetSent...
It makes it harder to compare logic with vanilla.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does have the distinction now that any packets handled by ServerListener in the packetSent event are packets that have been sent by the library user, not internal MCPL. I think its worth it to not introduce state switching to the library user for a single case (if i understand correctly)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now not even possible anymore since explicit flushes after the writeAndFlush are needed due to race conditions. The code doesn't use onSent anymore for state switching. Developers need to manually switch state after sending the packet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would still be weird though to add back packetSent...
It makes it harder to compare logic with vanilla.

Minecraft is also the maintainer AND user of its network code—I think it is worth it here for the sake of ease of use.

Minecraft has a method for sending ClientboundStartConfigurationPacket and switching outbound protocol, but I'm not sure this project's structure would facilitate something like that?

Copy link
Contributor Author

@AlexProgrammerDE AlexProgrammerDE Sep 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate?
What I'm saying is that the calling thread for the switchOutbound matters. Always forcing it to be inside netty threads could lead to deadlocks if the event loop is used for the inbound processing.

@Konicai Konicai changed the title Implement incoming/outgoing packet registry spliitting to exactly replicate vanilla behaviour. Split incoming/outgoing packet registry, transition protocol states correctly Jul 28, 2024
This replicates the same approach Mojang uses in their networking code.
@AlexProgrammerDE
Copy link
Contributor Author

Race conditions and weird disconnects are fixed. This PR can be merged.

Comment on lines +182 to +184
// The developer who sends ClientboundStartConfigurationPacket needs to setOutboundState to CONFIGURATION
// after sending the packet. We can't do it in this class because it needs to be a method call right after it was sent.
// Using nettys event loop to change outgoing state may cause differences to vanilla.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would still be weird though to add back packetSent...
It makes it harder to compare logic with vanilla.

Minecraft is also the maintainer AND user of its network code—I think it is worth it here for the sake of ease of use.

Minecraft has a method for sending ClientboundStartConfigurationPacket and switching outbound protocol, but I'm not sure this project's structure would facilitate something like that?

# Conflicts:
#	protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ClientListener.java
#	protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ServerListener.java
@onebeastchris
Copy link
Member

As discussed on discord, being able to disable/suppress the packet en/decoding logging while in debug mode using e.g. markers as flags would be ideal.
Alternatively, the logging addition could get implemented in a separate PR to not block this PR further - IMO it's the only thing remaining

@AlexProgrammerDE
Copy link
Contributor Author

Should be able to be reviewed now. Added the markers.

@onebeastchris onebeastchris merged commit f846035 into GeyserMC:master Oct 8, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants