107 lines
4.5 KiB
C#
107 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Dalamud.Game.ClientState;
|
|
using Dalamud.Logging;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
|
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
|
using MareSynchronos.Managers;
|
|
using MareSynchronos.Models;
|
|
using Penumbra.GameData.ByteString;
|
|
using Penumbra.Interop.Structs;
|
|
|
|
namespace MareSynchronos.Factories
|
|
{
|
|
public class CharacterCacheFactory
|
|
{
|
|
private readonly ClientState _clientState;
|
|
private readonly IpcManager _ipcManager;
|
|
private readonly FileReplacementFactory _factory;
|
|
|
|
public CharacterCacheFactory(ClientState clientState, IpcManager ipcManager, FileReplacementFactory factory)
|
|
{
|
|
_clientState = clientState;
|
|
_ipcManager = ipcManager;
|
|
_factory = factory;
|
|
}
|
|
|
|
private string GetPlayerName()
|
|
{
|
|
return _clientState.LocalPlayer!.Name.ToString();
|
|
}
|
|
|
|
public unsafe CharacterCache BuildCharacterCache()
|
|
{
|
|
var cache = new CharacterCache();
|
|
|
|
while (_clientState.LocalPlayer == null)
|
|
{
|
|
PluginLog.Debug("Character is null but it shouldn't be, waiting");
|
|
Thread.Sleep(50);
|
|
}
|
|
var model = (CharacterBase*)((Character*)_clientState.LocalPlayer!.Address)->GameObject.GetDrawObject();
|
|
for (var idx = 0; idx < model->SlotCount; ++idx)
|
|
{
|
|
var mdl = (RenderModel*)model->ModelArray[idx];
|
|
if (mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var mdlPath = new Utf8String(mdl->ResourceHandle->FileName()).ToString();
|
|
|
|
FileReplacement cachedMdlResource = _factory.Create();
|
|
cachedMdlResource.GamePaths = _ipcManager.PenumbraReverseResolvePath(mdlPath, GetPlayerName());
|
|
cachedMdlResource.SetResolvedPath(mdlPath);
|
|
//PluginLog.Verbose("Resolving for model " + mdlPath);
|
|
|
|
cache.AddAssociatedResource(cachedMdlResource, null!, null!);
|
|
|
|
for (int mtrlIdx = 0; mtrlIdx < mdl->MaterialCount; mtrlIdx++)
|
|
{
|
|
var mtrl = (Material*)mdl->Materials[mtrlIdx];
|
|
if (mtrl == null) continue;
|
|
|
|
//var mtrlFileResource = factory.Create();
|
|
var mtrlPath = new Utf8String(mtrl->ResourceHandle->FileName()).ToString().Split("|")[2];
|
|
//PluginLog.Verbose("Resolving for material " + mtrlPath);
|
|
var cachedMtrlResource = _factory.Create();
|
|
cachedMtrlResource.GamePaths = _ipcManager.PenumbraReverseResolvePath(mtrlPath, GetPlayerName());
|
|
cachedMtrlResource.SetResolvedPath(mtrlPath);
|
|
cache.AddAssociatedResource(cachedMtrlResource, cachedMdlResource, null!);
|
|
|
|
var mtrlResource = (MtrlResource*)mtrl->ResourceHandle;
|
|
for (int resIdx = 0; resIdx < mtrlResource->NumTex; resIdx++)
|
|
{
|
|
var texPath = new Utf8String(mtrlResource->TexString(resIdx)).ToString();
|
|
|
|
if (string.IsNullOrEmpty(texPath.ToString())) continue;
|
|
|
|
var cachedTexResource = _factory.Create();
|
|
cachedTexResource.GamePaths = new[] { texPath };
|
|
cachedTexResource.SetResolvedPath(_ipcManager.PenumbraResolvePath(texPath, GetPlayerName())!);
|
|
if (!cachedTexResource.HasFileReplacement)
|
|
{
|
|
// try resolving tex with -- in name instead
|
|
texPath = texPath.Insert(texPath.LastIndexOf('/') + 1, "--");
|
|
var reResolvedPath = _ipcManager.PenumbraResolvePath(texPath, GetPlayerName())!;
|
|
if (reResolvedPath != texPath)
|
|
{
|
|
cachedTexResource.GamePaths = new[] { texPath };
|
|
cachedTexResource.SetResolvedPath(reResolvedPath);
|
|
}
|
|
}
|
|
cache.AddAssociatedResource(cachedTexResource, cachedMdlResource, cachedMtrlResource);
|
|
}
|
|
}
|
|
}
|
|
|
|
return cache;
|
|
}
|
|
}
|
|
}
|