More stains, more misc fixes

I made my best to try to fix as much as I could. I have no idea if it is correct but I hope it is and I hope this will be helpful for ApiX / Dawntrail update.
This commit is contained in:
Aspher0 2024-07-11 09:21:26 +02:00
parent 8a954e6e09
commit e9d1efccdc
25 changed files with 117 additions and 110 deletions

View file

@ -257,10 +257,10 @@ public class DesignBase
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
{
var item = _designData.Item(slot);
var stain = _designData.Stain(slot);
var stains = _designData.Stain(slot);
var crestSlot = slot.ToCrestFlag();
var crest = _designData.Crest(crestSlot);
ret[slot.ToString()] = Serialize(item.Id, stain, crest, DoApplyEquip(slot), DoApplyStain(slot), DoApplyCrest(crestSlot));
ret[slot.ToString()] = Serialize(item.Id, stains, crest, DoApplyEquip(slot), DoApplyStain(slot), DoApplyCrest(crestSlot));
}
ret["Hat"] = new QuadBool(_designData.IsHatVisible(), DoApplyMeta(MetaIndex.HatState)).ToJObject("Show", "Apply");
@ -274,11 +274,11 @@ public class DesignBase
return ret;
static JObject Serialize(CustomItemId id, StainId stain, bool crest, bool apply, bool applyStain, bool applyCrest)
static JObject Serialize(CustomItemId id, StainIds stains, bool crest, bool apply, bool applyStain, bool applyCrest)
=> new()
{
["ItemId"] = id.Id,
["Stain"] = stain.Id,
["Stain"] = stains.ToString(),
["Crest"] = crest,
["Apply"] = apply,
["ApplyStain"] = applyStain,
@ -522,15 +522,15 @@ public class DesignBase
return;
}
static (CustomItemId, StainId, bool, bool, bool, bool) ParseItem(EquipSlot slot, JToken? item)
static (CustomItemId, StainIds, bool, bool, bool, bool) ParseItem(EquipSlot slot, JToken? item)
{
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot).Id;
var stain = (StainId)(item?["Stain"]?.ToObject<byte>() ?? 0);
var stains = (item?["Stain"]?.ToObject<StainIds>() ?? StainIds.None);
var crest = item?["Crest"]?.ToObject<bool>() ?? false;
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
var applyCrest = item?["ApplyCrest"]?.ToObject<bool>() ?? false;
return (id, stain, crest, apply, applyStain, applyCrest);
return (id, stains, crest, apply, applyStain, applyCrest);
}
void PrintWarning(string msg)
@ -541,13 +541,13 @@ public class DesignBase
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var (id, stain, crest, apply, applyStain, applyCrest) = ParseItem(slot, equip[slot.ToString()]);
var (id, stains, crest, apply, applyStain, applyCrest) = ParseItem(slot, equip[slot.ToString()]);
PrintWarning(items.ValidateItem(slot, id, out var item, allowUnknown));
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
PrintWarning(items.ValidateStain(stains, out stains, allowUnknown));
var crestSlot = slot.ToCrestFlag();
design._designData.SetItem(slot, item);
design._designData.SetStain(slot, stain);
design._designData.SetStain(slot, stains);
design._designData.SetCrest(crestSlot, crest);
design.SetApplyEquip(slot, apply);
design.SetApplyStain(slot, applyStain);

View file

@ -52,10 +52,10 @@ public unsafe struct DesignData
|| name.IsContained(_nameMainhand)
|| name.IsContained(_nameOffhand);
public readonly StainId Stain(EquipSlot slot)
public readonly StainIds Stain(EquipSlot slot)
{
var index = slot.ToIndex();
return index > 11 ? (StainId)0 : _equipmentBytes[4 * index + 3];
return index > 11 ? StainIds.None : new(_equipmentBytes[4 * index + 3], _equipmentBytes[4 * index + 3]);
}
public readonly bool Crest(CrestFlag slot)

View file

