Files
GaCy-GO/internal/gameserver/handlers_raw.go
T

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