Compare commits
5 Commits
718816599d
...
0c012c8747
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c012c8747 | ||
|
|
f090fa8eb1 | ||
|
|
55510cf46c | ||
|
|
14afa59833 | ||
|
|
0d483a2bd9 |
6
Protocol/Const.cs
Normal file
6
Protocol/Const.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace stick.plugins.kcpable.Protocol;
|
||||||
|
|
||||||
|
public static class Const
|
||||||
|
{
|
||||||
|
public const byte version = 1;
|
||||||
|
}
|
||||||
13
Protocol/ConvGenerator.cs
Normal file
13
Protocol/ConvGenerator.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using Steamworks;
|
||||||
|
|
||||||
|
namespace stick.plugins.kcpable.Protocol;
|
||||||
|
|
||||||
|
public class ConvGenerator(CSteamID local, CSteamID remote, int channel)
|
||||||
|
{
|
||||||
|
readonly ulong smaller = Math.Min(local.m_SteamID, remote.m_SteamID);
|
||||||
|
readonly ulong bigger = Math.Max(local.m_SteamID, remote.m_SteamID);
|
||||||
|
readonly int channel = channel;
|
||||||
|
private ulong Combined => smaller ^ (bigger << 1) ^ ((ulong)channel << 2); // 位交错
|
||||||
|
public uint Generate() => (uint)(Combined & 0xFFFFFFFF) ^ (uint)(Combined >> 32); // 全部64位异或压缩到32位的conv
|
||||||
|
}
|
||||||
13
Protocol/Hello.cs
Normal file
13
Protocol/Hello.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace stick.plugins.kcpable.Protocol;
|
||||||
|
|
||||||
|
// 在懒得发的原有网络栈上握手使用的Hello消息
|
||||||
|
public class Hello
|
||||||
|
{
|
||||||
|
public byte version = Const.version;
|
||||||
|
public void Send(P2PPackageHandler p2pHandler, NetConnection user)
|
||||||
|
{
|
||||||
|
p2pHandler.SendSocketP2PPacketToUser(user, [version], (P2PPackageHandler.MsgType)MsgType.Hello);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Protocol/MsgType.cs
Normal file
9
Protocol/MsgType.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace stick.plugins.kcpable.Protocol;
|
||||||
|
|
||||||
|
// 这里是在懒得发的原有网络栈上发消息使用的msgtype
|
||||||
|
// 0-38 被懒得发用了
|
||||||
|
// 目前应该暂时只需要一个 Hello ,其它都走 kcp 内部了
|
||||||
|
public enum MsgType : byte
|
||||||
|
{
|
||||||
|
Hello = 75, // 'K'
|
||||||
|
}
|
||||||
69
plan.md
Normal file
69
plan.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Kcpable
|
||||||
|
|
||||||
|
本项目旨在改善柴的联机延迟
|
||||||
|
|
||||||
|
*本项目灵感来源于[`streamable`](https://mcp-docs.cn/specification/2025-11-25/basic/transports#streamable-http)*
|
||||||
|
|
||||||
|
## 优势
|
||||||
|
|
||||||
|
### 降低延迟
|
||||||
|
|
||||||
|
使用[`kcp`](https://github.com/skywind3000/kcp)覆盖在`steamworks`的`udp`栈上,用少量冗余带宽换取更低的延迟
|
||||||
|
|
||||||
|
### 向下兼容
|
||||||
|
|
||||||
|
本插件会采用类似`streamable`的方式进行握手,这是与使用`tcp`栈发包的游戏原始行为并行的,若握手失败则什么都不做,非常透明
|
||||||
|
|
||||||
|
## 协议
|
||||||
|
|
||||||
|
本协议与项目同名,称为`Kcpable`,重点在`-able`,旨在简单可靠地完成协议升级,同时保持对不支持协议的客户端的透明性(~~其实没有那么透明,但是懒得发帮我们把识别不出来的包丢掉了~~)
|
||||||
|
|
||||||
|
存在本地和对端两个游戏客户端,在p2p的背景下两者是等价的,都有如下两种状态:
|
||||||
|
|
||||||
|
- 支持`kcp`协议
|
||||||
|
- 不支持`kcp`协议
|
||||||
|
|
||||||
|
考虑到后者大部分情况下为原版游戏/原版网络栈,我们无法对其进行修改,因此后者对于任何原游戏协议外的数据包的处理方式可以看做直接丢弃,所以场景简化为:
|
||||||
|
|
||||||
|
- 本地客户端
|
||||||
|
- 支持`kcp`协议
|
||||||
|
- 对端客户端
|
||||||
|
- 支持`kcp`协议
|
||||||
|
- 不支持`kcp`协议
|
||||||
|
|
||||||
|
显而易见的,本地应当主动发起握手,但是考虑到本项目的使用场景与`streamable`还不一样,是P2P的,因此决定简化为:
|
||||||
|
|
||||||
|
- 主动行为(发送)
|
||||||
|
- 进入房间时向所有人发送请求协议升级的握手包~~(考虑重复三次以规避高丢包场景)~~
|
||||||
|
*还是算了,因为默认的tcp本来就会保证送达,改成超时重传,最多重传三次吧*
|
||||||
|
- 房间里有新人进入时亦然
|
||||||
|
- 同时增加发送握手包快捷键以主动向所有人发送握手包(加上频率限制防止手动flood)
|
||||||
|
- 被动行为(接收)
|
||||||
|
- 若在收到合法握手包:
|
||||||
|
- 若与来源客户端正使用`tcp`连接则对其启用`kcp`连接
|
||||||
|
- 若与来源客户端已使用`kcp`连接,则无视
|
||||||
|
- 其余均无视,走游戏默认行为
|
||||||
|
|
||||||
|
也就是只发送类似`hello`的包,但是不使用`ack`,因为可以默认收到了合法`hello`就是支持协议
|
||||||
|
|
||||||
|
目前暂时不考虑协议降级
|
||||||
|
|
||||||
|
### conv协商
|
||||||
|
|
||||||
|
直到看到了`kcp`库的文档我才知道conv是需要协商的,他相当于一个uuid,不过我觉得可以通过约定预协商
|
||||||
|
|
||||||
|
conv的划分应该精确到单人单channel
|
||||||
|
|
||||||
|
1. 取两边steamid
|
||||||
|
2. 按大小分成bigger和smaller
|
||||||
|
3. 取需要发送到的目标channel(懒得发只定义了两个)
|
||||||
|
4. 计算
|
||||||
|
|
||||||
|
``` csharp
|
||||||
|
private ulong Combined => smaller ^ (bigger << 1) ^ ((ulong)channel << 2); // 位交错
|
||||||
|
public uint Generate() => (uint)(Combined & 0xFFFFFFFF) ^ (uint)(Combined >> 32); // 全部64位异或压缩到32位的conv
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其它
|
||||||
|
|
||||||
|
考虑在建立了`kcp`连接的玩家名后添加紫色`[K]`以标识
|
||||||
Reference in New Issue
Block a user