mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-23 08:17:59 +01:00
Improve Imc Handling.
This commit is contained in:
parent
d7a8c9415b
commit
03d3c38ad5
16 changed files with 197 additions and 233 deletions
|
|
@ -34,7 +34,7 @@ public sealed unsafe class CmpFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public CmpFile(MetaFileManager manager)
|
||||
: base(manager, MetaIndex.HumanCmp)
|
||||
: base(manager, manager.MarshalAllocator, MetaIndex.HumanCmp)
|
||||
{
|
||||
AllocateData(DefaultData.Length);
|
||||
Reset();
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public ExpandedEqdpFile(MetaFileManager manager, GenderRace raceCode, bool accessory)
|
||||
: base(manager, CharacterUtilityData.EqdpIdx(raceCode, accessory))
|
||||
: base(manager, manager.MarshalAllocator, CharacterUtilityData.EqdpIdx(raceCode, accessory))
|
||||
{
|
||||
var def = (byte*)DefaultData.Data;
|
||||
var blockSize = *(ushort*)(def + IdentifierSize);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile
|
|||
}
|
||||
|
||||
public ExpandedEqpGmpBase(MetaFileManager manager, bool gmp)
|
||||
: base(manager, gmp ? MetaIndex.Gmp : MetaIndex.Eqp)
|
||||
: base(manager, manager.MarshalAllocator, gmp ? MetaIndex.Gmp : MetaIndex.Eqp)
|
||||
{
|
||||
AllocateData(MaxSize);
|
||||
Reset();
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ public sealed unsafe class EstFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public EstFile(MetaFileManager manager, EstType estType)
|
||||
: base(manager, (MetaIndex)estType)
|
||||
: base(manager, manager.MarshalAllocator, (MetaIndex)estType)
|
||||
{
|
||||
var length = DefaultData.Length;
|
||||
AllocateData(length + IncreaseSize);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Penumbra.Meta.Files;
|
|||
/// Containing Flags in each byte, 0x01 set for Body, 0x02 set for Helmet.
|
||||
/// Each flag corresponds to a mount row from the Mounts table and determines whether the mount disables the effect.
|
||||
/// </summary>
|
||||
public unsafe class EvpFile : MetaBaseFile
|
||||
public unsafe class EvpFile(MetaFileManager manager) : MetaBaseFile(manager, manager.MarshalAllocator, (MetaIndex)1)
|
||||
{
|
||||
public const int FlagArraySize = 512;
|
||||
|
||||
|
|
@ -57,8 +57,4 @@ public unsafe class EvpFile : MetaBaseFile
|
|||
|
||||
return EvpFlag.None;
|
||||
}
|
||||
|
||||
public EvpFile(MetaFileManager manager)
|
||||
: base(manager, (MetaIndex)1) // TODO: Name
|
||||
{ }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,16 +7,10 @@ using Penumbra.String.Functions;
|
|||
|
||||
namespace Penumbra.Meta.Files;
|
||||
|
||||
public class ImcException : Exception
|
||||
public class ImcException(ImcIdentifier identifier, Utf8GamePath path) : Exception
|
||||
{
|
||||
public readonly ImcIdentifier Identifier;
|
||||
public readonly string GamePath;
|
||||
|
||||
public ImcException(ImcIdentifier identifier, Utf8GamePath path)
|
||||
{
|
||||
Identifier = identifier;
|
||||
GamePath = path.ToString();
|
||||
}
|
||||
public readonly ImcIdentifier Identifier = identifier;
|
||||
public readonly string GamePath = path.ToString();
|
||||
|
||||
public override string Message
|
||||
=> "Could not obtain default Imc File.\n"
|
||||
|
|
@ -146,7 +140,11 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
}
|
||||
|
||||
public ImcFile(MetaFileManager manager, ImcIdentifier identifier)
|
||||
: base(manager, 0)
|
||||
: this(manager, manager.MarshalAllocator, identifier)
|
||||
{ }
|
||||
|
||||
public ImcFile(MetaFileManager manager, IFileAllocator alloc, ImcIdentifier identifier)
|
||||
: base(manager, alloc, 0)
|
||||
{
|
||||
var path = identifier.GamePathString();
|
||||
Path = Utf8GamePath.FromString(path, out var p) ? p : Utf8GamePath.Empty;
|
||||
|
|
@ -194,7 +192,13 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
public void Replace(ResourceHandle* resource)
|
||||
{
|
||||
var (data, length) = resource->GetData();
|
||||
var newData = Manager.AllocateDefaultMemory(ActualLength, 8);
|
||||
if (length == ActualLength)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked((byte*)data, Data, ActualLength);
|
||||
return;
|
||||
}
|
||||
|
||||
var newData = Manager.XivAllocator.Allocate(ActualLength, 8);
|
||||
if (newData == null)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not replace loaded IMC data at 0x{(ulong)resource:X}, allocation failed.");
|
||||
|
|
@ -203,7 +207,7 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
|
||||
MemoryUtility.MemCpyUnchecked(newData, Data, ActualLength);
|
||||
|
||||
Manager.Free(data, length);
|
||||
resource->SetData((IntPtr)newData, ActualLength);
|
||||
Manager.XivAllocator.Release((void*)data, length);
|
||||
resource->SetData((nint)newData, ActualLength);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,75 @@
|
|||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.String.Functions;
|
||||
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
|
||||
|
||||
namespace Penumbra.Meta.Files;
|
||||
|
||||
public unsafe class MetaBaseFile : IDisposable
|
||||
public unsafe interface IFileAllocator
|
||||
{
|
||||
protected readonly MetaFileManager Manager;
|
||||
public T* Allocate<T>(int length, int alignment = 1) where T : unmanaged;
|
||||
public void Release<T>(ref T* pointer, int length) where T : unmanaged;
|
||||
|
||||
public void Release(void* pointer, int length)
|
||||
{
|
||||
var tmp = (byte*)pointer;
|
||||
Release(ref tmp, length);
|
||||
}
|
||||
|
||||
public byte* Allocate(int length, int alignment = 1)
|
||||
=> Allocate<byte>(length, alignment);
|
||||
}
|
||||
|
||||
public sealed class MarshalAllocator : IFileAllocator
|
||||
{
|
||||
public unsafe T* Allocate<T>(int length, int alignment = 1) where T : unmanaged
|
||||
=> (T*)Marshal.AllocHGlobal(length * sizeof(T));
|
||||
|
||||
public unsafe void Release<T>(ref T* pointer, int length) where T : unmanaged
|
||||
{
|
||||
Marshal.FreeHGlobal((nint)pointer);
|
||||
pointer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed unsafe class XivFileAllocator : IFileAllocator, IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Allocate in the games space for file storage.
|
||||
/// We only need this if using any meta file.
|
||||
/// </summary>
|
||||
[Signature(Sigs.GetFileSpace)]
|
||||
private readonly nint _getFileSpaceAddress = nint.Zero;
|
||||
|
||||
public XivFileAllocator(IGameInteropProvider provider)
|
||||
=> provider.InitializeFromAttributes(this);
|
||||
|
||||
public IMemorySpace* GetFileSpace()
|
||||
=> ((delegate* unmanaged<IMemorySpace*>)_getFileSpaceAddress)();
|
||||
|
||||
public T* Allocate<T>(int length, int alignment = 1) where T : unmanaged
|
||||
=> (T*)GetFileSpace()->Malloc((ulong)(length * sizeof(T)), (ulong)alignment);
|
||||
|
||||
public void Release<T>(ref T* pointer, int length) where T : unmanaged
|
||||
{
|
||||
IMemorySpace.Free(pointer, (ulong)(length * sizeof(T)));
|
||||
pointer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe class MetaBaseFile(MetaFileManager manager, IFileAllocator alloc, MetaIndex idx) : IDisposable
|
||||
{
|
||||
protected readonly MetaFileManager Manager = manager;
|
||||
protected readonly IFileAllocator Allocator = alloc;
|
||||
|
||||
public byte* Data { get; private set; }
|
||||
public int Length { get; private set; }
|
||||
public CharacterUtility.InternalIndex Index { get; }
|
||||
|
||||
public MetaBaseFile(MetaFileManager manager, MetaIndex idx)
|
||||
{
|
||||
Manager = manager;
|
||||
Index = CharacterUtility.ReverseIndices[(int)idx];
|
||||
}
|
||||
public CharacterUtility.InternalIndex Index { get; } = CharacterUtility.ReverseIndices[(int)idx];
|
||||
|
||||
protected (IntPtr Data, int Length) DefaultData
|
||||
=> Manager.CharacterUtility.DefaultResource(Index);
|
||||
|
|
@ -30,7 +82,7 @@ public unsafe class MetaBaseFile : IDisposable
|
|||
protected void AllocateData(int length)
|
||||
{
|
||||
Length = length;
|
||||
Data = (byte*)Manager.AllocateFileMemory(length);
|
||||
Data = Allocator.Allocate(length);
|
||||
if (length > 0)
|
||||
GC.AddMemoryPressure(length);
|
||||
}
|
||||
|
|
@ -38,8 +90,7 @@ public unsafe class MetaBaseFile : IDisposable
|
|||
/// <summary> Free memory. </summary>
|
||||
protected void ReleaseUnmanagedResources()
|
||||
{
|
||||
var ptr = (IntPtr)Data;
|
||||
MemoryHelper.GameFree(ref ptr, (ulong)Length);
|
||||
Allocator.Release(Data, Length);
|
||||
if (Length > 0)
|
||||
GC.RemoveMemoryPressure(Length);
|
||||
|
||||
|
|
@ -53,7 +104,7 @@ public unsafe class MetaBaseFile : IDisposable
|
|||
if (newLength == Length)
|
||||
return;
|
||||
|
||||
var data = (byte*)Manager.AllocateFileMemory((ulong)newLength);
|
||||
var data = Allocator.Allocate(newLength);
|
||||
if (newLength > Length)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked(data, Data, Length);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||
using OtterGui.Compression;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Import;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Groups;
|
||||
|
|
@ -28,6 +24,9 @@ public unsafe class MetaFileManager
|
|||
internal readonly ObjectIdentification Identifier;
|
||||
internal readonly FileCompactor Compactor;
|
||||
internal readonly ImcChecker ImcChecker;
|
||||
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,
|
||||
|
|
@ -42,6 +41,7 @@ public unsafe class MetaFileManager
|
|||
Identifier = identifier;
|
||||
Compactor = compactor;
|
||||
ImcChecker = new ImcChecker(this);
|
||||
XivAllocator = new XivFileAllocator(interop);
|
||||
interop.InitializeFromAttributes(this);
|
||||
}
|
||||
|
||||
|
|
@ -76,57 +76,11 @@ public unsafe class MetaFileManager
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public void SetFile(MetaBaseFile? file, MetaIndex metaIndex)
|
||||
{
|
||||
if (file == null || !Config.EnableMods)
|
||||
CharacterUtility.ResetResource(metaIndex);
|
||||
else
|
||||
CharacterUtility.SetResource(metaIndex, (nint)file.Data, file.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public MetaList.MetaReverter TemporarilySetFile(MetaBaseFile? file, MetaIndex metaIndex)
|
||||
=> Config.EnableMods
|
||||
? file == null
|
||||
? CharacterUtility.TemporarilyResetResource(metaIndex)
|
||||
: CharacterUtility.TemporarilySetResource(metaIndex, (nint)file.Data, file.Length)
|
||||
: MetaList.MetaReverter.Disabled;
|
||||
|
||||
public void ApplyDefaultFiles(ModCollection? collection)
|
||||
{
|
||||
if (ActiveCollections.Default != collection || !CharacterUtility.Ready || !Config.EnableMods)
|
||||
return;
|
||||
|
||||
ResidentResources.Reload();
|
||||
if (collection._cache == null)
|
||||
CharacterUtility.ResetAll();
|
||||
else
|
||||
collection._cache.Meta.SetFiles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocate in the games space for file storage.
|
||||
/// We only need this if using any meta file.
|
||||
/// </summary>
|
||||
[Signature(Sigs.GetFileSpace)]
|
||||
private readonly nint _getFileSpaceAddress = nint.Zero;
|
||||
|
||||
public IMemorySpace* GetFileSpace()
|
||||
=> ((delegate* unmanaged<IMemorySpace*>)_getFileSpaceAddress)();
|
||||
|
||||
public void* AllocateFileMemory(ulong length, ulong alignment = 0)
|
||||
=> GetFileSpace()->Malloc(length, alignment);
|
||||
|
||||
public void* AllocateFileMemory(int length, int alignment = 0)
|
||||
=> AllocateFileMemory((ulong)length, (ulong)alignment);
|
||||
|
||||
public void* AllocateDefaultMemory(ulong length, ulong alignment = 0)
|
||||
=> GetFileSpace()->Malloc(length, alignment);
|
||||
|
||||
public void* AllocateDefaultMemory(int length, int alignment = 0)
|
||||
=> IMemorySpace.GetDefaultSpace()->Malloc((ulong)length, (ulong)alignment);
|
||||
|
||||
public void Free(nint ptr, int length)
|
||||
=> IMemorySpace.Free((void*)ptr, (ulong)length);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue