fix: sync current handlers, repair relic data and restore visible launcher consoles

This commit is contained in:
CAtlas0784 committed 2026-10-16 22:19:52 +07:00
1 parent 163d4433e6
commit 74f3c4411b
46 files changed
+4599 -1402

No files matched your search

+101 -555
View File
@@ -1,6 +1,7 @@
package gameserver
import (
"fmt"
"sort"
"google.golang.org/protobuf/proto"
@@ -9,8 +10,8 @@ import (
goproto "gac-hkrpg-go/protocol/proto"
)
// Full Go port of challenge.rs: StartChallenge / Tierce / Peak flows with the
// hand-built 4.6.51 response layouts (cmd 1787 / 8973).
// Challenge flows use the generated request and response layouts. Command
// numbers are resolved through the current protocol table at registration/send.
type decodedChallengeStart struct {
challengeID uint32
@@ -106,433 +107,89 @@ func mapChallengeStageID(id uint32) uint32 {
return id
}
func readLenDelimAndAdvance(buf *[]byte) ([]byte, bool) {
b := *buf
l, n := readUvarint(b)
if n == 0 || int(l) > len(b[n:]) {
*buf = nil
return nil, false
}
sub := b[n : n+int(l)]
*buf = b[n+int(l):]
return sub, true
}
func readLenDelim(buf []byte) ([]byte, bool) {
l, n := readUvarint(buf)
if n == 0 || int(l) > len(buf[n:]) {
return nil, false
}
return buf[n : n+int(l)], true
}
func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
var req decodedChallengeStart
var pbReq goproto.StartChallengeCsReq
if err := proto.Unmarshal(payload, &pbReq); err == nil && pbReq.ChallengeId != 0 {
req.challengeID = pbReq.ChallengeId
req.firstAvatars = pbReq.FirstLineup
if len(req.firstAvatars) == 0 && len(pbReq.AvatarLineupFirst) > 0 {
for _, av := range pbReq.AvatarLineupFirst {
if av.Id != 0 {
req.firstAvatars = append(req.firstAvatars, av.Id)
}
}
}
req.secondAvatars = pbReq.SecondLineup
if len(req.secondAvatars) == 0 && len(pbReq.AvatarLineupSecond) > 0 {
for _, av := range pbReq.AvatarLineupSecond {
if av.Id != 0 {
req.secondAvatars = append(req.secondAvatars, av.Id)
}
}
}
if pbReq.StageInfo != nil {
if pbReq.StageInfo.BossInfo != nil && pbReq.StageInfo.BossInfo.BuffOne != 0 {
req.buffID = pbReq.StageInfo.BossInfo.BuffOne
} else if pbReq.StageInfo.StoryInfo != nil && pbReq.StageInfo.StoryInfo.BuffOne != 0 {
req.buffID = pbReq.StageInfo.StoryInfo.BuffOne
}
}
return req
if err := proto.Unmarshal(payload, &pbReq); err != nil {
return decodedChallengeStart{}
}
buf := payload
for len(buf) > 0 {
tag, n := readUvarint(buf)
if n == 0 {
break
}
buf = buf[n:]
fieldNumber := uint32(tag >> 3)
wireType := uint32(tag & 0x7)
switch {
case (fieldNumber == 14 || fieldNumber == 12) && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
req := decodedChallengeStart{challengeID: pbReq.ChallengeId,
firstAvatars: pbReq.FirstLineup, secondAvatars: pbReq.SecondLineup}
if len(req.firstAvatars) == 0 {
for _, avatar := range pbReq.AvatarLineupFirst {
if avatar.Id != 0 {
req.firstAvatars = append(req.firstAvatars, avatar.Id)
}
buf = buf[n2:]
if req.challengeID == 0 {
req.challengeID = uint32(v)
}
case fieldNumber == 6 && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
}
buf = buf[n2:]
req.firstAvatars = append(req.firstAvatars, uint32(v))
case fieldNumber == 6 && wireType == 2:
sub, ok := readLenDelimAndAdvance(&buf)
if !ok {
break
}
for len(sub) > 0 {
v, n3 := readUvarint(sub)
if n3 == 0 {
break
}
sub = sub[n3:]
req.firstAvatars = append(req.firstAvatars, uint32(v))
}
case fieldNumber == 8 && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
}
buf = buf[n2:]
req.secondAvatars = append(req.secondAvatars, uint32(v))
case fieldNumber == 8 && wireType == 2:
sub, ok := readLenDelimAndAdvance(&buf)
if !ok {
break
}
for len(sub) > 0 {
v, n3 := readUvarint(sub)
if n3 == 0 {
break
}
sub = sub[n3:]
req.secondAvatars = append(req.secondAvatars, uint32(v))
}
case (fieldNumber == 4 || fieldNumber == 15) && wireType == 2:
sub, ok := readLenDelimAndAdvance(&buf)
if !ok {
break
}
for len(sub) > 0 {
stag, n3 := readUvarint(sub)
if n3 == 0 {
break
}
sfn := uint32(stag >> 3)
swt := uint32(stag & 0x7)
if sfn == 1 && swt == 0 {
v, n4 := readUvarint(sub[n3:])
if n4 == 0 {
break
}
sub = sub[n3+n4:]
if fieldNumber == 4 {
req.firstAvatars = append(req.firstAvatars, uint32(v))
} else {
req.secondAvatars = append(req.secondAvatars, uint32(v))
}
} else {
skipWireField(swt, &sub)
}
}
case fieldNumber == 10 && wireType == 2:
sub, ok := readLenDelimAndAdvance(&buf)
if !ok {
break
}
for len(sub) > 0 {
stag, n3 := readUvarint(sub)
if n3 == 0 {
break
}
sfn := uint32(stag >> 3)
swt := uint32(stag & 0x7)
sub = sub[n3:]
if swt == 2 && (sfn == 9 || sfn == 10) {
inner, ok2 := readLenDelimAndAdvance(&sub)
if !ok2 {
break
}
for len(inner) > 0 {
t2, n4 := readUvarint(inner)
if n4 == 0 {
break
}
f2 := uint32(t2 >> 3)
w2 := uint32(t2 & 0x7)
inner = inner[n4:]
if w2 == 0 && (f2 == 10 || f2 == 15) {
v, n5 := readUvarint(inner)
if n5 == 0 {
break
}
inner = inner[n5:]
if req.buffID == 0 {
req.buffID = uint32(v)
}
} else {
skipWireField(w2, &inner)
}
}
} else {
skipWireField(swt, &sub)
}
}
default:
skipWireField(wireType, &buf)
}
}
if len(req.secondAvatars) == 0 {
for _, avatar := range pbReq.AvatarLineupSecond {
if avatar.Id != 0 {
req.secondAvatars = append(req.secondAvatars, avatar.Id)
}
}
}
if pbReq.StageInfo != nil {
if info := pbReq.StageInfo.BossInfo; info != nil {
req.buffID = info.BuffOne
}
if info := pbReq.StageInfo.StoryInfo; info != nil && req.buffID == 0 {
req.buffID = info.BuffOne
}
}
return req
}
type tierceStageEntry struct {
buff uint32
lineup []uint32
}
func decodeStartChallengeTierceReq(payload []byte) decodedChallengeStart {
var req decodedChallengeStart
var stagesAvatars []tierceStageEntry
var pbReq goproto.StartChallengeTierceCsReq
if err := proto.Unmarshal(payload, &pbReq); err == nil && pbReq.ChallengeId != 0 {
req.challengeID = pbReq.ChallengeId
req.stageIndex = pbReq.FINOCEGDBDI
req.isSingleStage = pbReq.MPKMIKBFEHG
for _, lt := range pbReq.LineupTierceList {
var l []uint32
for _, av := range lt.TierceAvatarIdList {
if av.Id != 0 {
l = append(l, av.Id)
}
}
stagesAvatars = append(stagesAvatars, tierceStageEntry{
buff: lt.BuffId,
lineup: l,
})
}
} else {
buf := payload
for len(buf) > 0 {
tag, n := readUvarint(buf)
if n == 0 {
break
}
buf = buf[n:]
fieldNumber := uint32(tag >> 3)
wireType := uint32(tag & 0x7)
switch {
case (fieldNumber == 10 || fieldNumber == 1 || fieldNumber == 5) && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
}
buf = buf[n2:]
req.stageIndex = uint32(v)
case (fieldNumber == 15 || fieldNumber == 3) && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
}
buf = buf[n2:]
req.challengeID = uint32(v)
case (fieldNumber == 2 || fieldNumber == 13) && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
}
buf = buf[n2:]
req.isSingleStage = v != 0
case (fieldNumber == 9 || fieldNumber == 12 || fieldNumber == 14) && wireType == 2:
sub, ok := readLenDelimAndAdvance(&buf)
if !ok {
break
}
var stageBuff uint32
var stageLineup []uint32
for len(sub) > 0 {
subTag, n2 := readUvarint(sub)
if n2 == 0 {
break
}
subFn := uint32(subTag >> 3)
subWt := uint32(subTag & 0x7)
sub = sub[n2:]
switch {
case (subFn == 10 || subFn == 6 || subFn == 5) && subWt == 0:
v, n3 := readUvarint(sub)
if n3 == 0 {
sub = nil
break
}
sub = sub[n3:]
stageBuff = uint32(v)
case (subFn == 9 || subFn == 4) && subWt == 2:
abuf, ok2 := readLenDelimAndAdvance(&sub)
if !ok2 {
break
}
var aid uint32
for len(abuf) > 0 {
atag, n4 := readUvarint(abuf)
if n4 == 0 {
break
}
afn := uint32(atag >> 3)
awt := uint32(atag & 0x7)
abuf = abuf[n4:]
if (afn == 1 || afn == 7 || afn == 9) && awt == 0 {
v, n5 := readUvarint(abuf)
if n5 == 0 {
break
}
abuf = abuf[n5:]
aid = uint32(v)
} else {
skipWireField(awt, &abuf)
}
}
if aid != 0 {
stageLineup = append(stageLineup, aid)
}
default:
skipWireField(subWt, &sub)
}
}
stagesAvatars = append(stagesAvatars, tierceStageEntry{buff: stageBuff, lineup: stageLineup})
default:
skipWireField(wireType, &buf)
if err := proto.Unmarshal(payload, &pbReq); err != nil {
return decodedChallengeStart{}
}
req := decodedChallengeStart{challengeID: pbReq.ChallengeId,
stageIndex: pbReq.FINOCEGDBDI, isSingleStage: pbReq.MPKMIKBFEHG}
for index, stage := range pbReq.LineupTierceList {
var avatars []uint32
for _, avatar := range stage.TierceAvatarIdList {
if avatar.Id != 0 {
avatars = append(avatars, avatar.Id)
}
}
}
for _, st := range stagesAvatars {
req.stageInfoList = append(req.stageInfoList, st.lineup)
}
if len(stagesAvatars) > 0 {
req.firstAvatars = stagesAvatars[0].lineup
if req.stageIndex == 0 && stagesAvatars[0].buff != 0 {
req.buffID = stagesAvatars[0].buff
req.stageInfoList = append(req.stageInfoList, avatars)
if uint32(index) == req.stageIndex {
req.buffID = stage.BuffId
}
}
if len(stagesAvatars) > 1 {
req.secondAvatars = stagesAvatars[1].lineup
if req.stageIndex == 1 && stagesAvatars[1].buff != 0 {
req.buffID = stagesAvatars[1].buff
}
if len(req.stageInfoList) > 0 {
req.firstAvatars = req.stageInfoList[0]
}
if len(stagesAvatars) > 2 {
req.thirdAvatars = stagesAvatars[2].lineup
if req.stageIndex == 2 && stagesAvatars[2].buff != 0 {
req.buffID = stagesAvatars[2].buff
}
if len(req.stageInfoList) > 1 {
req.secondAvatars = req.stageInfoList[1]
}
if len(req.stageInfoList) > 2 {
req.thirdAvatars = req.stageInfoList[2]
}
return req
}
func decodeSetChallengeTierceLineupReq(payload []byte) (uint32, [][]uint32) {
var challengeID uint32
var stages [][]uint32
buf := payload
for len(buf) > 0 {
tag, n := readUvarint(buf)
if n == 0 {
break
}
buf = buf[n:]
fieldNumber := uint32(tag >> 3)
wireType := uint32(tag & 0x7)
switch {
case fieldNumber == 7 && wireType == 0:
v, n2 := readUvarint(buf)
if n2 == 0 {
buf = nil
break
}
buf = buf[n2:]
challengeID = uint32(v)
case fieldNumber == 12 && wireType == 2:
sub, ok := readLenDelim(buf)
if !ok {
buf = nil
break
}
buf = buf[len(sub):]
var stageLineup []uint32
for len(sub) > 0 {
subTag, n2 := readUvarint(sub)
if n2 == 0 {
break
}
subFn := uint32(subTag >> 3)
subWt := uint32(subTag & 0x7)
if subFn == 9 && subWt == 2 {
abuf, ok2 := readLenDelim(sub[n2:])
if !ok2 {
sub = nil
break
}
sub = sub[n2+len(abuf):]
var aid uint32
for len(abuf) > 0 {
atag, n4 := readUvarint(abuf)
if n4 == 0 {
break
}
afn := uint32(atag >> 3)
awt := uint32(atag & 0x7)
if afn == 9 && awt == 0 {
v, n5 := readUvarint(abuf[n4:])
if n5 == 0 {
break
}
abuf = abuf[n4+n5:]
aid = uint32(v)
} else {
skipWireField(awt, &abuf)
}
}
if aid != 0 {
stageLineup = append(stageLineup, aid)
}
} else {
skipWireField(subWt, &sub)
}
}
stages = append(stages, stageLineup)
default:
skipWireField(wireType, &buf)
}
var req goproto.SetChallengeTierceLineupCsReq
if err := proto.Unmarshal(payload, &req); err != nil {
return 0, nil
}
return challengeID, stages
var stages [][]uint32
for _, stage := range req.StageInfoList {
var avatars []uint32
for _, avatar := range stage.TierceAvatarIdList {
if avatar.Id != 0 {
avatars = append(avatars, avatar.Id)
}
}
stages = append(stages, avatars)
}
return req.ChallengeId, stages
}
// ---------------------------------------------------------------------------
// battle config setup shared by start handlers
// config setup shared by start handlers
// ---------------------------------------------------------------------------
func setChallengeBattleConfig(player *common.FreesrData, avatars []uint32, challengeID uint32, eventID uint32, buff uint32) {
@@ -618,63 +275,12 @@ func dedupeTruncate4(in []uint32) []uint32 {
return out
}
// looksLikeChallengeID: known challenge-id ranges across endgame modes.
func looksLikeChallengeID(v uint64) bool {
switch {
case v >= 101 && v <= 119, v == 900,
v >= 1001 && v <= 1035,
v >= 2001 && v <= 2025,
v >= 3001 && v <= 3020,
v >= 5000 && v <= 5700, // MoC floors incl. 4.6 phases
v >= 20000 && v <= 20300, // Pure Fiction
v >= 30000 && v <= 30300: // Apocalyptic Shadow
return true
}
cd := getChallengeData()
_, okC := cd.Challenges[uint32(v)]
_, okT := cd.Tierce[uint32(v)]
return okC || okT
}
// detectChallengeID: when the strict decoder misses the challenge id (field
// layout drift between client builds), scan top-level varint fields for the
// first value that looks like a challenge id.
func detectChallengeID(payload []byte) (uint32, int) {
buf := payload
for len(buf) > 0 {
tag, n := readUvarint(buf)
if n == 0 {
break
}
buf = buf[n:]
wireType := uint32(tag & 0x7)
if wireType == 0 {
v, n2 := readUvarint(buf)
if n2 == 0 {
break
}
buf = buf[n2:]
if looksLikeChallengeID(v) {
return uint32(v), int(tag >> 3)
}
} else {
skipWireField(wireType, &buf)
}
}
return 0, 0
}
// handleStartChallenge ports handle_start_challenge: respond cmd 1787 with
// retcode(3) + cur_challenge(5) + lineup_list(6) + scene(10) + stage_info(13).
func handleStartChallenge(s *Session, payload []byte) error {
req := decodeStartChallengeReq(payload)
if req.challengeID == 0 {
if id, field := detectChallengeID(payload); id != 0 {
Log("handle_start_challenge: strict decode missed, detected challenge_id=" + itoa(int(id)) + " at field " + itoa(field))
req.challengeID = id
} else {
PacketLog("[CHALLENGE] challenge_id=0 payload=" + hexDump(payload, 128))
}
return s.Send(&goproto.StartChallengeScRsp{Retcode: uint32(goproto.Retcode_RET_CHALLENGE_NOT_EXIST)})
}
Log("handle_start_challenge: challenge_id=" + itoa(int(req.challengeID)))
@@ -742,12 +348,7 @@ func handleStartChallenge(s *Session, payload []byte) error {
LineupList: lineups,
Scene: sceneInfo,
}
rspBuf, err := proto.Marshal(rsp)
if err != nil {
return err
}
return s.SendRaw(&NetPacket{CmdType: 1787, Body: rspBuf})
return s.Send(rsp)
}
func scoreIDFor(challengeID uint32) uint32 {
@@ -757,9 +358,12 @@ func scoreIDFor(challengeID uint32) uint32 {
return 0
}
// handleStartChallengeTierce ports handle_start_challenge_tierce -> cmd 8998 (4.6.51).
// handleStartChallengeTierce uses the current Tierce request schema.
func handleStartChallengeTierce(s *Session, payload []byte) error {
req := decodeStartChallengeTierceReq(payload)
if req.challengeID == 0 {
return s.Send(&goproto.StartChallengeTierceScRsp{Retcode: uint32(goproto.Retcode_RET_CHALLENGE_NOT_EXIST)})
}
baseID := mapChallengeStageID(req.challengeID)
Log("handle_start_challenge_tierce: challenge_id=" + itoa(int(req.challengeID)) + " (mapped " + itoa(int(baseID)) + ")")
@@ -910,8 +514,8 @@ func handleStartChallengeTierce(s *Session, payload []byte) error {
tierceLineupList = append(tierceLineupList, lineupInfoFromAvatars(stageAvatars, sceneInfo.PlaneId, goproto.ExtraLineupType(1), uint32(stIdx)))
}
// 4.6.51 StartChallengeTierceScRsp (CmdID 8998)
rsp46 := &goproto.StartChallengeTierceScRsp{
// Generated response resolves its command ID through Session.Send.
rsp := &goproto.StartChallengeTierceScRsp{
Retcode: 0,
Scene: sceneInfo,
CurTierceChallenge: &goproto.CurTierceChallenge{
@@ -921,110 +525,61 @@ func handleStartChallengeTierce(s *Session, payload []byte) error {
MPKMIKBFEHG: req.isSingleStage,
},
}
rspBuf, err := proto.Marshal(rsp46)
if err != nil {
return err
}
return s.SendRaw(&NetPacket{CmdType: 8998, Body: rspBuf})
return s.Send(rsp)
}
func handleSetChallengeTierceLineup(s *Session, payload []byte) error {
challengeID, stages := decodeSetChallengeTierceLineupReq(payload)
if challengeID == 0 {
return s.Send(&goproto.SetChallengeTierceLineupScRsp{Retcode: uint32(goproto.Retcode_RET_CHALLENGE_NOT_EXIST)})
}
if len(stages) > 0 {
tierceLineupsMu.Lock()
tierceLineups[challengeID] = stages
tierceLineupsMu.Unlock()
}
// 4.6.51 SetChallengeTierceLineupScRsp (cmd 8985, retcode tag 1 = 0)
if err := s.SendRaw(&NetPacket{CmdType: 8985, Body: []byte{0x08, 0x00}}); err != nil {
return err
}
_ = s.SendRaw(&NetPacket{CmdType: 8999, Body: []byte{0x08, 0x00}})
_ = s.SendRaw(&NetPacket{CmdType: 8995, Body: []byte{0x60, 0x00}})
return nil
return s.Send(&goproto.SetChallengeTierceLineupScRsp{})
}
func handleLeaveChallenge(s *Session, _ []byte) error {
var returnEntry uint32 = 102020107
if player := s.JSON(); player != nil {
player.BattleConfig.CustomBattleLineup = nil
// Always return safely to Belobog Admin District 102020107
player.Scene.EntryID = 102020107
player.Scene.PlaneID = 10202
player.Scene.FloorID = 10202001
player.Position = common.Position{X: -92, Y: 4278, Z: 68083, RotY: 155566}
player.SavePersistent()
}
// 4.6.51 LeaveChallengeScRsp (cmd 1771, tag 10 retcode 0)
if err := s.SendRaw(&NetPacket{CmdType: 1771, Body: []byte{0x50, 0x00}}); err != nil {
return err
}
_ = s.SendRaw(&NetPacket{CmdType: 1716, Body: []byte{0x20, 0x00}})
_ = s.SendRaw(&NetPacket{CmdType: 1781, Body: []byte{0x40, 0x00}})
// Restore the player back to the open world
_, _ = loadScene(s, returnEntry, true, nil, nil)
_ = refreshLineup(s)
return nil
return leaveChallengeScene(s, &goproto.LeaveChallengeScRsp{})
}
func handleLeaveChallengeTierce(s *Session, _ []byte) error {
var returnEntry uint32 = 102020107
if player := s.JSON(); player != nil {
player.BattleConfig.CustomBattleLineup = nil
// Always return safely to Belobog Admin District 102020107
player.Scene.EntryID = 102020107
player.Scene.PlaneID = 10202
player.Scene.FloorID = 10202001
player.Position = common.Position{X: -92, Y: 4278, Z: 68083, RotY: 155566}
player.SavePersistent()
return leaveChallengeScene(s, &goproto.LeaveChallengeTierceScRsp{})
}
func leaveChallengeScene(s *Session, response proto.Message) error {
player := s.JSON()
if player == nil || player.Scene.EntryID == 0 {
return fmt.Errorf("challenge return scene is unavailable")
}
// 4.6.51 LeaveChallengeTierceScRsp (cmd 8983, tag 13 retcode 0)
if err := s.SendRaw(&NetPacket{CmdType: 8983, Body: []byte{0x68, 0x00}}); err != nil {
// loadChallengeScene preserves the player's saved overworld scene.
entryID := player.Scene.EntryID
player.BattleConfig.CustomBattleLineup = nil
CURRENT_BATTLE.Delete(s.Token)
if err := s.Send(&goproto.QuitBattleScNotify{}); err != nil {
return err
}
_ = s.SendRaw(&NetPacket{CmdType: 8997, Body: []byte{0x38, 0x00}})
_ = s.SendRaw(&NetPacket{CmdType: 8982, Body: []byte{0x68, 0x00}})
// Restore the player back to the open world
_, _ = loadScene(s, returnEntry, true, nil, nil)
_ = refreshLineup(s)
return nil
if _, err := loadScene(s, entryID, true, true, nil, nil); err != nil {
return err
}
if err := refreshLineup(s); err != nil {
return err
}
return s.Send(response)
}
func handleTakeChallengeReward(s *Session, payload []byte) error {
var groupID uint32
buf := payload
for len(buf) > 0 {
tag, n := readUvarint(buf)
if n == 0 {
break
}
buf = buf[n:]
fnNum := uint32(tag >> 3)
wt := uint32(tag & 0x7)
if fnNum == 4 && wt == 0 {
v, n2 := readUvarint(buf)
if n2 == 0 {
break
}
buf = buf[n2:]
groupID = uint32(v)
break
}
skipWireField(wt, &buf)
var req goproto.TakeChallengeRewardCsReq
if err := proto.Unmarshal(payload, &req); err != nil {
return err
}
var body []byte
body = append(body, 0x10) // tag 2: group_id
body = appendUvarint(body, uint64(groupID))
body = append(body, 0x30, 0x00) // tag 6: retcode = 0
return s.SendRaw(&NetPacket{CmdType: 1704, Body: body})
return s.Send(&goproto.TakeChallengeRewardScRsp{GroupId: req.GroupId})
}
// buildGetChallengeTierceDataScRsp — verbatim port of the Rust builder.
func buildGetChallengeTierceDataScRspReal() []byte {
// buildGetChallengeTierceDataScRspReal builds the generated current response.
func buildGetChallengeTierceDataScRspReal() *goproto.GetChallengeTierceDataScRsp {
cd := getChallengeData()
type tierceEntry struct {
@@ -1066,17 +621,8 @@ func buildGetChallengeTierceDataScRspReal() []byte {
})
}
rspMsg := &goproto.GetChallengeTierceDataScRsp{
return &goproto.GetChallengeTierceDataScRsp{
ChallengeTierceGroups: groups,
Retcode: 0,
}
body, err := proto.Marshal(rspMsg)
if err == nil {
return body
}
var rsp []byte
rsp = append(rsp, 0x40, 0x00) // tag 8: retcode = 0
rsp = append(rsp, 0x60, 0x00) // legacy tag 12: retcode = 0
return rsp
}