namespace Ananta.Server.Protocol.Client4229938; /// /// Per-character weapon-skin assignments (spiritId -> weapon sceneItemId -> skinId), held on /// so a re-login replays them (硬规则 2). The donor keeps this in a /// process-wide static that resets on restart; here it rides the same snapshot as the outfit and the /// dye, so dressing a character actually survives. /// /// ⛑⛑ Like the dye, nothing is pushed when the player assigns a skin: the client commits locally on /// err=0 and the state is replayed through the login seed /// (PlayerWeaponSkinInfo.SpiritWeaponSkinDict). /// internal static class WeaponSkinStore { internal static Dictionary GetEquipped(WorldEntryState? state, uint spiritId) { if (state is null) return []; lock (state.SyncRoot) return state.WeaponSkins.TryGetValue(spiritId, out var record) ? new Dictionary(record.SkinBySceneItem) : []; } /// Assigns one skin to every listed weapon of a character. internal static void SetSkin( WorldEntryState state, uint spiritId, IEnumerable sceneItemIds, uint skinId) { lock (state.SyncRoot) { var current = state.WeaponSkins.TryGetValue(spiritId, out var record) ? new Dictionary(record.SkinBySceneItem) : []; foreach (var sceneItemId in sceneItemIds) { if (sceneItemId == 0) continue; current[sceneItemId] = skinId; } state.WeaponSkins[spiritId] = new WeaponSkinRecord4229938(current); } } /// Copies one character's whole skin set onto the target characters ("apply to all"). internal static void SetAll(WorldEntryState state, uint spiritId, Dictionary skinBySceneItem) { lock (state.SyncRoot) state.WeaponSkins[spiritId] = new WeaponSkinRecord4229938(new Dictionary(skinBySceneItem)); } /// Everything worn right now: spiritId -> (sceneItemId -> skinId), for the login seed. internal static Dictionary> Snapshot(WorldEntryState? state) { var result = new Dictionary>(); if (state is null) return result; lock (state.SyncRoot) { foreach (var (spiritId, record) in state.WeaponSkins) { if (spiritId == 0 || record?.SkinBySceneItem is null || record.SkinBySceneItem.Count == 0) continue; result[spiritId] = new Dictionary(record.SkinBySceneItem); } } return result; } }