From b67cdc261cc9eedfa19b10f5588fff1074abaac0 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 17 Feb 2026 04:16:27 -0800 Subject: [PATCH] Fix character creation on Turtle WoW (4 extra bytes + IN_PROGRESS handling) CMSG_CHAR_CREATE was silently dropped by the server because the packet was 4 bytes too short. Wireshark capture of the real 1.12.1 client revealed 4 trailing zero bytes after outfitId. Also treat IN_PROGRESS (code 46) as success since Turtle WoW sends it instead of SUCCESS. --- src/game/game_handler.cpp | 13 +++++++++++-- src/game/world_packets.cpp | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 8ee25d8..6bb7f0c 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -1798,8 +1798,8 @@ void GameHandler::handleCharCreateResponse(network::Packet& packet) { return; } - if (data.result == CharCreateResult::SUCCESS) { - LOG_INFO("Character created successfully"); + if (data.result == CharCreateResult::SUCCESS || data.result == CharCreateResult::IN_PROGRESS) { + LOG_INFO("Character created successfully (code=", static_cast(data.result), ")"); requestCharacterList(); if (charCreateCallback_) { charCreateCallback_(true, "Character created!"); @@ -1821,6 +1821,15 @@ void GameHandler::handleCharCreateResponse(network::Packet& packet) { case CharCreateResult::LEVEL_REQUIREMENT: msg = "Level requirement not met"; break; case CharCreateResult::UNIQUE_CLASS_LIMIT: msg = "Unique class limit reached"; break; case CharCreateResult::RESTRICTED_RACECLASS: msg = "Race/class combination not allowed"; break; + case CharCreateResult::IN_PROGRESS: msg = "Character creation in progress..."; break; + case CharCreateResult::CHARACTER_CHOOSE_RACE: msg = "Please choose a different race"; break; + case CharCreateResult::CHARACTER_ARENA_LEADER: msg = "Arena team leader restriction"; break; + case CharCreateResult::CHARACTER_DELETE_MAIL: msg = "Character has mail"; break; + case CharCreateResult::CHARACTER_SWAP_FACTION: msg = "Faction swap restriction"; break; + case CharCreateResult::CHARACTER_RACE_ONLY: msg = "Race-only restriction"; break; + case CharCreateResult::CHARACTER_GOLD_LIMIT: msg = "Gold limit reached"; break; + case CharCreateResult::FORCE_LOGIN: msg = "Force login required"; break; + case CharCreateResult::CHARACTER_IN_GUILD: msg = "Character is in a guild"; break; // Name validation errors case CharCreateResult::NAME_FAILURE: msg = "Invalid name"; break; case CharCreateResult::NAME_NO_NAME: msg = "Please enter a name"; break; diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index 038be17..3d29cc2 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -299,6 +299,9 @@ network::Packet CharCreatePacket::build(const CharCreateData& data) { packet.writeUInt8(data.hairColor); packet.writeUInt8(data.facialHair); packet.writeUInt8(0); // outfitId, always 0 + // Turtle WoW / 1.12.1 clients send 4 extra zero bytes after outfitId. + // Servers may validate packet length and silently drop undersized packets. + packet.writeUInt32(0); LOG_DEBUG("Built CMSG_CHAR_CREATE: name=", data.name, " race=", static_cast(data.race),