Skip to content

Conversation

@ShiraGawaAnri
Copy link

@ShiraGawaAnri ShiraGawaAnri commented Jul 5, 2022

  • Addressed Issue(s):
  • Server Mode:
    测试的PACKETVER : 20200304 推荐至少2018以上

测试的版本:RE(复兴后)

  • Description of Pull Request:

多个服务器玩家的跨服功能


日本官方已有先例,但实现方式略有不同,而且按照官方的实现有庞大的工作量。
因此,试着实现一个真正意义的跨服交互。


Ra架构简析

首先简析Ra目前多Map的架构
Login - Char - Map1(prt_fild08以外的地图) - Map2(prt_fild08)的地图
当玩家尝试进入prt_fild08的地图时,会按照以下流程

  1. 检索Map本身是否管理该地图并有正确的缓存,如果没有则进入2,否则进入3
  2. 从Char服检索prt_fild08处于哪个Map管理
  3. 向Char请求所得的 目标Map 的Ip和Port发送给客户端
  4. 进行save存储
  5. 发送封包使客户端连接指定的Map2

基于此架构下的新增功能

当加载此跨服功能后,除保留以上原架构外,利用Map与Char之间已经构建好的特性,实现了一个Map链接多个Char,
即A服与B服通过中立服,制造出一个交汇点,使得两个或多个服的玩家可以在其中,通过中立服的Map运算,达到多源服务器数据交互这一跨服行为。

※A服玩家是不可能到B服的,同理B服玩家也是。

测试场景

服务器 数据库 启动服务
A服 数据库A 3个主要EXE
B服 数据库B 3个主要EXE
中立服 数据库C 3个主要EXE

名词指代:
跨服 - 一般指A服<->中立服,B服<->中立服的行为。
源服 - 指在进行跨服前,来自哪个服务器(A,B,中立都有可能)

准备工作

测试时、请使用3份同样的源码以及DB

  1. 源码需要打开#Pandas_Cross_Server的功能,#Pandas_Fake_Id_Check_Debug可酌情关掉
  2. 编译后,首先修改中立服的conf/inter_athena.conf中的选项 cross_server: on,A服B服无需打开此选项
  3. 编辑中立服的base.conf,只加载server-1.conf
  4. 按实际情况编辑对应服务器的 *_ip等其他选项
  5. 测试时,请使用默认的cs_userid,cs_passwd
  6. 编辑A服的设置与server-1.conf中除server_id,server_name外的设置一一对应(假设目标是A服)
  7. 编辑A服maps_athena.conf,注释prt_fild08(假设目标是A服)
  8. 编辑中立服maps_athena.conf,只保留prt_fild08

运行测试

  1. 打开A服的3个EXE
  2. 打开中立服的3个EXE
  3. 待两边都没有出现等待连接XXX的字样以及报错信息
  4. 打开客户端,连接A服的IP和相应端口
  5. 正常登陆A服后,通过传送阵移动到prt_fild08 (当前测试数据则是首都南方向移动到南门)
  6. 正确配置的话此时将会移动到中立服的prt_fild08
  7. 如预期表现后关掉中立服,编辑中立服的base.conf,新增加载server-2.conf(注:server_id必须不一样)
  8. (参照时目标为B服)重复准备工作中的4-8步骤
  9. (目标为B服)重复运行测试的1-5步骤

※注意: 单机测试时A服、B服、中立服的各3个端口5121,6121,6900都必须不同
※注意: 更多可选的配置位于conf/battle/crossserver.conf中

预期结果: 玩家1(来源A服),玩家2(来源B服)于中立服中的prt_fild08见面,并且可以进行各种交互。

