找回密码
 registerss
搜索
查看: 21|回复: 0

洱海月 v0-07-0300 封包解析:ID 440 LCRetCreateChar(创建角色结果回包)

[复制链接]
  • 打卡等级:本地老炮
  • 打卡总天数:603
  • 打卡月天数:1
  • 打卡总奖励:600
  • 最近打卡:2026-10-03 06:32:28
Waylee 发表于 2026-4-14 13:31 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?registerss

×

LCRetCreateChar 是登录服返回给客户端的一条创建角色结果包,对应请求包 CLAskCreateChar(522)。当前 Game.exe 与现役 /home/ubuntu/Game2/services/login Lua 都能确认:它是一条固定 4 字节的下行包,包体只有一个 int32 result。现役登录服在收到 CLAskCreateChar 后,会把 .Playermanager 的创建结果原样写入该字段;若结果为成功,还会紧接着补发最新 LCRetCharList。

包信息

项目 内容
封包 ID 440
包名 LCRetCreateChar
方向 LC 登录服 -> 客户端
固定包长 4
对应请求 CLAskCreateChar(522)
当前 Lua 状态 现役协议;登录服已接入
作用 返回本次创建角色请求的结果码,并在成功时配合后续角色列表刷新完成创建流程

当前 Game.exe 可直接确认:

LCRetCreateChar
GetPacketID()   = 0x1405EE5C0 -> 440;
GetPacketSize() = 0x1403A0C40 -> 4;
Read            = 0x1405C6D30;
Write           = 0x140606B30;
Execute thunk   = 0x1405FB240 -> 0x140364B90;

包体结构

当前 Game.exe 与现役 Lua 一致,这条回包固定只有一个 int32 字段:

偏移 长度 字段 类型 含义
0x00 0x04 result int32 创建角色结果码;当前登录服把 .Playermanager:create_char(...) 的返回值原样写入该字段

当前现役 Lua 可确认会返回的结果子集为:

result 当前 Lua 含义
0 创建成功
3 当前账号角色已满
4 角色重名
7 名字非法

其中 1 / 2 / 5 / 6 在当前 define.ASKCREATECHAR_RESULT 里仍有保留名,但现役 playermanager_core:create_char() 不会走到这些分支。

当前实际行为

  • 当前登录服在收到 CLAskCreateChar 后,会先校验登录会话,再调用 .Playermanager 的 create_char(uuid, server_id, packet, uid)。
  • create_char() 当前会先检查角色数量是否已满,再检查名字是否含 #、*、敏感词或重名;通过后才真正插入新角色并更新账号 char_list。
  • 登录服随后构造 LCRetCreateChar,把返回结果写入 ret.result 后立即发送给客户端。
  • 若 result == 0,登录服会紧接着调用 server.send_char_list(fd, char_list, idx),因此客户端的成功分支不是孤立结束,而是紧跟一次角色列表刷新。
  • 当前客户端对 result == 0 的处理是关闭/切换创建角色相关界面状态,并继续进入成功后的角色列表刷新流程。
  • 当前客户端仍保留了大量旧错误码分支:1 / 2 / 3 / 4 / 5 / 6 / 8 / 9 / 10 / 11 / 12。从字符串资源可直接确认的旧提示名包括 Server_Busy_Retry、Role_Is_Full、Name_Exist、INVALID_STRING_IN_NAME、FaceModel_Invaild、HairModel_Invaild、HeadImage_Invaild 等;但这些都属于客户端保留分支,不代表现役 Lua 会实际返回。
  • 但现役 Lua 实际只会回 0 / 3 / 4 / 7。其中最关键的兼容性差异是:当前 Lua 把“名字非法”写成 7,而当前客户端显式提示分支使用的是 case 8 -> INVALID_STRING_IN_NAME,没有单独的 case 7。
  • 因此,现役服务端返回 result == 7 时,当前客户端不会命中“非法名字”专用提示,而会落入默认的 Unknow_Err 分支。这是当前 Lua 与当前 Game.exe 之间的一个结果码不对齐点。

服务端落点

  • 登录协议定义:/home/ubuntu/Game2/services/login/packet.lua
  • 登录包处理:/home/ubuntu/Game2/services/login/logind.lua
  • 创建角色结果码定义:/home/ubuntu/Game2/lualib/define.lua
  • 创建角色核心逻辑:/home/ubuntu/Game2/lualib/playermanager_core.lua

关键代码

