PandasWS / Pandas

熊猫模拟器 - 基于 rAthena 构建的中文仙境传说模拟器(欢迎加入QQ交流群:928171346)
https://pandas.ws
GNU General Public License v3.0
8 stars 2 forks source link

[experiment] 跨服功能 #607

Open ShiraGawaAnri opened 2 years ago

ShiraGawaAnri commented 2 years ago

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

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进行攻击并造成了伤害

因为按照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:

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

cloudman123 commented 2 years ago

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