package gameserver import ( goproto "gac-hkrpg-go/protocol/proto" ) // This file ports the raw special-case arms of CommandHandler::on_message and // the dummy! macro list from the Rust packet.rs / handlers/mod.rs. func init() { // ---- dummy (empty ScRsp) list ---- for _, name := range []string{ "GetLevelRewardTakenList", "QueryProductInfo", "GetQuestRecord", "GetCurAssist", "GetDailyActiveInfo", "GetFightActivityData", "GetExpeditionData", "GetLoginActivity", "GetRaidInfo", "GetTrialActivityData", "GetNpcStatus", "GetSecretKeyInfo", "GetVideoVersionKey", "FinishTalkMission", "GetRechargeGiftInfo", "GetPreAvatarGrowthInfo", "GetPreAvatarActivityList", "GetFriendAssistList", "GetAssistList", "B51RacingGetData", } { dummy(name) } // ---- fixed-body raw replies (cmd -> rsp cmd + body bytes) ---- simpleReply := func(reqIDs []uint16, rspID uint16, body []byte) { for _, id := range reqIDs { id := id rawHandlers[id] = func(s *Session, payload []byte) error { return s.SendRaw(&NetPacket{CmdType: rspID, Body: body}) } } } simpleReply([]uint16{8909}, 8923, []byte{0x60, 0x00}) // tag 12 retcode 0 simpleReply([]uint16{8924, 8968}, 8920, []byte{0x10, 0x00}) // tag 2 retcode 0 simpleReply([]uint16{8935}, 8915, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{8917}, 8929, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{8933}, 8906, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{8919}, 8948, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{8910}, 8921, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{8975}, 8992, []byte{0x40, 0x00}) // tag 8 retcode 0 simpleReply([]uint16{8990}, 8977, []byte{0x40, 0x00}) // tag 8 retcode 0 simpleReply([]uint16{8977}, 8999, []byte{0x50, 0x00}) // tag 10 retcode 0 simpleReply([]uint16{2966}, 2955, []byte{0x30, 0x00}) // tag 6 retcode 0 simpleReply([]uint16{2916}, 2906, []byte{0x18, 0x00}) // tag 3 retcode 0 simpleReply([]uint16{2919}, 2928, []byte{0x48, 0x00}) // tag 9 retcode 0 simpleReply([]uint16{740}, 733, []byte{0x58, 0x00}) // tag 11 retcode 0 simpleReply([]uint16{1748}, 1745, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{1765}, 1730, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{1742}, 1772, []byte{0x08, 0x00}) // tag 1 retcode 0 simpleReply([]uint16{1738}, 1748, nil) // empty body simpleReply([]uint16{188}, 181, []byte{0x50, 0x00}) // tag 10 retcode 0 simpleReply([]uint16{4130}, 4124, []byte{0x70, 0x00}) // tag 14 retcode 0 simpleReply([]uint16{8110, 8115}, 8104, []byte{0x18, 0x00}) // GetSwitchHandData tag 3 retcode 0 simpleReply([]uint16{8993, 8991}, 8981, []byte{0x70, 0x00}) // 4.6.51: tag 14 retcode 0 simpleReply([]uint16{8987}, 8986, []byte{0x38, 0x00}) // ConfirmChallengeTierceStageSettle tag 7 retcode 0 // ---- 1775 | 1711 -> GetChallengeGroupStatisticsScRsp (cmd 1708) ---- rawHandlers[1775] = challengeGroupStatsReply rawHandlers[1711] = challengeGroupStatsReply // ---- 8995 | 8979 | 8981 -> tierce data (cmd 8996 + legacy 8994) ---- rawHandlers[8995] = challengeTierceReply rawHandlers[8979] = challengeTierceReply rawHandlers[8981] = challengeTierceReply // ---- challenge flow (StartChallenge family) ---- rawHandlers[1731] = handleStartChallenge rawHandlers[1793] = handleStartChallenge rawHandlers[8986] = handleStartChallengeTierce rawHandlers[8983] = handleStartChallengeTierce rawHandlers[8988] = handleStartChallengeTierce rawHandlers[8978] = handleSetChallengeTierceLineup rawHandlers[1705] = handleLeaveChallenge rawHandlers[1760] = handleLeaveChallenge rawHandlers[1788] = handleLeaveChallenge rawHandlers[8989] = handleLeaveChallengeTierce rawHandlers[8998] = handleLeaveChallengeTierce rawHandlers[1739] = handleTakeChallengeReward } // challengeGroupStatsReply ports the 1775/1711 arm: pull group_id (field 12 // varint) from the request and answer cmd 1708 with per-mode statistics. func challengeGroupStatsReply(s *Session, payload []byte) error { groupID := uint32(100) buf := payload for len(buf) > 0 { tag, n := readUvarint(buf) if n == 0 { break } buf = buf[n:] fieldNumber := tag >> 3 wireType := tag & 0x7 if fieldNumber == 12 && wireType == 0 { v, n2 := readUvarint(buf) if n2 == 0 { break } buf = buf[n2:] groupID = uint32(v) break } else if wireType == 0 { _, n2 := readUvarint(buf) if n2 == 0 { break } buf = buf[n2:] } else { break } } var body []byte // tag 9: group_id body = append(body, 0x48) body = appendUvarint(body, uint64(groupID)) // tag 15: retcode 0 body = append(body, 0x78, 0x00) switch { case groupID >= 2000 && groupID < 3000: // Pure Fiction: tag 8 = challenge_story (ChallengeStoryStatistics) var eik []byte eik = append(eik, 0x50) // tag 10: score_id 80000 eik = appendUvarint(eik, 80000) eik = append(eik, 0x58) // tag 11: level 4 eik = appendUvarint(eik, 4) var css []byte css = append(css, 0x32) // tag 6 css = appendUvarint(css, uint64(len(eik))) css = append(css, eik...) css = append(css, 0x38) // tag 7: record_id 1 css = appendUvarint(css, 1) body = append(body, 0x42) // tag 8 body = appendUvarint(body, uint64(len(css))) body = append(body, css...) case groupID >= 1000 && groupID < 2000: // Memory of Chaos: tag 2 = challenge_default (ChallengeStatistics) var adk []byte adk = append(adk, 0x10) // tag 2: round_count 20 adk = appendUvarint(adk, 20) adk = append(adk, 0x18) // tag 3: level 12 adk = appendUvarint(adk, 12) var cs []byte cs = append(cs, 0x32) // tag 6 cs = appendUvarint(cs, uint64(len(adk))) cs = append(cs, adk...) cs = append(cs, 0x50) // tag 10: record_id 1 cs = appendUvarint(cs, 1) body = append(body, 0x12) // tag 2 body = appendUvarint(body, uint64(len(cs))) body = append(body, cs...) case groupID >= 3000: // Apocalyptic Shadow: tag 11 = challenge_boss (ChallengeBossStatistics) var aan []byte aan = append(aan, 0x50) // tag 10: score_id 8000 aan = appendUvarint(aan, 8000) aan = append(aan, 0x18) // tag 3: level 4 aan = appendUvarint(aan, 4) var cbs []byte cbs = append(cbs, 0x0A) // tag 1 cbs = appendUvarint(cbs, uint64(len(aan))) cbs = append(cbs, aan...) cbs = append(cbs, 0x70) // tag 14: record_id 1 cbs = appendUvarint(cbs, 1) body = append(body, 0x5A) // tag 11 body = appendUvarint(body, uint64(len(cbs))) body = append(body, cbs...) } return s.SendRaw(&NetPacket{CmdType: 1708, Body: body}) } // challengeTierceReply ports the 8995/8979/8981 arm: cmd 8996 (4.6.51) plus // legacy cmd 8994 with the same tierce body. func challengeTierceReply(s *Session, payload []byte) error { body := buildGetChallengeTierceDataScRsp() if err := s.SendRaw(&NetPacket{CmdType: 8996, Body: body}); err != nil { return err } _ = s.SendRaw(&NetPacket{CmdType: 8994, Body: body}) return nil } // buildGetChallengeTierceDataScRsp mirrors challenge::build_get_challenge_tierce_data_sc_rsp // (hand-built protobuf, verified against the 4.6.51 client). func buildGetChallengeTierceDataScRsp() []byte { return buildGetChallengeTierceDataScRspReal() } func readUvarint(b []byte) (uint64, int) { var x uint64 var s uint for i := 0; i < len(b) && i < 10; i++ { y := b[i] if y < 0x80 { if i == 9 && y > 1 { return 0, 0 } return x | uint64(y)<= 0x80 { b = append(b, byte(v)|0x80) v >>= 7 } return append(b, byte(v)) } var _ = goproto.CmdIDByName