mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-02 05:43:42 +01:00
Atch stuff.
This commit is contained in:
parent
65538868c3
commit
b1be868a6a
32 changed files with 802 additions and 43 deletions
26
Penumbra/Meta/AtchManager.cs
Normal file
26
Penumbra/Meta/AtchManager.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Frozen;
|
||||
using Dalamud.Plugin.Services;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
|
||||
namespace Penumbra.Interop.Hooks.Meta;
|
||||
|
||||
public sealed unsafe class AtchManager : IService
|
||||
{
|
||||
private static readonly IReadOnlyList<GenderRace> GenderRaces =
|
||||
[
|
||||
GenderRace.MidlanderMale, GenderRace.MidlanderFemale, GenderRace.HighlanderMale, GenderRace.HighlanderFemale, GenderRace.ElezenMale,
|
||||
GenderRace.ElezenFemale, GenderRace.MiqoteMale, GenderRace.MiqoteFemale, GenderRace.RoegadynMale, GenderRace.RoegadynFemale,
|
||||
GenderRace.LalafellMale, GenderRace.LalafellFemale, GenderRace.AuRaMale, GenderRace.AuRaFemale, GenderRace.HrothgarMale,
|
||||
GenderRace.HrothgarFemale, GenderRace.VieraMale, GenderRace.VieraFemale,
|
||||
];
|
||||
|
||||
public readonly IReadOnlyDictionary<GenderRace, AtchFile> AtchFileBase;
|
||||
|
||||
public AtchManager(IDataManager manager)
|
||||
{
|
||||
AtchFileBase = GenderRaces.ToFrozenDictionary(gr => gr,
|
||||
gr => new AtchFile(manager.GetFile($"chara/xls/attachOffset/c{gr.ToRaceCode()}.atch")!.DataSpan));
|
||||
}
|
||||
}
|
||||
77
Penumbra/Meta/Manipulations/AtchIdentifier.cs
Normal file
77
Penumbra/Meta/Manipulations/AtchIdentifier.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files.AtchStructs;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
||||
namespace Penumbra.Meta.Manipulations;
|
||||
|
||||
public readonly record struct AtchIdentifier(AtchType Type, GenderRace GenderRace, ushort EntryIndex)
|
||||
: IComparable<AtchIdentifier>, IMetaIdentifier
|
||||
{
|
||||
public Gender Gender
|
||||
=> GenderRace.Split().Item1;
|
||||
|
||||
public ModelRace Race
|
||||
=> GenderRace.Split().Item2;
|
||||
|
||||
public int CompareTo(AtchIdentifier other)
|
||||
{
|
||||
var typeComparison = Type.CompareTo(other.Type);
|
||||
if (typeComparison != 0)
|
||||
return typeComparison;
|
||||
|
||||
var genderRaceComparison = GenderRace.CompareTo(other.GenderRace);
|
||||
if (genderRaceComparison != 0)
|
||||
return genderRaceComparison;
|
||||
|
||||
return EntryIndex.CompareTo(other.EntryIndex);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"Atch - {Type.ToAbbreviation()} - {GenderRace.ToName()} - {EntryIndex}";
|
||||
|
||||
public void AddChangedItems(ObjectIdentification identifier, IDictionary<string, IIdentifiedObjectData?> changedItems)
|
||||
{
|
||||
// Nothing specific
|
||||
}
|
||||
|
||||
public MetaIndex FileIndex()
|
||||
=> (MetaIndex)(-1);
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
var race = (int)GenderRace / 100;
|
||||
var remainder = (int)GenderRace - 100 * race;
|
||||
if (remainder != 1)
|
||||
return false;
|
||||
|
||||
return race is >= 0 and <= 18;
|
||||
}
|
||||
|
||||
public JObject AddToJson(JObject jObj)
|
||||
{
|
||||
var (gender, race) = GenderRace.Split();
|
||||
jObj["Gender"] = gender.ToString();
|
||||
jObj["Race"] = race.ToString();
|
||||
jObj["Type"] = Type.ToAbbreviation();
|
||||
jObj["Index"] = EntryIndex;
|
||||
return jObj;
|
||||
}
|
||||
|
||||
public static AtchIdentifier? FromJson(JObject jObj)
|
||||
{
|
||||
var gender = jObj["Gender"]?.ToObject<Gender>() ?? Gender.Unknown;
|
||||
var race = jObj["Race"]?.ToObject<ModelRace>() ?? ModelRace.Unknown;
|
||||
var type = AtchExtensions.FromString(jObj["Type"]?.ToObject<string>() ?? string.Empty);
|
||||
var entryIndex = jObj["Index"]?.ToObject<ushort>() ?? ushort.MaxValue;
|
||||
if (entryIndex == ushort.MaxValue || type is AtchType.Unknown)
|
||||
return null;
|
||||
|
||||
var ret = new AtchIdentifier(type, Names.CombinedRace(gender, race), entryIndex);
|
||||
return ret.Validate() ? ret : null;
|
||||
}
|
||||
|
||||
MetaManipulationType IMetaIdentifier.Type
|
||||
=> MetaManipulationType.Atch;
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ public enum MetaManipulationType : byte
|
|||
Gmp = 5,
|
||||
Rsp = 6,
|
||||
GlobalEqp = 7,
|
||||
Atch = 8,
|
||||
}
|
||||
|
||||
public interface IMetaIdentifier
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
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;
|
||||
|
|
@ -16,6 +17,7 @@ public class MetaDictionary
|
|||
private readonly Dictionary<EstIdentifier, EstEntry> _est = [];
|
||||
private readonly Dictionary<RspIdentifier, RspEntry> _rsp = [];
|
||||
private readonly Dictionary<GmpIdentifier, GmpEntry> _gmp = [];
|
||||
private readonly Dictionary<AtchIdentifier, AtchEntry> _atch = [];
|
||||
private readonly HashSet<GlobalEqpManipulation> _globalEqp = [];
|
||||
|
||||
public IReadOnlyDictionary<ImcIdentifier, ImcEntry> Imc
|
||||
|
|
@ -36,6 +38,9 @@ public class MetaDictionary
|
|||
public IReadOnlyDictionary<RspIdentifier, RspEntry> Rsp
|
||||
=> _rsp;
|
||||
|
||||
public IReadOnlyDictionary<AtchIdentifier, AtchEntry> Atch
|
||||
=> _atch;
|
||||
|
||||
public IReadOnlySet<GlobalEqpManipulation> GlobalEqp
|
||||
=> _globalEqp;
|
||||
|
||||
|
|
@ -50,6 +55,7 @@ public class MetaDictionary
|
|||
MetaManipulationType.Est => _est.Count,
|
||||
MetaManipulationType.Gmp => _gmp.Count,
|
||||
MetaManipulationType.Rsp => _rsp.Count,
|
||||
MetaManipulationType.Atch => _atch.Count,
|
||||
MetaManipulationType.GlobalEqp => _globalEqp.Count,
|
||||
_ => 0,
|
||||
};
|
||||
|
|
@ -63,6 +69,7 @@ public class MetaDictionary
|
|||
GlobalEqpManipulation i => _globalEqp.Contains(i),
|
||||
GmpIdentifier i => _gmp.ContainsKey(i),
|
||||
ImcIdentifier i => _imc.ContainsKey(i),
|
||||
AtchIdentifier i => _atch.ContainsKey(i),
|
||||
RspIdentifier i => _rsp.ContainsKey(i),
|
||||
_ => false,
|
||||
};
|
||||
|
|
@ -76,6 +83,7 @@ public class MetaDictionary
|
|||
_est.Clear();
|
||||
_rsp.Clear();
|
||||
_gmp.Clear();
|
||||
_atch.Clear();
|
||||
_globalEqp.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -88,6 +96,7 @@ public class MetaDictionary
|
|||
_est.Clear();
|
||||
_rsp.Clear();
|
||||
_gmp.Clear();
|
||||
_atch.Clear();
|
||||
}
|
||||
|
||||
public bool Equals(MetaDictionary other)
|
||||
|
|
@ -98,6 +107,7 @@ public class MetaDictionary
|
|||
&& _est.SetEquals(other._est)
|
||||
&& _rsp.SetEquals(other._rsp)
|
||||
&& _gmp.SetEquals(other._gmp)
|
||||
&& _atch.SetEquals(other._atch)
|
||||
&& _globalEqp.SetEquals(other._globalEqp);
|
||||
|
||||
public IEnumerable<IMetaIdentifier> Identifiers
|
||||
|
|
@ -107,6 +117,7 @@ public class MetaDictionary
|
|||
.Concat(_est.Keys.Cast<IMetaIdentifier>())
|
||||
.Concat(_gmp.Keys.Cast<IMetaIdentifier>())
|
||||
.Concat(_rsp.Keys.Cast<IMetaIdentifier>())
|
||||
.Concat(_atch.Keys.Cast<IMetaIdentifier>())
|
||||
.Concat(_globalEqp.Cast<IMetaIdentifier>());
|
||||
|
||||
#region TryAdd
|
||||
|
|
@ -171,6 +182,15 @@ public class MetaDictionary
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool TryAdd(AtchIdentifier identifier, in AtchEntry entry)
|
||||
{
|
||||
if (!_atch.TryAdd(identifier, entry))
|
||||
return false;
|
||||
|
||||
++Count;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryAdd(GlobalEqpManipulation identifier)
|
||||
{
|
||||
if (!_globalEqp.Add(identifier))
|
||||
|
|
@ -244,6 +264,15 @@ public class MetaDictionary
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool Update(AtchIdentifier identifier, in AtchEntry entry)
|
||||
{
|
||||
if (!_atch.ContainsKey(identifier))
|
||||
return false;
|
||||
|
||||
_atch[identifier] = entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TryGetValue
|
||||
|
|
@ -266,6 +295,9 @@ public class MetaDictionary
|
|||
public bool TryGetValue(ImcIdentifier identifier, out ImcEntry value)
|
||||
=> _imc.TryGetValue(identifier, out value);
|
||||
|
||||
public bool TryGetValue(AtchIdentifier identifier, out AtchEntry value)
|
||||
=> _atch.TryGetValue(identifier, out value);
|
||||
|
||||
#endregion
|
||||
|
||||
public bool Remove(IMetaIdentifier identifier)
|
||||
|
|
@ -279,6 +311,7 @@ public class MetaDictionary
|
|||
GmpIdentifier i => _gmp.Remove(i),
|
||||
ImcIdentifier i => _imc.Remove(i),
|
||||
RspIdentifier i => _rsp.Remove(i),
|
||||
AtchIdentifier i => _atch.Remove(i),
|
||||
_ => false,
|
||||
};
|
||||
if (ret)
|
||||
|
|
@ -308,6 +341,9 @@ public class MetaDictionary
|
|||
foreach (var (identifier, entry) in manips._est)
|
||||
TryAdd(identifier, entry);
|
||||
|
||||
foreach (var (identifier, entry) in manips._atch)
|
||||
TryAdd(identifier, entry);
|
||||
|
||||
foreach (var identifier in manips._globalEqp)
|
||||
TryAdd(identifier);
|
||||
}
|
||||
|
|
@ -351,6 +387,12 @@ public class MetaDictionary
|
|||
return false;
|
||||
}
|
||||
|
||||
foreach (var (identifier, _) in manips._atch.Where(kvp => !TryAdd(kvp.Key, kvp.Value)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var identifier in manips._globalEqp.Where(identifier => !TryAdd(identifier)))
|
||||
{
|
||||
failedIdentifier = identifier;
|
||||
|
|
@ -369,8 +411,9 @@ public class MetaDictionary
|
|||
_est.SetTo(other._est);
|
||||
_rsp.SetTo(other._rsp);
|
||||
_gmp.SetTo(other._gmp);
|
||||
_atch.SetTo(other._atch);
|
||||
_globalEqp.SetTo(other._globalEqp);
|
||||
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _globalEqp.Count;
|
||||
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _atch.Count + _globalEqp.Count;
|
||||
}
|
||||
|
||||
public void UpdateTo(MetaDictionary other)
|
||||
|
|
@ -381,8 +424,9 @@ public class MetaDictionary
|
|||
_est.UpdateTo(other._est);
|
||||
_rsp.UpdateTo(other._rsp);
|
||||
_gmp.UpdateTo(other._gmp);
|
||||
_atch.UpdateTo(other._atch);
|
||||
_globalEqp.UnionWith(other._globalEqp);
|
||||
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _globalEqp.Count;
|
||||
Count = _imc.Count + _eqp.Count + _eqdp.Count + _est.Count + _rsp.Count + _gmp.Count + _atch.Count + _globalEqp.Count;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -460,6 +504,16 @@ public class MetaDictionary
|
|||
}),
|
||||
};
|
||||
|
||||
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(GlobalEqpManipulation identifier)
|
||||
=> new()
|
||||
{
|
||||
|
|
@ -487,6 +541,8 @@ public class MetaDictionary
|
|||
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(GlobalEqpManipulation))
|
||||
return Serialize(Unsafe.As<TIdentifier, GlobalEqpManipulation>(ref identifier));
|
||||
|
||||
|
|
@ -531,6 +587,7 @@ public class MetaDictionary
|
|||
SerializeTo(array, value._est);
|
||||
SerializeTo(array, value._rsp);
|
||||
SerializeTo(array, value._gmp);
|
||||
SerializeTo(array, value._atch);
|
||||
SerializeTo(array, value._globalEqp);
|
||||
array.WriteTo(writer);
|
||||
}
|
||||
|
|
@ -618,6 +675,16 @@ public class MetaDictionary
|
|||
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.GlobalEqp:
|
||||
{
|
||||
var identifier = GlobalEqpManipulation.FromJson(manip);
|
||||
|
|
@ -648,6 +715,7 @@ public class MetaDictionary
|
|||
_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);
|
||||
_globalEqp = cache.GlobalEqp.Select(kvp => kvp.Key).ToHashSet();
|
||||
Count = cache.Count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Penumbra.Collections;
|
|||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Import;
|
||||
using Penumbra.Interop.Hooks.Meta;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Mods;
|
||||
|
|
@ -25,13 +26,14 @@ public class MetaFileManager : IService
|
|||
internal readonly ObjectIdentification Identifier;
|
||||
internal readonly FileCompactor Compactor;
|
||||
internal readonly ImcChecker ImcChecker;
|
||||
internal readonly AtchManager AtchManager;
|
||||
internal readonly IFileAllocator MarshalAllocator = new MarshalAllocator();
|
||||
internal readonly IFileAllocator XivAllocator;
|
||||
|
||||
|
||||
public MetaFileManager(CharacterUtility characterUtility, ResidentResourceManager residentResources, IDataManager gameData,
|
||||
ActiveCollectionData activeCollections, Configuration config, ValidityChecker validityChecker, ObjectIdentification identifier,
|
||||
FileCompactor compactor, IGameInteropProvider interop)
|
||||
FileCompactor compactor, IGameInteropProvider interop, AtchManager atchManager)
|
||||
{
|
||||
CharacterUtility = characterUtility;
|
||||
ResidentResources = residentResources;
|
||||
|
|
@ -41,6 +43,7 @@ public class MetaFileManager : IService
|
|||
ValidityChecker = validityChecker;
|
||||
Identifier = identifier;
|
||||
Compactor = compactor;
|
||||
AtchManager = atchManager;
|
||||
ImcChecker = new ImcChecker(this);
|
||||
XivAllocator = new XivFileAllocator(interop);
|
||||
interop.InitializeFromAttributes(this);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue