diff --git a/Glamourer/Designs/DesignData.cs b/Glamourer/Designs/DesignData.cs
index 935f80b..7570b11 100644
--- a/Glamourer/Designs/DesignData.cs
+++ b/Glamourer/Designs/DesignData.cs
@@ -205,15 +205,14 @@ public unsafe struct DesignData
}
- public bool LoadNonHuman(uint modelId, Customize customize, byte* equipData)
+ public bool LoadNonHuman(uint modelId, Customize customize, nint equipData)
{
ModelId = modelId;
IsHuman = false;
Customize.Load(customize);
fixed (byte* ptr = _equipmentBytes)
{
- MemoryUtility.MemCpyUnchecked(ptr, equipData, 40);
- MemoryUtility.MemSet(ptr + 40, 0, 8);
+ MemoryUtility.MemCpyUnchecked(ptr, (byte*) equipData, 40);
}
SetHatVisible(true);
@@ -221,19 +220,14 @@ public unsafe struct DesignData
SetVisor(false);
fixed (uint* ptr = _itemIds)
{
- MemoryUtility.MemSet(ptr, 0, 12 * 4);
+ MemoryUtility.MemSet(ptr, 0, 10 * 4);
}
fixed (ushort* ptr = _iconIds)
{
- MemoryUtility.MemSet(ptr, 0, 12 * 2);
+ MemoryUtility.MemSet(ptr, 0, 10 * 2);
}
- _secondaryMainhand = 0;
- _secondaryOffhand = 0;
- _typeMainhand = FullEquipType.Unknown;
- _typeOffhand = FullEquipType.Unknown;
-
_nameHead = string.Empty;
_nameBody = string.Empty;
_nameHands = string.Empty;
@@ -244,8 +238,6 @@ public unsafe struct DesignData
_nameWrists = string.Empty;
_nameRFinger = string.Empty;
_nameLFinger = string.Empty;
- _nameMainhand = string.Empty;
- _nameOffhand = string.Empty;
return true;
}
diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs
index 5560357..5c58671 100644
--- a/Glamourer/Designs/DesignManager.cs
+++ b/Glamourer/Designs/DesignManager.cs
@@ -13,6 +13,7 @@ using Newtonsoft.Json.Linq;
using OtterGui;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
+using static OtterGui.Raii.ImRaii;
namespace Glamourer.Designs;
@@ -259,6 +260,28 @@ public class DesignManager
_event.Invoke(DesignChanged.Type.WriteProtection, design, value);
}
+ public void ChangeModelId(Design design, uint modelId, Customize customize, nint equipData, bool isHuman)
+ {
+ var oldValue = design.DesignData.ModelId;
+
+ if (!isHuman)
+ {
+ design.DesignData.LoadNonHuman(modelId, customize, equipData);
+ }
+ else if (!design.DesignData.IsHuman)
+ {
+ design.DesignData.IsHuman = true;
+ design.DesignData.ModelId = modelId;
+ design.DesignData.SetDefaultEquipment(_items);
+ design.DesignData.Customize = Customize.Default;
+ }
+
+ design.LastEdit = DateTimeOffset.UtcNow;
+ Glamourer.Log.Debug($"Changed model id in design {design.Identifier} from {oldValue} to {modelId}.");
+ _saveService.QueueSave(design);
+ _event.Invoke(DesignChanged.Type.ModelId, design, (oldValue, modelId));
+ }
+
/// Change a customization value.
public void ChangeCustomize(Design design, CustomizeIndex idx, CustomizeValue value)
{
@@ -454,6 +477,36 @@ public class DesignManager
/// Apply an entire design based on its appliance rules piece by piece.
public void ApplyDesign(Design design, DesignBase other)
{
+ ChangeModelId(design, other.DesignData.ModelId, other.DesignData.Customize, other.DesignData.GetEquipmentPtr(),
+ other.DesignData.IsHuman);
+
+ if (other.DoApplyWetness())
+ design.DesignData.SetIsWet(other.DesignData.IsWet());
+ if (other.DoApplyHatVisible())
+ design.DesignData.SetHatVisible(other.DesignData.IsHatVisible());
+ if (other.DoApplyVisorToggle())
+ design.DesignData.SetVisor(other.DesignData.IsVisorToggled());
+ if (other.DoApplyWeaponVisible())
+ design.DesignData.SetWeaponVisible(other.DesignData.IsWeaponVisible());
+
+ if (design.DesignData.IsHuman)
+ {
+ foreach (var index in Enum.GetValues())
+ {
+ if (other.DoApplyCustomize(index))
+ ChangeCustomize(design, index, other.DesignData.Customize[index]);
+ }
+
+ foreach (var slot in EquipSlotExtensions.EqdpSlots)
+ {
+ if (other.DoApplyEquip(slot))
+ ChangeEquip(design, slot, other.DesignData.Item(slot));
+
+ if (other.DoApplyStain(slot))
+ ChangeStain(design, slot, other.DesignData.Stain(slot));
+ }
+ }
+
if (other.DoApplyEquip(EquipSlot.MainHand))
ChangeWeapon(design, EquipSlot.MainHand, other.DesignData.Item(EquipSlot.MainHand));
@@ -465,31 +518,6 @@ public class DesignManager
if (other.DoApplyStain(EquipSlot.OffHand))
ChangeStain(design, EquipSlot.OffHand, other.DesignData.Stain(EquipSlot.OffHand));
-
-
- foreach (var slot in EquipSlotExtensions.EqdpSlots)
- {
- if (other.DoApplyEquip(slot))
- ChangeEquip(design, slot, other.DesignData.Item(slot));
-
- if (other.DoApplyStain(slot))
- ChangeStain(design, slot, other.DesignData.Stain(slot));
- }
-
- foreach (var index in Enum.GetValues())
- {
- if (other.DoApplyCustomize(index))
- ChangeCustomize(design, index, other.DesignData.Customize[index]);
- }
-
- if (other.DoApplyHatVisible())
- design.DesignData.SetHatVisible(other.DesignData.IsHatVisible());
- if (other.DoApplyVisorToggle())
- design.DesignData.SetVisor(other.DesignData.IsVisorToggled());
- if (other.DoApplyWeaponVisible())
- design.DesignData.SetWeaponVisible(other.DesignData.IsWeaponVisible());
- if (other.DoApplyWetness())
- design.DesignData.SetIsWet(other.DesignData.IsWet());
}
private void MigrateOldDesigns()
diff --git a/Glamourer/Events/DesignChanged.cs b/Glamourer/Events/DesignChanged.cs
index 154880a..b36af52 100644
--- a/Glamourer/Events/DesignChanged.cs
+++ b/Glamourer/Events/DesignChanged.cs
@@ -46,6 +46,9 @@ public sealed class DesignChanged : EventWrapper An existing design had an existing associated mod removed. Data is the Mod and its Settings [(Mod, ModSettings)].
RemovedMod,
+ /// An existing design had its model id changed. This means everything else might also have changed. Data is the old value and the new value. [(uint, uint)].
+ ModelId,
+
/// An existing design had a customization changed. Data is the old value, the new value and the type [(CustomizeValue, CustomizeValue, CustomizeIndex)].
Customize,
diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs
index 6f8cba0..789e027 100644
--- a/Glamourer/State/StateEditor.cs
+++ b/Glamourer/State/StateEditor.cs
@@ -65,11 +65,8 @@ public class StateEditor
}
else
{
- unsafe
- {
- state.ModelData.LoadNonHuman(modelId, customize, (byte*)equipData);
- state[ActorState.MetaIndex.ModelId] = source;
- }
+ state.ModelData.LoadNonHuman(modelId, customize, equipData);
+ state[ActorState.MetaIndex.ModelId] = source;
}
return true;
diff --git a/Glamourer/State/StateListener.cs b/Glamourer/State/StateListener.cs
index 5c4208c..9353849 100644
--- a/Glamourer/State/StateListener.cs
+++ b/Glamourer/State/StateListener.cs
@@ -327,7 +327,7 @@ public class StateListener : IDisposable
if (isHuman)
state.BaseData = _manager.FromActor(actor, false);
else
- state.BaseData.LoadNonHuman(modelId, *(Customize*)customizeData, (byte*)equipData);
+ state.BaseData.LoadNonHuman(modelId, *(Customize*)customizeData, equipData);
return UpdateState.Change;
}
diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs
index 4f67764..37becae 100644
--- a/Glamourer/State/StateManager.cs
+++ b/Glamourer/State/StateManager.cs
@@ -116,7 +116,7 @@ public class StateManager : IReadOnlyDictionary
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
{
ret.LoadNonHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId, *(Customize*)&actor.AsCharacter->DrawData.CustomizeData,
- (byte*)&actor.AsCharacter->DrawData.Head);
+ (nint) (&actor.AsCharacter->DrawData.Head));
return ret;
}