mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-17 04:57:43 +01:00
.
This commit is contained in:
parent
4cf082aa19
commit
1eb16b98a8
17 changed files with 735 additions and 497 deletions
|
|
@ -21,50 +21,50 @@ public partial class Design : DesignBase
|
|||
public string[] Tags { get; private set; } = Array.Empty<string>();
|
||||
public int Index { get; private set; }
|
||||
|
||||
private EquipFlag _applyEquip;
|
||||
private CustomizeFlag _applyCustomize;
|
||||
public QuadBool Wetness { get; private set; } = QuadBool.NullFalse;
|
||||
public QuadBool Visor { get; private set; } = QuadBool.NullFalse;
|
||||
public QuadBool Hat { get; private set; } = QuadBool.NullFalse;
|
||||
public QuadBool Weapon { get; private set; } = QuadBool.NullFalse;
|
||||
public bool WriteProtected { get; private set; }
|
||||
public EquipFlag ApplyEquip { get; private set; }
|
||||
public CustomizeFlag ApplyCustomize { get; private set; }
|
||||
public QuadBool Wetness { get; private set; } = QuadBool.NullFalse;
|
||||
public QuadBool Visor { get; private set; } = QuadBool.NullFalse;
|
||||
public QuadBool Hat { get; private set; } = QuadBool.NullFalse;
|
||||
public QuadBool Weapon { get; private set; } = QuadBool.NullFalse;
|
||||
public bool WriteProtected { get; private set; }
|
||||
|
||||
public bool DoApplyEquip(EquipSlot slot)
|
||||
=> _applyEquip.HasFlag(slot.ToFlag());
|
||||
=> ApplyEquip.HasFlag(slot.ToFlag());
|
||||
|
||||
public bool DoApplyStain(EquipSlot slot)
|
||||
=> _applyEquip.HasFlag(slot.ToStainFlag());
|
||||
=> ApplyEquip.HasFlag(slot.ToStainFlag());
|
||||
|
||||
public bool DoApplyCustomize(CustomizeIndex idx)
|
||||
=> _applyCustomize.HasFlag(idx.ToFlag());
|
||||
=> ApplyCustomize.HasFlag(idx.ToFlag());
|
||||
|
||||
private bool SetApplyEquip(EquipSlot slot, bool value)
|
||||
{
|
||||
var newValue = value ? _applyEquip | slot.ToFlag() : _applyEquip & ~slot.ToFlag();
|
||||
if (newValue == _applyEquip)
|
||||
var newValue = value ? ApplyEquip | slot.ToFlag() : ApplyEquip & ~slot.ToFlag();
|
||||
if (newValue == ApplyEquip)
|
||||
return false;
|
||||
|
||||
_applyEquip = newValue;
|
||||
ApplyEquip = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SetApplyStain(EquipSlot slot, bool value)
|
||||
{
|
||||
var newValue = value ? _applyEquip | slot.ToStainFlag() : _applyEquip & ~slot.ToStainFlag();
|
||||
if (newValue == _applyEquip)
|
||||
var newValue = value ? ApplyEquip | slot.ToStainFlag() : ApplyEquip & ~slot.ToStainFlag();
|
||||
if (newValue == ApplyEquip)
|
||||
return false;
|
||||
|
||||
_applyEquip = newValue;
|
||||
ApplyEquip = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SetApplyCustomize(CustomizeIndex idx, bool value)
|
||||
{
|
||||
var newValue = value ? _applyCustomize | idx.ToFlag() : _applyCustomize & ~idx.ToFlag();
|
||||
if (newValue == _applyCustomize)
|
||||
var newValue = value ? ApplyCustomize | idx.ToFlag() : ApplyCustomize & ~idx.ToFlag();
|
||||
if (newValue == ApplyCustomize)
|
||||
return false;
|
||||
|
||||
_applyCustomize = newValue;
|
||||
ApplyCustomize = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,8 @@ public partial class Design : DesignBase
|
|||
{
|
||||
[nameof(MainHand)] =
|
||||
Serialize(MainHand, CharacterData.MainHand.Stain, DoApplyEquip(EquipSlot.MainHand), DoApplyStain(EquipSlot.MainHand)),
|
||||
[nameof(OffHand)] = Serialize(OffHand, CharacterData.OffHand.Stain, DoApplyEquip(EquipSlot.OffHand), DoApplyStain(EquipSlot.OffHand)),
|
||||
[nameof(OffHand)] = Serialize(OffHand, CharacterData.OffHand.Stain, DoApplyEquip(EquipSlot.OffHand),
|
||||
DoApplyStain(EquipSlot.OffHand)),
|
||||
};
|
||||
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
|
|
@ -258,82 +259,41 @@ public partial class Design : DesignBase
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void MigrateBase64(string base64)
|
||||
{
|
||||
static void CheckSize(int length, int requiredLength)
|
||||
{
|
||||
if (length != requiredLength)
|
||||
throw new Exception(
|
||||
$"Can not parse Base64 string into CharacterSave:\n\tInvalid size {length} instead of {requiredLength}.");
|
||||
}
|
||||
|
||||
var bytes = Convert.FromBase64String(base64);
|
||||
|
||||
byte applicationFlags;
|
||||
ushort equipFlags;
|
||||
|
||||
switch (bytes[0])
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CheckSize(bytes.Length, 86);
|
||||
applicationFlags = bytes[1];
|
||||
equipFlags = BitConverter.ToUInt16(bytes, 2);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
CheckSize(bytes.Length, 91);
|
||||
applicationFlags = bytes[1];
|
||||
equipFlags = BitConverter.ToUInt16(bytes, 2);
|
||||
Hat = Hat.SetValue((bytes[90] & 0x01) == 0);
|
||||
Visor = Visor.SetValue((bytes[90] & 0x10) != 0);
|
||||
Weapon = Weapon.SetValue((bytes[90] & 0x02) == 0);
|
||||
break;
|
||||
}
|
||||
default: throw new Exception($"Can not parse Base64 string into design for migration:\n\tInvalid Version {bytes[0]}.");
|
||||
}
|
||||
|
||||
_applyCustomize = (applicationFlags & 0x01) != 0 ? CustomizeFlagExtensions.All : 0;
|
||||
Wetness = (applicationFlags & 0x02) != 0 ? QuadBool.True : QuadBool.NullFalse;
|
||||
Hat = Hat.SetEnabled((applicationFlags & 0x04) != 0);
|
||||
Weapon = Weapon.SetEnabled((applicationFlags & 0x08) != 0);
|
||||
Visor = Visor.SetEnabled((applicationFlags & 0x10) != 0);
|
||||
WriteProtected = (applicationFlags & 0x20) != 0;
|
||||
|
||||
CharacterData.ModelId = 0;
|
||||
|
||||
SetApplyEquip(EquipSlot.MainHand, (equipFlags & 0x0001) != 0);
|
||||
SetApplyEquip(EquipSlot.OffHand, (equipFlags & 0x0002) != 0);
|
||||
SetApplyStain(EquipSlot.MainHand, (equipFlags & 0x0001) != 0);
|
||||
SetApplyStain(EquipSlot.OffHand, (equipFlags & 0x0002) != 0);
|
||||
var flag = 0x0002u;
|
||||
var data = MigrateBase64(base64, out var applyEquip, out var applyCustomize, out var writeProtected, out var wet, out var hat,
|
||||
out var visor, out var weapon);
|
||||
UpdateMainhand(data.MainHand);
|
||||
UpdateMainhand(data.OffHand);
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
flag <<= 1;
|
||||
var apply = (equipFlags & flag) != 0;
|
||||
SetApplyEquip(slot, apply);
|
||||
SetApplyStain(slot, apply);
|
||||
}
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = bytes)
|
||||
{
|
||||
CharacterData.CustomizeData.Read(ptr + 4);
|
||||
var cur = (CharacterWeapon*)(ptr + 30);
|
||||
|
||||
UpdateMainhand(cur[0]);
|
||||
SetStain(EquipSlot.MainHand, cur[0].Stain);
|
||||
UpdateOffhand(cur[1]);
|
||||
SetStain(EquipSlot.OffHand, cur[1].Stain);
|
||||
var eq = (CharacterArmor*)(cur + 2);
|
||||
foreach (var (slot, idx) in EquipSlotExtensions.EqdpSlots.WithIndex())
|
||||
{
|
||||
UpdateArmor(slot, eq[idx], true);
|
||||
SetStain(slot, eq[idx].Stain);
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateArmor(slot, data.Equipment[slot], true);
|
||||
CharacterData.CustomizeData = data.CustomizeData;
|
||||
ApplyEquip = applyEquip;
|
||||
ApplyCustomize = applyCustomize;
|
||||
WriteProtected = writeProtected;
|
||||
Wetness = wet;
|
||||
Hat = hat;
|
||||
Visor = visor;
|
||||
Weapon = weapon;
|
||||
}
|
||||
|
||||
public static Design CreateTemporaryFromBase64(string base64, bool customize, bool equip)
|
||||
{
|
||||
var ret = new Design();
|
||||
ret.MigrateBase64(base64);
|
||||
if (!customize)
|
||||
ret.ApplyCustomize = 0;
|
||||
if (!equip)
|
||||
ret.ApplyEquip = 0;
|
||||
ret.Wetness = ret.Wetness.SetEnabled(customize);
|
||||
ret.Visor = ret.Visor.SetEnabled(equip);
|
||||
ret.Hat = ret.Hat.SetEnabled(equip);
|
||||
ret.Weapon = ret.Weapon.SetEnabled(equip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Outdated.
|
||||
public string CreateOldBase64()
|
||||
=> CreateOldBase64(in CharacterData, ApplyEquip, ApplyCustomize, Wetness == QuadBool.True, Hat.ForcedValue, Hat.Enabled,
|
||||
Visor.ForcedValue, Visor.Enabled, Weapon.ForcedValue, Weapon.Enabled, WriteProtected, 1f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Util;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -74,11 +76,12 @@ public class DesignBase
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
public Weapon WeaponMain
|
||||
=> new(MainhandName, MainHand, CharacterData.MainHand, MainhandType);
|
||||
|
||||
public Weapon WeaponOff
|
||||
=> Designs.Weapon.Offhand(OffhandName, OffHand, CharacterData.OffHand, MainhandType);
|
||||
=> Weapon.Offhand(OffhandName, OffHand, CharacterData.OffHand, MainhandType);
|
||||
|
||||
public CustomizeValue GetCustomize(CustomizeIndex idx)
|
||||
=> Customize()[idx];
|
||||
|
|
@ -108,7 +111,6 @@ public class DesignBase
|
|||
protected bool UpdateArmor(EquipSlot slot, CharacterArmor armor, bool force)
|
||||
{
|
||||
if (!force)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case EquipSlot.Head when CharacterData.Head.Value == armor.Value: return false;
|
||||
|
|
@ -122,7 +124,6 @@ public class DesignBase
|
|||
case EquipSlot.RFinger when CharacterData.RFinger.Value == armor.Value: return false;
|
||||
case EquipSlot.LFinger when CharacterData.LFinger.Value == armor.Value: return false;
|
||||
}
|
||||
}
|
||||
|
||||
var (valid, id, name) = Glamourer.Items.Identify(slot, armor.Set, armor.Variant);
|
||||
if (!valid)
|
||||
|
|
@ -329,4 +330,123 @@ public class DesignBase
|
|||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected const int Base64Size = 89;
|
||||
|
||||
public static CharacterData MigrateBase64(string base64, out EquipFlag equipFlags, out CustomizeFlag customizeFlags,
|
||||
out bool writeProtected, out QuadBool wet, out QuadBool hat, out QuadBool visor, out QuadBool weapon)
|
||||
{
|
||||
static void CheckSize(int length, int requiredLength)
|
||||
{
|
||||
if (length != requiredLength)
|
||||
throw new Exception(
|
||||
$"Can not parse Base64 string into CharacterSave:\n\tInvalid size {length} instead of {requiredLength}.");
|
||||
}
|
||||
|
||||
byte applicationFlags;
|
||||
ushort equipFlagsS;
|
||||
var bytes = Convert.FromBase64String(base64);
|
||||
hat = QuadBool.Null;
|
||||
visor = QuadBool.Null;
|
||||
weapon = QuadBool.Null;
|
||||
switch (bytes[0])
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CheckSize(bytes.Length, 86);
|
||||
applicationFlags = bytes[1];
|
||||
equipFlagsS = BitConverter.ToUInt16(bytes, 2);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
CheckSize(bytes.Length, Base64Size);
|
||||
applicationFlags = bytes[1];
|
||||
equipFlagsS = BitConverter.ToUInt16(bytes, 2);
|
||||
hat = hat.SetValue((bytes[90] & 0x01) == 0);
|
||||
visor = visor.SetValue((bytes[90] & 0x10) != 0);
|
||||
weapon = weapon.SetValue((bytes[90] & 0x02) == 0);
|
||||
break;
|
||||
}
|
||||
default: throw new Exception($"Can not parse Base64 string into design for migration:\n\tInvalid Version {bytes[0]}.");
|
||||
}
|
||||
|
||||
customizeFlags = (applicationFlags & 0x01) != 0 ? CustomizeFlagExtensions.All : 0;
|
||||
wet = (applicationFlags & 0x02) != 0 ? QuadBool.True : QuadBool.NullFalse;
|
||||
hat = hat.SetEnabled((applicationFlags & 0x04) != 0);
|
||||
weapon = weapon.SetEnabled((applicationFlags & 0x08) != 0);
|
||||
visor = visor.SetEnabled((applicationFlags & 0x10) != 0);
|
||||
writeProtected = (applicationFlags & 0x20) != 0;
|
||||
|
||||
equipFlags = 0;
|
||||
equipFlags |= (equipFlagsS & 0x0001) != 0 ? EquipFlag.Mainhand | EquipFlag.MainhandStain : 0;
|
||||
equipFlags |= (equipFlagsS & 0x0002) != 0 ? EquipFlag.Offhand | EquipFlag.OffhandStain : 0;
|
||||
var flag = 0x0002u;
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
flag <<= 1;
|
||||
equipFlags |= (equipFlagsS & flag) != 0 ? slot.ToFlag() | slot.ToStainFlag() : 0;
|
||||
}
|
||||
|
||||
var data = new CharacterData();
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = bytes)
|
||||
{
|
||||
data.CustomizeData.Read(ptr + 4);
|
||||
var cur = (CharacterWeapon*)(ptr + 30);
|
||||
data.MainHand = cur[0];
|
||||
data.OffHand = cur[1];
|
||||
var eq = (CharacterArmor*)(cur + 2);
|
||||
foreach (var (slot, idx) in EquipSlotExtensions.EqdpSlots.WithIndex())
|
||||
data.Equipment[slot] = eq[idx];
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static unsafe string CreateOldBase64(in CharacterData save, EquipFlag equipFlags, CustomizeFlag customizeFlags, bool wet, bool hat,
|
||||
bool setHat, bool visor, bool setVisor, bool weapon, bool setWeapon, bool writeProtected, float alpha)
|
||||
{
|
||||
var data = stackalloc byte[Base64Size];
|
||||
data[0] = 2;
|
||||
data[1] = (byte)((customizeFlags == CustomizeFlagExtensions.All ? 0x01 : 0)
|
||||
| (wet ? 0x02 : 0)
|
||||
| (setHat ? 0x04 : 0)
|
||||
| (setWeapon ? 0x08 : 0)
|
||||
| (setVisor ? 0x10 : 0)
|
||||
| (writeProtected ? 0x20 : 0));
|
||||
data[2] = (byte)((equipFlags.HasFlag(EquipFlag.Mainhand) ? 0x01 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Offhand) ? 0x02 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Head) ? 0x04 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Body) ? 0x08 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Hands) ? 0x10 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Legs) ? 0x20 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Feet) ? 0x40 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Ears) ? 0x80 : 0));
|
||||
data[3] = (byte)((equipFlags.HasFlag(EquipFlag.Neck) ? 0x01 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.Wrist) ? 0x02 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.RFinger) ? 0x04 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.LFinger) ? 0x08 : 0));
|
||||
save.CustomizeData.Write(data + 4);
|
||||
((CharacterWeapon*)(data + 30))[0] = save.MainHand;
|
||||
((CharacterWeapon*)(data + 30))[1] = save.OffHand;
|
||||
((CharacterArmor*)(data + 44))[0] = save.Head;
|
||||
((CharacterArmor*)(data + 44))[1] = save.Body;
|
||||
((CharacterArmor*)(data + 44))[2] = save.Hands;
|
||||
((CharacterArmor*)(data + 44))[3] = save.Legs;
|
||||
((CharacterArmor*)(data + 44))[4] = save.Feet;
|
||||
((CharacterArmor*)(data + 44))[5] = save.Ears;
|
||||
((CharacterArmor*)(data + 44))[6] = save.Neck;
|
||||
((CharacterArmor*)(data + 44))[7] = save.Wrists;
|
||||
((CharacterArmor*)(data + 44))[8] = save.RFinger;
|
||||
((CharacterArmor*)(data + 44))[9] = save.LFinger;
|
||||
*(float*)(data + 84) = 1f;
|
||||
data[88] = (byte)((hat ? 0x01 : 0)
|
||||
| (visor ? 0x10 : 0)
|
||||
| (weapon ? 0x02 : 0));
|
||||
|
||||
return Convert.ToBase64String(new Span<byte>(data, Base64Size));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ public enum EquipFlag : uint
|
|||
|
||||
public static class EquipFlagExtensions
|
||||
{
|
||||
public const EquipFlag All = (EquipFlag)(((uint)EquipFlag.OffhandStain << 1) - 1);
|
||||
|
||||
public static EquipFlag ToFlag(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue