fix(audit): Fortuna pass level, display-name persist, loadout & craft-timer queries
Build & Deploy / build (push) Successful in 39s

Audit of the emulator surface + 4 fixes:
- Fortuna pass level was frozen: nothing ever granted season XP. ClaimActiveContract
  now grants + persists FortunaPass{2,3}_SeasonXp (scaled to the contract's reputation)
  and returns the new total, so the pass level moves as you complete contracts.
- UpdateUserTitleDisplayName never persisted the rename (echoed back, lost on relog).
  Added DbUserService.UpdateDisplayNameAsync and call it.
- GetPlayerSets returned a blank loadout; now reads the persisted LOADOUT key.
- GetCraftingInProgressData was a stub; now returns the persisted CraftingTimer so an
  in-progress craft + remaining time survive a menu reopen/relog.

Remaining known gaps documented in Plane (need client data / multiplayer / out of scope).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 02:56:47 +02:00
co-authored by Claude Opus 4.8
parent 14ab3267f4
commit 1b4c1b2606
9 changed files with 80 additions and 29 deletions
@@ -81,9 +81,16 @@ public class ClaimActiveContract : ICloudScriptFunction<FYClaimCompletedActiveCo
}
var factionKey = "FactionProgression" + contract.Faction;
// Fortuna pass season XP is stored per season; the client derives the pass level
// from this key. No challenge system is emulated, so contracts are the XP source.
#if SEASON_3_RELEASE || SEASON_3_DEBUG
const string seasonXpKey = "FortunaPass3_SeasonXp";
#else
const string seasonXpKey = "FortunaPass2_SeasonXp";
#endif
var userData = await _userDataService.FindAsync(
userId, userId,
new List<string>{"ContractsActive", "ContractsOneTimeCompleted", "Balance", "Inventory", factionKey, "JobBoardsData" }
new List<string>{"ContractsActive", "ContractsOneTimeCompleted", "Balance", "Inventory", factionKey, "JobBoardsData", seasonXpKey }
);
var factionProgression = JsonSerializer.Deserialize<int>(userData[factionKey].Value);
@@ -270,6 +277,12 @@ public class ClaimActiveContract : ICloudScriptFunction<FYClaimCompletedActiveCo
newContracts.Add(newContract);
}
// Grant Fortuna pass season XP for completing this contract and persist it, so the
// pass level (derived client-side from FortunaPass{season}_SeasonXp) actually moves.
// No exact rate ships in the data, so scale it to the contract's reputation value.
var seasonXp = int.TryParse(userData[seasonXpKey].Value, out var currentSeasonXp) ? currentSeasonXp : 0;
seasonXp += contract.ReputationIncrease * 10;
await _userDataService.UpdateAsync(
userId, userId,
new Dictionary<string, string>{
@@ -279,6 +292,7 @@ public class ClaimActiveContract : ICloudScriptFunction<FYClaimCompletedActiveCo
["Inventory"] = JsonSerializer.Serialize(newInventory),
[factionKey] = JsonSerializer.Serialize(factionProgression),
["JobBoardsData"] = JsonSerializer.Serialize(jobBoardsData),
[seasonXpKey] = JsonSerializer.Serialize(seasonXp),
}
);
@@ -297,7 +311,7 @@ public class ClaimActiveContract : ICloudScriptFunction<FYClaimCompletedActiveCo
CurrentProgression = factionProgression,
},
Status = 18, // EYClaimContractRewardsStatus::OK
UpdatedSeasonXp = 0 // TODO: Probably a separate season XP rate configured by server?
UpdatedSeasonXp = seasonXp // new season XP total (client derives the pass level from it)
};
}
}