以下代码块中,将 sub_1403F9B00 按读取/写入语义简化记为 read_u32 / write_u32,便于对照结构理解。

当前 Lua 协议定义

packet.LCRetCreateChar = {
    xy_id = packet.XYID_LCRETCREATECHAR,
    new = function()
        local o = {}
        setmetatable(o, {__index = packet.LCRetCreateChar})
        o:ctor()
        return o
    end,
    ctor = function(self)
        self.result = 0
    end,
    bos = function(self)
        local stream = bostream.new()
        stream:writeint(self.result)
        return stream:get()
    end
}

当前登录服回包逻辑

elseif packet.xy_id == packet_def.XYID_CLASKCREATECHAR then
    local result, char_list = skynet.call(".Playermanager", "lua", "create_char", uuid, server.server_id, packet, uid)
    ret = packet_def.LCRetCreateChar.new()
    ret.result = result
    loginservice.send(fd, idx, ret)
    if result == define.ASKCREATECHAR_RESULT.ASKCREATECHAR_SUCCESS then
        server.send_char_list(fd, char_list, idx)
    end
end

当前 Lua 创建角色结果来源

define.ASKCREATECHAR_RESULT = {
    ASKCREATECHAR_SUCCESS = 0,
    ASKCREATECHAR_SERVER_BUSY = 1,
    ASKCREATECHAR_OP_TIMES = 2,
    ASKCREATECHAR_FULL = 3,
    ASKCREATECHAR_SAME_NAME = 4,
    ASKCREATECHAR_OP_ERROR = 5,
    ASKCREATECHAR_INTERNAL_ERROR = 6,
    ASKCREATECHAR_INVALID_NAME = 7
}

function playermanager_core:create_char(uuid, server_id, req, uid)
    ...
    if self:check_character_full(server_id, char_guids) then
        return define.ASKCREATECHAR_RESULT.ASKCREATECHAR_FULL
    end
    local result = self:check_name_vaild(name, server_id)
    if result ~= define.ASKCREATECHAR_RESULT.ASKCREATECHAR_SUCCESS then
        return result
    end
    ...
    return define.ASKCREATECHAR_RESULT.ASKCREATECHAR_SUCCESS, char_guids
end

当前 Game.exe 读写与包长

__int64 __fastcall LCRetCreateChar_Read(__int64 packet, __int64 stream)
{
    read_u32(stream, packet + 24);
    return 1;
}

__int64 __fastcall LCRetCreateChar_Write(__int64 packet, __int64 stream)
{
    write_u32(stream, packet + 24);
    return 1;
}

__int64 LCRetCreateChar_GetPacketID()
{
    return 440;
}

__int64 LCRetCreateChar_GetPacketSize()
{
    return 4;
}

当前客户端结果分支要点

switch (result)
{
  case 0:
    // 关闭/切换创建角色相关界面,并继续进入成功后的角色列表刷新链
    post_event(604);
    break;
  case 3:
    // "Role Is Full"
    show_prompt(272, "LCRetCreateCharHandler_Info_Role_Is_Full");
    post_event(605);
    break;
  case 4:
    // "Name Exist"
    show_prompt(272, "Login_Create_Role_Name_Exist");
    post_event(605);
    break;
  case 8:
    // "INVALID_STRING_IN_NAME"
    show_prompt(272, "INVALID_STRING_IN_NAME");
    post_event(605);
    break;
  default:
    // "Unknow_Err"
    show_prompt(272, "LCRetCreateCharHandler_Info_Unknow_Err");
    post_event(605);
    break;
}

结论

  1. LCRetCreateChar(440) 是 CLAskCreateChar(522) 的结果回包,固定长度为 4 字节。
  2. 包体只有一个 result(int32) 字段,当前登录服把 .Playermanager:create_char(...) 的返回值原样写入该字段。
  3. 现役登录服当前实际会回的结果子集是 0 / 3 / 4 / 7,成功时还会立即补发最新角色列表。
  4. 当前客户端保留了更多旧错误码分支,但并不代表现役 Lua 一定会返回这些值。
  5. 当前最值得注意的现役差异是:Lua 使用 7 表示非法名字,而当前客户端显式非法名字提示分支使用的是 8,因此现役 result == 7 会落入默认未知错误分支。
您需要登录后才可以回帖 登录 | registerss

本版积分规则

QQ|手机版|雪舞知识库 ( 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 )|天天打卡

GMT+8, 2026-10-4 11:26 , Processed in 0.062636 second(s), 26 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表