@ -167,29 +167,29 @@ public class DesignEditor(
}
/// <inheritdoc/>
public void ChangeStain(object data, EquipSlot slot, StainId stain, ApplySettings _ = default)
public void ChangeStain(object data, EquipSlot slot, StainIds stains, ApplySettings _ = default)
{
var design = (Design)data;
if (Items.ValidateStain(stain, out var _, false).Length > 0)
if (Items.ValidateStain(stains, out var _, false).Length > 0)
return;
var oldStain = design.DesignData.Stain(slot);
if (!design.GetDesignDataRef().SetStain(slot, stain))
if (!design.GetDesignDataRef().SetStain(slot, stains))
return;
design.LastEdit = DateTimeOffset.UtcNow;
SaveService.QueueSave(design);
Glamourer.Log.Debug($"Set stain of {slot} equipment piece to {stain.Id}.");
DesignChanged.Invoke(DesignChanged.Type.Stain, design, (oldStain, stain, slot));
Glamourer.Log.Debug($"Set stain of {slot} equipment piece to {stains}.");
DesignChanged.Invoke(DesignChanged.Type.Stain, design, (oldStain, stains, slot));
}
/// <inheritdoc/>
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainId? stain, ApplySettings _ = default)
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainIds? stains, ApplySettings _ = default)
{
if (item.HasValue)
ChangeItem(data, slot, item.Value, _);
if (stain.HasValue)
ChangeStain(data, slot, stain.Value, _);
if (stains.HasValue)
ChangeStain(data, slot, stains.Value, _);
}
/// <inheritdoc/>
@ -366,4 +366,9 @@ public class DesignEditor(
return true;
}
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainId? stain, ApplySettings settings = default)
{
throw new NotImplementedException();
}
}

View file

@ -65,11 +65,11 @@ public interface IDesignEditor
=> ChangeEquip(data, slot, item, null, settings);
/// <summary> Change the stain for any equipment piece. </summary>
public void ChangeStain(object data, EquipSlot slot, StainId stain, ApplySettings settings = default)
=> ChangeEquip(data, slot, null, stain, settings);
public void ChangeStain(object data, EquipSlot slot, StainIds stains, ApplySettings settings = default)
=> ChangeEquip(data, slot, null, stains, settings);
/// <summary> Change an equipment piece and its stain at the same time. </summary>
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainId? stain, ApplySettings settings = default);
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainIds? stains, ApplySettings settings = default);
/// <summary> Change the crest visibility for any equipment piece. </summary>
public void ChangeCrest(object data, CrestFlag slot, bool crest, ApplySettings settings = default);

View file

