Add authentication server, dev CLI, Docker multi-service setup, and cross-platform improvements

This commit is contained in:
Ilya Groshev
2026-04-21 16:49:44 +03:00
parent 43d6527b42
commit a3fbb1aeba
121 changed files with 4523 additions and 2888 deletions
+8 -6
View File
@@ -20,7 +20,9 @@ type assetResolution struct {
Candidates []assetCandidate
}
type assetResolver struct{}
type assetResolver struct {
baseDir string
}
func newRevisionTracker() *revisionTracker {
return &revisionTracker{
@@ -28,8 +30,8 @@ func newRevisionTracker() *revisionTracker {
}
}
func newAssetResolver() *assetResolver {
return &assetResolver{}
func newAssetResolver(baseDir string) *assetResolver {
return &assetResolver{baseDir: baseDir}
}
func normalizeClientAddr(remoteAddr string) string {
@@ -73,7 +75,7 @@ func (r *assetResolver) Resolve(objectId, assetType, activeRevision string) (ass
resolution := assetResolution{ActiveRevision: activeRevision}
revision := activeRevision
candidates, listSize, ok := objectIdToFilePathCandidates(revision, assetType, objectId)
candidates, listSize, ok := objectIdToFilePathCandidates(r.baseDir, revision, assetType, objectId)
if ok && len(candidates) > 0 {
resolution.ListRevision = revision
resolution.ListSize = listSize
@@ -94,6 +96,6 @@ func (r *assetResolver) Prewarm(activeRevision string) {
if activeRevision == "" {
return
}
_, _ = loadListBinIndex(activeRevision)
_ = loadInfoIndex(activeRevision)
_, _ = loadListBinIndex(r.baseDir, activeRevision)
_ = loadInfoIndex(r.baseDir, activeRevision)
}
-2
View File
@@ -6,7 +6,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type BannerServiceServer struct {
@@ -44,6 +43,5 @@ func (s *BannerServiceServer) GetMamaBanner(ctx context.Context, req *pb.GetMama
TermLimitedGacha: termLimited,
LatestChapterGacha: latestChapter,
IsExistUnreadPop: false,
DiffUserData: userdata.EmptyDiff(),
}, nil
}
+4 -9
View File
@@ -7,7 +7,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type BattleServiceServer struct {
@@ -22,7 +21,7 @@ func NewBattleServiceServer(users store.UserRepository, sessions store.SessionRe
func (s *BattleServiceServer) StartWave(ctx context.Context, req *pb.StartWaveRequest) (*pb.StartWaveResponse, error) {
log.Printf("[BattleService] StartWave: userParty=%d npcParty=%d", len(req.UserPartyInitialInfoList), len(req.NpcPartyInitialInfoList))
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
user.Battle.IsActive = true
user.Battle.StartCount++
@@ -30,15 +29,13 @@ func (s *BattleServiceServer) StartWave(ctx context.Context, req *pb.StartWaveRe
user.Battle.LastUserPartyCount = int32(len(req.UserPartyInitialInfoList))
user.Battle.LastNpcPartyCount = int32(len(req.NpcPartyInitialInfoList))
})
return &pb.StartWaveResponse{
DiffUserData: userdata.EmptyDiff(),
}, nil
return &pb.StartWaveResponse{}, nil
}
func (s *BattleServiceServer) FinishWave(ctx context.Context, req *pb.FinishWaveRequest) (*pb.FinishWaveResponse, error) {
log.Printf("[BattleService] FinishWave: battleBinary=%d userParty=%d npcParty=%d elapsedFrames=%d",
len(req.BattleBinary), len(req.UserPartyResultInfoList), len(req.NpcPartyResultInfoList), req.ElapsedFrameCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
user.Battle.IsActive = false
user.Battle.FinishCount++
@@ -48,7 +45,5 @@ func (s *BattleServiceServer) FinishWave(ctx context.Context, req *pb.FinishWave
user.Battle.LastBattleBinarySize = int32(len(req.BattleBinary))
user.Battle.LastElapsedFrameCount = req.ElapsedFrameCount
})
return &pb.FinishWaveResponse{
DiffUserData: userdata.EmptyDiff(),
}, nil
return &pb.FinishWaveResponse{}, nil
}
+5 -24
View File
@@ -9,7 +9,6 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type CageOrnamentServiceServer struct {
@@ -32,9 +31,9 @@ func (s *CageOrnamentServiceServer) ReceiveReward(ctx context.Context, req *pb.R
log.Fatalf("[CageOrnamentService] ReceiveReward: no reward for cageOrnamentId=%d", req.CageOrnamentId)
}
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
user.CageOrnamentRewards[req.CageOrnamentId] = store.CageOrnamentRewardState{
CageOrnamentId: req.CageOrnamentId,
AcquisitionDatetime: nowMillis,
@@ -43,17 +42,6 @@ func (s *CageOrnamentServiceServer) ReceiveReward(ctx context.Context, req *pb.R
s.granter.GrantFull(user, model.PossessionType(reward.PossessionType), reward.PossessionId, reward.Count, nowMillis)
})
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(user,
[]string{
"IUserMaterial", "IUserConsumableItem", "IUserGem",
"IUserCostume", "IUserCostumeActiveSkill", "IUserCharacter",
"IUserWeapon", "IUserWeaponSkill", "IUserWeaponAbility",
"IUserWeaponNote",
"IUserCageOrnamentReward",
},
))
userdata.AddWeaponStoryDiff(diff, user, s.granter.DrainChangedStoryWeaponIds())
return &pb.ReceiveRewardResponse{
CageOrnamentReward: []*pb.CageOrnamentReward{
{
@@ -62,16 +50,15 @@ func (s *CageOrnamentServiceServer) ReceiveReward(ctx context.Context, req *pb.R
Count: reward.Count,
},
},
DiffUserData: diff,
}, nil
}
func (s *CageOrnamentServiceServer) RecordAccess(ctx context.Context, req *pb.RecordAccessRequest) (*pb.RecordAccessResponse, error) {
log.Printf("[CageOrnamentService] RecordAccess: cageOrnamentId=%d", req.CageOrnamentId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
if _, exists := user.CageOrnamentRewards[req.CageOrnamentId]; !exists {
user.CageOrnamentRewards[req.CageOrnamentId] = store.CageOrnamentRewardState{
CageOrnamentId: req.CageOrnamentId,
@@ -81,11 +68,5 @@ func (s *CageOrnamentServiceServer) RecordAccess(ctx context.Context, req *pb.Re
}
})
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(user,
[]string{"IUserCageOrnamentReward"},
))
return &pb.RecordAccessResponse{
DiffUserData: diff,
}, nil
return &pb.RecordAccessResponse{}, nil
}
+3 -12
View File
@@ -8,7 +8,6 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type CharacterServiceServer struct {
@@ -26,7 +25,7 @@ func NewCharacterServiceServer(users store.UserRepository, sessions store.Sessio
func (s *CharacterServiceServer) Rebirth(ctx context.Context, req *pb.RebirthRequest) (*pb.RebirthResponse, error) {
log.Printf("[CharacterService] Rebirth: characterId=%d rebirthCount=%d", req.CharacterId, req.RebirthCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
stepGroupId, ok := s.catalog.StepGroupByCharacterId[req.CharacterId]
@@ -35,11 +34,7 @@ func (s *CharacterServiceServer) Rebirth(ctx context.Context, req *pb.RebirthReq
return &pb.RebirthResponse{}, nil
}
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserMaterial", oldUser, userdata.SortedMaterialRecords, []string{"userId", "materialId"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
current := user.CharacterRebirths[req.CharacterId]
currentCount := current.RebirthCount
targetCount := currentCount + req.RebirthCount
@@ -77,9 +72,5 @@ func (s *CharacterServiceServer) Rebirth(ctx context.Context, req *pb.RebirthReq
return nil, err
}
rebirthTables := []string{"IUserCharacterRebirth", "IUserMaterial", "IUserConsumableItem"}
tables := userdata.ProjectTables(snapshot, rebirthTables)
diff := tracker.Apply(snapshot, tables)
return &pb.RebirthResponse{DiffUserData: diff}, nil
return &pb.RebirthResponse{}, nil
}
+8 -25
View File
@@ -8,7 +8,6 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type CharacterBoardServiceServer struct {
@@ -25,14 +24,9 @@ func NewCharacterBoardServiceServer(users store.UserRepository, sessions store.S
func (s *CharacterBoardServiceServer) ReleasePanel(ctx context.Context, req *pb.ReleasePanelRequest) (*pb.ReleasePanelResponse, error) {
log.Printf("[CharacterBoardService] ReleasePanel: panelIds=%v", req.CharacterBoardPanelId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserMaterial", oldUser, userdata.SortedMaterialRecords, []string{"userId", "materialId"}).
Track("IUserConsumableItem", oldUser, userdata.SortedConsumableItemRecords, []string{"userId", "consumableItemId"})
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
for _, panelId := range req.CharacterBoardPanelId {
panel, ok := s.catalog.PanelById[panelId]
if !ok {
@@ -46,28 +40,17 @@ func (s *CharacterBoardServiceServer) ReleasePanel(ctx context.Context, req *pb.
}
})
boardTables := []string{
"IUserCharacterBoard",
"IUserCharacterBoardAbility",
"IUserCharacterBoardStatusUp",
"IUserMaterial",
"IUserConsumableItem",
"IUserGem",
}
tables := userdata.ProjectTables(user, boardTables)
diff := tracker.Apply(user, tables)
return &pb.ReleasePanelResponse{DiffUserData: diff}, nil
return &pb.ReleasePanelResponse{}, nil
}
func (s *CharacterBoardServiceServer) consumeCosts(user *store.UserState, panel masterdata.CharacterBoardPanelRow) {
func (s *CharacterBoardServiceServer) consumeCosts(user *store.UserState, panel masterdata.EntityMCharacterBoardPanel) {
costs := s.catalog.ReleaseCostsByGroupId[panel.CharacterBoardPanelReleasePossessionGroupId]
for _, cost := range costs {
store.DeductPossession(user, model.PossessionType(cost.PossessionType), cost.PossessionId, cost.Count)
}
}
func (s *CharacterBoardServiceServer) setReleaseBit(user *store.UserState, panel masterdata.CharacterBoardPanelRow) {
func (s *CharacterBoardServiceServer) setReleaseBit(user *store.UserState, panel masterdata.EntityMCharacterBoardPanel) {
boardId := panel.CharacterBoardId
board := user.CharacterBoards[boardId]
board.CharacterBoardId = boardId
@@ -90,7 +73,7 @@ func (s *CharacterBoardServiceServer) setReleaseBit(user *store.UserState, panel
user.CharacterBoards[boardId] = board
}
func (s *CharacterBoardServiceServer) applyEffects(user *store.UserState, panel masterdata.CharacterBoardPanelRow) {
func (s *CharacterBoardServiceServer) applyEffects(user *store.UserState, panel masterdata.EntityMCharacterBoardPanel) {
effects := s.catalog.ReleaseEffectsByGroupId[panel.CharacterBoardPanelReleaseEffectGroupId]
for _, eff := range effects {
switch model.CharacterBoardEffectType(eff.CharacterBoardEffectType) {
@@ -102,7 +85,7 @@ func (s *CharacterBoardServiceServer) applyEffects(user *store.UserState, panel
}
}
func (s *CharacterBoardServiceServer) applyAbilityEffect(user *store.UserState, eff masterdata.CharacterBoardReleaseEffectRow) {
func (s *CharacterBoardServiceServer) applyAbilityEffect(user *store.UserState, eff masterdata.EntityMCharacterBoardPanelReleaseEffectGroup) {
ability, ok := s.catalog.AbilityById[eff.CharacterBoardEffectId]
if !ok {
log.Printf("[CharacterBoardService] unknown abilityId=%d", eff.CharacterBoardEffectId)
@@ -127,7 +110,7 @@ func (s *CharacterBoardServiceServer) applyAbilityEffect(user *store.UserState,
user.CharacterBoardAbilities[key] = state
}
func (s *CharacterBoardServiceServer) applyStatusUpEffect(user *store.UserState, eff masterdata.CharacterBoardReleaseEffectRow) {
func (s *CharacterBoardServiceServer) applyStatusUpEffect(user *store.UserState, eff masterdata.EntityMCharacterBoardPanelReleaseEffectGroup) {
statusUp, ok := s.catalog.StatusUpById[eff.CharacterBoardEffectId]
if !ok {
log.Printf("[CharacterBoardService] unknown statusUpId=%d", eff.CharacterBoardEffectId)
+1 -28
View File
@@ -2,12 +2,10 @@ package service
import (
"context"
"encoding/json"
"fmt"
"log"
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
@@ -28,7 +26,7 @@ func NewCharacterViewerServiceServer(users store.UserRepository, sessions store.
func (s *CharacterViewerServiceServer) CharacterViewerTop(ctx context.Context, _ *emptypb.Empty) (*pb.CharacterViewerTopResponse, error) {
log.Printf("[CharacterViewerService] CharacterViewerTop")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
panic(fmt.Sprintf("CharacterViewerTop: no user for userId=%d: %v", userId, err))
@@ -37,32 +35,7 @@ func (s *CharacterViewerServiceServer) CharacterViewerTop(ctx context.Context, _
released := s.catalog.ReleasedFieldIds(user)
log.Printf("[CharacterViewerService] released %d fields for user %d", len(released), userId)
now := gametime.NowMillis()
records := make([]map[string]any, 0, len(released))
for _, fieldId := range released {
records = append(records, map[string]any{
"userId": userId,
"characterViewerFieldId": fieldId,
"releaseDatetime": now,
"latestVersion": 0,
})
}
payload := "[]"
if len(records) > 0 {
data, _ := json.Marshal(records)
payload = string(data)
}
diff := map[string]*pb.DiffData{
"IUserCharacterViewerField": {
UpdateRecordsJson: payload,
DeleteKeysJson: "[]",
},
}
return &pb.CharacterViewerTopResponse{
ReleaseCharacterViewerFieldId: released,
DiffUserData: diff,
}, nil
}
+3 -14
View File
@@ -9,17 +9,10 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
const companionMaxLevel = int32(50)
var companionDiffTables = []string{
"IUserCompanion",
"IUserMaterial",
"IUserConsumableItem",
}
type CompanionServiceServer struct {
pb.UnimplementedCompanionServiceServer
users store.UserRepository
@@ -35,10 +28,10 @@ func NewCompanionServiceServer(users store.UserRepository, sessions store.Sessio
func (s *CompanionServiceServer) Enhance(ctx context.Context, req *pb.CompanionEnhanceRequest) (*pb.CompanionEnhanceResponse, error) {
log.Printf("[CompanionService] Enhance: uuid=%s addLevel=%d", req.UserCompanionUuid, req.AddLevelCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
companion, ok := user.Companions[req.UserCompanionUuid]
if !ok {
log.Printf("[CompanionService] Enhance: companion uuid=%s not found", req.UserCompanionUuid)
@@ -77,9 +70,5 @@ func (s *CompanionServiceServer) Enhance(ctx context.Context, req *pb.CompanionE
return nil, fmt.Errorf("companion enhance: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, companionDiffTables))
return &pb.CompanionEnhanceResponse{
DiffUserData: diff,
}, nil
return &pb.CompanionEnhanceResponse{}, nil
}
+1 -3
View File
@@ -5,7 +5,6 @@ import (
"log"
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/userdata"
"google.golang.org/protobuf/types/known/emptypb"
)
@@ -14,7 +13,7 @@ type ConfigServiceServer struct {
pb.UnimplementedConfigServiceServer
GrpcHost string
GrpcPort int32
OctoURL string // HTTP base URL for Octo (list + assets); client uses this instead of default resources.app.nierreincarnation.com
OctoURL string
}
func NewConfigServiceServer(host string, port int32, octoURL string) *ConfigServiceServer {
@@ -42,6 +41,5 @@ func (s *ConfigServiceServer) GetReviewServerConfig(ctx context.Context, _ *empt
MasterData: &pb.MasterDataConfig{
UrlFormat: s.OctoURL + "/master-data/%s",
},
DiffUserData: userdata.EmptyDiff(),
}, nil
}
+3 -13
View File
@@ -8,7 +8,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type ConsumableItemServiceServer struct {
@@ -26,13 +25,9 @@ func NewConsumableItemServiceServer(users store.UserRepository, sessions store.S
func (s *ConsumableItemServiceServer) Sell(ctx context.Context, req *pb.ConsumableItemSellRequest) (*pb.ConsumableItemSellResponse, error) {
log.Printf("[ConsumableItemService] Sell: %d item(s)", len(req.ConsumableItemPossession))
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserConsumableItem", oldUser, userdata.SortedConsumableItemRecords, []string{"userId", "consumableItemId"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
totalGold := int32(0)
for _, item := range req.ConsumableItemPossession {
row, ok := s.catalog.All[item.ConsumableItemId]
@@ -66,10 +61,5 @@ func (s *ConsumableItemServiceServer) Sell(ctx context.Context, req *pb.Consumab
return nil, fmt.Errorf("consumable item sell: %w", err)
}
tables := userdata.ProjectTables(snapshot, []string{"IUserConsumableItem"})
diff := tracker.Apply(snapshot, tables)
return &pb.ConsumableItemSellResponse{
DiffUserData: diff,
}, nil
return &pb.ConsumableItemSellResponse{}, nil
}
+3 -8
View File
@@ -8,7 +8,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type ContentsStoryServiceServer struct {
@@ -24,19 +23,15 @@ func NewContentsStoryServiceServer(users store.UserRepository, sessions store.Se
func (s *ContentsStoryServiceServer) RegisterPlayed(ctx context.Context, req *pb.ContentsStoryRegisterPlayedRequest) (*pb.ContentsStoryRegisterPlayedResponse, error) {
log.Printf("[ContentsStoryService] RegisterPlayed: contentsStoryId=%d", req.ContentsStoryId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
user.ContentsStories[req.ContentsStoryId] = nowMillis
})
if err != nil {
return nil, fmt.Errorf("update user: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserContentsStory"}))
return &pb.ContentsStoryRegisterPlayedResponse{
DiffUserData: diff,
}, nil
return &pb.ContentsStoryRegisterPlayedResponse{}, nil
}
+21 -89
View File
@@ -14,15 +14,8 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
var costumeDiffTables = []string{
"IUserCostume",
"IUserMaterial",
"IUserConsumableItem",
}
type CostumeServiceServer struct {
pb.UnimplementedCostumeServiceServer
users store.UserRepository
@@ -38,10 +31,10 @@ func NewCostumeServiceServer(users store.UserRepository, sessions store.SessionR
func (s *CostumeServiceServer) Enhance(ctx context.Context, req *pb.EnhanceRequest) (*pb.EnhanceResponse, error) {
log.Printf("[CostumeService] Enhance: uuid=%s materials=%v", req.UserCostumeUuid, req.Materials)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
costume, ok := user.Costumes[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] Enhance: costume uuid=%s not found", req.UserCostumeUuid)
@@ -98,30 +91,19 @@ func (s *CostumeServiceServer) Enhance(ctx context.Context, req *pb.EnhanceReque
return nil, fmt.Errorf("costume enhance: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, costumeDiffTables))
return &pb.EnhanceResponse{
IsGreatSuccess: false,
SurplusEnhanceMaterial: map[int32]int32{},
DiffUserData: diff,
}, nil
}
var awakenDiffTables = []string{
"IUserCostume",
"IUserMaterial",
"IUserConsumableItem",
"IUserCostumeAwakenStatusUp",
"IUserThought",
}
func (s *CostumeServiceServer) Awaken(ctx context.Context, req *pb.AwakenRequest) (*pb.AwakenResponse, error) {
log.Printf("[CostumeService] Awaken: uuid=%s materials=%v", req.UserCostumeUuid, req.Materials)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
costume, ok := user.Costumes[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] Awaken: costume uuid=%s not found", req.UserCostumeUuid)
@@ -179,11 +161,7 @@ func (s *CostumeServiceServer) Awaken(ctx context.Context, req *pb.AwakenRequest
return nil, fmt.Errorf("costume awaken: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, awakenDiffTables))
return &pb.AwakenResponse{
DiffUserData: diff,
}, nil
return &pb.AwakenResponse{}, nil
}
func (s *CostumeServiceServer) applyAwakenStatusUp(user *store.UserState, costumeUuid string, statusUpGroupId int32, nowMillis int64) {
@@ -245,19 +223,13 @@ func (s *CostumeServiceServer) applyAwakenItemAcquire(user *store.UserState, ite
log.Printf("[CostumeService] Awaken: granted thought id=%d", acq.PossessionId)
}
var activeSkillDiffTables = []string{
"IUserCostumeActiveSkill",
"IUserMaterial",
"IUserConsumableItem",
}
func (s *CostumeServiceServer) EnhanceActiveSkill(ctx context.Context, req *pb.EnhanceActiveSkillRequest) (*pb.EnhanceActiveSkillResponse, error) {
log.Printf("[CostumeService] EnhanceActiveSkill: uuid=%s addLevel=%d", req.UserCostumeUuid, req.AddLevelCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
costume, ok := user.Costumes[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] EnhanceActiveSkill: costume uuid=%s not found", req.UserCostumeUuid)
@@ -332,20 +304,16 @@ func (s *CostumeServiceServer) EnhanceActiveSkill(ctx context.Context, req *pb.E
return nil, fmt.Errorf("costume enhance active skill: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, activeSkillDiffTables))
return &pb.EnhanceActiveSkillResponse{
DiffUserData: diff,
}, nil
return &pb.EnhanceActiveSkillResponse{}, nil
}
func (s *CostumeServiceServer) LimitBreak(ctx context.Context, req *pb.LimitBreakRequest) (*pb.LimitBreakResponse, error) {
log.Printf("[CostumeService] LimitBreak: uuid=%s materials=%v", req.UserCostumeUuid, req.Materials)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
costume, ok := user.Costumes[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] LimitBreak: costume uuid=%s not found", req.UserCostumeUuid)
@@ -389,30 +357,16 @@ func (s *CostumeServiceServer) LimitBreak(ctx context.Context, req *pb.LimitBrea
return nil, fmt.Errorf("costume limit break: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, costumeDiffTables))
return &pb.LimitBreakResponse{
DiffUserData: diff,
}, nil
}
var lotteryEffectDiffTables = []string{
"IUserCostume",
"IUserCostumeLotteryEffect",
"IUserCostumeLotteryEffectAbility",
"IUserCostumeLotteryEffectStatusUp",
"IUserCostumeLotteryEffectPending",
"IUserConsumableItem",
"IUserMaterial",
return &pb.LimitBreakResponse{}, nil
}
func (s *CostumeServiceServer) UnlockLotteryEffectSlot(ctx context.Context, req *pb.UnlockLotteryEffectSlotRequest) (*pb.UnlockLotteryEffectSlotResponse, error) {
log.Printf("[CostumeService] UnlockLotteryEffectSlot: uuid=%s slot=%d", req.UserCostumeUuid, req.SlotNumber)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
costume, ok := user.Costumes[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] UnlockLotteryEffectSlot: costume uuid=%s not found", req.UserCostumeUuid)
@@ -458,26 +412,16 @@ func (s *CostumeServiceServer) UnlockLotteryEffectSlot(ctx context.Context, req
return nil, fmt.Errorf("costume unlock lottery effect slot: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, lotteryEffectDiffTables))
return &pb.UnlockLotteryEffectSlotResponse{
DiffUserData: diff,
}, nil
return &pb.UnlockLotteryEffectSlotResponse{}, nil
}
func (s *CostumeServiceServer) DrawLotteryEffect(ctx context.Context, req *pb.DrawLotteryEffectRequest) (*pb.DrawLotteryEffectResponse, error) {
log.Printf("[CostumeService] DrawLotteryEffect: uuid=%s slot=%d", req.UserCostumeUuid, req.SlotNumber)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserMaterial", oldUser, userdata.SortedMaterialRecords, []string{"userId", "materialId"}).
Track("IUserConsumableItem", oldUser, userdata.SortedConsumableItemRecords, []string{"userId", "consumableItemId"}).
Track("IUserCostumeLotteryEffectPending", oldUser, userdata.SortedCostumeLotteryEffectPendingRecords, []string{"userId", "userCostumeUuid"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
costume, ok := user.Costumes[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] DrawLotteryEffect: costume uuid=%s not found", req.UserCostumeUuid)
@@ -514,7 +458,7 @@ func (s *CostumeServiceServer) DrawLotteryEffect(ctx context.Context, req *pb.Dr
totalWeight += row.Weight
}
roll := rand.Int31n(totalWeight)
var picked masterdata.CostumeLotteryEffectOddsRow
var picked masterdata.EntityMCostumeLotteryEffectOddsGroup
for _, row := range oddsPool {
roll -= row.Weight
if roll < 0 {
@@ -550,24 +494,16 @@ func (s *CostumeServiceServer) DrawLotteryEffect(ctx context.Context, req *pb.Dr
return nil, fmt.Errorf("costume draw lottery effect: %w", err)
}
diff := tracker.Apply(snapshot, userdata.ProjectTables(snapshot, lotteryEffectDiffTables))
return &pb.DrawLotteryEffectResponse{
DiffUserData: diff,
}, nil
return &pb.DrawLotteryEffectResponse{}, nil
}
func (s *CostumeServiceServer) ConfirmLotteryEffect(ctx context.Context, req *pb.ConfirmLotteryEffectRequest) (*pb.ConfirmLotteryEffectResponse, error) {
log.Printf("[CostumeService] ConfirmLotteryEffect: uuid=%s accept=%v", req.UserCostumeUuid, req.IsAccept)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserCostumeLotteryEffectPending", oldUser, userdata.SortedCostumeLotteryEffectPendingRecords, []string{"userId", "userCostumeUuid"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
pending, ok := user.CostumeLotteryEffectPending[req.UserCostumeUuid]
if !ok {
log.Printf("[CostumeService] ConfirmLotteryEffect: no pending for uuid=%s", req.UserCostumeUuid)
@@ -596,9 +532,5 @@ func (s *CostumeServiceServer) ConfirmLotteryEffect(ctx context.Context, req *pb
return nil, fmt.Errorf("costume confirm lottery effect: %w", err)
}
diff := tracker.Apply(snapshot, userdata.ProjectTables(snapshot, lotteryEffectDiffTables))
return &pb.ConfirmLotteryEffectResponse{
DiffUserData: diff,
}, nil
return &pb.ConfirmLotteryEffectResponse{}, nil
}
+1 -1
View File
@@ -41,7 +41,7 @@ func (s *DataServiceServer) GetUserDataNameV2(ctx context.Context, _ *emptypb.Em
func (s *DataServiceServer) GetUserData(ctx context.Context, req *pb.UserDataGetRequest) (*pb.UserDataGetResponse, error) {
log.Printf("[DataService] GetUserData: tables=%v", req.TableName)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("snapshot user: %w", err)
+33 -59
View File
@@ -8,7 +8,6 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type DeckServiceServer struct {
@@ -23,26 +22,23 @@ func NewDeckServiceServer(users store.UserRepository, sessions store.SessionRepo
func (s *DeckServiceServer) UpdateName(ctx context.Context, req *pb.UpdateNameRequest) (*pb.UpdateNameResponse, error) {
log.Printf("[DeckService] UpdateName: deckType=%d deckNumber=%d name=%q", req.DeckType, req.UserDeckNumber, req.Name)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
deckKey := store.DeckKey{DeckType: model.DeckType(req.DeckType), UserDeckNumber: req.UserDeckNumber}
deck := user.Decks[deckKey]
deck.Name = req.Name
user.Decks[deckKey] = deck
})
result := userdata.ProjectTables(user, []string{"IUserDeck"})
return &pb.UpdateNameResponse{
DiffUserData: userdata.BuildDiffFromTables(result),
}, nil
return &pb.UpdateNameResponse{}, nil
}
func (s *DeckServiceServer) RefreshDeckPower(ctx context.Context, req *pb.RefreshDeckPowerRequest) (*pb.RefreshDeckPowerResponse, error) {
log.Printf("[DeckService] RefreshDeckPower: deckType=%d deckNumber=%d", req.DeckType, req.UserDeckNumber)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
if req.DeckPower == nil {
log.Printf("[DeckService] RefreshDeckPower: deckPower is nil")
return
@@ -81,19 +77,14 @@ func (s *DeckServiceServer) RefreshDeckPower(ctx context.Context, req *pb.Refres
}
})
result := userdata.ProjectTables(user, []string{
"IUserDeck", "IUserDeckCharacter", "IUserDeckTypeNote",
})
return &pb.RefreshDeckPowerResponse{
DiffUserData: userdata.BuildDiffFromTables(result),
}, nil
return &pb.RefreshDeckPowerResponse{}, nil
}
func (s *DeckServiceServer) RefreshMultiDeckPower(ctx context.Context, req *pb.RefreshMultiDeckPowerRequest) (*pb.RefreshMultiDeckPowerResponse, error) {
log.Printf("[DeckService] RefreshMultiDeckPower: %d entries", len(req.DeckPowerInfo))
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
for _, info := range req.DeckPowerInfo {
if info.DeckPower == nil {
continue
@@ -133,12 +124,7 @@ func (s *DeckServiceServer) RefreshMultiDeckPower(ctx context.Context, req *pb.R
}
})
result := userdata.ProjectTables(user, []string{
"IUserDeck", "IUserDeckCharacter", "IUserDeckTypeNote",
})
return &pb.RefreshMultiDeckPowerResponse{
DiffUserData: userdata.BuildDiffFromTables(result),
}, nil
return &pb.RefreshMultiDeckPowerResponse{}, nil
}
func deckSlotsFromProto(deck *pb.Deck) []store.DeckCharacterInput {
@@ -171,47 +157,23 @@ func (s *DeckServiceServer) ReplaceDeck(ctx context.Context, req *pb.ReplaceDeck
i+1, ch.UserCostumeUuid, ch.MainUserWeaponUuid, ch.SubUserWeaponUuid, ch.UserCompanionUuid, ch.UserThoughtUuid)
}
}
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserDeckSubWeaponGroup", oldUser, userdata.DeckSubWeaponRecords,
[]string{"userId", "userDeckCharacterUuid", "userWeaponUuid"}).
Track("IUserDeckPartsGroup", oldUser, userdata.DeckPartsGroupRecords,
[]string{"userId", "userDeckCharacterUuid", "userPartsUuid"}).
Track("IUserDeckCharacterDressupCostume", oldUser, userdata.DeckDressupCostumeRecords,
[]string{"userId", "userDeckCharacterUuid"})
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
if req.Deck == nil {
return
}
store.ApplyDeckReplacement(user, model.DeckType(req.DeckType), req.UserDeckNumber, deckSlotsFromProto(req.Deck), gametime.NowMillis())
})
result := userdata.ProjectTables(user, []string{
"IUserDeck", "IUserDeckCharacter", "IUserDeckSubWeaponGroup", "IUserDeckPartsGroup",
"IUserDeckCharacterDressupCostume",
})
return &pb.ReplaceDeckResponse{
DiffUserData: tracker.Apply(user, result),
}, nil
return &pb.ReplaceDeckResponse{}, nil
}
func (s *DeckServiceServer) ReplaceTripleDeck(ctx context.Context, req *pb.ReplaceTripleDeckRequest) (*pb.ReplaceTripleDeckResponse, error) {
log.Printf("[DeckService] ReplaceTripleDeck: deckType=%d deckNumber=%d", req.DeckType, req.UserDeckNumber)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserDeckSubWeaponGroup", oldUser, userdata.DeckSubWeaponRecords,
[]string{"userId", "userDeckCharacterUuid", "userWeaponUuid"}).
Track("IUserDeckPartsGroup", oldUser, userdata.DeckPartsGroupRecords,
[]string{"userId", "userDeckCharacterUuid", "userPartsUuid"}).
Track("IUserDeckCharacterDressupCostume", oldUser, userdata.DeckDressupCostumeRecords,
[]string{"userId", "userDeckCharacterUuid"})
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
for idx, detail := range []*pb.DeckDetail{req.DeckDetail01, req.DeckDetail02, req.DeckDetail03} {
if detail == nil || detail.Deck == nil {
@@ -231,11 +193,23 @@ func (s *DeckServiceServer) ReplaceTripleDeck(ctx context.Context, req *pb.Repla
}
})
result := userdata.ProjectTables(user, []string{
"IUserDeck", "IUserDeckCharacter", "IUserDeckSubWeaponGroup", "IUserDeckPartsGroup",
"IUserDeckCharacterDressupCostume",
})
return &pb.ReplaceTripleDeckResponse{
DiffUserData: tracker.Apply(user, result),
}, nil
return &pb.ReplaceTripleDeckResponse{}, nil
}
func (s *DeckServiceServer) ReplaceMultiDeck(ctx context.Context, req *pb.ReplaceMultiDeckRequest) (*pb.ReplaceMultiDeckResponse, error) {
log.Printf("[DeckService] ReplaceMultiDeck: %d entries", len(req.DeckDetail))
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
for idx, detail := range req.DeckDetail {
if detail == nil || detail.Deck == nil {
continue
}
log.Printf("[DeckService] ReplaceMultiDeck detail %d: deckType=%d deckNumber=%d", idx+1, detail.DeckType, detail.UserDeckNumber)
store.ApplyDeckReplacement(user, model.DeckType(detail.DeckType), detail.UserDeckNumber, deckSlotsFromProto(detail.Deck), nowMillis)
}
})
return &pb.ReplaceMultiDeckResponse{}, nil
}
+3 -8
View File
@@ -7,7 +7,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type DokanServiceServer struct {
@@ -23,8 +22,8 @@ func NewDokanServiceServer(users store.UserRepository, sessions store.SessionRep
func (s *DokanServiceServer) RegisterDokanConfirmed(ctx context.Context, req *pb.RegisterDokanConfirmedRequest) (*pb.RegisterDokanConfirmedResponse, error) {
log.Printf("[DokanService] RegisterDokanConfirmed: dokanIds=%v", req.DokanId)
userId := currentUserId(ctx, s.users, s.sessions)
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
for _, id := range req.DokanId {
user.DokanConfirmed[id] = true
}
@@ -33,9 +32,5 @@ func (s *DokanServiceServer) RegisterDokanConfirmed(ctx context.Context, req *pb
return nil, fmt.Errorf("update user: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserDokan"}))
return &pb.RegisterDokanConfirmedResponse{
DiffUserData: diff,
}, nil
return &pb.RegisterDokanConfirmedResponse{}, nil
}
+8 -32
View File
@@ -10,7 +10,6 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
const (
@@ -19,18 +18,6 @@ const (
exploreRewardBaseCount = 1
)
var exploreDiffTables = []string{
"IUserExplore",
"IUserExploreScore",
}
var exploreFinishDiffTables = []string{
"IUserExplore",
"IUserExploreScore",
"IUserMaterial",
"IUserStatus",
}
type ExploreServiceServer struct {
pb.UnimplementedExploreServiceServer
users store.UserRepository
@@ -49,10 +36,10 @@ func (s *ExploreServiceServer) StartExplore(ctx context.Context, req *pb.StartEx
return nil, fmt.Errorf("explore id=%d not found", req.ExploreId)
}
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
explore := s.catalog.Explores[req.ExploreId]
if req.UseConsumableItemId > 0 && explore.ConsumeItemCount > 0 {
cur := user.ConsumableItems[req.UseConsumableItemId]
@@ -71,11 +58,7 @@ func (s *ExploreServiceServer) StartExplore(ctx context.Context, req *pb.StartEx
return nil, fmt.Errorf("start explore: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, exploreDiffTables))
return &pb.StartExploreResponse{
DiffUserData: diff,
}, nil
return &pb.StartExploreResponse{}, nil
}
func (s *ExploreServiceServer) FinishExplore(ctx context.Context, req *pb.FinishExploreRequest) (*pb.FinishExploreResponse, error) {
@@ -88,12 +71,12 @@ func (s *ExploreServiceServer) FinishExplore(ctx context.Context, req *pb.Finish
assetGradeIconId := s.catalog.GradeForScore(req.ExploreId, req.Score)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
rewardCount := int32(exploreRewardBaseCount) * explore.RewardLotteryCount
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
existing, exists := user.ExploreScores[req.ExploreId]
if !exists || req.Score > existing.MaxScore {
user.ExploreScores[req.ExploreId] = store.ExploreScoreState{
@@ -123,8 +106,6 @@ func (s *ExploreServiceServer) FinishExplore(ctx context.Context, req *pb.Finish
return nil, fmt.Errorf("finish explore: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, exploreFinishDiffTables))
rewards := []*pb.ExploreReward{
{
PossessionType: int32(model.PossessionTypeMaterial),
@@ -137,17 +118,16 @@ func (s *ExploreServiceServer) FinishExplore(ctx context.Context, req *pb.Finish
AcquireStaminaCount: exploreStaminaRecovery,
ExploreReward: rewards,
AssetGradeIconId: assetGradeIconId,
DiffUserData: diff,
}, nil
}
func (s *ExploreServiceServer) RetireExplore(ctx context.Context, req *pb.RetireExploreRequest) (*pb.RetireExploreResponse, error) {
log.Printf("[ExploreService] RetireExplore: exploreId=%d", req.ExploreId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
user.Explore = store.ExploreState{
PlayingExploreId: 0,
IsUseExploreTicket: false,
@@ -159,9 +139,5 @@ func (s *ExploreServiceServer) RetireExplore(ctx context.Context, req *pb.Retire
return nil, fmt.Errorf("retire explore: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserExplore"}))
return &pb.RetireExploreResponse{
DiffUserData: diff,
}, nil
return &pb.RetireExploreResponse{}, nil
}
+3 -7
View File
@@ -6,7 +6,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -23,7 +22,7 @@ func NewFriendServiceServer(users store.UserRepository, sessions store.SessionRe
func (s *FriendServiceServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
log.Printf("[FriendService] GetUser: playerId=%d", req.PlayerId)
return &pb.GetUserResponse{DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetUserResponse{}, nil
}
func (s *FriendServiceServer) GetFriendList(ctx context.Context, req *pb.GetFriendListRequest) (*pb.GetFriendListResponse, error) {
@@ -32,22 +31,19 @@ func (s *FriendServiceServer) GetFriendList(ctx context.Context, req *pb.GetFrie
FriendUser: []*pb.FriendUser{},
SendCheerCount: 0,
ReceivedCheerCount: 0,
DiffUserData: userdata.EmptyDiff(),
}, nil
}
func (s *FriendServiceServer) GetFriendRequestList(ctx context.Context, req *emptypb.Empty) (*pb.GetFriendRequestListResponse, error) {
log.Printf("[FriendService] GetFriendRequestList")
return &pb.GetFriendRequestListResponse{
User: []*pb.User{},
DiffUserData: userdata.EmptyDiff(),
User: []*pb.User{},
}, nil
}
func (s *FriendServiceServer) SearchRecommendedUsers(ctx context.Context, req *emptypb.Empty) (*pb.SearchRecommendedUsersResponse, error) {
log.Printf("[FriendService] SearchRecommendedUsers")
return &pb.SearchRecommendedUsersResponse{
Users: []*pb.User{},
DiffUserData: userdata.EmptyDiff(),
Users: []*pb.User{},
}, nil
}
+8 -36
View File
@@ -11,25 +11,11 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
)
var gachaDiffTables = []string{
"IUserGem",
"IUserCostume",
"IUserWeapon",
"IUserConsumableItem",
"IUserCostumeActiveSkill",
"IUserWeaponNote",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserCharacter",
"IUserMaterial",
}
type GachaServiceServer struct {
pb.UnimplementedGachaServiceServer
users store.UserRepository
@@ -56,7 +42,7 @@ func (s *GachaServiceServer) GetGachaList(ctx context.Context, req *pb.GetGachaL
log.Printf("[GachaService] GetGachaList: labels=%v", req.GachaLabelType)
catalog := s.catalog
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, err := s.users.UpdateUser(userId, func(user *store.UserState) {
@@ -82,7 +68,6 @@ func (s *GachaServiceServer) GetGachaList(ctx context.Context, req *pb.GetGachaL
return &pb.GetGachaListResponse{
Gacha: gachaList,
ConvertedGachaMedal: toProtoConvertedGachaMedal(user.Gacha.ConvertedGachaMedal),
DiffUserData: userdata.EmptyDiff(),
}, nil
}
@@ -134,7 +119,7 @@ func (s *GachaServiceServer) GetGacha(ctx context.Context, req *pb.GetGachaReque
catalog := s.catalog
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("snapshot user: %w", err)
@@ -152,8 +137,7 @@ func (s *GachaServiceServer) GetGacha(ctx context.Context, req *pb.GetGachaReque
}
return &pb.GetGachaResponse{
Gacha: byId,
DiffUserData: userdata.EmptyDiff(),
Gacha: byId,
}, nil
}
@@ -165,7 +149,7 @@ func (s *GachaServiceServer) Draw(ctx context.Context, req *pb.DrawRequest) (*pb
return nil, fmt.Errorf("gacha %d not found", req.GachaId)
}
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
execCount := req.ExecCount
if execCount <= 0 {
execCount = 1
@@ -290,17 +274,11 @@ func (s *GachaServiceServer) Draw(ctx context.Context, req *pb.DrawRequest) (*pb
bs := updatedUser.Gacha.BannerStates[entry.GachaId]
nextGacha := toProtoGacha(*entry, &bs)
changedStoryIds := s.handler.Granter.DrainChangedStoryWeaponIds()
diffOrder := append(gachaDiffTables, "IUserWeaponStory")
diff := userdata.BuildDiffFromTablesOrdered(userdata.ProjectTables(updatedUser, diffOrder), diffOrder)
userdata.AddWeaponStoryDiff(diff, updatedUser, changedStoryIds)
return &pb.DrawResponse{
NextGacha: nextGacha,
GachaResult: gachaResults,
GachaBonus: bonuses,
MenuGachaBadgeInfo: []*pb.MenuGachaBadgeInfo{},
DiffUserData: diff,
}, nil
}
@@ -312,7 +290,7 @@ func (s *GachaServiceServer) ResetBoxGacha(ctx context.Context, req *pb.ResetBox
return nil, fmt.Errorf("gacha %d not found", req.GachaId)
}
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
updatedUser, err := s.users.UpdateUser(userId, func(user *store.UserState) {
if resetErr := s.handler.HandleResetBox(user, *entry); resetErr != nil {
log.Printf("[GachaService] ResetBoxGacha error: %v", resetErr)
@@ -325,14 +303,13 @@ func (s *GachaServiceServer) ResetBoxGacha(ctx context.Context, req *pb.ResetBox
bs := updatedUser.Gacha.BannerStates[entry.GachaId]
return &pb.ResetBoxGachaResponse{
Gacha: toProtoGacha(*entry, &bs),
DiffUserData: userdata.EmptyDiff(),
Gacha: toProtoGacha(*entry, &bs),
}, nil
}
func (s *GachaServiceServer) GetRewardGacha(ctx context.Context, req *emptypb.Empty) (*pb.GetRewardGachaResponse, error) {
log.Printf("[GachaService] GetRewardGacha")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("snapshot user: %w", err)
@@ -353,14 +330,13 @@ func (s *GachaServiceServer) GetRewardGacha(ctx context.Context, req *emptypb.Em
Available: drawCount < maxCount,
TodaysCurrentDrawCount: drawCount,
DailyMaxCount: maxCount,
DiffUserData: userdata.EmptyDiff(),
}, nil
}
func (s *GachaServiceServer) RewardDraw(ctx context.Context, req *pb.RewardDrawRequest) (*pb.RewardDrawResponse, error) {
log.Printf("[GachaService] RewardDraw: placement=%q reward=%q amount=%q", req.PlacementName, req.RewardName, req.RewardAmount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
var items []gacha.DrawnItem
updatedUser, err := s.users.UpdateUser(userId, func(user *store.UserState) {
@@ -393,12 +369,8 @@ func (s *GachaServiceServer) RewardDraw(ctx context.Context, req *pb.RewardDrawR
})
}
tables := userdata.FullClientTableMap(updatedUser)
diff := userdata.BuildDiffFromTables(tables)
return &pb.RewardDrawResponse{
RewardGachaResult: results,
DiffUserData: diff,
}, nil
}
-2
View File
@@ -5,7 +5,6 @@ import (
"log"
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/userdata"
)
type GameplayServiceServer struct {
@@ -23,6 +22,5 @@ func (s *GameplayServiceServer) CheckBeforeGamePlay(ctx context.Context, req *pb
return &pb.CheckBeforeGamePlayResponse{
IsExistUnreadPop: false,
MenuGachaBadgeInfo: []*pb.MenuGachaBadgeInfo{},
DiffUserData: userdata.EmptyDiff(),
}, nil
}
+4 -9
View File
@@ -11,7 +11,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
@@ -30,7 +29,7 @@ func NewGiftServiceServer(users store.UserRepository, sessions store.SessionRepo
func (s *GiftServiceServer) ReceiveGift(ctx context.Context, req *pb.ReceiveGiftRequest) (*pb.ReceiveGiftResponse, error) {
log.Printf("[GiftService] ReceiveGift: giftUuids=%d", len(req.UserGiftUuid))
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
received := make([]string, 0, len(req.UserGiftUuid))
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
@@ -54,7 +53,6 @@ func (s *GiftServiceServer) ReceiveGift(ctx context.Context, req *pb.ReceiveGift
ReceivedGiftUuid: []string{},
ExpiredGiftUuid: []string{},
OverflowGiftUuid: []string{},
DiffUserData: userdata.EmptyDiff(),
}, nil
}
@@ -62,7 +60,6 @@ func (s *GiftServiceServer) ReceiveGift(ctx context.Context, req *pb.ReceiveGift
ReceivedGiftUuid: received,
ExpiredGiftUuid: []string{},
OverflowGiftUuid: []string{},
DiffUserData: userdata.EmptyDiff(),
}, nil
}
@@ -70,7 +67,7 @@ func (s *GiftServiceServer) GetGiftList(ctx context.Context, req *pb.GetGiftList
log.Printf("[GiftService] GetGiftList: rewardKinds=%v expirationType=%d ascending=%v nextCursor=%d previousCursor=%d getCount=%d",
req.RewardKindType, req.ExpirationType, req.IsAscendingSort, req.NextCursor, req.PreviousCursor, req.GetCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("snapshot user: %w", err)
@@ -101,13 +98,12 @@ func (s *GiftServiceServer) GetGiftList(ctx context.Context, req *pb.GetGiftList
TotalPageCount: pageCount(len(user.Gifts.NotReceived), int(req.GetCount)),
NextCursor: 0,
PreviousCursor: 0,
DiffUserData: userdata.EmptyDiff(),
}, nil
}
func (s *GiftServiceServer) GetGiftReceiveHistoryList(ctx context.Context, req *emptypb.Empty) (*pb.GetGiftReceiveHistoryListResponse, error) {
log.Printf("[GiftService] GetGiftReceiveHistoryList")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("snapshot user: %w", err)
@@ -121,8 +117,7 @@ func (s *GiftServiceServer) GetGiftReceiveHistoryList(ctx context.Context, req *
})
}
return &pb.GetGiftReceiveHistoryListResponse{
Gift: items,
DiffUserData: userdata.EmptyDiff(),
Gift: items,
}, nil
}
+11 -22
View File
@@ -8,7 +8,6 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -27,8 +26,8 @@ func NewGimmickServiceServer(users store.UserRepository, sessions store.SessionR
func (s *GimmickServiceServer) UpdateSequence(ctx context.Context, req *pb.UpdateSequenceRequest) (*pb.UpdateSequenceResponse, error) {
log.Printf("[GimmickService] UpdateSequence: scheduleId=%d sequenceId=%d",
req.GimmickSequenceScheduleId, req.GimmickSequenceId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
key := store.GimmickSequenceKey{
GimmickSequenceScheduleId: req.GimmickSequenceScheduleId,
GimmickSequenceId: req.GimmickSequenceId,
@@ -37,16 +36,14 @@ func (s *GimmickServiceServer) UpdateSequence(ctx context.Context, req *pb.Updat
sequence.Key = key
user.Gimmick.Sequences[key] = sequence
})
return &pb.UpdateSequenceResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{"IUserGimmickSequence"})),
}, nil
return &pb.UpdateSequenceResponse{}, nil
}
func (s *GimmickServiceServer) UpdateGimmickProgress(ctx context.Context, req *pb.UpdateGimmickProgressRequest) (*pb.UpdateGimmickProgressResponse, error) {
log.Printf("[GimmickService] UpdateGimmickProgress: scheduleId=%d sequenceId=%d gimmickId=%d ornamentIndex=%d progressValueBit=%d flowType=%d",
req.GimmickSequenceScheduleId, req.GimmickSequenceId, req.GimmickId, req.GimmickOrnamentIndex, req.ProgressValueBit, req.FlowType)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
progressKey := store.GimmickKey{
GimmickSequenceScheduleId: req.GimmickSequenceScheduleId,
@@ -74,18 +71,14 @@ func (s *GimmickServiceServer) UpdateGimmickProgress(ctx context.Context, req *p
GimmickOrnamentReward: []*pb.GimmickReward{},
IsSequenceCleared: false,
GimmickSequenceClearReward: []*pb.GimmickReward{},
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{
"IUserGimmick",
"IUserGimmickOrnamentProgress",
})),
}, nil
}
func (s *GimmickServiceServer) InitSequenceSchedule(ctx context.Context, _ *emptypb.Empty) (*pb.InitSequenceScheduleResponse, error) {
log.Printf("[GimmickService] InitSequenceSchedule")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
now := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
added := 0
for _, key := range s.gimmickCatalog.ActiveScheduleKeys(*user, now) {
if _, exists := user.Gimmick.Sequences[key]; !exists {
@@ -97,15 +90,13 @@ func (s *GimmickServiceServer) InitSequenceSchedule(ctx context.Context, _ *empt
log.Printf("[GimmickService] InitSequenceSchedule: added %d sequences (total %d)", added, len(user.Gimmick.Sequences))
}
})
return &pb.InitSequenceScheduleResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, gimmickDiffTables)),
}, nil
return &pb.InitSequenceScheduleResponse{}, nil
}
func (s *GimmickServiceServer) Unlock(ctx context.Context, req *pb.UnlockRequest) (*pb.UnlockResponse, error) {
log.Printf("[GimmickService] Unlock: gimmickKeys=%d", len(req.GimmickKey))
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
for _, item := range req.GimmickKey {
key := store.GimmickKey{
GimmickSequenceScheduleId: item.GimmickSequenceScheduleId,
@@ -118,7 +109,5 @@ func (s *GimmickServiceServer) Unlock(ctx context.Context, req *pb.UnlockRequest
user.Gimmick.Unlocks[key] = unlock
}
})
return &pb.UnlockResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{"IUserGimmickUnlock"})),
}, nil
return &pb.UnlockResponse{}, nil
}
+14 -15
View File
@@ -208,7 +208,7 @@ func parseListBin(data []byte) listBinIndex {
return idx
}
func loadListBinIndex(revision string) (listBinIndex, bool) {
func loadListBinIndex(baseDir, revision string) (listBinIndex, bool) {
listBinCacheMu.RLock()
idx, ok := listBinCache[revision]
listBinCacheMu.RUnlock()
@@ -230,7 +230,7 @@ func loadListBinIndex(revision string) (listBinIndex, bool) {
listBinInflight[revision] = load
listBinCacheMu.Unlock()
filePath := filepath.Join("assets", "revisions", revision, "list.bin")
filePath := filepath.Join(baseDir, "assets", "revisions", revision, "list.bin")
data, err := os.ReadFile(filePath)
if err != nil {
listBinCacheMu.Lock()
@@ -250,7 +250,7 @@ func loadListBinIndex(revision string) (listBinIndex, bool) {
return idx, true
}
func loadInfoIndex(revision string) map[string]infoAlias {
func loadInfoIndex(baseDir, revision string) map[string]infoAlias {
infoCacheMu.RLock()
m, ok := infoCache[revision]
infoCacheMu.RUnlock()
@@ -272,7 +272,7 @@ func loadInfoIndex(revision string) map[string]infoAlias {
infoInflight[revision] = load
infoCacheMu.Unlock()
filePath := filepath.Join("assets", "revisions", revision, "info.json")
filePath := filepath.Join(baseDir, "assets", "revisions", revision, "info.json")
data, err := os.ReadFile(filePath)
if err != nil {
infoCacheMu.Lock()
@@ -378,7 +378,7 @@ func hasNonASCII(s string) bool {
// an en locale fallback is appended (marked IsLocaleFallback so callers can skip MD5 validation).
// For paths with non-ASCII characters, mojibake (double-encoded) and fullwidth-to-ASCII
// variants are also tried.
func pathStrToFullPaths(revision, assetType, pathStr string) []pathCandidate {
func pathStrToFullPaths(baseDir, revision, assetType, pathStr string) []pathCandidate {
fsPath := strings.ReplaceAll(pathStr, ")", "/")
if strings.Contains(fsPath, "..") || filepath.IsAbs(fsPath) || strings.HasPrefix(fsPath, "/") {
return nil
@@ -402,7 +402,7 @@ func pathStrToFullPaths(revision, assetType, pathStr string) []pathCandidate {
if strings.Contains(pathStr, ")ko)") {
entries = append(entries, tagged{strings.ReplaceAll(pathStr, ")ko)", ")en)"), true})
}
base := filepath.Join("assets", "revisions", revision)
base := filepath.Join(baseDir, "assets", "revisions", revision)
var out []pathCandidate
seen := make(map[string]bool)
for _, e := range entries {
@@ -434,13 +434,13 @@ func appendUniqueCandidate(candidates []assetCandidate, seen map[string]bool, ca
return append(candidates, candidate)
}
func duplicateCandidatePath(candidate assetCandidate, assetType, targetRevision, targetBaseName string) string {
root := filepath.Join("assets", "revisions", candidate.Revision, assetType)
func duplicateCandidatePath(baseDir string, candidate assetCandidate, assetType, targetRevision, targetBaseName string) string {
root := filepath.Join(baseDir, "assets", "revisions", candidate.Revision, assetType)
rel, err := filepath.Rel(root, candidate.Path)
if err != nil || strings.HasPrefix(rel, "..") || filepath.IsAbs(rel) {
return ""
}
return filepath.Join("assets", "revisions", targetRevision, assetType, filepath.Dir(rel), targetBaseName)
return filepath.Join(baseDir, "assets", "revisions", targetRevision, assetType, filepath.Dir(rel), targetBaseName)
}
// objectIdToFilePathCandidates returns candidate file paths for the object: list.bin path, locale fallbacks
@@ -448,8 +448,8 @@ func duplicateCandidatePath(candidate assetCandidate, assetType, targetRevision,
// The original locale path is tried first (with MD5 validation); locale fallbacks are tried after
// (without MD5 validation, since the hash in list.bin refers to the original locale's content).
// Callers should try each path until one exists on disk.
func objectIdToFilePathCandidates(revision, assetType, objectId string) (candidates []assetCandidate, size int64, ok bool) {
idx, ok := loadListBinIndex(revision)
func objectIdToFilePathCandidates(baseDir, revision, assetType, objectId string) (candidates []assetCandidate, size int64, ok bool) {
idx, ok := loadListBinIndex(baseDir, revision)
if !ok || idx == nil {
return nil, 0, false
}
@@ -457,7 +457,7 @@ func objectIdToFilePathCandidates(revision, assetType, objectId string) (candida
if !ok || entry.Path == "" {
return nil, 0, false
}
paths := pathStrToFullPaths(revision, assetType, entry.Path)
paths := pathStrToFullPaths(baseDir, revision, assetType, entry.Path)
if len(paths) == 0 {
return nil, 0, false
}
@@ -474,15 +474,14 @@ func objectIdToFilePathCandidates(revision, assetType, objectId string) (candida
ExpectedMD5: md5,
})
}
// Add paths from info.json: when requested file is a "from-name" (duplicate not included), serve "to-name" instead.
infoIndex := loadInfoIndex(revision)
infoIndex := loadInfoIndex(baseDir, revision)
if len(infoIndex) > 0 {
for _, c := range candidates {
alias, ok := infoIndex[filepath.Base(c.Path)]
if !ok || alias.ToName == "" {
continue
}
alt := duplicateCandidatePath(c, assetType, alias.ToRevision, alias.ToName)
alt := duplicateCandidatePath(baseDir, c, assetType, alias.ToRevision, alias.ToName)
if alt == "" {
continue
}
+3 -8
View File
@@ -11,7 +11,6 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -29,9 +28,9 @@ func NewLoginBonusServiceServer(users store.UserRepository, sessions store.Sessi
func (s *LoginBonusServiceServer) ReceiveStamp(ctx context.Context, req *emptypb.Empty) (*pb.ReceiveStampResponse, error) {
log.Printf("[LoginBonusService] ReceiveStamp")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
now := gametime.NowMillis()
nextStamp := user.LoginBonus.CurrentStampNumber + 1
@@ -64,9 +63,5 @@ func (s *LoginBonusServiceServer) ReceiveStamp(ctx context.Context, req *emptypb
user.LoginBonus.LatestVersion = now
})
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(user,
[]string{"IUserLoginBonus"},
))
setCommonResponseTrailers(ctx, diff, false)
return &pb.ReceiveStampResponse{DiffUserData: diff}, nil
return &pb.ReceiveStampResponse{}, nil
}
+3 -18
View File
@@ -8,14 +8,8 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
var materialDiffTables = []string{
"IUserMaterial",
"IUserConsumableItem",
}
type MaterialServiceServer struct {
pb.UnimplementedMaterialServiceServer
users store.UserRepository
@@ -31,13 +25,9 @@ func NewMaterialServiceServer(users store.UserRepository, sessions store.Session
func (s *MaterialServiceServer) Sell(ctx context.Context, req *pb.MaterialSellRequest) (*pb.MaterialSellResponse, error) {
log.Printf("[MaterialService] Sell: %d item(s)", len(req.MaterialPossession))
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserMaterial", oldUser, userdata.SortedMaterialRecords, []string{"userId", "materialId"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
totalGold := int32(0)
for _, item := range req.MaterialPossession {
mat, ok := s.catalog.All[item.MaterialId]
@@ -71,10 +61,5 @@ func (s *MaterialServiceServer) Sell(ctx context.Context, req *pb.MaterialSellRe
return nil, fmt.Errorf("material sell: %w", err)
}
tables := userdata.ProjectTables(snapshot, materialDiffTables)
diff := tracker.Apply(snapshot, tables)
return &pb.MaterialSellResponse{
DiffUserData: diff,
}, nil
return &pb.MaterialSellResponse{}, nil
}
+3 -8
View File
@@ -7,7 +7,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type MissionServiceServer struct {
@@ -23,15 +22,11 @@ func NewMissionServiceServer(users store.UserRepository, sessions store.SessionR
func (s *MissionServiceServer) UpdateMissionProgress(ctx context.Context, req *pb.UpdateMissionProgressRequest) (*pb.UpdateMissionProgressResponse, error) {
log.Printf("[MissionService] UpdateMissionProgress: cage=%v pictureBook=%v", req.CageMeasurableValues, req.PictureBookMeasurableValues)
userId := currentUserId(ctx, s.users, s.sessions)
snapshot, err := s.users.LoadUser(userId)
userId := CurrentUserId(ctx, s.users, s.sessions)
_, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("snapshot user: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserMission"}))
return &pb.UpdateMissionProgressResponse{
DiffUserData: diff,
}, nil
return &pb.UpdateMissionProgressResponse{}, nil
}
+3 -8
View File
@@ -8,7 +8,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type MovieServiceServer struct {
@@ -24,10 +23,10 @@ func NewMovieServiceServer(users store.UserRepository, sessions store.SessionRep
func (s *MovieServiceServer) SaveViewedMovie(ctx context.Context, req *pb.SaveViewedMovieRequest) (*pb.SaveViewedMovieResponse, error) {
log.Printf("[MovieService] SaveViewedMovie: movieIds=%v", req.MovieId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
now := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
for _, mid := range req.MovieId {
user.ViewedMovies[mid] = now
}
@@ -36,9 +35,5 @@ func (s *MovieServiceServer) SaveViewedMovie(ctx context.Context, req *pb.SaveVi
return nil, fmt.Errorf("update user: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserMovie"}))
return &pb.SaveViewedMovieResponse{
DiffUserData: diff,
}, nil
return &pb.SaveViewedMovieResponse{}, nil
}
+3 -8
View File
@@ -7,7 +7,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type NaviCutInServiceServer struct {
@@ -23,17 +22,13 @@ func NewNaviCutInServiceServer(users store.UserRepository, sessions store.Sessio
func (s *NaviCutInServiceServer) RegisterPlayed(ctx context.Context, req *pb.RegisterPlayedRequest) (*pb.RegisterPlayedResponse, error) {
log.Printf("[NaviCutInService] RegisterPlayed: naviCutId=%d", req.NaviCutId)
userId := currentUserId(ctx, s.users, s.sessions)
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
user.NaviCutInPlayed[req.NaviCutId] = true
})
if err != nil {
return nil, fmt.Errorf("update user: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserNaviCutIn"}))
return &pb.RegisterPlayedResponse{
DiffUserData: diff,
}, nil
return &pb.RegisterPlayedResponse{}, nil
}
+1 -4
View File
@@ -6,7 +6,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -23,20 +22,18 @@ func NewNotificationServiceServer(users store.UserRepository, sessions store.Ses
func (s *NotificationServiceServer) GetHeaderNotification(ctx context.Context, req *emptypb.Empty) (*pb.GetHeaderNotificationResponse, error) {
log.Printf("[NotificationService] GetHeaderNotification")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return &pb.GetHeaderNotificationResponse{
GiftNotReceiveCount: 0,
FriendRequestReceiveCount: 0,
IsExistUnreadInformation: false,
DiffUserData: userdata.EmptyDiff(),
}, nil
}
return &pb.GetHeaderNotificationResponse{
GiftNotReceiveCount: int32(len(user.Gifts.NotReceived)),
FriendRequestReceiveCount: user.Notifications.FriendRequestReceiveCount,
IsExistUnreadInformation: user.Notifications.IsExistUnreadInformation,
DiffUserData: userdata.EmptyDiff(),
}, nil
}
+10 -8
View File
@@ -50,6 +50,7 @@ const resourcesURLOriginal = "https://resources.app.nierreincarnation.com"
type OctoHTTPServer struct {
mux *http.ServeMux
ResourcesBaseURL string // if non-empty and exactly 43 chars, list.bin is rewritten to use this base for asset URLs
BaseDir string // root directory containing the assets/ tree; empty means current directory
revisions *revisionTracker
resolver *assetResolver
}
@@ -124,12 +125,13 @@ func fileMD5Hex(path string, info os.FileInfo) (string, error) {
return sum, nil
}
func NewOctoHTTPServer(resourcesBaseURL string) *OctoHTTPServer {
func NewOctoHTTPServer(resourcesBaseURL, baseDir string) *OctoHTTPServer {
s := &OctoHTTPServer{
mux: http.NewServeMux(),
ResourcesBaseURL: resourcesBaseURL,
BaseDir: baseDir,
revisions: newRevisionTracker(),
resolver: newAssetResolver(),
resolver: newAssetResolver(baseDir),
}
s.resolver.Prewarm("0")
s.mux.HandleFunc("/", s.handleAll)
@@ -226,7 +228,7 @@ func (s *OctoHTTPServer) handleOctoV2(w http.ResponseWriter, r *http.Request, pa
requestedRevision := parts[len(parts)-1]
if requestedRevision != "" {
revision := "0"
filePath := "assets/revisions/0/list.bin"
filePath := filepath.Join(s.BaseDir, "assets", "revisions", "0", "list.bin")
if requestedRevision != revision {
log.Printf("[OctoV2] Resource list request revision=%s canonicalized to revision=%s", requestedRevision, revision)
}
@@ -266,7 +268,7 @@ func (s *OctoHTTPServer) serveOctoV1List(w http.ResponseWriter, r *http.Request,
requestedRevision = parts[len(parts)-1]
}
revision := "0"
filePath := "assets/revisions/0/list.bin"
filePath := filepath.Join(s.BaseDir, "assets", "revisions", "0", "list.bin")
if requestedRevision != revision {
log.Printf("[OctoV1] list request revision=%s canonicalized to revision=%s", requestedRevision, revision)
}
@@ -316,11 +318,11 @@ func (s *OctoHTTPServer) serveUnsoAsset(w http.ResponseWriter, r *http.Request,
w.WriteHeader(http.StatusNotFound)
return
}
baseDir := filepath.Join("assets", "revisions")
revDir := filepath.Join(s.BaseDir, "assets", "revisions")
var triedPaths []string
var md5Mismatches []string
for _, candidate := range resolution.Candidates {
rel, err := filepath.Rel(baseDir, candidate.Path)
rel, err := filepath.Rel(revDir, candidate.Path)
if err != nil || strings.Contains(rel, "..") || filepath.IsAbs(rel) {
continue
}
@@ -409,9 +411,9 @@ func (s *OctoHTTPServer) serveDatabaseBinE(w http.ResponseWriter, r *http.Reques
break
}
}
filePath := "assets/release/database.bin.e"
filePath := filepath.Join(s.BaseDir, "assets", "release", "database.bin.e")
if version != "" {
vPath := "assets/release/" + version + ".bin.e"
vPath := filepath.Join(s.BaseDir, "assets", "release", version+".bin.e")
if _, err := os.Stat(vPath); err == nil {
filePath = vPath
}
+2 -6
View File
@@ -9,7 +9,6 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type OmikujiServiceServer struct {
@@ -26,21 +25,18 @@ func NewOmikujiServiceServer(users store.UserRepository, sessions store.SessionR
func (s *OmikujiServiceServer) OmikujiDraw(ctx context.Context, req *pb.OmikujiDrawRequest) (*pb.OmikujiDrawResponse, error) {
log.Printf("[OmikujiService] OmikujiDraw: omikujiId=%d", req.OmikujiId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
now := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
user.DrawnOmikuji[req.OmikujiId] = now
})
if err != nil {
return nil, fmt.Errorf("update user: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserOmikuji"}))
return &pb.OmikujiDrawResponse{
OmikujiResultAssetId: s.catalog.LookupAssetId(req.OmikujiId),
OmikujiItem: []*pb.OmikujiItem{},
DiffUserData: diff,
}, nil
}
+9 -31
View File
@@ -10,16 +10,10 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
const partsMaxLevel = int32(15)
var partsDiffTables = []string{
"IUserParts",
"IUserConsumableItem",
}
type PartsServiceServer struct {
pb.UnimplementedPartsServiceServer
users store.UserRepository
@@ -35,13 +29,9 @@ func NewPartsServiceServer(users store.UserRepository, sessions store.SessionRep
func (s *PartsServiceServer) Sell(ctx context.Context, req *pb.PartsSellRequest) (*pb.PartsSellResponse, error) {
log.Printf("[PartsService] Sell: %d part(s)", len(req.UserPartsUuid))
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserParts", oldUser, userdata.SortedPartsRecords, []string{"userId", "userPartsUuid"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
totalGold := int32(0)
for _, uuid := range req.UserPartsUuid {
part, ok := user.Parts[uuid]
@@ -81,23 +71,18 @@ func (s *PartsServiceServer) Sell(ctx context.Context, req *pb.PartsSellRequest)
return nil, fmt.Errorf("parts sell: %w", err)
}
tables := userdata.ProjectTables(snapshot, partsDiffTables)
diff := tracker.Apply(snapshot, tables)
return &pb.PartsSellResponse{
DiffUserData: diff,
}, nil
return &pb.PartsSellResponse{}, nil
}
func (s *PartsServiceServer) Enhance(ctx context.Context, req *pb.PartsEnhanceRequest) (*pb.PartsEnhanceResponse, error) {
log.Printf("[PartsService] Enhance: uuid=%s", req.UserPartsUuid)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
isSuccess := false
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
part, ok := user.Parts[req.UserPartsUuid]
if !ok {
log.Printf("[PartsService] Enhance: part uuid=%s not found", req.UserPartsUuid)
@@ -158,11 +143,8 @@ func (s *PartsServiceServer) Enhance(ctx context.Context, req *pb.PartsEnhanceRe
return nil, fmt.Errorf("parts enhance: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, partsDiffTables))
return &pb.PartsEnhanceResponse{
IsSuccess: isSuccess,
DiffUserData: diff,
IsSuccess: isSuccess,
}, nil
}
@@ -170,10 +152,10 @@ func (s *PartsServiceServer) ReplacePreset(ctx context.Context, req *pb.PartsRep
log.Printf("[PartsService] ReplacePreset: preset=%d uuids=[%s, %s, %s]",
req.UserPartsPresetNumber, req.UserPartsUuid01, req.UserPartsUuid02, req.UserPartsUuid03)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
preset := user.PartsPresets[req.UserPartsPresetNumber]
preset.UserPartsPresetNumber = req.UserPartsPresetNumber
preset.UserPartsUuid01 = req.UserPartsUuid01
@@ -186,9 +168,5 @@ func (s *PartsServiceServer) ReplacePreset(ctx context.Context, req *pb.PartsRep
return nil, fmt.Errorf("parts replace preset: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserPartsPreset"}))
return &pb.PartsReplacePresetResponse{
DiffUserData: diff,
}, nil
return &pb.PartsReplacePresetResponse{}, nil
}
+3 -10
View File
@@ -7,7 +7,6 @@ import (
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type PortalCageServiceServer struct {
@@ -23,17 +22,11 @@ func NewPortalCageServiceServer(users store.UserRepository, sessions store.Sessi
func (s *PortalCageServiceServer) UpdatePortalCageSceneProgress(ctx context.Context, req *pb.UpdatePortalCageSceneProgressRequest) (*pb.UpdatePortalCageSceneProgressResponse, error) {
log.Printf("[PortalCageService] UpdatePortalCageSceneProgress: portalCageSceneId=%d", req.PortalCageSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
now := gametime.NowMillis()
user.PortalCageStatus.IsCurrentProgress = true
user.PortalCageStatus.LatestVersion = now
})
tables := userdata.ProjectTables(user,
[]string{"IUserPortalCageStatus"},
)
return &pb.UpdatePortalCageSceneProgressResponse{
DiffUserData: userdata.BuildDiffFromTablesOrdered(tables, []string{"IUserPortalCageStatus"}),
}, nil
return &pb.UpdatePortalCageSceneProgressResponse{}, nil
}
+17 -46
View File
@@ -10,7 +10,6 @@ import (
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/questflow"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -32,25 +31,11 @@ func NewBigHuntServiceServer(
return &BigHuntServiceServer{users: users, sessions: sessions, catalog: catalog, engine: engine}
}
var bigHuntDiffTables = []string{
"IUserBigHuntProgressStatus",
"IUserBigHuntMaxScore",
"IUserBigHuntStatus",
"IUserBigHuntScheduleMaxScore",
"IUserBigHuntWeeklyMaxScore",
"IUserBigHuntWeeklyStatus",
}
func buildBigHuntDiff(user store.UserState, tableNames []string) map[string]*pb.DiffData {
tables := userdata.ProjectTables(user, tableNames)
return userdata.BuildDiffFromTablesOrdered(tables, tableNames)
}
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)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
bhQuest, ok := s.catalog.QuestById[req.BigHuntQuestId]
@@ -58,7 +43,7 @@ func (s *BigHuntServiceServer) StartBigHuntQuest(ctx context.Context, req *pb.St
log.Printf("[BigHuntService] StartBigHuntQuest: unknown bigHuntQuestId=%d", req.BigHuntQuestId)
}
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
if ok {
s.engine.HandleBigHuntQuestStart(user, bhQuest.QuestId, req.UserDeckNumber, nowMillis)
}
@@ -80,31 +65,27 @@ func (s *BigHuntServiceServer) StartBigHuntQuest(ctx context.Context, req *pb.St
user.BigHuntStatuses[req.BigHuntBossQuestId] = st
})
return &pb.StartBigHuntQuestResponse{
DiffUserData: buildBigHuntDiff(user, append([]string{"IUserQuest"}, bigHuntDiffTables...)),
}, nil
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)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
user.BigHuntProgress.CurrentQuestSceneId = req.QuestSceneId
user.BigHuntProgress.LatestVersion = nowMillis
})
return &pb.UpdateBigHuntQuestSceneProgressResponse{
DiffUserData: buildBigHuntDiff(user, []string{"IUserBigHuntProgressStatus"}),
}, nil
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)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
bhQuest := s.catalog.QuestById[req.BigHuntQuestId]
@@ -114,7 +95,7 @@ func (s *BigHuntServiceServer) FinishBigHuntQuest(ctx context.Context, req *pb.F
var scoreInfo *pb.BigHuntScoreInfo
var scoreRewards []*pb.BigHuntReward
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleBigHuntQuestFinish(user, bhQuest.QuestId, req.IsRetired, false, nowMillis)
if req.IsRetired || user.BigHuntProgress.IsDryRun {
@@ -229,18 +210,13 @@ func (s *BigHuntServiceServer) FinishBigHuntQuest(ctx context.Context, req *pb.F
BattleReport: &pb.BigHuntBattleReport{
BattleReportWave: []*pb.BigHuntBattleReportWave{},
},
DiffUserData: buildBigHuntDiff(user, append([]string{
"IUserQuest",
"IUserConsumableItem",
"IUserMaterial",
}, bigHuntDiffTables...)),
}, 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)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
bhQuest := s.catalog.QuestById[req.BigHuntQuestId]
@@ -248,7 +224,7 @@ func (s *BigHuntServiceServer) RestartBigHuntQuest(ctx context.Context, req *pb.
var battleBinary []byte
var deckNumber int32
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleBigHuntQuestStart(user, bhQuest.QuestId, user.BigHuntDeckNumber, nowMillis)
user.BigHuntProgress.CurrentQuestSceneId = 0
@@ -267,17 +243,16 @@ func (s *BigHuntServiceServer) RestartBigHuntQuest(ctx context.Context, req *pb.
return &pb.RestartBigHuntQuestResponse{
BattleBinary: battleBinary,
DeckNumber: deckNumber,
DiffUserData: buildBigHuntDiff(user, append([]string{"IUserQuest"}, bigHuntDiffTables...)),
}, 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)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
st := user.BigHuntStatuses[req.BigHuntBossQuestId]
st.DailyChallengeCount += req.SkipCount
st.LatestChallengeDatetime = nowMillis
@@ -286,15 +261,14 @@ func (s *BigHuntServiceServer) SkipBigHuntQuest(ctx context.Context, req *pb.Ski
})
return &pb.SkipBigHuntQuestResponse{
ScoreReward: []*pb.BigHuntReward{},
DiffUserData: buildBigHuntDiff(user, bigHuntDiffTables),
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)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
var totalDamage int64
@@ -306,7 +280,7 @@ func (s *BigHuntServiceServer) SaveBigHuntBattleInfo(ctx context.Context, req *p
}
}
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
user.BigHuntBattleBinary = req.BattleBinary
if req.BigHuntBattleDetail != nil {
@@ -322,15 +296,13 @@ func (s *BigHuntServiceServer) SaveBigHuntBattleInfo(ctx context.Context, req *p
user.BigHuntProgress.LatestVersion = nowMillis
})
return &pb.SaveBigHuntBattleInfoResponse{
DiffUserData: buildBigHuntDiff(user, []string{"IUserBigHuntProgressStatus"}),
}, nil
return &pb.SaveBigHuntBattleInfoResponse{}, nil
}
func (s *BigHuntServiceServer) GetBigHuntTopData(ctx context.Context, _ *emptypb.Empty) (*pb.GetBigHuntTopDataResponse, error) {
log.Printf("[BigHuntService] GetBigHuntTopData")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, _ := s.users.LoadUser(userId)
nowMillis := gametime.NowMillis()
@@ -368,7 +340,6 @@ func (s *BigHuntServiceServer) GetBigHuntTopData(ctx context.Context, _ *emptypb
WeeklyScoreReward: weeklyRewards,
IsReceivedWeeklyScoreReward: ws.IsReceivedWeeklyReward,
LastWeekWeeklyScoreReward: lastWeekRewards,
DiffUserData: buildBigHuntDiff(user, bigHuntDiffTables),
}, nil
}
+12 -67
View File
@@ -8,7 +8,6 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/questflow"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -16,9 +15,9 @@ import (
func (s *QuestServiceServer) StartEventQuest(ctx context.Context, req *pb.StartEventQuestRequest) (*pb.StartEventQuestResponse, error) {
log.Printf("[QuestService] StartEventQuest: chapterId=%d questId=%d isBattleOnly=%v", req.EventQuestChapterId, req.QuestId, req.IsBattleOnly)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleEventQuestStart(user, req.EventQuestChapterId, req.QuestId, req.IsBattleOnly, req.UserDeckNumber, nowMillis)
})
@@ -34,12 +33,6 @@ func (s *QuestServiceServer) StartEventQuest(ctx context.Context, req *pb.StartE
return &pb.StartEventQuestResponse{
BattleDropReward: pbDrops,
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserStatus",
"IUserQuest",
"IUserQuestMission",
"IUserEventQuestProgressStatus",
}),
}, nil
}
@@ -47,34 +40,12 @@ func (s *QuestServiceServer) FinishEventQuest(ctx context.Context, req *pb.Finis
log.Printf("[QuestService] FinishEventQuest: chapterId=%d questId=%d isRetired=%v isAnnihilated=%v", req.EventQuestChapterId, req.QuestId, req.IsRetired, req.IsAnnihilated)
nowMillis := gametime.NowMillis()
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
var outcome questflow.FinishOutcome
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
outcome = s.engine.HandleEventQuestFinish(user, req.EventQuestChapterId, req.QuestId, req.IsRetired, req.IsAnnihilated, nowMillis)
})
diff := buildSelectedQuestDiff(user, []string{
"IUserQuest",
"IUserQuestMission",
"IUserEventQuestProgressStatus",
"IUserStatus",
"IUserGem",
"IUserCharacter",
"IUserCostume",
"IUserCostumeActiveSkill",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponNote",
"IUserCompanion",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserParts",
"IUserPartsGroupNote",
})
userdata.AddWeaponStoryDiff(diff, user, outcome.ChangedWeaponStoryIds)
return &pb.FinishEventQuestResponse{
DropReward: toProtoRewards(outcome.DropRewards),
FirstClearReward: toProtoRewards(outcome.FirstClearRewards),
@@ -84,55 +55,31 @@ func (s *QuestServiceServer) FinishEventQuest(ctx context.Context, req *pb.Finis
IsBigWin: outcome.IsBigWin,
BigWinClearedQuestMissionIdList: outcome.BigWinClearedQuestMissionIds,
UserStatusCampaignReward: []*pb.QuestReward{},
DiffUserData: diff,
}, nil
}
func (s *QuestServiceServer) RestartEventQuest(ctx context.Context, req *pb.RestartEventQuestRequest) (*pb.RestartEventQuestResponse, error) {
log.Printf("[QuestService] RestartEventQuest: chapterId=%d questId=%d", req.EventQuestChapterId, req.QuestId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleEventQuestRestart(user, req.EventQuestChapterId, req.QuestId, gametime.NowMillis())
})
return &pb.RestartEventQuestResponse{
BattleDropReward: []*pb.BattleDropReward{},
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserQuest",
"IUserQuestMission",
"IUserEventQuestProgressStatus",
}),
}, nil
}
func (s *QuestServiceServer) UpdateEventQuestSceneProgress(ctx context.Context, req *pb.UpdateEventQuestSceneProgressRequest) (*pb.UpdateEventQuestSceneProgressResponse, error) {
log.Printf("[QuestService] UpdateEventQuestSceneProgress: questSceneId=%d", req.QuestSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleEventQuestSceneProgress(user, req.QuestSceneId, gametime.NowMillis())
})
diff := buildSelectedQuestDiff(user, []string{
"IUserEventQuestProgressStatus",
"IUserCharacter",
"IUserCostume",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserCompanion",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserParts",
"IUserPartsGroupNote",
})
userdata.AddWeaponStoryDiff(diff, user, s.engine.Granter.DrainChangedStoryWeaponIds())
return &pb.UpdateEventQuestSceneProgressResponse{
DiffUserData: diff,
}, nil
return &pb.UpdateEventQuestSceneProgressResponse{}, nil
}
const defaultGuerrillaFreeOpenMinutes = int32(60)
@@ -140,16 +87,14 @@ const defaultGuerrillaFreeOpenMinutes = int32(60)
func (s *QuestServiceServer) StartGuerrillaFreeOpen(ctx context.Context, req *emptypb.Empty) (*pb.StartGuerrillaFreeOpenResponse, error) {
log.Printf("[QuestService] StartGuerrillaFreeOpen")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
user.GuerrillaFreeOpen.StartDatetime = nowMillis
user.GuerrillaFreeOpen.OpenMinutes = defaultGuerrillaFreeOpenMinutes
user.GuerrillaFreeOpen.DailyOpenedCount++
user.GuerrillaFreeOpen.LatestVersion = nowMillis
})
return &pb.StartGuerrillaFreeOpenResponse{
DiffUserData: buildSelectedQuestDiff(user, []string{"IUserEventQuestGuerrillaFreeOpen"}),
}, nil
return &pb.StartGuerrillaFreeOpenResponse{}, nil
}
+12 -63
View File
@@ -8,15 +8,14 @@ import (
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/questflow"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
func (s *QuestServiceServer) StartExtraQuest(ctx context.Context, req *pb.StartExtraQuestRequest) (*pb.StartExtraQuestResponse, error) {
log.Printf("[QuestService] StartExtraQuest: questId=%d deckNumber=%d", req.QuestId, req.UserDeckNumber)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleExtraQuestStart(user, req.QuestId, req.UserDeckNumber, nowMillis)
})
@@ -32,12 +31,6 @@ func (s *QuestServiceServer) StartExtraQuest(ctx context.Context, req *pb.StartE
return &pb.StartExtraQuestResponse{
BattleDropReward: pbDrops,
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserStatus",
"IUserQuest",
"IUserQuestMission",
"IUserExtraQuestProgressStatus",
}),
}, nil
}
@@ -45,34 +38,12 @@ func (s *QuestServiceServer) FinishExtraQuest(ctx context.Context, req *pb.Finis
log.Printf("[QuestService] FinishExtraQuest: questId=%d isRetired=%v isAnnihilated=%v", req.QuestId, req.IsRetired, req.IsAnnihilated)
nowMillis := gametime.NowMillis()
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
var outcome questflow.FinishOutcome
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
outcome = s.engine.HandleExtraQuestFinish(user, req.QuestId, req.IsRetired, req.IsAnnihilated, nowMillis)
})
diff := buildSelectedQuestDiff(user, []string{
"IUserQuest",
"IUserQuestMission",
"IUserExtraQuestProgressStatus",
"IUserStatus",
"IUserGem",
"IUserCharacter",
"IUserCostume",
"IUserCostumeActiveSkill",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponNote",
"IUserCompanion",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserParts",
"IUserPartsGroupNote",
})
userdata.AddWeaponStoryDiff(diff, user, outcome.ChangedWeaponStoryIds)
return &pb.FinishExtraQuestResponse{
DropReward: toProtoRewards(outcome.DropRewards),
FirstClearReward: toProtoRewards(outcome.FirstClearRewards),
@@ -81,16 +52,17 @@ func (s *QuestServiceServer) FinishExtraQuest(ctx context.Context, req *pb.Finis
IsBigWin: outcome.IsBigWin,
BigWinClearedQuestMissionIdList: outcome.BigWinClearedQuestMissionIds,
UserStatusCampaignReward: []*pb.QuestReward{},
DiffUserData: diff,
}, nil
}
func (s *QuestServiceServer) RestartExtraQuest(ctx context.Context, req *pb.RestartExtraQuestRequest) (*pb.RestartExtraQuestResponse, error) {
log.Printf("[QuestService] RestartExtraQuest: questId=%d", req.QuestId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
var deckNumber int32
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleExtraQuestRestart(user, req.QuestId, gametime.NowMillis())
deckNumber = user.Quests[req.QuestId].UserDeckNumber
})
drops := s.engine.BattleDropRewards(req.QuestId)
@@ -105,40 +77,17 @@ func (s *QuestServiceServer) RestartExtraQuest(ctx context.Context, req *pb.Rest
return &pb.RestartExtraQuestResponse{
BattleDropReward: pbDrops,
DeckNumber: user.Quests[req.QuestId].UserDeckNumber,
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserQuest",
"IUserQuestMission",
"IUserExtraQuestProgressStatus",
}),
DeckNumber: deckNumber,
}, nil
}
func (s *QuestServiceServer) UpdateExtraQuestSceneProgress(ctx context.Context, req *pb.UpdateExtraQuestSceneProgressRequest) (*pb.UpdateExtraQuestSceneProgressResponse, error) {
log.Printf("[QuestService] UpdateExtraQuestSceneProgress: questSceneId=%d", req.QuestSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleExtraQuestSceneProgress(user, req.QuestSceneId, gametime.NowMillis())
})
diff := buildSelectedQuestDiff(user, []string{
"IUserExtraQuestProgressStatus",
"IUserCharacter",
"IUserCostume",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserCompanion",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserParts",
"IUserPartsGroupNote",
})
userdata.AddWeaponStoryDiff(diff, user, s.engine.Granter.DrainChangedStoryWeaponIds())
return &pb.UpdateExtraQuestSceneProgressResponse{
DiffUserData: diff,
}, nil
return &pb.UpdateExtraQuestSceneProgressResponse{}, nil
}
+31 -152
View File
@@ -9,7 +9,6 @@ import (
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/questflow"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -28,91 +27,45 @@ func NewQuestServiceServer(users store.UserRepository, sessions store.SessionRep
return &QuestServiceServer{users: users, sessions: sessions, engine: engine}
}
func buildSelectedQuestDiff(user store.UserState, tableNames []string) map[string]*pb.DiffData {
tables := userdata.ProjectTables(user, tableNames)
return userdata.BuildDiffFromTablesOrdered(tables, tableNames)
}
func (s *QuestServiceServer) UpdateMainFlowSceneProgress(ctx context.Context, req *pb.UpdateMainFlowSceneProgressRequest) (*pb.UpdateMainFlowSceneProgressResponse, error) {
log.Printf("[QuestService] UpdateMainFlowSceneProgress: questSceneId=%d", req.QuestSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleMainFlowSceneProgress(user, req.QuestSceneId, gametime.NowMillis())
})
diff := buildSelectedQuestDiff(user, []string{
"IUserMainQuestFlowStatus",
"IUserMainQuestMainFlowStatus",
"IUserMainQuestProgressStatus",
"IUserMainQuestSeasonRoute",
"IUserPortalCageStatus",
"IUserSideStoryQuestSceneProgressStatus",
"IUserQuest",
"IUserCharacter",
"IUserCostume",
"IUserCostumeActiveSkill",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponNote",
"IUserCompanion",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserParts",
"IUserPartsGroupNote",
})
userdata.AddWeaponStoryDiff(diff, user, s.engine.Granter.DrainChangedStoryWeaponIds())
return &pb.UpdateMainFlowSceneProgressResponse{
DiffUserData: diff,
}, nil
return &pb.UpdateMainFlowSceneProgressResponse{}, nil
}
func (s *QuestServiceServer) UpdateReplayFlowSceneProgress(ctx context.Context, req *pb.UpdateReplayFlowSceneProgressRequest) (*pb.UpdateReplayFlowSceneProgressResponse, error) {
log.Printf("[QuestService] UpdateReplayFlowSceneProgress: questSceneId=%d", req.QuestSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleReplayFlowSceneProgress(user, req.QuestSceneId, gametime.NowMillis())
})
return &pb.UpdateReplayFlowSceneProgressResponse{
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserMainQuestFlowStatus",
"IUserMainQuestReplayFlowStatus",
}),
}, nil
return &pb.UpdateReplayFlowSceneProgressResponse{}, nil
}
func (s *QuestServiceServer) UpdateMainQuestSceneProgress(ctx context.Context, req *pb.UpdateMainQuestSceneProgressRequest) (*pb.UpdateMainQuestSceneProgressResponse, error) {
log.Printf("[QuestService] UpdateMainQuestSceneProgress: questSceneId=%d", req.QuestSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleMainQuestSceneProgress(user, req.QuestSceneId)
})
return &pb.UpdateMainQuestSceneProgressResponse{
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserStatus",
"IUserCharacter",
"IUserQuest",
"IUserQuestMission",
"IUserMainQuestFlowStatus",
"IUserMainQuestMainFlowStatus",
"IUserMainQuestProgressStatus",
}),
}, nil
return &pb.UpdateMainQuestSceneProgressResponse{}, nil
}
func (s *QuestServiceServer) StartMainQuest(ctx context.Context, req *pb.StartMainQuestRequest) (*pb.StartMainQuestResponse, error) {
log.Printf("[QuestService] StartMainQuest: %+v", req)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
if req.IsReplayFlow {
s.engine.HandleQuestStartReplay(user, req.QuestId, req.IsBattleOnly, req.UserDeckNumber, nowMillis)
} else {
@@ -132,16 +85,6 @@ func (s *QuestServiceServer) StartMainQuest(ctx context.Context, req *pb.StartMa
return &pb.StartMainQuestResponse{
BattleDropReward: pbDrops,
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserStatus",
"IUserQuest",
"IUserQuestMission",
"IUserMainQuestFlowStatus",
"IUserMainQuestMainFlowStatus",
"IUserMainQuestProgressStatus",
"IUserMainQuestSeasonRoute",
"IUserMainQuestReplayFlowStatus",
}),
}, nil
}
@@ -165,38 +108,12 @@ func (s *QuestServiceServer) FinishMainQuest(ctx context.Context, req *pb.Finish
req.QuestId, req.IsMainFlow, req.IsRetired, req.IsAnnihilated, req.StorySkipType)
nowMillis := gametime.NowMillis()
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
var outcome questflow.FinishOutcome
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
outcome = s.engine.HandleQuestFinish(user, req.QuestId, req.IsRetired, req.IsAnnihilated, nowMillis)
})
diff := buildSelectedQuestDiff(user, []string{
"IUserQuest",
"IUserQuestMission",
"IUserMainQuestFlowStatus",
"IUserMainQuestMainFlowStatus",
"IUserMainQuestProgressStatus",
"IUserMainQuestSeasonRoute",
"IUserMainQuestReplayFlowStatus",
"IUserStatus",
"IUserGem",
"IUserCharacter",
"IUserCostume",
"IUserCostumeActiveSkill",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponNote",
"IUserCompanion",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserParts",
"IUserPartsGroupNote",
})
userdata.AddWeaponStoryDiff(diff, user, outcome.ChangedWeaponStoryIds)
return &pb.FinishMainQuestResponse{
DropReward: toProtoRewards(outcome.DropRewards),
FirstClearReward: toProtoRewards(outcome.FirstClearRewards),
@@ -207,16 +124,17 @@ func (s *QuestServiceServer) FinishMainQuest(ctx context.Context, req *pb.Finish
BigWinClearedQuestMissionIdList: outcome.BigWinClearedQuestMissionIds,
ReplayFlowFirstClearReward: toProtoRewards(outcome.ReplayFlowFirstClearRewards),
UserStatusCampaignReward: []*pb.QuestReward{},
DiffUserData: diff,
}, nil
}
func (s *QuestServiceServer) RestartMainQuest(ctx context.Context, req *pb.RestartMainQuestRequest) (*pb.RestartMainQuestResponse, error) {
log.Printf("[QuestService] RestartMainQuest: questId=%d isMainFlow=%v", req.QuestId, req.IsMainFlow)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
var deckNumber int32
s.users.UpdateUser(userId, func(user *store.UserState) {
s.engine.HandleQuestRestart(user, req.QuestId, gametime.NowMillis())
deckNumber = user.Quests[req.QuestId].UserDeckNumber
})
drops := s.engine.BattleDropRewards(req.QuestId)
@@ -231,33 +149,22 @@ func (s *QuestServiceServer) RestartMainQuest(ctx context.Context, req *pb.Resta
return &pb.RestartMainQuestResponse{
BattleDropReward: pbDrops,
DeckNumber: user.Quests[req.QuestId].UserDeckNumber,
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserStatus",
"IUserQuest",
"IUserQuestMission",
"IUserMainQuestFlowStatus",
"IUserMainQuestMainFlowStatus",
"IUserMainQuestProgressStatus",
"IUserMainQuestSeasonRoute",
}),
DeckNumber: deckNumber,
}, nil
}
func (s *QuestServiceServer) FinishAutoOrbit(ctx context.Context, req *emptypb.Empty) (*pb.FinishAutoOrbitResponse, error) {
log.Printf("[QuestService] FinishAutoOrbit")
return &pb.FinishAutoOrbitResponse{
DiffUserData: userdata.EmptyDiff(),
}, nil
return &pb.FinishAutoOrbitResponse{}, nil
}
func (s *QuestServiceServer) SkipQuest(ctx context.Context, req *pb.SkipQuestRequest) (*pb.SkipQuestResponse, error) {
log.Printf("[QuestService] SkipQuest: questId=%d skipCount=%d useEffectItems=%d", req.QuestId, req.SkipCount, len(req.UseEffectItem))
nowMillis := gametime.NowMillis()
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
var outcome questflow.FinishOutcome
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
for _, item := range req.UseEffectItem {
log.Printf("[QuestService] SkipQuest UseEffectItem: consumableItemId=%d count=%d", item.ConsumableItemId, item.Count)
user.ConsumableItems[item.ConsumableItemId] -= item.Count
@@ -271,24 +178,14 @@ func (s *QuestServiceServer) SkipQuest(ctx context.Context, req *pb.SkipQuestReq
return &pb.SkipQuestResponse{
DropReward: toProtoRewards(outcome.DropRewards),
UserStatusCampaignReward: []*pb.QuestReward{},
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserQuest",
"IUserStatus",
"IUserConsumableItem",
"IUserMaterial",
"IUserParts",
"IUserPartsGroupNote",
"IUserCharacter",
"IUserCostume",
}),
}, nil
}
func (s *QuestServiceServer) SetRoute(ctx context.Context, req *pb.SetRouteRequest) (*pb.SetRouteResponse, error) {
log.Printf("[QuestService] SetRoute: mainQuestRouteId=%d", req.MainQuestRouteId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
user.MainQuest.CurrentMainQuestRouteId = req.MainQuestRouteId
if seasonId, ok := s.engine.SeasonIdByRouteId[req.MainQuestRouteId]; ok {
user.MainQuest.MainQuestSeasonId = seasonId
@@ -298,30 +195,22 @@ func (s *QuestServiceServer) SetRoute(ctx context.Context, req *pb.SetRouteReque
user.PortalCageStatus.LatestVersion = now
})
return &pb.SetRouteResponse{
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserMainQuestSeasonRoute",
"IUserMainQuestMainFlowStatus",
"IUserPortalCageStatus",
}),
}, nil
return &pb.SetRouteResponse{}, nil
}
func (s *QuestServiceServer) SetQuestSceneChoice(ctx context.Context, req *pb.SetQuestSceneChoiceRequest) (*pb.SetQuestSceneChoiceResponse, error) {
log.Printf("[QuestService] SetQuestSceneChoice: questSceneId=%d choiceNumber=%d",
req.QuestSceneId, req.ChoiceNumber)
return &pb.SetQuestSceneChoiceResponse{
DiffUserData: userdata.EmptyDiff(),
}, nil
return &pb.SetQuestSceneChoiceResponse{}, nil
}
func (s *QuestServiceServer) ResetLimitContentQuestProgress(ctx context.Context, req *pb.ResetLimitContentQuestProgressRequest) (*pb.ResetLimitContentQuestProgressResponse, error) {
log.Printf("[QuestService] ResetLimitContentQuestProgress: eventQuestChapterId=%d questId=%d",
req.EventQuestChapterId, req.QuestId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
if _, exists := user.SideStoryQuests[req.QuestId]; exists {
user.SideStoryQuests[req.QuestId] = store.SideStoryQuestProgress{
HeadSideStoryQuestSceneId: 0,
@@ -339,20 +228,14 @@ func (s *QuestServiceServer) ResetLimitContentQuestProgress(ctx context.Context,
}
})
return &pb.ResetLimitContentQuestProgressResponse{
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserSideStoryQuest",
"IUserSideStoryQuestSceneProgressStatus",
"IUserQuestLimitContentStatus",
}),
}, nil
return &pb.ResetLimitContentQuestProgressResponse{}, nil
}
func (s *QuestServiceServer) SetAutoSaleSetting(ctx context.Context, req *pb.SetAutoSaleSettingRequest) (*pb.SetAutoSaleSettingResponse, error) {
log.Printf("[QuestService] SetAutoSaleSetting: items=%d", len(req.AutoSaleSettingItem))
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
user.AutoSaleSettings = make(map[int32]store.AutoSaleSettingState, len(req.AutoSaleSettingItem))
for itemType, itemValue := range req.AutoSaleSettingItem {
user.AutoSaleSettings[itemType] = store.AutoSaleSettingState{
@@ -362,9 +245,5 @@ func (s *QuestServiceServer) SetAutoSaleSetting(ctx context.Context, req *pb.Set
}
})
return &pb.SetAutoSaleSettingResponse{
DiffUserData: buildSelectedQuestDiff(user, []string{
"IUserAutoSaleSettingDetail",
}),
}, nil
return &pb.SetAutoSaleSettingResponse{}, nil
}
+6 -22
View File
@@ -9,7 +9,6 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type SideStoryQuestServiceServer struct {
@@ -23,19 +22,14 @@ func NewSideStoryQuestServiceServer(users store.UserRepository, sessions store.S
return &SideStoryQuestServiceServer{users: users, sessions: sessions, catalog: catalog}
}
func buildSideStoryDiff(user store.UserState, tableNames []string) map[string]*pb.DiffData {
tables := userdata.ProjectTables(user, tableNames)
return userdata.BuildDiffFromTablesOrdered(tables, tableNames)
}
func (s *SideStoryQuestServiceServer) MoveSideStoryQuestProgress(ctx context.Context, req *pb.MoveSideStoryQuestRequest) (*pb.MoveSideStoryQuestResponse, error) {
log.Printf("[SideStoryQuestService] MoveSideStoryQuestProgress: sideStoryQuestId=%d", req.SideStoryQuestId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
firstSceneId := s.catalog.FirstSceneByQuestId[req.SideStoryQuestId]
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
existing, exists := user.SideStoryQuests[req.SideStoryQuestId]
var sceneId int32
@@ -58,21 +52,16 @@ func (s *SideStoryQuestServiceServer) MoveSideStoryQuestProgress(ctx context.Con
}
})
return &pb.MoveSideStoryQuestResponse{
DiffUserData: buildSideStoryDiff(user, []string{
"IUserSideStoryQuest",
"IUserSideStoryQuestSceneProgressStatus",
}),
}, nil
return &pb.MoveSideStoryQuestResponse{}, nil
}
func (s *SideStoryQuestServiceServer) UpdateSideStoryQuestSceneProgress(ctx context.Context, req *pb.UpdateSideStoryQuestSceneProgressRequest) (*pb.UpdateSideStoryQuestSceneProgressResponse, error) {
log.Printf("[SideStoryQuestService] UpdateSideStoryQuestSceneProgress: sideStoryQuestId=%d sceneId=%d",
req.SideStoryQuestId, req.SideStoryQuestSceneId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
user.SideStoryActiveProgress.CurrentSideStoryQuestSceneId = req.SideStoryQuestSceneId
user.SideStoryActiveProgress.LatestVersion = nowMillis
@@ -84,10 +73,5 @@ func (s *SideStoryQuestServiceServer) UpdateSideStoryQuestSceneProgress(ctx cont
user.SideStoryQuests[req.SideStoryQuestId] = progress
})
return &pb.UpdateSideStoryQuestSceneProgressResponse{
DiffUserData: buildSideStoryDiff(user, []string{
"IUserSideStoryQuest",
"IUserSideStoryQuestSceneProgressStatus",
}),
}, nil
return &pb.UpdateSideStoryQuestSceneProgressResponse{}, nil
}
+2 -11
View File
@@ -9,7 +9,6 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@@ -34,7 +33,7 @@ func NewRewardServiceServer(
func (s *RewardServiceServer) ReceiveBigHuntReward(ctx context.Context, _ *emptypb.Empty) (*pb.ReceiveBigHuntRewardResponse, error) {
log.Printf("[RewardService] ReceiveBigHuntReward")
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
weeklyVersion := gametime.WeeklyVersion(nowMillis)
@@ -42,7 +41,7 @@ func (s *RewardServiceServer) ReceiveBigHuntReward(ctx context.Context, _ *empty
var weeklyRewards []*pb.BigHuntReward
isReceived := false
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
ws := user.BigHuntWeeklyStatuses[weeklyVersion]
isReceived = ws.IsReceivedWeeklyReward
@@ -106,19 +105,11 @@ func (s *RewardServiceServer) ReceiveBigHuntReward(ctx context.Context, _ *empty
weeklyScoreResults = []*pb.WeeklyScoreResult{}
}
tables := userdata.ProjectTables(user, []string{
"IUserBigHuntWeeklyStatus",
"IUserBigHuntWeeklyMaxScore",
"IUserConsumableItem",
"IUserMaterial",
})
return &pb.ReceiveBigHuntRewardResponse{
WeeklyScoreResult: weeklyScoreResults,
WeeklyScoreReward: weeklyRewards,
IsReceivedWeeklyScoreReward: isReceived,
LastWeekWeeklyScoreReward: []*pb.BigHuntReward{},
DiffUserData: userdata.BuildDiffFromTables(tables),
}, nil
}
+10 -46
View File
@@ -10,30 +10,10 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
"google.golang.org/protobuf/types/known/emptypb"
)
var shopDiffTables = []string{
"IUserShopItem",
"IUserShopReplaceable",
"IUserShopReplaceableLineup",
"IUserGem",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
"IUserPremiumItem",
"IUserStatus",
"IUserCostume",
"IUserCostumeActiveSkill",
"IUserCharacter",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponNote",
}
type ShopServiceServer struct {
pb.UnimplementedShopServiceServer
users store.UserRepository
@@ -49,10 +29,10 @@ func NewShopServiceServer(users store.UserRepository, sessions store.SessionRepo
func (s *ShopServiceServer) Buy(ctx context.Context, req *pb.BuyRequest) (*pb.BuyResponse, error) {
log.Printf("[ShopService] Buy: shopId=%d items=%v", req.ShopId, req.ShopItems)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
for shopItemId, qty := range req.ShopItems {
item, ok := s.catalog.Items[shopItemId]
if !ok {
@@ -88,23 +68,18 @@ func (s *ShopServiceServer) Buy(ctx context.Context, req *pb.BuyRequest) (*pb.Bu
if err != nil {
return nil, fmt.Errorf("shop buy: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, shopDiffTables))
userdata.AddWeaponStoryDiff(diff, snapshot, s.granter.DrainChangedStoryWeaponIds())
return &pb.BuyResponse{
OverflowPossession: []*pb.Possession{},
DiffUserData: diff,
}, nil
}
func (s *ShopServiceServer) RefreshUserData(ctx context.Context, req *pb.RefreshRequest) (*pb.RefreshResponse, error) {
log.Printf("[ShopService] RefreshUserData: isGemUsed=%v", req.IsGemUsed)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
if len(user.ShopReplaceableLineup) == 0 && len(s.catalog.ItemShopPool) > 0 {
for i, itemId := range s.catalog.ItemShopPool {
slot := int32(i + 1)
@@ -131,18 +106,13 @@ func (s *ShopServiceServer) RefreshUserData(ctx context.Context, req *pb.Refresh
return nil, fmt.Errorf("shop refresh: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, shopDiffTables))
return &pb.RefreshResponse{
DiffUserData: diff,
}, nil
return &pb.RefreshResponse{}, nil
}
func (s *ShopServiceServer) GetCesaLimit(_ context.Context, _ *emptypb.Empty) (*pb.GetCesaLimitResponse, error) {
log.Printf("[ShopService] GetCesaLimit")
return &pb.GetCesaLimitResponse{
CesaLimit: []*pb.CesaLimit{},
DiffUserData: userdata.EmptyDiff(),
CesaLimit: []*pb.CesaLimit{},
}, nil
}
@@ -150,10 +120,10 @@ func (s *ShopServiceServer) CreatePurchaseTransaction(ctx context.Context, req *
log.Printf("[ShopService] CreatePurchaseTransaction: shopId=%d shopItemId=%d productId=%s",
req.ShopId, req.ShopItemId, req.ProductId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
item, ok := s.catalog.Items[req.ShopItemId]
if !ok {
log.Printf("[ShopService] CreatePurchaseTransaction: unknown shopItemId=%d", req.ShopItemId)
@@ -193,28 +163,22 @@ func (s *ShopServiceServer) CreatePurchaseTransaction(ctx context.Context, req *
txId := fmt.Sprintf("tx_%d_%d_%d", userId, req.ShopItemId, nowMillis)
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, shopDiffTables))
return &pb.CreatePurchaseTransactionResponse{
PurchaseTransactionId: txId,
DiffUserData: diff,
}, nil
}
func (s *ShopServiceServer) PurchaseGooglePlayStoreProduct(ctx context.Context, req *pb.PurchaseGooglePlayStoreProductRequest) (*pb.PurchaseGooglePlayStoreProductResponse, error) {
log.Printf("[ShopService] PurchaseGooglePlayStoreProduct: txId=%s", req.PurchaseTransactionId)
userId := currentUserId(ctx, s.users, s.sessions)
snapshot, err := s.users.LoadUser(userId)
userId := CurrentUserId(ctx, s.users, s.sessions)
_, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("purchase google play: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, shopDiffTables))
return &pb.PurchaseGooglePlayStoreProductResponse{
OverflowPossession: []*pb.Possession{},
DiffUserData: diff,
}, nil
}
+1 -37
View File
@@ -8,43 +8,7 @@ import (
"google.golang.org/grpc/metadata"
)
var startedGameStartTables = []string{
"IUserProfile",
"IUserCharacter",
"IUserCostume",
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserCompanion",
"IUserDeckCharacter",
"IUserDeck",
"IUserGem",
"IUserMission",
"IUserMainQuestFlowStatus",
"IUserMainQuestMainFlowStatus",
"IUserMainQuestProgressStatus",
"IUserMainQuestSeasonRoute",
"IUserQuest",
"IUserQuestMission",
"IUserTutorialProgress",
"IUserWeaponNote",
"IUserCostumeActiveSkill",
"IUserDeckTypeNote",
"IUserDeckSubWeaponGroup",
"IUserDeckPartsGroup",
"IUserConsumableItem",
"IUserMaterial",
"IUserImportantItem",
}
var gimmickDiffTables = []string{
"IUserGimmick",
"IUserGimmickOrnamentProgress",
"IUserGimmickSequence",
"IUserGimmickUnlock",
}
func currentUserId(ctx context.Context, users store.UserRepository, sessions store.SessionRepository) int64 {
func CurrentUserId(ctx context.Context, users store.UserRepository, sessions store.SessionRepository) int64 {
if md, ok := metadata.FromIncomingContext(ctx); ok {
if vals := md.Get("x-apb-session-key"); len(vals) > 0 {
if userId, err := sessions.ResolveUserId(vals[0]); err == nil {
+6 -30
View File
@@ -9,7 +9,6 @@ import (
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/questflow"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
type TutorialServiceServer struct {
@@ -25,10 +24,10 @@ func NewTutorialServiceServer(users store.UserRepository, sessions store.Session
func (s *TutorialServiceServer) SetTutorialProgress(ctx context.Context, req *pb.SetTutorialProgressRequest) (*pb.SetTutorialProgressResponse, error) {
log.Printf("[TutorialService] SetTutorialProgress: type=%d phase=%d choice=%d", req.TutorialType, req.ProgressPhase, req.ChoiceId)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
var grants []questflow.RewardGrant
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
existing, exists := user.Tutorials[req.TutorialType]
if !exists || req.ProgressPhase >= existing.ProgressPhase {
user.Tutorials[req.TutorialType] = store.TutorialProgressState{
@@ -42,22 +41,7 @@ func (s *TutorialServiceServer) SetTutorialProgress(ctx context.Context, req *pb
store.EnsureDefaultDeck(user, nowMillis)
}
})
tables := []string{"IUserTutorialProgress"}
if req.TutorialType == int32(model.TutorialTypeMenuFirst) ||
req.TutorialType == int32(model.TutorialTypeMenuSecond) {
tables = append(tables,
"IUserCharacter", "IUserCostume", "IUserWeapon",
"IUserWeaponSkill", "IUserWeaponAbility",
"IUserCompanion", "IUserDeckCharacter", "IUserDeck",
)
}
if len(grants) > 0 {
tables = append(tables, "IUserCompanion")
}
result := userdata.ProjectTables(user, tables)
for _, t := range tables {
log.Printf("[TutorialService] DiffTable %s -> %s", t, result[t])
}
rewards := make([]*pb.TutorialChoiceReward, len(grants))
for i, g := range grants {
rewards[i] = &pb.TutorialChoiceReward{
@@ -68,14 +52,13 @@ func (s *TutorialServiceServer) SetTutorialProgress(ctx context.Context, req *pb
}
return &pb.SetTutorialProgressResponse{
TutorialChoiceReward: rewards,
DiffUserData: userdata.BuildDiffFromTables(result),
}, nil
}
func (s *TutorialServiceServer) SetTutorialProgressAndReplaceDeck(ctx context.Context, req *pb.SetTutorialProgressAndReplaceDeckRequest) (*pb.SetTutorialProgressAndReplaceDeckResponse, error) {
log.Printf("[TutorialService] SetTutorialProgressAndReplaceDeck: type=%d phase=%d deckType=%d deckNumber=%d", req.TutorialType, req.ProgressPhase, req.DeckType, req.UserDeckNumber)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
existing, exists := user.Tutorials[req.TutorialType]
if !exists || req.ProgressPhase >= existing.ProgressPhase {
user.Tutorials[req.TutorialType] = store.TutorialProgressState{
@@ -87,12 +70,5 @@ func (s *TutorialServiceServer) SetTutorialProgressAndReplaceDeck(ctx context.Co
store.ApplyDeckReplacement(user, model.DeckType(req.DeckType), req.UserDeckNumber, deckSlotsFromProto(req.Deck), gametime.NowMillis())
}
})
return &pb.SetTutorialProgressAndReplaceDeckResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{
"IUserTutorialProgress",
"IUserDeck",
"IUserDeckCharacter",
"IUserDeckSubWeaponGroup",
})),
}, nil
return &pb.SetTutorialProgressAndReplaceDeckResponse{}, nil
}
+142 -90
View File
@@ -2,73 +2,56 @@ package service
import (
"context"
"encoding/json"
"fmt"
"log"
"sort"
"net/http"
"strconv"
"strings"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
pb "lunar-tear/server/gen/proto"
"lunar-tear/server/internal/gametime"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
)
type UserServiceServer struct {
pb.UnimplementedUserServiceServer
users store.UserRepository
sessions store.SessionRepository
authURL string
}
func NewUserServiceServer(users store.UserRepository, sessions store.SessionRepository) *UserServiceServer {
return &UserServiceServer{users: users, sessions: sessions}
}
func setCommonResponseTrailers(ctx context.Context, diff map[string]*pb.DiffData, includeUpdateNames bool) {
keys := make([]string, 0, len(diff))
for key := range diff {
keys = append(keys, key)
}
sort.Strings(keys)
var pairs []string
if includeUpdateNames && len(keys) > 0 {
pairs = append(pairs, "x-apb-update-user-data-names", keys[0])
for _, key := range keys[1:] {
pairs[len(pairs)-1] += "," + key
}
}
if err := grpc.SetTrailer(ctx, metadata.Pairs(pairs...)); err != nil {
log.Printf("[UserService] failed to set trailers: %v", err)
func NewUserServiceServer(users store.UserRepository, sessions store.SessionRepository, authURL string) *UserServiceServer {
if authURL != "" && !strings.Contains(authURL, "://") {
authURL = "http://" + authURL
}
return &UserServiceServer{users: users, sessions: sessions, authURL: authURL}
}
func (s *UserServiceServer) RegisterUser(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RegisterUserResponse, error) {
userId, err := s.users.CreateUser(req.Uuid)
platform := model.ClientPlatformFromContext(ctx)
userId, err := s.users.CreateUser(req.Uuid, platform)
if err != nil {
return nil, fmt.Errorf("create user: %w", err)
}
user, err := s.users.LoadUser(userId)
if err != nil {
return nil, fmt.Errorf("load user: %w", err)
}
log.Printf("[UserService] RegisterUser: uuid=%s terminalId=%s -> userId=%d", req.Uuid, req.TerminalId, user.UserId)
log.Printf("[UserService] RegisterUser: uuid=%s terminalId=%s platform=%s -> userId=%d", req.Uuid, req.TerminalId, platform, userId)
return &pb.RegisterUserResponse{
UserId: user.UserId,
Signature: fmt.Sprintf("sig_%d_%d", user.UserId, gametime.Now().Unix()),
DiffUserData: userdata.BuildDiffFromTables(userdata.FirstEntranceClientTableMap(user)),
UserId: userId,
Signature: fmt.Sprintf("sig_%d_%d", userId, gametime.Now().Unix()),
}, nil
}
func (s *UserServiceServer) Auth(ctx context.Context, req *pb.AuthUserRequest) (*pb.AuthUserResponse, error) {
log.Printf("[UserService] Auth: uuid=%s", req.Uuid)
platform := model.ClientPlatformFromContext(ctx)
log.Printf("[UserService] Auth: uuid=%s platform=%s", req.Uuid, platform)
session, err := s.sessions.CreateSession(req.Uuid, 24*time.Hour)
if err != nil {
@@ -84,7 +67,6 @@ func (s *UserServiceServer) Auth(ctx context.Context, req *pb.AuthUserRequest) (
ExpireDatetime: timestamppb.New(session.ExpireAt),
Signature: req.Signature,
UserId: user.UserId,
DiffUserData: userdata.BuildDiffFromTables(userdata.FirstEntranceClientTableMap(user)),
}, nil
}
@@ -97,81 +79,69 @@ func (s *UserServiceServer) GameStart(ctx context.Context, _ *emptypb.Empty) (*p
}
}
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
user.GameStartDatetime = gametime.NowMillis()
})
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(user, startedGameStartTables))
setCommonResponseTrailers(ctx, diff, true)
return &pb.GameStartResponse{
// Apply only the starter outgame rows we need after title completion.
// Keep IUser and other risky core-account rows out of GameStart diff.
DiffUserData: diff,
}, nil
return &pb.GameStartResponse{}, nil
}
func (s *UserServiceServer) TransferUser(ctx context.Context, req *pb.TransferUserRequest) (*pb.TransferUserResponse, error) {
log.Printf("[UserService] TransferUser")
userId, err := s.users.CreateUser(req.Uuid)
platform := model.ClientPlatformFromContext(ctx)
log.Printf("[UserService] TransferUser: platform=%s", platform)
userId, err := s.users.CreateUser(req.Uuid, platform)
if err != nil {
return nil, fmt.Errorf("create user: %w", err)
}
return &pb.TransferUserResponse{
UserId: userId,
Signature: "transferred-sig",
DiffUserData: userdata.EmptyDiff(),
UserId: userId,
Signature: "transferred-sig",
}, nil
}
func (s *UserServiceServer) SetUserName(ctx context.Context, req *pb.SetUserNameRequest) (*pb.SetUserNameResponse, error) {
log.Printf("[UserService] SetUserName: %s", req.Name)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
user.Profile.Name = req.Name
user.Profile.NameUpdateDatetime = nowMillis
})
return &pb.SetUserNameResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{"IUserProfile"})),
}, nil
return &pb.SetUserNameResponse{}, nil
}
func (s *UserServiceServer) SetUserMessage(ctx context.Context, req *pb.SetUserMessageRequest) (*pb.SetUserMessageResponse, error) {
log.Printf("[UserService] SetUserMessage: %s", req.Message)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
user.Profile.Message = req.Message
user.Profile.MessageUpdateDatetime = nowMillis
})
return &pb.SetUserMessageResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{"IUserProfile"})),
}, nil
return &pb.SetUserMessageResponse{}, nil
}
func (s *UserServiceServer) SetUserFavoriteCostumeId(ctx context.Context, req *pb.SetUserFavoriteCostumeIdRequest) (*pb.SetUserFavoriteCostumeIdResponse, error) {
log.Printf("[UserService] SetUserFavoriteCostumeId: %d", req.FavoriteCostumeId)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
nowMillis := gametime.NowMillis()
user.Profile.FavoriteCostumeId = req.FavoriteCostumeId
user.Profile.FavoriteCostumeIdUpdateDatetime = nowMillis
})
return &pb.SetUserFavoriteCostumeIdResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{"IUserProfile"})),
}, nil
return &pb.SetUserFavoriteCostumeIdResponse{}, nil
}
func (s *UserServiceServer) GetUserProfile(ctx context.Context, req *pb.GetUserProfileRequest) (*pb.GetUserProfileResponse, error) {
log.Printf("[UserService] GetUserProfile: playerId=%d", req.PlayerId)
userId := req.PlayerId
if userId == 0 {
userId = currentUserId(ctx, s.users, s.sessions)
userId = CurrentUserId(ctx, s.users, s.sessions)
}
user, err := s.users.LoadUser(userId)
if err != nil {
return &pb.GetUserProfileResponse{DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetUserProfileResponse{}, nil
}
deckCharacters := []*pb.ProfileDeckCharacter{}
@@ -210,66 +180,148 @@ func (s *UserServiceServer) GetUserProfile(ctx context.Context, req *pb.GetUserP
HistoryItem: []*pb.PlayHistoryItem{},
HistoryCategoryGraphItem: []*pb.PlayHistoryCategoryGraphItem{},
},
DiffUserData: userdata.EmptyDiff(),
}, nil
}
func (s *UserServiceServer) SetBirthYearMonth(ctx context.Context, req *pb.SetBirthYearMonthRequest) (*pb.SetBirthYearMonthResponse, error) {
log.Printf("[UserService] SetBirthYearMonth: %d/%d", req.BirthYear, req.BirthMonth)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
_, _ = s.users.UpdateUser(userId, func(user *store.UserState) {
user.BirthYear = req.BirthYear
user.BirthMonth = req.BirthMonth
})
return &pb.SetBirthYearMonthResponse{DiffUserData: userdata.EmptyDiff()}, nil
return &pb.SetBirthYearMonthResponse{}, nil
}
func (s *UserServiceServer) GetBirthYearMonth(ctx context.Context, _ *emptypb.Empty) (*pb.GetBirthYearMonthResponse, error) {
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return &pb.GetBirthYearMonthResponse{BirthYear: 2000, BirthMonth: 1, DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetBirthYearMonthResponse{BirthYear: 2000, BirthMonth: 1}, nil
}
return &pb.GetBirthYearMonthResponse{BirthYear: user.BirthYear, BirthMonth: user.BirthMonth, DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetBirthYearMonthResponse{BirthYear: user.BirthYear, BirthMonth: user.BirthMonth}, nil
}
func (s *UserServiceServer) GetChargeMoney(ctx context.Context, _ *emptypb.Empty) (*pb.GetChargeMoneyResponse, error) {
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return &pb.GetChargeMoneyResponse{ChargeMoneyThisMonth: 0, DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetChargeMoneyResponse{ChargeMoneyThisMonth: 0}, nil
}
return &pb.GetChargeMoneyResponse{ChargeMoneyThisMonth: user.ChargeMoneyThisMonth, DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetChargeMoneyResponse{ChargeMoneyThisMonth: user.ChargeMoneyThisMonth}, nil
}
func (s *UserServiceServer) SetUserSetting(ctx context.Context, req *pb.SetUserSettingRequest) (*pb.SetUserSettingResponse, error) {
log.Printf("[UserService] SetUserSetting: isNotifyPurchaseAlert=%v", req.IsNotifyPurchaseAlert)
userId := currentUserId(ctx, s.users, s.sessions)
user, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
userId := CurrentUserId(ctx, s.users, s.sessions)
s.users.UpdateUser(userId, func(user *store.UserState) {
user.Setting.IsNotifyPurchaseAlert = req.IsNotifyPurchaseAlert
})
return &pb.SetUserSettingResponse{
DiffUserData: userdata.BuildDiffFromTables(userdata.ProjectTables(user, []string{"IUserSetting"})),
}, nil
return &pb.SetUserSettingResponse{}, nil
}
func (s *UserServiceServer) GetAndroidArgs(ctx context.Context, req *pb.GetAndroidArgsRequest) (*pb.GetAndroidArgsResponse, error) {
return &pb.GetAndroidArgsResponse{Nonce: "Mama", ApiKey: "1234567890", DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetAndroidArgsResponse{Nonce: "Mama", ApiKey: "1234567890"}, nil
}
func (s *UserServiceServer) GetBackupToken(ctx context.Context, req *pb.GetBackupTokenRequest) (*pb.GetBackupTokenResponse, error) {
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
user, err := s.users.LoadUser(userId)
if err != nil {
return &pb.GetBackupTokenResponse{BackupToken: "mock-backup-token", DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetBackupTokenResponse{BackupToken: "mock-backup-token"}, nil
}
return &pb.GetBackupTokenResponse{BackupToken: user.BackupToken, DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetBackupTokenResponse{BackupToken: user.BackupToken}, nil
}
func (s *UserServiceServer) CheckTransferSetting(ctx context.Context, _ *emptypb.Empty) (*pb.CheckTransferSettingResponse, error) {
return &pb.CheckTransferSettingResponse{DiffUserData: userdata.EmptyDiff()}, nil
return &pb.CheckTransferSettingResponse{}, nil
}
func (s *UserServiceServer) GetUserGamePlayNote(ctx context.Context, req *pb.GetUserGamePlayNoteRequest) (*pb.GetUserGamePlayNoteResponse, error) {
return &pb.GetUserGamePlayNoteResponse{DiffUserData: userdata.EmptyDiff()}, nil
return &pb.GetUserGamePlayNoteResponse{}, nil
}
func (s *UserServiceServer) resolveAuthToken(token string) (facebookId int64, err error) {
if s.authURL == "" {
return 0, status.Error(codes.FailedPrecondition, "auth server not configured (--auth-url)")
}
resp, err := http.Get(s.authURL + "/me?access_token=" + token)
if err != nil {
return 0, status.Errorf(codes.Internal, "auth server unreachable: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return 0, status.Error(codes.Unauthenticated, "invalid or expired token")
}
var body struct {
ID string `json:"id"`
Name string `json:"name"`
}
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
return 0, status.Errorf(codes.Internal, "decode auth response: %v", err)
}
if body.ID == "" {
return 0, status.Error(codes.Unauthenticated, "auth server returned empty id")
}
id, err := strconv.ParseInt(body.ID, 10, 64)
if err != nil {
return 0, status.Errorf(codes.Internal, "invalid auth id %q: %v", body.ID, err)
}
return id, nil
}
func (s *UserServiceServer) SetFacebookAccount(ctx context.Context, req *pb.SetFacebookAccountRequest) (*pb.SetFacebookAccountResponse, error) {
log.Printf("[UserService] SetFacebookAccount")
fbId, err := s.resolveAuthToken(req.Token)
if err != nil {
return nil, err
}
userId := CurrentUserId(ctx, s.users, s.sessions)
if err := s.users.SetFacebookId(userId, fbId); err != nil {
return nil, fmt.Errorf("set facebook id: %w", err)
}
log.Printf("[UserService] linked facebook_id=%d to user_id=%d", fbId, userId)
return &pb.SetFacebookAccountResponse{}, nil
}
func (s *UserServiceServer) UnsetFacebookAccount(ctx context.Context, _ *emptypb.Empty) (*pb.UnsetFacebookAccountResponse, error) {
log.Printf("[UserService] UnsetFacebookAccount")
userId := CurrentUserId(ctx, s.users, s.sessions)
if err := s.users.ClearFacebookId(userId); err != nil {
return nil, fmt.Errorf("clear facebook id: %w", err)
}
log.Printf("[UserService] unlinked facebook from user_id=%d", userId)
return &pb.UnsetFacebookAccountResponse{}, nil
}
func (s *UserServiceServer) TransferUserByFacebook(ctx context.Context, req *pb.TransferUserByFacebookRequest) (*pb.TransferUserByFacebookResponse, error) {
log.Printf("[UserService] TransferUserByFacebook: uuid=%s", req.Uuid)
fbId, err := s.resolveAuthToken(req.Token)
if err != nil {
return nil, err
}
userId, err := s.users.GetUserByFacebookId(fbId)
if err != nil {
return nil, status.Error(codes.NotFound, "no account linked to this login")
}
if err := s.users.UpdateUUID(userId, req.Uuid); err != nil {
return nil, fmt.Errorf("update uuid: %w", err)
}
log.Printf("[UserService] transferred facebook_id=%d -> user_id=%d with new uuid=%s", fbId, userId, req.Uuid)
return &pb.TransferUserByFacebookResponse{
UserId: userId,
Signature: fmt.Sprintf("fb_transfer_%d_%d", userId, gametime.Now().Unix()),
}, nil
}
+44 -133
View File
@@ -11,35 +11,8 @@ import (
"lunar-tear/server/internal/masterdata"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/store"
"lunar-tear/server/internal/userdata"
)
var weaponDiffTables = []string{
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponAwaken",
"IUserMaterial",
"IUserConsumableItem",
}
var limitBreakDiffTables = []string{
"IUserWeapon",
"IUserWeaponSkill",
"IUserWeaponAbility",
"IUserWeaponAwaken",
"IUserMaterial",
"IUserConsumableItem",
"IUserWeaponNote",
}
var weaponAwakenDiffTables = []string{
"IUserWeapon",
"IUserWeaponAwaken",
"IUserMaterial",
"IUserConsumableItem",
}
type WeaponServiceServer struct {
pb.UnimplementedWeaponServiceServer
users store.UserRepository
@@ -55,10 +28,10 @@ func NewWeaponServiceServer(users store.UserRepository, sessions store.SessionRe
func (s *WeaponServiceServer) Protect(ctx context.Context, req *pb.ProtectRequest) (*pb.ProtectResponse, error) {
log.Printf("[WeaponService] Protect: uuids=%v", req.UserWeaponUuid)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
for _, uuid := range req.UserWeaponUuid {
weapon, ok := user.Weapons[uuid]
if !ok {
@@ -71,17 +44,16 @@ func (s *WeaponServiceServer) Protect(ctx context.Context, req *pb.ProtectReques
}
})
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserWeapon"}))
return &pb.ProtectResponse{DiffUserData: diff}, nil
return &pb.ProtectResponse{}, nil
}
func (s *WeaponServiceServer) Unprotect(ctx context.Context, req *pb.UnprotectRequest) (*pb.UnprotectResponse, error) {
log.Printf("[WeaponService] Unprotect: uuids=%v", req.UserWeaponUuid)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, _ := s.users.UpdateUser(userId, func(user *store.UserState) {
s.users.UpdateUser(userId, func(user *store.UserState) {
for _, uuid := range req.UserWeaponUuid {
weapon, ok := user.Weapons[uuid]
if !ok {
@@ -94,18 +66,16 @@ func (s *WeaponServiceServer) Unprotect(ctx context.Context, req *pb.UnprotectRe
}
})
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, []string{"IUserWeapon"}))
return &pb.UnprotectResponse{DiffUserData: diff}, nil
return &pb.UnprotectResponse{}, nil
}
func (s *WeaponServiceServer) EnhanceByMaterial(ctx context.Context, req *pb.EnhanceByMaterialRequest) (*pb.EnhanceByMaterialResponse, error) {
log.Printf("[WeaponService] EnhanceByMaterial: uuid=%s materials=%v", req.UserWeaponUuid, req.Materials)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
var changedStoryIds []int32
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] EnhanceByMaterial: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -157,35 +127,24 @@ func (s *WeaponServiceServer) EnhanceByMaterial(ctx context.Context, req *pb.Enh
user.Weapons[req.UserWeaponUuid] = weapon
log.Printf("[WeaponService] EnhanceByMaterial: weaponId=%d +%d exp -> total=%d level=%d", weapon.WeaponId, totalExp, weapon.Exp, weapon.Level)
changedStoryIds = s.checkWeaponStoryUnlocks(user, weapon.WeaponId, weapon.Level, nowMillis)
s.checkWeaponStoryUnlocks(user, weapon.WeaponId, weapon.Level, nowMillis)
})
if err != nil {
return nil, fmt.Errorf("weapon enhance by material: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, weaponDiffTables))
userdata.AddWeaponStoryDiff(diff, snapshot, changedStoryIds)
return &pb.EnhanceByMaterialResponse{
IsGreatSuccess: false,
SurplusEnhanceMaterial: map[int32]int32{},
DiffUserData: diff,
}, nil
}
func (s *WeaponServiceServer) Sell(ctx context.Context, req *pb.SellRequest) (*pb.SellResponse, error) {
log.Printf("[WeaponService] Sell: uuids=%v", req.UserWeaponUuid)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserWeapon", oldUser, userdata.SortedWeaponRecords, []string{"userId", "userWeaponUuid"}).
Track("IUserWeaponSkill", oldUser, userdata.SortedWeaponSkillRecords, []string{"userId", "userWeaponUuid", "slotNumber"}).
Track("IUserWeaponAbility", oldUser, userdata.SortedWeaponAbilityRecords, []string{"userId", "userWeaponUuid", "slotNumber"}).
Track("IUserWeaponAwaken", oldUser, userdata.SortedWeaponAwakenRecords, []string{"userId", "userWeaponUuid"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
totalGold := int32(0)
for _, uuid := range req.UserWeaponUuid {
weapon, ok := user.Weapons[uuid]
@@ -225,21 +184,16 @@ func (s *WeaponServiceServer) Sell(ctx context.Context, req *pb.SellRequest) (*p
return nil, fmt.Errorf("weapon sell: %w", err)
}
sellDiffTables := []string{"IUserWeapon", "IUserWeaponSkill", "IUserWeaponAbility", "IUserWeaponAwaken", "IUserConsumableItem"}
tables := userdata.ProjectTables(snapshot, sellDiffTables)
diff := tracker.Apply(snapshot, tables)
return &pb.SellResponse{DiffUserData: diff}, nil
return &pb.SellResponse{}, nil
}
func (s *WeaponServiceServer) Evolve(ctx context.Context, req *pb.EvolveRequest) (*pb.EvolveResponse, error) {
log.Printf("[WeaponService] Evolve: uuid=%s", req.UserWeaponUuid)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
var changedStoryIds []int32
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] Evolve: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -298,25 +252,22 @@ func (s *WeaponServiceServer) Evolve(ctx context.Context, req *pb.EvolveRequest)
log.Printf("[WeaponService] Evolve: weaponId %d -> %d", wm.WeaponId, evolvedId)
changedStoryIds = s.checkWeaponStoryUnlocks(user, evolvedId, weapon.Level, nowMillis)
s.checkWeaponStoryUnlocks(user, evolvedId, weapon.Level, nowMillis)
})
if err != nil {
return nil, fmt.Errorf("weapon evolve: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, weaponDiffTables))
userdata.AddWeaponStoryDiff(diff, snapshot, changedStoryIds)
return &pb.EvolveResponse{DiffUserData: diff}, nil
return &pb.EvolveResponse{}, nil
}
func (s *WeaponServiceServer) EnhanceSkill(ctx context.Context, req *pb.EnhanceSkillRequest) (*pb.EnhanceSkillResponse, error) {
log.Printf("[WeaponService] EnhanceSkill: uuid=%s skillId=%d addLevel=%d", req.UserWeaponUuid, req.SkillId, req.AddLevelCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] EnhanceSkill: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -330,7 +281,7 @@ func (s *WeaponServiceServer) EnhanceSkill(ctx context.Context, req *pb.EnhanceS
}
groupRows := s.catalog.SkillGroupsByGroupId[wm.WeaponSkillGroupId]
var skillGroup *masterdata.WeaponSkillGroupRow
var skillGroup *masterdata.EntityMWeaponSkillGroup
for i := range groupRows {
if groupRows[i].SkillId == req.SkillId {
skillGroup = &groupRows[i]
@@ -403,18 +354,16 @@ func (s *WeaponServiceServer) EnhanceSkill(ctx context.Context, req *pb.EnhanceS
return nil, fmt.Errorf("weapon enhance skill: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, weaponDiffTables))
return &pb.EnhanceSkillResponse{DiffUserData: diff}, nil
return &pb.EnhanceSkillResponse{}, nil
}
func (s *WeaponServiceServer) EnhanceAbility(ctx context.Context, req *pb.EnhanceAbilityRequest) (*pb.EnhanceAbilityResponse, error) {
log.Printf("[WeaponService] EnhanceAbility: uuid=%s abilityId=%d addLevel=%d", req.UserWeaponUuid, req.AbilityId, req.AddLevelCount)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] EnhanceAbility: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -428,7 +377,7 @@ func (s *WeaponServiceServer) EnhanceAbility(ctx context.Context, req *pb.Enhanc
}
groupRows := s.catalog.AbilityGroupsByGroupId[wm.WeaponAbilityGroupId]
var abilityGroup *masterdata.WeaponAbilityGroupRow
var abilityGroup *masterdata.EntityMWeaponAbilityGroup
for i := range groupRows {
if groupRows[i].AbilityId == req.AbilityId {
abilityGroup = &groupRows[i]
@@ -501,18 +450,16 @@ func (s *WeaponServiceServer) EnhanceAbility(ctx context.Context, req *pb.Enhanc
return nil, fmt.Errorf("weapon enhance ability: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, weaponDiffTables))
return &pb.EnhanceAbilityResponse{DiffUserData: diff}, nil
return &pb.EnhanceAbilityResponse{}, nil
}
func (s *WeaponServiceServer) LimitBreakByMaterial(ctx context.Context, req *pb.LimitBreakByMaterialRequest) (*pb.LimitBreakByMaterialResponse, error) {
log.Printf("[WeaponService] LimitBreakByMaterial: uuid=%s materials=%v", req.UserWeaponUuid, req.Materials)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] LimitBreakByMaterial: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -572,25 +519,16 @@ func (s *WeaponServiceServer) LimitBreakByMaterial(ctx context.Context, req *pb.
return nil, fmt.Errorf("weapon limit break by material: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, limitBreakDiffTables))
return &pb.LimitBreakByMaterialResponse{DiffUserData: diff}, nil
return &pb.LimitBreakByMaterialResponse{}, nil
}
func (s *WeaponServiceServer) LimitBreakByWeapon(ctx context.Context, req *pb.LimitBreakByWeaponRequest) (*pb.LimitBreakByWeaponResponse, error) {
log.Printf("[WeaponService] LimitBreakByWeapon: uuid=%s materialUuids=%v", req.UserWeaponUuid, req.MaterialUserWeaponUuids)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserWeapon", oldUser, userdata.SortedWeaponRecords, []string{"userId", "userWeaponUuid"}).
Track("IUserWeaponSkill", oldUser, userdata.SortedWeaponSkillRecords, []string{"userId", "userWeaponUuid", "slotNumber"}).
Track("IUserWeaponAbility", oldUser, userdata.SortedWeaponAbilityRecords, []string{"userId", "userWeaponUuid", "slotNumber"}).
Track("IUserWeaponAwaken", oldUser, userdata.SortedWeaponAwakenRecords, []string{"userId", "userWeaponUuid"})
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] LimitBreakByWeapon: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -658,27 +596,16 @@ func (s *WeaponServiceServer) LimitBreakByWeapon(ctx context.Context, req *pb.Li
return nil, fmt.Errorf("weapon limit break by weapon: %w", err)
}
tables := userdata.ProjectTables(snapshot, limitBreakDiffTables)
diff := tracker.Apply(snapshot, tables)
return &pb.LimitBreakByWeaponResponse{DiffUserData: diff}, nil
return &pb.LimitBreakByWeaponResponse{}, nil
}
func (s *WeaponServiceServer) EnhanceByWeapon(ctx context.Context, req *pb.EnhanceByWeaponRequest) (*pb.EnhanceByWeaponResponse, error) {
log.Printf("[WeaponService] EnhanceByWeapon: uuid=%s materialUuids=%v", req.UserWeaponUuid, req.MaterialUserWeaponUuids)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
oldUser, _ := s.users.LoadUser(userId)
tracker := userdata.NewDeleteTracker().
Track("IUserWeapon", oldUser, userdata.SortedWeaponRecords, []string{"userId", "userWeaponUuid"}).
Track("IUserWeaponSkill", oldUser, userdata.SortedWeaponSkillRecords, []string{"userId", "userWeaponUuid", "slotNumber"}).
Track("IUserWeaponAbility", oldUser, userdata.SortedWeaponAbilityRecords, []string{"userId", "userWeaponUuid", "slotNumber"}).
Track("IUserWeaponAwaken", oldUser, userdata.SortedWeaponAwakenRecords, []string{"userId", "userWeaponUuid"})
var changedStoryIds []int32
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] EnhanceByWeapon: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -740,77 +667,63 @@ func (s *WeaponServiceServer) EnhanceByWeapon(ctx context.Context, req *pb.Enhan
user.Weapons[req.UserWeaponUuid] = weapon
log.Printf("[WeaponService] EnhanceByWeapon: weaponId=%d +%d exp -> total=%d level=%d", weapon.WeaponId, totalExp, weapon.Exp, weapon.Level)
changedStoryIds = s.checkWeaponStoryUnlocks(user, weapon.WeaponId, weapon.Level, nowMillis)
s.checkWeaponStoryUnlocks(user, weapon.WeaponId, weapon.Level, nowMillis)
})
if err != nil {
return nil, fmt.Errorf("weapon enhance by weapon: %w", err)
}
tables := userdata.ProjectTables(snapshot, weaponDiffTables)
diff := tracker.Apply(snapshot, tables)
userdata.AddWeaponStoryDiff(diff, snapshot, changedStoryIds)
return &pb.EnhanceByWeaponResponse{
IsGreatSuccess: false,
SurplusEnhanceWeapon: []string{},
DiffUserData: diff,
}, nil
}
func (s *WeaponServiceServer) checkWeaponStoryUnlocks(user *store.UserState, weaponId, level int32, nowMillis int64) []int32 {
func (s *WeaponServiceServer) checkWeaponStoryUnlocks(user *store.UserState, weaponId, level int32, nowMillis int64) {
wm, ok := s.catalog.Weapons[weaponId]
if !ok || wm.WeaponStoryReleaseConditionGroupId == 0 {
return nil
return
}
evoOrder, hasEvo := s.catalog.EvolutionOrder[weaponId]
conditions := s.catalog.ReleaseConditionsByGroupId[wm.WeaponStoryReleaseConditionGroupId]
changed := false
for _, cond := range conditions {
granted := false
switch cond.WeaponStoryReleaseConditionType {
switch model.WeaponStoryReleaseConditionType(cond.WeaponStoryReleaseConditionType) {
case model.WeaponStoryReleaseConditionTypeAcquisition:
granted = store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
case model.WeaponStoryReleaseConditionTypeReachSpecifiedLevel:
if level >= cond.ConditionValue {
granted = store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
}
case model.WeaponStoryReleaseConditionTypeReachInitialMaxLevel:
if maxFunc, ok := s.catalog.MaxLevelByEnhanceId[wm.WeaponSpecificEnhanceId]; ok {
if level >= maxFunc.Evaluate(0) {
granted = store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
}
}
case model.WeaponStoryReleaseConditionTypeReachOnceEvolvedMaxLevel:
if hasEvo && evoOrder >= 1 {
if maxFunc, ok := s.catalog.MaxLevelByEnhanceId[wm.WeaponSpecificEnhanceId]; ok {
if level >= maxFunc.Evaluate(0) {
granted = store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
}
}
}
case model.WeaponStoryReleaseConditionTypeReachSpecifiedEvolutionCount:
if hasEvo && evoOrder >= cond.ConditionValue {
granted = store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
store.GrantWeaponStoryUnlock(user, weaponId, cond.StoryIndex, nowMillis)
}
}
if granted {
changed = true
}
}
if changed {
return []int32{weaponId}
}
return nil
}
func (s *WeaponServiceServer) Awaken(ctx context.Context, req *pb.WeaponAwakenRequest) (*pb.WeaponAwakenResponse, error) {
log.Printf("[WeaponService] Awaken: uuid=%s", req.UserWeaponUuid)
userId := currentUserId(ctx, s.users, s.sessions)
userId := CurrentUserId(ctx, s.users, s.sessions)
nowMillis := gametime.NowMillis()
snapshot, err := s.users.UpdateUser(userId, func(user *store.UserState) {
_, err := s.users.UpdateUser(userId, func(user *store.UserState) {
weapon, ok := user.Weapons[req.UserWeaponUuid]
if !ok {
log.Printf("[WeaponService] Awaken: weapon uuid=%s not found", req.UserWeaponUuid)
@@ -857,7 +770,5 @@ func (s *WeaponServiceServer) Awaken(ctx context.Context, req *pb.WeaponAwakenRe
return nil, fmt.Errorf("weapon awaken: %w", err)
}
diff := userdata.BuildDiffFromTables(userdata.ProjectTables(snapshot, weaponAwakenDiffTables))
return &pb.WeaponAwakenResponse{DiffUserData: diff}, nil
return &pb.WeaponAwakenResponse{}, nil
}