mirror of Walter-Sparrow / lunar-tear
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix stale story-unlock and post-evolve weapon state

+145 -11
+27
server/internal/masterdata/weapon.go
··· 42 42 BaseExpByEnhanceId map[int32]int32 43 43 ReleaseConditionsByGroupId map[int32][]EntityMWeaponStoryReleaseConditionGroup 44 44 45 + LevelingEnhanceIdByWeaponId map[int32]int32 46 + 45 47 AwakenByWeaponId map[int32]EntityMWeaponAwaken 46 48 AwakenMaterialsByGroupId map[int32][]EntityMWeaponAwakenMaterialGroup 47 49 } ··· 141 143 LimitBreakCostByMaterialByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)), 142 144 BaseExpByEnhanceId: make(map[int32]int32, len(enhanceRows)), 143 145 ReleaseConditionsByGroupId: make(map[int32][]EntityMWeaponStoryReleaseConditionGroup), 146 + 147 + LevelingEnhanceIdByWeaponId: make(map[int32]int32, len(weapons)), 144 148 145 149 AwakenByWeaponId: make(map[int32]EntityMWeaponAwaken, len(awakenRows)), 146 150 AwakenMaterialsByGroupId: make(map[int32][]EntityMWeaponAwakenMaterialGroup), ··· 341 345 fallbackCount++ 342 346 } 343 347 log.Printf("[WeaponCatalog] rarity fallback: assigned synthetic enhance IDs to %d weapons", fallbackCount) 348 + 349 + // Build LevelingEnhanceIdByWeaponId: every member of an evolution chain 350 + // inherits the chain root's (post-rarity-fallback) WeaponSpecificEnhanceId 351 + // so cumulative exp stays consistent across Evolve. Weapons not in any 352 + // chain map to their own enhance id. 353 + for _, rows := range grouped { 354 + if len(rows) == 0 { 355 + continue 356 + } 357 + rootMaster, ok := catalog.Weapons[rows[0].WeaponId] 358 + if !ok { 359 + continue 360 + } 361 + rootEnhanceId := rootMaster.WeaponSpecificEnhanceId 362 + for _, row := range rows { 363 + catalog.LevelingEnhanceIdByWeaponId[row.WeaponId] = rootEnhanceId 364 + } 365 + } 366 + for wid, w := range catalog.Weapons { 367 + if _, exists := catalog.LevelingEnhanceIdByWeaponId[wid]; !exists { 368 + catalog.LevelingEnhanceIdByWeaponId[wid] = w.WeaponSpecificEnhanceId 369 + } 370 + } 344 371 345 372 return catalog, nil 346 373 }
+83 -4
server/internal/service/weapon.go
··· 122 122 } 123 123 124 124 weapon.Exp += totalExp 125 - if thresholds, ok := catalog.ExpByEnhanceId[wm.WeaponSpecificEnhanceId]; ok { 125 + levelingEnhanceId := catalog.LevelingEnhanceIdByWeaponId[weapon.WeaponId] 126 + if thresholds, ok := catalog.ExpByEnhanceId[levelingEnhanceId]; ok { 126 127 weapon.Level, weapon.Exp = gameutil.LevelAndCap(weapon.Exp, thresholds) 128 + if maxFunc, ok := catalog.MaxLevelByEnhanceId[wm.WeaponSpecificEnhanceId]; ok { 129 + cap := maxFunc.Evaluate(weapon.LimitBreakCount) 130 + if weapon.Level > cap { 131 + weapon.Level = cap 132 + if int(cap) >= 0 && int(cap) < len(thresholds) { 133 + weapon.Exp = thresholds[cap] 134 + } 135 + } 136 + } 137 + } 138 + 139 + note := user.WeaponNotes[weapon.WeaponId] 140 + if note.MaxLevel < weapon.Level { 141 + note.WeaponId = weapon.WeaponId 142 + note.MaxLevel = weapon.Level 143 + note.LatestVersion = nowMillis 144 + user.WeaponNotes[weapon.WeaponId] = note 127 145 } 128 146 129 147 weapon.LatestVersion = nowMillis ··· 240 258 log.Printf("[WeaponService] Evolve: gold cost=%d", goldCost) 241 259 } 242 260 261 + oldWeaponId := wm.WeaponId 243 262 weapon.WeaponId = evolvedId 244 263 weapon.LatestVersion = nowMillis 245 264 user.Weapons[req.UserWeaponUuid] = weapon 246 265 266 + note, hasNote := user.WeaponNotes[evolvedId] 267 + if !hasNote { 268 + note = store.WeaponNoteState{ 269 + WeaponId: evolvedId, 270 + MaxLevel: weapon.Level, 271 + MaxLimitBreakCount: weapon.LimitBreakCount, 272 + FirstAcquisitionDatetime: nowMillis, 273 + LatestVersion: nowMillis, 274 + } 275 + user.WeaponNotes[evolvedId] = note 276 + } else { 277 + changed := false 278 + if note.MaxLevel < weapon.Level { 279 + note.MaxLevel = weapon.Level 280 + changed = true 281 + } 282 + if note.MaxLimitBreakCount < weapon.LimitBreakCount { 283 + note.MaxLimitBreakCount = weapon.LimitBreakCount 284 + changed = true 285 + } 286 + if changed { 287 + note.WeaponId = evolvedId 288 + note.LatestVersion = nowMillis 289 + user.WeaponNotes[evolvedId] = note 290 + } 291 + } 292 + 293 + if oldStory, hasOldStory := user.WeaponStories[oldWeaponId]; hasOldStory { 294 + newStory, hasNewStory := user.WeaponStories[evolvedId] 295 + if !hasNewStory || newStory.ReleasedMaxStoryIndex < oldStory.ReleasedMaxStoryIndex { 296 + if user.WeaponStories == nil { 297 + user.WeaponStories = make(map[int32]store.WeaponStoryState) 298 + } 299 + user.WeaponStories[evolvedId] = store.WeaponStoryState{ 300 + WeaponId: evolvedId, 301 + ReleasedMaxStoryIndex: oldStory.ReleasedMaxStoryIndex, 302 + LatestVersion: nowMillis, 303 + } 304 + } 305 + } 306 + 247 307 evolvedMaster, ok := catalog.Weapons[evolvedId] 248 308 if ok { 249 309 if slots, ok := catalog.AbilitySlots[evolvedMaster.WeaponAbilityGroupId]; ok { ··· 259 319 } 260 320 } 261 321 262 - log.Printf("[WeaponService] Evolve: weaponId %d -> %d", wm.WeaponId, evolvedId) 322 + log.Printf("[WeaponService] Evolve: weaponId %d -> %d", oldWeaponId, evolvedId) 263 323 264 324 checkWeaponStoryUnlocks(catalog, user, evolvedId, weapon.Level, nowMillis) 265 325 }) ··· 657 717 continue 658 718 } 659 719 660 - baseExp := catalog.BaseExpByEnhanceId[matMaster.WeaponSpecificEnhanceId] 720 + matLevelingEnhanceId := catalog.LevelingEnhanceIdByWeaponId[matWeapon.WeaponId] 721 + baseExp := catalog.BaseExpByEnhanceId[matLevelingEnhanceId] 661 722 if matMaster.WeaponType != 0 && matMaster.WeaponType == wm.WeaponType { 662 723 baseExp = baseExp * config.MaterialSameWeaponExpCoefficientPermil / 1000 663 724 } ··· 683 744 } 684 745 685 746 weapon.Exp += totalExp 686 - if thresholds, ok := catalog.ExpByEnhanceId[wm.WeaponSpecificEnhanceId]; ok { 747 + levelingEnhanceId := catalog.LevelingEnhanceIdByWeaponId[weapon.WeaponId] 748 + if thresholds, ok := catalog.ExpByEnhanceId[levelingEnhanceId]; ok { 687 749 weapon.Level, weapon.Exp = gameutil.LevelAndCap(weapon.Exp, thresholds) 750 + if maxFunc, ok := catalog.MaxLevelByEnhanceId[wm.WeaponSpecificEnhanceId]; ok { 751 + cap := maxFunc.Evaluate(weapon.LimitBreakCount) 752 + if weapon.Level > cap { 753 + weapon.Level = cap 754 + if int(cap) >= 0 && int(cap) < len(thresholds) { 755 + weapon.Exp = thresholds[cap] 756 + } 757 + } 758 + } 759 + } 760 + 761 + note := user.WeaponNotes[weapon.WeaponId] 762 + if note.MaxLevel < weapon.Level { 763 + note.WeaponId = weapon.WeaponId 764 + note.MaxLevel = weapon.Level 765 + note.LatestVersion = nowMillis 766 + user.WeaponNotes[weapon.WeaponId] = note 688 767 } 689 768 690 769 weapon.LatestVersion = nowMillis
+6 -7
server/internal/userdata/changed_tables.go
··· 294 294 diff := make(map[string]*pb.DiffData, len(changedTables)) 295 295 for _, table := range changedTables { 296 296 afterJSON := projectTable(table, *after) 297 + updates := afterJSON 297 298 deleteKeys := "[]" 298 299 if kf := keyFieldsForTable(table); len(kf) > 0 { 299 - beforeJSON := projectTable(table, *before) 300 - deleteKeys = ComputeDeleteKeys( 301 - parseJSONRecords(beforeJSON), 302 - parseJSONRecords(afterJSON), 303 - kf, 304 - ) 300 + beforeRecs := parseJSONRecords(projectTable(table, *before)) 301 + afterRecs := parseJSONRecords(afterJSON) 302 + updates = ComputeUpdateRecords(beforeRecs, afterRecs, kf) 303 + deleteKeys = ComputeDeleteKeys(beforeRecs, afterRecs, kf) 305 304 } 306 305 diff[table] = &pb.DiffData{ 307 - UpdateRecordsJson: afterJSON, 306 + UpdateRecordsJson: updates, 308 307 DeleteKeysJson: deleteKeys, 309 308 } 310 309 }
+29
server/internal/userdata/diffset.go
··· 3 3 import ( 4 4 "encoding/json" 5 5 "fmt" 6 + "reflect" 6 7 "strings" 7 8 8 9 pb "lunar-tear/server/gen/proto" ··· 114 115 return "[]" 115 116 } 116 117 b, err := json.Marshal(deleted) 118 + if err != nil { 119 + return "[]" 120 + } 121 + return string(b) 122 + } 123 + 124 + func ComputeUpdateRecords(oldRecords, newRecords []map[string]any, keyFields []string) string { 125 + if len(newRecords) == 0 { 126 + return "[]" 127 + } 128 + 129 + oldByKey := make(map[string]map[string]any, len(oldRecords)) 130 + for _, r := range oldRecords { 131 + oldByKey[compositeKey(r, keyFields)] = r 132 + } 133 + 134 + var changed []map[string]any 135 + for _, r := range newRecords { 136 + prev, exists := oldByKey[compositeKey(r, keyFields)] 137 + if !exists || !reflect.DeepEqual(prev, r) { 138 + changed = append(changed, r) 139 + } 140 + } 141 + 142 + if len(changed) == 0 { 143 + return "[]" 144 + } 145 + b, err := json.Marshal(changed) 117 146 if err != nil { 118 147 return "[]" 119 148 }