@ -11,7 +11,7 @@ namespace Glamourer.Events;
/// </list>
/// </summary>
public sealed class MovedEquipment()
: EventWrapper<(EquipSlot, uint, StainId)[], MovedEquipment.Priority>(nameof(MovedEquipment))
: EventWrapper<(EquipSlot, uint, StainIds)[], MovedEquipment.Priority>(nameof(MovedEquipment))
{
public enum Priority
{

View file

@ -23,8 +23,8 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
public readonly void SetItem(EquipItem item)
=> _editor.ChangeItem(_object, Slot, item, ApplySettings.Manual);
public readonly void SetStain(StainId stain)
=> _editor.ChangeStain(_object, Slot, stain, ApplySettings.Manual);
public readonly void SetStain(StainIds stains)
=> _editor.ChangeStain(_object, Slot, stains, ApplySettings.Manual);
public readonly void SetApplyItem(bool value)
{
@ -41,9 +41,9 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
}
public EquipItem CurrentItem = designData.Item(slot);
public StainId CurrentStain = designData.Stain(slot);
public StainIds CurrentStain = designData.Stain(slot);
public EquipItem GameItem = default;
public StainId GameStain = default;
public StainIds GameStain = default;
public bool CurrentApply;
public bool CurrentApplyStain;

View file

@ -87,8 +87,8 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
{
PrintRow(slot.ToName(), ItemString(state.BaseData, slot), ItemString(state.ModelData, slot), state.Sources[slot, false]);
ImGuiUtil.DrawTableColumn(state.BaseData.Stain(slot).Id.ToString());
ImGuiUtil.DrawTableColumn(state.ModelData.Stain(slot).Id.ToString());
ImGuiUtil.DrawTableColumn($"{state.BaseData.Stain(slot)[0]}, {state.BaseData.Stain(slot)[1]}");
ImGuiUtil.DrawTableColumn($"{state.ModelData.Stain(slot)[0]}, {state.ModelData.Stain(slot)[1]}");
ImGuiUtil.DrawTableColumn(state.Sources[slot, true].ToString());
}

View file

@ -51,7 +51,7 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
using (ImRaii.Group())
{
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)manager:X}");
ImGui.TextUnformatted(manager == null ? "-" : manager->GlamourPlatesSpan.Length.ToString());
ImGui.TextUnformatted(manager == null ? "-" : manager->GlamourPlates.Length.ToString());
ImGui.TextUnformatted(manager == null ? "-" : manager->GlamourPlatesRequested.ToString());
ImGui.SameLine();
if (ImGui.SmallButton("Request Update"))
@ -67,13 +67,13 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
var (identifier, data) = _objects.PlayerData;
var enabled = data.Valid && _state.GetOrCreate(identifier, data.Objects[0], out state);
for (var i = 0; i < manager->GlamourPlatesSpan.Length; ++i)
for (var i = 0; i < manager->GlamourPlates.Length; ++i)
{
using var tree = ImRaii.TreeNode($"Plate #{i + 1:D2}");
if (!tree)
continue;
ref var plate = ref manager->GlamourPlatesSpan[i];
ref var plate = ref manager->GlamourPlates[i];
if (ImGuiUtil.DrawDisabledButton("Apply to Player", Vector2.Zero, string.Empty, !enabled))
{
var design = CreateDesign(plate);
@ -90,7 +90,7 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
using (ImRaii.Group())
{
foreach (var (_, index) in EquipSlotExtensions.FullSlots.WithIndex())
ImGui.TextUnformatted($"{plate.ItemIds[index]:D6}, {plate.StainIds[index]:D3}");
ImGui.TextUnformatted($"{plate.ItemIds[index]:D6}, {plate.Stain0Ids[index]:D3}, {plate.Stain1Ids[index]:D3}");
}
}
}
@ -126,7 +126,7 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
continue;
design.GetDesignDataRef().SetItem(slot, item);
design.GetDesignDataRef().SetStain(slot, plate.StainIds[index]);
design.GetDesignDataRef().SetStain(slot, new(plate.Stain0Ids[index], plate.Stain1Ids[index]));
design.ApplyEquip |= slot.ToBothFlags();
}

View file

@ -43,8 +43,8 @@ public unsafe class InventoryPanel : IGameDataDrawer
}
else
{
ImGuiUtil.DrawTableColumn(item->ItemID.ToString());
ImGuiUtil.DrawTableColumn(item->GlamourID.ToString());
ImGuiUtil.DrawTableColumn(item->ItemId.ToString());
ImGuiUtil.DrawTableColumn(item->GlamourId.ToString());
ImGui.TableNextColumn();
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)item:X}");
}

View file

@ -453,7 +453,7 @@ public class DesignPanel
}
private static unsafe string GetUserPath()
=> Framework.Instance()->UserPath;
=> Framework.Instance()->UserPathString;
private sealed class LockButton(DesignPanel panel) : Button

View file

@ -233,7 +233,7 @@ public class UnlockOverview
ImGui.TextUnformatted($"For all {_jobs.AllJobGroups[item.JobRestrictions.Id].Name} of at least Level {item.Level}");
}
if (item.Flags.HasFlag(ItemFlags.IsDyable))
if (item.Flags.HasFlag(ItemFlags.IsDyable1))
ImGui.TextUnformatted("Dyable");
if (item.Flags.HasFlag(ItemFlags.IsTradable))
ImGui.TextUnformatted("Tradable");

