-
-
Notifications
You must be signed in to change notification settings - Fork 201
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
base: master
Are you sure you want to change the base?
Conversation
PR is ready for review |
There was a problem hiding this 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
protocol/src/main/java/org/geysermc/mcprotocollib/network/packet/Packet.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/Session.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/Session.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/Session.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpFlowControlHandler.java
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ClientListener.java
Outdated
Show resolved
Hide resolved
// 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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ServerListener.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/Session.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/Session.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/Session.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpPacketCodec.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/protocol/MinecraftProtocol.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/protocol/MinecraftProtocol.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ServerListener.java
Show resolved
Hide resolved
…ion.java Co-authored-by: chris <github@onechris.mozmail.com>
…ecraftProtocol.java Co-authored-by: chris <github@onechris.mozmail.com>
…ecraftProtocol.java Co-authored-by: chris <github@onechris.mozmail.com>
This replicates the same approach Mojang uses in their networking code.
Race conditions and weird disconnects are fixed. This PR can be merged. |
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpClientSession.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpServer.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpClientSession.java
Outdated
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/TcpPacketCodec.java
Show resolved
Hide resolved
protocol/src/main/java/org/geysermc/mcprotocollib/network/tcp/DropPacketFilter.java
Outdated
Show resolved
Hide resolved
…TcpServer.java Co-authored-by: chris <github@onechris.mozmail.com>
// 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. |
There was a problem hiding this comment.
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?
if (keepAlivePacket.getPingId() == this.lastPingId) { | ||
long time = System.currentTimeMillis() - this.lastPingTime; | ||
session.setFlag(MinecraftConstants.PING_KEY, time); | ||
KeepAliveState currentKeepAliveState = this.keepAliveState; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What specifically is this being cached to a variable for? The field value seems to be mutated when updating the keep alive, but replaced on login and config start/end.
If we are trying to prevent races with the keep alive thread, have we considered making KeepAliveState
immutable?
Also, could keepAlivePending
be replaced with the field being null when not pending, and have the field be volatile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is coded closer to mojangs impl.
The pending field and other fields are part of the commonpacketlistener. And each protocol state keeps track of separate keepalives.
protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ServerListener.java
Outdated
Show resolved
Hide resolved
# Conflicts: # protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ClientListener.java # protocol/src/main/java/org/geysermc/mcprotocollib/protocol/ServerListener.java
@@ -84,7 +90,8 @@ public MinecraftProtocol(PacketCodec codec) { | |||
this.codec = codec; | |||
this.targetState = ProtocolState.STATUS; | |||
|
|||
this.setState(ProtocolState.HANDSHAKE); | |||
this.setInboundState(ProtocolState.HANDSHAKE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we could just have a setState/setStates method just for convenience.
These changes are necessary to avoid race-conditions in the code and to prepare the codebase for ViaVersion support.