Simplify userdb access

This commit is contained in:
BillyCool
2026-04-21 02:29:56 +10:00
parent c5595ea083
commit 352f97682c
18 changed files with 241 additions and 235 deletions

View File

@@ -10,6 +10,8 @@ namespace MariesWonderland.Data;
/// </summary> /// </summary>
public class DarkUserMemoryDatabase public class DarkUserMemoryDatabase
{ {
public long UserId { get; set; }
public List<EntityIUser> EntityIUser { get; set; } = []; public List<EntityIUser> EntityIUser { get; set; } = [];
public List<EntityIUserApple> EntityIUserApple { get; set; } = []; public List<EntityIUserApple> EntityIUserApple { get; set; } = [];

View File

@@ -26,8 +26,8 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
var userId = GenerateUserId(); var userId = GenerateUserId();
_uuidToUserId[uuid] = userId; _uuidToUserId[uuid] = userId;
var db = new DarkUserMemoryDatabase(); var db = new DarkUserMemoryDatabase { UserId = userId };
SeedInitialUserData(db, userId); SeedInitialUserData(db);
_users[userId] = db; _users[userId] = db;
return (userId, true); return (userId, true);
} }
@@ -64,7 +64,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
{ {
if (!_users.TryGetValue(userId, out var db)) if (!_users.TryGetValue(userId, out var db))
{ {
db = new DarkUserMemoryDatabase(); db = new DarkUserMemoryDatabase { UserId = userId };
_users[userId] = db; _users[userId] = db;
} }
return db; return db;
@@ -96,7 +96,10 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
/// Stores a user database, replacing any existing one for that userId. /// Stores a user database, replacing any existing one for that userId.
/// </summary> /// </summary>
public void Set(long userId, DarkUserMemoryDatabase db) public void Set(long userId, DarkUserMemoryDatabase db)
=> _users[userId] = db; {
db.UserId = userId;
_users[userId] = db;
}
public IReadOnlyDictionary<long, DarkUserMemoryDatabase> All => _users; public IReadOnlyDictionary<long, DarkUserMemoryDatabase> All => _users;
@@ -141,7 +144,10 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
_sessions.Clear(); _sessions.Clear();
foreach (var (userId, db) in snapshot.Users) foreach (var (userId, db) in snapshot.Users)
{
db.UserId = userId;
_users[userId] = db; _users[userId] = db;
}
foreach (var (uuid, userId) in snapshot.UuidToUserId) foreach (var (uuid, userId) in snapshot.UuidToUserId)
_uuidToUserId[uuid] = userId; _uuidToUserId[uuid] = userId;
@@ -173,13 +179,13 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
/// <summary> /// <summary>
/// Populates a new user database with default records (profile, status, starting weapons, etc.). /// Populates a new user database with default records (profile, status, starting weapons, etc.).
/// </summary> /// </summary>
private void SeedInitialUserData(DarkUserMemoryDatabase db, long userId) private void SeedInitialUserData(DarkUserMemoryDatabase db)
{ {
var nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
db.EntityIUser.Add(new EntityIUser db.EntityIUser.Add(new EntityIUser
{ {
UserId = userId, UserId = db.UserId,
PlayerId = GeneratePlayerId(), PlayerId = GeneratePlayerId(),
OsType = 2, OsType = 2,
PlatformType = PlatformType.GOOGLE_PLAY_STORE, PlatformType = PlatformType.GOOGLE_PLAY_STORE,
@@ -190,13 +196,13 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserSetting.Add(new EntityIUserSetting db.EntityIUserSetting.Add(new EntityIUserSetting
{ {
UserId = userId, UserId = db.UserId,
IsNotifyPurchaseAlert = false IsNotifyPurchaseAlert = false
}); });
db.EntityIUserStatus.Add(new EntityIUserStatus db.EntityIUserStatus.Add(new EntityIUserStatus
{ {
UserId = userId, UserId = db.UserId,
Level = 1, Level = 1,
Exp = 0, Exp = 0,
StaminaMilliValue = 60000, StaminaMilliValue = 60000,
@@ -205,7 +211,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserProfile.Add(new EntityIUserProfile db.EntityIUserProfile.Add(new EntityIUserProfile
{ {
UserId = userId, UserId = db.UserId,
Name = string.Empty, Name = string.Empty,
NameUpdateDatetime = nowMs, NameUpdateDatetime = nowMs,
Message = string.Empty, Message = string.Empty,
@@ -216,7 +222,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserLogin.Add(new EntityIUserLogin db.EntityIUserLogin.Add(new EntityIUserLogin
{ {
UserId = userId, UserId = db.UserId,
TotalLoginCount = 1, TotalLoginCount = 1,
ContinualLoginCount = 1, ContinualLoginCount = 1,
MaxContinualLoginCount = 1, MaxContinualLoginCount = 1,
@@ -226,7 +232,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserLoginBonus.Add(new EntityIUserLoginBonus db.EntityIUserLoginBonus.Add(new EntityIUserLoginBonus
{ {
UserId = userId, UserId = db.UserId,
LoginBonusId = 1, LoginBonusId = 1,
CurrentPageNumber = 1, CurrentPageNumber = 1,
CurrentStampNumber = 0, CurrentStampNumber = 0,
@@ -235,7 +241,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserTutorialProgress.Add(new EntityIUserTutorialProgress db.EntityIUserTutorialProgress.Add(new EntityIUserTutorialProgress
{ {
UserId = userId, UserId = db.UserId,
TutorialType = TutorialType.GAME_START, TutorialType = TutorialType.GAME_START,
ProgressPhase = 0, ProgressPhase = 0,
ChoiceId = 0 ChoiceId = 0
@@ -247,7 +253,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserWeapon.Add(new EntityIUserWeapon db.EntityIUserWeapon.Add(new EntityIUserWeapon
{ {
UserId = userId, UserId = db.UserId,
UserWeaponUuid = uuid, UserWeaponUuid = uuid,
WeaponId = weaponId, WeaponId = weaponId,
Level = 1, Level = 1,
@@ -259,7 +265,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserWeaponNote.Add(new EntityIUserWeaponNote db.EntityIUserWeaponNote.Add(new EntityIUserWeaponNote
{ {
UserId = userId, UserId = db.UserId,
WeaponId = weaponId, WeaponId = weaponId,
MaxLevel = 1, MaxLevel = 1,
MaxLimitBreakCount = 0, MaxLimitBreakCount = 0,
@@ -268,7 +274,7 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
db.EntityIUserWeaponStory.Add(new EntityIUserWeaponStory db.EntityIUserWeaponStory.Add(new EntityIUserWeaponStory
{ {
UserId = userId, UserId = db.UserId,
WeaponId = weaponId, WeaponId = weaponId,
ReleasedMaxStoryIndex = 1 ReleasedMaxStoryIndex = 1
}); });
@@ -277,10 +283,10 @@ public class UserDataStore(DarkMasterMemoryDatabase masterDb)
if (masterWeapon != null) if (masterWeapon != null)
{ {
foreach (EntityMWeaponAbilityGroup ag in _masterDb.EntityMWeaponAbilityGroup.Where(g => g.WeaponAbilityGroupId == masterWeapon.WeaponAbilityGroupId)) foreach (EntityMWeaponAbilityGroup ag in _masterDb.EntityMWeaponAbilityGroup.Where(g => g.WeaponAbilityGroupId == masterWeapon.WeaponAbilityGroupId))
db.EntityIUserWeaponAbility.Add(new EntityIUserWeaponAbility { UserId = userId, UserWeaponUuid = uuid, SlotNumber = ag.SlotNumber, Level = 1 }); db.EntityIUserWeaponAbility.Add(new EntityIUserWeaponAbility { UserId = db.UserId, UserWeaponUuid = uuid, SlotNumber = ag.SlotNumber, Level = 1 });
foreach (EntityMWeaponSkillGroup sg in _masterDb.EntityMWeaponSkillGroup.Where(g => g.WeaponSkillGroupId == masterWeapon.WeaponSkillGroupId)) foreach (EntityMWeaponSkillGroup sg in _masterDb.EntityMWeaponSkillGroup.Where(g => g.WeaponSkillGroupId == masterWeapon.WeaponSkillGroupId))
db.EntityIUserWeaponSkill.Add(new EntityIUserWeaponSkill { UserId = userId, UserWeaponUuid = uuid, SlotNumber = sg.SlotNumber, Level = 1 }); db.EntityIUserWeaponSkill.Add(new EntityIUserWeaponSkill { UserId = db.UserId, UserWeaponUuid = uuid, SlotNumber = sg.SlotNumber, Level = 1 });
} }
} }
} }

View File

@@ -13,7 +13,7 @@ public static class PossessionHelper
/// <summary> /// <summary>
/// Grants a possession to the user by type, delegating to type-specific handlers. /// Grants a possession to the user by type, delegating to type-specific handlers.
/// </summary> /// </summary>
public static void Apply(DarkUserMemoryDatabase userDb, long userId, PossessionType type, int id, int count, DarkMasterMemoryDatabase masterDb) public static void Apply(DarkUserMemoryDatabase userDb, PossessionType type, int id, int count, DarkMasterMemoryDatabase masterDb)
{ {
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
@@ -29,7 +29,7 @@ public static class PossessionHelper
{ {
EntityIUserMaterial? mat = userDb.EntityIUserMaterial.FirstOrDefault(m => m.MaterialId == id); EntityIUserMaterial? mat = userDb.EntityIUserMaterial.FirstOrDefault(m => m.MaterialId == id);
if (mat == null) if (mat == null)
userDb.EntityIUserMaterial.Add(new EntityIUserMaterial { UserId = userId, MaterialId = id, Count = count, FirstAcquisitionDatetime = nowMs }); userDb.EntityIUserMaterial.Add(new EntityIUserMaterial { UserId = userDb.UserId, MaterialId = id, Count = count, FirstAcquisitionDatetime = nowMs });
else else
mat.Count += count; mat.Count += count;
break; break;
@@ -38,7 +38,7 @@ public static class PossessionHelper
{ {
EntityIUserConsumableItem? item = userDb.EntityIUserConsumableItem.FirstOrDefault(c => c.ConsumableItemId == id); EntityIUserConsumableItem? item = userDb.EntityIUserConsumableItem.FirstOrDefault(c => c.ConsumableItemId == id);
if (item == null) if (item == null)
userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem { UserId = userId, ConsumableItemId = id, Count = count, FirstAcquisitionDatetime = nowMs }); userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem { UserId = userDb.UserId, ConsumableItemId = id, Count = count, FirstAcquisitionDatetime = nowMs });
else else
item.Count += count; item.Count += count;
break; break;
@@ -47,7 +47,7 @@ public static class PossessionHelper
{ {
EntityIUserImportantItem? item = userDb.EntityIUserImportantItem.FirstOrDefault(c => c.ImportantItemId == id); EntityIUserImportantItem? item = userDb.EntityIUserImportantItem.FirstOrDefault(c => c.ImportantItemId == id);
if (item == null) if (item == null)
userDb.EntityIUserImportantItem.Add(new EntityIUserImportantItem { UserId = userId, ImportantItemId = id, Count = count, FirstAcquisitionDatetime = nowMs }); userDb.EntityIUserImportantItem.Add(new EntityIUserImportantItem { UserId = userDb.UserId, ImportantItemId = id, Count = count, FirstAcquisitionDatetime = nowMs });
else else
item.Count += count; item.Count += count;
break; break;
@@ -56,24 +56,24 @@ public static class PossessionHelper
{ {
EntityIUserPremiumItem? item = userDb.EntityIUserPremiumItem.FirstOrDefault(p => p.PremiumItemId == id); EntityIUserPremiumItem? item = userDb.EntityIUserPremiumItem.FirstOrDefault(p => p.PremiumItemId == id);
if (item == null) if (item == null)
userDb.EntityIUserPremiumItem.Add(new EntityIUserPremiumItem { UserId = userId, PremiumItemId = id, AcquisitionDatetime = nowMs }); userDb.EntityIUserPremiumItem.Add(new EntityIUserPremiumItem { UserId = userDb.UserId, PremiumItemId = id, AcquisitionDatetime = nowMs });
else else
item.AcquisitionDatetime = nowMs; item.AcquisitionDatetime = nowMs;
break; break;
} }
case PossessionType.WEAPON: case PossessionType.WEAPON:
case PossessionType.WEAPON_ENHANCED: case PossessionType.WEAPON_ENHANCED:
WeaponHelper.GrantWeapon(userDb, userId, id, masterDb); WeaponHelper.GrantWeapon(userDb, id, masterDb);
break; break;
case PossessionType.COSTUME: case PossessionType.COSTUME:
case PossessionType.COSTUME_ENHANCED: case PossessionType.COSTUME_ENHANCED:
GrantCostume(userDb, userId, id, masterDb); GrantCostume(userDb, id, masterDb);
break; break;
case PossessionType.COMPANION: case PossessionType.COMPANION:
GrantCompanion(userDb, userId, id); GrantCompanion(userDb, id);
break; break;
case PossessionType.PARTS: case PossessionType.PARTS:
GrantParts(userDb, userId, id, masterDb); GrantParts(userDb, id, masterDb);
break; break;
} }
} }
@@ -81,14 +81,14 @@ public static class PossessionHelper
/// <summary> /// <summary>
/// Grants a costume to the user, unlocking the associated character if not already owned. /// Grants a costume to the user, unlocking the associated character if not already owned.
/// </summary> /// </summary>
public static void GrantCostume(DarkUserMemoryDatabase userDb, long userId, int costumeId, DarkMasterMemoryDatabase masterDb) public static void GrantCostume(DarkUserMemoryDatabase userDb, int costumeId, DarkMasterMemoryDatabase masterDb)
{ {
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string uuid = Guid.NewGuid().ToString(); string uuid = Guid.NewGuid().ToString();
userDb.EntityIUserCostume.Add(new EntityIUserCostume userDb.EntityIUserCostume.Add(new EntityIUserCostume
{ {
UserId = userId, UserId = userDb.UserId,
UserCostumeUuid = uuid, UserCostumeUuid = uuid,
CostumeId = costumeId, CostumeId = costumeId,
Level = 1, Level = 1,
@@ -99,22 +99,22 @@ public static class PossessionHelper
// Auto-unlock the character tied to this costume if not already owned // Auto-unlock the character tied to this costume if not already owned
EntityMCostume? masterCostume = masterDb.EntityMCostume.FirstOrDefault(c => c.CostumeId == costumeId); EntityMCostume? masterCostume = masterDb.EntityMCostume.FirstOrDefault(c => c.CostumeId == costumeId);
if (masterCostume != null && !userDb.EntityIUserCharacter.Any(c => c.CharacterId == masterCostume.CharacterId)) if (masterCostume != null && !userDb.EntityIUserCharacter.Any(c => c.CharacterId == masterCostume.CharacterId))
userDb.EntityIUserCharacter.Add(new EntityIUserCharacter { UserId = userId, CharacterId = masterCostume.CharacterId, Level = 1 }); userDb.EntityIUserCharacter.Add(new EntityIUserCharacter { UserId = userDb.UserId, CharacterId = masterCostume.CharacterId, Level = 1 });
userDb.EntityIUserCostumeActiveSkill.Add(new EntityIUserCostumeActiveSkill { UserId = userId, UserCostumeUuid = uuid, Level = 1, AcquisitionDatetime = nowMs }); userDb.EntityIUserCostumeActiveSkill.Add(new EntityIUserCostumeActiveSkill { UserId = userDb.UserId, UserCostumeUuid = uuid, Level = 1, AcquisitionDatetime = nowMs });
} }
/// <summary> /// <summary>
/// Grants a companion to the user. Skips if the companion is already owned. /// Grants a companion to the user. Skips if the companion is already owned.
/// </summary> /// </summary>
public static void GrantCompanion(DarkUserMemoryDatabase userDb, long userId, int companionId) public static void GrantCompanion(DarkUserMemoryDatabase userDb, int companionId)
{ {
if (userDb.EntityIUserCompanion.Any(c => c.CompanionId == companionId)) return; if (userDb.EntityIUserCompanion.Any(c => c.CompanionId == companionId)) return;
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
userDb.EntityIUserCompanion.Add(new EntityIUserCompanion userDb.EntityIUserCompanion.Add(new EntityIUserCompanion
{ {
UserId = userId, UserId = userDb.UserId,
UserCompanionUuid = Guid.NewGuid().ToString(), UserCompanionUuid = Guid.NewGuid().ToString(),
CompanionId = companionId, CompanionId = companionId,
Level = 1, Level = 1,
@@ -126,7 +126,7 @@ public static class PossessionHelper
/// <summary> /// <summary>
/// Grants a single Parts item to the user. Skips if the user already owns a part with the same PartsId. /// Grants a single Parts item to the user. Skips if the user already owns a part with the same PartsId.
/// </summary> /// </summary>
public static void GrantParts(DarkUserMemoryDatabase userDb, long userId, int partsId, DarkMasterMemoryDatabase masterDb) public static void GrantParts(DarkUserMemoryDatabase userDb, int partsId, DarkMasterMemoryDatabase masterDb)
{ {
if (userDb.EntityIUserParts.Any(p => p.PartsId == partsId)) return; if (userDb.EntityIUserParts.Any(p => p.PartsId == partsId)) return;
@@ -148,7 +148,7 @@ public static class PossessionHelper
{ {
userDb.EntityIUserPartsGroupNote.Add(new EntityIUserPartsGroupNote userDb.EntityIUserPartsGroupNote.Add(new EntityIUserPartsGroupNote
{ {
UserId = userId, UserId = userDb.UserId,
PartsGroupId = partsDef.PartsGroupId, PartsGroupId = partsDef.PartsGroupId,
FirstAcquisitionDatetime = nowMs FirstAcquisitionDatetime = nowMs
}); });
@@ -157,7 +157,7 @@ public static class PossessionHelper
userDb.EntityIUserParts.Add(new EntityIUserParts userDb.EntityIUserParts.Add(new EntityIUserParts
{ {
UserId = userId, UserId = userDb.UserId,
UserPartsUuid = Guid.NewGuid().ToString(), UserPartsUuid = Guid.NewGuid().ToString(),
PartsId = partsId, PartsId = partsId,
Level = 1, Level = 1,

View File

@@ -14,14 +14,14 @@ public static class WeaponHelper
/// Grants a weapon to the user: creates EntityIUserWeapon, EntityIUserWeaponNote (if new), /// Grants a weapon to the user: creates EntityIUserWeapon, EntityIUserWeaponNote (if new),
/// ability/skill slots, and unlocks weapon stories for the ACQUISITION condition. /// ability/skill slots, and unlocks weapon stories for the ACQUISITION condition.
/// </summary> /// </summary>
public static void GrantWeapon(DarkUserMemoryDatabase userDb, long userId, int weaponId, DarkMasterMemoryDatabase masterDb) public static void GrantWeapon(DarkUserMemoryDatabase userDb, int weaponId, DarkMasterMemoryDatabase masterDb)
{ {
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string uuid = Guid.NewGuid().ToString(); string uuid = Guid.NewGuid().ToString();
userDb.EntityIUserWeapon.Add(new EntityIUserWeapon userDb.EntityIUserWeapon.Add(new EntityIUserWeapon
{ {
UserId = userId, UserId = userDb.UserId,
UserWeaponUuid = uuid, UserWeaponUuid = uuid,
WeaponId = weaponId, WeaponId = weaponId,
Level = 1, Level = 1,
@@ -33,7 +33,7 @@ public static class WeaponHelper
{ {
userDb.EntityIUserWeaponNote.Add(new EntityIUserWeaponNote userDb.EntityIUserWeaponNote.Add(new EntityIUserWeaponNote
{ {
UserId = userId, UserId = userDb.UserId,
WeaponId = weaponId, WeaponId = weaponId,
MaxLevel = 1, MaxLevel = 1,
FirstAcquisitionDatetime = nowMs FirstAcquisitionDatetime = nowMs
@@ -46,11 +46,11 @@ public static class WeaponHelper
// Create one ability slot per entry in the weapon's ability group // Create one ability slot per entry in the weapon's ability group
foreach (EntityMWeaponAbilityGroup ag in masterDb.EntityMWeaponAbilityGroup.Where(g => g.WeaponAbilityGroupId == masterWeapon.WeaponAbilityGroupId)) foreach (EntityMWeaponAbilityGroup ag in masterDb.EntityMWeaponAbilityGroup.Where(g => g.WeaponAbilityGroupId == masterWeapon.WeaponAbilityGroupId))
userDb.EntityIUserWeaponAbility.Add(new EntityIUserWeaponAbility { UserId = userId, UserWeaponUuid = uuid, SlotNumber = ag.SlotNumber, Level = 1 }); userDb.EntityIUserWeaponAbility.Add(new EntityIUserWeaponAbility { UserId = userDb.UserId, UserWeaponUuid = uuid, SlotNumber = ag.SlotNumber, Level = 1 });
// Create one skill slot per entry in the weapon's skill group // Create one skill slot per entry in the weapon's skill group
foreach (EntityMWeaponSkillGroup sg in masterDb.EntityMWeaponSkillGroup.Where(g => g.WeaponSkillGroupId == masterWeapon.WeaponSkillGroupId)) foreach (EntityMWeaponSkillGroup sg in masterDb.EntityMWeaponSkillGroup.Where(g => g.WeaponSkillGroupId == masterWeapon.WeaponSkillGroupId))
userDb.EntityIUserWeaponSkill.Add(new EntityIUserWeaponSkill { UserId = userId, UserWeaponUuid = uuid, SlotNumber = sg.SlotNumber, Level = 1 }); userDb.EntityIUserWeaponSkill.Add(new EntityIUserWeaponSkill { UserId = userDb.UserId, UserWeaponUuid = uuid, SlotNumber = sg.SlotNumber, Level = 1 });
// Unlock weapon stories for ACQUISITION condition // Unlock weapon stories for ACQUISITION condition
if (masterWeapon.WeaponStoryReleaseConditionGroupId != 0) if (masterWeapon.WeaponStoryReleaseConditionGroupId != 0)
@@ -60,17 +60,17 @@ public static class WeaponHelper
&& c.WeaponStoryReleaseConditionType == WeaponStoryReleaseConditionType.ACQUISITION && c.WeaponStoryReleaseConditionType == WeaponStoryReleaseConditionType.ACQUISITION
&& c.ConditionValue == 0)) && c.ConditionValue == 0))
{ {
GrantWeaponStory(userDb, masterWeapon.WeaponId, condRow.StoryIndex, userId); GrantWeaponStory(userDb, masterWeapon.WeaponId, condRow.StoryIndex);
} }
} }
} }
/// <summary>Creates or updates a weapon story unlock record.</summary> /// <summary>Creates or updates a weapon story unlock record.</summary>
public static void GrantWeaponStory(DarkUserMemoryDatabase userDb, int weaponId, int storyIndex, long userId) public static void GrantWeaponStory(DarkUserMemoryDatabase userDb, int weaponId, int storyIndex)
{ {
EntityIUserWeaponStory? existing = userDb.EntityIUserWeaponStory.FirstOrDefault(s => s.WeaponId == weaponId); EntityIUserWeaponStory? existing = userDb.EntityIUserWeaponStory.FirstOrDefault(s => s.WeaponId == weaponId);
if (existing == null) if (existing == null)
userDb.EntityIUserWeaponStory.Add(new EntityIUserWeaponStory { UserId = userId, WeaponId = weaponId, ReleasedMaxStoryIndex = storyIndex }); userDb.EntityIUserWeaponStory.Add(new EntityIUserWeaponStory { UserId = userDb.UserId, WeaponId = weaponId, ReleasedMaxStoryIndex = storyIndex });
else else
existing.ReleasedMaxStoryIndex = Math.Max(existing.ReleasedMaxStoryIndex, storyIndex); existing.ReleasedMaxStoryIndex = Math.Max(existing.ReleasedMaxStoryIndex, storyIndex);
} }

View File

@@ -31,7 +31,7 @@ public class AutoSaveInterceptor(UserDataStore store, ILogger<AutoSaveIntercepto
{ {
string[] parts = context.Method.Split('/', StringSplitOptions.RemoveEmptyEntries); string[] parts = context.Method.Split('/', StringSplitOptions.RemoveEmptyEntries);
string methodSuffix = parts.Length >= 2 ? $"{parts[^2]}_{parts[^1]}" : context.Method.TrimStart('/').Replace('/', '_'); string methodSuffix = parts.Length >= 2 ? $"{parts[^2]}_{parts[^1]}" : context.Method.TrimStart('/').Replace('/', '_');
_ = Task.Run(() => SaveUser(userId, userDb, methodSuffix)); _ = Task.Run(() => SaveUser(userDb, methodSuffix));
} }
return response; return response;
@@ -40,20 +40,20 @@ public class AutoSaveInterceptor(UserDataStore store, ILogger<AutoSaveIntercepto
/// <summary> /// <summary>
/// Serializes and writes a user's database to a timestamped JSON file. /// Serializes and writes a user's database to a timestamped JSON file.
/// </summary> /// </summary>
private void SaveUser(long userId, DarkUserMemoryDatabase userDb, string methodSuffix) private void SaveUser(DarkUserMemoryDatabase userDb, string methodSuffix)
{ {
try try
{ {
Directory.CreateDirectory(SavesDirectory); Directory.CreateDirectory(SavesDirectory);
string timestamp = DateTime.UtcNow.ToString("yyyyMMdd_HHmmss"); string timestamp = DateTime.UtcNow.ToString("yyyyMMdd_HHmmss");
string filePath = Path.Combine(SavesDirectory, $"{userId}_{timestamp}_{methodSuffix}.json"); string filePath = Path.Combine(SavesDirectory, $"{userDb.UserId}_{timestamp}_{methodSuffix}.json");
string json = JsonSerializer.Serialize(userDb, JsonOptions); string json = JsonSerializer.Serialize(userDb, JsonOptions);
File.WriteAllText(filePath, json); File.WriteAllText(filePath, json);
//logger.LogDebug("Auto-saved user {UserId} to {FilePath}", userId, filePath); //logger.LogDebug("Auto-saved user {UserId} to {FilePath}", userDb.UserId, filePath);
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError(ex, "AutoSaveInterceptor failed to save user {UserId}", userId); logger.LogError(ex, "AutoSaveInterceptor failed to save user {UserId}", userDb.UserId);
} }
} }
} }

View File

@@ -30,22 +30,22 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
if (bhQuest is not null) if (bhQuest is not null)
{ {
HandleBigHuntQuestStart(userDb, userId, bhQuest.QuestId, request.UserDeckNumber, nowMs); HandleBigHuntQuestStart(userDb, bhQuest.QuestId, request.UserDeckNumber, nowMs);
} }
// Set progress status // Set progress status
EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb, userId); EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb);
progress.CurrentBigHuntBossQuestId = request.BigHuntBossQuestId; progress.CurrentBigHuntBossQuestId = request.BigHuntBossQuestId;
progress.CurrentBigHuntQuestId = request.BigHuntQuestId; progress.CurrentBigHuntQuestId = request.BigHuntQuestId;
progress.CurrentQuestSceneId = 0; progress.CurrentQuestSceneId = 0;
progress.IsDryRun = request.IsDryRun; progress.IsDryRun = request.IsDryRun;
// Store deck number in server-side session // Store deck number in server-side session
EntitySBigHuntSession session = GetOrCreateSession(userDb, userId); EntitySBigHuntSession session = GetOrCreateSession(userDb);
session.DeckNumber = request.UserDeckNumber; session.DeckNumber = request.UserDeckNumber;
// Update per-boss-quest status // Update per-boss-quest status
EntityIUserBigHuntStatus status = GetOrCreateStatus(userDb, userId, request.BigHuntBossQuestId); EntityIUserBigHuntStatus status = GetOrCreateStatus(userDb, request.BigHuntBossQuestId);
status.DailyChallengeCount++; status.DailyChallengeCount++;
status.LatestChallengeDatetime = nowMs; status.LatestChallengeDatetime = nowMs;
@@ -60,7 +60,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
long userId = context.GetUserId(); long userId = context.GetUserId();
DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId); DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId);
EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb, userId); EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb);
progress.CurrentQuestSceneId = request.QuestSceneId; progress.CurrentQuestSceneId = request.QuestSceneId;
return Task.FromResult(new UpdateBigHuntQuestSceneProgressResponse()); return Task.FromResult(new UpdateBigHuntQuestSceneProgressResponse());
@@ -87,11 +87,11 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
if (bhQuest is not null) if (bhQuest is not null)
{ {
HandleBigHuntQuestFinish(userDb, userId, bhQuest.QuestId, request.IsRetired, nowMs); HandleBigHuntQuestFinish(userDb, bhQuest.QuestId, request.IsRetired, nowMs);
} }
EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb, userId); EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb);
EntitySBigHuntSession session = GetOrCreateSession(userDb, userId); EntitySBigHuntSession session = GetOrCreateSession(userDb);
// Retired or dry run — clear progress and return empty score info. // Retired or dry run — clear progress and return empty score info.
if (request.IsRetired || progress.IsDryRun) if (request.IsRetired || progress.IsDryRun)
@@ -246,7 +246,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
List<(PossessionType Type, int Id, int Count)> newItems = CollectNewRewards(rewardGroupId, oldMaxScore, userScore); List<(PossessionType Type, int Id, int Count)> newItems = CollectNewRewards(rewardGroupId, oldMaxScore, userScore);
foreach ((PossessionType type, int id, int count) in newItems) foreach ((PossessionType type, int id, int count) in newItems)
{ {
GrantPossessionViaPossessionHelper(userDb, userId, type, id, count); GrantPossessionViaPossessionHelper(userDb, type, id, count);
scoreRewards.Add(new BigHuntReward scoreRewards.Add(new BigHuntReward
{ {
PossessionType = (int)type, PossessionType = (int)type,
@@ -289,19 +289,19 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
EntityMBigHuntQuest? bhQuest = _masterDb.EntityMBigHuntQuest EntityMBigHuntQuest? bhQuest = _masterDb.EntityMBigHuntQuest
.FirstOrDefault(q => q.BigHuntQuestId == request.BigHuntQuestId); .FirstOrDefault(q => q.BigHuntQuestId == request.BigHuntQuestId);
EntitySBigHuntSession session = GetOrCreateSession(userDb, userId); EntitySBigHuntSession session = GetOrCreateSession(userDb);
if (bhQuest is not null) if (bhQuest is not null)
{ {
HandleBigHuntQuestStart(userDb, userId, bhQuest.QuestId, session.DeckNumber, nowMs); HandleBigHuntQuestStart(userDb, bhQuest.QuestId, session.DeckNumber, nowMs);
} }
// Reset scene progress // Reset scene progress
EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb, userId); EntityIUserBigHuntProgressStatus progress = GetOrCreateProgress(userDb);
progress.CurrentQuestSceneId = 0; progress.CurrentQuestSceneId = 0;
// Increment daily challenge count // Increment daily challenge count
EntityIUserBigHuntStatus status = GetOrCreateStatus(userDb, userId, request.BigHuntBossQuestId); EntityIUserBigHuntStatus status = GetOrCreateStatus(userDb, request.BigHuntBossQuestId);
status.DailyChallengeCount++; status.DailyChallengeCount++;
status.LatestChallengeDatetime = nowMs; status.LatestChallengeDatetime = nowMs;
@@ -324,7 +324,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId); DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId);
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
EntityIUserBigHuntStatus status = GetOrCreateStatus(userDb, userId, request.BigHuntBossQuestId); EntityIUserBigHuntStatus status = GetOrCreateStatus(userDb, request.BigHuntBossQuestId);
status.DailyChallengeCount += request.SkipCount; status.DailyChallengeCount += request.SkipCount;
status.LatestChallengeDatetime = nowMs; status.LatestChallengeDatetime = nowMs;
@@ -343,7 +343,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
long userId = context.GetUserId(); long userId = context.GetUserId();
DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId); DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId);
EntitySBigHuntSession session = GetOrCreateSession(userDb, userId); EntitySBigHuntSession session = GetOrCreateSession(userDb);
session.BattleBinary= request.BattleBinary.ToByteArray(); session.BattleBinary= request.BattleBinary.ToByteArray();
if (request.BigHuntBattleDetail is not null) if (request.BigHuntBattleDetail is not null)
@@ -412,11 +412,11 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
.FirstOrDefault(s => s.BigHuntWeeklyVersion == weeklyVersion); .FirstOrDefault(s => s.BigHuntWeeklyVersion == weeklyVersion);
// Resolve current week rewards // Resolve current week rewards
List<BigHuntReward> weeklyRewards = ResolveWeeklyRewards(userDb, userId, weeklyVersion, nowMs); List<BigHuntReward> weeklyRewards = ResolveWeeklyRewards(userDb, weeklyVersion, nowMs);
// Resolve last week rewards // Resolve last week rewards
long lastWeekVersion = weeklyVersion - (7L * 24 * 60 * 60 * 1000); long lastWeekVersion = weeklyVersion - (7L * 24 * 60 * 60 * 1000);
List<BigHuntReward> lastWeekRewards = ResolveWeeklyRewards(userDb, userId, lastWeekVersion, nowMs); List<BigHuntReward> lastWeekRewards = ResolveWeeklyRewards(userDb, lastWeekVersion, nowMs);
GetBigHuntTopDataResponse response = new() GetBigHuntTopDataResponse response = new()
{ {
@@ -434,13 +434,13 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
/// <summary> /// <summary>
/// Initializes quest and mission state for the underlying quest, and transitions its state to active. /// Initializes quest and mission state for the underlying quest, and transitions its state to active.
/// </summary> /// </summary>
private void HandleBigHuntQuestStart(DarkUserMemoryDatabase userDb, long userId, int questId, int deckNumber, long nowMs) private void HandleBigHuntQuestStart(DarkUserMemoryDatabase userDb, int questId, int deckNumber, long nowMs)
{ {
EntityMQuest? masterQuest = _masterDb.EntityMQuest.FirstOrDefault(q => q.QuestId == questId); EntityMQuest? masterQuest = _masterDb.EntityMQuest.FirstOrDefault(q => q.QuestId == questId);
EntityIUserQuest userQuest = userDb.EntityIUserQuest EntityIUserQuest userQuest = userDb.EntityIUserQuest
.FirstOrDefault(q => q.QuestId == questId) .FirstOrDefault(q => q.QuestId == questId)
?? AddEntity(userDb.EntityIUserQuest, new EntityIUserQuest { UserId = userId, QuestId = questId }); ?? AddEntity(userDb.EntityIUserQuest, new EntityIUserQuest { UserId = userDb.UserId, QuestId = questId });
// Initialize quest missions // Initialize quest missions
if (masterQuest is not null && masterQuest.QuestMissionGroupId != 0) if (masterQuest is not null && masterQuest.QuestMissionGroupId != 0)
@@ -449,7 +449,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
.Where(g => g.QuestMissionGroupId == masterQuest.QuestMissionGroupId)) .Where(g => g.QuestMissionGroupId == masterQuest.QuestMissionGroupId))
{ {
if (!userDb.EntityIUserQuestMission.Any(m => m.QuestId == questId && m.QuestMissionId == missionGroupRow.QuestMissionId)) if (!userDb.EntityIUserQuestMission.Any(m => m.QuestId == questId && m.QuestMissionId == missionGroupRow.QuestMissionId))
userDb.EntityIUserQuestMission.Add(new EntityIUserQuestMission { UserId = userId, QuestId = questId, QuestMissionId = missionGroupRow.QuestMissionId }); userDb.EntityIUserQuestMission.Add(new EntityIUserQuestMission { UserId = userDb.UserId, QuestId = questId, QuestMissionId = missionGroupRow.QuestMissionId });
} }
} }
@@ -461,7 +461,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
/// Marks the quest cleared, applies first-clear and drop rewards on success, /// Marks the quest cleared, applies first-clear and drop rewards on success,
/// and clears quest missions. /// and clears quest missions.
/// </summary> /// </summary>
private void HandleBigHuntQuestFinish(DarkUserMemoryDatabase userDb, long userId, int questId, bool isRetired, long nowMs) private void HandleBigHuntQuestFinish(DarkUserMemoryDatabase userDb, int questId, bool isRetired, long nowMs)
{ {
EntityMQuest? masterQuest = _masterDb.EntityMQuest.FirstOrDefault(q => q.QuestId == questId); EntityMQuest? masterQuest = _masterDb.EntityMQuest.FirstOrDefault(q => q.QuestId == questId);
EntityIUserQuest? userQuest = userDb.EntityIUserQuest EntityIUserQuest? userQuest = userDb.EntityIUserQuest
@@ -486,7 +486,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
foreach (EntityMQuestFirstClearRewardGroup reward in _masterDb.EntityMQuestFirstClearRewardGroup foreach (EntityMQuestFirstClearRewardGroup reward in _masterDb.EntityMQuestFirstClearRewardGroup
.Where(r => r.QuestFirstClearRewardGroupId == rewardGroupId)) .Where(r => r.QuestFirstClearRewardGroupId == rewardGroupId))
{ {
PossessionHelper.Apply(userDb, userId, reward.PossessionType, reward.PossessionId, reward.Count, _masterDb); PossessionHelper.Apply(userDb, reward.PossessionType, reward.PossessionId, reward.Count, _masterDb);
} }
} }
@@ -499,7 +499,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
EntityMBattleDropReward? drop = _masterDb.EntityMBattleDropReward EntityMBattleDropReward? drop = _masterDb.EntityMBattleDropReward
.FirstOrDefault(d => d.BattleDropRewardId == pickup.BattleDropRewardId); .FirstOrDefault(d => d.BattleDropRewardId == pickup.BattleDropRewardId);
if (drop != null) if (drop != null)
PossessionHelper.Apply(userDb, userId, drop.PossessionType, drop.PossessionId, drop.Count, _masterDb); PossessionHelper.Apply(userDb, drop.PossessionType, drop.PossessionId, drop.Count, _masterDb);
} }
} }
@@ -519,7 +519,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
.FirstOrDefault(m => m.QuestId == questId && m.QuestMissionId == missionGroupRow.QuestMissionId); .FirstOrDefault(m => m.QuestId == questId && m.QuestMissionId == missionGroupRow.QuestMissionId);
if (userMission is null) if (userMission is null)
{ {
userMission = new EntityIUserQuestMission { UserId = userId, QuestId = questId, QuestMissionId = missionGroupRow.QuestMissionId }; userMission = new EntityIUserQuestMission { UserId = userDb.UserId, QuestId = questId, QuestMissionId = missionGroupRow.QuestMissionId };
userDb.EntityIUserQuestMission.Add(userMission); userDb.EntityIUserQuestMission.Add(userMission);
} }
userMission.IsClear = true; userMission.IsClear = true;
@@ -656,7 +656,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
/// Builds the list of weekly reward items earned across all boss attributes for a given week version, /// Builds the list of weekly reward items earned across all boss attributes for a given week version,
/// based on the player's weekly max scores. /// based on the player's weekly max scores.
/// </summary> /// </summary>
private List<BigHuntReward> ResolveWeeklyRewards(DarkUserMemoryDatabase userDb, long userId, long weeklyVersion, long nowMs) private List<BigHuntReward> ResolveWeeklyRewards(DarkUserMemoryDatabase userDb, long weeklyVersion, long nowMs)
{ {
List<BigHuntReward> rewards = []; List<BigHuntReward> rewards = [];
@@ -669,7 +669,7 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
} }
EntityIUserBigHuntWeeklyMaxScore? ws = userDb.EntityIUserBigHuntWeeklyMaxScore EntityIUserBigHuntWeeklyMaxScore? ws = userDb.EntityIUserBigHuntWeeklyMaxScore
.FirstOrDefault(m => m.UserId == userId .FirstOrDefault(m => m.UserId == userDb.UserId
&& m.BigHuntWeeklyVersion == weeklyVersion && m.BigHuntWeeklyVersion == weeklyVersion
&& m.AttributeType == boss.AttributeType); && m.AttributeType == boss.AttributeType);
@@ -694,23 +694,23 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
/// <summary> /// <summary>
/// Gets or initialises the player's BigHunt in-progress quest status record. /// Gets or initialises the player's BigHunt in-progress quest status record.
/// </summary> /// </summary>
private static EntityIUserBigHuntProgressStatus GetOrCreateProgress(DarkUserMemoryDatabase userDb, long userId) private static EntityIUserBigHuntProgressStatus GetOrCreateProgress(DarkUserMemoryDatabase userDb)
{ {
return userDb.EntityIUserBigHuntProgressStatus return userDb.EntityIUserBigHuntProgressStatus
.FirstOrDefault(p => p.UserId == userId) .FirstOrDefault(p => p.UserId == userDb.UserId)
?? AddEntity(userDb.EntityIUserBigHuntProgressStatus, new EntityIUserBigHuntProgressStatus { UserId = userId }); ?? AddEntity(userDb.EntityIUserBigHuntProgressStatus, new EntityIUserBigHuntProgressStatus { UserId = userDb.UserId });
} }
/// <summary> /// <summary>
/// Gets or initialises the player's per-boss-quest challenge status record. /// Gets or initialises the player's per-boss-quest challenge status record.
/// </summary> /// </summary>
private static EntityIUserBigHuntStatus GetOrCreateStatus(DarkUserMemoryDatabase userDb, long userId, int bossQuestId) private static EntityIUserBigHuntStatus GetOrCreateStatus(DarkUserMemoryDatabase userDb, int bossQuestId)
{ {
return userDb.EntityIUserBigHuntStatus return userDb.EntityIUserBigHuntStatus
.FirstOrDefault(s => s.BigHuntBossQuestId == bossQuestId) .FirstOrDefault(s => s.BigHuntBossQuestId == bossQuestId)
?? AddEntity(userDb.EntityIUserBigHuntStatus, new EntityIUserBigHuntStatus ?? AddEntity(userDb.EntityIUserBigHuntStatus, new EntityIUserBigHuntStatus
{ {
UserId = userId, UserId = userDb.UserId,
BigHuntBossQuestId = bossQuestId BigHuntBossQuestId = bossQuestId
}); });
} }
@@ -718,11 +718,11 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
/// <summary> /// <summary>
/// Gets or initialises the player's server-side battle session record. /// Gets or initialises the player's server-side battle session record.
/// </summary> /// </summary>
private static EntitySBigHuntSession GetOrCreateSession(DarkUserMemoryDatabase userDb, long userId) private static EntitySBigHuntSession GetOrCreateSession(DarkUserMemoryDatabase userDb)
{ {
return userDb.EntitySBigHuntSession return userDb.EntitySBigHuntSession
.FirstOrDefault(s => s.UserId == userId) .FirstOrDefault(s => s.UserId == userDb.UserId)
?? AddEntity(userDb.EntitySBigHuntSession, new EntitySBigHuntSession { UserId = userId }); ?? AddEntity(userDb.EntitySBigHuntSession, new EntitySBigHuntSession { UserId = userDb.UserId });
} }
/// <summary> /// <summary>
@@ -741,9 +741,9 @@ public class BigHuntService(UserDataStore store, DarkMasterMemoryDatabase master
/// <summary> /// <summary>
/// Routes possession grants through PossessionHelper.Apply for consistent handling. /// Routes possession grants through PossessionHelper.Apply for consistent handling.
/// </summary> /// </summary>
private void GrantPossessionViaPossessionHelper(DarkUserMemoryDatabase userDb, long userId, PossessionType possessionType, int possessionId, int count) private void GrantPossessionViaPossessionHelper(DarkUserMemoryDatabase userDb, PossessionType possessionType, int possessionId, int count)
{ {
PossessionHelper.Apply(userDb, userId, possessionType, possessionId, count, _masterDb); PossessionHelper.Apply(userDb, possessionType, possessionId, count, _masterDb);
} }
// ────────── Time helpers ────────── // ────────── Time helpers ──────────

View File

@@ -53,7 +53,7 @@ public class CageOrnamentService(UserDataStore store, DarkMasterMemoryDatabase m
}); });
} }
PossessionHelper.Apply(userDb, userId, reward.PossessionType, reward.PossessionId, reward.Count, _masterDb); PossessionHelper.Apply(userDb, reward.PossessionType, reward.PossessionId, reward.Count, _masterDb);
ReceiveRewardResponse response = new(); ReceiveRewardResponse response = new();
response.CageOrnamentReward.Add(new CageOrnamentReward response.CageOrnamentReward.Add(new CageOrnamentReward

View File

@@ -37,8 +37,8 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
} }
ConsumeCosts(userDb, panel); ConsumeCosts(userDb, panel);
SetReleaseBit(userDb, userId, panel); SetReleaseBit(userDb, panel);
ApplyEffects(userDb, userId, panel); ApplyEffects(userDb, panel);
} }
return Task.FromResult(new ReleasePanelResponse()); return Task.FromResult(new ReleasePanelResponse());
@@ -129,7 +129,7 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
} }
/// <summary>Sets the release bit for a panel on the user's character board, using bitfield-packed storage (32 panels per field).</summary> /// <summary>Sets the release bit for a panel on the user's character board, using bitfield-packed storage (32 panels per field).</summary>
private static void SetReleaseBit(DarkUserMemoryDatabase userDb, long userId, EntityMCharacterBoardPanel panel) private static void SetReleaseBit(DarkUserMemoryDatabase userDb, EntityMCharacterBoardPanel panel)
{ {
int boardId = panel.CharacterBoardId; int boardId = panel.CharacterBoardId;
@@ -147,7 +147,7 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
{ {
board = new EntityIUserCharacterBoard board = new EntityIUserCharacterBoard
{ {
UserId = userId, UserId = userDb.UserId,
CharacterBoardId = boardId CharacterBoardId = boardId
}; };
userDb.EntityIUserCharacterBoard.Add(board); userDb.EntityIUserCharacterBoard.Add(board);
@@ -175,7 +175,7 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
} }
/// <summary>Applies the panel's release effects (ability unlocks or stat boosts) to the character.</summary> /// <summary>Applies the panel's release effects (ability unlocks or stat boosts) to the character.</summary>
private void ApplyEffects(DarkUserMemoryDatabase userDb, long userId, EntityMCharacterBoardPanel panel) private void ApplyEffects(DarkUserMemoryDatabase userDb, EntityMCharacterBoardPanel panel)
{ {
foreach (EntityMCharacterBoardPanelReleaseEffectGroup eff in _masterDb.EntityMCharacterBoardPanelReleaseEffectGroup) foreach (EntityMCharacterBoardPanelReleaseEffectGroup eff in _masterDb.EntityMCharacterBoardPanelReleaseEffectGroup)
{ {
@@ -187,17 +187,17 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
switch (eff.CharacterBoardEffectType) switch (eff.CharacterBoardEffectType)
{ {
case CharacterBoardEffectType.ABILITY: case CharacterBoardEffectType.ABILITY:
ApplyAbilityEffect(userDb, userId, eff); ApplyAbilityEffect(userDb, eff);
break; break;
case CharacterBoardEffectType.STATUS_UP: case CharacterBoardEffectType.STATUS_UP:
ApplyStatusUpEffect(userDb, userId, eff); ApplyStatusUpEffect(userDb, eff);
break; break;
} }
} }
} }
/// <summary>Grants or levels up a character ability from a board panel release, capped by the master-defined max level.</summary> /// <summary>Grants or levels up a character ability from a board panel release, capped by the master-defined max level.</summary>
private void ApplyAbilityEffect(DarkUserMemoryDatabase userDb, long userId, EntityMCharacterBoardPanelReleaseEffectGroup eff) private void ApplyAbilityEffect(DarkUserMemoryDatabase userDb, EntityMCharacterBoardPanelReleaseEffectGroup eff)
{ {
EntityMCharacterBoardAbility? ability = null; EntityMCharacterBoardAbility? ability = null;
foreach (EntityMCharacterBoardAbility a in _masterDb.EntityMCharacterBoardAbility) foreach (EntityMCharacterBoardAbility a in _masterDb.EntityMCharacterBoardAbility)
@@ -235,7 +235,7 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
{ {
state = new EntityIUserCharacterBoardAbility state = new EntityIUserCharacterBoardAbility
{ {
UserId = userId, UserId = userDb.UserId,
CharacterId = characterId, CharacterId = characterId,
AbilityId = ability.AbilityId, AbilityId = ability.AbilityId,
Level = 0 Level = 0
@@ -260,7 +260,7 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
} }
/// <summary>Applies a stat increase (HP, ATK, AGI, VIT, CRIT) to a character from a board panel release.</summary> /// <summary>Applies a stat increase (HP, ATK, AGI, VIT, CRIT) to a character from a board panel release.</summary>
private void ApplyStatusUpEffect(DarkUserMemoryDatabase userDb, long userId, EntityMCharacterBoardPanelReleaseEffectGroup eff) private void ApplyStatusUpEffect(DarkUserMemoryDatabase userDb, EntityMCharacterBoardPanelReleaseEffectGroup eff)
{ {
EntityMCharacterBoardStatusUp? statusUp = null; EntityMCharacterBoardStatusUp? statusUp = null;
foreach (EntityMCharacterBoardStatusUp s in _masterDb.EntityMCharacterBoardStatusUp) foreach (EntityMCharacterBoardStatusUp s in _masterDb.EntityMCharacterBoardStatusUp)
@@ -300,7 +300,7 @@ public class CharacterBoardService(DarkMasterMemoryDatabase masterDb, UserDataSt
{ {
state = new EntityIUserCharacterBoardStatusUp state = new EntityIUserCharacterBoardStatusUp
{ {
UserId = userId, UserId = userDb.UserId,
CharacterId = characterId, CharacterId = characterId,
StatusCalculationType = calcType StatusCalculationType = calcType
}; };

View File

@@ -70,14 +70,14 @@ public class ConsumableItemService(DarkMasterMemoryDatabase masterDb, UserDataSt
if (totalGold > 0) if (totalGold > 0)
{ {
AddGold(userDb, userId, totalGold); AddGold(userDb, totalGold);
} }
return Task.FromResult(new SellResponse()); return Task.FromResult(new SellResponse());
} }
/// <summary>Adds gold (consumable item ID 1) to the user's inventory, creating the entry if needed.</summary> /// <summary>Adds gold (consumable item ID 1) to the user's inventory, creating the entry if needed.</summary>
private void AddGold(DarkUserMemoryDatabase userDb, long userId, int amount) private void AddGold(DarkUserMemoryDatabase userDb, int amount)
{ {
foreach (EntityIUserConsumableItem ci in userDb.EntityIUserConsumableItem) foreach (EntityIUserConsumableItem ci in userDb.EntityIUserConsumableItem)
{ {
@@ -90,7 +90,7 @@ public class ConsumableItemService(DarkMasterMemoryDatabase masterDb, UserDataSt
userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem
{ {
UserId = userId, UserId = userDb.UserId,
ConsumableItemId = _gameConfig.ConsumableItemIdForGold, ConsumableItemId = _gameConfig.ConsumableItemIdForGold,
Count = amount, Count = amount,
FirstAcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() FirstAcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()

View File

@@ -461,12 +461,12 @@ public class CostumeService(DarkMasterMemoryDatabase masterDb, UserDataStore sto
switch (effect.CostumeAwakenEffectType) switch (effect.CostumeAwakenEffectType)
{ {
case CostumeAwakenEffectType.STATUS_UP: case CostumeAwakenEffectType.STATUS_UP:
ApplyAwakenStatusUp(userDb, userId, request.UserCostumeUuid, effect.CostumeAwakenEffectId); ApplyAwakenStatusUp(userDb, request.UserCostumeUuid, effect.CostumeAwakenEffectId);
break; break;
case CostumeAwakenEffectType.ABILITY: case CostumeAwakenEffectType.ABILITY:
break; break;
case CostumeAwakenEffectType.ITEM_ACQUIRE: case CostumeAwakenEffectType.ITEM_ACQUIRE:
ApplyAwakenItemAcquire(userDb, userId, effect.CostumeAwakenEffectId); ApplyAwakenItemAcquire(userDb, effect.CostumeAwakenEffectId);
break; break;
} }
} }
@@ -668,7 +668,7 @@ public class CostumeService(DarkMasterMemoryDatabase masterDb, UserDataStore sto
/// <summary> /// <summary>
/// Applies awakening stat bonuses (HP, ATK, VIT, AGI, CRIT, etc.) to the costume's awaken status record. /// Applies awakening stat bonuses (HP, ATK, VIT, AGI, CRIT, etc.) to the costume's awaken status record.
/// </summary> /// </summary>
private void ApplyAwakenStatusUp(DarkUserMemoryDatabase userDb, long userId, string userCostumeUuid, int statusUpGroupId) private void ApplyAwakenStatusUp(DarkUserMemoryDatabase userDb, string userCostumeUuid, int statusUpGroupId)
{ {
foreach (EntityMCostumeAwakenStatusUpGroup row in _masterDb.EntityMCostumeAwakenStatusUpGroup) foreach (EntityMCostumeAwakenStatusUpGroup row in _masterDb.EntityMCostumeAwakenStatusUpGroup)
{ {
@@ -691,7 +691,7 @@ public class CostumeService(DarkMasterMemoryDatabase masterDb, UserDataStore sto
{ {
state = new EntityIUserCostumeAwakenStatusUp state = new EntityIUserCostumeAwakenStatusUp
{ {
UserId = userId, UserId = userDb.UserId,
UserCostumeUuid = userCostumeUuid, UserCostumeUuid = userCostumeUuid,
StatusCalculationType = row.StatusCalculationType, StatusCalculationType = row.StatusCalculationType,
}; };
@@ -728,7 +728,7 @@ public class CostumeService(DarkMasterMemoryDatabase masterDb, UserDataStore sto
/// <summary> /// <summary>
/// Grants a thought item as an awakening reward, creating a new inventory entry if not already owned. /// Grants a thought item as an awakening reward, creating a new inventory entry if not already owned.
/// </summary> /// </summary>
private void ApplyAwakenItemAcquire(DarkUserMemoryDatabase userDb, long userId, int itemAcquireId) private void ApplyAwakenItemAcquire(DarkUserMemoryDatabase userDb, int itemAcquireId)
{ {
EntityMCostumeAwakenItemAcquire? acq = null; EntityMCostumeAwakenItemAcquire? acq = null;
foreach (EntityMCostumeAwakenItemAcquire a in _masterDb.EntityMCostumeAwakenItemAcquire) foreach (EntityMCostumeAwakenItemAcquire a in _masterDb.EntityMCostumeAwakenItemAcquire)
@@ -756,7 +756,7 @@ public class CostumeService(DarkMasterMemoryDatabase masterDb, UserDataStore sto
userDb.EntityIUserThought.Add(new EntityIUserThought userDb.EntityIUserThought.Add(new EntityIUserThought
{ {
UserId = userId, UserId = userDb.UserId,
UserThoughtUuid = uuid, UserThoughtUuid = uuid,
ThoughtId = acq.PossessionId, ThoughtId = acq.PossessionId,
AcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), AcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),

View File

@@ -34,14 +34,14 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
if (request.Deck != null) if (request.Deck != null)
{ {
ApplyDeckReplacement(userDb, userId, (DeckType)request.DeckType, request.UserDeckNumber, request.Deck); ApplyDeckReplacement(userDb, (DeckType)request.DeckType, request.UserDeckNumber, request.Deck);
} }
return Task.FromResult(new ReplaceDeckResponse()); return Task.FromResult(new ReplaceDeckResponse());
} }
/// <summary>Creates a deck character record from a DeckCharacter slot proto and returns the new UUID.</summary> /// <summary>Creates a deck character record from a DeckCharacter slot proto and returns the new UUID.</summary>
private static string CreateDeckCharacter(DarkUserMemoryDatabase db, long userId, DeckCharacter? slot) private static string CreateDeckCharacter(DarkUserMemoryDatabase db, DeckCharacter? slot)
{ {
if (slot is null || string.IsNullOrEmpty(slot.UserCostumeUuid)) if (slot is null || string.IsNullOrEmpty(slot.UserCostumeUuid))
{ {
@@ -51,7 +51,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
string newUuid = Guid.NewGuid().ToString(); string newUuid = Guid.NewGuid().ToString();
db.EntityIUserDeckCharacter.Add(new EntityIUserDeckCharacter db.EntityIUserDeckCharacter.Add(new EntityIUserDeckCharacter
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
UserCostumeUuid = slot.UserCostumeUuid, UserCostumeUuid = slot.UserCostumeUuid,
MainUserWeaponUuid = slot.MainUserWeaponUuid, MainUserWeaponUuid = slot.MainUserWeaponUuid,
@@ -64,7 +64,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
{ {
db.EntityIUserDeckCharacterDressupCostume.Add(new EntityIUserDeckCharacterDressupCostume db.EntityIUserDeckCharacterDressupCostume.Add(new EntityIUserDeckCharacterDressupCostume
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
DressupCostumeId = slot.DressupCostumeId DressupCostumeId = slot.DressupCostumeId
}); });
@@ -75,7 +75,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
if (string.IsNullOrEmpty(slot.UserPartsUuid[i])) { continue; } if (string.IsNullOrEmpty(slot.UserPartsUuid[i])) { continue; }
db.EntityIUserDeckPartsGroup.Add(new EntityIUserDeckPartsGroup db.EntityIUserDeckPartsGroup.Add(new EntityIUserDeckPartsGroup
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
UserPartsUuid = slot.UserPartsUuid[i], UserPartsUuid = slot.UserPartsUuid[i],
SortOrder = i + 1 SortOrder = i + 1
@@ -87,7 +87,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
if (string.IsNullOrEmpty(slot.SubUserWeaponUuid[i])) { continue; } if (string.IsNullOrEmpty(slot.SubUserWeaponUuid[i])) { continue; }
db.EntityIUserDeckSubWeaponGroup.Add(new EntityIUserDeckSubWeaponGroup db.EntityIUserDeckSubWeaponGroup.Add(new EntityIUserDeckSubWeaponGroup
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
UserWeaponUuid = slot.SubUserWeaponUuid[i], UserWeaponUuid = slot.SubUserWeaponUuid[i],
SortOrder = i + 1 SortOrder = i + 1
@@ -123,7 +123,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
if (request.DeckPower != null) if (request.DeckPower != null)
{ {
ApplyDeckPowerRefresh(userDb, userId, (DeckType)request.DeckType, request.UserDeckNumber, request.DeckPower); ApplyDeckPowerRefresh(userDb, (DeckType)request.DeckType, request.UserDeckNumber, request.DeckPower);
} }
return Task.FromResult(new RefreshDeckPowerResponse()); return Task.FromResult(new RefreshDeckPowerResponse());
@@ -148,7 +148,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
continue; continue;
} }
ApplyDeckReplacement(userDb, userId, (DeckType)detail.DeckType, detail.UserDeckNumber, detail.Deck); ApplyDeckReplacement(userDb, (DeckType)detail.DeckType, detail.UserDeckNumber, detail.Deck);
} }
return Task.FromResult(new ReplaceTripleDeckResponse()); return Task.FromResult(new ReplaceTripleDeckResponse());
@@ -167,7 +167,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
continue; continue;
} }
ApplyDeckReplacement(userDb, userId, (DeckType)detail.DeckType, detail.UserDeckNumber, detail.Deck); ApplyDeckReplacement(userDb, (DeckType)detail.DeckType, detail.UserDeckNumber, detail.Deck);
} }
return Task.FromResult(new ReplaceMultiDeckResponse()); return Task.FromResult(new ReplaceMultiDeckResponse());
@@ -186,14 +186,14 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
continue; continue;
} }
ApplyDeckPowerRefresh(userDb, userId, (DeckType)info.DeckType, info.UserDeckNumber, info.DeckPower); ApplyDeckPowerRefresh(userDb, (DeckType)info.DeckType, info.UserDeckNumber, info.DeckPower);
} }
return Task.FromResult(new RefreshMultiDeckPowerResponse()); return Task.FromResult(new RefreshMultiDeckPowerResponse());
} }
/// <summary>Removes old deck characters and creates new ones from the provided deck proto.</summary> /// <summary>Removes old deck characters and creates new ones from the provided deck proto.</summary>
private static void ApplyDeckReplacement(DarkUserMemoryDatabase userDb, long userId, DeckType deckType, int deckNumber, Deck deck) private static void ApplyDeckReplacement(DarkUserMemoryDatabase userDb, DeckType deckType, int deckNumber, Deck deck)
{ {
EntityIUserDeck? existing = userDb.EntityIUserDeck EntityIUserDeck? existing = userDb.EntityIUserDeck
.FirstOrDefault(d => d.DeckType == deckType && d.UserDeckNumber == deckNumber); .FirstOrDefault(d => d.DeckType == deckType && d.UserDeckNumber == deckNumber);
@@ -210,15 +210,15 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
userDb.EntityIUserDeckSubWeaponGroup.RemoveAll(swg => oldUuids.Contains(swg.UserDeckCharacterUuid)); userDb.EntityIUserDeckSubWeaponGroup.RemoveAll(swg => oldUuids.Contains(swg.UserDeckCharacterUuid));
} }
string uuid01 = CreateDeckCharacter(userDb, userId, deck.Character01); string uuid01 = CreateDeckCharacter(userDb, deck.Character01);
string uuid02 = CreateDeckCharacter(userDb, userId, deck.Character02); string uuid02 = CreateDeckCharacter(userDb, deck.Character02);
string uuid03 = CreateDeckCharacter(userDb, userId, deck.Character03); string uuid03 = CreateDeckCharacter(userDb, deck.Character03);
if (existing == null) if (existing == null)
{ {
existing = new EntityIUserDeck existing = new EntityIUserDeck
{ {
UserId = userId, UserId = userDb.UserId,
DeckType = deckType, DeckType = deckType,
UserDeckNumber = deckNumber, UserDeckNumber = deckNumber,
Name = $"Loadout {deckNumber}", Name = $"Loadout {deckNumber}",
@@ -233,7 +233,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
} }
/// <summary>Updates deck and character power values and tracks max deck power per type.</summary> /// <summary>Updates deck and character power values and tracks max deck power per type.</summary>
private static void ApplyDeckPowerRefresh(DarkUserMemoryDatabase userDb, long userId, DeckType deckType, int deckNumber, DeckPower deckPower) private static void ApplyDeckPowerRefresh(DarkUserMemoryDatabase userDb, DeckType deckType, int deckNumber, DeckPower deckPower)
{ {
EntityIUserDeck? deck = userDb.EntityIUserDeck.FirstOrDefault(d => EntityIUserDeck? deck = userDb.EntityIUserDeck.FirstOrDefault(d =>
d.DeckType == deckType && d.UserDeckNumber == deckNumber); d.DeckType == deckType && d.UserDeckNumber == deckNumber);
@@ -271,7 +271,7 @@ public class DeckService(UserDataStore store) : MariesWonderland.Proto.Deck.Deck
if (note == null) if (note == null)
{ {
note = new EntityIUserDeckTypeNote { UserId = userId, DeckType = deckType }; note = new EntityIUserDeckTypeNote { UserId = userDb.UserId, DeckType = deckType };
userDb.EntityIUserDeckTypeNote.Add(note); userDb.EntityIUserDeckTypeNote.Add(note);
} }

View File

@@ -67,7 +67,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
int conversionRate = entry.Medal.ConversionRate > 0 ? entry.Medal.ConversionRate : 1; int conversionRate = entry.Medal.ConversionRate > 0 ? entry.Medal.ConversionRate : 1;
int bookmarkCount = bs.MedalCount * conversionRate; int bookmarkCount = bs.MedalCount * conversionRate;
PossessionHelper.Apply(userDb, userId, PossessionType.CONSUMABLE_ITEM, entry.Medal.ConsumableItemId, bookmarkCount, _masterDb); PossessionHelper.Apply(userDb, PossessionType.CONSUMABLE_ITEM, entry.Medal.ConsumableItemId, bookmarkCount, _masterDb);
convertedMedal.ConvertedMedalPossession.Add(new ConsumableItemPossession convertedMedal.ConvertedMedalPossession.Add(new ConsumableItemPossession
{ {
@@ -162,7 +162,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
} }
// Find or create banner state // Find or create banner state
EntitySGachaBannerState bannerState = GetOrCreateBannerState(userDb, userId, entry.GachaId); EntitySGachaBannerState bannerState = GetOrCreateBannerState(userDb, entry.GachaId);
// Draw items based on label type // Draw items based on label type
List<DrawnItem> drawnItems; List<DrawnItem> drawnItems;
@@ -221,7 +221,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
if (isMaterialDraw) if (isMaterialDraw)
{ {
// Material draws: grant material and build simple result // Material draws: grant material and build simple result
PossessionHelper.Apply(userDb, userId, (PossessionType)item.PossessionType, item.PossessionId, 1, _masterDb); PossessionHelper.Apply(userDb, (PossessionType)item.PossessionType, item.PossessionId, 1, _masterDb);
bool isNew = !IsOwnedByType(item.PossessionType, item.PossessionId, ownedCostumeIds, ownedWeaponIds, userDb); bool isNew = !IsOwnedByType(item.PossessionType, item.PossessionId, ownedCostumeIds, ownedWeaponIds, userDb);
gachaResults.Add(new DrawGachaOddsItem gachaResults.Add(new DrawGachaOddsItem
@@ -259,14 +259,14 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
} }
else else
{ {
PossessionHelper.GrantCostume(userDb, userId, item.PossessionId, _masterDb); PossessionHelper.GrantCostume(userDb, item.PossessionId, _masterDb);
ownedCostumeIds.Add(item.PossessionId); ownedCostumeIds.Add(item.PossessionId);
// Bonus weapon via costume->weapon pairing map // Bonus weapon via costume->weapon pairing map
GachaItem bonusGachaItem = new(); GachaItem bonusGachaItem = new();
if (costumeWeaponMap.TryGetValue(item.PossessionId, out int pairedWeaponId) && pairedWeaponId > 0) if (costumeWeaponMap.TryGetValue(item.PossessionId, out int pairedWeaponId) && pairedWeaponId > 0)
{ {
WeaponHelper.GrantWeapon(userDb, userId, pairedWeaponId, _masterDb); WeaponHelper.GrantWeapon(userDb, pairedWeaponId, _masterDb);
bonusGachaItem = new GachaItem bonusGachaItem = new GachaItem
{ {
PossessionType = (int)PossessionType.WEAPON, PossessionType = (int)PossessionType.WEAPON,
@@ -294,7 +294,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
{ {
// Weapon // Weapon
bool isNew = !ownedWeaponIds.Contains(item.PossessionId); bool isNew = !ownedWeaponIds.Contains(item.PossessionId);
WeaponHelper.GrantWeapon(userDb, userId, item.PossessionId, _masterDb); WeaponHelper.GrantWeapon(userDb, item.PossessionId, _masterDb);
ownedWeaponIds.Add(item.PossessionId); ownedWeaponIds.Add(item.PossessionId);
gachaResults.Add(new DrawGachaOddsItem gachaResults.Add(new DrawGachaOddsItem
@@ -325,7 +325,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
// Grant medal consumable items (1 per draw) // Grant medal consumable items (1 per draw)
if (entry.Medal != null && medalBonus > 0) if (entry.Medal != null && medalBonus > 0)
{ {
PossessionHelper.Apply(userDb, userId, PossessionType.CONSUMABLE_ITEM, entry.Medal.ConsumableItemId, medalBonus, _masterDb); PossessionHelper.Apply(userDb, PossessionType.CONSUMABLE_ITEM, entry.Medal.ConsumableItemId, medalBonus, _masterDb);
} }
DrawResponse response = new() DrawResponse response = new()
@@ -361,7 +361,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
return Task.FromResult(new ResetBoxGachaResponse()); return Task.FromResult(new ResetBoxGachaResponse());
} }
EntitySGachaBannerState bannerState = GetOrCreateBannerState(userDb, userId, request.GachaId); EntitySGachaBannerState bannerState = GetOrCreateBannerState(userDb, request.GachaId);
bannerState.BoxDrewCounts = []; bannerState.BoxDrewCounts = [];
bannerState.BoxNumber++; bannerState.BoxNumber++;
@@ -459,7 +459,7 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
{ {
EntityMMaterial mat = materials[Random.Shared.Next(materials.Count)]; EntityMMaterial mat = materials[Random.Shared.Next(materials.Count)];
drawnItems.Add(((int)PossessionType.MATERIAL, mat.MaterialId)); drawnItems.Add(((int)PossessionType.MATERIAL, mat.MaterialId));
PossessionHelper.Apply(userDb, userId, PossessionType.MATERIAL, mat.MaterialId, 1, _masterDb); PossessionHelper.Apply(userDb, PossessionType.MATERIAL, mat.MaterialId, 1, _masterDb);
} }
int newCount = currentCount + drawCount; int newCount = currentCount + drawCount;
@@ -1248,14 +1248,14 @@ public class GachaService(DarkMasterMemoryDatabase masterDb, UserDataStore store
return null; return null;
} }
private static EntitySGachaBannerState GetOrCreateBannerState(DarkUserMemoryDatabase userDb, long userId, int gachaId) private static EntitySGachaBannerState GetOrCreateBannerState(DarkUserMemoryDatabase userDb, int gachaId)
{ {
EntitySGachaBannerState? bs = FindBannerState(userDb, gachaId); EntitySGachaBannerState? bs = FindBannerState(userDb, gachaId);
if (bs != null) return bs; if (bs != null) return bs;
bs = new EntitySGachaBannerState bs = new EntitySGachaBannerState
{ {
UserId = userId, UserId = userDb.UserId,
GachaId = gachaId, GachaId = gachaId,
BoxNumber = 1, BoxNumber = 1,
StepNumber = 1 StepNumber = 1

View File

@@ -83,7 +83,7 @@ public class PartsService(DarkMasterMemoryDatabase masterDb, UserDataStore store
// Award total gold earned from the sale // Award total gold earned from the sale
if (totalGold > 0) if (totalGold > 0)
{ {
AddGold(userDb, userId, totalGold); AddGold(userDb, totalGold);
} }
return Task.FromResult(new SellResponse()); return Task.FromResult(new SellResponse());
@@ -452,7 +452,7 @@ public class PartsService(DarkMasterMemoryDatabase masterDb, UserDataStore store
/// <summary> /// <summary>
/// Credits gold to the user's consumable inventory, creating the inventory entry if one does not yet exist. /// Credits gold to the user's consumable inventory, creating the inventory entry if one does not yet exist.
/// </summary> /// </summary>
private void AddGold(DarkUserMemoryDatabase userDb, long userId, int amount) private void AddGold(DarkUserMemoryDatabase userDb, int amount)
{ {
EntityIUserConsumableItem? gold = null; EntityIUserConsumableItem? gold = null;
foreach (EntityIUserConsumableItem ci in userDb.EntityIUserConsumableItem) foreach (EntityIUserConsumableItem ci in userDb.EntityIUserConsumableItem)
@@ -472,7 +472,7 @@ public class PartsService(DarkMasterMemoryDatabase masterDb, UserDataStore store
{ {
userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem
{ {
UserId = userId, UserId = userDb.UserId,
ConsumableItemId = _gameConfig.ConsumableItemIdForGold, ConsumableItemId = _gameConfig.ConsumableItemIdForGold,
Count = amount, Count = amount,
FirstAcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() FirstAcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()

View File

@@ -66,7 +66,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
EntityIUserPortalCageStatus portalCageStatus = userDb.EntityIUserPortalCageStatus.GetOrCreate(userId); EntityIUserPortalCageStatus portalCageStatus = userDb.EntityIUserPortalCageStatus.GetOrCreate(userId);
portalCageStatus.IsCurrentProgress = false; portalCageStatus.IsCurrentProgress = false;
ApplySceneGrants(userDb, questSceneId, userId); ApplySceneGrants(userDb, questSceneId);
return Task.FromResult(new UpdateMainFlowSceneProgressResponse()); return Task.FromResult(new UpdateMainFlowSceneProgressResponse());
} }
@@ -156,12 +156,12 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
if (IsSceneAhead(questSceneId, progressStatus.HeadQuestSceneId)) if (IsSceneAhead(questSceneId, progressStatus.HeadQuestSceneId))
progressStatus.HeadQuestSceneId = questSceneId; progressStatus.HeadQuestSceneId = questSceneId;
ApplySceneGrants(userDb, questSceneId, userId); ApplySceneGrants(userDb, questSceneId);
EntityMQuestScene? scene = _masterDb.EntityMQuestScene.FirstOrDefault(s => s.QuestSceneId == questSceneId); EntityMQuestScene? scene = _masterDb.EntityMQuestScene.FirstOrDefault(s => s.QuestSceneId == questSceneId);
if (scene != null && scene.QuestResultType == QuestResultType.HALF_RESULT) if (scene != null && scene.QuestResultType == QuestResultType.HALF_RESULT)
{ {
ClearQuestMissions(userDb, scene.QuestId, userId, nowMs); ClearQuestMissions(userDb, scene.QuestId, nowMs);
} }
return Task.FromResult(new UpdateExtraQuestSceneProgressResponse()); return Task.FromResult(new UpdateExtraQuestSceneProgressResponse());
@@ -181,12 +181,12 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
if (IsSceneAhead(questSceneId, progressStatus.HeadQuestSceneId)) if (IsSceneAhead(questSceneId, progressStatus.HeadQuestSceneId))
progressStatus.HeadQuestSceneId = questSceneId; progressStatus.HeadQuestSceneId = questSceneId;
ApplySceneGrants(userDb, questSceneId, userId); ApplySceneGrants(userDb, questSceneId);
EntityMQuestScene? scene = _masterDb.EntityMQuestScene.FirstOrDefault(s => s.QuestSceneId == questSceneId); EntityMQuestScene? scene = _masterDb.EntityMQuestScene.FirstOrDefault(s => s.QuestSceneId == questSceneId);
if (scene != null && scene.QuestResultType == QuestResultType.HALF_RESULT) if (scene != null && scene.QuestResultType == QuestResultType.HALF_RESULT)
{ {
ClearQuestMissions(userDb, scene.QuestId, userId, nowMs); ClearQuestMissions(userDb, scene.QuestId, nowMs);
} }
return Task.FromResult(new UpdateEventQuestSceneProgressResponse()); return Task.FromResult(new UpdateEventQuestSceneProgressResponse());
@@ -505,14 +505,14 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
{ {
if (isFirstClear) if (isFirstClear)
{ {
ApplyExpRewards(userDb, quest, userId, questId); ApplyExpRewards(userDb, quest, questId);
ApplyGoldReward(userDb, quest, userId, nowMs); ApplyGoldReward(userDb, quest, nowMs);
ApplyFirstClearPossessions(userDb, firstClearRewardRows, userId, _masterDb); ApplyFirstClearPossessions(userDb, firstClearRewardRows, _masterDb);
ApplyWeaponStoryUnlocks(userDb, questId, userId); ApplyWeaponStoryUnlocks(userDb, questId);
} }
ApplyDropRewardPossessions(userDb, dropRewards, userId, _masterDb); ApplyDropRewardPossessions(userDb, dropRewards, _masterDb);
ApplyDropRewardPossessions(userDb, replayFlowFirstClearRewards, userId, _masterDb); ApplyDropRewardPossessions(userDb, replayFlowFirstClearRewards, _masterDb);
userQuest.QuestStateType = (int)QuestStateType.CLEARED; userQuest.QuestStateType = (int)QuestStateType.CLEARED;
userQuest.ClearCount++; userQuest.ClearCount++;
@@ -546,7 +546,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
} }
// Mark all missions as cleared (always) // Mark all missions as cleared (always)
ClearQuestMissions(userDb, questId, userId, nowMs); ClearQuestMissions(userDb, questId, nowMs);
// Build response with all reward categories and clean up the server-side quest session // Build response with all reward categories and clean up the server-side quest session
FinishMainQuestResponse response= new() { IsBigWin = isBigWin }; FinishMainQuestResponse response= new() { IsBigWin = isBigWin };
@@ -566,7 +566,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
} }
/// <summary>Applies user, character, and costume EXP from quest completion. Rental quests skip character/costume EXP.</summary> /// <summary>Applies user, character, and costume EXP from quest completion. Rental quests skip character/costume EXP.</summary>
private void ApplyExpRewards(DarkUserMemoryDatabase userDb, EntityMQuest quest, long userId, int questId) private void ApplyExpRewards(DarkUserMemoryDatabase userDb, EntityMQuest quest, int questId)
{ {
// User EXP is always applied regardless of deck. // User EXP is always applied regardless of deck.
EntityIUserStatus? status = userDb.EntityIUserStatus.FirstOrDefault(); EntityIUserStatus? status = userDb.EntityIUserStatus.FirstOrDefault();
@@ -675,7 +675,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
} }
/// <summary>Clears all quest missions for a given quest, creating any missing records.</summary> /// <summary>Clears all quest missions for a given quest, creating any missing records.</summary>
private void ClearQuestMissions(DarkUserMemoryDatabase userDb, int questId, long userId, long nowMs) private void ClearQuestMissions(DarkUserMemoryDatabase userDb, int questId, long nowMs)
{ {
EntityMQuest? quest = _masterDb.EntityMQuest.FirstOrDefault(q => q.QuestId == questId); EntityMQuest? quest = _masterDb.EntityMQuest.FirstOrDefault(q => q.QuestId == questId);
if (quest == null || quest.QuestMissionGroupId == 0) return; if (quest == null || quest.QuestMissionGroupId == 0) return;
@@ -685,7 +685,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
{ {
EntityIUserQuestMission userMission = userDb.EntityIUserQuestMission.GetOrCreate( EntityIUserQuestMission userMission = userDb.EntityIUserQuestMission.GetOrCreate(
m => m.QuestId == questId && m.QuestMissionId == missionGroupRow.QuestMissionId, m => m.QuestId == questId && m.QuestMissionId == missionGroupRow.QuestMissionId,
() => new EntityIUserQuestMission { UserId = userId, QuestId = questId, QuestMissionId = missionGroupRow.QuestMissionId }); () => new EntityIUserQuestMission { UserId = userDb.UserId, QuestId = questId, QuestMissionId = missionGroupRow.QuestMissionId });
userMission.IsClear = true; userMission.IsClear = true;
userMission.ProgressValue = 1; userMission.ProgressValue = 1;
userMission.LatestClearDatetime = nowMs; userMission.LatestClearDatetime = nowMs;
@@ -693,44 +693,44 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
} }
/// <summary>Grants gold (consumable item ID 1) from quest completion.</summary> /// <summary>Grants gold (consumable item ID 1) from quest completion.</summary>
private static void ApplyGoldReward(DarkUserMemoryDatabase userDb, EntityMQuest quest, long userId, long nowMs) private static void ApplyGoldReward(DarkUserMemoryDatabase userDb, EntityMQuest quest, long nowMs)
{ {
if (quest.Gold <= 0) return; if (quest.Gold <= 0) return;
EntityIUserConsumableItem? gold = userDb.EntityIUserConsumableItem.FirstOrDefault(c => c.ConsumableItemId == 1); EntityIUserConsumableItem? gold = userDb.EntityIUserConsumableItem.FirstOrDefault(c => c.ConsumableItemId == 1);
if (gold == null) if (gold == null)
{ {
gold = new EntityIUserConsumableItem { UserId = userId, ConsumableItemId = 1, Count = 0, FirstAcquisitionDatetime = nowMs }; gold = new EntityIUserConsumableItem { UserId = userDb.UserId, ConsumableItemId = 1, Count = 0, FirstAcquisitionDatetime = nowMs };
userDb.EntityIUserConsumableItem.Add(gold); userDb.EntityIUserConsumableItem.Add(gold);
} }
gold.Count += quest.Gold; gold.Count += quest.Gold;
} }
/// <summary>Grants first-clear reward possessions to the user.</summary> /// <summary>Grants first-clear reward possessions to the user.</summary>
private static void ApplyFirstClearPossessions(DarkUserMemoryDatabase userDb, List<EntityMQuestFirstClearRewardGroup> rewardRows, long userId, DarkMasterMemoryDatabase masterDb) private static void ApplyFirstClearPossessions(DarkUserMemoryDatabase userDb, List<EntityMQuestFirstClearRewardGroup> rewardRows, DarkMasterMemoryDatabase masterDb)
{ {
foreach (EntityMQuestFirstClearRewardGroup row in rewardRows) foreach (EntityMQuestFirstClearRewardGroup row in rewardRows)
PossessionHelper.Apply(userDb, userId, row.PossessionType, row.PossessionId, row.Count, masterDb); PossessionHelper.Apply(userDb, row.PossessionType, row.PossessionId, row.Count, masterDb);
} }
/// <summary>Grants scene-based possessions from master data for the given quest scene.</summary> /// <summary>Grants scene-based possessions from master data for the given quest scene.</summary>
private void ApplySceneGrants(DarkUserMemoryDatabase userDb, int questSceneId, long userId) private void ApplySceneGrants(DarkUserMemoryDatabase userDb, int questSceneId)
{ {
List<EntityMUserQuestSceneGrantPossession> grants = [.. _masterDb.EntityMUserQuestSceneGrantPossession List<EntityMUserQuestSceneGrantPossession> grants = [.. _masterDb.EntityMUserQuestSceneGrantPossession
.Where(g => g.QuestSceneId == questSceneId && !g.IsDebug)]; .Where(g => g.QuestSceneId == questSceneId && !g.IsDebug)];
foreach (EntityMUserQuestSceneGrantPossession grant in grants) foreach (EntityMUserQuestSceneGrantPossession grant in grants)
PossessionHelper.Apply(userDb, userId, grant.PossessionType, grant.PossessionId, grant.Count, _masterDb); PossessionHelper.Apply(userDb, grant.PossessionType, grant.PossessionId, grant.Count, _masterDb);
} }
/// <summary>Grants all drop reward possessions from a reward list.</summary> /// <summary>Grants all drop reward possessions from a reward list.</summary>
private static void ApplyDropRewardPossessions(DarkUserMemoryDatabase userDb, List<QuestReward> rewards, long userId, DarkMasterMemoryDatabase masterDb) private static void ApplyDropRewardPossessions(DarkUserMemoryDatabase userDb, List<QuestReward> rewards, DarkMasterMemoryDatabase masterDb)
{ {
foreach (QuestReward reward in rewards) foreach (QuestReward reward in rewards)
PossessionHelper.Apply(userDb, userId, (PossessionType)reward.PossessionType, reward.PossessionId, reward.Count, masterDb); PossessionHelper.Apply(userDb, (PossessionType)reward.PossessionType, reward.PossessionId, reward.Count, masterDb);
} }
/// <summary>Unlocks weapon stories triggered by QUEST_CLEAR. ACQUISITION unlocks are handled by WeaponHelper.GrantWeapon.</summary> /// <summary>Unlocks weapon stories triggered by QUEST_CLEAR. ACQUISITION unlocks are handled by WeaponHelper.GrantWeapon.</summary>
private void ApplyWeaponStoryUnlocks(DarkUserMemoryDatabase userDb, int questId, long userId) private void ApplyWeaponStoryUnlocks(DarkUserMemoryDatabase userDb, int questId)
{ {
IEnumerable<EntityMWeaponStoryReleaseConditionGroup> questClearCondRows = _masterDb.EntityMWeaponStoryReleaseConditionGroup IEnumerable<EntityMWeaponStoryReleaseConditionGroup> questClearCondRows = _masterDb.EntityMWeaponStoryReleaseConditionGroup
.Where(c => c.WeaponStoryReleaseConditionType == WeaponStoryReleaseConditionType.QUEST_CLEAR .Where(c => c.WeaponStoryReleaseConditionType == WeaponStoryReleaseConditionType.QUEST_CLEAR
@@ -740,7 +740,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
EntityMWeapon? masterWeapon = _masterDb.EntityMWeapon EntityMWeapon? masterWeapon = _masterDb.EntityMWeapon
.FirstOrDefault(w => w.WeaponStoryReleaseConditionGroupId == condRow.WeaponStoryReleaseConditionGroupId); .FirstOrDefault(w => w.WeaponStoryReleaseConditionGroupId == condRow.WeaponStoryReleaseConditionGroupId);
if (masterWeapon != null) if (masterWeapon != null)
WeaponHelper.GrantWeaponStory(userDb, masterWeapon.WeaponId, condRow.StoryIndex, userId); WeaponHelper.GrantWeaponStory(userDb, masterWeapon.WeaponId, condRow.StoryIndex);
} }
} }
@@ -962,13 +962,13 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
{ {
if (isFirstClear) if (isFirstClear)
{ {
ApplyExpRewards(userDb, quest, userId, questId); ApplyExpRewards(userDb, quest, questId);
ApplyGoldReward(userDb, quest, userId, nowMs); ApplyGoldReward(userDb, quest, nowMs);
ApplyFirstClearPossessions(userDb, firstClearRewardRows, userId, _masterDb); ApplyFirstClearPossessions(userDb, firstClearRewardRows, _masterDb);
ApplyWeaponStoryUnlocks(userDb, questId, userId); ApplyWeaponStoryUnlocks(userDb, questId);
} }
ApplyDropRewardPossessions(userDb, dropRewardsExtra, userId, _masterDb); ApplyDropRewardPossessions(userDb, dropRewardsExtra, _masterDb);
userQuest.QuestStateType = (int)QuestStateType.CLEARED; userQuest.QuestStateType = (int)QuestStateType.CLEARED;
userQuest.ClearCount++; userQuest.ClearCount++;
@@ -987,7 +987,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
} }
// Mark all missions as cleared (always) // Mark all missions as cleared (always)
ClearQuestMissions(userDb, questId, userId, nowMs); ClearQuestMissions(userDb, questId, nowMs);
FinishExtraQuestResponse response= new() { IsBigWin = isBigWin }; FinishExtraQuestResponse response= new() { IsBigWin = isBigWin };
response.DropReward.AddRange(dropRewardsExtra); response.DropReward.AddRange(dropRewardsExtra);
@@ -1218,13 +1218,13 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
{ {
if (isFirstClear) if (isFirstClear)
{ {
ApplyExpRewards(userDb, quest, userId, questId); ApplyExpRewards(userDb, quest, questId);
ApplyGoldReward(userDb, quest, userId, nowMs); ApplyGoldReward(userDb, quest, nowMs);
ApplyFirstClearPossessions(userDb, firstClearRewardRows, userId, _masterDb); ApplyFirstClearPossessions(userDb, firstClearRewardRows, _masterDb);
ApplyWeaponStoryUnlocks(userDb, questId, userId); ApplyWeaponStoryUnlocks(userDb, questId);
} }
ApplyDropRewardPossessions(userDb, dropRewardsEvent, userId, _masterDb); ApplyDropRewardPossessions(userDb, dropRewardsEvent, _masterDb);
userQuest.QuestStateType = (int)QuestStateType.CLEARED; userQuest.QuestStateType = (int)QuestStateType.CLEARED;
userQuest.ClearCount++; userQuest.ClearCount++;
@@ -1243,7 +1243,7 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
} }
// Mark all missions as cleared (always) // Mark all missions as cleared (always)
ClearQuestMissions(userDb, questId, userId, nowMs); ClearQuestMissions(userDb, questId, nowMs);
FinishEventQuestResponse response= new() { IsBigWin = isBigWin }; FinishEventQuestResponse response= new() { IsBigWin = isBigWin };
response.DropReward.AddRange(dropRewardsEvent); response.DropReward.AddRange(dropRewardsEvent);
@@ -1335,11 +1335,11 @@ public class QuestService(UserDataStore store, DarkMasterMemoryDatabase masterDb
for (int i = 0; i < request.SkipCount; i++) for (int i = 0; i < request.SkipCount; i++)
{ {
List<QuestReward> iterDrops = BuildDropRewards(quest); List<QuestReward> iterDrops = BuildDropRewards(quest);
ApplyDropRewardPossessions(userDb, iterDrops, userId, _masterDb); ApplyDropRewardPossessions(userDb, iterDrops, _masterDb);
dropRewards.AddRange(iterDrops); dropRewards.AddRange(iterDrops);
ApplyGoldReward(userDb, quest, userId, nowMs); ApplyGoldReward(userDb, quest, nowMs);
ApplyExpRewards(userDb, quest, userId, questId); ApplyExpRewards(userDb, quest, questId);
} }
userQuest.ClearCount += request.SkipCount; userQuest.ClearCount += request.SkipCount;

View File

@@ -73,7 +73,7 @@ public class RewardService(UserDataStore store, DarkMasterMemoryDatabase masterD
List<EntityMBigHuntRewardGroup> items = CollectNewRewards(rewardGroupId, 0, maxScore); List<EntityMBigHuntRewardGroup> items = CollectNewRewards(rewardGroupId, 0, maxScore);
foreach (EntityMBigHuntRewardGroup item in items) foreach (EntityMBigHuntRewardGroup item in items)
{ {
PossessionHelper.Apply(userDb, userId, item.PossessionType, item.PossessionId, item.Count, _masterDb); PossessionHelper.Apply(userDb, item.PossessionType, item.PossessionId, item.Count, _masterDb);
weeklyRewards.Add(new BigHuntReward weeklyRewards.Add(new BigHuntReward
{ {
PossessionType = (int)item.PossessionType, PossessionType = (int)item.PossessionType,

View File

@@ -37,11 +37,11 @@ public class ShopService(UserDataStore store, DarkMasterMemoryDatabase masterDb)
foreach (EntityMShopItemContentPossession content in contents) foreach (EntityMShopItemContentPossession content in contents)
{ {
GrantShopPossession(userDb, userId, content.PossessionType, content.PossessionId, content.Count * qty); GrantShopPossession(userDb, content.PossessionType, content.PossessionId, content.Count * qty);
} }
// Apply side effects (e.g., stamina recovery) // Apply side effects (e.g., stamina recovery)
ApplyContentEffects(userDb, shopItemId, qty, userId, nowMs); ApplyContentEffects(userDb, shopItemId, qty, nowMs);
// Track purchase count // Track purchase count
EntityIUserShopItem? shopItem = userDb.EntityIUserShopItem.FirstOrDefault(s => s.ShopItemId == shopItemId); EntityIUserShopItem? shopItem = userDb.EntityIUserShopItem.FirstOrDefault(s => s.ShopItemId == shopItemId);
@@ -145,10 +145,10 @@ public class ShopService(UserDataStore store, DarkMasterMemoryDatabase masterDb)
foreach (EntityMShopItemContentPossession content in contents) foreach (EntityMShopItemContentPossession content in contents)
{ {
GrantShopPossession(userDb, userId, content.PossessionType, content.PossessionId, content.Count); GrantShopPossession(userDb, content.PossessionType, content.PossessionId, content.Count);
} }
ApplyContentEffects(userDb, request.ShopItemId, 1, userId, nowMs); ApplyContentEffects(userDb, request.ShopItemId, 1, nowMs);
EntityIUserShopItem? shopItem = userDb.EntityIUserShopItem.FirstOrDefault(s => s.ShopItemId == request.ShopItemId); EntityIUserShopItem? shopItem = userDb.EntityIUserShopItem.FirstOrDefault(s => s.ShopItemId == request.ShopItemId);
if (shopItem == null) if (shopItem == null)
@@ -226,7 +226,7 @@ public class ShopService(UserDataStore store, DarkMasterMemoryDatabase masterDb)
/// Grants a shop possession to the user. For costumes already owned, grants duplication /// Grants a shop possession to the user. For costumes already owned, grants duplication
/// exchange items instead. All other types delegate to PossessionHelper.Apply. /// exchange items instead. All other types delegate to PossessionHelper.Apply.
/// </summary> /// </summary>
private void GrantShopPossession(DarkUserMemoryDatabase userDb, long userId, PossessionType possessionType, int possessionId, int count) private void GrantShopPossession(DarkUserMemoryDatabase userDb, PossessionType possessionType, int possessionId, int count)
{ {
if (possessionType is PossessionType.COSTUME or PossessionType.COSTUME_ENHANCED if (possessionType is PossessionType.COSTUME or PossessionType.COSTUME_ENHANCED
&& userDb.EntityIUserCostume.Any(c => c.CostumeId == possessionId)) && userDb.EntityIUserCostume.Any(c => c.CostumeId == possessionId))
@@ -234,21 +234,21 @@ public class ShopService(UserDataStore store, DarkMasterMemoryDatabase masterDb)
foreach (EntityMCostumeDuplicationExchangePossessionGroup exchange in _masterDb.EntityMCostumeDuplicationExchangePossessionGroup foreach (EntityMCostumeDuplicationExchangePossessionGroup exchange in _masterDb.EntityMCostumeDuplicationExchangePossessionGroup
.Where(e => e.CostumeId == possessionId)) .Where(e => e.CostumeId == possessionId))
{ {
PossessionHelper.Apply(userDb, userId, exchange.PossessionType, exchange.PossessionId, exchange.Count * count, _masterDb); PossessionHelper.Apply(userDb, exchange.PossessionType, exchange.PossessionId, exchange.Count * count, _masterDb);
} }
return; return;
} }
PossessionHelper.Apply(userDb, userId, possessionType, possessionId, count, _masterDb); PossessionHelper.Apply(userDb, possessionType, possessionId, count, _masterDb);
} }
/// <summary>Applies side-effect content(e.g., stamina recovery) from a shop item purchase.</summary> /// <summary>Applies side-effect content(e.g., stamina recovery) from a shop item purchase.</summary>
private void ApplyContentEffects(DarkUserMemoryDatabase userDb, int shopItemId, int qty, long userId, long nowMs) private void ApplyContentEffects(DarkUserMemoryDatabase userDb, int shopItemId, int qty, long nowMs)
{ {
List<EntityMShopItemContentEffect> effects = [.. _masterDb.EntityMShopItemContentEffect List<EntityMShopItemContentEffect> effects = [.. _masterDb.EntityMShopItemContentEffect
.Where(e => e.ShopItemId == shopItemId)]; .Where(e => e.ShopItemId == shopItemId)];
EntityIUserStatus? userStatus = userDb.EntityIUserStatus.FirstOrDefault(s => s.UserId == userId); EntityIUserStatus? userStatus = userDb.EntityIUserStatus.FirstOrDefault(s => s.UserId == userDb.UserId);
if (userStatus == null) { return; } if (userStatus == null) { return; }
EntityMUserLevel? levelData = _masterDb.EntityMUserLevel.FirstOrDefault(l => l.UserLevel == userStatus.Level); EntityMUserLevel? levelData = _masterDb.EntityMUserLevel.FirstOrDefault(l => l.UserLevel == userStatus.Level);

View File

@@ -18,15 +18,15 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
DarkUserMemoryDatabase userDb = store.GetOrCreate(userId); DarkUserMemoryDatabase userDb = store.GetOrCreate(userId);
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
UpsertTutorialProgress(userDb, userId, (TutorialType)request.TutorialType, request.ProgressPhase, request.ChoiceId); UpsertTutorialProgress(userDb, (TutorialType)request.TutorialType, request.ProgressPhase, request.ChoiceId);
if (request.TutorialType == (int)TutorialType.MENU_FIRST || if (request.TutorialType == (int)TutorialType.MENU_FIRST ||
request.TutorialType == (int)TutorialType.MENU_SECOND) request.TutorialType == (int)TutorialType.MENU_SECOND)
{ {
CreateStarterDeck(userDb, userId); CreateStarterDeck(userDb);
} }
List<TutorialChoiceReward> rewards = ApplyTutorialRewards(userDb, userId, (TutorialType)request.TutorialType); List<TutorialChoiceReward> rewards = ApplyTutorialRewards(userDb, (TutorialType)request.TutorialType);
SetTutorialProgressResponse response = new(); SetTutorialProgressResponse response = new();
response.TutorialChoiceReward.AddRange(rewards); response.TutorialChoiceReward.AddRange(rewards);
@@ -39,14 +39,14 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
long userId = context.GetUserId(); long userId = context.GetUserId();
DarkUserMemoryDatabase userDb = store.GetOrCreate(userId); DarkUserMemoryDatabase userDb = store.GetOrCreate(userId);
UpsertTutorialProgress(userDb, userId, (TutorialType)request.TutorialType, request.ProgressPhase, choiceId: 0); UpsertTutorialProgress(userDb, (TutorialType)request.TutorialType, request.ProgressPhase, choiceId: 0);
UpsertDeck(userDb, userId, request); UpsertDeck(userDb, request);
return Task.FromResult(new SetTutorialProgressAndReplaceDeckResponse()); return Task.FromResult(new SetTutorialProgressAndReplaceDeckResponse());
} }
/// <summary>Creates or updates a tutorial progress record, advancing to the specified phase.</summary> /// <summary>Creates or updates a tutorial progress record, advancing to the specified phase.</summary>
private static void UpsertTutorialProgress(DarkUserMemoryDatabase db, long userId, TutorialType type, int phase, int choiceId) private static void UpsertTutorialProgress(DarkUserMemoryDatabase db, TutorialType type, int phase, int choiceId)
{ {
EntityIUserTutorialProgress? existing = db.EntityIUserTutorialProgress EntityIUserTutorialProgress? existing = db.EntityIUserTutorialProgress
.FirstOrDefault(t => t.TutorialType == type); .FirstOrDefault(t => t.TutorialType == type);
@@ -55,7 +55,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
{ {
db.EntityIUserTutorialProgress.Add(new EntityIUserTutorialProgress db.EntityIUserTutorialProgress.Add(new EntityIUserTutorialProgress
{ {
UserId = userId, UserId = db.UserId,
TutorialType = type, TutorialType = type,
ProgressPhase = phase, ProgressPhase = phase,
ChoiceId = choiceId ChoiceId = choiceId
@@ -76,7 +76,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
/// owned costume/weapon/companion. Only runs when no deck 1 character slot exists yet. /// owned costume/weapon/companion. Only runs when no deck 1 character slot exists yet.
/// Idempotent: safe to call multiple times. /// Idempotent: safe to call multiple times.
/// </summary> /// </summary>
private static void CreateStarterDeck(DarkUserMemoryDatabase db, long userId) private static void CreateStarterDeck(DarkUserMemoryDatabase db)
{ {
if (db.EntityIUserCostume.Count == 0) if (db.EntityIUserCostume.Count == 0)
{ {
@@ -106,7 +106,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
db.EntityIUserDeckCharacter.Add(new EntityIUserDeckCharacter db.EntityIUserDeckCharacter.Add(new EntityIUserDeckCharacter
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = dcUuid, UserDeckCharacterUuid = dcUuid,
UserCostumeUuid = costumeUuid, UserCostumeUuid = costumeUuid,
MainUserWeaponUuid = weaponUuid, MainUserWeaponUuid = weaponUuid,
@@ -117,9 +117,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
{ {
db.EntityIUserDeck.Add(new EntityIUserDeck db.EntityIUserDeck.Add(new EntityIUserDeck
{ {
UserId = userId, UserId = db.UserId,
DeckType = DeckType.QUEST,
UserDeckNumber = 1,
UserDeckCharacterUuid01 = dcUuid, UserDeckCharacterUuid01 = dcUuid,
Name = "Loadout 1", Name = "Loadout 1",
Power = 0 Power = 0
@@ -137,7 +135,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
{ {
db.EntityIUserDeckTypeNote.Add(new EntityIUserDeckTypeNote db.EntityIUserDeckTypeNote.Add(new EntityIUserDeckTypeNote
{ {
UserId = userId, UserId = db.UserId,
DeckType = DeckType.QUEST, DeckType = DeckType.QUEST,
MaxDeckPower = 0 MaxDeckPower = 0
}); });
@@ -149,7 +147,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
/// Removes existing EntityIUserDeckCharacter records for the deck, creates fresh ones with new /// Removes existing EntityIUserDeckCharacter records for the deck, creates fresh ones with new
/// UUIDs, and updates EntityIUserDeck to reference the newly generated character UUIDs. /// UUIDs, and updates EntityIUserDeck to reference the newly generated character UUIDs.
/// </summary> /// </summary>
private static void UpsertDeck(DarkUserMemoryDatabase db, long userId, SetTutorialProgressAndReplaceDeckRequest request) private static void UpsertDeck(DarkUserMemoryDatabase db, SetTutorialProgressAndReplaceDeckRequest request)
{ {
DeckType deckType = (DeckType)request.DeckType; DeckType deckType = (DeckType)request.DeckType;
@@ -168,15 +166,15 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
db.EntityIUserDeckSubWeaponGroup.RemoveAll(swg => oldUuids.Contains(swg.UserDeckCharacterUuid)); db.EntityIUserDeckSubWeaponGroup.RemoveAll(swg => oldUuids.Contains(swg.UserDeckCharacterUuid));
} }
string uuid01 = CreateDeckCharacter(db, userId, request.Deck?.Character01); string uuid01 = CreateDeckCharacter(db, request.Deck?.Character01);
string uuid02 = CreateDeckCharacter(db, userId, request.Deck?.Character02); string uuid02 = CreateDeckCharacter(db, request.Deck?.Character02);
string uuid03 = CreateDeckCharacter(db, userId, request.Deck?.Character03); string uuid03 = CreateDeckCharacter(db, request.Deck?.Character03);
if (existing is null) if (existing is null)
{ {
db.EntityIUserDeck.Add(new EntityIUserDeck db.EntityIUserDeck.Add(new EntityIUserDeck
{ {
UserId = userId, UserId = db.UserId,
DeckType = deckType, DeckType = deckType,
UserDeckNumber = request.UserDeckNumber, UserDeckNumber = request.UserDeckNumber,
UserDeckCharacterUuid01 = uuid01, UserDeckCharacterUuid01 = uuid01,
@@ -195,7 +193,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
} }
/// <summary>Creates a deck character record from a DeckCharacter slot proto and returns the new UUID.</summary> /// <summary>Creates a deck character record from a DeckCharacter slot proto and returns the new UUID.</summary>
private static string CreateDeckCharacter(DarkUserMemoryDatabase db, long userId, DeckCharacter? slot) private static string CreateDeckCharacter(DarkUserMemoryDatabase db, DeckCharacter? slot)
{ {
if (slot is null || string.IsNullOrEmpty(slot.UserCostumeUuid)) if (slot is null || string.IsNullOrEmpty(slot.UserCostumeUuid))
{ {
@@ -205,7 +203,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
string newUuid = Guid.NewGuid().ToString(); string newUuid = Guid.NewGuid().ToString();
db.EntityIUserDeckCharacter.Add(new EntityIUserDeckCharacter db.EntityIUserDeckCharacter.Add(new EntityIUserDeckCharacter
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
UserCostumeUuid = slot.UserCostumeUuid, UserCostumeUuid = slot.UserCostumeUuid,
MainUserWeaponUuid = slot.MainUserWeaponUuid, MainUserWeaponUuid = slot.MainUserWeaponUuid,
@@ -218,7 +216,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
{ {
db.EntityIUserDeckCharacterDressupCostume.Add(new EntityIUserDeckCharacterDressupCostume db.EntityIUserDeckCharacterDressupCostume.Add(new EntityIUserDeckCharacterDressupCostume
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
DressupCostumeId = slot.DressupCostumeId DressupCostumeId = slot.DressupCostumeId
}); });
@@ -229,7 +227,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
if (string.IsNullOrEmpty(slot.UserPartsUuid[i])) { continue; } if (string.IsNullOrEmpty(slot.UserPartsUuid[i])) { continue; }
db.EntityIUserDeckPartsGroup.Add(new EntityIUserDeckPartsGroup db.EntityIUserDeckPartsGroup.Add(new EntityIUserDeckPartsGroup
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
UserPartsUuid = slot.UserPartsUuid[i], UserPartsUuid = slot.UserPartsUuid[i],
SortOrder = i + 1 SortOrder = i + 1
@@ -241,7 +239,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
if (string.IsNullOrEmpty(slot.SubUserWeaponUuid[i])) { continue; } if (string.IsNullOrEmpty(slot.SubUserWeaponUuid[i])) { continue; }
db.EntityIUserDeckSubWeaponGroup.Add(new EntityIUserDeckSubWeaponGroup db.EntityIUserDeckSubWeaponGroup.Add(new EntityIUserDeckSubWeaponGroup
{ {
UserId = userId, UserId = db.UserId,
UserDeckCharacterUuid = newUuid, UserDeckCharacterUuid = newUuid,
UserWeaponUuid = slot.SubUserWeaponUuid[i], UserWeaponUuid = slot.SubUserWeaponUuid[i],
SortOrder = i + 1 SortOrder = i + 1
@@ -255,7 +253,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
/// Grants tutorial rewards from master data keyed by tutorial type and returns the reward list /// Grants tutorial rewards from master data keyed by tutorial type and returns the reward list
/// for the response. Each tutorial type may grant companions, gems, items, or other possessions. /// for the response. Each tutorial type may grant companions, gems, items, or other possessions.
/// </summary> /// </summary>
private List<TutorialChoiceReward> ApplyTutorialRewards(DarkUserMemoryDatabase db, long userId, TutorialType tutorialType) private List<TutorialChoiceReward> ApplyTutorialRewards(DarkUserMemoryDatabase db, TutorialType tutorialType)
{ {
List<EntityMTutorialConsumePossessionGroup> rewardRows = [.. masterDb.EntityMTutorialConsumePossessionGroup List<EntityMTutorialConsumePossessionGroup> rewardRows = [.. masterDb.EntityMTutorialConsumePossessionGroup
.Where(r => r.TutorialType == tutorialType)]; .Where(r => r.TutorialType == tutorialType)];
@@ -264,7 +262,7 @@ public class TutorialService(UserDataStore store, DarkMasterMemoryDatabase maste
foreach (EntityMTutorialConsumePossessionGroup row in rewardRows) foreach (EntityMTutorialConsumePossessionGroup row in rewardRows)
{ {
PossessionHelper.Apply(db, userId, row.PossessionType, row.PossessionId, row.Count, masterDb); PossessionHelper.Apply(db, row.PossessionType, row.PossessionId, row.Count, masterDb);
result.Add(new TutorialChoiceReward result.Add(new TutorialChoiceReward
{ {

View File

@@ -53,7 +53,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
{ {
if (exchange.WeaponId == weapon.WeaponId) if (exchange.WeaponId == weapon.WeaponId)
{ {
AddConsumableItem(userDb, userId, exchange.ConsumableItemId, exchange.Count); AddConsumableItem(userDb, exchange.ConsumableItemId, exchange.Count);
} }
} }
@@ -66,7 +66,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
if (totalGold > 0) if (totalGold > 0)
{ {
AddConsumableItem(userDb, userId, _gameConfig.ConsumableItemIdForGold, totalGold); AddConsumableItem(userDb, _gameConfig.ConsumableItemIdForGold, totalGold);
} }
return Task.FromResult(new SellResponse()); return Task.FromResult(new SellResponse());
@@ -186,7 +186,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
weapon.Exp += totalExp; weapon.Exp += totalExp;
ApplyLevelFromExp(weapon, wm); ApplyLevelFromExp(weapon, wm);
CheckWeaponStoryUnlocks(userDb, userId, weapon.WeaponId, weapon.Level); CheckWeaponStoryUnlocks(userDb, weapon.WeaponId, weapon.Level);
return Task.FromResult(new EnhanceByMaterialResponse{ IsGreatSuccess = false }); return Task.FromResult(new EnhanceByMaterialResponse{ IsGreatSuccess = false });
} }
@@ -242,7 +242,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
{ {
if (exchange.WeaponId == matWeapon.WeaponId) if (exchange.WeaponId == matWeapon.WeaponId)
{ {
AddConsumableItem(userDb, userId, exchange.ConsumableItemId, exchange.Count); AddConsumableItem(userDb, exchange.ConsumableItemId, exchange.Count);
} }
} }
@@ -269,7 +269,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
weapon.Exp += totalExp; weapon.Exp += totalExp;
ApplyLevelFromExp(weapon, wm); ApplyLevelFromExp(weapon, wm);
CheckWeaponStoryUnlocks(userDb, userId, weapon.WeaponId, weapon.Level); CheckWeaponStoryUnlocks(userDb, weapon.WeaponId, weapon.Level);
return Task.FromResult(new EnhanceByWeaponResponse{ IsGreatSuccess = false }); return Task.FromResult(new EnhanceByWeaponResponse{ IsGreatSuccess = false });
} }
@@ -533,7 +533,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
weapon.LimitBreakCount += totalMaterialCount; weapon.LimitBreakCount += totalMaterialCount;
// Track the highest limit break count in the weapon note // Track the highest limit break count in the weapon note
UpdateWeaponNote(userDb, userId, weapon); UpdateWeaponNote(userDb, weapon);
return Task.FromResult(new LimitBreakByMaterialResponse()); return Task.FromResult(new LimitBreakByMaterialResponse());
} }
@@ -583,7 +583,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
{ {
if (exchange.WeaponId == matWeapon.WeaponId) if (exchange.WeaponId == matWeapon.WeaponId)
{ {
AddConsumableItem(userDb, userId, exchange.ConsumableItemId, exchange.Count); AddConsumableItem(userDb, exchange.ConsumableItemId, exchange.Count);
} }
} }
@@ -609,7 +609,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
weapon.LimitBreakCount += consumedCount; weapon.LimitBreakCount += consumedCount;
// Track the highest limit break count in the weapon note // Track the highest limit break count in the weapon note
UpdateWeaponNote(userDb, userId, weapon); UpdateWeaponNote(userDb, weapon);
return Task.FromResult(new LimitBreakByWeaponResponse()); return Task.FromResult(new LimitBreakByWeaponResponse());
} }
@@ -712,7 +712,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
} }
// Check if the evolution unlocks new weapon story pages // Check if the evolution unlocks new weapon story pages
CheckWeaponStoryUnlocks(userDb, userId, evolvedId, weapon.Level); CheckWeaponStoryUnlocks(userDb, evolvedId, weapon.Level);
return Task.FromResult(new EvolveResponse()); return Task.FromResult(new EvolveResponse());
} }
@@ -883,7 +883,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
/// <summary> /// <summary>
/// Grants a consumable item to the user, creating the inventory entry if it doesn't exist yet. /// Grants a consumable item to the user, creating the inventory entry if it doesn't exist yet.
/// </summary> /// </summary>
private static void AddConsumableItem(DarkUserMemoryDatabase userDb, long userId, int itemId, int count) private static void AddConsumableItem(DarkUserMemoryDatabase userDb, int itemId, int count)
{ {
foreach (EntityIUserConsumableItem ci in userDb.EntityIUserConsumableItem) foreach (EntityIUserConsumableItem ci in userDb.EntityIUserConsumableItem)
{ {
@@ -896,7 +896,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem userDb.EntityIUserConsumableItem.Add(new EntityIUserConsumableItem
{ {
UserId = userId, UserId = userDb.UserId,
ConsumableItemId = itemId, ConsumableItemId = itemId,
Count = count, Count = count,
FirstAcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() FirstAcquisitionDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
@@ -992,7 +992,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
/// <summary> /// <summary>
/// Updates the weapon note to track the highest limit break count ever achieved for this weapon. /// Updates the weapon note to track the highest limit break count ever achieved for this weapon.
/// </summary> /// </summary>
private static void UpdateWeaponNote(DarkUserMemoryDatabase userDb, long userId, EntityIUserWeapon weapon) private static void UpdateWeaponNote(DarkUserMemoryDatabase userDb, EntityIUserWeapon weapon)
{ {
EntityIUserWeaponNote? note = null; EntityIUserWeaponNote? note = null;
foreach (EntityIUserWeaponNote n in userDb.EntityIUserWeaponNote) foreach (EntityIUserWeaponNote n in userDb.EntityIUserWeaponNote)
@@ -1016,7 +1016,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
/// <summary> /// <summary>
/// Evaluates weapon story release conditions and unlocks story pages when conditions are met (level reached, evolution, acquisition, etc.). /// Evaluates weapon story release conditions and unlocks story pages when conditions are met (level reached, evolution, acquisition, etc.).
/// </summary> /// </summary>
private void CheckWeaponStoryUnlocks(DarkUserMemoryDatabase userDb, long userId, int weaponId, int level) private void CheckWeaponStoryUnlocks(DarkUserMemoryDatabase userDb, int weaponId, int level)
{ {
EntityMWeapon? wm = FindWeaponMaster(weaponId); EntityMWeapon? wm = FindWeaponMaster(weaponId);
if (wm == null || wm.WeaponStoryReleaseConditionGroupId == 0) if (wm == null || wm.WeaponStoryReleaseConditionGroupId == 0)
@@ -1057,7 +1057,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
if (shouldUnlock) if (shouldUnlock)
{ {
GrantWeaponStoryUnlock(userDb, userId, weaponId, cond.StoryIndex); GrantWeaponStoryUnlock(userDb, weaponId, cond.StoryIndex);
} }
} }
} }
@@ -1086,7 +1086,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
/// <summary> /// <summary>
/// Unlocks a weapon story page, creating the story record if new or advancing the max released story index. /// Unlocks a weapon story page, creating the story record if new or advancing the max released story index.
/// </summary> /// </summary>
private static void GrantWeaponStoryUnlock(DarkUserMemoryDatabase userDb, long userId, int weaponId, int storyIndex) private static void GrantWeaponStoryUnlock(DarkUserMemoryDatabase userDb, int weaponId, int storyIndex)
{ {
EntityIUserWeaponStory? existing = null; EntityIUserWeaponStory? existing = null;
foreach (EntityIUserWeaponStory ws in userDb.EntityIUserWeaponStory) foreach (EntityIUserWeaponStory ws in userDb.EntityIUserWeaponStory)
@@ -1109,7 +1109,7 @@ public class WeaponService(DarkMasterMemoryDatabase masterDb, UserDataStore stor
{ {
userDb.EntityIUserWeaponStory.Add(new EntityIUserWeaponStory userDb.EntityIUserWeaponStory.Add(new EntityIUserWeaponStory
{ {
UserId = userId, UserId = userDb.UserId,
WeaponId = weaponId, WeaponId = weaponId,
ReleasedMaxStoryIndex = storyIndex ReleasedMaxStoryIndex = storyIndex
}); });