mirror of
https://github.com/Walter-Sparrow/lunar-tear.git
synced 2026-07-02 05:43:41 +03:00
Fix stale story-unlock and post-evolve weapon state
This commit is contained in:
@@ -42,6 +42,8 @@ type WeaponCatalog struct {
|
||||
BaseExpByEnhanceId map[int32]int32
|
||||
ReleaseConditionsByGroupId map[int32][]EntityMWeaponStoryReleaseConditionGroup
|
||||
|
||||
LevelingEnhanceIdByWeaponId map[int32]int32
|
||||
|
||||
AwakenByWeaponId map[int32]EntityMWeaponAwaken
|
||||
AwakenMaterialsByGroupId map[int32][]EntityMWeaponAwakenMaterialGroup
|
||||
}
|
||||
@@ -142,6 +144,8 @@ func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
|
||||
BaseExpByEnhanceId: make(map[int32]int32, len(enhanceRows)),
|
||||
ReleaseConditionsByGroupId: make(map[int32][]EntityMWeaponStoryReleaseConditionGroup),
|
||||
|
||||
LevelingEnhanceIdByWeaponId: make(map[int32]int32, len(weapons)),
|
||||
|
||||
AwakenByWeaponId: make(map[int32]EntityMWeaponAwaken, len(awakenRows)),
|
||||
AwakenMaterialsByGroupId: make(map[int32][]EntityMWeaponAwakenMaterialGroup),
|
||||
}
|
||||
@@ -342,5 +346,28 @@ func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
|
||||
}
|
||||
log.Printf("[WeaponCatalog] rarity fallback: assigned synthetic enhance IDs to %d weapons", fallbackCount)
|
||||
|
||||
// Build LevelingEnhanceIdByWeaponId: every member of an evolution chain
|
||||
// inherits the chain root's (post-rarity-fallback) WeaponSpecificEnhanceId
|
||||
// so cumulative exp stays consistent across Evolve. Weapons not in any
|
||||
// chain map to their own enhance id.
|
||||
for _, rows := range grouped {
|
||||
if len(rows) == 0 {
|
||||
continue
|
||||
}
|
||||
rootMaster, ok := catalog.Weapons[rows[0].WeaponId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
rootEnhanceId := rootMaster.WeaponSpecificEnhanceId
|
||||
for _, row := range rows {
|
||||
catalog.LevelingEnhanceIdByWeaponId[row.WeaponId] = rootEnhanceId
|
||||
}
|
||||
}
|
||||
for wid, w := range catalog.Weapons {
|
||||
if _, exists := catalog.LevelingEnhanceIdByWeaponId[wid]; !exists {
|
||||
catalog.LevelingEnhanceIdByWeaponId[wid] = w.WeaponSpecificEnhanceId
|
||||
}
|
||||
}
|
||||
|
||||
return catalog, nil
|
||||
}
|
||||
|
||||
@@ -122,8 +122,26 @@ func (s *WeaponServiceServer) EnhanceByMaterial(ctx context.Context, req *pb.Enh
|
||||
}
|
||||
|
||||
weapon.Exp += totalExp
|
||||
if thresholds, ok := catalog.ExpByEnhanceId[wm.WeaponSpecificEnhanceId]; ok {
|
||||
levelingEnhanceId := catalog.LevelingEnhanceIdByWeaponId[weapon.WeaponId]
|
||||
if thresholds, ok := catalog.ExpByEnhanceId[levelingEnhanceId]; ok {
|
||||
weapon.Level, weapon.Exp = gameutil.LevelAndCap(weapon.Exp, thresholds)
|
||||
if maxFunc, ok := catalog.MaxLevelByEnhanceId[wm.WeaponSpecificEnhanceId]; ok {
|
||||
cap := maxFunc.Evaluate(weapon.LimitBreakCount)
|
||||
if weapon.Level > cap {
|
||||
weapon.Level = cap
|
||||
if int(cap) >= 0 && int(cap) < len(thresholds) {
|
||||
weapon.Exp = thresholds[cap]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
note := user.WeaponNotes[weapon.WeaponId]
|
||||
if note.MaxLevel < weapon.Level {
|
||||
note.WeaponId = weapon.WeaponId
|
||||
note.MaxLevel = weapon.Level
|
||||
note.LatestVersion = nowMillis
|
||||
user.WeaponNotes[weapon.WeaponId] = note
|
||||
}
|
||||
|
||||
weapon.LatestVersion = nowMillis
|
||||
@@ -240,10 +258,52 @@ func (s *WeaponServiceServer) Evolve(ctx context.Context, req *pb.EvolveRequest)
|
||||
log.Printf("[WeaponService] Evolve: gold cost=%d", goldCost)
|
||||
}
|
||||
|
||||
oldWeaponId := wm.WeaponId
|
||||
weapon.WeaponId = evolvedId
|
||||
weapon.LatestVersion = nowMillis
|
||||
user.Weapons[req.UserWeaponUuid] = weapon
|
||||
|
||||
note, hasNote := user.WeaponNotes[evolvedId]
|
||||
if !hasNote {
|
||||
note = store.WeaponNoteState{
|
||||
WeaponId: evolvedId,
|
||||
MaxLevel: weapon.Level,
|
||||
MaxLimitBreakCount: weapon.LimitBreakCount,
|
||||
FirstAcquisitionDatetime: nowMillis,
|
||||
LatestVersion: nowMillis,
|
||||
}
|
||||
user.WeaponNotes[evolvedId] = note
|
||||
} else {
|
||||
changed := false
|
||||
if note.MaxLevel < weapon.Level {
|
||||
note.MaxLevel = weapon.Level
|
||||
changed = true
|
||||
}
|
||||
if note.MaxLimitBreakCount < weapon.LimitBreakCount {
|
||||
note.MaxLimitBreakCount = weapon.LimitBreakCount
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
note.WeaponId = evolvedId
|
||||
note.LatestVersion = nowMillis
|
||||
user.WeaponNotes[evolvedId] = note
|
||||
}
|
||||
}
|
||||
|
||||
if oldStory, hasOldStory := user.WeaponStories[oldWeaponId]; hasOldStory {
|
||||
newStory, hasNewStory := user.WeaponStories[evolvedId]
|
||||
if !hasNewStory || newStory.ReleasedMaxStoryIndex < oldStory.ReleasedMaxStoryIndex {
|
||||
if user.WeaponStories == nil {
|
||||
user.WeaponStories = make(map[int32]store.WeaponStoryState)
|
||||
}
|
||||
user.WeaponStories[evolvedId] = store.WeaponStoryState{
|
||||
WeaponId: evolvedId,
|
||||
ReleasedMaxStoryIndex: oldStory.ReleasedMaxStoryIndex,
|
||||
LatestVersion: nowMillis,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
evolvedMaster, ok := catalog.Weapons[evolvedId]
|
||||
if ok {
|
||||
if slots, ok := catalog.AbilitySlots[evolvedMaster.WeaponAbilityGroupId]; ok {
|
||||
@@ -259,7 +319,7 @@ func (s *WeaponServiceServer) Evolve(ctx context.Context, req *pb.EvolveRequest)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[WeaponService] Evolve: weaponId %d -> %d", wm.WeaponId, evolvedId)
|
||||
log.Printf("[WeaponService] Evolve: weaponId %d -> %d", oldWeaponId, evolvedId)
|
||||
|
||||
checkWeaponStoryUnlocks(catalog, user, evolvedId, weapon.Level, nowMillis)
|
||||
})
|
||||
@@ -657,7 +717,8 @@ func (s *WeaponServiceServer) EnhanceByWeapon(ctx context.Context, req *pb.Enhan
|
||||
continue
|
||||
}
|
||||
|
||||
baseExp := catalog.BaseExpByEnhanceId[matMaster.WeaponSpecificEnhanceId]
|
||||
matLevelingEnhanceId := catalog.LevelingEnhanceIdByWeaponId[matWeapon.WeaponId]
|
||||
baseExp := catalog.BaseExpByEnhanceId[matLevelingEnhanceId]
|
||||
if matMaster.WeaponType != 0 && matMaster.WeaponType == wm.WeaponType {
|
||||
baseExp = baseExp * config.MaterialSameWeaponExpCoefficientPermil / 1000
|
||||
}
|
||||
@@ -683,8 +744,26 @@ func (s *WeaponServiceServer) EnhanceByWeapon(ctx context.Context, req *pb.Enhan
|
||||
}
|
||||
|
||||
weapon.Exp += totalExp
|
||||
if thresholds, ok := catalog.ExpByEnhanceId[wm.WeaponSpecificEnhanceId]; ok {
|
||||
levelingEnhanceId := catalog.LevelingEnhanceIdByWeaponId[weapon.WeaponId]
|
||||
if thresholds, ok := catalog.ExpByEnhanceId[levelingEnhanceId]; ok {
|
||||
weapon.Level, weapon.Exp = gameutil.LevelAndCap(weapon.Exp, thresholds)
|
||||
if maxFunc, ok := catalog.MaxLevelByEnhanceId[wm.WeaponSpecificEnhanceId]; ok {
|
||||
cap := maxFunc.Evaluate(weapon.LimitBreakCount)
|
||||
if weapon.Level > cap {
|
||||
weapon.Level = cap
|
||||
if int(cap) >= 0 && int(cap) < len(thresholds) {
|
||||
weapon.Exp = thresholds[cap]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
note := user.WeaponNotes[weapon.WeaponId]
|
||||
if note.MaxLevel < weapon.Level {
|
||||
note.WeaponId = weapon.WeaponId
|
||||
note.MaxLevel = weapon.Level
|
||||
note.LatestVersion = nowMillis
|
||||
user.WeaponNotes[weapon.WeaponId] = note
|
||||
}
|
||||
|
||||
weapon.LatestVersion = nowMillis
|
||||
|
||||
@@ -294,17 +294,16 @@ func ComputeDelta(before, after *store.UserState, changedTables []string) map[st
|
||||
diff := make(map[string]*pb.DiffData, len(changedTables))
|
||||
for _, table := range changedTables {
|
||||
afterJSON := projectTable(table, *after)
|
||||
updates := afterJSON
|
||||
deleteKeys := "[]"
|
||||
if kf := keyFieldsForTable(table); len(kf) > 0 {
|
||||
beforeJSON := projectTable(table, *before)
|
||||
deleteKeys = ComputeDeleteKeys(
|
||||
parseJSONRecords(beforeJSON),
|
||||
parseJSONRecords(afterJSON),
|
||||
kf,
|
||||
)
|
||||
beforeRecs := parseJSONRecords(projectTable(table, *before))
|
||||
afterRecs := parseJSONRecords(afterJSON)
|
||||
updates = ComputeUpdateRecords(beforeRecs, afterRecs, kf)
|
||||
deleteKeys = ComputeDeleteKeys(beforeRecs, afterRecs, kf)
|
||||
}
|
||||
diff[table] = &pb.DiffData{
|
||||
UpdateRecordsJson: afterJSON,
|
||||
UpdateRecordsJson: updates,
|
||||
DeleteKeysJson: deleteKeys,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package userdata
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
pb "lunar-tear/server/gen/proto"
|
||||
@@ -120,6 +121,34 @@ func ComputeDeleteKeys(oldRecords, newRecords []map[string]any, keyFields []stri
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func ComputeUpdateRecords(oldRecords, newRecords []map[string]any, keyFields []string) string {
|
||||
if len(newRecords) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
|
||||
oldByKey := make(map[string]map[string]any, len(oldRecords))
|
||||
for _, r := range oldRecords {
|
||||
oldByKey[compositeKey(r, keyFields)] = r
|
||||
}
|
||||
|
||||
var changed []map[string]any
|
||||
for _, r := range newRecords {
|
||||
prev, exists := oldByKey[compositeKey(r, keyFields)]
|
||||
if !exists || !reflect.DeepEqual(prev, r) {
|
||||
changed = append(changed, r)
|
||||
}
|
||||
}
|
||||
|
||||
if len(changed) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
b, err := json.Marshal(changed)
|
||||
if err != nil {
|
||||
return "[]"
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func compositeKey(record map[string]any, fields []string) string {
|
||||
var sb strings.Builder
|
||||
for i, f := range fields {
|
||||
|
||||
Reference in New Issue
Block a user