159 lines
4.8 KiB
Go
159 lines
4.8 KiB
Go
package gameserver
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"gac-hkrpg-go/internal/common"
|
|
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)
|
|
}
|
|
|
|
// Bind requests by the current command names; do not retain numeric aliases
|
|
// from earlier builds, which may now identify responses or notifications.
|
|
rawNamed("GetChallengeGroupStatisticsCsReq", challengeGroupStatsReply)
|
|
rawNamed("GetChallengeTierceDataCsReq", challengeTierceReply)
|
|
rawNamed("StartChallengeCsReq", handleStartChallenge)
|
|
rawNamed("StartChallengeTierceCsReq", handleStartChallengeTierce)
|
|
rawNamed("SetChallengeTierceLineupCsReq", handleSetChallengeTierceLineup)
|
|
rawNamed("LeaveChallengeCsReq", handleLeaveChallenge)
|
|
rawNamed("LeaveChallengeTierceCsReq", handleLeaveChallengeTierce)
|
|
rawNamed("TakeChallengeCumulativeRewardCsReq", handleTakeChallengeReward)
|
|
// The request/response names remain obfuscated in the upstream schema.
|
|
rawNamed("HIGLJHLNODG", handleExRankUnlock)
|
|
|
|
rawNamed("GetSwitchHandDataCsReq", func(s *Session, payload []byte) error {
|
|
return s.Send(&goproto.GetSwitchHandDataScRsp{})
|
|
})
|
|
|
|
handle("GetChallengeTierceController", func(s *Session, req *goproto.GetChallengeTierceControllerCsReq, rsp *goproto.GetChallengeTierceControllerScRsp) error {
|
|
rsp.Retcode = 0
|
|
return nil
|
|
})
|
|
handle("StartChallengePeak", handleStartChallengePeak)
|
|
rawNamed("LeaveChallengePeakCsReq", func(s *Session, payload []byte) error {
|
|
return leaveChallengeScene(s, &goproto.LeaveChallengePeakScRsp{})
|
|
})
|
|
|
|
}
|
|
|
|
// handleExRankUnlock handles CmdID 400 (Affinitive Eidolon / Ex-Rank unlock request from client).
|
|
func handleExRankUnlock(s *Session, payload []byte) error {
|
|
Log(fmt.Sprintf("[EX-RANK] Received cmd 400 (len: %d) payload: %x", len(payload), payload))
|
|
|
|
var req goproto.HIGLJHLNODG
|
|
if err := proto.Unmarshal(payload, &req); err != nil {
|
|
return err
|
|
}
|
|
parsedVal := req.OJFIGABCKLG
|
|
|
|
var avatarID uint32
|
|
if parsedVal >= 100000 {
|
|
avatarID = parsedVal / 100 // e.g. 120401 -> 1204, 121301 -> 1213, 130801 -> 1308
|
|
} else if parsedVal >= 1000 && parsedVal < 10000 {
|
|
avatarID = parsedVal
|
|
}
|
|
|
|
Log(fmt.Sprintf("[EX-RANK] Target avatarID: %d (from val: %d)", avatarID, parsedVal))
|
|
|
|
player := s.JSON()
|
|
if player != nil {
|
|
if avatarID == 0 {
|
|
// Fallback: unlock for all avatars that have ExRank defined (1204, 1213, 1308)
|
|
for aid := range common.AvatarExRankMap {
|
|
if av, ok := player.Avatars[aid]; ok {
|
|
av.ExRankUnlocked = true
|
|
Log(fmt.Sprintf("[EX-RANK] Fallback set ExRankUnlocked=true for avatar %d", aid))
|
|
syncNotify := &goproto.PlayerSyncScNotify{}
|
|
buildSync(player, syncNotify, []uint32{aid}, nil, nil)
|
|
_ = s.Send(syncNotify)
|
|
}
|
|
}
|
|
} else {
|
|
if av, ok := player.Avatars[avatarID]; ok {
|
|
av.ExRankUnlocked = true
|
|
Log(fmt.Sprintf("[EX-RANK] Set ExRankUnlocked=true for avatar %d", avatarID))
|
|
}
|
|
syncNotify := &goproto.PlayerSyncScNotify{}
|
|
buildSync(player, syncNotify, []uint32{avatarID}, nil, nil)
|
|
_ = s.Send(syncNotify)
|
|
}
|
|
player.SavePersistent()
|
|
}
|
|
|
|
// The matching response is declared by the current upstream schema.
|
|
return s.Send(&goproto.LPOLGDLAADM{})
|
|
}
|
|
|
|
// challengeGroupStatsReply uses the current typed statistics response.
|
|
func challengeGroupStatsReply(s *Session, payload []byte) error {
|
|
var req goproto.GetChallengeGroupStatisticsCsReq
|
|
if err := proto.Unmarshal(payload, &req); err != nil {
|
|
return err
|
|
}
|
|
// Match upstream: echo the group without fabricating historical scores.
|
|
return s.Send(&goproto.GetChallengeGroupStatisticsScRsp{GroupId: req.GroupId})
|
|
}
|
|
|
|
// challengeTierceReply sends only the response paired with the current request.
|
|
func challengeTierceReply(s *Session, payload []byte) error {
|
|
return s.Send(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)<<s, i + 1
|
|
}
|
|
x |= uint64(y&0x7f) << s
|
|
s += 7
|
|
}
|
|
return 0, 0
|
|
}
|
|
|
|
func appendUvarint(b []byte, v uint64) []byte {
|
|
for v >= 0x80 {
|
|
b = append(b, byte(v)|0x80)
|
|
v >>= 7
|
|
}
|
|
return append(b, byte(v))
|
|
}
|
|
|
|
var _ = goproto.CmdIDByName
|