View file

@ -384,7 +384,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
=> Tooltip = "Whether the item is dyable.";
protected override bool GetValue(EquipItem item)
=> item.Flags.HasFlag(ItemFlags.IsDyable);
=> item.Flags.HasFlag(ItemFlags.IsDyable1);
}
private sealed class TradableColumn : YesNoColumn<EquipItem>

View file

@ -36,7 +36,7 @@ public unsafe class ChangeCustomizeService : EventWrapperRef2<Model, CustomizeAr
_penumbraReloaded = penumbraReloaded;
_interop = interop;
_changeCustomizeHook = Create();
_original = Human.MemberFunctionPointers.UpdateDrawData;
_original = (delegate* unmanaged[Stdcall]<Human*, byte*, bool, bool>)Human.MemberFunctionPointers.UpdateDrawData;
interop.InitializeFromAttributes(this);
_penumbraReloaded.Subscribe(Restore, PenumbraReloaded.Priority.ChangeCustomizeService);
}

View file

@ -60,7 +60,7 @@ public sealed class CharaFile
return;
data.SetItem(slot, item);
data.SetStain(slot, dye);
data.SetStain(slot, new(dye, dye));
flags |= slot.ToFlag();
flags |= slot.ToStainFlag();
}
@ -79,7 +79,7 @@ public sealed class CharaFile
return;
data.SetItem(slot, item);
data.SetStain(slot, dye);
data.SetStain(slot, new(dye, dye));
flags |= slot.ToFlag();
flags |= slot.ToStainFlag();
}

View file

@ -96,7 +96,7 @@ public sealed class CmaFile
if (offhand == null)
{
data.SetItem(EquipSlot.MainHand, defaultOffhand);
data.SetStain(EquipSlot.MainHand, defaultOffhand.PrimaryId.Id == 0 ? 0 : data.Stain(EquipSlot.MainHand));
data.SetStain(EquipSlot.MainHand, defaultOffhand.PrimaryId.Id == 0 ? StainIds.None : data.Stain(EquipSlot.MainHand));
return;
}

View file

@ -96,7 +96,7 @@ public sealed unsafe class CrestService : EventWrapperRef3<Actor, CrestFlag, boo
if (!model.IsHuman)
return false;
var getter = (delegate* unmanaged<Human*, byte, byte>)((nint*)model.AsCharacterBase->VTable)[95];
var getter = (delegate* unmanaged<Human*, byte, byte>)((nint*)model.AsCharacterBase->VirtualTable)[95];
return getter(model.AsHuman, index) != 0;
}
case CrestType.Offhand:
@ -105,7 +105,7 @@ public sealed unsafe class CrestService : EventWrapperRef3<Actor, CrestFlag, boo
if (!model.IsWeapon)
return false;
var getter = (delegate* unmanaged<Weapon*, byte, byte>)((nint*)model.AsCharacterBase->VTable)[95];
var getter = (delegate* unmanaged<Weapon*, byte, byte>)((nint*)model.AsCharacterBase->VirtualTable)[95];
return getter(model.AsWeapon, index) != 0;
}
}

View file

