mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 02:07:25 +01:00
Random fixes and penumbra attach update.
This commit is contained in:
parent
78fd4ce9b9
commit
dbdaaf1ca8
15 changed files with 264 additions and 180 deletions
|
|
@ -150,7 +150,7 @@ namespace Glamourer.Customization
|
|||
var row = _listSheet.GetRow(((uint) race - 1) * 2 - 1 + (uint) gender)!;
|
||||
var set = new CustomizationSet(race, gender)
|
||||
{
|
||||
HairStyles = race.ToRace() == Race.Hrothgar ? HrothgarFaces(row) : GetHairStyles(race, gender),
|
||||
HairStyles = GetHairStyles(race, gender),
|
||||
HairColors = hair,
|
||||
SkinColors = skin,
|
||||
EyeColors = _eyeColorPicker,
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@
|
|||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Penumbra.GameData">
|
||||
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.GameData.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29613.14
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32210.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Glamourer", "Glamourer\Glamourer.csproj", "{A5439F6B-83C1-4078-9371-354A147FF554}"
|
||||
EndProject
|
||||
|
|
@ -13,6 +13,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Glamourer.GameData", "Glamourer.GameData\Glamourer.GameData.csproj", "{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj", "{9BEE2336-AA93-4669-8EEA-4756B3B2D024}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.PlayerWatch", "..\Penumbra\Penumbra.PlayerWatch\Penumbra.PlayerWatch.csproj", "{FECEDB39-C103-4333-82A6-A422BDC51EEE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -47,6 +51,30 @@ Global
|
|||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
||||
<Assembly Path="H:\Projects\FFPlugins\Penumbra\Penumbra\bin\Debug\net472\Penumbra.GameData.dll" />
|
||||
<Assembly Path="C:\Users\Ozy\AppData\Roaming\XIVLauncher\addon\Hooks\dev\Dalamud.dll" />
|
||||
<Assembly Path="H:\Projects\FFPlugins\Penumbra\Penumbra\bin\Debug\net5.0-windows\Penumbra.GameData.dll" />
|
||||
</AssemblyExplorer></s:String></wpf:ResourceDictionary>
|
||||
BIN
Glamourer.zip
BIN
Glamourer.zip
Binary file not shown.
|
|
@ -4,20 +4,8 @@ namespace Glamourer;
|
|||
|
||||
public static class CharacterExtensions
|
||||
{
|
||||
public const int WetnessOffset = 0x1ADA;
|
||||
public const byte WetnessFlag = 0x80;
|
||||
public const int HatVisibleOffset = 0x84E;
|
||||
public const int VisorToggledOffset = 0x84F;
|
||||
public const byte HatHiddenFlag = 0x01;
|
||||
public const byte VisorToggledFlag = 0x08;
|
||||
public const int AlphaOffset = 0x19E0;
|
||||
public const int WeaponHiddenOffset1 = 0x84F;
|
||||
public const int WeaponHiddenOffset2 = 0x72C; // maybe
|
||||
public const byte WeaponHiddenFlag1 = 0x01;
|
||||
public const byte WeaponHiddenFlag2 = 0x02;
|
||||
|
||||
public static unsafe bool IsWet(this Character a)
|
||||
=> (*((byte*)a.Address + WetnessOffset) & WetnessFlag) != 0;
|
||||
=> (*((byte*)a.Address + Offsets.Character.Wetness) & Offsets.Character.Flags.IsWet) != 0;
|
||||
|
||||
public static unsafe bool SetWetness(this Character a, bool value)
|
||||
{
|
||||
|
|
@ -26,14 +14,16 @@ public static class CharacterExtensions
|
|||
return false;
|
||||
|
||||
if (value)
|
||||
*((byte*)a.Address + WetnessOffset) = (byte)(*((byte*)a.Address + WetnessOffset) | WetnessFlag);
|
||||
*((byte*)a.Address + Offsets.Character.Wetness) =
|
||||
(byte)(*((byte*)a.Address + Offsets.Character.Wetness) | Offsets.Character.Flags.IsWet);
|
||||
else
|
||||
*((byte*)a.Address + WetnessOffset) = (byte)(*((byte*)a.Address + WetnessOffset) & ~WetnessFlag);
|
||||
*((byte*)a.Address + Offsets.Character.Wetness) =
|
||||
(byte)(*((byte*)a.Address + Offsets.Character.Wetness) & ~Offsets.Character.Flags.IsWet);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static unsafe bool IsHatVisible(this Character a)
|
||||
=> (*((byte*)a.Address + HatVisibleOffset) & HatHiddenFlag) == 0;
|
||||
=> (*((byte*)a.Address + Offsets.Character.HatVisible) & Offsets.Character.Flags.IsHatHidden) == 0;
|
||||
|
||||
public static unsafe bool SetHatVisible(this Character a, bool visible)
|
||||
{
|
||||
|
|
@ -42,14 +32,17 @@ public static class CharacterExtensions
|
|||
return false;
|
||||
|
||||
if (visible)
|
||||
*((byte*)a.Address + HatVisibleOffset) = (byte)(*((byte*)a.Address + HatVisibleOffset) & ~HatHiddenFlag);
|
||||
*((byte*)a.Address + Offsets.Character.HatVisible) =
|
||||
(byte)(*((byte*)a.Address + Offsets.Character.HatVisible) & ~Offsets.Character.Flags.IsHatHidden);
|
||||
else
|
||||
*((byte*)a.Address + HatVisibleOffset) = (byte)(*((byte*)a.Address + HatVisibleOffset) | HatHiddenFlag);
|
||||
*((byte*)a.Address + Offsets.Character.HatVisible) =
|
||||
(byte)(*((byte*)a.Address + Offsets.Character.HatVisible) | Offsets.Character.Flags.IsHatHidden);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static unsafe bool IsVisorToggled(this Character a)
|
||||
=> (*((byte*)a.Address + VisorToggledOffset) & VisorToggledFlag) == VisorToggledFlag;
|
||||
=> (*((byte*)a.Address + Offsets.Character.VisorToggled) & Offsets.Character.Flags.IsVisorToggled)
|
||||
== Offsets.Character.Flags.IsVisorToggled;
|
||||
|
||||
public static unsafe bool SetVisorToggled(this Character a, bool toggled)
|
||||
{
|
||||
|
|
@ -58,15 +51,19 @@ public static class CharacterExtensions
|
|||
return false;
|
||||
|
||||
if (toggled)
|
||||
*((byte*)a.Address + VisorToggledOffset) = (byte)(*((byte*)a.Address + VisorToggledOffset) | VisorToggledFlag);
|
||||
*((byte*)a.Address + Offsets.Character.VisorToggled) =
|
||||
(byte)(*((byte*)a.Address + Offsets.Character.VisorToggled) | Offsets.Character.Flags.IsVisorToggled);
|
||||
else
|
||||
*((byte*)a.Address + VisorToggledOffset) = (byte)(*((byte*)a.Address + VisorToggledOffset) & ~VisorToggledFlag);
|
||||
*((byte*)a.Address + Offsets.Character.VisorToggled) =
|
||||
(byte)(*((byte*)a.Address + Offsets.Character.VisorToggled) & ~Offsets.Character.Flags.IsVisorToggled);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static unsafe bool IsWeaponHidden(this Character a)
|
||||
=> (*((byte*)a.Address + WeaponHiddenOffset1) & WeaponHiddenFlag1) == WeaponHiddenFlag1
|
||||
&& (*((byte*)a.Address + WeaponHiddenOffset2) & WeaponHiddenFlag2) == WeaponHiddenFlag2;
|
||||
=> (*((byte*)a.Address + Offsets.Character.WeaponHidden1) & Offsets.Character.Flags.IsWeaponHidden1)
|
||||
== Offsets.Character.Flags.IsWeaponHidden1
|
||||
&& (*((byte*)a.Address + Offsets.Character.WeaponHidden2) & Offsets.Character.Flags.IsWeaponHidden2)
|
||||
== Offsets.Character.Flags.IsWeaponHidden2;
|
||||
|
||||
public static unsafe bool SetWeaponHidden(this Character a, bool value)
|
||||
{
|
||||
|
|
@ -74,21 +71,22 @@ public static class CharacterExtensions
|
|||
if (hidden == value)
|
||||
return false;
|
||||
|
||||
var val1 = *((byte*)a.Address + WeaponHiddenOffset1);
|
||||
var val2 = *((byte*)a.Address + WeaponHiddenOffset2);
|
||||
var val1 = *((byte*)a.Address + Offsets.Character.WeaponHidden1);
|
||||
var val2 = *((byte*)a.Address + Offsets.Character.WeaponHidden2);
|
||||
if (value)
|
||||
{
|
||||
*((byte*)a.Address + WeaponHiddenOffset1) = (byte)(val1 | WeaponHiddenFlag1);
|
||||
*((byte*)a.Address + WeaponHiddenOffset2) = (byte)(val2 | WeaponHiddenFlag2);
|
||||
*((byte*)a.Address + Offsets.Character.WeaponHidden1) = (byte)(val1 | Offsets.Character.Flags.IsWeaponHidden1);
|
||||
*((byte*)a.Address + Offsets.Character.WeaponHidden2) = (byte)(val2 | Offsets.Character.Flags.IsWeaponHidden2);
|
||||
}
|
||||
else
|
||||
{
|
||||
*((byte*)a.Address + WeaponHiddenOffset1) = (byte)(val1 & ~WeaponHiddenFlag1);
|
||||
*((byte*)a.Address + WeaponHiddenOffset2) = (byte)(val2 & ~WeaponHiddenFlag2);
|
||||
*((byte*)a.Address + Offsets.Character.WeaponHidden1) = (byte)(val1 & ~Offsets.Character.Flags.IsWeaponHidden1);
|
||||
*((byte*)a.Address + Offsets.Character.WeaponHidden2) = (byte)(val2 & ~Offsets.Character.Flags.IsWeaponHidden2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static unsafe ref float Alpha(this Character a)
|
||||
=> ref *(float*)((byte*)a.Address + AlphaOffset);
|
||||
=> ref *(float*)((byte*)a.Address + Offsets.Character.Alpha);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,11 +310,11 @@ public class CharacterSave
|
|||
a.SetWetness(IsWet);
|
||||
a.Alpha() = Alpha;
|
||||
if (SetHatState)
|
||||
a.SetHatVisible(!HatState);
|
||||
a.SetHatVisible(HatState);
|
||||
if (SetVisorState)
|
||||
a.SetVisorToggled(VisorState);
|
||||
if (SetWeaponState)
|
||||
a.SetWeaponHidden(WeaponState);
|
||||
a.SetWeaponHidden(!WeaponState);
|
||||
}
|
||||
|
||||
public void ApplyOnlyEquipment(Character a)
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ namespace Glamourer.Designs
|
|||
design.Jobs.Name);
|
||||
design.Design.Data.Apply(character);
|
||||
Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character);
|
||||
Glamourer.Penumbra.RedrawObject(character, RedrawType.WithSettings, false);
|
||||
Glamourer.Penumbra.RedrawObject(character, RedrawType.Redraw, false);
|
||||
}
|
||||
|
||||
public void Add(string name, Design design, JobGroup group, bool enabled = false)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
|
|
@ -69,23 +70,35 @@
|
|||
<HintPath>$(appdata)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Penumbra.GameData">
|
||||
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.GameData.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Penumbra.PlayerWatch">
|
||||
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.PlayerWatch.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3">
|
||||
<Private>false</Private>
|
||||
</PackageReference>
|
||||
|
||||
<PackageReference Include="System.Memory" Version="4.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Glamourer.GameData\Glamourer.GameData.csproj" />
|
||||
<ProjectReference Include="..\..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||
<ProjectReference Include="..\..\Penumbra\Penumbra.PlayerWatch\Penumbra.PlayerWatch.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ namespace Glamourer.Gui
|
|||
{
|
||||
internal partial class Interface
|
||||
{
|
||||
private readonly CharacterSave _currentSave = new();
|
||||
private string _newDesignName = string.Empty;
|
||||
private bool _keyboardFocus;
|
||||
private const string DesignNamePopupLabel = "Save Design As...";
|
||||
private const uint RedHeaderColor = 0xFF1818C0;
|
||||
private const uint GreenHeaderColor = 0xFF18C018;
|
||||
private readonly CharacterSave _currentSave = new();
|
||||
private string _newDesignName = string.Empty;
|
||||
private bool _keyboardFocus;
|
||||
private bool _holdShift;
|
||||
private bool _holdCtrl;
|
||||
private const string DesignNamePopupLabel = "Save Design As...";
|
||||
private const uint RedHeaderColor = 0xFF1818C0;
|
||||
private const uint GreenHeaderColor = 0xFF18C018;
|
||||
|
||||
private void DrawPlayerHeader()
|
||||
{
|
||||
|
|
@ -58,10 +60,10 @@ namespace Glamourer.Gui
|
|||
save.Apply(player);
|
||||
}
|
||||
|
||||
private CharacterSave ConditionalCopy(CharacterSave save)
|
||||
private static CharacterSave ConditionalCopy(CharacterSave save, bool shift, bool ctrl)
|
||||
{
|
||||
var copy = save.Copy();
|
||||
if (ImGui.GetIO().KeyShift)
|
||||
if (shift)
|
||||
{
|
||||
copy.Load(new CharacterEquipment());
|
||||
copy.SetHatState = false;
|
||||
|
|
@ -69,7 +71,7 @@ namespace Glamourer.Gui
|
|||
copy.SetWeaponState = false;
|
||||
copy.WriteEquipment = CharacterEquipMask.None;
|
||||
}
|
||||
else if (ImGui.GetIO().KeyCtrl)
|
||||
else if (ctrl)
|
||||
{
|
||||
copy.Load(CharacterCustomization.Default);
|
||||
copy.SetHatState = false;
|
||||
|
|
@ -77,8 +79,8 @@ namespace Glamourer.Gui
|
|||
copy.SetWeaponState = false;
|
||||
copy.WriteCustomizations = false;
|
||||
}
|
||||
|
||||
return save.Copy();
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private bool DrawApplyClipboardButton()
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ namespace Glamourer.Gui
|
|||
var count = set.Count(CustomizationId.FacialFeaturesTattoos);
|
||||
using (var _ = ImGuiRaii.NewGroup())
|
||||
{
|
||||
var face = set.Race == Race.Hrothgar ? customization.Hairstyle : customization.Face;
|
||||
var face = customization.Face;
|
||||
if (set.Faces.Count < face)
|
||||
face = 1;
|
||||
for (var i = 0; i < count; ++i)
|
||||
|
|
@ -288,9 +288,6 @@ namespace Glamourer.Gui
|
|||
ret = true;
|
||||
}
|
||||
|
||||
if (id == CustomizationId.Hairstyle && customization.Race == Race.Hrothgar)
|
||||
customization[CustomizationId.Face] = (byte) ((customization[CustomizationId.Hairstyle] + 1) / 2);
|
||||
|
||||
ImGui.Text($"{label} ({custom.Value.Value})");
|
||||
ImGuiCustom.HoverTooltip(tooltip);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ namespace Glamourer.Gui
|
|||
if (!change)
|
||||
return false;
|
||||
|
||||
newItem = new Item(newItem.Base, newItem.Name, slot);
|
||||
if (_player == null)
|
||||
return _inDesignMode && (_selection?.Data.WriteItem(newItem) ?? false);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,7 @@ namespace Glamourer.Gui
|
|||
case CustomizationId.Gender: break;
|
||||
case CustomizationId.FacialFeaturesTattoos: break;
|
||||
case CustomizationId.HighlightsOnFlag: break;
|
||||
case CustomizationId.Face:
|
||||
if (customization.Race != Race.Hrothgar)
|
||||
goto default;
|
||||
break;
|
||||
case CustomizationId.Face: break;
|
||||
default:
|
||||
var count = set.Count(id);
|
||||
if (set.DataByValue(id, customization[id], out _) < 0)
|
||||
|
|
@ -148,7 +145,7 @@ namespace Glamourer.Gui
|
|||
switch (use)
|
||||
{
|
||||
case DesignNameUse.SaveCurrent:
|
||||
SaveNewDesign(ConditionalCopy(_currentSave));
|
||||
SaveNewDesign(ConditionalCopy(_currentSave, _holdShift, _holdCtrl));
|
||||
break;
|
||||
case DesignNameUse.NewDesign:
|
||||
var empty = new CharacterSave();
|
||||
|
|
@ -157,7 +154,7 @@ namespace Glamourer.Gui
|
|||
SaveNewDesign(empty);
|
||||
break;
|
||||
case DesignNameUse.DuplicateDesign:
|
||||
SaveNewDesign(ConditionalCopy(_selection!.Data));
|
||||
SaveNewDesign(ConditionalCopy(_selection!.Data, _holdShift, _holdCtrl));
|
||||
break;
|
||||
case DesignNameUse.NewFolder:
|
||||
_designs.FileSystem
|
||||
|
|
@ -196,6 +193,8 @@ namespace Glamourer.Gui
|
|||
{
|
||||
_newDesignName = string.Empty;
|
||||
_keyboardFocus = true;
|
||||
_holdCtrl = ImGui.GetIO().KeyCtrl;
|
||||
_holdShift = ImGui.GetIO().KeyShift;
|
||||
ImGui.OpenPopup($"{DesignNamePopupLabel}{use}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
23
Glamourer/Offsets.cs
Normal file
23
Glamourer/Offsets.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace Glamourer;
|
||||
|
||||
public static class Offsets
|
||||
{
|
||||
public static class Character
|
||||
{
|
||||
public const int Wetness = 0x1ADA;
|
||||
public const int HatVisible = 0x84E;
|
||||
public const int VisorToggled = 0x84F;
|
||||
public const int WeaponHidden1 = 0x84F;
|
||||
public const int WeaponHidden2 = 0x72C;
|
||||
public const int Alpha = 0x19E0;
|
||||
|
||||
public static class Flags
|
||||
{
|
||||
public const byte IsHatHidden = 0x01;
|
||||
public const byte IsVisorToggled = 0x08;
|
||||
public const byte IsWet = 0x80;
|
||||
public const byte IsWeaponHidden1 = 0x01;
|
||||
public const byte IsWeaponHidden2 = 0x02;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,135 +6,155 @@ using Glamourer.Gui;
|
|||
using ImGuiNET;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer
|
||||
namespace Glamourer;
|
||||
|
||||
public class PenumbraAttach : IDisposable
|
||||
{
|
||||
public class PenumbraAttach : IDisposable
|
||||
public const int RequiredPenumbraShareVersion = 4;
|
||||
|
||||
private ICallGateSubscriber<ChangedItemType, uint, object>? _tooltipSubscriber;
|
||||
private ICallGateSubscriber<MouseButton, ChangedItemType, uint, object>? _clickSubscriber;
|
||||
private ICallGateSubscriber<string, int, object>? _redrawSubscriberName;
|
||||
private ICallGateSubscriber<GameObject, int, object>? _redrawSubscriberObject;
|
||||
|
||||
private readonly ICallGateSubscriber<object?> _initializedEvent;
|
||||
private readonly ICallGateSubscriber<object?> _disposedEvent;
|
||||
|
||||
public PenumbraAttach(bool attach)
|
||||
{
|
||||
public const int RequiredPenumbraShareVersion = 3;
|
||||
_initializedEvent = Dalamud.PluginInterface.GetIpcSubscriber<object?>("Penumbra.Initialized");
|
||||
_disposedEvent = Dalamud.PluginInterface.GetIpcSubscriber<object?>("Penumbra.Disposed");
|
||||
_initializedEvent.Subscribe(Reattach);
|
||||
_disposedEvent.Subscribe(Unattach);
|
||||
Reattach(attach);
|
||||
}
|
||||
|
||||
private ICallGateSubscriber<ChangedItemType, uint, object>? _tooltipSubscriber;
|
||||
private ICallGateSubscriber<MouseButton, ChangedItemType, uint, object>? _clickSubscriber;
|
||||
private ICallGateSubscriber<string, int, object>? _redrawSubscriberName;
|
||||
private ICallGateSubscriber<GameObject, int, object>? _redrawSubscriberObject;
|
||||
private void Reattach()
|
||||
=> Reattach(Glamourer.Config.AttachToPenumbra);
|
||||
|
||||
public PenumbraAttach(bool attach)
|
||||
=> Reattach(attach);
|
||||
public void Reattach(bool attach)
|
||||
{
|
||||
try
|
||||
{
|
||||
Unattach();
|
||||
|
||||
public void Reattach(bool attach)
|
||||
var versionSubscriber = Dalamud.PluginInterface.GetIpcSubscriber<int>("Penumbra.ApiVersion");
|
||||
var version = versionSubscriber.InvokeFunc();
|
||||
if (version != RequiredPenumbraShareVersion)
|
||||
throw new Exception($"Invalid Version {version}, required Version {RequiredPenumbraShareVersion}.");
|
||||
|
||||
_redrawSubscriberName = Dalamud.PluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
|
||||
_redrawSubscriberObject = Dalamud.PluginInterface.GetIpcSubscriber<GameObject, int, object>("Penumbra.RedrawObject");
|
||||
|
||||
if (!attach)
|
||||
return;
|
||||
|
||||
_tooltipSubscriber = Dalamud.PluginInterface.GetIpcSubscriber<ChangedItemType, uint, object>("Penumbra.ChangedItemTooltip");
|
||||
_clickSubscriber =
|
||||
Dalamud.PluginInterface.GetIpcSubscriber<MouseButton, ChangedItemType, uint, object>("Penumbra.ChangedItemClick");
|
||||
_tooltipSubscriber.Subscribe(PenumbraTooltip);
|
||||
_clickSubscriber.Subscribe(PenumbraRightClick);
|
||||
PluginLog.Debug("Glamourer attached to Penumbra.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PluginLog.Debug($"Could not attach to Penumbra:\n{e}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Unattach()
|
||||
{
|
||||
_tooltipSubscriber?.Unsubscribe(PenumbraTooltip);
|
||||
_clickSubscriber?.Unsubscribe(PenumbraRightClick);
|
||||
_tooltipSubscriber = null;
|
||||
_clickSubscriber = null;
|
||||
_redrawSubscriberName = null;
|
||||
if (_redrawSubscriberObject != null)
|
||||
{
|
||||
PluginLog.Debug("Glamourer detached from Penumbra.");
|
||||
_redrawSubscriberObject = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_initializedEvent.Unsubscribe(Reattach);
|
||||
_disposedEvent.Unsubscribe(Unattach);
|
||||
Unattach();
|
||||
}
|
||||
|
||||
private static void PenumbraTooltip(ChangedItemType type, uint _)
|
||||
{
|
||||
if (type == ChangedItemType.Item)
|
||||
ImGui.Text("Right click to apply to current Glamourer Set. [Glamourer]");
|
||||
}
|
||||
|
||||
private void PenumbraRightClick(MouseButton button, ChangedItemType type, uint id)
|
||||
{
|
||||
if (button != MouseButton.Right || type != ChangedItemType.Item)
|
||||
return;
|
||||
|
||||
var gPose = Dalamud.Objects[Interface.GPoseObjectId] as Character;
|
||||
var player = Dalamud.Objects[0] as Character;
|
||||
var item = (Lumina.Excel.GeneratedSheets.Item)type.GetObject(id)!;
|
||||
var writeItem = new Item(item, string.Empty);
|
||||
if (gPose != null)
|
||||
{
|
||||
writeItem.Write(gPose.Address);
|
||||
UpdateCharacters(gPose, player);
|
||||
}
|
||||
else if (player != null)
|
||||
{
|
||||
writeItem.Write(player.Address);
|
||||
UpdateCharacters(player);
|
||||
}
|
||||
}
|
||||
|
||||
public void RedrawObject(GameObject actor, RedrawType settings, bool repeat)
|
||||
{
|
||||
if (_redrawSubscriberObject != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Unattach();
|
||||
|
||||
var versionSubscriber = Dalamud.PluginInterface.GetIpcSubscriber<int>("Penumbra.ApiVersion");
|
||||
var version = versionSubscriber.InvokeFunc();
|
||||
if (version != RequiredPenumbraShareVersion)
|
||||
throw new Exception($"Invalid Version {version}, required Version {RequiredPenumbraShareVersion}.");
|
||||
|
||||
_redrawSubscriberName = Dalamud.PluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
|
||||
_redrawSubscriberObject = Dalamud.PluginInterface.GetIpcSubscriber<GameObject, int, object>("Penumbra.RedrawObject");
|
||||
|
||||
if (!attach)
|
||||
return;
|
||||
|
||||
_tooltipSubscriber = Dalamud.PluginInterface.GetIpcSubscriber<ChangedItemType, uint, object>("Penumbra.ChangedItemTooltip");
|
||||
_clickSubscriber =
|
||||
Dalamud.PluginInterface.GetIpcSubscriber<MouseButton, ChangedItemType, uint, object>("Penumbra.ChangedItemClick");
|
||||
_tooltipSubscriber.Subscribe(PenumbraTooltip);
|
||||
_clickSubscriber.Subscribe(PenumbraRightClick);
|
||||
_redrawSubscriberObject.InvokeAction(actor, (int)settings);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PluginLog.Debug($"Could not attach to Penumbra:\n{e}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Unattach()
|
||||
{
|
||||
_tooltipSubscriber?.Unsubscribe(PenumbraTooltip);
|
||||
_clickSubscriber?.Unsubscribe(PenumbraRightClick);
|
||||
_tooltipSubscriber = null;
|
||||
_clickSubscriber = null;
|
||||
_redrawSubscriberName = null;
|
||||
_redrawSubscriberObject = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> Unattach();
|
||||
|
||||
private static void PenumbraTooltip(ChangedItemType type, uint _)
|
||||
{
|
||||
if (type == ChangedItemType.Item)
|
||||
ImGui.Text("Right click to apply to current Glamourer Set. [Glamourer]");
|
||||
}
|
||||
|
||||
private void PenumbraRightClick(MouseButton button, ChangedItemType type, uint id)
|
||||
{
|
||||
if (button != MouseButton.Right || type != ChangedItemType.Item)
|
||||
return;
|
||||
|
||||
var gPose = Dalamud.Objects[Interface.GPoseObjectId] as Character;
|
||||
var player = Dalamud.Objects[0] as Character;
|
||||
var item = (Lumina.Excel.GeneratedSheets.Item) type.GetObject(id)!;
|
||||
var writeItem = new Item(item, string.Empty);
|
||||
if (gPose != null)
|
||||
{
|
||||
writeItem.Write(gPose.Address);
|
||||
UpdateCharacters(gPose, player);
|
||||
}
|
||||
else if (player != null)
|
||||
{
|
||||
writeItem.Write(player.Address);
|
||||
UpdateCharacters(player);
|
||||
}
|
||||
}
|
||||
|
||||
public void RedrawObject(GameObject actor, RedrawType settings, bool repeat)
|
||||
{
|
||||
if (_redrawSubscriberObject != null)
|
||||
{
|
||||
try
|
||||
if (repeat)
|
||||
{
|
||||
_redrawSubscriberObject.InvokeAction(actor, (int) settings);
|
||||
Reattach(Glamourer.Config.AttachToPenumbra);
|
||||
RedrawObject(actor, settings, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
if (repeat)
|
||||
{
|
||||
Reattach(Glamourer.Config.AttachToPenumbra);
|
||||
RedrawObject(actor, settings, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.Debug($"Failure redrawing object:\n{e}");
|
||||
}
|
||||
PluginLog.Debug($"Failure redrawing object:\n{e}");
|
||||
}
|
||||
}
|
||||
else if (repeat)
|
||||
{
|
||||
Reattach(Glamourer.Config.AttachToPenumbra);
|
||||
RedrawObject(actor, settings, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.Debug("Trying to redraw object, but not attached to Penumbra.");
|
||||
}
|
||||
}
|
||||
|
||||
// Update objects without triggering PlayerWatcher Events,
|
||||
// then manually redraw using Penumbra.
|
||||
public void UpdateCharacters(Character character, Character? gPoseOriginalCharacter = null)
|
||||
else if (repeat)
|
||||
{
|
||||
var newEquip = Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character);
|
||||
RedrawObject(character, RedrawType.WithSettings, true);
|
||||
|
||||
// Special case for carrying over changes to the gPose player to the regular player, too.
|
||||
if (gPoseOriginalCharacter == null)
|
||||
return;
|
||||
|
||||
newEquip.Write(gPoseOriginalCharacter.Address);
|
||||
Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(gPoseOriginalCharacter);
|
||||
RedrawObject(gPoseOriginalCharacter, RedrawType.AfterGPoseWithSettings, false);
|
||||
Reattach(Glamourer.Config.AttachToPenumbra);
|
||||
RedrawObject(actor, settings, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.Debug("Trying to redraw object, but not attached to Penumbra.");
|
||||
}
|
||||
}
|
||||
|
||||
// Update objects without triggering PlayerWatcher Events,
|
||||
// then manually redraw using Penumbra.
|
||||
public void UpdateCharacters(Character character, Character? gPoseOriginalCharacter = null)
|
||||
{
|
||||
var newEquip = Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character);
|
||||
RedrawObject(character, RedrawType.Redraw, true);
|
||||
|
||||
// Special case for carrying over changes to the gPose player to the regular player, too.
|
||||
if (gPoseOriginalCharacter == null)
|
||||
return;
|
||||
|
||||
newEquip.Write(gPoseOriginalCharacter.Address);
|
||||
Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(gPoseOriginalCharacter);
|
||||
RedrawObject(gPoseOriginalCharacter, RedrawType.AfterGPose, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue