From 70582340c2bb18c8c4d57de34b0645d1febf1c34 Mon Sep 17 00:00:00 2001 From: WinterSolstice8 <60417494+wintersolstice8@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:47:57 -0700 Subject: [PATCH 1/3] [core] Handle C2S 0x0DC properly from reversing co-authored-by: atom0s --- src/map/packet_system.cpp | 234 +++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 127 deletions(-) diff --git a/src/map/packet_system.cpp b/src/map/packet_system.cpp index 55936be9e10..c7bde0bb080 100644 --- a/src/map/packet_system.cpp +++ b/src/map/packet_system.cpp @@ -6313,145 +6313,125 @@ void SmallPacket0x0DB(map_session_data_t* const PSession, CCharEntity* const PCh PChar->pushPacket(PChar); } -/************************************************************************ - * * - * Set Name Flags (Party, Away, Autogroup, etc.) * - * * - ************************************************************************/ +// https://github.com/atom0s/XiPackets/blob/main/world/client/0x00DC/README.md +struct GP_CLI_CONFIG +{ + uint16_t id : 9; + uint16_t size : 7; + uint16_t sync; + uint8_t InviteFlg : 1; // PS2: InviteFlg + uint8_t AwayFlg : 1; // PS2: AwayFlg + uint8_t AnonymityFlg : 1; // PS2: AnonymityFlg + uint8_t Language : 2; // PS2: Language + uint8_t unused05 : 3; // PS2: GmLevel + uint8_t unused08 : 1; // PS2: InvisFlg + uint8_t unused09 : 1; // PS2: InvulFlg + uint8_t unused10 : 1; // PS2: IgnoreFlg + uint8_t unused11 : 2; // PS2: SysMesFilterLevel + uint8_t unused13 : 1; // PS2: GmNoPrintFlg + uint8_t AutoTargetOffFlg : 1; // PS2: AutoTargetOffFlg + uint8_t AutoPartyFlg : 1; // PS2: AutoPartyFlg + uint8_t unused16 : 8; // PS2: JailNo + uint8_t unused24 : 1; // PS2: (New; previously padding byte.) + uint8_t MentorFlg : 1; // PS2: (New; previously padding byte.) + uint8_t NewAdventurerOffFlg : 1; // PS2: (New; previously padding byte.) + uint8_t DisplayHeadOffFlg : 1; // PS2: (New; previously padding byte.) + uint8_t unused28 : 1; // PS2: (New; previously padding byte.) + uint8_t RecruitFlg : 1; // PS2: (New; previously padding byte.) + uint8_t unused30 : 2; // PS2: (New; previously padding byte.) + uint32_t unused00; // PS2: (Other misc data.) + uint32_t unused01; // PS2: (Other misc data.) + uint8_t SetFlg; // Ps2: SetFlg + uint8_t padding00[3]; // PS2: (New; did not exist.) +}; void SmallPacket0x0DC(map_session_data_t* const PSession, CCharEntity* const PChar, CBasicPacket& data) { TracyZoneScoped; - switch (data.ref(0x04)) + auto configUpdateData = data.as(); + + bool value = configUpdateData->SetFlg == 1; // 1 == on, 2 == off. What? + + bool updated = false; + + if (configUpdateData->InviteFlg) { - case 0x01: - // /invite [on|off] - if (PChar->PParty) - { - // Can't put flag up while in a party - PChar->playerConfig.InviteFlg = false; - } - else - { - PChar->playerConfig.InviteFlg = !PChar->playerConfig.InviteFlg; - } - break; - case 0x02: - // /away | /online - if (data.ref(0x10) == 1) - { - PChar->playerConfig.AwayFlg = true; - } - if (data.ref(0x10) == 2) - { - PChar->playerConfig.AwayFlg = false; - } - break; - case 0x04: - { - // /anon [on|off] - auto oldAnon = PChar->playerConfig.AnonymityFlg; + updated = true; - auto param = data.ref(0x10); - if (param == 1) - { - PChar->playerConfig.AnonymityFlg = true; - } - else if (param == 2) - { - PChar->playerConfig.AnonymityFlg = false; - } + PChar->playerConfig.InviteFlg = value; + } - if (static_cast(oldAnon) != PChar->isAnon()) - { - PChar->pushPacket(0, 0, param == 1 ? MsgStd::CharacterInfoHidden : MsgStd::CharacterInfoShown); - } - break; - } - case 0x4000: - // /autotarget [on|off] - if (data.ref(0x10) == 1) - { - PChar->playerConfig.AutoTargetOffFlg = false; - } - if (data.ref(0x10) == 2) - { - PChar->playerConfig.AutoTargetOffFlg = true; - } - break; - case 0x8000: - // /autogroup [on|off] - if (data.ref(0x10) == 1) - { - PChar->playerConfig.AutoPartyFlg = true; - } - if (data.ref(0x10) == 2) - { - PChar->playerConfig.AutoPartyFlg = false; - } - break; - case 0x2000000: - // /mentor [on|off] - if (data.ref(0x10) == 1) - { - PChar->playerConfig.MentorFlg = true; - } - else if (data.ref(0x10) == 2) - { - PChar->playerConfig.MentorFlg = false; - } - break; - case 0x04000000: - // Cancel new adventurer status from help desk menu. - if (data.ref(0x10) == 1) - { - PChar->playerConfig.NewAdventurerOffFlg = true; - } - break; - case 0x08000000: - { - // /displayhead [on|off] - uint8 oldDisplayHeadflag = PChar->playerConfig.DisplayHeadOffFlg; - uint8 param = data.ref(0x10); + if (configUpdateData->AwayFlg) + { + updated = true; - if (param == 1) - { - PChar->playerConfig.DisplayHeadOffFlg = true; - } - else if (param == 2) - { - PChar->playerConfig.DisplayHeadOffFlg = false; - } + PChar->playerConfig.AwayFlg = value; + } - if (oldDisplayHeadflag != PChar->playerConfig.DisplayHeadOffFlg) - { - PChar->pushPacket(PChar); - PChar->pushPacket(param == 1 ? MsgStd::HeadgearHide : MsgStd::HeadgearShow); - } - break; - } - case 0x20000000: - // /recruit [on|off] - if (data.ref(0x10) == 1) - { - PChar->playerConfig.RecruitFlg = true; - } - if (data.ref(0x10) == 2) - { - PChar->playerConfig.RecruitFlg = false; - } - break; - default: // If this wasn't a valid request, don't send a bunch of updates for no reason. - return; + if (configUpdateData->AnonymityFlg) + { + updated = true; + + PChar->playerConfig.AnonymityFlg = value; + PChar->pushPacket(0, 0, value ? MsgStd::CharacterInfoHidden : MsgStd::CharacterInfoShown); } - PChar->updatemask |= UPDATE_HP; + if (configUpdateData->AutoTargetOffFlg) + { + updated = true; - charutils::SaveCharStats(PChar); - charutils::SavePlayerSettings(PChar); - PChar->pushPacket(PChar); - PChar->pushPacket(PChar); - PChar->pushPacket(PChar); + PChar->playerConfig.AutoTargetOffFlg = value; + } + + if (configUpdateData->AutoPartyFlg) + { + updated = true; + + PChar->playerConfig.AutoPartyFlg = value; + } + + if (configUpdateData->MentorFlg) + { + updated = true; + + PChar->playerConfig.MentorFlg = value; + } + + if (configUpdateData->NewAdventurerOffFlg) + { + updated = true; + + PChar->playerConfig.NewAdventurerOffFlg = value; + } + + if (configUpdateData->DisplayHeadOffFlg) + { + updated = true; + + PChar->playerConfig.DisplayHeadOffFlg = value; + + // TODO: if you have no headgear you blink anyway. Check if retail does this. + PChar->pushPacket(PChar); + PChar->pushPacket(value ? MsgStd::HeadgearHide : MsgStd::HeadgearShow); + } + + if (configUpdateData->RecruitFlg) + { + updated = true; + + PChar->playerConfig.RecruitFlg = value; + } + + if (updated) + { + PChar->updatemask |= UPDATE_HP; + + charutils::SaveCharStats(PChar); + charutils::SavePlayerSettings(PChar); + PChar->pushPacket(PChar); + PChar->pushPacket(PChar); + PChar->pushPacket(PChar); + } } /************************************************************************ From 1d3ae42ce745321109aac3090889d3b7eb8f7490 Mon Sep 17 00:00:00 2001 From: WinterSolstice8 <60417494+wintersolstice8@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:48:54 -0700 Subject: [PATCH 2/3] [core] Copy correct byte count from SAVE_CONF into S2C 0x00A packet --- src/map/packets/zone_in.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/map/packets/zone_in.cpp b/src/map/packets/zone_in.cpp index aa0578f63c2..bdb733f6a4c 100644 --- a/src/map/packets/zone_in.cpp +++ b/src/map/packets/zone_in.cpp @@ -85,6 +85,7 @@ struct GP_MYROOM_DANCER_PKT }; // PS2: SAVE_CONF +// Seems to be a truncated version of SAVE_CONF missing PvpFlg and AreaCode? struct SAVE_CONF_PKT { uint32_t unknown00[3]; // PS2: (Multiple fields; bits.) @@ -352,7 +353,7 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) ref(0xEC) = PChar->GetMaxMP(); // ref(0xEF) = TODO: implement flag of 1 = high for "has unlocked sub and can change jobs" - std::memcpy(&buffer_[offsetof(GP_SERV_LOGIN, ConfData)], &PChar->playerConfig, sizeof(SAVE_CONF)); + std::memcpy(&buffer_[offsetof(GP_SERV_LOGIN, ConfData)], &PChar->playerConfig, sizeof(SAVE_CONF_PKT)); ref(0x100) = 0x01; // observed: RoZ = 3, CoP = 5, ToAU = 9, WoTG = 11, SoA/original areas = 1 From bf4bd90c83d16197a92ffb0f90b25a02f31d0fd2 Mon Sep 17 00:00:00 2001 From: WinterSolstice8 <60417494+wintersolstice8@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:49:45 -0700 Subject: [PATCH 3/3] [core] Update player config when joining a party --- src/map/party.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/map/party.cpp b/src/map/party.cpp index e93a5ab47c3..e651214c415 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -626,11 +626,13 @@ void CParty::AddMember(CBattleEntity* PEntity) PChar->updatemask |= UPDATE_HP; charutils::SaveCharStats(PChar); + charutils::SavePlayerSettings(PChar); PChar->pushPacket(PChar); PChar->pushPacket(PChar); PChar->pushPacket(PChar); } + PChar->PTreasurePool->UpdatePool(PChar); // Apply level sync if the party is level synced