MirageNet / Mirage

Easy to use high performance Network library for Unity 3d
https://miragenet.github.io/Mirage/
MIT License
507 stars 63 forks source link

Where is the KCP transport #1042

Closed sekkit closed 2 years ago

sekkit commented 2 years ago

Try using Mirage in Unity. But found no KCP transport available

cxxpxr commented 2 years ago

Mirage has their own native udp socket. KCP is mirror only.

SoftwareGuy commented 2 years ago

KCP doesn't exist in Mirage. Use the native UDP Socket transport instead.

sekkit commented 2 years ago

But it's unreliable. Why not use TCP instead

cxxpxr commented 2 years ago

No it isn't, Mirage udp socket has built in reliability. KCP also has reliability and it is also UDP.

SoftwareGuy commented 2 years ago

@sekkit This is not the place for TCP vs UDP discussion. The discord is better for chatter like that.

As @cxxpxr has stated, KCP is based on the UDP protocol. That's a fact - one of the other reasons it's called KCP is because it's the name and implementation of reliability, fragmentation and sequencing that utilizes the low-level UDP protocol. It's still utilizing UDP at its core - denying that would be silly.

James-Frowen commented 2 years ago

KCP is just a reliability algorithm it is meant to reduce latency but at the cost of bandwidth. Where as Mirage's Socket layer has other feature too, like Notify algorithm to know if unreliable message are received or lost.

Some of the new features we are working on for Mirage use unreliable sends and use other techniques to make sure stuff say in sync.

As @SoftwareGuy mentinoed the discord is a good place to discuss this :) https://discordapp.com/invite/DTBPBYvexy

sgf commented 10 months ago

Latency is critical for gaming networks, and I doubt that a homemade ARQ protocol can be better than KCP.

James-Frowen commented 10 months ago

Latency is critical for gaming networks, and I doubt that a homemade ARQ protocol can be better than KCP.

KCP is just a reliable algorithm.

If you want low latency you need to use the unreliable channel and send the new data each frame, instead of re-sending old data that was not received. This is kinda oversimplifying it, but it is the basic idea.

sgf commented 10 months ago

If you want low latency you need to use the unreliable channel and send the new data each frame, instead of re-sending old data that was not received. This is kinda oversimplifying it, but it is the basic idea.

As any valuable data packet, unless the game can force it to give up, retransmission at the bottom is almost inevitable.

James-Frowen commented 10 months ago

As any valuable data packet, unless the game can force it to give up, retransmission at the bottom is almost inevitable.

There are other techniques to ensure valuable data there without re-sending the whole packet.

For example, with Transform data, you shouldn't resend packets that are slow or late. Instead, you should just send the new Transform data for that frame. This is because when the data arrives on the client side, the client only cares about the most recent data. So if you resend the previous frame and current frame data, the client will just discard the previous frame data and use the current frame. Even if you are interpolating between the previous and current frames, the re-sent previous frame would be too late to be used, and the client would just use the n-2 or n-3 data instead.

While Transform data is the most obvious use of the Unreliable channel instead of the Reliable one, it can also apply to any other data.

However, sending everything each frame isn't very bandwidth efficient. This is where techniques like delta compression come in, where you can just send the changed data vs the frame/tick that you know the client has received. For example, if you know the client has received tick n-6, you can send the delta vs that tick. There will be some redundancy in this, but it will have lower latency than a reliable channel where you have to re-send an entire packet if it is late or lost.

Many techniques like this still require the client to ACK what packets have been received or not, but that ACK isn't as time-sensitive as game data. This ACK (without resending) is a feature that Mirage's Transport has that algorithms like KCP don't have because they are purely just a reliable algorithm.

James-Frowen commented 10 months ago

Also most of the "KCP is lower latency" is measured vs TCP. This is because of how TCP works more than how KCP works. Most RUDP will be lower latency than TCP.

sgf commented 10 months ago

The method of discarding part of the data packets is not suitable for key frame data packets. At the same time, the scenario you describe seems to only apply to some intermediate frames (those moving frames that can be interpolated). However, attack frame data packets, attacked data packets, and chat data packets cannot be discarded. At the same time, perhaps it would be a better design to separate the transport-level protocol from the upper-layer application-level protocol.

James-Frowen commented 10 months ago

However, attack frame data packets, attacked data packets,

For something like this you'd layout your state so that you can re-send that data every frame (until acked) without using too much bandwidth. For example, instead of sending a Reliable RPC saying "player 1 attacked", you can have network state that says when the player can attack next, and the client can infer that an attack took place when that changes.

and chat data packets cannot be discarded.

latency for chat isn't important so even TCP would be acceptable for that.

At the same time, perhaps it would be a better design to separate the transport-level protocol from the upper-layer application-level protocol.

Mirage's transport does this, It has a Notify channel that acts like the unreliable channel, expect gives Received/Lost callbacks so the high level can easily know what data was received. The the high level can then work out what needs to be sent next frame based on what the current state is, and the state that it knows the client has.

James-Frowen commented 10 months ago

The basic idea is you can re-send the data, but you shouldn't resend the whole reliable packet.

Any reliable channel (TCP, KCP, Mirage reliable channel), all have the problem with Head-of-line blocking. which will be the biggest cause of latency when a packet is lost.

This is why in games where latency is important you should avoid the reliable channel where possible

sgf commented 10 months ago

Any reliable channel (TCP, KCP, Mirage reliable channel), all have the problem with Head-of-line blocking. which will be the biggest cause of latency when a packet is lost.

Only the streaming-based will have the problem of Head-of-line blocking. If it is message-based, even if the previous packet is not received completely, it will not affect the receipt of subsequent packets.

James-Frowen commented 10 months ago

Only the streaming-based will have the problem of Head-of-line blocking. If it is message-based, even if the previous packet is not received completely, it will not affect the receipt of subsequent packets.

The reliable channel is reliable and ordered like TCP, it does have the same problem of Head-of-line blocking.

Packets that arrive out of order will be held until previous packets also arrive. If a packet is lost then the receiver will need to wait for re-send, It will then be given to the high level in the order they were sent.

KCP and other RUDP protocols attempt to mimic TCP, but give you a lot of control how it is done. There are upsides and downsides. With KCP it has lower latency but higher bandwidth