using LiteDB; namespace Campus_live_rewrite.api.dbs { // What each player has equipped, per equipment prefab. // // The client POSTs /api/equipment/v1/update every time a skin is equipped, sending // the full entry for that prefab: // // [{"PrefabName":"[ShareCamera]","ModificationGuid":"48c97ace-...", // "FriendlyName":"Camping Share Camera","Tooltip":"","Rarity":0, // "ThumbnailImageName":null,"Favorited":true}] // // That route did not exist, so the POST 404'd and the choice lived only in the // running client - at the next login everyone was back on the default skin. // // Stored as a collection inside Players.db rather than its own file, so it rides the // existing checkpoint (DbMaintenance.CheckpointAll) instead of adding another // write-ahead log that never gets merged. public static class EquipmentDB { public class EquippedItem { public string PrefabName { get; set; } = ""; public string ModificationGuid { get; set; } = ""; public string? FriendlyName { get; set; } public string? Tooltip { get; set; } public int Rarity { get; set; } public string? ThumbnailImageName { get; set; } public bool Favorited { get; set; } } public class PlayerEquipment { [BsonId] public ulong PlayerId { get; set; } public List Equipped { get; set; } = new(); } private static readonly ILiteCollection _col = PlayerDB.PlayerDBFile.GetCollection("player_equipment"); public static List Get(ulong playerId) => _col.FindById(playerId)?.Equipped ?? new List(); /// /// Records the state the client just sent, keyed by prefab AND modification guid. /// Returns the player's full loadout afterwards. /// /// Keying by prefab alone loses data. One request carries SEVERAL entries for the /// same prefab - the newly equipped skin, plus the one it replaced so its flag can /// be cleared: /// /// [MakerPen] Professor Maker Pen (the new one) /// [MakerPen] Host 2 Maker Pen (the old one, flag being cleared) /// /// Replacing "all entries for [MakerPen]" therefore kept only whichever happened to /// come LAST in the array - frequently the one being switched OFF - so the skin came /// back unequipped. The client decides which entry is current; our job is to store /// exactly what it told us, per item. /// public static List Update(ulong playerId, IEnumerable? items) { var row = _col.FindById(playerId) ?? new PlayerEquipment { PlayerId = playerId }; if (items == null) return row.Equipped; foreach (var item in items) { if (item == null || string.IsNullOrWhiteSpace(item.PrefabName)) continue; row.Equipped.RemoveAll(e => string.Equals(e.PrefabName, item.PrefabName, StringComparison.OrdinalIgnoreCase) && string.Equals(e.ModificationGuid, item.ModificationGuid, StringComparison.OrdinalIgnoreCase)); row.Equipped.Add(item); } _col.Upsert(row); return row.Equipped; } } }