架构细节

  1. 为解决在中立服出现相同AID、CID的问题,实现了ID伪装转换。具体表现为在中立服时,AID、CID均被其对应的server_id作为前缀附加的原ID数字,通过数字ID能直接判断来自哪个服务器。
  2. 由于AID、CID与实际客户端存储的不同(※1)、需要在诸多地方上修改(※2)。
  3. Party、Guild、Clan等因为支持建立,有可能会引入其他服的玩家AID、CID,因此这部分需要用到中立服的数据库。
  4. 存储的时候要对中立服、源服同时进行存储,并且要区分Party、Guild、Clan等Id的记录。
  5. 跨服前存在于客户端的Party内容,Guild内容需要被清空显示。(※3)
  6. 原则上支持多个服务器,目前最大5个,但由于Map和Char之间强依赖,数据的一致性问题,并非越多越好。
  7. 未实现开放式API,所以中立服需要得知AB服等账号密码。
  8. 由于中立服Map负责运算,因此原先A,B服相应配置无效,还有$@变量,query_sql等一些指令,只会操作于中立服的Map内。

※1 客户端获得AID的时机,是从输入账号校验登陆后获得。此时无法区分将要登陆的是A服还是中立服,因此无法把伪装后的AID发给客户端

※2 细节上的一个例子,涉及客户端动画效果播放。
假设存在玩家A,怪物B,玩家C,其中A与B发生交互,C在观察。
服务端传来这样一段伤害的封包: A对B进行攻击并造成了伤害

  • 封包主要内容有: 1.代号、长度 2.源自AID(玩家)或GID(怪物) 3.目标AID(玩家)或GID(怪物) 4.伤害 5.技能ID等其他
  • 客户端收到此封包时,会在画面上寻找对应的源和目标,进行相应的显示操作(如技能、效果等)
  • 由于在中立服Map运行时,是以伪装过的AID进行运算,因此玩家A是看不到自己发生的部分行为

因为按照RA的架构下,跨服架构下的各方ID如下所示

人/怪 阵营 服务端 AID/GID 客户端 AID/GID 行为 结果
玩家A 互动对象 10200(来自A服) 自己眼里: 200(未伪装),C眼里:10200(伪装过) 进行攻击 什么也没发生
怪物B 互动对象 1 1 受到攻击 不会被发送封包
玩家C 观察者 20200(来自B服) 自己眼里: 200(未伪装),A眼里:20200(伪装过) 观察 看到A攻击B

因此,要对参与互动的玩家对象,都得额外补发一个真实ID的封包,才能正确显示。
以表格为例,需要对玩家A补发一个 AID:200 对 GID:1 进行攻击的 封包。

以此得知,玩家A,玩家C交互时,需要对双方补发一个双方真实ID的封包。
由此会带来少量的宽带占用问题,但现在的网络环境来说是完全可以接受的。

※3

原架构如下

image

跨服架构后

image

Guild Clan方面也是相应的改动

ToDo:

  • 跨服伤害、效果的正确显示
  • 跨服Party、Guild的正确显示与正确功能
  • 跨服Clan的切换存储
  • base.conf中预定实现的功能
  • 跨服前的触发事件
  • 跨服副本方面检查
  • 跨服冒险家中介所检查
  • 跨服独立背包/仓库/手推车开关
  • 跨服角色数据开关
  • @warp等指令在原架构或跨服架构下支持切换Map-Serv
  • 移除中立服对于A、B服的数据库账号密码的依赖。

本功能已经可以正常测试使用

- bug 虚假实体残留(没有意义的分身bug)
- update 名字获取,名字前缀等
- 进度 25%
- update 死亡&复活的正确对应
- fix 角色1对其他使用单体技能
- fix 角色对自身使用技能
- update 跨服移动前,对应map-serv掉线后正确清理中立服的记录,防直接断线
- update 阻挡跨服ID好友
- fix 中立服务器 未正确存储的问题

- bug 从中立服务器 回去 源服务器时,party无法正确刷新的问题,需要重新上线获取.
- deprecated 自定义缓存 mmo_status_cache 不需要了

- fixme 组队时,有概率会使得新队员看自己像队长(新队员重登后正常)
- fixme 组队时,get_real_name函数在面对未前缀化的名字可能会异常
- fix 伤害指令没有显示的问题
- fix 技能释放时没有正确显示的问题
- fix 组队、公会的大部分问题
- update clan的跨服支持(待完整测试)
- update 新增"跨服失败时标准事件" OnPCCSFailedEvent
- 移动base.conf的选项至conf/battle/crosseserver.conf
- 修正server.conf.default的内容
- update Quest,Achievement的正确存储
- update 删除部分非必要选项
- update Rodex Mail的对应(仍需完善)
- update 换服时检查到对应map掉线的处置
- update 源服map-serv退出时,将会使中立服对应的角色也正确退出(ctrl+c,@mapexit等指令)
- update 正确统计在线人数
- update 正确删除pet、homunculus、memr
- update 邮件正常发送
- update 交易名字正常发送
- update 私聊正常交互
- update fake name完善
- update 实现group_id继承规则
- fix 移动地图后特殊情况下死亡的bug
- fix skillcooldown独立
- fix refresh mailbox
@cloudman123
Copy link