@ -14,7 +14,7 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService
{
private readonly MovedEquipment _movedItemsEvent;
private readonly EquippedGearset _gearsetEvent;
private readonly List<(EquipSlot, uint, StainId)> _itemList = new(12);
private readonly List<(EquipSlot, uint, StainIds)> _itemList = new(12);
public InventoryService(MovedEquipment movedItemsEvent, IGameInteropProvider interop, EquippedGearset gearsetEvent)
{
@ -60,56 +60,56 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService
if (glamourPlateId != 0)
{
void Add(EquipSlot slot, uint glamourId, StainId glamourStain, ref RaptureGearsetModule.GearsetItem item)
void Add(EquipSlot slot, uint glamourId, StainId glamourStain1, StainId glamourStain2, ref RaptureGearsetModule.GearsetItem item)
{
if (item.ItemID == 0)
_itemList.Add((slot, 0, 0));
if (item.ItemId == 0)
_itemList.Add((slot, 0, new(0, 0)));
else if (glamourId != 0)
_itemList.Add((slot, glamourId, glamourStain));
_itemList.Add((slot, glamourId, new(glamourStain1, glamourStain2)));
else if (item.GlamourId != 0)
_itemList.Add((slot, item.GlamourId, item.Stain));
_itemList.Add((slot, item.GlamourId, new(item.Stain0Id, item.Stain1Id)));
else
_itemList.Add((slot, FixId(item.ItemID), item.Stain));
_itemList.Add((slot, FixId(item.ItemId), new(item.Stain0Id, item.Stain1Id)));
}
var plate = MirageManager.Instance()->GlamourPlatesSpan[glamourPlateId - 1];
Add(EquipSlot.MainHand, plate.ItemIds[0], plate.StainIds[0], ref entry->ItemsSpan[0]);
Add(EquipSlot.OffHand, plate.ItemIds[1], plate.StainIds[1], ref entry->ItemsSpan[1]);
Add(EquipSlot.Head, plate.ItemIds[2], plate.StainIds[2], ref entry->ItemsSpan[2]);
Add(EquipSlot.Body, plate.ItemIds[3], plate.StainIds[3], ref entry->ItemsSpan[3]);
Add(EquipSlot.Hands, plate.ItemIds[4], plate.StainIds[4], ref entry->ItemsSpan[5]);
Add(EquipSlot.Legs, plate.ItemIds[5], plate.StainIds[5], ref entry->ItemsSpan[6]);
Add(EquipSlot.Feet, plate.ItemIds[6], plate.StainIds[6], ref entry->ItemsSpan[7]);
Add(EquipSlot.Ears, plate.ItemIds[7], plate.StainIds[7], ref entry->ItemsSpan[8]);
Add(EquipSlot.Neck, plate.ItemIds[8], plate.StainIds[8], ref entry->ItemsSpan[9]);
Add(EquipSlot.Wrists, plate.ItemIds[9], plate.StainIds[9], ref entry->ItemsSpan[10]);
Add(EquipSlot.RFinger, plate.ItemIds[10], plate.StainIds[10], ref entry->ItemsSpan[11]);
Add(EquipSlot.LFinger, plate.ItemIds[11], plate.StainIds[11], ref entry->ItemsSpan[12]);
var plate = MirageManager.Instance()->GlamourPlates[glamourPlateId - 1];
Add(EquipSlot.MainHand, plate.ItemIds[0], plate.Stain0Ids[0], plate.Stain1Ids[0], ref entry->Items[0]);
Add(EquipSlot.OffHand, plate.ItemIds[1], plate.Stain0Ids[1], plate.Stain1Ids[1], ref entry->Items[1]);
Add(EquipSlot.Head, plate.ItemIds[2], plate.Stain0Ids[2], plate.Stain1Ids[2], ref entry->Items[2]);
Add(EquipSlot.Body, plate.ItemIds[3], plate.Stain0Ids[3], plate.Stain1Ids[3], ref entry->Items[3]);
Add(EquipSlot.Hands, plate.ItemIds[4], plate.Stain0Ids[4], plate.Stain1Ids[4], ref entry->Items[5]);
Add(EquipSlot.Legs, plate.ItemIds[5], plate.Stain0Ids[5], plate.Stain1Ids[5], ref entry->Items[6]);
Add(EquipSlot.Feet, plate.ItemIds[6], plate.Stain0Ids[6], plate.Stain1Ids[6], ref entry->Items[7]);
Add(EquipSlot.Ears, plate.ItemIds[7], plate.Stain0Ids[7], plate.Stain1Ids[7], ref entry->Items[8]);
Add(EquipSlot.Neck, plate.ItemIds[8], plate.Stain0Ids[8], plate.Stain1Ids[8], ref entry->Items[9]);
Add(EquipSlot.Wrists, plate.ItemIds[9], plate.Stain0Ids[9], plate.Stain1Ids[9], ref entry->Items[10]);
Add(EquipSlot.RFinger, plate.ItemIds[10], plate.Stain0Ids[10], plate.Stain1Ids[10], ref entry->Items[11]);
Add(EquipSlot.LFinger, plate.ItemIds[11], plate.Stain0Ids[11], plate.Stain1Ids[11], ref entry->Items[12]);
}
else
{
void Add(EquipSlot slot, ref RaptureGearsetModule.GearsetItem item)
{
if (item.ItemID == 0)
_itemList.Add((slot, 0, 0));
if (item.ItemId == 0)
_itemList.Add((slot, 0, new(0, 0)));
else if (item.GlamourId != 0)
_itemList.Add((slot, item.GlamourId, item.Stain));
_itemList.Add((slot, item.GlamourId, new(item.Stain0Id, item.Stain1Id)));
else
_itemList.Add((slot, FixId(item.ItemID), item.Stain));
_itemList.Add((slot, FixId(item.ItemId), new(item.Stain0Id, item.Stain1Id)));
}
Add(EquipSlot.MainHand, ref entry->ItemsSpan[0]);
Add(EquipSlot.OffHand, ref entry->ItemsSpan[1]);
Add(EquipSlot.Head, ref entry->ItemsSpan[2]);
Add(EquipSlot.Body, ref entry->ItemsSpan[3]);
Add(EquipSlot.Hands, ref entry->ItemsSpan[5]);
Add(EquipSlot.Legs, ref entry->ItemsSpan[6]);
Add(EquipSlot.Feet, ref entry->ItemsSpan[7]);
Add(EquipSlot.Ears, ref entry->ItemsSpan[8]);
Add(EquipSlot.Neck, ref entry->ItemsSpan[9]);
Add(EquipSlot.Wrists, ref entry->ItemsSpan[10]);
Add(EquipSlot.RFinger, ref entry->ItemsSpan[11]);
Add(EquipSlot.LFinger, ref entry->ItemsSpan[12]);
Add(EquipSlot.MainHand, ref entry->Items[0]);
Add(EquipSlot.OffHand, ref entry->Items[1]);
Add(EquipSlot.Head, ref entry->Items[2]);
Add(EquipSlot.Body, ref entry->Items[3]);
Add(EquipSlot.Hands, ref entry->Items[5]);
Add(EquipSlot.Legs, ref entry->Items[6]);
Add(EquipSlot.Feet, ref entry->Items[7]);
Add(EquipSlot.Ears, ref entry->Items[8]);
Add(EquipSlot.Neck, ref entry->Items[9]);
Add(EquipSlot.Wrists, ref entry->Items[10]);
Add(EquipSlot.RFinger, ref entry->Items[11]);
Add(EquipSlot.LFinger, ref entry->Items[12]);
}
_movedItemsEvent.Invoke(_itemList.ToArray());
@ -155,7 +155,7 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService
return ret;
}
private static bool InvokeSource(InventoryType sourceContainer, uint sourceSlot, out (EquipSlot, uint, StainId) tuple)
private static bool InvokeSource(InventoryType sourceContainer, uint sourceSlot, out (EquipSlot, uint, StainIds) tuple)
{
tuple = default;
if (sourceContainer is not InventoryType.EquippedItems)
@ -165,12 +165,12 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService
if (slot is EquipSlot.Unknown)
return false;
tuple = (slot, 0u, 0);
tuple = (slot, 0u, StainIds.None);
return true;
}
private static bool InvokeTarget(InventoryManager* manager, InventoryType targetContainer, uint targetSlot,
out (EquipSlot, uint, StainId) tuple)
out (EquipSlot, uint, StainIds) tuple)
{
tuple = default;
if (targetContainer is not InventoryType.EquippedItems)
@ -189,7 +189,7 @@ public sealed unsafe class InventoryService : IDisposable, IRequiredService
if (item == null)
return false;
tuple = (slot, item->GlamourID != 0 ? item->GlamourID : item->ItemID, item->Stain);
tuple = (slot, item->GlamourId != 0 ? item->GlamourId : item->ItemId, new(item->Stains[0], item->Stains[1]));
return true;
}

