mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add PBD Post-Processor that appends EPBD data if the loaded PBD does not contain it.
This commit is contained in:
parent
9aff388e21
commit
a7246b9d98
8 changed files with 187 additions and 52 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0eaf7655123bd6502456e93d6ae9593249d3f792
|
Subproject commit 3ea61642a05403fb2b64032112ff674b387825b3
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2f5e901314444238ab3aa6c5043368622bca815a
|
Subproject commit 2cf59c61494a01fd14aecf925e7dc6325a7374ac
|
||||||
|
|
@ -63,7 +63,7 @@ public sealed unsafe class PreBoneDeformerReplacer : IDisposable, IRequiredServi
|
||||||
if (!_framework.IsInFrameworkUpdateThread)
|
if (!_framework.IsInFrameworkUpdateThread)
|
||||||
Penumbra.Log.Warning(
|
Penumbra.Log.Warning(
|
||||||
$"{nameof(PreBoneDeformerReplacer)}.{nameof(SetupHssReplacements)}(0x{(nint)drawObject:X}, {slotIndex}) called out of framework thread");
|
$"{nameof(PreBoneDeformerReplacer)}.{nameof(SetupHssReplacements)}(0x{(nint)drawObject:X}, {slotIndex}) called out of framework thread");
|
||||||
|
|
||||||
var preBoneDeformer = GetPreBoneDeformerForCharacter(drawObject);
|
var preBoneDeformer = GetPreBoneDeformerForCharacter(drawObject);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
119
Penumbra/Interop/Processing/PbdFilePostProcessor.cs
Normal file
119
Penumbra/Interop/Processing/PbdFilePostProcessor.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Penumbra.Api.Enums;
|
||||||
|
using Penumbra.GameData;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
|
using Penumbra.Interop.Structs;
|
||||||
|
using Penumbra.Meta.Files;
|
||||||
|
using Penumbra.String;
|
||||||
|
|
||||||
|
namespace Penumbra.Interop.Processing;
|
||||||
|
|
||||||
|
public sealed class PbdFilePostProcessor : IFilePostProcessor
|
||||||
|
{
|
||||||
|
private readonly IFileAllocator _allocator;
|
||||||
|
private byte[] _epbdData;
|
||||||
|
private unsafe delegate* unmanaged<ResourceHandle*, void> _loadEpbdData;
|
||||||
|
|
||||||
|
public ResourceType Type
|
||||||
|
=> ResourceType.Pbd;
|
||||||
|
|
||||||
|
public unsafe PbdFilePostProcessor(IDataManager dataManager, XivFileAllocator allocator, ISigScanner scanner)
|
||||||
|
{
|
||||||
|
_allocator = allocator;
|
||||||
|
_epbdData = SetEpbdData(dataManager);
|
||||||
|
_loadEpbdData = (delegate* unmanaged<ResourceHandle*, void>)scanner.ScanText(Sigs.LoadEpbdData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void PostProcess(ResourceHandle* resource, CiByteString originalGamePath, ReadOnlySpan<byte> additionalData)
|
||||||
|
{
|
||||||
|
if (_epbdData.Length is 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (resource->LoadState is not LoadState.Success)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Warning($"[ResourceLoader] Requested PBD at {originalGamePath} failed load ({resource->LoadState}).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (data, length) = resource->GetData();
|
||||||
|
if (length is 0 || data == nint.Zero)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Warning($"[ResourceLoader] Requested PBD at {originalGamePath} succeeded load but has no data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var span = new ReadOnlySpan<byte>((void*)data, (int)resource->FileSize);
|
||||||
|
var reader = new PackReader(span);
|
||||||
|
if (reader.HasData)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Excessive($"[ResourceLoader] Successfully loaded PBD at {originalGamePath} with EPBD data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newData = AppendData(span);
|
||||||
|
fixed (byte* ptr = newData)
|
||||||
|
{
|
||||||
|
// Set the appended data and the actual file size, then re-load the EPBD data via game function call.
|
||||||
|
if (resource->SetData((nint)ptr, newData.Length))
|
||||||
|
{
|
||||||
|
resource->FileSize = (uint)newData.Length;
|
||||||
|
resource->CsHandle.FileSize2 = (uint)newData.Length;
|
||||||
|
resource->CsHandle.FileSize3 = (uint)newData.Length;
|
||||||
|
_loadEpbdData(resource);
|
||||||
|
// Free original data.
|
||||||
|
_allocator.Release((void*)data, length);
|
||||||
|
Penumbra.Log.Verbose($"[ResourceLoader] Loaded {originalGamePath} from file and appended default EPBD data.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Penumbra.Log.Warning(
|
||||||
|
$"[ResourceLoader] Failed to append EPBD data to custom PBD at {originalGamePath}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Combine the given data with the default PBD data using the game's file allocator. </summary>
|
||||||
|
private unsafe ReadOnlySpan<byte> AppendData(ReadOnlySpan<byte> data)
|
||||||
|
{
|
||||||
|
// offset has to be set, otherwise not called.
|
||||||
|
var newLength = data.Length + _epbdData.Length;
|
||||||
|
var memory = _allocator.Allocate(newLength);
|
||||||
|
var span = new Span<byte>(memory, newLength);
|
||||||
|
data.CopyTo(span);
|
||||||
|
_epbdData.CopyTo(span[data.Length..]);
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Fetch the default EPBD data from the .pbd file of the game's installation. </summary>
|
||||||
|
private static byte[] SetEpbdData(IDataManager dataManager)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var file = dataManager.GetFile(GamePaths.Pbd.Path);
|
||||||
|
if (file is null || file.Data.Length is 0)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Warning("Default PBD file has no data.");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> span = file.Data;
|
||||||
|
var reader = new PackReader(span);
|
||||||
|
if (!reader.HasData)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Warning("Default PBD file has no EPBD section.");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset = span.Length - (int)reader.PackLength;
|
||||||
|
var ret = span[offset..];
|
||||||
|
Penumbra.Log.Verbose($"Default PBD file has EPBD section of length {ret.Length} at offset {offset}.");
|
||||||
|
return ret.ToArray();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Penumbra.Log.Error($"Unknown error getting default EPBD data:\n{ex}");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ using OtterGui.Compression;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Files;
|
using Penumbra.GameData.Files;
|
||||||
using Penumbra.Mods.Editor;
|
using Penumbra.Mods.Editor;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
|
|
@ -80,7 +81,7 @@ public class FileEditor<T>(
|
||||||
private Exception? _currentException;
|
private Exception? _currentException;
|
||||||
private bool _changed;
|
private bool _changed;
|
||||||
|
|
||||||
private string _defaultPath = string.Empty;
|
private string _defaultPath = typeof(T) == typeof(ModEditWindow.PbdTab) ? GamePaths.Pbd.Path : string.Empty;
|
||||||
private bool _inInput;
|
private bool _inInput;
|
||||||
private Utf8GamePath _defaultPathUtf8;
|
private Utf8GamePath _defaultPathUtf8;
|
||||||
private bool _isDefaultPathUtf8Valid;
|
private bool _isDefaultPathUtf8Valid;
|
||||||
|
|
|
||||||
|
|
@ -1236,16 +1236,12 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void DrawCopyableAddress(ReadOnlySpan<byte> label, void* address)
|
public static unsafe void DrawCopyableAddress(ReadOnlySpan<byte> label, void* address)
|
||||||
{
|
=> DrawCopyableAddress(label, (nint)address);
|
||||||
using (var _ = ImRaii.PushFont(UiBuilder.MonoFont))
|
|
||||||
{
|
|
||||||
if (ImUtf8.Selectable($"0x{(nint)address:X16} {label}"))
|
|
||||||
ImUtf8.SetClipboardText($"0x{(nint)address:X16}");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImUtf8.HoverTooltip("Click to copy address to clipboard."u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static unsafe void DrawCopyableAddress(ReadOnlySpan<byte> label, nint address)
|
public static unsafe void DrawCopyableAddress(ReadOnlySpan<byte> label, nint address)
|
||||||
=> DrawCopyableAddress(label, (void*)address);
|
{
|
||||||
|
Penumbra.Dynamis.DrawPointer(address);
|
||||||
|
ImUtf8.SameLineInner();
|
||||||
|
ImUtf8.Text(label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,31 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var actionManager = (ActionTimelineManager**)ActionTimelineManager.Instance();
|
var actionManager = (ActionTimelineManager**)ActionTimelineManager.Instance();
|
||||||
DebugTab.DrawCopyableAddress("CharacterUtility"u8, characterUtility.Address);
|
using (ImUtf8.Group())
|
||||||
DebugTab.DrawCopyableAddress("ResidentResourceManager"u8, residentResources.Address);
|
{
|
||||||
DebugTab.DrawCopyableAddress("ScheduleManagement"u8, ScheduleManagement.Instance());
|
Penumbra.Dynamis.DrawPointer(characterUtility.Address);
|
||||||
DebugTab.DrawCopyableAddress("ActionTimelineManager*"u8, actionManager);
|
Penumbra.Dynamis.DrawPointer(residentResources.Address);
|
||||||
DebugTab.DrawCopyableAddress("ActionTimelineManager"u8, actionManager != null ? *actionManager : null);
|
Penumbra.Dynamis.DrawPointer(ScheduleManagement.Instance());
|
||||||
DebugTab.DrawCopyableAddress("SchedulerResourceManagement*"u8, scheduler.Address);
|
Penumbra.Dynamis.DrawPointer(actionManager);
|
||||||
DebugTab.DrawCopyableAddress("SchedulerResourceManagement"u8, scheduler.Address != null ? *scheduler.Address : null);
|
Penumbra.Dynamis.DrawPointer(actionManager != null ? *actionManager : null);
|
||||||
DebugTab.DrawCopyableAddress("Device"u8, Device.Instance());
|
Penumbra.Dynamis.DrawPointer(scheduler.Address);
|
||||||
|
Penumbra.Dynamis.DrawPointer(scheduler.Address != null ? *scheduler.Address : null);
|
||||||
|
Penumbra.Dynamis.DrawPointer(Device.Instance());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
using (ImUtf8.Group())
|
||||||
|
{
|
||||||
|
ImUtf8.Text("CharacterUtility"u8);
|
||||||
|
ImUtf8.Text("ResidentResourceManager"u8);
|
||||||
|
ImUtf8.Text("ScheduleManagement"u8);
|
||||||
|
ImUtf8.Text("ActionTimelineManager*"u8);
|
||||||
|
ImUtf8.Text("ActionTimelineManager"u8);
|
||||||
|
ImUtf8.Text("SchedulerResourceManagement*"u8);
|
||||||
|
ImUtf8.Text("SchedulerResourceManagement"u8);
|
||||||
|
ImUtf8.Text("Device"u8);
|
||||||
|
}
|
||||||
|
|
||||||
DrawCharacterUtility();
|
DrawCharacterUtility();
|
||||||
DrawResidentResources();
|
DrawResidentResources();
|
||||||
DrawSchedulerResourcesMap();
|
DrawSchedulerResourcesMap();
|
||||||
|
|
@ -63,7 +80,7 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
var resource = characterUtility.Address->Resource(idx);
|
var resource = characterUtility.Address->Resource(idx);
|
||||||
ImUtf8.DrawTableColumn($"[{idx}]");
|
ImUtf8.DrawTableColumn($"[{idx}]");
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
Penumbra.Dynamis.DrawPointer(resource);
|
||||||
if (resource == null)
|
if (resource == null)
|
||||||
{
|
{
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
|
|
@ -74,25 +91,12 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var data = (nint)resource->CsHandle.GetData();
|
var data = (nint)resource->CsHandle.GetData();
|
||||||
var length = resource->CsHandle.GetLength();
|
var length = resource->CsHandle.GetLength();
|
||||||
if (ImUtf8.Selectable($"0x{data:X}"))
|
Penumbra.Dynamis.DrawPointer(data);
|
||||||
if (data != nint.Zero && length > 0)
|
|
||||||
ImUtf8.SetClipboardText(string.Join("\n",
|
|
||||||
new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2"))));
|
|
||||||
|
|
||||||
ImUtf8.HoverTooltip("Click to copy bytes to clipboard."u8);
|
|
||||||
ImUtf8.DrawTableColumn(length.ToString());
|
ImUtf8.DrawTableColumn(length.ToString());
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
if (intern.Value != -1)
|
if (intern.Value != -1)
|
||||||
{
|
{
|
||||||
ImUtf8.Selectable($"0x{characterUtility.DefaultResource(intern).Address:X}");
|
Penumbra.Dynamis.DrawPointer(characterUtility.DefaultResource(intern).Address);
|
||||||
if (ImGui.IsItemClicked())
|
|
||||||
ImUtf8.SetClipboardText(string.Join("\n",
|
|
||||||
new ReadOnlySpan<byte>((byte*)characterUtility.DefaultResource(intern).Address,
|
|
||||||
characterUtility.DefaultResource(intern).Size).ToArray().Select(b => b.ToString("X2"))));
|
|
||||||
|
|
||||||
ImUtf8.HoverTooltip("Click to copy bytes to clipboard."u8);
|
|
||||||
|
|
||||||
ImUtf8.DrawTableColumn($"{characterUtility.DefaultResource(intern).Size}");
|
ImUtf8.DrawTableColumn($"{characterUtility.DefaultResource(intern).Size}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -122,7 +126,7 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
var resource = residentResources.Address->ResourceList[idx];
|
var resource = residentResources.Address->ResourceList[idx];
|
||||||
ImUtf8.DrawTableColumn($"[{idx}]");
|
ImUtf8.DrawTableColumn($"[{idx}]");
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
Penumbra.Dynamis.DrawPointer(resource);
|
||||||
if (resource == null)
|
if (resource == null)
|
||||||
{
|
{
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
|
|
@ -133,12 +137,7 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var data = (nint)resource->CsHandle.GetData();
|
var data = (nint)resource->CsHandle.GetData();
|
||||||
var length = resource->CsHandle.GetLength();
|
var length = resource->CsHandle.GetLength();
|
||||||
if (ImUtf8.Selectable($"0x{data:X}"))
|
Penumbra.Dynamis.DrawPointer(data);
|
||||||
if (data != nint.Zero && length > 0)
|
|
||||||
ImUtf8.SetClipboardText(string.Join("\n",
|
|
||||||
new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2"))));
|
|
||||||
|
|
||||||
ImUtf8.HoverTooltip("Click to copy bytes to clipboard."u8);
|
|
||||||
ImUtf8.DrawTableColumn(length.ToString());
|
ImUtf8.DrawTableColumn(length.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,15 +183,15 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
ImUtf8.DrawTableColumn($"{resource->Consumers}");
|
ImUtf8.DrawTableColumn($"{resource->Consumers}");
|
||||||
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
|
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
Penumbra.Dynamis.DrawPointer(resource);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var resourceHandle = *((ResourceHandle**)resource + 3);
|
var resourceHandle = *((ResourceHandle**)resource + 3);
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resourceHandle:X}");
|
Penumbra.Dynamis.DrawPointer(resourceHandle);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
|
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
uint dataLength = 0;
|
uint dataLength = 0;
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource->GetResourceData(&dataLength):X}");
|
Penumbra.Dynamis.DrawPointer(resource->GetResourceData(&dataLength));
|
||||||
ImUtf8.DrawTableColumn($"{dataLength}");
|
ImUtf8.DrawTableColumn($"{dataLength}");
|
||||||
++_shownResourcesMap;
|
++_shownResourcesMap;
|
||||||
}
|
}
|
||||||
|
|
@ -233,15 +232,15 @@ public unsafe class GlobalVariablesDrawer(
|
||||||
ImUtf8.DrawTableColumn($"{resource->Consumers}");
|
ImUtf8.DrawTableColumn($"{resource->Consumers}");
|
||||||
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
|
ImUtf8.DrawTableColumn($"{resource->Unk1}"); // key
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource:X}");
|
Penumbra.Dynamis.DrawPointer(resource);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
var resourceHandle = *((ResourceHandle**)resource + 3);
|
var resourceHandle = *((ResourceHandle**)resource + 3);
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resourceHandle:X}");
|
Penumbra.Dynamis.DrawPointer(resourceHandle);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
|
ImUtf8.CopyOnClickSelectable(resourceHandle->FileName().Span);
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
uint dataLength = 0;
|
uint dataLength = 0;
|
||||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)resource->GetResourceData(&dataLength):X}");
|
Penumbra.Dynamis.DrawPointer(resource->GetResourceData(&dataLength));
|
||||||
ImUtf8.DrawTableColumn($"{dataLength}");
|
ImUtf8.DrawTableColumn($"{dataLength}");
|
||||||
++_shownResourcesList;
|
++_shownResourcesList;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,19 @@
|
||||||
"resolved": "3.1.11",
|
"resolved": "3.1.11",
|
||||||
"contentHash": "JfPLyigLthuE50yi6tMt7Amrenr/fA31t2CvJyhy/kQmfulIBAqo5T/YFUSRHtuYPXRSaUHygFeh6Qd933EoSw=="
|
"contentHash": "JfPLyigLthuE50yi6tMt7Amrenr/fA31t2CvJyhy/kQmfulIBAqo5T/YFUSRHtuYPXRSaUHygFeh6Qd933EoSw=="
|
||||||
},
|
},
|
||||||
|
"FlatSharp.Compiler": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "7.9.0",
|
||||||
|
"contentHash": "MU6808xvdbWJ3Ev+5PKalqQuzvVbn1DzzQH8txRDHGFUNDvHjd+ejqpvnYc9BSJ8Qp8VjkkpJD8OzRYilbPp3A=="
|
||||||
|
},
|
||||||
|
"FlatSharp.Runtime": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "7.9.0",
|
||||||
|
"contentHash": "Bm8+WqzEsWNpxqrD5x4x+zQ8dyINlToCreM5FI2oNSfUVc9U9ZB+qztX/jd8rlJb3r0vBSlPwVLpw0xBtPa3Vw==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Memory": "4.5.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"JetBrains.Annotations": {
|
"JetBrains.Annotations": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "2024.3.0",
|
"resolved": "2024.3.0",
|
||||||
|
|
@ -94,6 +107,11 @@
|
||||||
"resolved": "4.6.0",
|
"resolved": "4.6.0",
|
||||||
"contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA=="
|
"contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA=="
|
||||||
},
|
},
|
||||||
|
"System.Memory": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.5",
|
||||||
|
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw=="
|
||||||
|
},
|
||||||
"System.Security.Cryptography.Pkcs": {
|
"System.Security.Cryptography.Pkcs": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.1",
|
"resolved": "8.0.1",
|
||||||
|
|
@ -133,8 +151,10 @@
|
||||||
"penumbra.gamedata": {
|
"penumbra.gamedata": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"FlatSharp.Compiler": "[7.9.0, )",
|
||||||
|
"FlatSharp.Runtime": "[7.9.0, )",
|
||||||
"OtterGui": "[1.0.0, )",
|
"OtterGui": "[1.0.0, )",
|
||||||
"Penumbra.Api": "[5.6.1, )",
|
"Penumbra.Api": "[5.10.0, )",
|
||||||
"Penumbra.String": "[1.0.6, )"
|
"Penumbra.String": "[1.0.6, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue