1
Fork 0
mirror of https://github.com/redstrate/Auracite.git synced 2025-06-30 09:37:45 +00:00

Add support for extracting inventory containers in Dalamud

This commit is contained in:
Joshua Goins 2025-06-28 12:44:29 -04:00
parent aa7c38634d
commit a6edfd903c
6 changed files with 227 additions and 44 deletions

View file

@ -1,34 +0,0 @@
using FFXIVClientStructs.FFXIV.Client.Game;
namespace Auracite;
public class CurrencyStep : IStep
{
public event IStep.CompletedDelegate? Completed;
public void Run()
{
if (Plugin.ClientState.LocalPlayer != null)
{
unsafe
{
Plugin.package.gil = InventoryManager.Instance()->GetGil();
}
}
Completed?.Invoke();
}
public string StepName()
{
return "Currency";
}
public string StepDescription()
{
return "No user action required.";
}
public void Dispose()
{
}
}

View file

@ -0,0 +1,80 @@
using FFXIVClientStructs.FFXIV.Client.Game;
namespace Auracite;
public class InventoryStep : IStep
{
public event IStep.CompletedDelegate? Completed;
public void Run()
{
if (Plugin.ClientState.LocalPlayer != null)
{
unsafe
{
var manager = InventoryManager.Instance();
Plugin.package.inventory1 = ProcessContainer(manager->GetInventoryContainer(InventoryType.Inventory1));
Plugin.package.inventory2 = ProcessContainer(manager->GetInventoryContainer(InventoryType.Inventory2));
Plugin.package.inventory3 = ProcessContainer(manager->GetInventoryContainer(InventoryType.Inventory3));
Plugin.package.inventory4 = ProcessContainer(manager->GetInventoryContainer(InventoryType.Inventory4));
Plugin.package.equipped_items = ProcessContainer(manager->GetInventoryContainer(InventoryType.EquippedItems));
Plugin.package.currency = ProcessContainer(manager->GetInventoryContainer(InventoryType.Currency));
Plugin.package.armory_off_hand = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryOffHand));
Plugin.package.armory_head = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryHead));
Plugin.package.armory_body = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryBody));
Plugin.package.armory_hands = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryHands));
Plugin.package.armory_waist = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryWaist));
Plugin.package.armory_legs = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryLegs));
Plugin.package.armory_ear = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryEar));
Plugin.package.armory_neck = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryNeck));
Plugin.package.armory_wrist = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryWrist));
Plugin.package.armory_rings = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryRings));
Plugin.package.armory_soul_crystal = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmorySoulCrystal));
Plugin.package.armory_main_hand = ProcessContainer(manager->GetInventoryContainer(InventoryType.ArmoryMainHand));
}
}
Completed?.Invoke();
}
private unsafe Auracite.Plugin.InventoryContainer ProcessContainer(FFXIVClientStructs.FFXIV.Client.Game.InventoryContainer *container) {
var serializedContainer = new Auracite.Plugin.InventoryContainer();
serializedContainer.items = new System.Collections.Generic.List<Plugin.InventoryItem>(); // TODO: lol
for (int i = 0; i < container->Size; i++) {
var item = container->GetInventorySlot(i);
if (item != null) {
if (item->GetQuantity() == 0) {
continue;
}
var serializedItem = new Auracite.Plugin.InventoryItem();
serializedItem.condition = item->GetCondition();
serializedItem.id = item->GetBaseItemId();
serializedItem.quantity = item->GetQuantity();
serializedItem.slot = item->GetSlot();
serializedItem.glamour_id = item->GetGlamourId();
serializedContainer.items.Add(serializedItem);
}
}
return serializedContainer;
}
public string StepName()
{
return "Currency";
}
public string StepDescription()
{
return "No user action required.";
}
public void Dispose()
{
}
}

View file