cloudman123 commented Jul 22, 2022

Ubuntu 18.04.6 LTS 編譯報錯如下:

/home/ubuntu/Pandas/src/common/socket.cpp: In function ‘int WFIFOSET(int, size_t)’:**
/home/ubuntu/Pandas/src/common/socket.cpp:858:62: error: ‘packet_trace_id’ was not declared in this scope
ShowDebug("S Trace:%d,cmd:%d,p:0x%04x,len:%d,time:%d.\n", packet_trace_id++, cmd, cmd, len, gettick());
^~~~~~~~~~~~~~~**
src/common/CMakeFiles/common_base.dir/build.make:231: recipe for target 'src/common/CMakeFiles/common_base.dir/socket.cpp.o' failed
make[2]: *** [src/common/CMakeFiles/common_base.dir/socket.cpp.o] Error 1
CMakeFiles/Makefile2:1189: recipe for target 'src/common/CMakeFiles/common_base.dir/all' failed
make[1]: *** [src/common/CMakeFiles/common_base.dir/all] Error 2
Makefile:151: recipe for target 'all' failed
make: *** [all] Error 2

嘗試#undef Pandas_Fake_Id_Check_Debug、#undef Pandas_Print_Trace_Packet報錯如下:

[ 76%] Linking CXX executable ../../../login-server
CMakeFiles/login-server.dir/loginchrif.cpp.o: 於函式 logchrif_parse_upd_global_accreg(int, int, char*):
/home/ubuntu/Pandas/src/login/loginchrif.cpp:499: 未定義參考到 get_real_id(int, bool)
CMakeFiles/login-server.dir/loginchrif.cpp.o: 於函式 logchrif_parse_req_global_accreg(int):
/home/ubuntu/Pandas/src/login/loginchrif.cpp:609: 未定義參考到 get_cs_id(int)
/home/ubuntu/Pandas/src/login/loginchrif.cpp:610: 未定義參考到 is_cross_server
/home/ubuntu/Pandas/src/login/loginchrif.cpp:610: 未定義參考到 is_cross_server
/home/ubuntu/Pandas/src/login/loginchrif.cpp:612: 未定義參考到 get_real_id(int, bool)
/home/ubuntu/Pandas/src/login/loginchrif.cpp:613: 未定義參考到 get_real_id(int, bool)
/home/ubuntu/Pandas/src/login/loginchrif.cpp:609: 未定義參考到 get_cs_id(int)
/home/ubuntu/Pandas/src/login/loginchrif.cpp:610: 未定義參考到 is_cross_server
/home/ubuntu/Pandas/src/login/loginchrif.cpp:610: 未定義參考到 is_cross_server
/home/ubuntu/Pandas/src/login/loginchrif.cpp:612: 未定義參考到 get_real_id(int, bool)
/home/ubuntu/Pandas/src/login/loginchrif.cpp:613: 未定義參考到 get_real_id(int, bool)
collect2: error: ld returned 1 exit status
src/login/CMakeFiles/login-server.dir/build.make:201: recipe for target '../login-server' failed
make[2]: *** [../login-server] Error 1
CMakeFiles/Makefile2:1224: recipe for target 'src/login/CMakeFiles/login-server.dir/all' failed
make[1]: *** [src/login/CMakeFiles/login-server.dir/all] Error 2
Makefile:151: recipe for target 'all' failed
make: *** [all] Error 2

- fix 中立服last_map不应该是非中立服的地图
- fix 在map_addiddb(&sd->bl)前调用pc_setoption有可能因为status_calc_pc导致崩溃
- fix 位移技能正确显示
- update 优化刷新客户端残留内容的时机
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants