fix(scene): unlock all teleports across maps, merge resource configs, fix scenary not load error, and add quick farm battle handlers
This commit is contained in:
1 parent
9aab62414f
commit
163d4433e6
47 files changed
+2025067
-6082
No files matched your search
@@ -62,8 +62,15 @@ func skipWireField(wireType uint32, buf *[]byte) {
|
||||
}
|
||||
|
||||
func mapChallengeStageID(id uint32) uint32 {
|
||||
cd := getChallengeData()
|
||||
if _, ok := cd.Challenges[id]; ok {
|
||||
return id
|
||||
}
|
||||
if _, ok := cd.Tierce[id]; ok {
|
||||
return id
|
||||
}
|
||||
switch {
|
||||
case id >= 5400 && id <= 5600: // MoC 1035/1036 -> 5301..5312
|
||||
case id >= 5400 && id <= 5700: // MoC 1035/1036 -> 5301..5312
|
||||
rem := id % 100
|
||||
if rem < 1 {
|
||||
rem = 1
|
||||
@@ -91,7 +98,6 @@ func mapChallengeStageID(id uint32) uint32 {
|
||||
}
|
||||
return 30200 + rem
|
||||
case id > 1:
|
||||
cd := getChallengeData()
|
||||
if _, ok := cd.Challenges[id]; !ok {
|
||||
return id - 1
|
||||
}
|
||||
@@ -100,10 +106,59 @@ 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
|
||||
buf := payload
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
buf := payload
|
||||
for len(buf) > 0 {
|
||||
tag, n := readUvarint(buf)
|
||||
if n == 0 {
|
||||
@@ -133,13 +188,10 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
buf = buf[n2:]
|
||||
req.firstAvatars = append(req.firstAvatars, uint32(v))
|
||||
case fieldNumber == 6 && wireType == 2:
|
||||
sub, ok := readLenDelim(buf)
|
||||
sub, ok := readLenDelimAndAdvance(&buf)
|
||||
if !ok {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[len(buf)-len(sub):] // consumed below
|
||||
buf = buf[len(sub):]
|
||||
for len(sub) > 0 {
|
||||
v, n3 := readUvarint(sub)
|
||||
if n3 == 0 {
|
||||
@@ -157,12 +209,10 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
buf = buf[n2:]
|
||||
req.secondAvatars = append(req.secondAvatars, uint32(v))
|
||||
case fieldNumber == 8 && wireType == 2:
|
||||
sub, ok := readLenDelim(buf)
|
||||
sub, ok := readLenDelimAndAdvance(&buf)
|
||||
if !ok {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[len(sub):]
|
||||
for len(sub) > 0 {
|
||||
v, n3 := readUvarint(sub)
|
||||
if n3 == 0 {
|
||||
@@ -171,14 +221,11 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
sub = sub[n3:]
|
||||
req.secondAvatars = append(req.secondAvatars, uint32(v))
|
||||
}
|
||||
case fieldNumber == 4 && wireType == 2:
|
||||
// AvatarLineup: id = tag 1
|
||||
sub, ok := readLenDelim(buf)
|
||||
case (fieldNumber == 4 || fieldNumber == 15) && wireType == 2:
|
||||
sub, ok := readLenDelimAndAdvance(&buf)
|
||||
if !ok {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[len(sub):]
|
||||
for len(sub) > 0 {
|
||||
stag, n3 := readUvarint(sub)
|
||||
if n3 == 0 {
|
||||
@@ -192,19 +239,20 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
break
|
||||
}
|
||||
sub = sub[n3+n4:]
|
||||
req.firstAvatars = append(req.firstAvatars, uint32(v))
|
||||
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:
|
||||
// ChallengeBuffInfo { story_info = 9, boss_info = 10 }
|
||||
sub, ok := readLenDelim(buf)
|
||||
sub, ok := readLenDelimAndAdvance(&buf)
|
||||
if !ok {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[len(sub):]
|
||||
for len(sub) > 0 {
|
||||
stag, n3 := readUvarint(sub)
|
||||
if n3 == 0 {
|
||||
@@ -212,9 +260,9 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
}
|
||||
sfn := uint32(stag >> 3)
|
||||
swt := uint32(stag & 0x7)
|
||||
sub2 := sub[n3:]
|
||||
sub = sub[n3:]
|
||||
if swt == 2 && (sfn == 9 || sfn == 10) {
|
||||
inner, ok2 := readLenDelim(sub2)
|
||||
inner, ok2 := readLenDelimAndAdvance(&sub)
|
||||
if !ok2 {
|
||||
break
|
||||
}
|
||||
@@ -225,12 +273,13 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
}
|
||||
f2 := uint32(t2 >> 3)
|
||||
w2 := uint32(t2 & 0x7)
|
||||
inner = inner[n4:]
|
||||
if w2 == 0 && (f2 == 10 || f2 == 15) {
|
||||
v, n5 := readUvarint(inner[n4:])
|
||||
v, n5 := readUvarint(inner)
|
||||
if n5 == 0 {
|
||||
break
|
||||
}
|
||||
inner = inner[n4+n5:]
|
||||
inner = inner[n5:]
|
||||
if req.buffID == 0 {
|
||||
req.buffID = uint32(v)
|
||||
}
|
||||
@@ -238,14 +287,6 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
skipWireField(w2, &inner)
|
||||
}
|
||||
}
|
||||
sub = sub2
|
||||
// skip the whole len-delimited field
|
||||
_, n6 := readUvarint(sub2)
|
||||
if n6 == 0 {
|
||||
sub = nil
|
||||
} else {
|
||||
sub = sub2[n6:]
|
||||
}
|
||||
} else {
|
||||
skipWireField(swt, &sub)
|
||||
}
|
||||
@@ -258,13 +299,6 @@ func decodeStartChallengeReq(payload []byte) decodedChallengeStart {
|
||||
return req
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type tierceStageEntry struct {
|
||||
buff uint32
|
||||
@@ -273,105 +307,122 @@ type tierceStageEntry struct {
|
||||
|
||||
func decodeStartChallengeTierceReq(payload []byte) decodedChallengeStart {
|
||||
var req decodedChallengeStart
|
||||
buf := payload
|
||||
var stagesAvatars []tierceStageEntry
|
||||
|
||||
for len(buf) > 0 {
|
||||
tag, n := readUvarint(buf)
|
||||
if n == 0 {
|
||||
break
|
||||
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,
|
||||
})
|
||||
}
|
||||
buf = buf[n:]
|
||||
fieldNumber := uint32(tag >> 3)
|
||||
wireType := uint32(tag & 0x7)
|
||||
} 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) && 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 == 5 || fieldNumber == 13) && wireType == 0:
|
||||
v, n2 := readUvarint(buf)
|
||||
if n2 == 0 {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[n2:]
|
||||
req.isSingleStage = v != 0
|
||||
case (fieldNumber == 12 || fieldNumber == 14) && wireType == 2:
|
||||
sub, ok := readLenDelim(buf)
|
||||
if !ok {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
buf = buf[len(sub):]
|
||||
|
||||
var stageBuff uint32
|
||||
var stageLineup []uint32
|
||||
for len(sub) > 0 {
|
||||
subTag, n2 := readUvarint(sub)
|
||||
switch {
|
||||
case (fieldNumber == 10 || fieldNumber == 1 || fieldNumber == 5) && wireType == 0:
|
||||
v, n2 := readUvarint(buf)
|
||||
if n2 == 0 {
|
||||
buf = nil
|
||||
break
|
||||
}
|
||||
subFn := uint32(subTag >> 3)
|
||||
subWt := uint32(subTag & 0x7)
|
||||
switch {
|
||||
case (subFn == 6 || subFn == 5) && subWt == 0:
|
||||
v, n3 := readUvarint(sub[n2:])
|
||||
if n3 == 0 {
|
||||
sub = nil
|
||||
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
|
||||
}
|
||||
sub = sub[n2+n3:]
|
||||
stageBuff = uint32(v)
|
||||
case (subFn == 4 || 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 {
|
||||
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
|
||||
}
|
||||
afn := uint32(atag >> 3)
|
||||
awt := uint32(atag & 0x7)
|
||||
if (afn == 7 || afn == 9) && awt == 0 {
|
||||
v, n5 := readUvarint(abuf[n4:])
|
||||
if n5 == 0 {
|
||||
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
|
||||
}
|
||||
abuf = abuf[n4+n5:]
|
||||
aid = uint32(v)
|
||||
} else {
|
||||
skipWireField(awt, &abuf)
|
||||
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)
|
||||
}
|
||||
if aid != 0 {
|
||||
stageLineup = append(stageLineup, aid)
|
||||
}
|
||||
default:
|
||||
skipWireField(subWt, &sub)
|
||||
}
|
||||
stagesAvatars = append(stagesAvatars, tierceStageEntry{buff: stageBuff, lineup: stageLineup})
|
||||
default:
|
||||
skipWireField(wireType, &buf)
|
||||
}
|
||||
stagesAvatars = append(stagesAvatars, tierceStageEntry{buff: stageBuff, lineup: stageLineup})
|
||||
default:
|
||||
skipWireField(wireType, &buf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,7 +687,7 @@ func handleStartChallenge(s *Session, payload []byte) error {
|
||||
|
||||
baseID := mapChallengeStageID(req.challengeID)
|
||||
cd := getChallengeData()
|
||||
entrance, group, monster, event, buff := uint32(3014101), uint32(5), uint32(4033010), uint32(30124011), uint32(0)
|
||||
entrance, group, monster, event, buff := uint32(3000101), uint32(5), uint32(4033010), uint32(30124011), uint32(0)
|
||||
if c, ok := cd.Challenges[baseID]; ok {
|
||||
entrance, group, monster, event = c.Entrance, c.Group1, c.Monster1, c.Event1
|
||||
if req.buffID != 0 {
|
||||
@@ -644,13 +695,12 @@ func handleStartChallenge(s *Session, payload []byte) error {
|
||||
} else {
|
||||
buff = c.Buff
|
||||
}
|
||||
} else if t, ok := cd.Tierce[baseID]; ok {
|
||||
entrance, group, monster, event = t.Entrance, t.Group, t.Monster, t.Event
|
||||
buff = req.buffID
|
||||
}
|
||||
|
||||
// the 4.6.51 client has no MapEntrance 3014101 (Rust lesson: Lua
|
||||
// GotoMapParam nil -> stuck loading) even though res.json has it
|
||||
if entrance == 3014101 {
|
||||
entrance = 3000101
|
||||
} else if res, err := common.GameRes(); err == nil && !mapHasEntry(res, entrance) {
|
||||
if res, err := common.GameRes(); err == nil && !mapHasEntry(res, entrance) {
|
||||
Log("[CHALLENGE] Arena entrance missing in res.json, fallback to 3000101")
|
||||
entrance = 3000101
|
||||
}
|
||||
@@ -667,64 +717,37 @@ func handleStartChallenge(s *Session, payload []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
custom := map[uint32]uint32{}
|
||||
for i, aid := range chosenAvatars {
|
||||
custom[uint32(i)] = aid
|
||||
var lineups []*goproto.LineupInfo
|
||||
lineups = append(lineups, lineupInfoFromAvatars(chosenAvatars, sceneInfo.PlaneId, goproto.ExtraLineupType(1), 0))
|
||||
|
||||
secondAvatars := req.secondAvatars
|
||||
if len(secondAvatars) == 0 {
|
||||
secondAvatars = chosenAvatars
|
||||
}
|
||||
lineupInfo := common.ToLineupInfo(custom)
|
||||
secondAvatars = dedupeTruncate4(secondAvatars)
|
||||
lineups = append(lineups, lineupInfoFromAvatars(secondAvatars, sceneInfo.PlaneId, goproto.ExtraLineupType(1), 1))
|
||||
|
||||
curChallenge := &goproto.CurChallenge{
|
||||
ChallengeId: req.challengeID,
|
||||
Status: 1, // CHALLENGE_DOING
|
||||
Status: goproto.ChallengeStatus_CHALLENGE_DOING,
|
||||
RoundCount: 0,
|
||||
ScoreId: scoreIDFor(req.challengeID),
|
||||
ScoreTwo: 0,
|
||||
ExtraLineupType: goproto.ExtraLineupType(1),
|
||||
}
|
||||
|
||||
chalBuf, err := proto.Marshal(curChallenge)
|
||||
if err != nil {
|
||||
return err
|
||||
rsp := &goproto.StartChallengeScRsp{
|
||||
Retcode: 0,
|
||||
CurChallenge: curChallenge,
|
||||
LineupList: lineups,
|
||||
Scene: sceneInfo,
|
||||
}
|
||||
lineupBuf, err := proto.Marshal(lineupInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sceneBuf, err := proto.Marshal(sceneInfo)
|
||||
rspBuf, err := proto.Marshal(rsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 4.6.51: StartChallengeScRsp.stage_info (tag 13) - boss node info echoes
|
||||
// the selected buff so the client can set up the challenge UI
|
||||
stageInfo := &goproto.ChallengeStageInfo{}
|
||||
if req.buffID != 0 {
|
||||
stageInfo.BossInfo = &goproto.ChallengeBossInfo{
|
||||
FirstNode: &goproto.ChallengeBossSingleNodeInfo{BuffId: req.buffID},
|
||||
SecondNode: &goproto.ChallengeBossSingleNodeInfo{BuffId: req.buffID},
|
||||
}
|
||||
}
|
||||
stageBuf, err := proto.Marshal(stageInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var body []byte
|
||||
body = append(body, 0x18, 0x00) // tag 3: retcode = 0
|
||||
body = append(body, 0x2A) // tag 5: cur_challenge
|
||||
body = appendUvarint(body, uint64(len(chalBuf)))
|
||||
body = append(body, chalBuf...)
|
||||
body = append(body, 0x32) // tag 6: lineup_list
|
||||
body = appendUvarint(body, uint64(len(lineupBuf)))
|
||||
body = append(body, lineupBuf...)
|
||||
body = append(body, 0x52) // tag 10: scene
|
||||
body = appendUvarint(body, uint64(len(sceneBuf)))
|
||||
body = append(body, sceneBuf...)
|
||||
body = append(body, 0x6A) // tag 13: stage_info
|
||||
body = appendUvarint(body, uint64(len(stageBuf)))
|
||||
body = append(body, stageBuf...)
|
||||
|
||||
return s.SendRaw(&NetPacket{CmdType: 1787, Body: body})
|
||||
return s.SendRaw(&NetPacket{CmdType: 1787, Body: rspBuf})
|
||||
}
|
||||
|
||||
func scoreIDFor(challengeID uint32) uint32 {
|
||||
@@ -734,7 +757,7 @@ func scoreIDFor(challengeID uint32) uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// handleStartChallengeTierce ports handle_start_challenge_tierce -> cmd 8973.
|
||||
// handleStartChallengeTierce ports handle_start_challenge_tierce -> cmd 8998 (4.6.51).
|
||||
func handleStartChallengeTierce(s *Session, payload []byte) error {
|
||||
req := decodeStartChallengeTierceReq(payload)
|
||||
baseID := mapChallengeStageID(req.challengeID)
|
||||
@@ -751,9 +774,17 @@ func handleStartChallengeTierce(s *Session, payload []byte) error {
|
||||
case 0:
|
||||
chosenAvatars = req.firstAvatars
|
||||
case 1:
|
||||
chosenAvatars = req.secondAvatars
|
||||
if len(req.secondAvatars) > 0 {
|
||||
chosenAvatars = req.secondAvatars
|
||||
} else {
|
||||
chosenAvatars = req.firstAvatars
|
||||
}
|
||||
case 2:
|
||||
chosenAvatars = req.thirdAvatars
|
||||
if len(req.thirdAvatars) > 0 {
|
||||
chosenAvatars = req.thirdAvatars
|
||||
} else {
|
||||
chosenAvatars = req.firstAvatars
|
||||
}
|
||||
}
|
||||
|
||||
if len(chosenAvatars) == 0 {
|
||||
@@ -768,32 +799,12 @@ func handleStartChallengeTierce(s *Session, payload []byte) error {
|
||||
}
|
||||
|
||||
cd := getChallengeData()
|
||||
entrance, group, monster, event, buff := uint32(3014101), uint32(5), uint32(4033010), uint32(30124011), uint32(0)
|
||||
switch {
|
||||
case req.stageIndex == 2:
|
||||
entrance, group, monster, event, buff := uint32(3000101), uint32(5), uint32(4033010), uint32(30124011), uint32(0)
|
||||
|
||||
if req.stageIndex == 0 {
|
||||
if t, ok := cd.Tierce[baseID]; ok {
|
||||
entrance, group, monster, event, buff = t.Entrance, t.Group, t.Monster, t.Event, req.buffID
|
||||
} else if c, ok2 := cd.Challenges[baseID]; ok2 {
|
||||
entrance, group, monster, event = c.Entrance2, c.Group2, c.Monster2, c.Event2
|
||||
if req.buffID != 0 {
|
||||
buff = req.buffID
|
||||
} else {
|
||||
buff = c.Buff
|
||||
}
|
||||
}
|
||||
case req.stageIndex == 1:
|
||||
if c, ok := cd.Challenges[baseID]; ok {
|
||||
entrance, group, monster, event = c.Entrance2, c.Group2, c.Monster2, c.Event2
|
||||
if req.buffID != 0 {
|
||||
buff = req.buffID
|
||||
} else {
|
||||
buff = c.Buff
|
||||
}
|
||||
} else {
|
||||
entrance, group, monster, event = 3014101, 6, 8013010, 30124012
|
||||
}
|
||||
default:
|
||||
if c, ok := cd.Challenges[baseID]; ok {
|
||||
entrance, group, monster, event = c.Entrance, c.Group1, c.Monster1, c.Event1
|
||||
if req.buffID != 0 {
|
||||
buff = req.buffID
|
||||
@@ -801,13 +812,32 @@ func handleStartChallengeTierce(s *Session, payload []byte) error {
|
||||
buff = c.Buff
|
||||
}
|
||||
}
|
||||
} else if req.stageIndex == 1 {
|
||||
// Stage 2 (Node 2)
|
||||
if c, ok := cd.Challenges[baseID-1]; ok && c.Entrance2 != 0 {
|
||||
entrance, group, monster, event = c.Entrance2, c.Group2, c.Monster2, c.Event2
|
||||
if req.buffID != 0 {
|
||||
buff = req.buffID
|
||||
} else {
|
||||
buff = c.Buff
|
||||
}
|
||||
} else if c, ok2 := cd.Challenges[baseID]; ok2 && c.Entrance2 != 0 {
|
||||
entrance, group, monster, event = c.Entrance2, c.Group2, c.Monster2, c.Event2
|
||||
if req.buffID != 0 {
|
||||
buff = req.buffID
|
||||
} else {
|
||||
buff = c.Buff
|
||||
}
|
||||
} else if t, ok3 := cd.Tierce[baseID]; ok3 {
|
||||
entrance, group, monster, event, buff = t.Entrance, t.Group, t.Monster, t.Event, req.buffID
|
||||
}
|
||||
} else {
|
||||
if t, ok := cd.Tierce[baseID]; ok {
|
||||
entrance, group, monster, event, buff = t.Entrance, t.Group, t.Monster, t.Event, req.buffID
|
||||
}
|
||||
}
|
||||
|
||||
// the 4.6.51 client cannot load arena 3014101 (no MapEntrance) - fall
|
||||
// back to the standard arena, mirroring handleStartChallenge
|
||||
if entrance == 3014101 {
|
||||
entrance = 3000101
|
||||
} else if res, err := common.GameRes(); err == nil && !mapHasEntry(res, entrance) {
|
||||
if res, err := common.GameRes(); err == nil && !mapHasEntry(res, entrance) {
|
||||
Log("[CHALLENGE] Tierce arena entrance missing in res.json, fallback to 3000101")
|
||||
entrance = 3000101
|
||||
}
|
||||
@@ -875,43 +905,27 @@ func handleStartChallengeTierce(s *Session, payload []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
// ChallengeTierceChallengeInfo: stage_index=4, challenge_id=6, is_single_stage=14, lineup_list=15
|
||||
var tierceInfo []byte
|
||||
tierceInfo = append(tierceInfo, 0x20) // tag 4: stage_index
|
||||
tierceInfo = appendUvarint(tierceInfo, uint64(req.stageIndex))
|
||||
tierceInfo = append(tierceInfo, 0x30) // tag 6: challenge_id
|
||||
tierceInfo = appendUvarint(tierceInfo, uint64(req.challengeID))
|
||||
if req.isSingleStage {
|
||||
tierceInfo = append(tierceInfo, 0x70, 0x01) // tag 14: true
|
||||
}
|
||||
|
||||
var tierceLineupList []*goproto.LineupInfo
|
||||
for stIdx, stageAvatars := range allLineups {
|
||||
lineup := lineupInfoFromAvatars(stageAvatars, sceneInfo.PlaneId, goproto.ExtraLineupType(1), uint32(stIdx))
|
||||
lineupBuf, err := proto.Marshal(lineup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tierceInfo = append(tierceInfo, 0x7A) // tag 15: lineup_list
|
||||
tierceInfo = appendUvarint(tierceInfo, uint64(len(lineupBuf)))
|
||||
tierceInfo = append(tierceInfo, lineupBuf...)
|
||||
tierceLineupList = append(tierceLineupList, lineupInfoFromAvatars(stageAvatars, sceneInfo.PlaneId, goproto.ExtraLineupType(1), uint32(stIdx)))
|
||||
}
|
||||
|
||||
sceneBuf, err := proto.Marshal(sceneInfo)
|
||||
// 4.6.51 StartChallengeTierceScRsp (CmdID 8998)
|
||||
rsp46 := &goproto.StartChallengeTierceScRsp{
|
||||
Retcode: 0,
|
||||
Scene: sceneInfo,
|
||||
CurTierceChallenge: &goproto.CurTierceChallenge{
|
||||
LineupList: tierceLineupList,
|
||||
ChallengeId: req.challengeID,
|
||||
FINOCEGDBDI: req.stageIndex,
|
||||
MPKMIKBFEHG: req.isSingleStage,
|
||||
},
|
||||
}
|
||||
rspBuf, err := proto.Marshal(rsp46)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// StartChallengeTierceScRsp cmd 8973: retcode=12, challenge_tierce_info=4, scene=9
|
||||
var body []byte
|
||||
body = append(body, 0x60, 0x00) // tag 12: retcode = 0
|
||||
body = append(body, 0x22) // tag 4
|
||||
body = appendUvarint(body, uint64(len(tierceInfo)))
|
||||
body = append(body, tierceInfo...)
|
||||
body = append(body, 0x4A) // tag 9: scene
|
||||
body = appendUvarint(body, uint64(len(sceneBuf)))
|
||||
body = append(body, sceneBuf...)
|
||||
|
||||
return s.SendRaw(&NetPacket{CmdType: 8973, Body: body})
|
||||
return s.SendRaw(&NetPacket{CmdType: 8998, Body: rspBuf})
|
||||
}
|
||||
|
||||
func handleSetChallengeTierceLineup(s *Session, payload []byte) error {
|
||||
@@ -921,34 +935,60 @@ func handleSetChallengeTierceLineup(s *Session, payload []byte) error {
|
||||
tierceLineups[challengeID] = stages
|
||||
tierceLineupsMu.Unlock()
|
||||
}
|
||||
if err := s.SendRaw(&NetPacket{CmdType: 8999, Body: []byte{0x08, 0x00}}); err != nil {
|
||||
// 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
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
if err := s.SendRaw(&NetPacket{CmdType: 1716, Body: []byte{0x20, 0x00}}); err != nil {
|
||||
// 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
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
if err := s.SendRaw(&NetPacket{CmdType: 8997, Body: []byte{0x38, 0x00}}); err != nil {
|
||||
// 4.6.51 LeaveChallengeTierceScRsp (cmd 8983, tag 13 retcode 0)
|
||||
if err := s.SendRaw(&NetPacket{CmdType: 8983, Body: []byte{0x68, 0x00}}); 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
|
||||
}
|
||||
|
||||
@@ -1017,62 +1057,26 @@ func buildGetChallengeTierceDataScRspReal() []byte {
|
||||
}
|
||||
sort.Slice(tierceStages, func(i, j int) bool { return tierceStages[i].id < tierceStages[j].id })
|
||||
|
||||
var groups []*goproto.ChallengeTierceGroup
|
||||
for _, e := range tierceStages {
|
||||
groups = append(groups, &goproto.ChallengeTierceGroup{
|
||||
ChallengeId: e.id,
|
||||
IsWin: true,
|
||||
FinishedTargetList: e.targets,
|
||||
})
|
||||
}
|
||||
|
||||
rspMsg := &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
|
||||
|
||||
for _, e := range tierceStages {
|
||||
var tierceData []byte
|
||||
|
||||
// tag 3: challenge_id
|
||||
tierceData = append(tierceData, 0x18)
|
||||
tierceData = appendUvarint(tierceData, uint64(e.id))
|
||||
// tag 6: is_passed = true
|
||||
tierceData = append(tierceData, 0x30, 0x01)
|
||||
// tag 7: finished_target_list (packed)
|
||||
var targetsBuf []byte
|
||||
for _, t := range e.targets {
|
||||
targetsBuf = appendUvarint(targetsBuf, uint64(t))
|
||||
}
|
||||
tierceData = append(tierceData, 0x3A)
|
||||
tierceData = appendUvarint(tierceData, uint64(len(targetsBuf)))
|
||||
tierceData = append(tierceData, targetsBuf...)
|
||||
|
||||
// tag 4: result_list (3 stages)
|
||||
for stageIdx := uint32(0); stageIdx < 3; stageIdx++ {
|
||||
var result []byte
|
||||
result = append(result, 0x18) // tag 3: score_id
|
||||
result = appendUvarint(result, uint64(e.score))
|
||||
result = append(result, 0x48) // tag 9: stage_index
|
||||
result = appendUvarint(result, uint64(stageIdx))
|
||||
result = append(result, 0x50, 0x01) // tag 10: end_status = WIN
|
||||
|
||||
tierceData = append(tierceData, 0x22)
|
||||
tierceData = appendUvarint(tierceData, uint64(len(result)))
|
||||
tierceData = append(tierceData, result...)
|
||||
}
|
||||
|
||||
// tag 8: stage_info_list (3 stages)
|
||||
for stageIdx := uint32(0); stageIdx < 3; stageIdx++ {
|
||||
var sinfo []byte
|
||||
sinfo = append(sinfo, 0x70) // tag 14: stage_index
|
||||
sinfo = appendUvarint(sinfo, uint64(stageIdx))
|
||||
|
||||
tierceData = append(tierceData, 0x42)
|
||||
tierceData = appendUvarint(tierceData, uint64(len(sinfo)))
|
||||
tierceData = append(tierceData, sinfo...)
|
||||
}
|
||||
|
||||
// tag 4: challenge_info_list (4.5.52)
|
||||
rsp = append(rsp, 0x22)
|
||||
rsp = appendUvarint(rsp, uint64(len(tierceData)))
|
||||
rsp = append(rsp, tierceData...)
|
||||
|
||||
// tag 10: challenge_info_list (legacy)
|
||||
rsp = append(rsp, 0x52)
|
||||
rsp = appendUvarint(rsp, uint64(len(tierceData)))
|
||||
rsp = append(rsp, tierceData...)
|
||||
}
|
||||
|
||||
return rsp
|
||||
}
|
||||
Reference in new issue
Block a user