147 lines
6.2 KiB
C#
147 lines
6.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
|
using MareSynchronos.Managers;
|
|
using MareSynchronos.Models;
|
|
using MareSynchronos.Utils;
|
|
using Penumbra.GameData.ByteString;
|
|
using Penumbra.Interop.Structs;
|
|
using Human = MareSynchronos.Interop.Human;
|
|
|
|
namespace MareSynchronos.Factories
|
|
{
|
|
public class CharacterDataFactory
|
|
{
|
|
private readonly DalamudUtil _dalamudUtil;
|
|
private readonly IpcManager _ipcManager;
|
|
|
|
public CharacterDataFactory(DalamudUtil dalamudUtil, IpcManager ipcManager)
|
|
{
|
|
Logger.Debug("Creating " + nameof(CharacterDataFactory));
|
|
|
|
_dalamudUtil = dalamudUtil;
|
|
_ipcManager = ipcManager;
|
|
}
|
|
|
|
private FileReplacement CreateFileReplacement(string path, bool doNotReverseResolve = false)
|
|
{
|
|
var fileReplacement = new FileReplacement(_ipcManager.PenumbraModDirectory()!);
|
|
if (!doNotReverseResolve)
|
|
{
|
|
fileReplacement.GamePaths =
|
|
_ipcManager.PenumbraReverseResolvePath(path, _dalamudUtil.PlayerName).ToList();
|
|
fileReplacement.SetResolvedPath(path);
|
|
}
|
|
else
|
|
{
|
|
fileReplacement.GamePaths = new List<string> { path };
|
|
fileReplacement.SetResolvedPath(_ipcManager.PenumbraResolvePath(path, _dalamudUtil.PlayerName)!);
|
|
}
|
|
|
|
return fileReplacement;
|
|
}
|
|
|
|
public CharacterData BuildCharacterData()
|
|
{
|
|
if (!_ipcManager.Initialized)
|
|
{
|
|
throw new ArgumentException("Penumbra is not connected");
|
|
}
|
|
|
|
return CreateCharacterData();
|
|
}
|
|
|
|
private unsafe CharacterData CreateCharacterData()
|
|
{
|
|
Stopwatch st = Stopwatch.StartNew();
|
|
while (!_dalamudUtil.IsPlayerPresent)
|
|
{
|
|
Logger.Debug("Character is null but it shouldn't be, waiting");
|
|
Thread.Sleep(50);
|
|
}
|
|
_dalamudUtil.WaitWhileCharacterIsDrawing(_dalamudUtil.PlayerPointer);
|
|
var cache = new CharacterData
|
|
{
|
|
JobId = _dalamudUtil.PlayerJobId,
|
|
GlamourerString = _ipcManager.GlamourerGetCharacterCustomization(_dalamudUtil.PlayerCharacter),
|
|
ManipulationString = _ipcManager.PenumbraGetMetaManipulations(_dalamudUtil.PlayerName)
|
|
};
|
|
var drawObject = (Human*)((Character*)_dalamudUtil.PlayerPointer)->GameObject.GetDrawObject();
|
|
for (var mdlIdx = 0; mdlIdx < drawObject->CharacterBase.SlotCount; ++mdlIdx)
|
|
{
|
|
var mdl = (RenderModel*)drawObject->CharacterBase.ModelArray[mdlIdx];
|
|
if (mdl == null || mdl->ResourceHandle == null || mdl->ResourceHandle->Category != ResourceCategory.Chara)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var mdlPath = new Utf8String(mdl->ResourceHandle->FileName()).ToString();
|
|
|
|
FileReplacement mdlFileReplacement = CreateFileReplacement(mdlPath);
|
|
Logger.Debug("Model " + string.Join(", ", mdlFileReplacement.GamePaths));
|
|
Logger.Debug("\t\t=> " + mdlFileReplacement.ResolvedPath);
|
|
|
|
cache.AddFileReplacement(mdlFileReplacement);
|
|
|
|
for (var mtrlIdx = 0; mtrlIdx < mdl->MaterialCount; mtrlIdx++)
|
|
{
|
|
var mtrl = (Material*)mdl->Materials[mtrlIdx];
|
|
if (mtrl == null) continue;
|
|
|
|
var mtrlPath = new Utf8String(mtrl->ResourceHandle->FileName()).ToString().Split("|")[2];
|
|
|
|
var mtrlFileReplacement = CreateFileReplacement(mtrlPath);
|
|
Logger.Debug("\tMaterial " + string.Join(", ", mtrlFileReplacement.GamePaths));
|
|
Logger.Debug("\t\t\t=> " + mtrlFileReplacement.ResolvedPath);
|
|
|
|
cache.AddFileReplacement(mtrlFileReplacement);
|
|
|
|
var mtrlResourceHandle = (MtrlResource*)mtrl->ResourceHandle;
|
|
for (var resIdx = 0; resIdx < mtrlResourceHandle->NumTex; resIdx++)
|
|
{
|
|
var texPath = new Utf8String(mtrlResourceHandle->TexString(resIdx)).ToString();
|
|
|
|
if (string.IsNullOrEmpty(texPath)) continue;
|
|
|
|
var texFileReplacement = CreateFileReplacement(texPath, true);
|
|
Logger.Debug("\t\tTexture " + string.Join(", ", texFileReplacement.GamePaths));
|
|
Logger.Debug("\t\t\t\t=> " + texFileReplacement.ResolvedPath);
|
|
|
|
cache.AddFileReplacement(texFileReplacement);
|
|
|
|
if (texPath.Contains("/--")) continue;
|
|
|
|
var texDoubleMinusFileReplacement =
|
|
CreateFileReplacement(texPath.Insert(texPath.LastIndexOf('/') + 1, "--"), true);
|
|
|
|
Logger.Debug("\t\tTexture-- " + string.Join(", ", texDoubleMinusFileReplacement.GamePaths));
|
|
Logger.Debug("\t\t\t\t=> " + texDoubleMinusFileReplacement.ResolvedPath);
|
|
cache.AddFileReplacement(texDoubleMinusFileReplacement);
|
|
}
|
|
}
|
|
}
|
|
|
|
var tattooDecalFileReplacement =
|
|
CreateFileReplacement(new Utf8String(drawObject->Decal->FileName()).ToString());
|
|
cache.AddFileReplacement(tattooDecalFileReplacement);
|
|
Logger.Debug("Decal " + string.Join(", ", tattooDecalFileReplacement.GamePaths));
|
|
Logger.Debug("\t\t=> " + tattooDecalFileReplacement.ResolvedPath);
|
|
|
|
var legacyDecalFileReplacement =
|
|
CreateFileReplacement(new Utf8String(drawObject->LegacyBodyDecal->FileName()).ToString());
|
|
cache.AddFileReplacement(legacyDecalFileReplacement);
|
|
Logger.Debug("Legacy Decal " + string.Join(", ", legacyDecalFileReplacement.GamePaths));
|
|
Logger.Debug("\t\t=> " + legacyDecalFileReplacement.ResolvedPath);
|
|
|
|
st.Stop();
|
|
Logger.Verbose("Building Character Data took " + st.Elapsed);
|
|
|
|
return cache;
|
|
}
|
|
}
|
|
}
|