Files
lunar-tear/server/internal/service/quest_bighunt.go
T
2026-04-28 21:22:28 +03:00

383 lines
12 KiB
Go

package service
import (
"context"
"log"
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/runtime"
"lunar-tear/server/internal/store"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
type BigHuntServiceServer struct {
pb.UnimplementedBigHuntServiceServer
users store.UserRepository
sessions store.SessionRepository
holder *runtime.Holder
}
func NewBigHuntServiceServer(
users store.UserRepository,
sessions store.SessionRepository,
holder *runtime.Holder,
) *BigHuntServiceServer {
return &BigHuntServiceServer{users: users, sessions: sessions, holder: holder}
}
func (s *BigHuntServiceServer) StartBigHuntQuest(ctx context.Context, req *pb.StartBigHuntQuestRequest) (*pb.StartBigHuntQuestResponse, error) {
log.Printf("[BigHuntService] StartBigHuntQuest: bossQuestId=%d questId=%d deckNumber=%d isDryRun=%v",
req.BigHuntBossQuestId, req.BigHuntQuestId, req.UserDeckNumber, req.IsDryRun)
cat := s.holder.Get()
catalog := cat.BigHunt
engine := cat.QuestHandler
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
bhQuest, ok := catalog.QuestById[req.BigHuntQuestId]
if !ok {
log.Printf("[BigHuntService] StartBigHuntQuest: unknown bigHuntQuestId=%d", req.BigHuntQuestId)
}
s.users.UpdateUser(userId, func(user *store.UserState) {
if ok {
engine.HandleBigHuntQuestStart(user, bhQuest.QuestId, req.UserDeckNumber, nowMillis)
}
user.BigHuntProgress = store.BigHuntProgress{
CurrentBigHuntBossQuestId: req.BigHuntBossQuestId,
CurrentBigHuntQuestId: req.BigHuntQuestId,
CurrentQuestSceneId: 0,
IsDryRun: req.IsDryRun,
LatestVersion: nowMillis,
}
user.BigHuntDeckNumber = req.UserDeckNumber
st := user.BigHuntStatuses[req.BigHuntBossQuestId]
st.DailyChallengeCount++
st.LatestChallengeDatetime = nowMillis
st.LatestVersion = nowMillis
user.BigHuntStatuses[req.BigHuntBossQuestId] = st
})
return &pb.StartBigHuntQuestResponse{}, nil
}
func (s *BigHuntServiceServer) UpdateBigHuntQuestSceneProgress(ctx context.Context, req *pb.UpdateBigHuntQuestSceneProgressRequest) (*pb.UpdateBigHuntQuestSceneProgressResponse, error) {
log.Printf("[BigHuntService] UpdateBigHuntQuestSceneProgress: questSceneId=%d", req.QuestSceneId)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
s.users.UpdateUser(userId, func(user *store.UserState) {
user.BigHuntProgress.CurrentQuestSceneId = req.QuestSceneId
user.BigHuntProgress.LatestVersion = nowMillis
})
return &pb.UpdateBigHuntQuestSceneProgressResponse{}, nil
}
func (s *BigHuntServiceServer) FinishBigHuntQuest(ctx context.Context, req *pb.FinishBigHuntQuestRequest) (*pb.FinishBigHuntQuestResponse, error) {
log.Printf("[BigHuntService] FinishBigHuntQuest: bossQuestId=%d questId=%d isRetired=%v",
req.BigHuntBossQuestId, req.BigHuntQuestId, req.IsRetired)
cat := s.holder.Get()
catalog := cat.BigHunt
engine := cat.QuestHandler
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
bhQuest := catalog.QuestById[req.BigHuntQuestId]
bossQuest := catalog.BossQuestById[req.BigHuntBossQuestId]
boss := catalog.BossByBossId[bossQuest.BigHuntBossId]
var scoreInfo *pb.BigHuntScoreInfo
var scoreRewards []*pb.BigHuntReward
s.users.UpdateUser(userId, func(user *store.UserState) {
engine.HandleBigHuntQuestFinish(user, bhQuest.QuestId, req.IsRetired, false, nowMillis)
if req.IsRetired || user.BigHuntProgress.IsDryRun {
user.BigHuntProgress = store.BigHuntProgress{LatestVersion: nowMillis}
return
}
detail := user.BigHuntBattleDetail
totalDamage := detail.TotalDamage
baseScore := totalDamage
difficultyBonusPermil := int32(0)
if coeff, ok := catalog.ScoreCoefficients[bhQuest.BigHuntQuestScoreCoefficientId]; ok {
difficultyBonusPermil = coeff
}
aliveBonusPermil := int32(500)
maxComboBonusPermil := int32(0)
if detail.MaxComboCount >= 100 {
maxComboBonusPermil = 300
} else if detail.MaxComboCount >= 50 {
maxComboBonusPermil = 200
} else if detail.MaxComboCount >= 20 {
maxComboBonusPermil = 100
}
userScore := baseScore * int64(1000+difficultyBonusPermil+aliveBonusPermil+maxComboBonusPermil) / 1000
isHighScore := false
oldMaxBoss := user.BigHuntMaxScores[bossQuest.BigHuntBossId]
oldMax := oldMaxBoss.MaxScore
if userScore > oldMax {
isHighScore = true
user.BigHuntMaxScores[bossQuest.BigHuntBossId] = store.BigHuntMaxScore{
MaxScore: userScore,
MaxScoreUpdateDatetime: nowMillis,
LatestVersion: nowMillis,
}
}
schedKey := store.BigHuntScheduleScoreKey{
BigHuntScheduleId: catalog.ActiveScheduleId,
BigHuntBossId: bossQuest.BigHuntBossId,
}
oldSchedMax := user.BigHuntScheduleMaxScores[schedKey].MaxScore
if userScore > oldSchedMax {
user.BigHuntScheduleMaxScores[schedKey] = store.BigHuntScheduleMaxScore{
MaxScore: userScore,
MaxScoreUpdateDatetime: nowMillis,
LatestVersion: nowMillis,
}
}
weeklyVersion := gametime.WeeklyVersion(nowMillis)
weekKey := store.BigHuntWeeklyScoreKey{
BigHuntWeeklyVersion: weeklyVersion,
AttributeType: boss.AttributeType,
}
oldWeeklyMax := user.BigHuntWeeklyMaxScores[weekKey].MaxScore
if userScore > oldWeeklyMax {
user.BigHuntWeeklyMaxScores[weekKey] = store.BigHuntWeeklyMaxScore{
MaxScore: userScore,
LatestVersion: nowMillis,
}
}
assetGradeIconId := catalog.ResolveGradeIconId(bossQuest.BigHuntBossId, userScore)
scoreInfo = &pb.BigHuntScoreInfo{
UserScore: userScore,
IsHighScore: isHighScore,
TotalDamage: totalDamage,
BaseScore: baseScore,
DifficultyBonusPermil: difficultyBonusPermil,
AliveBonusPermil: aliveBonusPermil,
MaxComboBonusPermil: maxComboBonusPermil,
AssetGradeIconId: assetGradeIconId,
}
if isHighScore {
rewardGroupId := catalog.ResolveActiveScoreRewardGroupId(
bossQuest.BigHuntScoreRewardGroupScheduleId, nowMillis)
if rewardGroupId > 0 {
newItems := catalog.CollectNewRewards(rewardGroupId, oldMax, userScore)
for _, item := range newItems {
engine.Granter.GrantFull(user, model.PossessionType(item.PossessionType), item.PossessionId, item.Count, nowMillis)
scoreRewards = append(scoreRewards, &pb.BigHuntReward{
PossessionType: item.PossessionType,
PossessionId: item.PossessionId,
Count: item.Count,
})
}
}
}
user.BigHuntProgress = store.BigHuntProgress{LatestVersion: nowMillis}
user.BigHuntBattleBinary = nil
user.BigHuntBattleDetail = store.BigHuntBattleDetail{}
})
if scoreInfo == nil {
scoreInfo = &pb.BigHuntScoreInfo{}
}
if scoreRewards == nil {
scoreRewards = []*pb.BigHuntReward{}
}
return &pb.FinishBigHuntQuestResponse{
ScoreInfo: scoreInfo,
ScoreReward: scoreRewards,
BattleReport: &pb.BigHuntBattleReport{
BattleReportWave: []*pb.BigHuntBattleReportWave{},
},
}, nil
}
func (s *BigHuntServiceServer) RestartBigHuntQuest(ctx context.Context, req *pb.RestartBigHuntQuestRequest) (*pb.RestartBigHuntQuestResponse, error) {
log.Printf("[BigHuntService] RestartBigHuntQuest: bossQuestId=%d questId=%d", req.BigHuntBossQuestId, req.BigHuntQuestId)
cat := s.holder.Get()
catalog := cat.BigHunt
engine := cat.QuestHandler
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
bhQuest := catalog.QuestById[req.BigHuntQuestId]
var battleBinary []byte
var deckNumber int32
s.users.UpdateUser(userId, func(user *store.UserState) {
engine.HandleBigHuntQuestStart(user, bhQuest.QuestId, user.BigHuntDeckNumber, nowMillis)
user.BigHuntProgress.CurrentQuestSceneId = 0
user.BigHuntProgress.LatestVersion = nowMillis
st := user.BigHuntStatuses[req.BigHuntBossQuestId]
st.DailyChallengeCount++
st.LatestChallengeDatetime = nowMillis
st.LatestVersion = nowMillis
user.BigHuntStatuses[req.BigHuntBossQuestId] = st
battleBinary = user.BigHuntBattleBinary
deckNumber = user.BigHuntDeckNumber
})
return &pb.RestartBigHuntQuestResponse{
BattleBinary: battleBinary,
DeckNumber: deckNumber,
}, nil
}
func (s *BigHuntServiceServer) SkipBigHuntQuest(ctx context.Context, req *pb.SkipBigHuntQuestRequest) (*pb.SkipBigHuntQuestResponse, error) {
log.Printf("[BigHuntService] SkipBigHuntQuest: bossQuestId=%d skipCount=%d", req.BigHuntBossQuestId, req.SkipCount)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
s.users.UpdateUser(userId, func(user *store.UserState) {
st := user.BigHuntStatuses[req.BigHuntBossQuestId]
st.DailyChallengeCount += req.SkipCount
st.LatestChallengeDatetime = nowMillis
st.LatestVersion = nowMillis
user.BigHuntStatuses[req.BigHuntBossQuestId] = st
})
return &pb.SkipBigHuntQuestResponse{
ScoreReward: []*pb.BigHuntReward{},
}, nil
}
func (s *BigHuntServiceServer) SaveBigHuntBattleInfo(ctx context.Context, req *pb.SaveBigHuntBattleInfoRequest) (*pb.SaveBigHuntBattleInfoResponse, error) {
log.Printf("[BigHuntService] SaveBigHuntBattleInfo: elapsedFrames=%d", req.ElapsedFrameCount)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
var totalDamage int64
if req.BigHuntBattleDetail != nil {
for _, ci := range req.BigHuntBattleDetail.CostumeBattleInfo {
if ci != nil {
totalDamage += ci.TotalDamage
}
}
}
s.users.UpdateUser(userId, func(user *store.UserState) {
user.BigHuntBattleBinary = req.BattleBinary
if req.BigHuntBattleDetail != nil {
user.BigHuntBattleDetail = store.BigHuntBattleDetail{
DeckType: req.BigHuntBattleDetail.DeckType,
UserTripleDeckNumber: req.BigHuntBattleDetail.UserTripleDeckNumber,
BossKnockDownCount: req.BigHuntBattleDetail.BossKnockDownCount,
MaxComboCount: req.BigHuntBattleDetail.MaxComboCount,
TotalDamage: totalDamage,
}
}
user.BigHuntProgress.LatestVersion = nowMillis
})
return &pb.SaveBigHuntBattleInfoResponse{}, nil
}
func (s *BigHuntServiceServer) GetBigHuntTopData(ctx context.Context, _ *emptypb.Empty) (*pb.GetBigHuntTopDataResponse, error) {
log.Printf("[BigHuntService] GetBigHuntTopData")
catalog := s.holder.Get().BigHunt
userId := CurrentUserId(ctx, s.users, s.sessions)
user, _ := s.users.LoadUser(userId)
nowMillis := gametime.NowMillis()
weeklyVersion := gametime.WeeklyVersion(nowMillis)
var weeklyScoreResults []*pb.WeeklyScoreResult
for _, boss := range catalog.BossByBossId {
key := store.BigHuntWeeklyScoreKey{
BigHuntWeeklyVersion: weeklyVersion,
AttributeType: boss.AttributeType,
}
ws := user.BigHuntWeeklyMaxScores[key]
gradeIconId := catalog.ResolveGradeIconId(boss.BigHuntBossId, ws.MaxScore)
weeklyScoreResults = append(weeklyScoreResults, &pb.WeeklyScoreResult{
AttributeType: boss.AttributeType,
BeforeMaxScore: ws.MaxScore,
CurrentMaxScore: ws.MaxScore,
BeforeAssetGradeIconId: gradeIconId,
CurrentAssetGradeIconId: gradeIconId,
AfterMaxScore: ws.MaxScore,
AfterAssetGradeIconId: gradeIconId,
})
}
ws := user.BigHuntWeeklyStatuses[weeklyVersion]
weeklyRewards := resolveBigHuntWeeklyRewards(catalog, user, weeklyVersion, nowMillis)
lastWeekVersion := weeklyVersion - 7*24*60*60*1000
lastWeekRewards := resolveBigHuntWeeklyRewards(catalog, user, lastWeekVersion, nowMillis)
return &pb.GetBigHuntTopDataResponse{
WeeklyScoreResult: weeklyScoreResults,
WeeklyScoreReward: weeklyRewards,
IsReceivedWeeklyScoreReward: ws.IsReceivedWeeklyReward,
LastWeekWeeklyScoreReward: lastWeekRewards,
}, nil
}
func resolveBigHuntWeeklyRewards(catalog *masterdata.BigHuntCatalog, user store.UserState, weeklyVersion, nowMillis int64) []*pb.BigHuntReward {
var rewards []*pb.BigHuntReward
for _, boss := range catalog.BossByBossId {
rewardKey := masterdata.BigHuntWeeklyRewardKey{
ScheduleId: 1,
AttributeType: boss.AttributeType,
}
rewardGroupId := catalog.ResolveActiveWeeklyRewardGroupId(rewardKey, nowMillis)
if rewardGroupId == 0 {
continue
}
weekKey := store.BigHuntWeeklyScoreKey{
BigHuntWeeklyVersion: weeklyVersion,
AttributeType: boss.AttributeType,
}
maxScore := user.BigHuntWeeklyMaxScores[weekKey].MaxScore
for _, item := range catalog.CollectNewRewards(rewardGroupId, 0, maxScore) {
rewards = append(rewards, &pb.BigHuntReward{
PossessionType: item.PossessionType,
PossessionId: item.PossessionId,
Count: item.Count,
})
}
}
if rewards == nil {
rewards = []*pb.BigHuntReward{}
}
return rewards
}