@ -15,17 +15,32 @@ public sealed class Plugin : IDalamudPlugin
private readonly WindowSystem WindowSystem = new("Auracite");
private readonly List<Type> _steps =
[typeof(AppearanceStep), typeof(CurrencyStep), typeof(MiscStep), typeof(PlaytimeStep), typeof(AdventurerPlateStep), typeof(EndStep)];
[typeof(AppearanceStep), typeof(InventoryStep), typeof(MiscStep), typeof(PlaytimeStep), typeof(AdventurerPlateStep), typeof(EndStep)];
private int _stepIndex;
private readonly StepWindow StepWindow;
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class InventoryItem
{
public int slot;
public uint quantity;
public int condition;
public uint id;
public uint glamour_id;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class InventoryContainer
{
public List<InventoryItem> items;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class Package
{
public string? playtime;
public uint gil;
public bool is_battle_mentor;
public bool is_trade_mentor;
public bool is_novice;
@ -74,6 +89,29 @@ public sealed class Plugin : IDalamudPlugin
public string? plate_frame;
public string? accent;
// inventory
public InventoryContainer inventory1;
public InventoryContainer inventory2;
public InventoryContainer inventory3;
public InventoryContainer inventory4;
public InventoryContainer equipped_items;
public InventoryContainer currency;
public InventoryContainer armory_off_hand;
public InventoryContainer armory_head;
public InventoryContainer armory_body;
public InventoryContainer armory_hands;
public InventoryContainer armory_waist;
public InventoryContainer armory_legs;
public InventoryContainer armory_ear;
public InventoryContainer armory_neck;
public InventoryContainer armory_wrist;
public InventoryContainer armory_rings;
public InventoryContainer armory_soul_crystal;
public InventoryContainer armory_main_hand;
public int voice;
}

View file

@ -1,8 +1,11 @@
use serde::Serialize;
use crate::value::{
use crate::{
package::InventoryContainer,
value::{
CityStateValue, ClassJobValue, GenderValue, GrandCompanyValue, GuardianValue, ItemValue,
NamedayValue, RaceValue, TribeValue, WorldValue,
},
};
#[derive(Default, Serialize)]
@ -120,4 +123,45 @@ pub struct CharacterData {
pub face_url: String,
#[serde(skip)]
pub portrait_url: String,
// inventory
#[serde(skip_serializing_if = "Option::is_none")]
pub inventory1: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inventory2: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inventory3: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inventory4: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub equipped_items: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_off_hand: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_head: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_body: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_hands: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_waist: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_legs: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_ear: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_neck: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_wrist: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_rings: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_soul_crystal: Option<InventoryContainer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub armory_main_hand: Option<InventoryContainer>,
}

View file

@ -226,10 +226,29 @@ pub async fn archive_character(id: u64, use_dalamud: bool) -> Result<Vec<u8>, Ar
facepaint_color: package.facepaint_color,
});
char_data.inventory1 = Some(package.inventory1);
char_data.inventory2 = Some(package.inventory2);
char_data.inventory3 = Some(package.inventory3);
char_data.inventory4 = Some(package.inventory4);
char_data.equipped_items = Some(package.equipped_items);
char_data.currency = Some(package.currency);
char_data.armory_off_hand = Some(package.armory_off_hand);
char_data.armory_head = Some(package.armory_head);
char_data.armory_body = Some(package.armory_body);
char_data.armory_hands = Some(package.armory_hands);
char_data.armory_waist = Some(package.armory_waist);
char_data.armory_legs = Some(package.armory_legs);
char_data.armory_ear = Some(package.armory_ear);
char_data.armory_neck = Some(package.armory_neck);
char_data.armory_wrist = Some(package.armory_wrist);
char_data.armory_rings = Some(package.armory_rings);
char_data.armory_soul_crystal = Some(package.armory_soul_crystal);
char_data.armory_main_hand = Some(package.armory_main_hand);
char_data.playtime = Some(package.playtime.parse().unwrap());
char_data.currencies = Some(Currencies {
gil: package.gil, // TODO: also fetch from the lodestone
});
char_data.is_battle_mentor = Some(package.is_battle_mentor);
char_data.is_trade_mentor = Some(package.is_trade_mentor);
char_data.is_novice = Some(package.is_novice);

View file

@ -1,9 +1,22 @@
use serde::Deserialize;
use serde::{Deserialize, Serialize};
#[derive(Default, Deserialize, Serialize, Clone)]
pub struct InventoryItem {
pub slot: i32,
pub quantity: u32,
pub condition: i32,
pub id: u32,
pub glamour_id: u32,
}
#[derive(Default, Deserialize, Serialize, Clone)]
pub struct InventoryContainer {
pub items: Vec<InventoryItem>,
}
#[derive(Default, Deserialize, Clone)]
pub struct Package {
pub playtime: String,
pub gil: u32,
pub is_battle_mentor: bool,
pub is_trade_mentor: bool,
pub is_novice: bool,
@ -52,4 +65,27 @@ pub struct Package {
pub bust_size: i32,
pub facepaint: i32,
pub facepaint_color: i32,
// inventory
pub inventory1: InventoryContainer,
pub inventory2: InventoryContainer,
pub inventory3: InventoryContainer,
pub inventory4: InventoryContainer,
pub equipped_items: InventoryContainer,
pub currency: InventoryContainer,
pub armory_off_hand: InventoryContainer,
pub armory_head: InventoryContainer,
pub armory_body: InventoryContainer,
pub armory_hands: InventoryContainer,
pub armory_waist: InventoryContainer,
pub armory_legs: InventoryContainer,
pub armory_ear: InventoryContainer,
pub armory_neck: InventoryContainer,
pub armory_wrist: InventoryContainer,
pub armory_rings: InventoryContainer,
pub armory_soul_crystal: InventoryContainer,
pub armory_main_hand: InventoryContainer,
}