76 lines
2.8 KiB
C#
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;
|
|
}
|
|
}
|