0.引言
本文主要对最终幻想14中诗人演奏系统的服务器-客户端通信机制进行调查和探讨
主要内容将包括以下几方面
1.《最终幻想14》中的演奏通信格式
2.《最终幻想14》中的诗人演奏系统通信机制
3.从机制中得出的结论
如果你没有兴趣看详细的抓包过程,可以直接跳到第三章结论部分
1.《最终幻想14》中的演奏通信格式
客户端->服务器的演奏数据包
上图为客户端->服务器的演奏数据包
笔者解析如下
黄色部分为实际的演奏数据,数据格式3个Byte为一组,每个byte的组成为【Note间隔|Note|分隔符】
数据格式的一些规定如下
-
分隔符为0xFF
-
Note的范围在0x18-0x3C
-
Note间隔单位为毫秒
-
Note是以标准midi的note为准
诗人演奏ui中最左面的键被认为是Note 24(C1) 最右面的键被认为是Note 60(C4)
※存在特殊的Note 0xFE,含义为停止当前Note的演奏,例如笛子等乐器的停止
-
每组数据可能会不存在Note间隔或者Note,但是一定会存在分隔符。
例如没有按键时,演奏数据会是0xFA 0xFF,即间隔250ms
没有Note间隔的情况比较少见,一般发生在内容包的第一组数据上,为【Note|分隔符】
服务器->客户端的演奏数据包
上图为服务器->客户端的演奏数据包
不难看出结构一致,只有Opcode变为0x02A5,SourceID这里是变成了其他玩家的ID
2.《最终幻想14》中的诗人演奏系统通信机制
❎注意:以下内容仅为笔者根据目前现象进行的猜想,不保证为实际游戏程序的逻辑❎
2-1.键盘采集
- 当玩家在演奏UI的状态下,键盘采集的结果会转换成note并进行发送
- 键盘采集的速度/间隔与客户端的FPS有关,当60FPS时我们认为键盘按下并保持13.3ms才会被客户端采集到
- 客户端不仅仅会采集键盘的按下事件(KeyDown),也会采集键盘的抬起事件(KeyUp)
2-2.数据包组成
-
一般来说每个数据包包含过去500ms内的按键信息(休眠后的第一包除外,关于休眠请参考本章第3节)
-
没有的按键信息会用没有Note的【Note间隔|分隔符】的数据填充
-
我们假设现在Q键对应诗人演奏的最左面的键,当你按下Q键200ms后松开时,客户端会将该按键组包如下
【Note间隔|0x18(Note C1)|0xFF】【0xC8(间隔200ms)|0xFE(停止Note)|0xFF】
由于后续没有按键,填充空白到500ms,即整包数据为
【Note间隔|0x18|0xFF】【0xC8|0xFE|0xFF】【0xFA(250ms)|0xFF】【0x32(50ms)|0xFF】
2-3.通信机制
-
数据包的发送间隔为500ms
-
当一个按键包发送后,客户端还会持续发送数据包5次,保持2500ms连续,但是包内容没有任何Note
-
当5次数据包发送完毕仍然没有按键按下/抬起,客户端会进入一种类似休眠的状态
-
休眠时采集到按键后,会有1-500ms的唤醒时间,然后再回到500ms周期的发送循环中
即:休眠后的第一包数据中,包含了过去500-1000ms内的按键信息
如果从发送数据包的时间点倒推,其发送的按键时间是与现实时间一致的
但是该数据包直接发送到服务器上,因此相当于比500ms周期延迟了0-500ms
如上图所示,玩家在0秒时按下第一个按键,第3秒的时候演奏包不再发送,客户端进入休眠状态
在3.5秒时玩家进行按键,但是由于休眠机制的存在,本应在第4秒发送出的数据包实际在4.2秒左右发送出
而且如果有其他按键也会在原有的500毫秒循环上向后延迟0.2秒变为4.2秒,4.7秒,5.2秒……
-
当检测到上一个按键的键盘抬起事件时,也会发送一包数据。与按键按下时一样,这包数据也会使客户端唤醒 ,会重置2500ms的计数器。
例:玩家在0秒的时候按下按键,3秒后客户端休眠,在第4秒抬起按键,此时客户端会从休眠中唤醒,发送6包数据后再次进入休眠状态
-
以长笛为代表的管弦乐器,系统会在第4秒自动发送Note停止,因此即便一直按下按键,也无法在休眠后通过抬起按键使客户端唤醒
2-4 隐藏特性
-
演奏包的最小note间隔为0x64=100ms 等于150BPM下的16分音符(在4.4之前的版本为125ms)
-
演奏包中的停止Note(0xFE)只会检测最后一个按下按键的抬起事件
即:如果先按下A键,松开A键,再按下B键,松开B键,会产生4个事件
而如果先按下A键,再按下B键,松开A键松开B键,只会产生3个事件,松开A键的事件不会被当成数据包发送
-
由于本地延迟或其他因素,客户端发送的数据包有可能丢包,这种情况下客户端会在约200ms后重新发送一包演奏包。但是该重发不会影响500ms的周期。
3.结论及一些对策
- 如果玩家的演奏中间有超过3秒的停顿,那么每次从停顿中恢复时都会产生一个0-500ms的随机延迟(该延迟不会叠加,请自行思考原因)
- 如果玩家的停顿小于6秒,那么可以通过保持按键->在3秒处松开按键的方法保持演奏数据包连续
附录
本文使用的抓包工具为FFXIVMonReborn,可以点击这里下载