mirror of
https://github.com/redstrate/Auracite.git
synced 2025-04-24 05:37:44 +00:00
All of your character's appearance data is now saved, and I've begun the groundwork for exporting it into a client-compatible dat file. If using the Dalamud plugin, the adventurer plate portrait is now exported.
112 lines
No EOL
3.5 KiB
C#
112 lines
No EOL
3.5 KiB
C#
using System;
|
|
using System.IO;
|
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
|
using Lumina.Excel.GeneratedSheets;
|
|
using SharpDX;
|
|
using SharpDX.Direct3D11;
|
|
using SharpDX.DXGI;
|
|
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.Formats.Png;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
|
|
namespace Auracite;
|
|
|
|
public class AdventurerPlateStep : IStep
|
|
{
|
|
public AdventurerPlateStep()
|
|
{
|
|
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
|
|
}
|
|
|
|
public event IStep.CompletedDelegate? Completed;
|
|
|
|
public void Run()
|
|
{
|
|
if (IsInPlateWindow())
|
|
{
|
|
unsafe
|
|
{
|
|
var image = GetCurrentCharaViewImage();
|
|
Plugin.package.portrait = image.ToBase64String(PngFormat.Instance);
|
|
Plugin.package.plate_title = Title?.Feminine; // TODO: Support mascs
|
|
Plugin.package.plate_title_is_prefix = Title?.IsPrefix;
|
|
Plugin.package.plate_class_job = ClassJob?.Name;
|
|
Plugin.package.plate_class_job_level = AgentCharaCard.Instance()->Data->Level;
|
|
Plugin.package.search_comment = AgentCharaCard.Instance()->Data->SearchComment.ToString();
|
|
Completed?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public unsafe Image GetCurrentCharaViewImage()
|
|
{
|
|
var texture = CppObject.FromPointer<Texture2D>((nint)AgentCharaCard.Instance()->Data->PortraitTexture->D3D11Texture2D);
|
|
var device = (Device5)(IntPtr)FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Device.Instance()->D3D11Forwarder;
|
|
|
|
// Copy to a CPU-mapped staging texture
|
|
var desc = texture.Description;
|
|
|
|
using var stagingTexture = new Texture2D(device, new Texture2DDescription()
|
|
{
|
|
ArraySize = 1,
|
|
BindFlags = BindFlags.None,
|
|
CpuAccessFlags = CpuAccessFlags.Read,
|
|
Format = desc.Format,
|
|
Height = desc.Height,
|
|
Width = desc.Width,
|
|
MipLevels = 1,
|
|
OptionFlags = desc.OptionFlags,
|
|
SampleDescription = new SampleDescription(1, 0),
|
|
Usage = ResourceUsage.Staging
|
|
});
|
|
|
|
device.ImmediateContext.CopyResource(texture, stagingTexture);
|
|
|
|
device.ImmediateContext.MapSubresource(stagingTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None, out var dataStream);
|
|
|
|
using var pixelDataStream = new MemoryStream();
|
|
dataStream.CopyTo(pixelDataStream);
|
|
|
|
device.ImmediateContext.UnmapSubresource(stagingTexture, 0);
|
|
|
|
return Image.LoadPixelData<Bgra32>(pixelDataStream.ToArray(), desc.Width, desc.Height);
|
|
}
|
|
|
|
private unsafe Title? Title {
|
|
get {
|
|
ushort titleId = AgentCharaCard.Instance()->Data->TitleId;
|
|
return titleId == 0
|
|
? null
|
|
: Plugin.DataManager.GetExcelSheet<Title>()?.GetRow(titleId);
|
|
}
|
|
}
|
|
|
|
private unsafe ClassJob? ClassJob {
|
|
get {
|
|
ushort classJobId = AgentCharaCard.Instance()->Data->ClassJobId;
|
|
return classJobId == 0
|
|
? null
|
|
: Plugin.DataManager.GetExcelSheet<ClassJob>()?.GetRow(classJobId);
|
|
}
|
|
}
|
|
|
|
public string StepName()
|
|
{
|
|
return "Adventurer Plate";
|
|
}
|
|
|
|
public string StepDescription()
|
|
{
|
|
return "Type /adventurerplate into the chat window or open your Adventurer Plate.";
|
|
}
|
|
|
|
private static unsafe bool IsInPlateWindow()
|
|
{
|
|
return AgentCharaCard.Instance()->AgentInterface.IsAgentActive();
|
|
}
|
|
} |