Chara file data export (#38)

* add rudimentary saving of chara file data

* fix building

* working prototype for MCDF import and application

* adjust code to use streams

* rename cache -> storage
add ui for import/export mcdf

* minor wording adjustments, version bump

Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
Co-authored-by: Stanley Dimant <stanley.dimant@varian.com>
This commit is contained in:
rootdarkarchon
2023-01-23 12:56:43 +01:00
committed by GitHub
parent 1c95a6d40e
commit 7a8655f6b1
15 changed files with 664 additions and 51 deletions

View File

@@ -8,11 +8,14 @@ using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Gui;
using Dalamud.Game.Text.SeStringHandling;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
namespace MareSynchronos.Utils;
public delegate void PlayerChange(Dalamud.Game.ClientState.Objects.Types.Character actor);
@@ -35,8 +38,12 @@ public class DalamudUtil : IDisposable
public event VoidDelegate? DelayedFrameworkUpdate;
public event VoidDelegate? ZoneSwitchStart;
public event VoidDelegate? ZoneSwitchEnd;
public event VoidDelegate? GposeStart;
public event VoidDelegate? GposeEnd;
public event VoidDelegate? GposeFrameworkUpdate;
private DateTime _delayedFrameworkUpdateCheck = DateTime.Now;
private bool _sentBetweenAreas = false;
public bool IsInGpose { get; private set; } = false;
public unsafe bool IsGameObjectPresent(IntPtr key)
{
@@ -84,8 +91,21 @@ public class DalamudUtil : IDisposable
_chatGui.Print(se.BuiltString);
}
private void FrameworkOnUpdate(Framework framework)
private unsafe void FrameworkOnUpdate(Framework framework)
{
if (GposeTarget != null && !IsInGpose)
{
Logger.Debug("Gpose start");
IsInGpose = true;
GposeStart?.Invoke();
}
else if (GposeTarget == null && IsInGpose)
{
Logger.Debug("Gpose end");
IsInGpose = false;
GposeEnd?.Invoke();
}
if (_condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51] || IsInGpose)
{
if (!_sentBetweenAreas)
@@ -95,6 +115,8 @@ public class DalamudUtil : IDisposable
ZoneSwitchStart?.Invoke();
}
if (IsInGpose) GposeFrameworkUpdate?.Invoke();
return;
}
else if (_sentBetweenAreas)
@@ -175,6 +197,10 @@ public class DalamudUtil : IDisposable
return _objectTable.CreateObjectReference(reference);
}
public unsafe GameObject* GposeTarget => TargetSystem.Instance()->GPoseTarget;
public unsafe Dalamud.Game.ClientState.Objects.Types.GameObject? GposeTargetGameObject => GposeTarget == null ? null : _objectTable[GposeTarget->ObjectIndex];
public bool IsLoggedIn { get; private set; }
public bool IsPlayerPresent => _clientState.LocalPlayer != null && _clientState.LocalPlayer.IsValid();
@@ -186,21 +212,21 @@ public class DalamudUtil : IDisposable
public unsafe IntPtr GetMinion()
{
return (IntPtr)((Character*)PlayerPointer)->CompanionObject;
return (IntPtr)((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)PlayerPointer)->CompanionObject;
}
public unsafe IntPtr GetPet(IntPtr? playerPointer = null)
{
var mgr = CharacterManager.Instance();
if (playerPointer == null) playerPointer = PlayerPointer;
return (IntPtr)mgr->LookupPetByOwnerObject((BattleChara*)playerPointer);
return (IntPtr)mgr->LookupPetByOwnerObject((FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara*)playerPointer);
}
public unsafe IntPtr GetCompanion(IntPtr? playerPointer = null)
{
var mgr = CharacterManager.Instance();
if (playerPointer == null) playerPointer = PlayerPointer;
return (IntPtr)mgr->LookupBuddyByOwnerObject((BattleChara*)playerPointer);
return (IntPtr)mgr->LookupBuddyByOwnerObject((FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara*)playerPointer);
}
public string PlayerName => _clientState.LocalPlayer?.Name.ToString() ?? "--";
@@ -211,8 +237,6 @@ public class DalamudUtil : IDisposable
public string PlayerNameHashed => Crypto.GetHash256(PlayerName + _clientState.LocalPlayer!.HomeWorld.Id);
public bool IsInGpose => _objectTable[201] != null;
public List<PlayerCharacter> GetPlayerCharacters()
{
return _objectTable.Where(obj =>
@@ -275,6 +299,30 @@ public class DalamudUtil : IDisposable
Thread.Sleep(tick);
}
public unsafe void DisableDraw(IntPtr characterAddress)
{
var obj = (GameObject*)characterAddress;
obj->DisableDraw();
}
public unsafe void WaitWhileGposeCharacterIsDrawing(IntPtr characterAddress, int timeOut = 5000)
{
Thread.Sleep(500);
var obj = (GameObject*)characterAddress;
const int tick = 250;
int curWaitTime = 0;
Logger.Verbose("RenderFlags:" + obj->RenderFlags.ToString("X"));
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while (obj->RenderFlags != 0x00 && curWaitTime < timeOut)
{
Logger.Verbose($"Waiting for gpose actor to finish drawing");
curWaitTime += tick;
Thread.Sleep(tick);
}
Thread.Sleep(tick * 2);
}
public void Dispose()
{
_clientState.Login -= ClientStateOnLogin;