mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-23 00:49:18 +01:00
937 lines
34 KiB
C#
937 lines
34 KiB
C#
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using Penumbra.Collections.Cache;
|
|
using Penumbra.GameData.Files.AtchStructs;
|
|
using Penumbra.GameData.Structs;
|
|
using Penumbra.Util;
|
|
using ImcEntry = Penumbra.GameData.Structs.ImcEntry;
|
|
|
|
namespace Penumbra.Meta.Manipulations;
|
|
|
|
[JsonConverter(typeof(Converter))]
|
|
public class MetaDictionary
|
|
{
|
|
private class Wrapper : HashSet<GlobalEqpManipulation>
|
|
{
|
|
public readonly Dictionary<ImcIdentifier, ImcEntry> Imc = [];
|
|
public readonly Dictionary<EqpIdentifier, EqpEntryInternal> Eqp = [];
|
|
public readonly Dictionary<EqdpIdentifier, EqdpEntryInternal> Eqdp = [];
|
|
public readonly Dictionary<EstIdentifier, EstEntry> Est = [];
|
|
public readonly Dictionary<RspIdentifier, RspEntry> Rsp = [];
|
|
public readonly Dictionary<GmpIdentifier, GmpEntry> Gmp = [];
|
|
public readonly Dictionary<AtchIdentifier, AtchEntry> Atch = [];
|
|
public readonly Dictionary<ShpIdentifier, ShpEntry> Shp = [];
|
|
public readonly Dictionary<AtrIdentifier, AtrEntry> Atr = [];
|
|
|
|
public Wrapper()
|
|
{ }
|
|
|
|
public Wrapper(MetaCache cache)
|
|
{
|
|
Imc = cache.Imc.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
Eqp = cache.Eqp.ToDictionary(kvp => kvp.Key, kvp => new EqpEntryInternal(kvp.Value.Entry, kvp.Key.Slot));
|
|
Eqdp = cache.Eqdp.ToDictionary(kvp => kvp.Key, kvp => new EqdpEntryInternal(kvp.Value.Entry, kvp.Key.Slot));
|
|
Est = cache.Est.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
Gmp = cache.Gmp.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
Rsp = cache.Rsp.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
Atch = cache.Atch.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
Shp = cache.Shp.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
Atr = cache.Atr.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Entry);
|
|
foreach (var geqp in cache.GlobalEqp.Keys)
|
|
Add(geqp);
|
|
}
|
|
}
|
|
|
|
private Wrapper? _data;
|
|
|
|
public IReadOnlyDictionary<ImcIdentifier, ImcEntry> Imc
|
|
=> _data?.Imc ?? [];
|
|
|
|
public IReadOnlyDictionary<EqpIdentifier, EqpEntryInternal> Eqp
|
|
=> _data?.Eqp ?? [];
|
|
|
|
public IReadOnlyDictionary<EqdpIdentifier, EqdpEntryInternal> Eqdp
|
|
=> _data?.Eqdp ?? [];
|
|
|
|
public IReadOnlyDictionary<EstIdentifier, EstEntry> Est
|
|
=> _data?.Est ?? [];
|
|
|
|
public IReadOnlyDictionary<GmpIdentifier, GmpEntry> Gmp
|
|
=> _data?.Gmp ?? [];
|
|
|
|
public IReadOnlyDictionary<RspIdentifier, RspEntry> Rsp
|
|
=> _data?.Rsp ?? [];
|
|
|
|
public IReadOnlyDictionary<AtchIdentifier, AtchEntry> Atch
|
|
=> _data?.Atch ?? [];
|
|
|
|
public IReadOnlyDictionary<ShpIdentifier, ShpEntry> Shp
|
|
=> _data?.Shp ?? [];
|
|
|
|
public IReadOnlyDictionary<AtrIdentifier, AtrEntry> Atr
|
|
=> _data?.Atr ?? [];
|
|
|
|
public IReadOnlySet<GlobalEqpManipulation> GlobalEqp
|
|
=> _data ?? [];
|
|
|
|
public int Count { get; private set; }
|
|
|
|
public int GetCount(MetaManipulationType type)
|
|
=> _data is null
|
|
? 0
|
|
: type switch
|
|
{
|
|
MetaManipulationType.Imc => _data.Imc.Count,
|
|
MetaManipulationType.Eqdp => _data.Eqdp.Count,
|
|
MetaManipulationType.Eqp => _data.Eqp.Count,
|
|
MetaManipulationType.Est => _data.Est.Count,
|
|
MetaManipulationType.Gmp => _data.Gmp.Count,
|
|
MetaManipulationType.Rsp => _data.Rsp.Count,
|
|
MetaManipulationType.Atch => _data.Atch.Count,
|
|
MetaManipulationType.Shp => _data.Shp.Count,
|
|
MetaManipulationType.Atr => _data.Atr.Count,
|
|
MetaManipulationType.GlobalEqp => _data.Count,
|
|
_ => 0,
|
|
};
|
|
|
|
public bool Contains(IMetaIdentifier identifier)
|
|
=> _data is not null
|
|
&& identifier switch
|
|
{
|
|
EqdpIdentifier i => _data.Eqdp.ContainsKey(i),
|
|
EqpIdentifier i => _data.Eqp.ContainsKey(i),
|
|
EstIdentifier i => _data.Est.ContainsKey(i),
|
|
GlobalEqpManipulation i => _data.Contains(i),
|
|
GmpIdentifier i => _data.Gmp.ContainsKey(i),
|
|
ImcIdentifier i => _data.Imc.ContainsKey(i),
|
|
AtchIdentifier i => _data.Atch.ContainsKey(i),
|
|
ShpIdentifier i => _data.Shp.ContainsKey(i),
|
|
AtrIdentifier i => _data.Atr.ContainsKey(i),
|
|
RspIdentifier i => _data.Rsp.ContainsKey(i),
|
|
_ => false,
|
|
};
|
|
|
|
public void Clear()
|
|
{
|
|
_data = null;
|
|
Count = 0;
|
|
}
|
|
|
|
public void ClearForDefault()
|
|
{
|
|
if (_data is null)
|
|
return;
|
|
|
|
if (_data.Count is 0 && Shp.Count is 0 && Atr.Count is 0)
|
|
{
|
|
_data = null;
|
|
Count = 0;
|
|
return;
|
|
}
|
|
|
|
Count = GlobalEqp.Count + Shp.Count + Atr.Count;
|
|
_data!.Imc.Clear();
|
|
_data!.Eqp.Clear();
|
|
_data!.Eqdp.Clear();
|
|
_data!.Est.Clear();
|
|
_data!.Rsp.Clear();
|
|
_data!.Gmp.Clear();
|
|
_data!.Atch.Clear();
|
|
}
|
|
|
|
public bool Equals(MetaDictionary other)
|
|
{
|
|
if (Count != other.Count)
|
|
return false;
|
|
|
|
if (_data is null)
|
|
return true;
|
|
|
|
return _data.Imc.SetEquals(other._data!.Imc)
|
|
&& _data.Eqp.SetEquals(other._data!.Eqp)
|
|
&& _data.Eqdp.SetEquals(other._data!.Eqdp)
|
|
&& _data.Est.SetEquals(other._data!.Est)
|
|
&& _data.Rsp.SetEquals(other._data!.Rsp)
|
|
&& _data.Gmp.SetEquals(other._data!.Gmp)
|
|
&& _data.Atch.SetEquals(other._data!.Atch)
|
|
&& _data.Shp.SetEquals(other._data!.Shp)
|
|
&& _data.Atr.SetEquals(other._data!.Atr)
|
|
&& _data.SetEquals(other._data!);
|
|
}
|
|
|
|
public IEnumerable<IMetaIdentifier> Identifiers
|
|
=> _data is null
|
|
? []
|
|
: _data.Imc.Keys.Cast<IMetaIdentifier>()
|
|
.Concat(_data!.Eqdp.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Eqp.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Est.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Gmp.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Rsp.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Atch.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Shp.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Atr.Keys.Cast<IMetaIdentifier>())
|
|
.Concat(_data!.Cast<IMetaIdentifier>());
|
|
|
|
#region TryAdd
|
|
|
|
public bool TryAdd(ImcIdentifier identifier, ImcEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Imc.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(EqpIdentifier identifier, EqpEntryInternal entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Eqp.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(EqpIdentifier identifier, EqpEntry entry)
|
|
=> TryAdd(identifier, new EqpEntryInternal(entry, identifier.Slot));
|
|
|
|
public bool TryAdd(EqdpIdentifier identifier, EqdpEntryInternal entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Eqdp.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(EqdpIdentifier identifier, EqdpEntry entry)
|
|
=> TryAdd(identifier, new EqdpEntryInternal(entry, identifier.Slot));
|
|
|
|
public bool TryAdd(EstIdentifier identifier, EstEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Est.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(GmpIdentifier identifier, GmpEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Gmp.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(RspIdentifier identifier, RspEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Rsp.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(AtchIdentifier identifier, in AtchEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Atch.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(ShpIdentifier identifier, in ShpEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Shp.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(AtrIdentifier identifier, in AtrEntry entry)
|
|
{
|
|
_data ??= [];
|
|
if (!_data!.Atr.TryAdd(identifier, entry))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
public bool TryAdd(GlobalEqpManipulation identifier)
|
|
{
|
|
_data ??= [];
|
|
if (!_data.Add(identifier))
|
|
return false;
|
|
|
|
++Count;
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Update
|
|
|
|
public bool Update(ImcIdentifier identifier, ImcEntry entry)
|
|
{
|
|
if (_data is null || !_data.Imc.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Imc[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(EqpIdentifier identifier, EqpEntryInternal entry)
|
|
{
|
|
if (_data is null || !_data.Eqp.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Eqp[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(EqpIdentifier identifier, EqpEntry entry)
|
|
=> Update(identifier, new EqpEntryInternal(entry, identifier.Slot));
|
|
|
|
public bool Update(EqdpIdentifier identifier, EqdpEntryInternal entry)
|
|
{
|
|
if (_data is null || !_data.Eqdp.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Eqdp[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(EqdpIdentifier identifier, EqdpEntry entry)
|
|
=> Update(identifier, new EqdpEntryInternal(entry, identifier.Slot));
|
|
|
|
public bool Update(EstIdentifier identifier, EstEntry entry)
|
|
{
|
|
if (_data is null || !_data.Est.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Est[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(GmpIdentifier identifier, GmpEntry entry)
|
|
{
|
|
if (_data is null || !_data.Gmp.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Gmp[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(RspIdentifier identifier, RspEntry entry)
|
|
{
|
|
if (_data is null || !_data.Rsp.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Rsp[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(AtchIdentifier identifier, in AtchEntry entry)
|
|
{
|
|
if (_data is null || !_data.Atch.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Atch[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(ShpIdentifier identifier, in ShpEntry entry)
|
|
{
|
|
if (_data is null || !_data.Shp.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Shp[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
public bool Update(AtrIdentifier identifier, in AtrEntry entry)
|
|
{
|
|
if (_data is null || !_data.Atr.ContainsKey(identifier))
|
|
return false;
|
|
|
|
_data.Atr[identifier] = entry;
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TryGetValue
|
|
|
|
public bool TryGetValue(EstIdentifier identifier, out EstEntry value)
|
|
=> _data?.Est.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(EqpIdentifier identifier, out EqpEntryInternal value)
|
|
=> _data?.Eqp.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(EqdpIdentifier identifier, out EqdpEntryInternal value)
|
|
=> _data?.Eqdp.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(GmpIdentifier identifier, out GmpEntry value)
|
|
=> _data?.Gmp.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(RspIdentifier identifier, out RspEntry value)
|
|
=> _data?.Rsp.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(ImcIdentifier identifier, out ImcEntry value)
|
|
=> _data?.Imc.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(AtchIdentifier identifier, out AtchEntry value)
|
|
=> _data?.Atch.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(ShpIdentifier identifier, out ShpEntry value)
|
|
=> _data?.Shp.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
public bool TryGetValue(AtrIdentifier identifier, out AtrEntry value)
|
|
=> _data?.Atr.TryGetValue(identifier, out value) ?? SetDefault(out value);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
|
private static bool SetDefault<T>(out T? value)
|
|
{
|
|
value = default;
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public bool Remove(IMetaIdentifier identifier)
|
|
{
|
|
if (_data is null)
|
|
return false;
|
|
|
|
var ret = identifier switch
|
|
{
|
|
EqdpIdentifier i => _data.Eqdp.Remove(i),
|
|
EqpIdentifier i => _data.Eqp.Remove(i),
|
|
EstIdentifier i => _data.Est.Remove(i),
|
|
GlobalEqpManipulation i => _data.Remove(i),
|
|
GmpIdentifier i => _data.Gmp.Remove(i),
|
|
ImcIdentifier i => _data.Imc.Remove(i),
|
|
RspIdentifier i => _data.Rsp.Remove(i),
|
|
AtchIdentifier i => _data.Atch.Remove(i),
|
|
ShpIdentifier i => _data.Shp.Remove(i),
|
|
AtrIdentifier i => _data.Atr.Remove(i),
|
|
_ => false,
|
|
};
|
|
if (ret && --Count is 0)
|
|
_data = null;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#region Merging
|
|
|
|
public void UnionWith(MetaDictionary manips)
|
|
{
|
|
if (manips.Count is 0)
|
|
return;
|
|
|
|
_data ??= [];
|
|
foreach (var (identifier, entry) in manips._data!.Imc)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Eqp)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Eqdp)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Gmp)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Rsp)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Est)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Atch)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Shp)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var (identifier, entry) in manips._data!.Atr)
|
|
TryAdd(identifier, entry);
|
|
|
|
foreach (var identifier in manips._data!)
|
|
TryAdd(identifier);
|
|
}
|
|
|
|
/// <summary> Try to merge all manipulations from manips into this, and return the first failure, if any. </summary>
|
|
public bool MergeForced(MetaDictionary manips, out IMetaIdentifier? failedIdentifier)
|
|
{
|
|
if (manips.Count is 0)
|
|
{
|
|
failedIdentifier = null;
|
|
return true;
|
|
}
|
|
|
|
_data ??= [];
|
|
foreach (var (identifier, _) in manips._data!.Imc.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Eqp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Eqdp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Gmp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Rsp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Est.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Atch.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Shp.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var (identifier, _) in manips._data!.Atr.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
foreach (var identifier in manips._data!.Where(identifier => !TryAdd(identifier)))
|
|
{
|
|
failedIdentifier = identifier;
|
|
return false;
|
|
}
|
|
|
|
failedIdentifier = null;
|
|
return true;
|
|
}
|
|
|
|
public void SetTo(MetaDictionary other)
|
|
{
|
|
if (other.Count is 0)
|
|
{
|
|
_data = null;
|
|
Count = 0;
|
|
return;
|
|
}
|
|
|
|
_data ??= [];
|
|
_data!.Imc.SetTo(other._data!.Imc);
|
|
_data!.Eqp.SetTo(other._data!.Eqp);
|
|
_data!.Eqdp.SetTo(other._data!.Eqdp);
|
|
_data!.Est.SetTo(other._data!.Est);
|
|
_data!.Rsp.SetTo(other._data!.Rsp);
|
|
_data!.Gmp.SetTo(other._data!.Gmp);
|
|
_data!.Atch.SetTo(other._data!.Atch);
|
|
_data!.Shp.SetTo(other._data!.Shp);
|
|
_data!.Atr.SetTo(other._data!.Atr);
|
|
_data!.SetTo(other._data!);
|
|
Count = other.Count;
|
|
}
|
|
|
|
public void UpdateTo(MetaDictionary other)
|
|
{
|
|
if (other.Count is 0)
|
|
return;
|
|
|
|
_data ??= [];
|
|
_data!.Imc.UpdateTo(other._data!.Imc);
|
|
_data!.Eqp.UpdateTo(other._data!.Eqp);
|
|
_data!.Eqdp.UpdateTo(other._data!.Eqdp);
|
|
_data!.Est.UpdateTo(other._data!.Est);
|
|
_data!.Rsp.UpdateTo(other._data!.Rsp);
|
|
_data!.Gmp.UpdateTo(other._data!.Gmp);
|
|
_data!.Atch.UpdateTo(other._data!.Atch);
|
|
_data!.Shp.UpdateTo(other._data!.Shp);
|
|
_data!.Atr.UpdateTo(other._data!.Atr);
|
|
_data!.UnionWith(other._data!);
|
|
Count = _data!.Imc.Count
|
|
+ _data!.Eqp.Count
|
|
+ _data!.Eqdp.Count
|
|
+ _data!.Est.Count
|
|
+ _data!.Rsp.Count
|
|
+ _data!.Gmp.Count
|
|
+ _data!.Atch.Count
|
|
+ _data!.Shp.Count
|
|
+ _data!.Atr.Count
|
|
+ _data!.Count;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public MetaDictionary Clone()
|
|
{
|
|
var ret = new MetaDictionary();
|
|
ret.SetTo(this);
|
|
return ret;
|
|
}
|
|
|
|
public static JObject Serialize(EqpIdentifier identifier, EqpEntryInternal entry)
|
|
=> Serialize(identifier, entry.ToEntry(identifier.Slot));
|
|
|
|
public static JObject Serialize(EqpIdentifier identifier, EqpEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Eqp.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = (ulong)entry,
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(EqdpIdentifier identifier, EqdpEntryInternal entry)
|
|
=> Serialize(identifier, entry.ToEntry(identifier.Slot));
|
|
|
|
public static JObject Serialize(EqdpIdentifier identifier, EqdpEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Eqdp.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = (ushort)entry,
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(EstIdentifier identifier, EstEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Est.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = entry.Value,
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(GmpIdentifier identifier, GmpEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Gmp.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = JObject.FromObject(entry),
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(ImcIdentifier identifier, ImcEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Imc.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = JObject.FromObject(entry),
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(RspIdentifier identifier, RspEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Rsp.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = entry.Value,
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(AtchIdentifier identifier, AtchEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Atch.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = entry.ToJson(),
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(ShpIdentifier identifier, ShpEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Shp.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = entry.Value,
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(AtrIdentifier identifier, AtrEntry entry)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.Atr.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject
|
|
{
|
|
["Entry"] = entry.Value,
|
|
}),
|
|
};
|
|
|
|
public static JObject Serialize(GlobalEqpManipulation identifier)
|
|
=> new()
|
|
{
|
|
["Type"] = MetaManipulationType.GlobalEqp.ToString(),
|
|
["Manipulation"] = identifier.AddToJson(new JObject()),
|
|
};
|
|
|
|
public static JObject? Serialize<TIdentifier, TEntry>(TIdentifier identifier, TEntry entry)
|
|
where TIdentifier : unmanaged, IMetaIdentifier
|
|
where TEntry : unmanaged
|
|
{
|
|
if (typeof(TIdentifier) == typeof(EqpIdentifier) && typeof(TEntry) == typeof(EqpEntryInternal))
|
|
return Serialize(Unsafe.As<TIdentifier, EqpIdentifier>(ref identifier), Unsafe.As<TEntry, EqpEntryInternal>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(EqpIdentifier) && typeof(TEntry) == typeof(EqpEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, EqpIdentifier>(ref identifier), Unsafe.As<TEntry, EqpEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(EqdpIdentifier) && typeof(TEntry) == typeof(EqdpEntryInternal))
|
|
return Serialize(Unsafe.As<TIdentifier, EqdpIdentifier>(ref identifier), Unsafe.As<TEntry, EqdpEntryInternal>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(EqdpIdentifier) && typeof(TEntry) == typeof(EqdpEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, EqdpIdentifier>(ref identifier), Unsafe.As<TEntry, EqdpEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(EstIdentifier) && typeof(TEntry) == typeof(EstEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, EstIdentifier>(ref identifier), Unsafe.As<TEntry, EstEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(GmpIdentifier) && typeof(TEntry) == typeof(GmpEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, GmpIdentifier>(ref identifier), Unsafe.As<TEntry, GmpEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(RspIdentifier) && typeof(TEntry) == typeof(RspEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, RspIdentifier>(ref identifier), Unsafe.As<TEntry, RspEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(ImcIdentifier) && typeof(TEntry) == typeof(ImcEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, ImcIdentifier>(ref identifier), Unsafe.As<TEntry, ImcEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(AtchIdentifier) && typeof(TEntry) == typeof(AtchEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, AtchIdentifier>(ref identifier), Unsafe.As<TEntry, AtchEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(ShpIdentifier) && typeof(TEntry) == typeof(ShpEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, ShpIdentifier>(ref identifier), Unsafe.As<TEntry, ShpEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(AtrIdentifier) && typeof(TEntry) == typeof(AtrEntry))
|
|
return Serialize(Unsafe.As<TIdentifier, AtrIdentifier>(ref identifier), Unsafe.As<TEntry, AtrEntry>(ref entry));
|
|
if (typeof(TIdentifier) == typeof(GlobalEqpManipulation))
|
|
return Serialize(Unsafe.As<TIdentifier, GlobalEqpManipulation>(ref identifier));
|
|
|
|
return null;
|
|
}
|
|
|
|
public static JArray SerializeTo<TIdentifier, TEntry>(JArray array, IEnumerable<KeyValuePair<TIdentifier, TEntry>> manipulations)
|
|
where TIdentifier : unmanaged, IMetaIdentifier
|
|
where TEntry : unmanaged
|
|
{
|
|
foreach (var (identifier, entry) in manipulations)
|
|
{
|
|
if (Serialize(identifier, entry) is { } jObj)
|
|
array.Add(jObj);
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
public static JArray SerializeTo(JArray array, IEnumerable<GlobalEqpManipulation> manipulations)
|
|
{
|
|
foreach (var manip in manipulations)
|
|
array.Add(Serialize(manip));
|
|
|
|
return array;
|
|
}
|
|
|
|
private class Converter : JsonConverter<MetaDictionary>
|
|
{
|
|
public override void WriteJson(JsonWriter writer, MetaDictionary? value, JsonSerializer serializer)
|
|
{
|
|
if (value is null)
|
|
{
|
|
writer.WriteNull();
|
|
return;
|
|
}
|
|
|
|
var array = new JArray();
|
|
if (value._data is not null)
|
|
{
|
|
SerializeTo(array, value._data!.Imc);
|
|
SerializeTo(array, value._data!.Eqp);
|
|
SerializeTo(array, value._data!.Eqdp);
|
|
SerializeTo(array, value._data!.Est);
|
|
SerializeTo(array, value._data!.Rsp);
|
|
SerializeTo(array, value._data!.Gmp);
|
|
SerializeTo(array, value._data!.Atch);
|
|
SerializeTo(array, value._data!.Shp);
|
|
SerializeTo(array, value._data!.Atr);
|
|
SerializeTo(array, value._data!);
|
|
}
|
|
|
|
array.WriteTo(writer);
|
|
}
|
|
|
|
public override MetaDictionary ReadJson(JsonReader reader, Type objectType, MetaDictionary? existingValue, bool hasExistingValue,
|
|
JsonSerializer serializer)
|
|
{
|
|
var dict = existingValue ?? new MetaDictionary();
|
|
dict.Clear();
|
|
var jObj = JArray.Load(reader);
|
|
foreach (var item in jObj)
|
|
{
|
|
var type = item["Type"]?.ToObject<MetaManipulationType>() ?? MetaManipulationType.Unknown;
|
|
if (type is MetaManipulationType.Unknown)
|
|
{
|
|
Penumbra.Log.Warning($"Invalid Meta Manipulation Type {type} encountered.");
|
|
continue;
|
|
}
|
|
|
|
if (item["Manipulation"] is not JObject manip)
|
|
{
|
|
Penumbra.Log.Warning($"Manipulation of type {type} does not contain manipulation data.");
|
|
continue;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case MetaManipulationType.Imc:
|
|
{
|
|
var identifier = ImcIdentifier.FromJson(manip);
|
|
var entry = manip["Entry"]?.ToObject<ImcEntry>();
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid IMC Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Eqdp:
|
|
{
|
|
var identifier = EqdpIdentifier.FromJson(manip);
|
|
var entry = (EqdpEntry?)manip["Entry"]?.ToObject<ushort>();
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid EQDP Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Eqp:
|
|
{
|
|
var identifier = EqpIdentifier.FromJson(manip);
|
|
var entry = (EqpEntry?)manip["Entry"]?.ToObject<ulong>();
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid EQP Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Est:
|
|
{
|
|
var identifier = EstIdentifier.FromJson(manip);
|
|
var entry = manip["Entry"]?.ToObject<EstEntry>();
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid EST Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Gmp:
|
|
{
|
|
var identifier = GmpIdentifier.FromJson(manip);
|
|
var entry = manip["Entry"]?.ToObject<GmpEntry>();
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid GMP Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Rsp:
|
|
{
|
|
var identifier = RspIdentifier.FromJson(manip);
|
|
var entry = manip["Entry"]?.ToObject<RspEntry>();
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid RSP Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Atch:
|
|
{
|
|
var identifier = AtchIdentifier.FromJson(manip);
|
|
var entry = AtchEntry.FromJson(manip["Entry"] as JObject);
|
|
if (identifier.HasValue && entry.HasValue)
|
|
dict.TryAdd(identifier.Value, entry.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid ATCH Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Shp:
|
|
{
|
|
var identifier = ShpIdentifier.FromJson(manip);
|
|
var entry = new ShpEntry(manip["Entry"]?.Value<bool>() ?? true);
|
|
if (identifier.HasValue)
|
|
dict.TryAdd(identifier.Value, entry);
|
|
else
|
|
Penumbra.Log.Warning("Invalid SHP Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.Atr:
|
|
{
|
|
var identifier = AtrIdentifier.FromJson(manip);
|
|
var entry = new AtrEntry(manip["Entry"]?.Value<bool>() ?? true);
|
|
if (identifier.HasValue)
|
|
dict.TryAdd(identifier.Value, entry);
|
|
else
|
|
Penumbra.Log.Warning("Invalid ATR Manipulation encountered.");
|
|
break;
|
|
}
|
|
case MetaManipulationType.GlobalEqp:
|
|
{
|
|
var identifier = GlobalEqpManipulation.FromJson(manip);
|
|
if (identifier.HasValue)
|
|
dict.TryAdd(identifier.Value);
|
|
else
|
|
Penumbra.Log.Warning("Invalid Global EQP Manipulation encountered.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dict;
|
|
}
|
|
}
|
|
|
|
public MetaDictionary()
|
|
{ }
|
|
|
|
public MetaDictionary(MetaCache? cache)
|
|
{
|
|
if (cache is null)
|
|
return;
|
|
|
|
_data = new Wrapper(cache);
|
|
Count = cache.Count;
|
|
}
|
|
}
|