mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Add support for modelchara id and extended arrays.
This commit is contained in:
parent
1f4685f505
commit
afc987432a
3 changed files with 89 additions and 55 deletions
|
|
@ -39,11 +39,13 @@ public class CharacterSaveConverter : JsonConverter
|
||||||
[JsonConverter(typeof(CharacterSaveConverter))]
|
[JsonConverter(typeof(CharacterSaveConverter))]
|
||||||
public class CharacterSave
|
public class CharacterSave
|
||||||
{
|
{
|
||||||
public const byte CurrentVersion = 2;
|
public const byte CurrentVersion = 4;
|
||||||
public const byte TotalSizeVersion1 = 1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes;
|
public const byte TotalSizeVersion1 = 1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes;
|
||||||
public const byte TotalSizeVersion2 = 1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1;
|
public const byte TotalSizeVersion2 = 1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1;
|
||||||
|
// Version 4 is part of the rework.
|
||||||
|
public const byte TotalSizeVersion4 = 1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1 + 4;
|
||||||
|
|
||||||
public const byte TotalSize = TotalSizeVersion2;
|
public const byte TotalSize = TotalSizeVersion4;
|
||||||
|
|
||||||
private readonly byte[] _bytes = new byte[TotalSize];
|
private readonly byte[] _bytes = new byte[TotalSize];
|
||||||
|
|
||||||
|
|
@ -63,6 +65,21 @@ public class CharacterSave
|
||||||
public byte Version
|
public byte Version
|
||||||
=> _bytes[0];
|
=> _bytes[0];
|
||||||
|
|
||||||
|
public uint ModelId
|
||||||
|
{
|
||||||
|
get => (uint)_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1]
|
||||||
|
| ((uint)_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1 + 1] << 8)
|
||||||
|
| ((uint)_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1 + 2] << 16)
|
||||||
|
| ((uint)_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1 + 3] << 24);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 1] = (byte)value;
|
||||||
|
_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 2] = (byte)(value >> 8);
|
||||||
|
_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 3] = (byte)(value >> 16);
|
||||||
|
_bytes[1 + 1 + 2 + 56 + CharacterCustomization.CustomizationBytes + 4 + 4] = (byte)(value >> 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool WriteCustomizations
|
public bool WriteCustomizations
|
||||||
{
|
{
|
||||||
get => (_bytes[1] & 0x01) != 0;
|
get => (_bytes[1] & 0x01) != 0;
|
||||||
|
|
@ -297,6 +314,7 @@ public class CharacterSave
|
||||||
|
|
||||||
IsWet = a.IsWet();
|
IsWet = a.IsWet();
|
||||||
Alpha = a.Alpha();
|
Alpha = a.Alpha();
|
||||||
|
ModelId = a.ModelType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -304,6 +322,7 @@ public class CharacterSave
|
||||||
{
|
{
|
||||||
Glamourer.RevertableDesigns.Add(a);
|
Glamourer.RevertableDesigns.Add(a);
|
||||||
|
|
||||||
|
a.SetModelType(ModelId);
|
||||||
if (WriteCustomizations)
|
if (WriteCustomizations)
|
||||||
Customizations.Write(a.Address);
|
Customizations.Write(a.Address);
|
||||||
if (WriteEquipment != CharacterEquipMask.None)
|
if (WriteEquipment != CharacterEquipMask.None)
|
||||||
|
|
@ -357,8 +376,28 @@ public class CharacterSave
|
||||||
case 2:
|
case 2:
|
||||||
CheckSize(bytes.Length, TotalSizeVersion2);
|
CheckSize(bytes.Length, TotalSizeVersion2);
|
||||||
CheckRange(2, bytes[1], 0, 0x3F);
|
CheckRange(2, bytes[1], 0, 0x3F);
|
||||||
|
oldVersion = true;
|
||||||
|
bytes[0] = CurrentVersion;
|
||||||
|
ModelId = 0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tVersion 3 is only supported by the rework.");
|
||||||
|
case CurrentVersion:
|
||||||
|
CheckSize(bytes.Length, TotalSizeVersion4);
|
||||||
|
CheckRange(2, bytes[1], 0, 0x3F);
|
||||||
oldVersion = false;
|
oldVersion = false;
|
||||||
break;
|
break;
|
||||||
|
// This is a compatibility version between old glamourer and new glamourer,
|
||||||
|
// where new glamourer sends the byte array for old in front of its own.
|
||||||
|
case 5:
|
||||||
|
if (bytes.Length < TotalSizeVersion4)
|
||||||
|
throw new Exception(
|
||||||
|
$"Can not parse Base64 string into CharacterSave:\n\tInvalid size {bytes.Length} instead of at least {TotalSizeVersion4}.");
|
||||||
|
CheckRange(2, bytes[1], 0, 0x3F);
|
||||||
|
oldVersion = false;
|
||||||
|
CheckCharacterMask(bytes[2], bytes[3]);
|
||||||
|
bytes.AsSpan(0, TotalSizeVersion4).CopyTo(_bytes.AsSpan());
|
||||||
|
return;
|
||||||
default: throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid Version {bytes[0]}.");
|
default: throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid Version {bytes[0]}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ namespace Glamourer.Gui
|
||||||
if (!ImGui.Selectable($"{id:D6}##models", id == currentModel) || id == currentModel)
|
if (!ImGui.Selectable($"{id:D6}##models", id == currentModel) || id == currentModel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_player!.SetModelType((int) id);
|
_player!.SetModelType(id);
|
||||||
Glamourer.Penumbra.UpdateCharacters(_player!);
|
Glamourer.Penumbra.UpdateCharacters(_player!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
|
||||||
namespace Penumbra.PlayerWatch
|
namespace Penumbra.PlayerWatch;
|
||||||
{
|
|
||||||
public static class CharacterFactory
|
public static class CharacterFactory
|
||||||
{
|
{
|
||||||
private static ConstructorInfo? _characterConstructor;
|
private static ConstructorInfo? _characterConstructor;
|
||||||
|
|
@ -30,9 +30,7 @@ namespace Penumbra.PlayerWatch
|
||||||
public static Character? Convert(GameObject? actor)
|
public static Character? Convert(GameObject? actor)
|
||||||
{
|
{
|
||||||
if (actor == null)
|
if (actor == null)
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
return actor switch
|
return actor switch
|
||||||
{
|
{
|
||||||
|
|
@ -52,12 +50,9 @@ namespace Penumbra.PlayerWatch
|
||||||
|
|
||||||
public static class GameObjectExtensions
|
public static class GameObjectExtensions
|
||||||
{
|
{
|
||||||
private const int ModelTypeOffset = 0x01B4;
|
public static unsafe uint ModelType(this Character actor)
|
||||||
|
=> (uint) ((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)actor.Address)->CharacterData.ModelCharaId;
|
||||||
|
|
||||||
public static unsafe int ModelType( this GameObject actor )
|
public static unsafe void SetModelType(this Character actor, uint value)
|
||||||
=> *( int* )( actor.Address + ModelTypeOffset );
|
=> ((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)actor.Address)->CharacterData.ModelCharaId = (int) value;
|
||||||
|
|
||||||
public static unsafe void SetModelType( this GameObject actor, int value )
|
|
||||||
=> *( int* )( actor.Address + ModelTypeOffset ) = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue