Introduce CharacterSave and rudimentary Clipboard buttons.

This commit is contained in:
Ottermandias 2021-08-07 12:41:17 +02:00
parent d582c83152
commit f71b800b2e
3 changed files with 137 additions and 11 deletions

View file

@ -250,14 +250,18 @@ namespace Glamourer.Customization
} }
} }
public unsafe byte[] ToBytes() public unsafe void WriteBytes(byte[] array, int offset = 0)
{ {
var ret = new byte[CustomizationBytes];
fixed (byte* ptr = &_race) fixed (byte* ptr = &_race)
{ {
Marshal.Copy(new IntPtr(ptr), ret, 0, CustomizationBytes); Marshal.Copy(new IntPtr(ptr), array, offset, CustomizationBytes);
} }
}
public byte[] ToBytes()
{
var ret = new byte[CustomizationBytes];
WriteBytes(ret);
return ret; return ret;
} }
} }

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Reflection; using System.Reflection;
using System.Windows.Forms;
using Dalamud.Game.ClientState.Actors; using Dalamud.Game.ClientState.Actors;
using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.ClientState.Actors.Types;
using Dalamud.Interface; using Dalamud.Interface;
@ -735,9 +736,8 @@ namespace Glamourer.Gui
private static readonly CustomizationId[] AllCustomizations = (CustomizationId[]) Enum.GetValues(typeof(CustomizationId)); private static readonly CustomizationId[] AllCustomizations = (CustomizationId[]) Enum.GetValues(typeof(CustomizationId));
private bool DrawStuff() private bool DrawStuff(LazyCustomization x)
{ {
var x = new LazyCustomization(_player!.Address);
_currentSubRace = x.Value.Clan; _currentSubRace = x.Value.Clan;
_currentGender = x.Value.Gender; _currentGender = x.Value.Gender;
var ret = DrawGenderSelector(x); var ret = DrawGenderSelector(x);
@ -885,8 +885,37 @@ namespace Glamourer.Gui
changes |= DrawEquip(EquipSlot.LFinger, equip.LFinger); changes |= DrawEquip(EquipSlot.LFinger, equip.LFinger);
} }
var x = new LazyCustomization(_player!.Address);
if (ImGui.CollapsingHeader("Character Customization")) if (ImGui.CollapsingHeader("Character Customization"))
changes |= DrawStuff(); changes |= DrawStuff(x);
if (ImGui.Button("Copy to Clipboard"))
{
var save = new CharacterSave();
save.Load(x.Value);
save.Load(equip);
Clipboard.SetText(save.ToBase64());
}
ImGui.SameLine();
if (ImGui.Button("Apply from Clipboard"))
{
var text = Clipboard.GetText();
if (text.Any())
{
try
{
var save = CharacterSave.FromString(text);
save.Customizations.Write(_player.Address);
save.Equipment.Write(_player.Address);
changes = true;
}
catch (Exception e)
{
PluginLog.Information($"{e}");
}
}
}
if (changes) if (changes)
UpdateActors(_player); UpdateActors(_player);

View file

@ -2,6 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Plugin; using Dalamud.Plugin;
using Glamourer.Customization; using Glamourer.Customization;
@ -15,12 +17,103 @@ namespace Glamourer
{ {
public class CharacterSave public class CharacterSave
{ {
public string Name { get; set; } = string.Empty; public const byte CurrentVersion = 1;
public ActorCustomization Customizations { get; private set; } public const byte TotalSizeVersion1 = 1 + 1 + 2 + 56 + ActorCustomization.CustomizationBytes;
public ActorEquipment Equipment { get; private set; } = null!;
public ActorEquipMask WriteEquipment { get; set; } = ActorEquipMask.None; public const byte TotalSize = TotalSizeVersion1;
public bool WriteCustomizations { get; set; } = false;
private readonly byte[] _bytes = new byte[TotalSize];
public CharacterSave()
=> _bytes[0] = CurrentVersion;
public byte Version
=> _bytes[0];
public bool WriteCustomizations
{
get => _bytes[1] != 0;
set => _bytes[1] = (byte) (value ? 1 : 0);
}
public ActorEquipMask WriteEquipment
{
get => (ActorEquipMask) ((ushort) _bytes[2] | ((ushort) _bytes[3] << 8));
set
{
_bytes[2] = (byte) (((ushort) value) & 0xFF);
_bytes[3] = (byte) (((ushort) value) >> 8);
}
}
public void Load(ActorCustomization customization)
{
WriteCustomizations = true;
customization.WriteBytes(_bytes, 4);
}
public void Load(ActorEquipment equipment, ActorEquipMask mask = ActorEquipMask.All)
{
WriteEquipment = mask;
equipment.WriteBytes(_bytes, 4 + ActorCustomization.CustomizationBytes);
}
public string ToBase64()
=> System.Convert.ToBase64String(_bytes);
public void Load(string base64)
{
var bytes = System.Convert.FromBase64String(base64);
switch (bytes[0])
{
case 1:
if (bytes.Length != TotalSizeVersion1)
throw new Exception(
$"Can not parse Base64 string into CharacterSave:\n\tInvalid size {bytes.Length} instead of {TotalSizeVersion1}.");
if (bytes[1] != 0 && bytes[1] != 1)
throw new Exception(
$"Can not parse Base64 string into CharacterSave:\n\tInvalid value {bytes[1]} in byte 2, should be either 0 or 1.");
var mask = (ActorEquipMask) ((ushort) bytes[2] | ((ushort) bytes[3] << 8));
if (!Enum.IsDefined(typeof(ActorEquipMask), mask))
throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid value {mask} in byte 3 and 4.");
bytes.CopyTo(_bytes, 0);
break;
default:
throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid Version {bytes[0]}.");
}
}
public static CharacterSave FromString(string base64)
{
var ret = new CharacterSave();
ret.Load(base64);
return ret;
}
public unsafe ActorCustomization Customizations
{
get
{
var ret = new ActorCustomization();
fixed (byte* ptr = _bytes)
{
ret.Read(new IntPtr(ptr) + 4);
}
return ret;
}
}
public ActorEquipment Equipment
{
get
{
var ret = new ActorEquipment();
ret.FromBytes(_bytes, 4 + ActorCustomization.CustomizationBytes);
return ret;
}
}
} }
internal class Glamourer internal class Glamourer