165 lines
4.9 KiB
Go
165 lines
4.9 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
|
|
if run := s.ChallengeRun; run != nil && run.Tierce {
|
|
rsp.CurTierceChallenge = run.TierceCur
|
|
}
|
|
return nil
|
|
})
|
|
handle("StartChallengePeak", handleStartChallengePeak)
|
|
rawNamed("LeaveChallengePeakCsReq", func(s *Session, payload []byte) error {
|
|
return leaveChallengeScene(s, &goproto.LeaveChallengePeakScRsp{})
|
|
})
|
|
|
|
}
|
|
|
|
// The EX request remains obfuscated in PearlSR 005d2c1: field 5 is
|
|
// interpreted as an avatar, EX-rank or material ID only by an explicit mapping.
|
|
// Never unlock every avatar when an unknown value is received.
|
|
func handleExRankUnlock(s *Session, payload []byte) error {
|
|
var req goproto.HIGLJHLNODG
|
|
if err := proto.Unmarshal(payload, &req); err != nil {
|
|
return err
|
|
}
|
|
value := req.OJFIGABCKLG
|
|
resources, err := loadEidolonResources()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var avatarID uint32
|
|
for id, exID := range common.AvatarExRankMap {
|
|
if value == id || value == exID || value == resources.ExMaterials[id].ItemID {
|
|
avatarID = id
|
|
break
|
|
}
|
|
}
|
|
rsp := &goproto.LPOLGDLAADM{}
|
|
player := s.JSON()
|
|
if player == nil || avatarID == 0 || player.Avatars[avatarID] == nil {
|
|
rsp.Retcode = uint32(goproto.Retcode_RET_AVATAR_NOT_EXIST)
|
|
Log(fmt.Sprintf("[EX-RANK] rejected unmapped value=%d", value))
|
|
return s.Send(rsp)
|
|
}
|
|
if _, active := CURRENT_BATTLE.Load(s.Token); active {
|
|
rsp.Retcode = uint32(goproto.Retcode_RET_AVATAR_RANK_NOT_MATCH)
|
|
return s.Send(rsp)
|
|
}
|
|
avatar := player.Avatars[avatarID]
|
|
previous := avatar.ExRankUnlocked
|
|
avatar.ExRankUnlocked = true
|
|
if err := player.SavePersistentChecked(); err != nil {
|
|
avatar.ExRankUnlocked = previous
|
|
return err
|
|
}
|
|
notify := &goproto.PlayerSyncScNotify{}
|
|
buildSync(player, notify, []uint32{avatarID}, nil, nil)
|
|
notify.MaterialList, err = eidolonMaterials(player)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := s.Send(notify); err != nil {
|
|
return err
|
|
}
|
|
Log(fmt.Sprintf("[EX-RANK] unlocked avatar=%d value=%d", avatarID, value))
|
|
return s.Send(rsp)
|
|
}
|
|
|
|
// 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(s))
|
|
}
|
|
|
|
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
|