mirror of
https://github.com/Caraxi/mare.client.git
synced 2025-12-12 18:07:22 +01:00
elevate penumbra resolving to default resolving method
This commit is contained in:
parent
baf747ba65
commit
940e3b5cca
5 changed files with 7 additions and 264 deletions
|
|
@ -1,49 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
|
||||
namespace MareSynchronos.Interop;
|
||||
#pragma warning disable MA0048
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct RenderModel
|
||||
{
|
||||
[FieldOffset(0x18)]
|
||||
public RenderModel* PreviousModel;
|
||||
|
||||
[FieldOffset(0x20)]
|
||||
public RenderModel* NextModel;
|
||||
|
||||
[FieldOffset(0x30)]
|
||||
public ResourceHandle* ResourceHandle;
|
||||
|
||||
[FieldOffset(0x40)]
|
||||
public Skeleton* Skeleton;
|
||||
|
||||
[FieldOffset(0x58)]
|
||||
public void** BoneList;
|
||||
|
||||
[FieldOffset(0x60)]
|
||||
public int BoneListCount;
|
||||
|
||||
[FieldOffset(0x98)]
|
||||
public void** Materials;
|
||||
|
||||
[FieldOffset(0xA0)]
|
||||
public int MaterialCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct Weapon
|
||||
{
|
||||
[FieldOffset(0x18)] public IntPtr Parent;
|
||||
[FieldOffset(0x20)] public IntPtr NextSibling;
|
||||
[FieldOffset(0x28)] public IntPtr PreviousSibling;
|
||||
[FieldOffset(0xA8)] public WeaponDrawObject* WeaponRenderModel;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public unsafe struct WeaponDrawObject
|
||||
{
|
||||
[FieldOffset(0x00)] public RenderModel* RenderModel;
|
||||
}
|
||||
#pragma warning restore MA0048
|
||||
|
|
@ -50,7 +50,6 @@ public class MareConfig : IMareConfiguration
|
|||
public int TransferBarsWidth { get; set; } = 250;
|
||||
public bool UseAlternativeFileUpload { get; set; } = false;
|
||||
public bool UseCompactor { get; set; } = false;
|
||||
public bool ExperimentalUsePenumbraResourceTree { get; set; } = false;
|
||||
public int Version { get; set; } = 1;
|
||||
public NotificationLocation WarningNotification { get; set; } = NotificationLocation.Both;
|
||||
}
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using MareSynchronos.API.Data.Enum;
|
||||
using MareSynchronos.FileCache;
|
||||
using MareSynchronos.Interop;
|
||||
|
|
@ -11,10 +8,7 @@ using MareSynchronos.PlayerData.Handlers;
|
|||
using MareSynchronos.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using CharacterData = MareSynchronos.PlayerData.Data.CharacterData;
|
||||
using Object = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.Object;
|
||||
using Weapon = MareSynchronos.Interop.Weapon;
|
||||
|
||||
namespace MareSynchronos.PlayerData.Factories;
|
||||
|
||||
|
|
@ -26,12 +20,11 @@ public class PlayerDataFactory
|
|||
private readonly IpcManager _ipcManager;
|
||||
private readonly ILogger<PlayerDataFactory> _logger;
|
||||
private readonly PerformanceCollectorService _performanceCollector;
|
||||
private readonly MareConfigService _mareConfigService;
|
||||
private readonly TransientResourceManager _transientResourceManager;
|
||||
|
||||
public PlayerDataFactory(ILogger<PlayerDataFactory> logger, DalamudUtilService dalamudUtil, IpcManager ipcManager,
|
||||
TransientResourceManager transientResourceManager, FileCacheManager fileReplacementFactory,
|
||||
PerformanceCollectorService performanceCollector, MareConfigService mareConfigService)
|
||||
PerformanceCollectorService performanceCollector)
|
||||
{
|
||||
_logger = logger;
|
||||
_dalamudUtil = dalamudUtil;
|
||||
|
|
@ -39,7 +32,6 @@ public class PlayerDataFactory
|
|||
_transientResourceManager = transientResourceManager;
|
||||
_fileCacheManager = fileReplacementFactory;
|
||||
_performanceCollector = performanceCollector;
|
||||
_mareConfigService = mareConfigService;
|
||||
_logger.LogTrace("Creating " + nameof(PlayerDataFactory));
|
||||
}
|
||||
|
||||
|
|
@ -107,190 +99,6 @@ public class PlayerDataFactory
|
|||
previousData.CustomizePlusScale = previousCustomize;
|
||||
}
|
||||
|
||||
private unsafe void AddPlayerSpecificReplacements(Human* human, HashSet<string> forwardResolve, HashSet<string> reverseResolve)
|
||||
{
|
||||
var weaponObject = (Weapon*)((Object*)human)->ChildObject;
|
||||
|
||||
if ((IntPtr)weaponObject != IntPtr.Zero)
|
||||
{
|
||||
var mainHandWeapon = weaponObject->WeaponRenderModel->RenderModel;
|
||||
|
||||
AddReplacementsFromRenderModel((Model*)mainHandWeapon, forwardResolve, reverseResolve);
|
||||
|
||||
foreach (var item in _transientResourceManager.GetTransientResources((IntPtr)weaponObject))
|
||||
{
|
||||
_logger.LogTrace("Found transient weapon resource: {item}", item);
|
||||
forwardResolve.Add(item);
|
||||
}
|
||||
|
||||
if (weaponObject->NextSibling != (IntPtr)weaponObject)
|
||||
{
|
||||
var offHandWeapon = ((Weapon*)weaponObject->NextSibling)->WeaponRenderModel->RenderModel;
|
||||
|
||||
AddReplacementsFromRenderModel((Model*)offHandWeapon, forwardResolve, reverseResolve);
|
||||
|
||||
foreach (var item in _transientResourceManager.GetTransientResources((IntPtr)offHandWeapon))
|
||||
{
|
||||
_logger.LogTrace("Found transient offhand weapon resource: {item}", item);
|
||||
forwardResolve.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddReplacementSkeleton((human)->RaceSexId, forwardResolve);
|
||||
try
|
||||
{
|
||||
AddReplacementsFromTexture((human)->Decal->ResourceHandle.FileName.ToString(), forwardResolve, reverseResolve, doNotReverseResolve: false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogWarning("Could not get Decal data");
|
||||
}
|
||||
try
|
||||
{
|
||||
AddReplacementsFromTexture((human)->LegacyBodyDecal->ResourceHandle.FileName.ToString(), forwardResolve, reverseResolve, doNotReverseResolve: false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogWarning("Could not get Legacy Body Decal Data");
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void AddReplacementsFromMaterial(Material* mtrl, HashSet<string> forwardResolve, HashSet<string> reverseResolve)
|
||||
{
|
||||
string fileName;
|
||||
try
|
||||
{
|
||||
fileName = mtrl->MaterialResourceHandle->ResourceHandle.FileName.ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogWarning("Could not get material data");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogTrace("Checking File Replacement for Material {file}", fileName);
|
||||
var mtrlPath = fileName.Split("|")[2];
|
||||
|
||||
reverseResolve.Add(mtrlPath);
|
||||
|
||||
var mtrlResourceHandle = mtrl->MaterialResourceHandle;
|
||||
for (var resIdx = 0; resIdx < mtrlResourceHandle->TextureCount; resIdx++)
|
||||
{
|
||||
string? texPath = null;
|
||||
try
|
||||
{
|
||||
texPath = mtrlResourceHandle->TexturePathString(resIdx);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogWarning(e, "Could not get Texture data for Material {file}", fileName);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(texPath)) continue;
|
||||
|
||||
AddReplacementsFromTexture(texPath, forwardResolve, reverseResolve);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var shpkPath = "shader/sm5/shpk/" + mtrlResourceHandle->ShpkNameString;
|
||||
_logger.LogTrace("Checking File Replacement for Shader {path}", shpkPath);
|
||||
forwardResolve.Add(shpkPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Could not find shpk for Material {path}", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void AddReplacementsFromRenderModel(Model* mdl, HashSet<string> forwardResolve, HashSet<string> reverseResolve)
|
||||
{
|
||||
if (mdl == null || mdl->ModelResourceHandle == null || (ResourceCategory)mdl->ModelResourceHandle->ResourceHandle.Type.Value != ResourceCategory.Chara)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string mdlPath;
|
||||
try
|
||||
{
|
||||
mdlPath = mdl->ModelResourceHandle->ResourceHandle.FileName.ToString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogWarning("Could not get model data");
|
||||
return;
|
||||
}
|
||||
_logger.LogTrace("Checking File Replacement for Model {path}", mdlPath);
|
||||
|
||||
reverseResolve.Add(mdlPath);
|
||||
|
||||
for (var mtrlIdx = 0; mtrlIdx < mdl->MaterialCount; mtrlIdx++)
|
||||
{
|
||||
var mtrl = mdl->Materials[mtrlIdx];
|
||||
if (mtrl == null) continue;
|
||||
|
||||
AddReplacementsFromMaterial(mtrl, forwardResolve, reverseResolve);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddReplacementsFromTexture(string texPath, HashSet<string> forwardResolve, HashSet<string> reverseResolve, bool doNotReverseResolve = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(texPath)) return;
|
||||
|
||||
_logger.LogTrace("Checking File Replacement for Texture {path}", texPath);
|
||||
|
||||
if (doNotReverseResolve)
|
||||
forwardResolve.Add(texPath);
|
||||
else
|
||||
reverseResolve.Add(texPath);
|
||||
|
||||
if (texPath.Contains("/--", StringComparison.Ordinal)) return;
|
||||
|
||||
var dx11Path = texPath.Insert(texPath.LastIndexOf('/') + 1, "--");
|
||||
if (doNotReverseResolve)
|
||||
forwardResolve.Add(dx11Path);
|
||||
else
|
||||
reverseResolve.Add(dx11Path);
|
||||
}
|
||||
|
||||
private void AddReplacementSkeleton(ushort raceSexId, HashSet<string> forwardResolve)
|
||||
{
|
||||
string raceSexIdString = raceSexId.ToString("0000", CultureInfo.InvariantCulture);
|
||||
|
||||
string skeletonPath = $"chara/human/c{raceSexIdString}/skeleton/base/b0001/skl_c{raceSexIdString}b0001.sklb";
|
||||
|
||||
_logger.LogTrace("Checking skeleton {path}", skeletonPath);
|
||||
|
||||
forwardResolve.Add(skeletonPath);
|
||||
}
|
||||
|
||||
private unsafe (HashSet<string> forwardResolve, HashSet<string> reverseResolve) BuildDataFromModel(ObjectKind objectKind, nint charaPointer, CancellationToken token)
|
||||
{
|
||||
HashSet<string> forwardResolve = new(StringComparer.Ordinal);
|
||||
HashSet<string> reverseResolve = new(StringComparer.Ordinal);
|
||||
var human = (Human*)((Character*)charaPointer)->GameObject.GetDrawObject();
|
||||
for (var mdlIdx = 0; mdlIdx < human->CharacterBase.SlotCount; ++mdlIdx)
|
||||
{
|
||||
var mdl = human->CharacterBase.Models[mdlIdx];
|
||||
if (mdl == null || mdl->ModelResourceHandle == null || (ResourceCategory)mdl->ModelResourceHandle->ResourceHandle.Type.Value != ResourceCategory.Chara)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
AddReplacementsFromRenderModel(mdl, forwardResolve, reverseResolve);
|
||||
}
|
||||
|
||||
if (objectKind == ObjectKind.Player && human->CharacterBase.GetModelType() == CharacterBase.ModelType.Human)
|
||||
{
|
||||
AddPlayerSpecificReplacements(human, forwardResolve, reverseResolve);
|
||||
}
|
||||
|
||||
return (forwardResolve, reverseResolve);
|
||||
}
|
||||
|
||||
private async Task<bool> CheckForNullDrawObject(IntPtr playerPointer)
|
||||
{
|
||||
return await _dalamudUtil.RunOnFrameworkThread(() => CheckForNullDrawObjectUnsafe(playerPointer)).ConfigureAwait(false);
|
||||
|
|
@ -333,17 +141,10 @@ public class PlayerDataFactory
|
|||
|
||||
// penumbra call, it's currently broken
|
||||
IReadOnlyDictionary<string, string[]>? resolvedPaths;
|
||||
if (_mareConfigService.Current.ExperimentalUsePenumbraResourceTree)
|
||||
{
|
||||
resolvedPaths = (await _ipcManager.PenumbraGetCharacterData(_logger, playerRelatedObject).ConfigureAwait(false))![0];
|
||||
if (resolvedPaths == null) throw new InvalidOperationException("Penumbra returned null data");
|
||||
}
|
||||
else
|
||||
{
|
||||
// gather static replacements from render model
|
||||
var (forwardResolve, reverseResolve) = await _dalamudUtil.RunOnFrameworkThread(() => BuildDataFromModel(objectKind, charaPointer, token)).ConfigureAwait(false);
|
||||
resolvedPaths = await GetFileReplacementsFromPaths(forwardResolve, reverseResolve).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
resolvedPaths = (await _ipcManager.PenumbraGetCharacterData(_logger, playerRelatedObject).ConfigureAwait(false))![0];
|
||||
if (resolvedPaths == null) throw new InvalidOperationException("Penumbra returned null data");
|
||||
|
||||
previousData.FileReplacements[objectKind] =
|
||||
new HashSet<FileReplacement>(resolvedPaths.Select(c => new FileReplacement([.. c.Value], c.Key)), FileReplacementComparer.Instance)
|
||||
.Where(p => p.HasFileReplacement).ToHashSet();
|
||||
|
|
|
|||
|
|
@ -600,15 +600,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||
}
|
||||
|
||||
_lastTab = "General";
|
||||
UiSharedService.FontText("Experimental", _uiShared.UidFont);
|
||||
var usePenumbraResolve = _configService.Current.ExperimentalUsePenumbraResourceTree;
|
||||
if (ImGui.Checkbox("Use Penumbra to resolve character", ref usePenumbraResolve))
|
||||
{
|
||||
_configService.Current.ExperimentalUsePenumbraResourceTree = usePenumbraResolve;
|
||||
_configService.Save();
|
||||
}
|
||||
UiSharedService.DrawHelpText("Requires Penumbra version greater equal to 0.8.2.1 - please report issues with that feature to the Penumbra Discord");
|
||||
ImGui.Separator();
|
||||
//UiSharedService.FontText("Experimental", _uiShared.UidFont);
|
||||
//ImGui.Separator();
|
||||
|
||||
UiSharedService.FontText("Notes", _uiShared.UidFont);
|
||||
if (UiSharedService.NormalizedIconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard"))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using MareSynchronos.API.Data.Extensions;
|
|||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.WebAPI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Globalization;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue