Files
Ananta-ps/Ananta.Server/Ananta.Core/Protocol/Client4229938/WeaponSkinStore.cs
T

76 lines
2.8 KiB
C#

namespace Ananta.Server.Protocol.Client4229938;
/// <summary>
/// Per-character weapon-skin assignments (spiritId -> weapon sceneItemId -> skinId), held on
/// <see cref="WorldEntryState"/> 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
/// (<c>PlayerWeaponSkinInfo.SpiritWeaponSkinDict</c>).
/// </summary>
internal static class WeaponSkinStore
{
internal static Dictionary<uint, uint> GetEquipped(WorldEntryState? state, uint spiritId)
{
if (state is null)
return [];
lock (state.SyncRoot)
return state.WeaponSkins.TryGetValue(spiritId, out var record)
? new Dictionary<uint, uint>(record.SkinBySceneItem)
: [];
}
/// <summary>Assigns one skin to every listed weapon of a character.</summary>
internal static void SetSkin(
WorldEntryState state, uint spiritId, IEnumerable<uint> sceneItemIds, uint skinId)
{
lock (state.SyncRoot)
{
var current = state.WeaponSkins.TryGetValue(spiritId, out var record)
? new Dictionary<uint, uint>(record.SkinBySceneItem)
: [];
foreach (var sceneItemId in sceneItemIds)
{
if (sceneItemId == 0)
continue;
current[sceneItemId] = skinId;
}
state.WeaponSkins[spiritId] = new WeaponSkinRecord4229938(current);
}
}
/// <summary>Copies one character's whole skin set onto the target characters ("apply to all").</summary>
internal static void SetAll(WorldEntryState state, uint spiritId, Dictionary<uint, uint> skinBySceneItem)
{
lock (state.SyncRoot)
state.WeaponSkins[spiritId] = new WeaponSkinRecord4229938(new Dictionary<uint, uint>(skinBySceneItem));
}
/// <summary>Everything worn right now: spiritId -> (sceneItemId -> skinId), for the login seed.</summary>
internal static Dictionary<uint, Dictionary<uint, uint>> Snapshot(WorldEntryState? state)
{
var result = new Dictionary<uint, Dictionary<uint, uint>>();
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<uint, uint>(record.SkinBySceneItem);
}
}
return result;
}
}