fix: sync current handlers, repair relic data and restore visible launcher consoles
This commit is contained in:
1 parent
163d4433e6
commit
74f3c4411b
46 files changed
+4599
-1402
No files matched your search
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user