View file

@ -48,12 +48,14 @@ public unsafe class MetaService : IDisposable
if (!actor.IsCharacter)
return;
actor.AsCharacter->DrawData.SetVisor(value);
// The function seems to not do anything if the head is 0, but also breaks for carbuncles turned human, sometimes?
var old = actor.AsCharacter->DrawData.Head.Id;
/* var old = actor.AsCharacter->DrawData.Head.Id;
if (old == 0 && actor.AsCharacter->CharacterData.ModelCharaId == 0)
actor.AsCharacter->DrawData.Head.Id = 1;
_hideHatGearHook.Original(&actor.AsCharacter->DrawData, 0, (byte)(value ? 0 : 1));
actor.AsCharacter->DrawData.Head.Id = old;
actor.AsCharacter->DrawData.Head.Id = old; */
}
public void SetWeaponState(Actor actor, bool value)

View file

@ -164,7 +164,7 @@ public sealed class CollectionOverrideService : IService, ISavable
var collection = _penumbra.CollectionByIdentifier(collectionIdentifier);
if (collection == null)
{
Glamourer.Messager.AddMessage(new Notification(
Glamourer.Messager.AddMessage(new OtterGui.Classes.Notification(
$"The overridden collection for identifier {identifier.Incognito(null)} with name {collectionIdentifier} could not be found by Penumbra for migration.",
NotificationType.Warning));
continue;

View file

@ -195,16 +195,16 @@ public class ItemManager
/// The returned stain id is either the input or 0.
/// The return value is an empty string if there was no problem and a warning otherwise.
/// </summary>
public string ValidateStain(StainId stain, out StainId ret, bool allowUnknown)
public string ValidateStain(StainIds stains, out StainIds ret, bool allowUnknown)
{
if (allowUnknown || IsStainValid(stain))
if (allowUnknown || IsStainValid(stains[0]) && IsStainValid(stains[1]))
{
ret = stain;
ret = stains;
return string.Empty;
}
ret = 0;
return $"The Stain {stain} does not exist, reset to unstained.";
ret = StainIds.None;
return $"The Stains {stains} does not exist, reset to unstained.";
}
/// <summary> Returns whether an offhand is valid given the required offhand type. </summary>

View file

@ -152,11 +152,11 @@ public class InternalStateEditor(
}
/// <summary> Change a single piece of equipment including stain. </summary>
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateSource source, out EquipItem oldItem,
out StainId oldStain, uint key = 0)
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainIds stains, StateSource source, out EquipItem oldItem,
out StainIds oldStains, uint key = 0)
{
oldItem = state.ModelData.Item(slot);
oldStain = state.ModelData.Stain(slot);
oldStains = state.ModelData.Stain(slot);
if (!state.CanUnlock(key))
return false;
@ -168,7 +168,7 @@ public class InternalStateEditor(
return false;
var old = oldItem;
var oldS = oldStain;
var oldS = oldStains;
gPose.AddActionOnLeave(() =>
{
if (old.Type == state.BaseData.Item(slot).Type)
@ -177,16 +177,16 @@ public class InternalStateEditor(
}
state.ModelData.SetItem(slot, item);
state.ModelData.SetStain(slot, stain);
state.ModelData.SetStain(slot, stains);
state.Sources[slot, false] = source;
state.Sources[slot, true] = source;
return true;
}
/// <summary> Change only the stain of an equipment piece. </summary>
public bool ChangeStain(ActorState state, EquipSlot slot, StainIds stains, StateSource source, out StainId oldStain, uint key = 0)
public bool ChangeStain(ActorState state, EquipSlot slot, StainIds stains, StateSource source, out StainIds oldStains, uint key = 0)
{
oldStain = state.ModelData.Stain(slot);
oldStains = state.ModelData.Stain(slot);
if (!state.CanUnlock(key))
return false;

View file

@ -118,7 +118,7 @@ public class StateEditor(
ApplyMainhandPeriphery(state, item, stains, settings);
Glamourer.Log.Verbose(
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item!.Value.Name} ({item.Value.ItemId}) and its stain from {oldStain.Id} to {stain!.Value.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item!.Value.Name} ({item.Value.ItemId}) and its stains from {oldStain[0]},{oldStain[1]} to {stains!.Value[0]}, {stains!.Value[1]}. [Affecting {actors.ToLazyString("nothing")}.]");
StateChanged.Invoke(type, settings.Source, state, actors, (old, item!.Value, slot));
StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (oldStain, stains!.Value, slot));
}
@ -132,7 +132,7 @@ public class StateEditor(
var actors = Applier.ChangeStain(state, slot, settings.Source.RequiresChange());
Glamourer.Log.Verbose(
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stains.ToString()}. [Affecting {actors.ToLazyString("nothing")}.]");
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old[0]},{old[1]} to {stains.ToString()}. [Affecting {actors.ToLazyString("nothing")}.]");
StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (old, stains, slot));
}

View file

@ -227,14 +227,14 @@ public class StateListener : IDisposable
(_, armor) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
}
private void OnMovedEquipment((EquipSlot, uint, StainId)[] items)
private void OnMovedEquipment((EquipSlot, uint, StainIds)[] items)
{
_objects.Update();
var (identifier, objects) = _objects.PlayerData;
if (!identifier.IsValid || !_manager.TryGetValue(identifier, out var state))
return;
foreach (var (slot, item, stain) in items)
foreach (var (slot, item, stains) in items)
{
var currentItem = state.BaseData.Item(slot);
var model = slot is EquipSlot.MainHand or EquipSlot.OffHand
@ -244,7 +244,7 @@ public class StateListener : IDisposable
if (model.Value == current.Value || !_items.ItemData.TryGetValue(item, EquipSlot.MainHand, out var changedItem))
continue;
var changed = changedItem.Weapon(stain);
var changed = changedItem.Weapon(stains);
var itemChanged = current.Skeleton == changed.Skeleton
&& current.Variant == changed.Variant
&& current.Weapon == changed.Weapon

View file

@ -174,7 +174,7 @@ public class CustomizeUnlockManager : IDisposable, ISavable
IDataManager gameData)
{
var ret = new Dictionary<CustomizeData, (uint Data, string Name)>();
var sheet = gameData.GetExcelSheet<CharaMakeCustomize>(ClientLanguage.English)!;
var sheet = gameData.GetExcelSheet<CharaMakeCustomize>(Dalamud.Game.ClientLanguage.English)!;
foreach (var (clan, gender) in CustomizeManager.AllSets())
{
var list = customizations.Manager.GetSet(clan, gender);

View file

@ -154,7 +154,7 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
if (newPlateState != _lastPlateState)
{
_lastPlateState = newPlateState;
foreach (var plate in mirageManager->GlamourPlatesSpan)
foreach (var plate in mirageManager->GlamourPlates)
{
// TODO: Make independent from hardcoded value
var span = new ReadOnlySpan<uint>(plate.ItemIds, 12);
@ -176,8 +176,8 @@ public class ItemUnlockManager : ISavable, IDisposable, IReadOnlyDictionary<Item
var item = container->GetInventorySlot(_currentInventoryIndex++);
if (item != null)
{
changes |= AddItem(item->ItemID, time);
changes |= AddItem(item->GlamourID, time);
changes |= AddItem(item->ItemId, time);
changes |= AddItem(item->GlamourId, time);
}
}
else