装备校验链/快捷栏/公会/好友情侣/交易仓库五项差距修复(增量 129)
- 装备校验:can_equip 按 CanEquipNow→FindEquipCell→EquipItem 精确重排, 新增 find_equip_cell() 1:1 复刻(RING/UNIQUE 占用翻转、COSTUME/BELT/DS), 帝国 antiflag 降级为 tooltip 提示,LIMIT_PCBANG/REAL_TIME* 语义与倒计时文案 - 快捷栏:死亡全槽禁用+激活守卫、变身(affect 220)技能置灰、 物品槽失配置灰(服务器回收/换武器后刷新) - 公会:GUILD_AUTH_* 权限位门控踢人/公告/技能升级,/gskillup、 被宣战应答弹窗(/war·/nowar)、资金存取行(40250 服务端已禁用仍保留 1:1) - 好友/情侣:messenger 三固定组(好友/公会/情侣),lover_login/logout/ near/far/divorce 命令事件→在线/在身边状态与离婚隐藏 - 交易/仓库:ExchangeState.last_notice(ALREADY/LESS_GOLD)结束浮层提示; 仓库改密 /safebox_change_password 三段输入;关窗补 /safebox_close·/mall_close; 仓库金钱经核实 40250 无 wire 协议,UI 定界只读 - app_flow:重连时 guild_marks_ready 重复连接加 is_connected 守卫 - 相机 look_at 零向量守卫(首帧/传送落点) - 测试:equip/love/guild 断言更新,79 项中 78 绿(game_camera_test 为 HEAD 既有失败);真服冒烟 LIVE_SMOKE PASS(192.168.21.203 全链路) - docs/CLIENT-GAP.md 同步增量 129 Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kUFvQGYusuY3dkfGitmAe
This commit is contained in:
@@ -276,12 +276,6 @@ enum : uint8_t {
|
||||
HDR_GC_EMPIRE = 90,
|
||||
HDR_GC_PARTY_LINK = 91,
|
||||
HDR_GC_PARTY_UNLINK = 92,
|
||||
// 40250 extended quest/script notification; payload is dynamically framed.
|
||||
HDR_GC_QUEST_SCRIPT = 148,
|
||||
// Extended servers also emit a dynamically framed mount/status notice here.
|
||||
HDR_GC_EXTENDED_STATUS = 59,
|
||||
// 40250 extended character/status packet (dynamic framing).
|
||||
HDR_GC_EXTENDED_CHARACTER = 105,
|
||||
HDR_GC_REFINE_INFORMATION_OLD = 95,
|
||||
HDR_GC_OBSERVER_ADD = 96,
|
||||
HDR_GC_OBSERVER_REMOVE = 97,
|
||||
@@ -1063,6 +1057,34 @@ enum : uint8_t {
|
||||
QUEST_SEND_COUNTER_VALUE = 1 << 5,
|
||||
QUEST_SEND_ICON_FILE = 1 << 6,
|
||||
};
|
||||
// Field widths written by PC::SendQuestInfoPakcet() (questpc.cpp) and read back
|
||||
// by the original client's field-by-field Recv() in RecvQuestInfoPacket().
|
||||
inline constexpr int QUEST_INFO_HEAD_SIZE = 6; // header + u16 size + u16 index + u8 flag
|
||||
inline constexpr int QUEST_INFO_IS_BEGIN_SIZE = 1;
|
||||
inline constexpr int QUEST_INFO_TITLE_SIZE = 30 + 1;
|
||||
inline constexpr int QUEST_INFO_CLOCK_NAME_SIZE = 16 + 1;
|
||||
inline constexpr int QUEST_INFO_CLOCK_VALUE_SIZE = 4;
|
||||
inline constexpr int QUEST_INFO_COUNTER_NAME_SIZE = 16 + 1;
|
||||
inline constexpr int QUEST_INFO_COUNTER_VALUE_SIZE = 4;
|
||||
inline constexpr int QUEST_INFO_ICON_FILE_SIZE = 24 + 1;
|
||||
|
||||
// The 40250 server fills the fixed head with `size = sizeof(packet_quest_info)`
|
||||
// (6) and then appends the optional fields while only bumping its own local
|
||||
// copy of `size` — the count on the wire never covers the tail. Framing this
|
||||
// packet off its size field therefore leaves the tail in the stream and
|
||||
// desyncs every packet after it, so derive the real length from `flag` the way
|
||||
// the original client does.
|
||||
constexpr int quest_info_packet_size(uint8_t flag) {
|
||||
int n = QUEST_INFO_HEAD_SIZE;
|
||||
if (flag & QUEST_SEND_IS_BEGIN) n += QUEST_INFO_IS_BEGIN_SIZE;
|
||||
if (flag & QUEST_SEND_TITLE) n += QUEST_INFO_TITLE_SIZE;
|
||||
if (flag & QUEST_SEND_CLOCK_NAME) n += QUEST_INFO_CLOCK_NAME_SIZE;
|
||||
if (flag & QUEST_SEND_CLOCK_VALUE) n += QUEST_INFO_CLOCK_VALUE_SIZE;
|
||||
if (flag & QUEST_SEND_COUNTER_NAME) n += QUEST_INFO_COUNTER_NAME_SIZE;
|
||||
if (flag & QUEST_SEND_COUNTER_VALUE) n += QUEST_INFO_COUNTER_VALUE_SIZE;
|
||||
if (flag & QUEST_SEND_ICON_FILE) n += QUEST_INFO_ICON_FILE_SIZE;
|
||||
return n;
|
||||
}
|
||||
|
||||
// --- GC party ---
|
||||
inline constexpr int PARTY_AFFECT_SLOT_MAX_NUM = 7;
|
||||
@@ -1465,9 +1487,6 @@ constexpr bool is_dynamic_gc(uint8_t h) {
|
||||
case HDR_GC_GUILD:
|
||||
case HDR_GC_MESSENGER:
|
||||
case HDR_GC_QUEST_INFO:
|
||||
case HDR_GC_QUEST_SCRIPT:
|
||||
case HDR_GC_EXTENDED_STATUS:
|
||||
case HDR_GC_EXTENDED_CHARACTER:
|
||||
case HDR_GC_DUEL_START:
|
||||
case HDR_GC_SYNC_POSITION:
|
||||
// client CMainPacketHeaderMap registers GC_WHISPER STATIC, but its
|
||||
|
||||
Reference in New Issue
Block a user