mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Compare commits
171 commits
testing_1.
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b6517aae8 | ||
|
|
aadcf771e7 | ||
|
|
bf4673a1d9 | ||
|
|
76b214c643 | ||
|
|
434a5a809e | ||
|
|
88fe25f69e | ||
|
|
bef1e39ac3 | ||
|
|
c604d5dbe5 | ||
|
|
a0d912a395 | ||
|
|
a56852f918 | ||
|
|
4228fc1b89 | ||
|
|
e644b8da28 | ||
|
|
ace3a8f755 | ||
|
|
76ed347cbf | ||
|
|
c3469a1687 | ||
|
|
0a9693daea | ||
|
|
414bd8bee7 | ||
|
|
8e1745d67a | ||
|
|
889f01a724 | ||
|
|
6e62905fa7 | ||
|
|
654787fa0d | ||
|
|
835ba23935 | ||
|
|
389a8781d6 | ||
|
|
3eabe591df | ||
|
|
487d3b9399 | ||
|
|
4d4e4669dd | ||
|
|
fb065549e9 | ||
|
|
2c34154915 | ||
|
|
3704051b0f | ||
|
|
b2b8f2b6eb | ||
|
|
22e6c0655b | ||
|
|
bb2ba0cf11 | ||
|
|
e854386b23 | ||
|
|
49d24df2e7 | ||
|
|
c9b291c2f3 | ||
|
|
65f789880d | ||
|
|
abf998a727 | ||
|
|
4cc191cb25 | ||
|
|
dc431c10a5 | ||
|
|
26862ba78f | ||
|
|
e4374337f2 | ||
|
|
240c889fff | ||
|
|
612cd31c3e | ||
|
|
304b362002 | ||
|
|
8f34f197d0 | ||
|
|
1c97266a93 | ||
|
|
a9caddafd5 | ||
|
|
34bf95dddb | ||
|
|
4761b8f584 | ||
|
|
0d94aae732 | ||
|
|
e83f328cdc | ||
|
|
52fd29c478 | ||
|
|
a8b79993df | ||
|
|
98574558e5 | ||
|
|
557cbf23ce | ||
|
|
56753ae7ba | ||
|
|
b66df624f7 | ||
|
|
be78f1447b | ||
|
|
97e32a3cb7 | ||
|
|
4472920536 | ||
|
|
ac6a726f57 | ||
|
|
00d550f4fe | ||
|
|
0f98fac157 | ||
|
|
c25f0f72db | ||
|
|
72e05e23bc | ||
|
|
2c3bed6ba5 | ||
|
|
d6df9885dc | ||
|
|
e7936500e0 | ||
|
|
4ef4e65d46 | ||
|
|
40b4a8fd7a | ||
|
|
8a1f03c272 | ||
|
|
8ed479eddf | ||
|
|
c0a278ca2c | ||
|
|
2e9a7004c6 | ||
|
|
75c76a92b9 | ||
|
|
282935c6d6 | ||
|
|
d7b189b714 | ||
|
|
e3da3f356c | ||
|
|
66bed4217f | ||
|
|
56bbf6593a | ||
|
|
b8e1e7c384 | ||
|
|
a0d2c39f45 | ||
|
|
07df3186c2 | ||
|
|
5b59e74417 | ||
|
|
b4485f028d | ||
|
|
74674cfa0c | ||
|
|
f192c17c9b | ||
|
|
aa1ac29182 | ||
|
|
081ac6bf8b | ||
|
|
e4b32343ae | ||
|
|
c93370ec92 | ||
|
|
9abd7f2767 | ||
|
|
8a9877bb01 | ||
|
|
c1e1476fa6 | ||
|
|
b1abbb8e77 | ||
|
|
fcb0660def | ||
|
|
a6073e2a42 | ||
|
|
2c87077918 | ||
|
|
4e0a9f62b9 | ||
|
|
39636f5293 | ||
|
|
b53124e708 | ||
|
|
9a684c9ff5 | ||
|
|
c7d1620c1e | ||
|
|
325b54031c | ||
|
|
155a9d6266 | ||
|
|
4f6fb44f79 | ||
|
|
bfce99859f | ||
|
|
6c556d6a61 | ||
|
|
7ed42005dd | ||
|
|
aad978f5f6 | ||
|
|
c0ad4aab51 | ||
|
|
8fe0ac8195 | ||
|
|
46f8818cee | ||
|
|
118f51cc64 | ||
|
|
096d82741d | ||
|
|
b98cb31fd2 | ||
|
|
90813ce030 | ||
|
|
95bc52b2bc | ||
|
|
d79e4b5853 | ||
|
|
a40a6905be | ||
|
|
6b3a64ce14 | ||
|
|
4fca1600ca | ||
|
|
b1e65e6f9d | ||
|
|
381b23fe0c | ||
|
|
782c4446b2 | ||
|
|
76eaa75d04 | ||
|
|
361ed536a3 | ||
|
|
b1d00e9812 | ||
|
|
b0abf865cb | ||
|
|
d398381b52 | ||
|
|
d75d70bee5 | ||
|
|
296f1e90b5 | ||
|
|
9d3dfbbece | ||
|
|
d6d592f099 | ||
|
|
00cb1b6643 | ||
|
|
22babad789 | ||
|
|
18ff905746 | ||
|
|
fd0d761b92 | ||
|
|
750d4f9eca | ||
|
|
25517525c9 | ||
|
|
99a8e1e8c5 | ||
|
|
381b2a1b8b | ||
|
|
3dee511b9a | ||
|
|
e93c3b7bb8 | ||
|
|
773682838e | ||
|
|
c9f00c6369 | ||
|
|
2026069ed3 | ||
|
|
ae093506c1 | ||
|
|
87f1b613f9 | ||
|
|
71e15474b2 | ||
|
|
3fd6108fa1 | ||
|
|
b9e4c144c2 | ||
|
|
6e685b96d1 | ||
|
|
c96f009fb4 | ||
|
|
3112079776 | ||
|
|
7015737d88 | ||
|
|
94f6e870e6 | ||
|
|
528aae7eee | ||
|
|
425c9471fb | ||
|
|
0c8110e15e | ||
|
|
8a7ec45bbf | ||
|
|
c1f84b4303 | ||
|
|
5a9e9513f4 | ||
|
|
9e7679e70f | ||
|
|
e5b2114ac2 | ||
|
|
1168460942 | ||
|
|
f7d6e75a9b | ||
|
|
5ca151b675 | ||
|
|
67fd65d366 | ||
|
|
45981f2fee | ||
|
|
cf308fc118 |
172 changed files with 3599 additions and 1726 deletions
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
|
@ -15,12 +15,12 @@ jobs:
|
|||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.x.x'
|
||||
dotnet-version: '9.x.x'
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Download Dalamud
|
||||
run: |
|
||||
Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/latest.zip -OutFile latest.zip
|
||||
Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -OutFile latest.zip
|
||||
Expand-Archive -Force latest.zip "$env:AppData\XIVLauncher\addon\Hooks\dev"
|
||||
- name: Build
|
||||
run: |
|
||||
|
|
|
|||
2
.github/workflows/test_release.yml
vendored
2
.github/workflows/test_release.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.x.x'
|
||||
dotnet-version: '9.x.x'
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Download Dalamud
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 9f9bdf0873899d2e45fabaca446bb1624303b418
|
||||
Subproject commit 59a7ab5fa9941eb754757b62e4cb189e455e9514
|
||||
|
|
@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
Glamourer\Glamourer.json = Glamourer\Glamourer.json
|
||||
repo.json = repo.json
|
||||
.github\workflows\test_release.yml = .github\workflows\test_release.yml
|
||||
EndProjectSection
|
||||
|
|
@ -29,30 +30,30 @@ Global
|
|||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Release|Any CPU.Build.0 = Release|x64
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}.Release|Any CPU.Build.0 = Release|x64
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{C0A2FAF8-C3AE-4B7B-ADDB-4AAC1A855428}.Release|Any CPU.Build.0 = Release|x64
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{AAFE22E7-0F9B-462A-AAA3-6EE3B268F3F8}.Release|Any CPU.Build.0 = Release|x64
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{EF233CE2-F243-449E-BE05-72B9D110E419}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9B46691B-FAB2-4CC3-9B89-C8B91A590F47}.Release|Any CPU.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
|
|
@ -1,33 +1,43 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.State;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Api;
|
||||
|
||||
public class ApiHelpers(ObjectManager objects, StateManager stateManager, ActorManager actors) : IApiService
|
||||
public class ApiHelpers(ActorObjectManager objects, StateManager stateManager, ActorManager actors) : IApiService
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal IEnumerable<ActorState> FindExistingStates(string actorName)
|
||||
internal IEnumerable<ActorState> FindExistingStates(string actorName, ushort worldId = ushort.MaxValue)
|
||||
{
|
||||
if (actorName.Length == 0 || !ByteString.FromString(actorName, out var byteString))
|
||||
yield break;
|
||||
|
||||
foreach (var state in stateManager.Values.Where(state
|
||||
=> state.Identifier.Type is IdentifierType.Player && state.Identifier.PlayerName == byteString))
|
||||
yield return state;
|
||||
if (worldId == WorldId.AnyWorld.Id)
|
||||
{
|
||||
foreach (var state in stateManager.Values.Where(state
|
||||
=> state.Identifier.Type is IdentifierType.Player && state.Identifier.PlayerName == byteString))
|
||||
yield return state;
|
||||
}
|
||||
else
|
||||
{
|
||||
var identifier = actors.CreatePlayer(byteString, worldId);
|
||||
if (stateManager.TryGetValue(identifier, out var state))
|
||||
yield return state;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal GlamourerApiEc FindExistingState(int objectIndex, out ActorState? state)
|
||||
{
|
||||
var actor = objects[objectIndex];
|
||||
var actor = objects.Objects[objectIndex];
|
||||
var identifier = actor.GetIdentifier(actors);
|
||||
if (!identifier.IsValid)
|
||||
{
|
||||
|
|
@ -42,7 +52,7 @@ public class ApiHelpers(ObjectManager objects, StateManager stateManager, ActorM
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal ActorState? FindState(int objectIndex)
|
||||
{
|
||||
var actor = objects[objectIndex];
|
||||
var actor = objects.Objects[objectIndex];
|
||||
var identifier = actor.GetIdentifier(actors);
|
||||
if (identifier.IsValid && stateManager.GetOrCreate(identifier, actor, out var state))
|
||||
return state;
|
||||
|
|
@ -73,10 +83,8 @@ public class ApiHelpers(ObjectManager objects, StateManager stateManager, ActorM
|
|||
if (objectName.Length == 0 || !ByteString.FromString(objectName, out var byteString))
|
||||
return [];
|
||||
|
||||
objects.Update();
|
||||
|
||||
return stateManager.Values.Where(state => state.Identifier.Type is IdentifierType.Player && state.Identifier.PlayerName == byteString)
|
||||
.Concat(objects.Identifiers
|
||||
.Concat(objects
|
||||
.Where(kvp => kvp.Key is { IsValid: true, Type: IdentifierType.Player } && kvp.Key.PlayerName == byteString)
|
||||
.SelectWhere(kvp =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,15 +2,32 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.State;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Services;
|
||||
|
||||
namespace Glamourer.Api;
|
||||
|
||||
public class DesignsApi(ApiHelpers helpers, DesignManager designs, StateManager stateManager) : IGlamourerApiDesigns, IApiService
|
||||
public class DesignsApi(
|
||||
ApiHelpers helpers,
|
||||
DesignManager designs,
|
||||
StateManager stateManager,
|
||||
DesignFileSystem fileSystem,
|
||||
DesignColors color,
|
||||
DesignConverter converter)
|
||||
: IGlamourerApiDesigns, IApiService
|
||||
{
|
||||
public Dictionary<Guid, string> GetDesignList()
|
||||
=> designs.Designs.ToDictionary(d => d.Identifier, d => d.Name.Text);
|
||||
|
||||
public Dictionary<Guid, (string DisplayName, string FullPath, uint DisplayColor, bool ShownInQdb)> GetDesignListExtended()
|
||||
=> fileSystem.ToDictionary(kvp => kvp.Key.Identifier,
|
||||
kvp => (kvp.Key.Name.Text, kvp.Value.FullName(), color.GetColor(kvp.Key), kvp.Key.QuickDesign));
|
||||
|
||||
public (string DisplayName, string FullPath, uint DisplayColor, bool ShowInQdb) GetExtendedDesignData(Guid designId)
|
||||
=> designs.Designs.ByIdentifier(designId) is { } d
|
||||
? (d.Name.Text, fileSystem.TryGetValue(d, out var leaf) ? leaf.FullName() : d.Name.Text, color.GetColor(d), d.QuickDesign)
|
||||
: (string.Empty, string.Empty, 0, false);
|
||||
|
||||
public GlamourerApiEc ApplyDesign(Guid designId, int objectIndex, uint key, ApplyFlag flags)
|
||||
{
|
||||
var args = ApiHelpers.Args("Design", designId, "Index", objectIndex, "Key", key, "Flags", flags);
|
||||
|
|
@ -66,4 +83,56 @@ public class DesignsApi(ApiHelpers helpers, DesignManager designs, StateManager
|
|||
|
||||
return ApiHelpers.Return(GlamourerApiEc.Success, args);
|
||||
}
|
||||
|
||||
public (GlamourerApiEc, Guid) AddDesign(string designInput, string name)
|
||||
{
|
||||
var args = ApiHelpers.Args("DesignData", designInput, "Name", name);
|
||||
|
||||
if (converter.FromBase64(designInput, true, true, out _) is not { } designBase)
|
||||
try
|
||||
{
|
||||
var jObj = JObject.Parse(designInput);
|
||||
designBase = converter.FromJObject(jObj, true, true);
|
||||
if (designBase is null)
|
||||
return (ApiHelpers.Return(GlamourerApiEc.CouldNotParse, args), Guid.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Log.Error($"Failure parsing data for AddDesign due to\n{ex}");
|
||||
return (ApiHelpers.Return(GlamourerApiEc.CouldNotParse, args), Guid.Empty);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var design = designBase is Design d
|
||||
? designs.CreateClone(d, name, true)
|
||||
: designs.CreateClone(designBase, name, true);
|
||||
return (ApiHelpers.Return(GlamourerApiEc.Success, args), design.Identifier);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Log.Error($"Unknown error creating design via IPC:\n{ex}");
|
||||
return (ApiHelpers.Return(GlamourerApiEc.UnknownError, args), Guid.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public GlamourerApiEc DeleteDesign(Guid designId)
|
||||
{
|
||||
var args = ApiHelpers.Args("DesignId", designId);
|
||||
if (designs.Designs.ByIdentifier(designId) is not { } design)
|
||||
return ApiHelpers.Return(GlamourerApiEc.NothingDone, args);
|
||||
|
||||
designs.Delete(design);
|
||||
return ApiHelpers.Return(GlamourerApiEc.Success, args);
|
||||
}
|
||||
|
||||
public string? GetDesignBase64(Guid designId)
|
||||
=> designs.Designs.ByIdentifier(designId) is { } design
|
||||
? converter.ShareBase64(design)
|
||||
: null;
|
||||
|
||||
public JObject? GetDesignJObject(Guid designId)
|
||||
=> designs.Designs.ByIdentifier(designId) is { } design
|
||||
? converter.ShareJObject(design)
|
||||
: null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace Glamourer.Api;
|
|||
public class GlamourerApi(DesignsApi designs, StateApi state, ItemsApi items) : IGlamourerApi, IApiService
|
||||
{
|
||||
public const int CurrentApiVersionMajor = 1;
|
||||
public const int CurrentApiVersionMinor = 4;
|
||||
public const int CurrentApiVersionMinor = 7;
|
||||
|
||||
public (int Major, int Minor) ApiVersion
|
||||
=> (CurrentApiVersionMajor, CurrentApiVersionMinor);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,14 @@ public sealed class IpcProviders : IDisposable, IApiService
|
|||
IpcSubscribers.ApiVersion.Provider(pi, api),
|
||||
|
||||
IpcSubscribers.GetDesignList.Provider(pi, api.Designs),
|
||||
IpcSubscribers.GetDesignListExtended.Provider(pi, api.Designs),
|
||||
IpcSubscribers.GetExtendedDesignData.Provider(pi, api.Designs),
|
||||
IpcSubscribers.ApplyDesign.Provider(pi, api.Designs),
|
||||
IpcSubscribers.ApplyDesignName.Provider(pi, api.Designs),
|
||||
IpcSubscribers.AddDesign.Provider(pi, api.Designs),
|
||||
IpcSubscribers.DeleteDesign.Provider(pi, api.Designs),
|
||||
IpcSubscribers.GetDesignBase64.Provider(pi, api.Designs),
|
||||
IpcSubscribers.GetDesignJObject.Provider(pi, api.Designs),
|
||||
|
||||
IpcSubscribers.SetItem.Provider(pi, api.Items),
|
||||
IpcSubscribers.SetItemName.Provider(pi, api.Items),
|
||||
|
|
@ -36,6 +42,8 @@ public sealed class IpcProviders : IDisposable, IApiService
|
|||
(a, b, c, d, e, f) => (int)api.Items.SetItemName(a, (ApiEquipSlot)b, c, [d], e, (ApplyFlag)f)),
|
||||
IpcSubscribers.SetBonusItem.Provider(pi, api.Items),
|
||||
IpcSubscribers.SetBonusItemName.Provider(pi, api.Items),
|
||||
IpcSubscribers.SetMetaState.Provider(pi, api.Items),
|
||||
IpcSubscribers.SetMetaStateName.Provider(pi, api.Items),
|
||||
IpcSubscribers.GetState.Provider(pi, api.State),
|
||||
IpcSubscribers.GetStateName.Provider(pi, api.State),
|
||||
IpcSubscribers.GetStateBase64.Provider(pi, api.State),
|
||||
|
|
@ -46,6 +54,7 @@ public sealed class IpcProviders : IDisposable, IApiService
|
|||
IpcSubscribers.RevertStateName.Provider(pi, api.State),
|
||||
IpcSubscribers.UnlockState.Provider(pi, api.State),
|
||||
IpcSubscribers.UnlockStateName.Provider(pi, api.State),
|
||||
IpcSubscribers.DeletePlayerState.Provider(pi, api.State),
|
||||
IpcSubscribers.UnlockAll.Provider(pi, api.State),
|
||||
IpcSubscribers.RevertToAutomation.Provider(pi, api.State),
|
||||
IpcSubscribers.RevertToAutomationName.Provider(pi, api.State),
|
||||
|
|
|
|||
|
|
@ -4,34 +4,31 @@ using Glamourer.Automation;
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Interop;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
using Penumbra.GameData.Structs;
|
||||
using StateChanged = Glamourer.Events.StateChanged;
|
||||
|
||||
namespace Glamourer.Api;
|
||||
|
||||
public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
||||
{
|
||||
private readonly ApiHelpers _helpers;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignApplier _autoDesigns;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly StateChanged _stateChanged;
|
||||
private readonly StateFinalized _stateFinalized;
|
||||
private readonly GPoseService _gPose;
|
||||
private readonly ApiHelpers _helpers;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly AutoDesignApplier _autoDesigns;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly StateChanged _stateChanged;
|
||||
private readonly StateFinalized _stateFinalized;
|
||||
private readonly GPoseService _gPose;
|
||||
|
||||
public StateApi(ApiHelpers helpers,
|
||||
StateManager stateManager,
|
||||
DesignConverter converter,
|
||||
Configuration config,
|
||||
AutoDesignApplier autoDesigns,
|
||||
ObjectManager objects,
|
||||
ActorObjectManager objects,
|
||||
StateChanged stateChanged,
|
||||
StateFinalized stateFinalized,
|
||||
GPoseService gPose)
|
||||
|
|
@ -39,7 +36,6 @@ public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
|||
_helpers = helpers;
|
||||
_stateManager = stateManager;
|
||||
_converter = converter;
|
||||
_config = config;
|
||||
_autoDesigns = autoDesigns;
|
||||
_objects = objects;
|
||||
_stateChanged = stateChanged;
|
||||
|
|
@ -204,6 +200,27 @@ public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
|||
return ApiHelpers.Return(GlamourerApiEc.Success, args);
|
||||
}
|
||||
|
||||
public GlamourerApiEc DeletePlayerState(string playerName, ushort worldId, uint key)
|
||||
{
|
||||
var args = ApiHelpers.Args("Name", playerName, "World", worldId, "Key", key);
|
||||
var states = _helpers.FindExistingStates(playerName).ToList();
|
||||
if (states.Count is 0)
|
||||
return ApiHelpers.Return(GlamourerApiEc.NothingDone, args);
|
||||
|
||||
var anyLocked = false;
|
||||
foreach (var state in states)
|
||||
{
|
||||
if (state.CanUnlock(key))
|
||||
_stateManager.DeleteState(state.Identifier);
|
||||
else
|
||||
anyLocked = true;
|
||||
}
|
||||
|
||||
return ApiHelpers.Return(anyLocked
|
||||
? GlamourerApiEc.InvalidKey
|
||||
: GlamourerApiEc.Success, args);
|
||||
}
|
||||
|
||||
public int UnlockAll(uint key)
|
||||
=> _stateManager.Values.Count(state => state.Unlock(key));
|
||||
|
||||
|
|
@ -219,7 +236,7 @@ public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
|||
if (!state.CanUnlock(key))
|
||||
return ApiHelpers.Return(GlamourerApiEc.InvalidKey, args);
|
||||
|
||||
RevertToAutomation(_objects[objectIndex], state, key, flags);
|
||||
RevertToAutomation(_objects.Objects[objectIndex], state, key, flags);
|
||||
return ApiHelpers.Return(GlamourerApiEc.Success, args);
|
||||
}
|
||||
|
||||
|
|
@ -272,15 +289,9 @@ public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
|||
var source = (flags & ApplyFlag.Once) != 0 ? StateSource.IpcManual : StateSource.IpcFixed;
|
||||
switch (flags & (ApplyFlag.Equipment | ApplyFlag.Customization))
|
||||
{
|
||||
case ApplyFlag.Equipment:
|
||||
_stateManager.ResetEquip(state, source, key);
|
||||
break;
|
||||
case ApplyFlag.Customization:
|
||||
_stateManager.ResetCustomize(state, source, key);
|
||||
break;
|
||||
case ApplyFlag.Equipment | ApplyFlag.Customization:
|
||||
_stateManager.ResetState(state, source, key);
|
||||
break;
|
||||
case ApplyFlag.Equipment: _stateManager.ResetEquip(state, source, key); break;
|
||||
case ApplyFlag.Customization: _stateManager.ResetCustomize(state, source, key); break;
|
||||
case ApplyFlag.Equipment | ApplyFlag.Customization: _stateManager.ResetState(state, source, key, true); break;
|
||||
}
|
||||
|
||||
ApiHelpers.Lock(state, key, flags);
|
||||
|
|
@ -288,7 +299,6 @@ public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
|||
|
||||
private GlamourerApiEc RevertToAutomation(ActorState state, uint key, ApplyFlag flags)
|
||||
{
|
||||
_objects.Update();
|
||||
if (!_objects.TryGetValue(state.Identifier, out var actors) || !actors.Valid)
|
||||
return GlamourerApiEc.ActorNotFound;
|
||||
|
||||
|
|
@ -314,7 +324,7 @@ public sealed class StateApi : IGlamourerApiState, IApiService, IDisposable
|
|||
if (!state.CanUnlock(key))
|
||||
return (GlamourerApiEc.InvalidKey, null);
|
||||
|
||||
return (GlamourerApiEc.Success, _converter.ShareJObject(state, ApplicationRules.AllWithConfig(_config)));
|
||||
return (GlamourerApiEc.Success, _converter.ShareJObject(state, ApplicationRules.All));
|
||||
}
|
||||
|
||||
private (GlamourerApiEc, string?) ConvertBase64(ActorState? state, uint key)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public static class ApplicationTypeExtensions
|
|||
var customizeFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeFlagExtensions.All : 0;
|
||||
var parameterFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeParameterExtensions.All : 0;
|
||||
var crestFlags = type.HasFlag(ApplicationType.GearCustomization) ? CrestExtensions.AllRelevant : 0;
|
||||
var metaFlags = (type.HasFlag(ApplicationType.Armor) ? MetaFlag.HatState | MetaFlag.VisorState : 0)
|
||||
var metaFlags = (type.HasFlag(ApplicationType.Armor) ? MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.EarState : 0)
|
||||
| (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0)
|
||||
| (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0);
|
||||
var bonusFlags = type.HasFlag(ApplicationType.Armor) ? BonusExtensions.All : 0;
|
||||
|
|
@ -47,7 +47,13 @@ public static class ApplicationTypeExtensions
|
|||
}
|
||||
|
||||
public static ApplicationCollection ApplyWhat(this ApplicationType type, IDesignStandIn designStandIn)
|
||||
=> designStandIn is not DesignBase design ? type.Collection() : type.Collection().Restrict(design.Application);
|
||||
{
|
||||
if(designStandIn is not DesignBase design)
|
||||
return type.Collection();
|
||||
var ret = type.Collection().Restrict(design.Application);
|
||||
ret.CustomizeRaw = ret.CustomizeRaw.FixApplication(design.CustomizeSet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand;
|
||||
public const EquipFlag ArmorFlags = EquipFlag.Head | EquipFlag.Body | EquipFlag.Hands | EquipFlag.Legs | EquipFlag.Feet;
|
||||
|
|
|
|||
|
|
@ -11,29 +11,28 @@ using Penumbra.GameData.DataContainers;
|
|||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Automation;
|
||||
|
||||
public sealed class AutoDesignApplier : IDisposable
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly StateManager _state;
|
||||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly WeaponLoading _weapons;
|
||||
private readonly HumanModelList _humans;
|
||||
private readonly DesignMerger _designMerger;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly StateManager _state;
|
||||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly WeaponLoading _weapons;
|
||||
private readonly HumanModelList _humans;
|
||||
private readonly DesignMerger _designMerger;
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly JobChangeState _jobChangeState;
|
||||
|
||||
public AutoDesignApplier(Configuration config, AutoDesignManager manager, StateManager state, JobService jobs, ActorManager actors,
|
||||
AutomationChanged @event, ObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState,
|
||||
AutomationChanged @event, ActorObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState,
|
||||
EquippedGearset equippedGearset, DesignMerger designMerger, JobChangeState jobChangeState)
|
||||
{
|
||||
_config = config;
|
||||
|
|
@ -154,7 +153,6 @@ public sealed class AutoDesignApplier : IDisposable
|
|||
if (newSet is not { Enabled: true })
|
||||
return;
|
||||
|
||||
_objects.Update();
|
||||
foreach (var id in newSet.Identifiers)
|
||||
{
|
||||
if (_objects.TryGetValue(id, out var data))
|
||||
|
|
@ -293,8 +291,16 @@ public sealed class AutoDesignApplier : IDisposable
|
|||
set.Designs.Where(d => d.IsActive(actor))
|
||||
.SelectMany(d => d.Design.AllLinks(newApplication).Select(l => (l.Design, l.Flags & d.Type, d.Jobs.Flags))),
|
||||
state.ModelData.Customize, state.BaseData, true, _config.AlwaysApplyAssociatedMods);
|
||||
if (set.ResetTemporarySettings)
|
||||
|
||||
if (_objects.IsInGPose && actor.IsGPoseOrCutscene)
|
||||
{
|
||||
mergedDesign.ResetTemporarySettings = false;
|
||||
mergedDesign.AssociatedMods.Clear();
|
||||
}
|
||||
else if (set.ResetTemporarySettings)
|
||||
{
|
||||
mergedDesign.ResetTemporarySettings = true;
|
||||
}
|
||||
|
||||
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, false));
|
||||
forcedRedraw = mergedDesign.ForcedRedraw;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Newtonsoft.Json;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Glamourer.Services;
|
|||
using Newtonsoft.Json;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.Widgets;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
|
|
@ -31,6 +32,7 @@ public class DefaultDesignSettings
|
|||
public bool ResetAdvancedDyes = false;
|
||||
public bool ShowQuickDesignBar = true;
|
||||
public bool ResetTemporarySettings = false;
|
||||
public bool Locked = false;
|
||||
}
|
||||
|
||||
public class Configuration : IPluginConfiguration, ISavable
|
||||
|
|
@ -38,35 +40,40 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
[JsonIgnore]
|
||||
public readonly EphemeralConfig Ephemeral;
|
||||
|
||||
public bool UseRestrictedGearProtection { get; set; } = false;
|
||||
public bool OpenFoldersByDefault { get; set; } = false;
|
||||
public bool AutoRedrawEquipOnChanges { get; set; } = false;
|
||||
public bool EnableAutoDesigns { get; set; } = true;
|
||||
public bool HideApplyCheckmarks { get; set; } = false;
|
||||
public bool SmallEquip { get; set; } = false;
|
||||
public bool UnlockedItemMode { get; set; } = false;
|
||||
public byte DisableFestivals { get; set; } = 1;
|
||||
public bool EnableGameContextMenu { get; set; } = true;
|
||||
public bool HideWindowInCutscene { get; set; } = false;
|
||||
public bool ShowAutomationSetEditing { get; set; } = true;
|
||||
public bool ShowAllAutomatedApplicationRules { get; set; } = true;
|
||||
public bool ShowUnlockedItemWarnings { get; set; } = true;
|
||||
public bool RevertManualChangesOnZoneChange { get; set; } = false;
|
||||
public bool ShowQuickBarInTabs { get; set; } = true;
|
||||
public bool OpenWindowAtStart { get; set; } = false;
|
||||
public bool ShowWindowWhenUiHidden { get; set; } = false;
|
||||
public bool UseAdvancedParameters { get; set; } = true;
|
||||
public bool UseAdvancedDyes { get; set; } = true;
|
||||
public bool KeepAdvancedDyesAttached { get; set; } = true;
|
||||
public bool ShowPalettePlusImport { get; set; } = true;
|
||||
public bool UseFloatForColors { get; set; } = true;
|
||||
public bool UseRgbForColors { get; set; } = true;
|
||||
public bool ShowColorConfig { get; set; } = true;
|
||||
public bool ChangeEntireItem { get; set; } = false;
|
||||
public bool AlwaysApplyAssociatedMods { get; set; } = false;
|
||||
public bool UseTemporarySettings { get; set; } = true;
|
||||
public bool AllowDoubleClickToApply { get; set; } = false;
|
||||
public bool RespectManualOnAutomationUpdate { get; set; } = false;
|
||||
public bool AttachToPcp { get; set; } = true;
|
||||
public bool UseRestrictedGearProtection { get; set; } = false;
|
||||
public bool OpenFoldersByDefault { get; set; } = false;
|
||||
public bool AutoRedrawEquipOnChanges { get; set; } = false;
|
||||
public bool EnableAutoDesigns { get; set; } = true;
|
||||
public bool HideApplyCheckmarks { get; set; } = false;
|
||||
public bool SmallEquip { get; set; } = false;
|
||||
public bool UnlockedItemMode { get; set; } = false;
|
||||
public byte DisableFestivals { get; set; } = 1;
|
||||
public bool EnableGameContextMenu { get; set; } = true;
|
||||
public bool HideWindowInCutscene { get; set; } = false;
|
||||
public bool ShowAutomationSetEditing { get; set; } = true;
|
||||
public bool ShowAllAutomatedApplicationRules { get; set; } = true;
|
||||
public bool ShowUnlockedItemWarnings { get; set; } = true;
|
||||
public bool RevertManualChangesOnZoneChange { get; set; } = false;
|
||||
public bool ShowQuickBarInTabs { get; set; } = true;
|
||||
public bool OpenWindowAtStart { get; set; } = false;
|
||||
public bool ShowWindowWhenUiHidden { get; set; } = false;
|
||||
public bool KeepAdvancedDyesAttached { get; set; } = true;
|
||||
public bool ShowPalettePlusImport { get; set; } = true;
|
||||
public bool UseFloatForColors { get; set; } = true;
|
||||
public bool UseRgbForColors { get; set; } = true;
|
||||
public bool ShowColorConfig { get; set; } = true;
|
||||
public bool ChangeEntireItem { get; set; } = false;
|
||||
public bool AlwaysApplyAssociatedMods { get; set; } = true;
|
||||
public bool UseTemporarySettings { get; set; } = true;
|
||||
public bool AllowDoubleClickToApply { get; set; } = false;
|
||||
public bool RespectManualOnAutomationUpdate { get; set; } = false;
|
||||
public bool PreventRandomRepeats { get; set; } = false;
|
||||
public string PcpFolder { get; set; } = "PCP";
|
||||
public string PcpColor { get; set; } = "";
|
||||
|
||||
public DesignPanelFlag HideDesignPanel { get; set; } = 0;
|
||||
public DesignPanelFlag AutoExpandDesignPanel { get; set; } = 0;
|
||||
|
||||
public DefaultDesignSettings DefaultDesignSettings { get; set; } = new();
|
||||
|
||||
|
|
@ -74,10 +81,11 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
||||
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
|
||||
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
|
||||
public DoubleModifier IncognitoModifier { get; set; } = new(ModifierHotkey.Control);
|
||||
public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New;
|
||||
|
||||
public QdbButtons QdbButtons { get; set; } =
|
||||
QdbButtons.ApplyDesign | QdbButtons.RevertAll | QdbButtons.RevertAutomation | QdbButtons.RevertAdvanced;
|
||||
QdbButtons.ApplyDesign | QdbButtons.RevertAll | QdbButtons.RevertAutomation | QdbButtons.RevertAdvancedDyes;
|
||||
|
||||
[JsonConverter(typeof(SortModeConverter))]
|
||||
[JsonProperty(Order = int.MaxValue)]
|
||||
|
|
@ -154,7 +162,7 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
|
||||
public static class Constants
|
||||
{
|
||||
public const int CurrentVersion = 7;
|
||||
public const int CurrentVersion = 8;
|
||||
|
||||
public static readonly ISortMode<Design>[] ValidSortModes =
|
||||
[
|
||||
|
|
|
|||
96
Glamourer/DesignPanelFlag.cs
Normal file
96
Glamourer/DesignPanelFlag.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
using Glamourer.Designs;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.EndObjects;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
[Flags]
|
||||
public enum DesignPanelFlag : uint
|
||||
{
|
||||
Customization = 0x0001,
|
||||
Equipment = 0x0002,
|
||||
AdvancedCustomizations = 0x0004,
|
||||
AdvancedDyes = 0x0008,
|
||||
AppearanceDetails = 0x0010,
|
||||
DesignDetails = 0x0020,
|
||||
ModAssociations = 0x0040,
|
||||
DesignLinks = 0x0080,
|
||||
ApplicationRules = 0x0100,
|
||||
DebugData = 0x0200,
|
||||
}
|
||||
|
||||
public static class DesignPanelFlagExtensions
|
||||
{
|
||||
public static ReadOnlySpan<byte> ToName(this DesignPanelFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
DesignPanelFlag.Customization => "Customization"u8,
|
||||
DesignPanelFlag.Equipment => "Equipment"u8,
|
||||
DesignPanelFlag.AdvancedCustomizations => "Advanced Customization"u8,
|
||||
DesignPanelFlag.AdvancedDyes => "Advanced Dyes"u8,
|
||||
DesignPanelFlag.DesignDetails => "Design Details"u8,
|
||||
DesignPanelFlag.ApplicationRules => "Application Rules"u8,
|
||||
DesignPanelFlag.ModAssociations => "Mod Associations"u8,
|
||||
DesignPanelFlag.DesignLinks => "Design Links"u8,
|
||||
DesignPanelFlag.DebugData => "Debug Data"u8,
|
||||
DesignPanelFlag.AppearanceDetails => "Appearance Details"u8,
|
||||
_ => ""u8,
|
||||
};
|
||||
|
||||
public static CollapsingHeader Header(this DesignPanelFlag flag, Configuration config)
|
||||
{
|
||||
if (config.HideDesignPanel.HasFlag(flag))
|
||||
return new CollapsingHeader()
|
||||
{
|
||||
Disposed = true,
|
||||
};
|
||||
|
||||
var expand = config.AutoExpandDesignPanel.HasFlag(flag);
|
||||
return ImUtf8.CollapsingHeaderId(flag.ToName(), expand ? ImGuiTreeNodeFlags.DefaultOpen : ImGuiTreeNodeFlags.None);
|
||||
}
|
||||
|
||||
public static void DrawTable(ReadOnlySpan<byte> label, DesignPanelFlag hidden, DesignPanelFlag expanded, Action<DesignPanelFlag> setterHide,
|
||||
Action<DesignPanelFlag> setterExpand)
|
||||
{
|
||||
var checkBoxWidth = Math.Max(ImGui.GetFrameHeight(), ImUtf8.CalcTextSize("Expand"u8).X);
|
||||
var textWidth = ImUtf8.CalcTextSize(DesignPanelFlag.AdvancedCustomizations.ToName()).X;
|
||||
var tableSize = 2 * (textWidth + 2 * checkBoxWidth) + 10 * ImGui.GetStyle().CellPadding.X + 2 * ImGui.GetStyle().WindowPadding.X + 2 * ImGui.GetStyle().FrameBorderSize;
|
||||
using var table = ImUtf8.Table(label, 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders, new Vector2(tableSize, 6 * ImGui.GetFrameHeight()));
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
var headerColor = ImGui.GetColorU32(ImGuiCol.TableHeaderBg);
|
||||
var checkBoxOffset = (checkBoxWidth - ImGui.GetFrameHeight()) / 2;
|
||||
ImUtf8.TableSetupColumn("Panel##1"u8, ImGuiTableColumnFlags.WidthFixed, textWidth);
|
||||
ImUtf8.TableSetupColumn("Show##1"u8, ImGuiTableColumnFlags.WidthFixed, checkBoxWidth);
|
||||
ImUtf8.TableSetupColumn("Expand##1"u8, ImGuiTableColumnFlags.WidthFixed, checkBoxWidth);
|
||||
ImUtf8.TableSetupColumn("Panel##2"u8, ImGuiTableColumnFlags.WidthFixed, textWidth);
|
||||
ImUtf8.TableSetupColumn("Show##2"u8, ImGuiTableColumnFlags.WidthFixed, checkBoxWidth);
|
||||
ImUtf8.TableSetupColumn("Expand##2"u8, ImGuiTableColumnFlags.WidthFixed, checkBoxWidth);
|
||||
|
||||
ImGui.TableHeadersRow();
|
||||
foreach (var panel in Enum.GetValues<DesignPanelFlag>())
|
||||
{
|
||||
using var id = ImUtf8.PushId((int)panel);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, headerColor);
|
||||
ImUtf8.TextFrameAligned(panel.ToName());
|
||||
var isShown = !hidden.HasFlag(panel);
|
||||
var isExpanded = expanded.HasFlag(panel);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + checkBoxOffset);
|
||||
if (ImUtf8.Checkbox("##show"u8, ref isShown))
|
||||
setterHide.Invoke(isShown ? hidden & ~panel : hidden | panel);
|
||||
ImUtf8.HoverTooltip(
|
||||
"Show this panel and associated functionality in all relevant tabs.\n\nToggling this off does NOT disable any functionality, just the display of it, so hide panels at your own risk."u8);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + checkBoxOffset);
|
||||
if (ImUtf8.Checkbox("##expand"u8, ref isExpanded))
|
||||
setterExpand.Invoke(isExpanded ? expanded | panel : expanded & ~panel);
|
||||
ImUtf8.HoverTooltip("Expand this panel by default in all relevant tabs."u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.GameData;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
|
@ -19,13 +19,13 @@ public record struct ApplicationCollection(
|
|||
public static readonly ApplicationCollection None = new(0, 0, CustomizeFlag.BodyType, 0, 0, 0);
|
||||
|
||||
public static readonly ApplicationCollection Equipment = new(EquipFlagExtensions.All, BonusExtensions.All,
|
||||
CustomizeFlag.BodyType, CrestExtensions.AllRelevant, 0, MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState);
|
||||
CustomizeFlag.BodyType, CrestExtensions.AllRelevant, 0, MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState | MetaFlag.EarState);
|
||||
|
||||
public static readonly ApplicationCollection Customizations = new(0, 0, CustomizeFlagExtensions.AllRelevant, 0,
|
||||
CustomizeParameterExtensions.All, MetaFlag.Wetness);
|
||||
|
||||
public static readonly ApplicationCollection Default = new(EquipFlagExtensions.All, BonusExtensions.All,
|
||||
CustomizeFlagExtensions.AllRelevant, CrestExtensions.AllRelevant, 0, MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState);
|
||||
CustomizeFlagExtensions.AllRelevant, CrestExtensions.AllRelevant, 0, MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState | MetaFlag.EarState);
|
||||
|
||||
public static ApplicationCollection FromKeys()
|
||||
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
||||
|
|
@ -47,7 +47,7 @@ public record struct ApplicationCollection(
|
|||
Equip = 0;
|
||||
BonusItem = 0;
|
||||
Crest = 0;
|
||||
Meta &= ~(MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState);
|
||||
Meta &= ~(MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState | MetaFlag.EarState);
|
||||
}
|
||||
|
||||
public void RemoveCustomize()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
|
@ -19,9 +19,6 @@ public readonly struct ApplicationRules(ApplicationCollection application, bool
|
|||
public static ApplicationRules AllButParameters(ActorState state)
|
||||
=> new(ApplicationCollection.All with { Parameters = ComputeParameters(state.ModelData, state.BaseData, All.Parameters) }, true);
|
||||
|
||||
public static ApplicationRules AllWithConfig(Configuration config)
|
||||
=> new(ApplicationCollection.All with { Parameters = config.UseAdvancedParameters ? All.Parameters : 0 }, config.UseAdvancedDyes);
|
||||
|
||||
public static ApplicationRules NpcFromModifiers(bool ctrl, bool shift)
|
||||
{
|
||||
var equip = ctrl || !shift ? EquipFlagExtensions.All : 0;
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
|
||||
public new JObject JsonSerialize()
|
||||
{
|
||||
var ret = new JObject()
|
||||
var ret = new JObject
|
||||
{
|
||||
["FileVersion"] = FileVersion,
|
||||
["Identifier"] = Identifier,
|
||||
|
|
@ -131,12 +131,17 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
var ret = new JArray();
|
||||
foreach (var (mod, settings) in AssociatedMods)
|
||||
{
|
||||
var obj = new JObject()
|
||||
var obj = new JObject
|
||||
{
|
||||
["Name"] = mod.Name,
|
||||
["Directory"] = mod.DirectoryName,
|
||||
["Enabled"] = settings.Enabled,
|
||||
};
|
||||
if (settings.Remove)
|
||||
obj["Remove"] = true;
|
||||
else if (settings.ForceInherit)
|
||||
obj["Inherit"] = true;
|
||||
else
|
||||
obj["Enabled"] = settings.Enabled;
|
||||
if (settings.Enabled)
|
||||
{
|
||||
obj["Priority"] = settings.Priority;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ public class DesignBase
|
|||
}
|
||||
|
||||
/// <summary> Used when importing .cma or .chara files. </summary>
|
||||
internal DesignBase(CustomizeService customize, in DesignData designData, EquipFlag equipFlags, CustomizeFlag customizeFlags, BonusItemFlag bonusFlags)
|
||||
internal DesignBase(CustomizeService customize, in DesignData designData, EquipFlag equipFlags, CustomizeFlag customizeFlags,
|
||||
BonusItemFlag bonusFlags)
|
||||
{
|
||||
_designData = designData;
|
||||
ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant;
|
||||
|
|
@ -254,9 +255,10 @@ public class DesignBase
|
|||
ret[slot.ToString()] = Serialize(item.Id, stains, crest, DoApplyEquip(slot), DoApplyStain(slot), DoApplyCrest(crestSlot));
|
||||
}
|
||||
|
||||
ret["Hat"] = new QuadBool(_designData.IsHatVisible(), DoApplyMeta(MetaIndex.HatState)).ToJObject("Show", "Apply");
|
||||
ret["Visor"] = new QuadBool(_designData.IsVisorToggled(), DoApplyMeta(MetaIndex.VisorState)).ToJObject("IsToggled", "Apply");
|
||||
ret["Weapon"] = new QuadBool(_designData.IsWeaponVisible(), DoApplyMeta(MetaIndex.WeaponState)).ToJObject("Show", "Apply");
|
||||
ret["Hat"] = new QuadBool(_designData.IsHatVisible(), DoApplyMeta(MetaIndex.HatState)).ToJObject("Show", "Apply");
|
||||
ret["VieraEars"] = new QuadBool(_designData.AreEarsVisible(), DoApplyMeta(MetaIndex.EarState)).ToJObject("Show", "Apply");
|
||||
ret["Visor"] = new QuadBool(_designData.IsVisorToggled(), DoApplyMeta(MetaIndex.VisorState)).ToJObject("IsToggled", "Apply");
|
||||
ret["Weapon"] = new QuadBool(_designData.IsWeaponVisible(), DoApplyMeta(MetaIndex.WeaponState)).ToJObject("Show", "Apply");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -603,6 +605,10 @@ public class DesignBase
|
|||
metaValue = QuadBool.FromJObject(equip["Visor"], "IsToggled", "Apply", QuadBool.NullFalse);
|
||||
design.SetApplyMeta(MetaIndex.VisorState, metaValue.Enabled);
|
||||
design._designData.SetVisor(metaValue.ForcedValue);
|
||||
|
||||
metaValue = QuadBool.FromJObject(equip["VieraEars"], "Show", "Apply", QuadBool.NullTrue);
|
||||
design.SetApplyMeta(MetaIndex.EarState, metaValue.Enabled);
|
||||
design._designData.SetEarsVisible(metaValue.ForcedValue);
|
||||
return;
|
||||
|
||||
void PrintWarning(string msg)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Services;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ using Dalamud.Interface.ImGuiNotification;
|
|||
using Dalamud.Interface.Utility.Raii;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
|
|
|
|||
|
|
@ -287,6 +287,7 @@ public unsafe struct DesignData
|
|||
MetaIndex.HatState => IsHatVisible(),
|
||||
MetaIndex.VisorState => IsVisorToggled(),
|
||||
MetaIndex.WeaponState => IsWeaponVisible(),
|
||||
MetaIndex.EarState => AreEarsVisible(),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
|
@ -297,6 +298,7 @@ public unsafe struct DesignData
|
|||
MetaIndex.HatState => SetHatVisible(value),
|
||||
MetaIndex.VisorState => SetVisor(value),
|
||||
MetaIndex.WeaponState => SetWeaponVisible(value),
|
||||
MetaIndex.EarState => SetEarsVisible(value),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
|
@ -340,6 +342,9 @@ public unsafe struct DesignData
|
|||
public readonly bool IsWeaponVisible()
|
||||
=> (_states & 0x08) == 0x08;
|
||||
|
||||
public readonly bool AreEarsVisible()
|
||||
=> (_states & 0x10) == 0x00;
|
||||
|
||||
public bool SetWeaponVisible(bool value)
|
||||
{
|
||||
if (value == IsWeaponVisible())
|
||||
|
|
@ -349,6 +354,15 @@ public unsafe struct DesignData
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool SetEarsVisible(bool value)
|
||||
{
|
||||
if (value == AreEarsVisible())
|
||||
return false;
|
||||
|
||||
_states = (byte)(value ? _states & ~0x10 : _states | 0x10);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetDefaultEquipment(ItemManager items)
|
||||
{
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
|
|
@ -386,6 +400,7 @@ public unsafe struct DesignData
|
|||
|
||||
SetHatVisible(true);
|
||||
SetWeaponVisible(true);
|
||||
SetEarsVisible(true);
|
||||
SetVisor(false);
|
||||
fixed (uint* ptr = _itemIds)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
|||
|
||||
public struct CreationDate : ISortMode<Design>
|
||||
{
|
||||
public string Name
|
||||
=> "Creation Date (Older First)";
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Creation Date (Older First)"u8;
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their creation date.";
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their creation date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderBy(l => l.Value.CreationDate));
|
||||
|
|
@ -53,11 +53,11 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
|||
|
||||
public struct UpdateDate : ISortMode<Design>
|
||||
{
|
||||
public string Name
|
||||
=> "Update Date (Older First)";
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Update Date (Older First)"u8;
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their last update date.";
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their last update date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderBy(l => l.Value.LastEdit));
|
||||
|
|
@ -65,11 +65,11 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
|||
|
||||
public struct InverseCreationDate : ISortMode<Design>
|
||||
{
|
||||
public string Name
|
||||
=> "Creation Date (Newer First)";
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Creation Date (Newer First)"u8;
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse creation date.";
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse creation date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderByDescending(l => l.Value.CreationDate));
|
||||
|
|
@ -77,11 +77,11 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
|||
|
||||
public struct InverseUpdateDate : ISortMode<Design>
|
||||
{
|
||||
public string Name
|
||||
=> "Update Date (Newer First)";
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Update Date (Newer First)"u8;
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse last update date.";
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse last update date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderByDescending(l => l.Value.LastEdit));
|
||||
|
|
@ -114,14 +114,14 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
|||
|
||||
return;
|
||||
case DesignChanged.Type.Deleted:
|
||||
if (FindLeaf(design, out var leaf1))
|
||||
if (TryGetValue(design, out var leaf1))
|
||||
Delete(leaf1);
|
||||
return;
|
||||
case DesignChanged.Type.ReloadedAll:
|
||||
Reload();
|
||||
return;
|
||||
case DesignChanged.Type.Renamed when (data as RenameTransaction?)?.Old is { } oldName:
|
||||
if (!FindLeaf(design, out var leaf2))
|
||||
if (!TryGetValue(design, out var leaf2))
|
||||
return;
|
||||
|
||||
var old = oldName.FixName();
|
||||
|
|
@ -150,15 +150,6 @@ public sealed class DesignFileSystem : FileSystem<Design>, IDisposable, ISavable
|
|||
? (string.Empty, false)
|
||||
: (DesignToIdentifier(design), true);
|
||||
|
||||
// Search the entire filesystem for the leaf corresponding to a design.
|
||||
public bool FindLeaf(Design design, [NotNullWhen(true)] out Leaf? leaf)
|
||||
{
|
||||
leaf = Root.GetAllDescendants(ISortMode<Design>.Lexicographical)
|
||||
.OfType<Leaf>()
|
||||
.FirstOrDefault(l => l.Value == design);
|
||||
return leaf != null;
|
||||
}
|
||||
|
||||
internal static void MigrateOldPaths(SaveService saveService, Dictionary<string, string> oldPaths)
|
||||
{
|
||||
if (oldPaths.Count == 0)
|
||||
|
|
|
|||
|
|
@ -3,14 +3,16 @@ using Glamourer.Designs.History;
|
|||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Services;
|
||||
using OtterGui.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
public sealed class DesignManager : DesignEditor
|
||||
|
|
@ -109,6 +111,7 @@ public sealed class DesignManager : DesignEditor
|
|||
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
|
||||
ResetTemporarySettings = Config.DefaultDesignSettings.ResetTemporarySettings,
|
||||
};
|
||||
design.SetWriteProtected(Config.DefaultDesignSettings.Locked);
|
||||
Designs.Add(design);
|
||||
Glamourer.Log.Debug($"Added new design {design.Identifier}.");
|
||||
SaveService.ImmediateSave(design);
|
||||
|
|
@ -133,6 +136,7 @@ public sealed class DesignManager : DesignEditor
|
|||
ResetTemporarySettings = Config.DefaultDesignSettings.ResetTemporarySettings,
|
||||
};
|
||||
|
||||
design.SetWriteProtected(Config.DefaultDesignSettings.Locked);
|
||||
Designs.Add(design);
|
||||
Glamourer.Log.Debug($"Added new design {design.Identifier} by cloning Temporary Design.");
|
||||
SaveService.ImmediateSave(design);
|
||||
|
|
@ -152,6 +156,7 @@ public sealed class DesignManager : DesignEditor
|
|||
Name = actualName,
|
||||
Index = Designs.Count,
|
||||
};
|
||||
design.SetWriteProtected(Config.DefaultDesignSettings.Locked);
|
||||
Designs.Add(design);
|
||||
Glamourer.Log.Debug(
|
||||
$"Added new design {design.Identifier} by cloning {clone.Identifier.ToString()}.");
|
||||
|
|
@ -224,7 +229,7 @@ public sealed class DesignManager : DesignEditor
|
|||
|
||||
design.Tags = design.Tags.Append(tag).OrderBy(t => t).ToArray();
|
||||
design.LastEdit = DateTimeOffset.UtcNow;
|
||||
var idx = design.Tags.IndexOf(tag);
|
||||
var idx = design.Tags.AsEnumerable().IndexOf(tag);
|
||||
SaveService.QueueSave(design);
|
||||
Glamourer.Log.Debug($"Added tag {tag} at {idx} to design {design.Identifier}.");
|
||||
DesignChanged.Invoke(DesignChanged.Type.AddedTag, design, new TagAddedTransaction(tag, idx));
|
||||
|
|
@ -257,7 +262,7 @@ public sealed class DesignManager : DesignEditor
|
|||
SaveService.QueueSave(design);
|
||||
Glamourer.Log.Debug($"Renamed tag {oldTag} at {tagIdx} to {newTag} in design {design.Identifier} and reordered tags.");
|
||||
DesignChanged.Invoke(DesignChanged.Type.ChangedTag, design,
|
||||
new TagChangedTransaction(oldTag, newTag, tagIdx, design.Tags.IndexOf(newTag)));
|
||||
new TagChangedTransaction(oldTag, newTag, tagIdx, design.Tags.AsEnumerable().IndexOf(newTag)));
|
||||
}
|
||||
|
||||
/// <summary> Add an associated mod to a design. </summary>
|
||||
|
|
@ -448,6 +453,39 @@ public sealed class DesignManager : DesignEditor
|
|||
DesignChanged.Invoke(DesignChanged.Type.ApplyParameter, design, new ApplicationTransaction(flag, !value, value));
|
||||
}
|
||||
|
||||
/// <summary> Change multiple application values at once. </summary>
|
||||
public void ChangeApplyMulti(Design design, bool? equipment, bool? customization, bool? bonus, bool? parameters, bool? meta, bool? stains,
|
||||
bool? materials, bool? crest)
|
||||
{
|
||||
if (equipment is { } e)
|
||||
foreach (var f in EquipSlotExtensions.FullSlots)
|
||||
ChangeApplyItem(design, f, e);
|
||||
if (stains is { } s)
|
||||
foreach (var f in EquipSlotExtensions.FullSlots)
|
||||
ChangeApplyStains(design, f, s);
|
||||
if (customization is { } c)
|
||||
foreach (var f in CustomizationExtensions.All.Where(design.CustomizeSet.IsAvailable).Prepend(CustomizeIndex.Clan)
|
||||
.Prepend(CustomizeIndex.Gender))
|
||||
ChangeApplyCustomize(design, f, c);
|
||||
if (bonus is { } b)
|
||||
foreach (var f in BonusExtensions.AllFlags)
|
||||
ChangeApplyBonusItem(design, f, b);
|
||||
if (meta is { } m)
|
||||
foreach (var f in MetaExtensions.AllRelevant)
|
||||
ChangeApplyMeta(design, f, m);
|
||||
if (crest is { } cr)
|
||||
foreach (var f in CrestExtensions.AllRelevantSet)
|
||||
ChangeApplyCrest(design, f, cr);
|
||||
|
||||
if (parameters is { } p)
|
||||
foreach (var f in CustomizeParameterExtensions.AllFlags)
|
||||
ChangeApplyParameter(design, f, p);
|
||||
|
||||
if (materials is { } ma)
|
||||
foreach (var (key, _) in design.GetMaterialData().ToArray())
|
||||
ChangeApplyMaterialValue(design, MaterialValueIndex.FromKey(key), ma);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void UndoDesignChange(Design design)
|
||||
|
|
@ -519,7 +557,7 @@ public sealed class DesignManager : DesignEditor
|
|||
try
|
||||
{
|
||||
File.Move(SaveService.FileNames.MigrationDesignFile,
|
||||
Path.ChangeExtension(SaveService.FileNames.MigrationDesignFile, ".json.bak"));
|
||||
Path.ChangeExtension(SaveService.FileNames.MigrationDesignFile, ".json.bak"), true);
|
||||
Glamourer.Log.Information($"Moved migrated design file {SaveService.FileNames.MigrationDesignFile} to backup file.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Designs.History;
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ public class EditorHistory : IDisposable, IService
|
|||
{
|
||||
if (!_stateEntries.TryGetValue(state, out var list))
|
||||
{
|
||||
list = new Queue();
|
||||
list = [];
|
||||
_stateEntries.Add(state, list);
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ public class EditorHistory : IDisposable, IService
|
|||
{
|
||||
if (!_designEntries.TryGetValue(design, out var list))
|
||||
{
|
||||
list = new Queue();
|
||||
list = [];
|
||||
_designEntries.Add(design, list);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Services;
|
||||
using Notification = OtterGui.Classes.Notification;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,15 @@ public enum MetaIndex
|
|||
VisorState = StateIndex.MetaVisorState,
|
||||
WeaponState = StateIndex.MetaWeaponState,
|
||||
ModelId = StateIndex.MetaModelId,
|
||||
EarState = StateIndex.MetaEarState,
|
||||
}
|
||||
|
||||
public static class MetaExtensions
|
||||
{
|
||||
public static readonly IReadOnlyList<MetaIndex> AllRelevant =
|
||||
[MetaIndex.Wetness, MetaIndex.HatState, MetaIndex.VisorState, MetaIndex.WeaponState];
|
||||
[MetaIndex.Wetness, MetaIndex.HatState, MetaIndex.VisorState, MetaIndex.WeaponState, MetaIndex.EarState];
|
||||
|
||||
public const MetaFlag All = MetaFlag.Wetness | MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState;
|
||||
public const MetaFlag All = MetaFlag.Wetness | MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState | MetaFlag.EarState;
|
||||
|
||||
public static MetaFlag ToFlag(this MetaIndex index)
|
||||
=> index switch
|
||||
|
|
@ -26,6 +27,7 @@ public static class MetaExtensions
|
|||
MetaIndex.HatState => MetaFlag.HatState,
|
||||
MetaIndex.VisorState => MetaFlag.VisorState,
|
||||
MetaIndex.WeaponState => MetaFlag.WeaponState,
|
||||
MetaIndex.EarState => MetaFlag.EarState,
|
||||
_ => (MetaFlag)byte.MaxValue,
|
||||
};
|
||||
|
||||
|
|
@ -36,7 +38,8 @@ public static class MetaExtensions
|
|||
MetaFlag.HatState => MetaIndex.HatState,
|
||||
MetaFlag.VisorState => MetaIndex.VisorState,
|
||||
MetaFlag.WeaponState => MetaIndex.WeaponState,
|
||||
_ => (MetaIndex)byte.MaxValue,
|
||||
MetaFlag.EarState => MetaIndex.EarState,
|
||||
_ => (MetaIndex)byte.MaxValue,
|
||||
};
|
||||
|
||||
public static IEnumerable<MetaIndex> ToIndices(this MetaFlag index)
|
||||
|
|
@ -49,6 +52,8 @@ public static class MetaExtensions
|
|||
yield return MetaIndex.VisorState;
|
||||
if (index.HasFlag(MetaFlag.WeaponState))
|
||||
yield return MetaIndex.WeaponState;
|
||||
if (index.HasFlag(MetaFlag.EarState))
|
||||
yield return MetaIndex.EarState;
|
||||
}
|
||||
|
||||
public static string ToName(this MetaIndex index)
|
||||
|
|
@ -58,6 +63,7 @@ public static class MetaExtensions
|
|||
MetaIndex.VisorState => "Visor Toggled",
|
||||
MetaIndex.WeaponState => "Weapon Visible",
|
||||
MetaIndex.Wetness => "Force Wetness",
|
||||
MetaIndex.EarState => "Ears Visible",
|
||||
_ => "Unknown Meta",
|
||||
};
|
||||
|
||||
|
|
@ -68,6 +74,7 @@ public static class MetaExtensions
|
|||
MetaIndex.VisorState => "Toggle the visor state of the characters head gear.",
|
||||
MetaIndex.WeaponState => "Hide or show the characters weapons when not drawn.",
|
||||
MetaIndex.Wetness => "Force the character to be wet or not.",
|
||||
MetaIndex.EarState => "Hide or show the characters ears through the head gear. (Viera only)",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,33 @@
|
|||
using OtterGui.Services;
|
||||
using OtterGui;
|
||||
using OtterGui.Services;
|
||||
|
||||
namespace Glamourer.Designs.Special;
|
||||
|
||||
public class RandomDesignGenerator(DesignStorage designs, DesignFileSystem fileSystem) : IService
|
||||
public class RandomDesignGenerator(DesignStorage designs, DesignFileSystem fileSystem, Configuration config) : IService
|
||||
{
|
||||
private readonly Random _rng = new();
|
||||
private readonly Random _rng = new();
|
||||
private readonly WeakReference<Design> _lastDesign = new(null!, false);
|
||||
|
||||
public Design? Design(IReadOnlyList<Design> localDesigns)
|
||||
{
|
||||
if (localDesigns.Count == 0)
|
||||
if (localDesigns.Count is 0)
|
||||
return null;
|
||||
|
||||
var idx = _rng.Next(0, localDesigns.Count);
|
||||
Glamourer.Log.Verbose($"[Random Design] Chose design {idx + 1} out of {localDesigns.Count}: {localDesigns[idx].Incognito}.");
|
||||
return localDesigns[idx];
|
||||
if (localDesigns.Count is 1)
|
||||
{
|
||||
_lastDesign.SetTarget(localDesigns[idx]);
|
||||
return localDesigns[idx];
|
||||
}
|
||||
|
||||
if (config.PreventRandomRepeats && _lastDesign.TryGetTarget(out var lastDesign))
|
||||
while (lastDesign == localDesigns[idx])
|
||||
idx = _rng.Next(0, localDesigns.Count);
|
||||
|
||||
var design = localDesigns[idx];
|
||||
Glamourer.Log.Verbose($"[Random Design] Chose design {idx + 1} out of {localDesigns.Count}: {design.Incognito}.");
|
||||
_lastDesign.SetTarget(design);
|
||||
return design;
|
||||
}
|
||||
|
||||
public Design? Design()
|
||||
|
|
@ -24,12 +38,12 @@ public class RandomDesignGenerator(DesignStorage designs, DesignFileSystem fileS
|
|||
|
||||
public Design? Design(IReadOnlyList<IDesignPredicate> predicates)
|
||||
{
|
||||
if (predicates.Count == 0)
|
||||
return Design();
|
||||
if (predicates.Count == 1)
|
||||
return Design(predicates[0]);
|
||||
|
||||
return Design(IDesignPredicate.Get(predicates, designs, fileSystem).ToList());
|
||||
return predicates.Count switch
|
||||
{
|
||||
0 => Design(),
|
||||
1 => Design(predicates[0]),
|
||||
_ => Design(IDesignPredicate.Get(predicates, designs, fileSystem).ToList()),
|
||||
};
|
||||
}
|
||||
|
||||
public Design? Design(string restrictions)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public interface IDesignPredicate
|
|||
: designs;
|
||||
|
||||
private static (Design Design, string LowerName, string Identifier, string LowerPath) Transform(Design d, DesignFileSystem fs)
|
||||
=> (d, d.Name.Lower, d.Identifier.ToString(), fs.FindLeaf(d, out var l) ? l.FullName().ToLowerInvariant() : string.Empty);
|
||||
=> (d, d.Name.Lower, d.Identifier.ToString(), fs.TryGetValue(d, out var l) ? l.FullName().ToLowerInvariant() : string.Empty);
|
||||
}
|
||||
|
||||
public static class RandomPredicate
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ public class EphemeralConfig : ISavable
|
|||
public Guid SelectedQuickDesign { get; set; } = Guid.Empty;
|
||||
public int LastSeenVersion { get; set; } = GlamourerChangelog.LastChangelogVersion;
|
||||
|
||||
public float CurrentDesignSelectorWidth { get; set; } = 200f;
|
||||
public float DesignSelectorMinimumScale { get; set; } = 0.1f;
|
||||
public float DesignSelectorMaximumScale { get; set; } = 0.5f;
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
private readonly SaveService _saveService;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Glamourer.Events;
|
|||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class GearsetDataLoaded()
|
||||
: EventWrapper<Model, GearsetDataLoaded.Priority>(nameof(GearsetDataLoaded))
|
||||
: EventWrapper<Actor, Model, GearsetDataLoaded.Priority>(nameof(GearsetDataLoaded))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,5 +15,8 @@ public sealed class PenumbraReloaded()
|
|||
|
||||
/// <seealso cref="Interop.VisorService.Restore"/>
|
||||
VisorService = 0,
|
||||
|
||||
/// <seealso cref="Interop.VieraEarService.Restore"/>
|
||||
VieraEarService = 0,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Glamourer.Designs.History;
|
|||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using Glamourer.Api;
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
|
|
|
|||
22
Glamourer/Events/VieraEarStateChanged.cs
Normal file
22
Glamourer/Events/VieraEarStateChanged.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the state of viera ear visibility for any draw object is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the model with a changed viera ear visibility state. </item>
|
||||
/// <item>Parameter is the new state. </item>
|
||||
/// <item>Parameter is whether to call the original function. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class VieraEarStateChanged()
|
||||
: EventWrapperRef2<Actor, bool, VieraEarStateChanged.Priority>(nameof(VieraEarStateChanged))
|
||||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="State.StateListener.OnVieraEarChange"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -19,4 +19,4 @@ public sealed class VisorStateChanged()
|
|||
/// <seealso cref="State.StateListener.OnVisorChange"/>
|
||||
StateListener = 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Race = Penumbra.GameData.Enums.Race;
|
||||
|
|
|
|||
|
|
@ -330,9 +330,9 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
|||
/// <summary> Check decal files for existence. </summary>
|
||||
private static void CheckFacepaintFiles(IDataManager data, BitArray facepaints)
|
||||
{
|
||||
for (var i = 0; i < 128; ++i)
|
||||
for (byte i = 0; i < 128; ++i)
|
||||
{
|
||||
var path = GamePaths.Character.Tex.DecalPath("face", (PrimaryId)i);
|
||||
var path = GamePaths.Tex.FaceDecal(i);
|
||||
if (data.FileExists(path))
|
||||
facepaints[i] = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@ using Glamourer.Gui;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
|
|
@ -28,6 +26,7 @@ public class Glamourer : IDalamudPlugin
|
|||
|
||||
public static readonly Logger Log = new();
|
||||
public static MessageService Messager { get; private set; } = null!;
|
||||
public static DynamisIpc Dynamis { get; private set; } = null!;
|
||||
|
||||
private readonly ServiceManager _services;
|
||||
|
||||
|
|
@ -37,6 +36,7 @@ public class Glamourer : IDalamudPlugin
|
|||
{
|
||||
_services = StaticServiceManager.CreateProvider(pluginInterface, Log, this);
|
||||
Messager = _services.GetService<MessageService>();
|
||||
Dynamis = _services.GetService<DynamisIpc>();
|
||||
_services.EnsureRequiredServices();
|
||||
|
||||
_services.GetService<VisorService>();
|
||||
|
|
@ -69,10 +69,10 @@ public class Glamourer : IDalamudPlugin
|
|||
sb.Append($"> **`Auto-Reload Gear: `** {config.AutoRedrawEquipOnChanges}\n");
|
||||
sb.Append($"> **`Revert on Zone Change:`** {config.RevertManualChangesOnZoneChange}\n");
|
||||
sb.Append($"> **`Festival Easter-Eggs: `** {config.DisableFestivals}\n");
|
||||
sb.Append($"> **`Advanced Customize: `** {config.UseAdvancedParameters}\n");
|
||||
sb.Append($"> **`Advanced Dye: `** {config.UseAdvancedDyes}\n");
|
||||
sb.Append($"> **`Apply Entire Weapon: `** {config.ChangeEntireItem}\n");
|
||||
sb.Append($"> **`Apply Associated Mods:`** {config.AlwaysApplyAssociatedMods}\n");
|
||||
sb.Append($"> **`Attach to PCP: `** {config.AttachToPcp}\n");
|
||||
sb.Append($"> **`Hidden Panels: `** {config.HideDesignPanel}\n");
|
||||
sb.Append($"> **`Show QDB: `** {config.Ephemeral.ShowDesignQuickBar}\n");
|
||||
sb.Append($"> **`QDB Hotkey: `** {config.ToggleQuickDesignBar}\n");
|
||||
sb.Append($"> **`Smaller Equip Display:`** {config.SmallEquip}\n");
|
||||
|
|
@ -83,7 +83,7 @@ public class Glamourer : IDalamudPlugin
|
|||
var designManager = _services.GetService<DesignManager>();
|
||||
var autoManager = _services.GetService<AutoDesignManager>();
|
||||
var stateManager = _services.GetService<StateManager>();
|
||||
var objectManager = _services.GetService<ObjectManager>();
|
||||
var objectManager = _services.GetService<ActorObjectManager>();
|
||||
var currentPlayer = objectManager.PlayerData.Identifier;
|
||||
var states = stateManager.Where(kvp => objectManager.ContainsKey(kvp.Key)).ToList();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,92 +1,32 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<RootNamespace>Glamourer</RootNamespace>
|
||||
<AssemblyName>Glamourer</AssemblyName>
|
||||
<FileVersion>9.0.0.1</FileVersion>
|
||||
<AssemblyVersion>9.0.0.1</AssemblyVersion>
|
||||
<Company>SoftOtter</Company>
|
||||
<Product>Glamourer</Product>
|
||||
<Copyright>Copyright © 2023</Copyright>
|
||||
<Deterministic>true</Deterministic>
|
||||
<OutputType>Library</OutputType>
|
||||
<Copyright>Copyright © 2025</Copyright>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="LegacyTattoo.raw" />
|
||||
|
||||
<None Include="Glamourer.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="LegacyTattoo.raw" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGui.NET">
|
||||
<HintPath>$(DalamudLibPath)ImGui.NET.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGuiScene">
|
||||
<HintPath>$(DalamudLibPath)ImGuiScene.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina">
|
||||
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina.Excel">
|
||||
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Glamourer.Api\Glamourer.Api.csproj" />
|
||||
<ProjectReference Include="..\OtterGui\OtterGui.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.Api\Penumbra.Api.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.String\Penumbra.string.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.String\Penumbra.String.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||
<PackageReference Include="Vortice.Direct3D11" Version="3.4.2-beta" />
|
||||
</ItemGroup>
|
||||
|
|
@ -116,14 +56,4 @@
|
|||
<InformationalVersion>$(GitCommitHash)</InformationalVersion>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Glamourer.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="if $(Configuration) == Release powershell Copy-Item -Force $(TargetDir)$(SolutionName).json -Destination $(SolutionDir)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"AssemblyVersion": "9.0.0.1",
|
||||
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
|
||||
"ApplicableVersion": "any",
|
||||
"DalamudApiLevel": 11,
|
||||
"DalamudApiLevel": 13,
|
||||
"ImageUrls": null,
|
||||
"IconUrl": "https://raw.githubusercontent.com/Ottermandias/Glamourer/master/images/icon.png"
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
|
|
@ -32,6 +32,7 @@ public enum ColorId
|
|||
ModdedItemMarker,
|
||||
ContainsItemsEnabled,
|
||||
ContainsItemsDisabled,
|
||||
AdvancedDyeActive,
|
||||
}
|
||||
|
||||
public static class Colors
|
||||
|
|
@ -70,6 +71,7 @@ public static class Colors
|
|||
ColorId.ModdedItemMarker => (0xFFFF20FF, "Modded Item Marker", "The color of dot in the unlocks overview tab signaling that the item is modded in the currently selected Penumbra collection." ),
|
||||
ColorId.ContainsItemsEnabled => (0xFFA0F0A0, "Enabled Mod Contains Design Items", "The color of enabled mods in the associated mod dropdown menu when they contain items used in this design." ),
|
||||
ColorId.ContainsItemsDisabled => (0x80A0F0A0, "Disabled Mod Contains Design Items", "The color of disabled mods in the associated mod dropdown menu when they contain items used in this design." ),
|
||||
ColorId.AdvancedDyeActive => (0xFF58DDFF, "Advanced Dyes Active", "The highlight color for the advanced dye button and marker if any advanced dyes are active for this slot." ),
|
||||
_ => (0x00000000, string.Empty, string.Empty ),
|
||||
// @formatter:on
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,83 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.GameData;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.EndObjects;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using System;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
public partial class CustomizationDrawer
|
||||
{
|
||||
private const string ColorPickerPopupName = "ColorPicker";
|
||||
private const string ColorPickerPopupName = "ColorPicker";
|
||||
private CustomizeValue _draggedColorValue;
|
||||
private CustomizeIndex _draggedColorType;
|
||||
|
||||
|
||||
private void DrawDragDropSource(CustomizeIndex index, CustomizeData custom)
|
||||
{
|
||||
using var dragDropSource = ImUtf8.DragDropSource();
|
||||
if (!dragDropSource)
|
||||
return;
|
||||
|
||||
if (!DragDropSource.SetPayload("##colorDragDrop"u8))
|
||||
_draggedColorValue = _customize[index];
|
||||
ImUtf8.Text(
|
||||
$"Dragging {(custom.Color == 0 ? $"{_currentOption} (NPC)" : _currentOption)} #{_draggedColorValue.Value}...");
|
||||
_draggedColorType = index;
|
||||
}
|
||||
|
||||
private void DrawDragDropTarget(CustomizeIndex index)
|
||||
{
|
||||
using var dragDropTarget = ImUtf8.DragDropTarget();
|
||||
if (!dragDropTarget.Success || !dragDropTarget.IsDropping("##colorDragDrop"u8))
|
||||
return;
|
||||
|
||||
var idx = _set.DataByValue(_draggedColorType, _draggedColorValue, out var draggedData, _customize.Face);
|
||||
var bestMatch = _draggedColorValue;
|
||||
if (draggedData.HasValue)
|
||||
{
|
||||
var draggedColor = draggedData.Value.Color;
|
||||
var targetData = _set.Data(index, idx);
|
||||
if (targetData.Color != draggedColor)
|
||||
{
|
||||
var bestDiff = Diff(targetData.Color, draggedColor);
|
||||
var count = _set.Count(index);
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
targetData = _set.Data(index, i);
|
||||
if (targetData.Color == draggedColor)
|
||||
{
|
||||
UpdateValue(_draggedColorValue);
|
||||
return;
|
||||
}
|
||||
|
||||
var diff = Diff(targetData.Color, draggedColor);
|
||||
if (diff >= bestDiff)
|
||||
continue;
|
||||
|
||||
bestDiff = diff;
|
||||
bestMatch = (CustomizeValue)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateValue(bestMatch);
|
||||
return;
|
||||
|
||||
static uint Diff(uint color1, uint color2)
|
||||
{
|
||||
var r = (color1 & 0xFF) - (color2 & 0xFF);
|
||||
var g = ((color1 >> 8) & 0xFF) - ((color2 >> 8) & 0xFF);
|
||||
var b = ((color1 >> 16) & 0xFF) - ((color2 >> 16) & 0xFF);
|
||||
return 30 * r * r + 59 * g * g + 11 * b * b;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawColorPicker(CustomizeIndex index)
|
||||
{
|
||||
|
|
@ -21,7 +88,7 @@ public partial class CustomizationDrawer
|
|||
|
||||
using (_ = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, current < 0))
|
||||
{
|
||||
if (ImGui.ColorButton($"{_customize[index].Value}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
|
||||
if (ImGui.ColorButton($"{_customize[index].Value}##color", color, ImGuiColorEditFlags.NoDragDrop, _framedIconSize))
|
||||
{
|
||||
ImGui.OpenPopup(ColorPickerPopupName);
|
||||
}
|
||||
|
|
@ -30,6 +97,9 @@ public partial class CustomizationDrawer
|
|||
var data = _set.Data(_currentIndex, current, _customize.Face);
|
||||
UpdateValue(data.Value);
|
||||
}
|
||||
|
||||
DrawDragDropSource(index, custom);
|
||||
DrawDragDropTarget(index);
|
||||
}
|
||||
|
||||
var npc = false;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -34,7 +35,7 @@ public partial class CustomizationDrawer
|
|||
var hasIcon = icon.TryGetWrap(out var wrap, out _);
|
||||
using (_ = ImRaii.Disabled(_locked || _currentIndex is CustomizeIndex.Face && _lockedRedraw))
|
||||
{
|
||||
if (ImGui.ImageButton(wrap?.ImGuiHandle ?? icon.GetWrapOrEmpty().ImGuiHandle, _iconSize))
|
||||
if (ImGui.ImageButton(wrap?.Handle ?? icon.GetWrapOrEmpty().Handle, _iconSize))
|
||||
{
|
||||
ImGui.OpenPopup(IconSelectorPopup);
|
||||
}
|
||||
|
|
@ -88,7 +89,7 @@ public partial class CustomizationDrawer
|
|||
: ImRaii.PushColor(ImGuiCol.Button, ColorId.FavoriteStarOn.Value(), isFavorite);
|
||||
var hasIcon = icon.TryGetWrap(out var wrap, out var _);
|
||||
|
||||
if (ImGui.ImageButton(wrap?.ImGuiHandle ?? icon.GetWrapOrEmpty().ImGuiHandle, _iconSize))
|
||||
if (ImGui.ImageButton(wrap?.Handle ?? icon.GetWrapOrEmpty().Handle, _iconSize))
|
||||
{
|
||||
UpdateValue(custom.Value);
|
||||
ImGui.CloseCurrentPopup();
|
||||
|
|
@ -214,7 +215,7 @@ public partial class CustomizationDrawer
|
|||
hasIcon = icon.TryGetWrap(out wrap, out _);
|
||||
}
|
||||
|
||||
if (ImGui.ImageButton(wrap?.ImGuiHandle ?? icon.GetWrapOrEmpty().ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One,
|
||||
if (ImGui.ImageButton(wrap?.Handle ?? icon.GetWrapOrEmpty().Handle, _iconSize, Vector2.Zero, Vector2.One,
|
||||
(int)ImGui.GetStyle().FramePadding.X, Vector4.Zero, enabled ? Vector4.One : _redTint))
|
||||
{
|
||||
_customize.Set(featureIdx, enabled ? CustomizeValue.Zero : CustomizeValue.Max);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGuiInternal;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Dalamud.Plugin.Services;
|
|||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Glamourer.Designs;
|
|||
using Glamourer.GameData;
|
||||
using Glamourer.Interop.PalettePlus;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
|
|
@ -287,13 +287,13 @@ public class CustomizeParameterDrawer(Configuration config, PaletteImport import
|
|||
}
|
||||
|
||||
private ImGuiColorEditFlags GetFlags()
|
||||
=> Format | Display | ImGuiColorEditFlags.HDR | ImGuiColorEditFlags.NoOptions;
|
||||
=> Format | Display | ImGuiColorEditFlags.Hdr | ImGuiColorEditFlags.NoOptions;
|
||||
|
||||
private ImGuiColorEditFlags Format
|
||||
=> config.UseFloatForColors ? ImGuiColorEditFlags.Float : ImGuiColorEditFlags.Uint8;
|
||||
|
||||
private ImGuiColorEditFlags Display
|
||||
=> config.UseRgbForColors ? ImGuiColorEditFlags.DisplayRGB : ImGuiColorEditFlags.DisplayHSV;
|
||||
=> config.UseRgbForColors ? ImGuiColorEditFlags.DisplayRgb : ImGuiColorEditFlags.DisplayHsv;
|
||||
|
||||
private ImRaii.IEndObject EnsureSize()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ using Glamourer.Designs;
|
|||
using Glamourer.Designs.History;
|
||||
using Glamourer.Designs.Special;
|
||||
using Glamourer.Events;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Widgets;
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, s
|
|||
protected readonly TabSelected TabSelected;
|
||||
protected float InnerWidth;
|
||||
private IDesignStandIn? _currentDesign;
|
||||
private bool _isCurrentSelectionDirty;
|
||||
|
||||
protected DesignComboBase(Func<IReadOnlyList<Tuple<IDesignStandIn, string>>> generator, Logger log, DesignChanged designChanged,
|
||||
TabSelected tabSelected, EphemeralConfig config, DesignColors designColors)
|
||||
|
|
@ -83,17 +85,11 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, s
|
|||
DrawRightAligned(quickDesign.ResolveName(false), "[Nothing]", DesignColors.MissingColor);
|
||||
}
|
||||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
CurrentSelectionIdx = Items.IndexOf(p => _currentDesign == p.Item1);
|
||||
UpdateSelection(CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : null);
|
||||
return CurrentSelectionIdx;
|
||||
}
|
||||
|
||||
protected bool Draw(IDesignStandIn? currentDesign, string? label, float width)
|
||||
{
|
||||
_currentDesign = currentDesign;
|
||||
InnerWidth = 400 * ImGuiHelpers.GlobalScale;
|
||||
UpdateCurrentSelection();
|
||||
InnerWidth = 400 * ImGuiHelpers.GlobalScale;
|
||||
var name = label ?? "Select Design Here...";
|
||||
bool ret;
|
||||
using (_ = currentDesign != null ? ImRaii.PushColor(ImGuiCol.Text, DesignColors.GetColor(currentDesign as Design)) : null)
|
||||
|
|
@ -127,37 +123,60 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, s
|
|||
return filter.IsContained(path) || filter.IsContained(design.ResolveName(false));
|
||||
}
|
||||
|
||||
private void OnDesignChanged(DesignChanged.Type type, Design design, ITransaction? _ = null)
|
||||
protected override void OnMouseWheel(string preview, ref int _2, int steps)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DesignChanged.Type.Created:
|
||||
case DesignChanged.Type.Renamed:
|
||||
case DesignChanged.Type.ChangedColor:
|
||||
case DesignChanged.Type.Deleted:
|
||||
case DesignChanged.Type.QuickDesignBar:
|
||||
var priorState = IsInitialized;
|
||||
if (priorState)
|
||||
Cleanup();
|
||||
CurrentSelectionIdx = Items.IndexOf(s => ReferenceEquals(s.Item1, CurrentSelection?.Item1));
|
||||
if (CurrentSelectionIdx >= 0)
|
||||
{
|
||||
UpdateSelection(Items[CurrentSelectionIdx]);
|
||||
}
|
||||
else if (Items.Count > 0)
|
||||
{
|
||||
CurrentSelectionIdx = 0;
|
||||
UpdateSelection(Items[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSelection(null);
|
||||
}
|
||||
if (!ReferenceEquals(_currentDesign, CurrentSelection?.Item1))
|
||||
CurrentSelectionIdx = -1;
|
||||
|
||||
if (!priorState)
|
||||
Cleanup();
|
||||
break;
|
||||
base.OnMouseWheel(preview, ref _2, steps);
|
||||
}
|
||||
|
||||
private void UpdateCurrentSelection()
|
||||
{
|
||||
if (!_isCurrentSelectionDirty)
|
||||
return;
|
||||
|
||||
var priorState = IsInitialized;
|
||||
if (priorState)
|
||||
Cleanup();
|
||||
CurrentSelectionIdx = Items.IndexOf(s => ReferenceEquals(s.Item1, CurrentSelection?.Item1));
|
||||
if (CurrentSelectionIdx >= 0)
|
||||
{
|
||||
UpdateSelection(Items[CurrentSelectionIdx]);
|
||||
}
|
||||
else if (Items.Count > 0)
|
||||
{
|
||||
CurrentSelectionIdx = 0;
|
||||
UpdateSelection(Items[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSelection(null);
|
||||
}
|
||||
|
||||
if (!priorState)
|
||||
Cleanup();
|
||||
_isCurrentSelectionDirty = false;
|
||||
}
|
||||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
CurrentSelectionIdx = Items.IndexOf(p => _currentDesign == p.Item1);
|
||||
UpdateSelection(CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : null);
|
||||
return CurrentSelectionIdx;
|
||||
}
|
||||
|
||||
private void OnDesignChanged(DesignChanged.Type type, Design? _1, ITransaction? _2 = null)
|
||||
{
|
||||
_isCurrentSelectionDirty = type switch
|
||||
{
|
||||
DesignChanged.Type.Created => true,
|
||||
DesignChanged.Type.Renamed => true,
|
||||
DesignChanged.Type.ChangedColor => true,
|
||||
DesignChanged.Type.Deleted => true,
|
||||
DesignChanged.Type.QuickDesignBar => true,
|
||||
_ => _isCurrentSelectionDirty,
|
||||
};
|
||||
}
|
||||
|
||||
private void QuickSelectedDesignTooltip(IDesignStandIn? design)
|
||||
|
|
@ -175,7 +194,7 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, s
|
|||
ImGui.TextUnformatted("Currently resolving to ");
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, DesignColors.GetColor(linkedDesign));
|
||||
ImGui.SameLine(0, 0);
|
||||
ImGui.TextUnformatted(linkedDesign.Name);
|
||||
ImGui.TextUnformatted(linkedDesign.Name.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -225,8 +244,7 @@ public abstract class DesignCombo : DesignComboBase
|
|||
|
||||
public sealed class QuickDesignCombo : DesignCombo
|
||||
{
|
||||
public QuickDesignCombo(DesignManager designs,
|
||||
DesignFileSystem fileSystem,
|
||||
public QuickDesignCombo(DesignFileSystem fileSystem,
|
||||
Logger log,
|
||||
DesignChanged designChanged,
|
||||
TabSelected tabSelected,
|
||||
|
|
@ -234,9 +252,9 @@ public sealed class QuickDesignCombo : DesignCombo
|
|||
DesignColors designColors)
|
||||
: base(log, designChanged, tabSelected, config, designColors, () =>
|
||||
[
|
||||
.. designs.Designs
|
||||
.Where(d => d.QuickDesign)
|
||||
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||
.. fileSystem
|
||||
.Where(kvp => kvp.Key.QuickDesign)
|
||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
||||
.OrderBy(d => d.Item2),
|
||||
])
|
||||
{
|
||||
|
|
@ -277,7 +295,6 @@ public sealed class QuickDesignCombo : DesignCombo
|
|||
}
|
||||
|
||||
public sealed class LinkDesignCombo(
|
||||
DesignManager designs,
|
||||
DesignFileSystem fileSystem,
|
||||
Logger log,
|
||||
DesignChanged designChanged,
|
||||
|
|
@ -286,8 +303,8 @@ public sealed class LinkDesignCombo(
|
|||
DesignColors designColors)
|
||||
: DesignCombo(log, designChanged, tabSelected, config, designColors, () =>
|
||||
[
|
||||
.. designs.Designs
|
||||
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||
.. fileSystem
|
||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
||||
.OrderBy(d => d.Item2),
|
||||
]);
|
||||
|
||||
|
|
@ -301,8 +318,8 @@ public sealed class RandomDesignCombo(
|
|||
DesignColors designColors)
|
||||
: DesignCombo(log, designChanged, tabSelected, config, designColors, () =>
|
||||
[
|
||||
.. designs.Designs
|
||||
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||
.. fileSystem
|
||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
||||
.OrderBy(d => d.Item2),
|
||||
])
|
||||
{
|
||||
|
|
@ -328,7 +345,6 @@ public sealed class RandomDesignCombo(
|
|||
}
|
||||
|
||||
public sealed class SpecialDesignCombo(
|
||||
DesignManager designs,
|
||||
DesignFileSystem fileSystem,
|
||||
TabSelected tabSelected,
|
||||
DesignColors designColors,
|
||||
|
|
@ -338,8 +354,8 @@ public sealed class SpecialDesignCombo(
|
|||
EphemeralConfig config,
|
||||
RandomDesignGenerator rng,
|
||||
QuickSelectedDesign quickSelectedDesign)
|
||||
: DesignComboBase(() => designs.Designs
|
||||
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||
: DesignComboBase(() => fileSystem
|
||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
||||
.OrderBy(d => d.Item2)
|
||||
.Prepend(new Tuple<IDesignStandIn, string>(new RandomDesign(rng), string.Empty))
|
||||
.Prepend(new Tuple<IDesignStandIn, string>(quickSelectedDesign, string.Empty))
|
||||
|
|
|
|||
|
|
@ -6,26 +6,28 @@ using Dalamud.Interface.Windowing;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
[Flags]
|
||||
public enum QdbButtons
|
||||
{
|
||||
ApplyDesign = 0x01,
|
||||
RevertAll = 0x02,
|
||||
RevertAutomation = 0x04,
|
||||
RevertAdvanced = 0x08,
|
||||
RevertEquip = 0x10,
|
||||
RevertCustomize = 0x20,
|
||||
ReapplyAutomation = 0x40,
|
||||
ApplyDesign = 0x01,
|
||||
RevertAll = 0x02,
|
||||
RevertAutomation = 0x04,
|
||||
RevertAdvancedDyes = 0x08,
|
||||
RevertEquip = 0x10,
|
||||
RevertCustomize = 0x20,
|
||||
ReapplyAutomation = 0x40,
|
||||
ResetSettings = 0x80,
|
||||
RevertAdvancedCustomization = 0x100,
|
||||
}
|
||||
|
||||
public sealed class DesignQuickBar : Window, IDisposable
|
||||
|
|
@ -35,19 +37,21 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
? ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoMove
|
||||
: ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoFocusOnAppearing;
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly QuickDesignCombo _designCombo;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly IKeyState _keyState;
|
||||
private readonly ImRaii.Style _windowPadding = new();
|
||||
private readonly ImRaii.Color _windowColor = new();
|
||||
private DateTime _keyboardToggle = DateTime.UnixEpoch;
|
||||
private int _numButtons;
|
||||
private readonly Configuration _config;
|
||||
private readonly QuickDesignCombo _designCombo;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly IKeyState _keyState;
|
||||
private readonly ImRaii.Style _windowPadding = new();
|
||||
private readonly ImRaii.Color _windowColor = new();
|
||||
private DateTime _keyboardToggle = DateTime.UnixEpoch;
|
||||
private int _numButtons;
|
||||
private readonly StringBuilder _tooltipBuilder = new(512);
|
||||
|
||||
public DesignQuickBar(Configuration config, QuickDesignCombo designCombo, StateManager stateManager, IKeyState keyState,
|
||||
ObjectManager objects, AutoDesignApplier autoDesignApplier)
|
||||
ActorObjectManager objects, AutoDesignApplier autoDesignApplier, PenumbraService penumbra)
|
||||
: base("Glamourer Quick Bar", ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoDocking)
|
||||
{
|
||||
_config = config;
|
||||
|
|
@ -56,9 +60,11 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
_keyState = keyState;
|
||||
_objects = objects;
|
||||
_autoDesignApplier = autoDesignApplier;
|
||||
_penumbra = penumbra;
|
||||
IsOpen = _config.Ephemeral.ShowDesignQuickBar;
|
||||
DisableWindowSounds = true;
|
||||
Size = Vector2.Zero;
|
||||
RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -103,7 +109,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
|
||||
private void Draw(float width)
|
||||
{
|
||||
using var group = ImRaii.Group();
|
||||
using var group = ImUtf8.Group();
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing;
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||
var buttonSize = new Vector2(ImGui.GetFrameHeight());
|
||||
|
|
@ -120,8 +126,10 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
DrawRevertEquipButton(buttonSize);
|
||||
DrawRevertCustomizeButton(buttonSize);
|
||||
DrawRevertAdvancedCustomization(buttonSize);
|
||||
DrawRevertAdvancedDyes(buttonSize);
|
||||
DrawRevertAutomationButton(buttonSize);
|
||||
DrawReapplyAutomationButton(buttonSize);
|
||||
DrawResetSettingsButton(buttonSize);
|
||||
}
|
||||
|
||||
private ActorIdentifier _playerIdentifier;
|
||||
|
|
@ -144,33 +152,38 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
{
|
||||
var design = _designCombo.Design as Design;
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (design == null)
|
||||
{
|
||||
tooltip = "No design selected.";
|
||||
_tooltipBuilder.Append("No design selected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_playerIdentifier.IsValid && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = $"Left-Click: Apply {design.ResolveName(_config.Ephemeral.IncognitoMode)} to yourself.";
|
||||
_tooltipBuilder.Append("Left-Click: Apply ")
|
||||
.Append(design.ResolveName(_config.Ephemeral.IncognitoMode))
|
||||
.Append(" to yourself.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Apply {design.ResolveName(_config.Ephemeral.IncognitoMode)} to {_targetIdentifier}.";
|
||||
_tooltipBuilder.Append("Right-Click: Apply ")
|
||||
.Append(design.ResolveName(_config.Ephemeral.IncognitoMode))
|
||||
.Append(" to ").Append(_config.Ephemeral.IncognitoMode ? _targetIdentifier.Incognito(null) : _targetIdentifier.ToName());
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target available.";
|
||||
_tooltipBuilder.Append("Neither player character nor target available.");
|
||||
}
|
||||
|
||||
|
||||
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.PlayCircle, size, tooltip, available);
|
||||
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.PlayCircle, size, available);
|
||||
ImGui.SameLine();
|
||||
if (!clicked)
|
||||
return;
|
||||
|
|
@ -192,25 +205,29 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
return;
|
||||
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false })
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = "Left-Click: Revert the player character to their game state.";
|
||||
_tooltipBuilder.Append("Left-Click: Revert the player character to their game state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false })
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Revert {_targetIdentifier} to their game state.";
|
||||
_tooltipBuilder.Append("Right-Click: Revert ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append(" to their game state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked.";
|
||||
_tooltipBuilder.Append(
|
||||
"Neither player character nor target are available, have state modified by Glamourer, or their state is locked.");
|
||||
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available);
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (clicked)
|
||||
_stateManager.ResetState(state!, StateSource.Manual, isFinal: true);
|
||||
|
|
@ -225,26 +242,29 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
return;
|
||||
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = "Left-Click: Revert the player character to their automation state.";
|
||||
_tooltipBuilder.Append("Left-Click: Revert the player character to their automation state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Revert {_targetIdentifier} to their automation state.";
|
||||
_tooltipBuilder.Append("Right-Click: Revert ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append(" to their automation state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked.";
|
||||
_tooltipBuilder.Append(
|
||||
"Neither player character nor target are available, have state modified by Glamourer, or their state is locked.");
|
||||
|
||||
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.SyncAlt, buttonSize, tooltip, available);
|
||||
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.SyncAlt, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (!clicked)
|
||||
return;
|
||||
|
|
@ -265,26 +285,29 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
return;
|
||||
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = "Left-Click: Reapply the player character's current automation on top of their current state.";
|
||||
_tooltipBuilder.Append("Left-Click: Reapply the player character's current automation on top of their current state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Reapply {_targetIdentifier}'s current automation on top of their current state.";
|
||||
_tooltipBuilder.Append("Right-Click: Reapply ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append("'s current automation on top of their current state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked.";
|
||||
_tooltipBuilder.Append(
|
||||
"Neither player character nor target are available, have state modified by Glamourer, or their state is locked.");
|
||||
|
||||
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.Repeat, buttonSize, tooltip, available);
|
||||
var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.Repeat, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (!clicked)
|
||||
return;
|
||||
|
|
@ -298,36 +321,68 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
|
||||
private void DrawRevertAdvancedCustomization(Vector2 buttonSize)
|
||||
{
|
||||
if (!_config.UseAdvancedParameters)
|
||||
return;
|
||||
|
||||
if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvanced))
|
||||
if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedCustomization))
|
||||
return;
|
||||
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = "Left-Click: Revert the advanced customizations and dyes of the player character to their game state.";
|
||||
_tooltipBuilder.Append("Left-Click: Revert the advanced customizations of the player character to their game state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Revert the advanced customizations and dyes of {_targetIdentifier} to their game state.";
|
||||
_tooltipBuilder.Append("Right-Click: Revert the advanced customizations of ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append(" to their game state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target are available or their state is locked.";
|
||||
_tooltipBuilder.Append("Neither player character nor target are available or their state is locked.");
|
||||
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available);
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.PaintBrush, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (clicked)
|
||||
_stateManager.ResetAdvancedState(state!, StateSource.Manual);
|
||||
_stateManager.ResetAdvancedCustomizations(state!, StateSource.Manual);
|
||||
}
|
||||
|
||||
private void DrawRevertAdvancedDyes(Vector2 buttonSize)
|
||||
{
|
||||
if (!_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedDyes))
|
||||
return;
|
||||
|
||||
var available = 0;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
_tooltipBuilder.Append("Left-Click: Revert the advanced dyes of the player character to their game state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
_tooltipBuilder.Append("Right-Click: Revert the advanced dyes of ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append(" to their game state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
_tooltipBuilder.Append("Neither player character nor target are available or their state is locked.");
|
||||
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (clicked)
|
||||
_stateManager.ResetAdvancedDyes(state!, StateSource.Manual);
|
||||
}
|
||||
|
||||
private void DrawRevertCustomizeButton(Vector2 buttonSize)
|
||||
|
|
@ -336,26 +391,28 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
return;
|
||||
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = "Left-Click: Revert the customizations of the player character to their game state.";
|
||||
_tooltipBuilder.Append("Left-Click: Revert the customizations of the player character to their game state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Revert the customizations of {_targetIdentifier} to their game state.";
|
||||
_tooltipBuilder.Append("Right-Click: Revert the customizations of ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append(" to their game state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target are available or their state is locked.";
|
||||
_tooltipBuilder.Append("Neither player character nor target are available or their state is locked.");
|
||||
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.User, buttonSize, tooltip, available);
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.User, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (clicked)
|
||||
_stateManager.ResetCustomize(state!, StateSource.Manual);
|
||||
|
|
@ -367,35 +424,80 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
return;
|
||||
|
||||
var available = 0;
|
||||
var tooltip = string.Empty;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
tooltip = "Left-Click: Revert the equipment of the player character to its game state.";
|
||||
_tooltipBuilder.Append("Left-Click: Revert the equipment of the player character to its game state.");
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
tooltip += '\n';
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
tooltip += $"Right-Click: Revert the equipment of {_targetIdentifier} to its game state.";
|
||||
_tooltipBuilder.Append("Right-Click: Revert the equipment of ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append(" to its game state.");
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
tooltip = "Neither player character nor target are available or their state is locked.";
|
||||
_tooltipBuilder.Append("Neither player character nor target are available or their state is locked.");
|
||||
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Vest, buttonSize, tooltip, available);
|
||||
var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Vest, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (clicked)
|
||||
_stateManager.ResetEquip(state!, StateSource.Manual);
|
||||
}
|
||||
|
||||
private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip,
|
||||
int available)
|
||||
private void DrawResetSettingsButton(Vector2 buttonSize)
|
||||
{
|
||||
ImGuiUtil.DrawDisabledButton(icon.ToIconString(), buttonSize, tooltip, available == 0, true);
|
||||
if (!_config.QdbButtons.HasFlag(QdbButtons.ResetSettings))
|
||||
return;
|
||||
|
||||
var available = 0;
|
||||
_tooltipBuilder.Clear();
|
||||
|
||||
if (_playerIdentifier.IsValid && _playerData.Valid)
|
||||
{
|
||||
available |= 1;
|
||||
_tooltipBuilder
|
||||
.Append(
|
||||
"Left-Click: Reset all temporary settings applied by Glamourer (manually or through automation) to the collection affecting ")
|
||||
.Append(_playerIdentifier)
|
||||
.Append('.');
|
||||
}
|
||||
|
||||
if (_targetIdentifier.IsValid && _targetData.Valid)
|
||||
{
|
||||
if (available != 0)
|
||||
_tooltipBuilder.Append('\n');
|
||||
available |= 2;
|
||||
_tooltipBuilder
|
||||
.Append(
|
||||
"Right-Click: Reset all temporary settings applied by Glamourer (manually or through automation) to the collection affecting ")
|
||||
.Append(_targetIdentifier)
|
||||
.Append('.');
|
||||
}
|
||||
|
||||
if (available == 0)
|
||||
_tooltipBuilder.Append("Neither player character nor target are available to identify their collections.");
|
||||
|
||||
var (clicked, _, data, _) = ResolveTarget(FontAwesomeIcon.Cog, buttonSize, available);
|
||||
ImGui.SameLine();
|
||||
if (clicked)
|
||||
{
|
||||
_penumbra.RemoveAllTemporarySettings(data.Objects[0].Index, StateSource.Manual);
|
||||
_penumbra.RemoveAllTemporarySettings(data.Objects[0].Index, StateSource.Fixed);
|
||||
}
|
||||
}
|
||||
|
||||
private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, int available)
|
||||
{
|
||||
var enumerator = _tooltipBuilder.GetChunks();
|
||||
var span = enumerator.MoveNext() ? enumerator.Current.Span : [];
|
||||
ImUtf8.IconButton(icon, span, buttonSize, available == 0);
|
||||
if ((available & 1) == 1 && ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
return (true, _playerIdentifier, _playerData, _playerState);
|
||||
if ((available & 2) == 2 && ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
|
|
@ -435,12 +537,16 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
++_numButtons;
|
||||
}
|
||||
|
||||
if ((_config.UseAdvancedParameters || _config.UseAdvancedDyes) && _config.QdbButtons.HasFlag(QdbButtons.RevertAdvanced))
|
||||
if (_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedCustomization))
|
||||
++_numButtons;
|
||||
if (_config.QdbButtons.HasFlag(QdbButtons.RevertAdvancedDyes))
|
||||
++_numButtons;
|
||||
if (_config.QdbButtons.HasFlag(QdbButtons.RevertCustomize))
|
||||
++_numButtons;
|
||||
if (_config.QdbButtons.HasFlag(QdbButtons.RevertEquip))
|
||||
++_numButtons;
|
||||
if (_config.UseTemporarySettings && _config.QdbButtons.HasFlag(QdbButtons.ResetSettings))
|
||||
++_numButtons;
|
||||
if (_config.QdbButtons.HasFlag(QdbButtons.ApplyDesign))
|
||||
{
|
||||
++_numButtons;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.State;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -9,10 +10,11 @@ public struct BonusDrawData(BonusItemFlag slot, in DesignData designData)
|
|||
{
|
||||
private IDesignEditor _editor = null!;
|
||||
private object _object = null!;
|
||||
public readonly BonusItemFlag Slot = slot;
|
||||
public readonly BonusItemFlag Slot = slot;
|
||||
public bool Locked;
|
||||
public bool DisplayApplication;
|
||||
public bool AllowRevert;
|
||||
public bool HasAdvancedDyes;
|
||||
|
||||
public readonly bool IsDesign
|
||||
=> _object is Design;
|
||||
|
|
@ -42,6 +44,7 @@ public struct BonusDrawData(BonusItemFlag slot, in DesignData designData)
|
|||
CurrentApply = design.DoApplyBonusItem(slot),
|
||||
Locked = design.WriteProtected(),
|
||||
DisplayApplication = true,
|
||||
HasAdvancedDyes = design.GetMaterialDataRef().CheckExistenceSlot(MaterialValueIndex.FromSlot(slot)),
|
||||
};
|
||||
|
||||
public static BonusDrawData FromState(StateManager manager, ActorState state, BonusItemFlag slot)
|
||||
|
|
@ -53,5 +56,6 @@ public struct BonusDrawData(BonusItemFlag slot, in DesignData designData)
|
|||
DisplayApplication = false,
|
||||
GameItem = state.BaseData.BonusItem(slot),
|
||||
AllowRevert = true,
|
||||
HasAdvancedDyes = state.Materials.CheckExistenceSlot(MaterialValueIndex.FromSlot(slot)),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Lumina.Excel.Sheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.State;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -9,7 +10,7 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
|
|||
{
|
||||
private IDesignEditor _editor = null!;
|
||||
private object _object = null!;
|
||||
public readonly EquipSlot Slot = slot;
|
||||
public readonly EquipSlot Slot = slot;
|
||||
public bool Locked;
|
||||
public bool DisplayApplication;
|
||||
public bool AllowRevert;
|
||||
|
|
@ -26,18 +27,19 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
|
|||
public readonly void SetStains(StainIds stains)
|
||||
=> _editor.ChangeStains(_object, Slot, stains, ApplySettings.Manual);
|
||||
|
||||
public readonly void SetStain(int which, StainId stain)
|
||||
=> _editor.ChangeStains(_object, Slot, CurrentStains.With(which, stain), ApplySettings.Manual);
|
||||
|
||||
public readonly void SetApplyItem(bool value)
|
||||
{
|
||||
var manager = (DesignManager)_editor;
|
||||
var design = (Design)_object;
|
||||
manager.ChangeApplyItem(design, Slot, value);
|
||||
manager.ChangeApplyItem((Design)_object, Slot, value);
|
||||
}
|
||||
|
||||
public readonly void SetApplyStain(bool value)
|
||||
{
|
||||
var manager = (DesignManager)_editor;
|
||||
var design = (Design)_object;
|
||||
manager.ChangeApplyStains(design, Slot, value);
|
||||
manager.ChangeApplyStains((Design)_object, Slot, value);
|
||||
}
|
||||
|
||||
public EquipItem CurrentItem = designData.Item(slot);
|
||||
|
|
@ -46,6 +48,7 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
|
|||
public StainIds GameStains = default;
|
||||
public bool CurrentApply;
|
||||
public bool CurrentApplyStain;
|
||||
public bool HasAdvancedDyes;
|
||||
|
||||
public readonly Gender CurrentGender = designData.Customize.Gender;
|
||||
public readonly Race CurrentRace = designData.Customize.Race;
|
||||
|
|
@ -58,6 +61,7 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
|
|||
CurrentApply = design.DoApplyEquip(slot),
|
||||
CurrentApplyStain = design.DoApplyStain(slot),
|
||||
Locked = design.WriteProtected(),
|
||||
HasAdvancedDyes = design.GetMaterialDataRef().CheckExistenceSlot(MaterialValueIndex.FromSlot(slot)),
|
||||
DisplayApplication = true,
|
||||
};
|
||||
|
||||
|
|
@ -70,6 +74,7 @@ public struct EquipDrawData(EquipSlot slot, in DesignData designData)
|
|||
DisplayApplication = false,
|
||||
GameItem = state.BaseData.Item(slot),
|
||||
GameStains = state.BaseData.Stain(slot),
|
||||
HasAdvancedDyes = state.Materials.CheckExistenceSlot(MaterialValueIndex.FromSlot(slot)),
|
||||
AllowRevert = true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
83
Glamourer/Gui/Equipment/EquipItemSlotCache.cs
Normal file
83
Glamourer/Gui/Equipment/EquipItemSlotCache.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
using Glamourer.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
[InlineArray(13)]
|
||||
public struct EquipItemSlotCache
|
||||
{
|
||||
private EquipItem _element;
|
||||
|
||||
public EquipItem Dragged
|
||||
{
|
||||
get => this[^1];
|
||||
set => this[^1] = value;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
=> ((Span<EquipItem>)this).Clear();
|
||||
|
||||
public EquipItem this[EquipSlot slot]
|
||||
{
|
||||
get => this[(int)slot.ToIndex()];
|
||||
set => this[(int)slot.ToIndex()] = value;
|
||||
}
|
||||
|
||||
public void Update(ItemManager items, in EquipItem item, EquipSlot startSlot)
|
||||
{
|
||||
if (item.Id == Dragged.Id && item.Type == Dragged.Type)
|
||||
return;
|
||||
|
||||
switch (startSlot)
|
||||
{
|
||||
case EquipSlot.MainHand:
|
||||
{
|
||||
Clear();
|
||||
this[EquipSlot.MainHand] = item;
|
||||
if (item.Type is FullEquipType.Sword)
|
||||
this[EquipSlot.OffHand] = items.FindClosestShield(item.ItemId, out var shield) ? shield : default;
|
||||
else
|
||||
this[EquipSlot.OffHand] = items.ItemData.Secondary.GetValueOrDefault(item.ItemId);
|
||||
break;
|
||||
}
|
||||
case EquipSlot.OffHand:
|
||||
{
|
||||
Clear();
|
||||
if (item.Type is FullEquipType.Shield)
|
||||
this[EquipSlot.MainHand] = items.FindClosestSword(item.ItemId, out var sword) ? sword : default;
|
||||
else
|
||||
this[EquipSlot.MainHand] = items.ItemData.Primary.GetValueOrDefault(item.ItemId);
|
||||
this[EquipSlot.OffHand] = item;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this[EquipSlot.MainHand] = default;
|
||||
this[EquipSlot.OffHand] = default;
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
if (startSlot == slot)
|
||||
{
|
||||
this[slot] = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
var slotItem = items.Identify(slot, item.PrimaryId, item.Variant);
|
||||
if (!slotItem.Valid || slotItem.ItemId.Id is not 0 != item.ItemId.Id is not 0)
|
||||
{
|
||||
slotItem = items.Identify(EquipSlot.OffHand, item.PrimaryId, item.SecondaryId, 1, item.Type);
|
||||
if (slotItem.ItemId.Id is not 0 != item.ItemId.Id is not 0)
|
||||
slotItem = default;
|
||||
}
|
||||
|
||||
this[slot] = slotItem;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Dragged = item;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,12 +5,13 @@ using Glamourer.Events;
|
|||
using Glamourer.Gui.Materials;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.EndObjects;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -31,20 +32,24 @@ public class EquipmentDrawer
|
|||
private readonly Configuration _config;
|
||||
private readonly GPoseService _gPose;
|
||||
private readonly AdvancedDyePopup _advancedDyes;
|
||||
private readonly ItemCopyService _itemCopy;
|
||||
|
||||
private float _requiredComboWidthUnscaled;
|
||||
private float _requiredComboWidth;
|
||||
|
||||
private Stain? _draggedStain;
|
||||
private Stain? _draggedStain;
|
||||
private EquipItemSlotCache _draggedItem;
|
||||
private EquipSlot _dragTarget;
|
||||
|
||||
public EquipmentDrawer(FavoriteManager favorites, IDataManager gameData, ItemManager items, TextureService textures,
|
||||
Configuration config, GPoseService gPose, AdvancedDyePopup advancedDyes)
|
||||
Configuration config, GPoseService gPose, AdvancedDyePopup advancedDyes, ItemCopyService itemCopy)
|
||||
{
|
||||
_items = items;
|
||||
_textures = textures;
|
||||
_config = config;
|
||||
_gPose = gPose;
|
||||
_advancedDyes = advancedDyes;
|
||||
_itemCopy = itemCopy;
|
||||
_stainData = items.Stains;
|
||||
_stainCombo = new GlamourerColorCombo(DefaultWidth - 20, _stainData, favorites);
|
||||
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log, favorites)).ToArray();
|
||||
|
|
@ -63,6 +68,7 @@ public class EquipmentDrawer
|
|||
|
||||
private Vector2 _iconSize;
|
||||
private float _comboLength;
|
||||
private uint _advancedMaterialColor;
|
||||
|
||||
public void Prepare()
|
||||
{
|
||||
|
|
@ -74,7 +80,9 @@ public class EquipmentDrawer
|
|||
.Max(i => ImGui.CalcTextSize($"{i.Item2.Name} ({i.Item2.ModelString})").X)
|
||||
/ ImGuiHelpers.GlobalScale;
|
||||
|
||||
_requiredComboWidth = _requiredComboWidthUnscaled * ImGuiHelpers.GlobalScale;
|
||||
_requiredComboWidth = _requiredComboWidthUnscaled * ImGuiHelpers.GlobalScale;
|
||||
_advancedMaterialColor = ColorId.AdvancedDyeActive.Value();
|
||||
_dragTarget = EquipSlot.Unknown;
|
||||
}
|
||||
|
||||
private bool VerifyRestrictedGear(EquipDrawData data)
|
||||
|
|
@ -91,7 +99,7 @@ public class EquipmentDrawer
|
|||
if (_config.HideApplyCheckmarks)
|
||||
equipDrawData.DisplayApplication = false;
|
||||
|
||||
using var id = ImRaii.PushId((int)equipDrawData.Slot);
|
||||
using var id = ImUtf8.PushId((int)equipDrawData.Slot);
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||
|
||||
|
|
@ -106,7 +114,7 @@ public class EquipmentDrawer
|
|||
if (_config.HideApplyCheckmarks)
|
||||
bonusDrawData.DisplayApplication = false;
|
||||
|
||||
using var id = ImRaii.PushId(100 + (int)bonusDrawData.Slot);
|
||||
using var id = ImUtf8.PushId(100 + (int)bonusDrawData.Slot);
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||
|
||||
|
|
@ -127,7 +135,7 @@ public class EquipmentDrawer
|
|||
offhand.DisplayApplication = false;
|
||||
}
|
||||
|
||||
using var id = ImRaii.PushId("Weapons");
|
||||
using var id = ImUtf8.PushId("Weapons"u8);
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||
|
||||
|
|
@ -174,12 +182,13 @@ public class EquipmentDrawer
|
|||
change = true;
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip($"{_config.DeleteDesignModifier.ToString()} and Right-click to clear.");
|
||||
ImUtf8.HoverTooltip($"{_config.DeleteDesignModifier.ToString()} and Right-click to clear.");
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
#region Small
|
||||
|
||||
private void DrawEquipSmall(in EquipDrawData equipDrawData)
|
||||
|
|
@ -196,14 +205,13 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (equipDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot);
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot, equipDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
|
||||
if (VerifyRestrictedGear(equipDrawData))
|
||||
label += " (Restricted)";
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(label);
|
||||
DrawEquipLabel(equipDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
}
|
||||
|
||||
private void DrawBonusItemSmall(in BonusDrawData bonusDrawData)
|
||||
|
|
@ -218,11 +226,10 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (bonusDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot);
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot, bonusDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(label);
|
||||
DrawEquipLabel(bonusDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
}
|
||||
|
||||
private void DrawWeaponsSmall(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
||||
|
|
@ -239,12 +246,12 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (mainhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand);
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand, mainhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
|
||||
if (allWeapons)
|
||||
mainhandLabel += $" ({mainhand.CurrentItem.Type.ToName()})";
|
||||
WeaponHelpMarker(mainhandLabel);
|
||||
WeaponHelpMarker(mainhand is { IsDesign: true, HasAdvancedDyes: true }, mainhandLabel);
|
||||
|
||||
if (offhand.CurrentItem.Type is FullEquipType.Unknown)
|
||||
return;
|
||||
|
|
@ -261,10 +268,10 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (offhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand);
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand, offhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
|
||||
WeaponHelpMarker(offhandLabel);
|
||||
WeaponHelpMarker(offhand is { IsDesign: true, HasAdvancedDyes: true }, offhandLabel);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -285,8 +292,8 @@ public class EquipmentDrawer
|
|||
DrawApply(equipDrawData);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(label);
|
||||
DrawEquipLabel(equipDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
|
||||
DrawStain(equipDrawData, false);
|
||||
if (equipDrawData.DisplayApplication)
|
||||
{
|
||||
|
|
@ -295,13 +302,13 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (equipDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot);
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot, equipDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
|
||||
if (VerifyRestrictedGear(equipDrawData))
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("(Restricted)");
|
||||
ImUtf8.Text("(Restricted)"u8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -319,11 +326,10 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (bonusDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot);
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot, bonusDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(label);
|
||||
DrawEquipLabel(bonusDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
}
|
||||
|
||||
private void DrawWeaponsNormal(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
||||
|
|
@ -334,7 +340,7 @@ public class EquipmentDrawer
|
|||
mainhand.CurrentItem.DrawIcon(_textures, _iconSize, EquipSlot.MainHand);
|
||||
var left = ImGui.IsItemClicked(ImGuiMouseButton.Left);
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.Group())
|
||||
using (ImUtf8.Group())
|
||||
{
|
||||
DrawMainhand(ref mainhand, ref offhand, out var mainhandLabel, allWeapons, false, left);
|
||||
if (mainhand.DisplayApplication)
|
||||
|
|
@ -343,7 +349,8 @@ public class EquipmentDrawer
|
|||
DrawApply(mainhand);
|
||||
}
|
||||
|
||||
WeaponHelpMarker(mainhandLabel, allWeapons ? mainhand.CurrentItem.Type.ToName() : null);
|
||||
WeaponHelpMarker(mainhand is { IsDesign: true, HasAdvancedDyes: true }, mainhandLabel,
|
||||
allWeapons ? mainhand.CurrentItem.Type.ToName() : null);
|
||||
|
||||
DrawStain(mainhand, false);
|
||||
if (mainhand.DisplayApplication)
|
||||
|
|
@ -353,7 +360,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (mainhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand);
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand, mainhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +371,7 @@ public class EquipmentDrawer
|
|||
var right = ImGui.IsItemClicked(ImGuiMouseButton.Right);
|
||||
left = ImGui.IsItemClicked(ImGuiMouseButton.Left);
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.Group())
|
||||
using (ImUtf8.Group())
|
||||
{
|
||||
DrawOffhand(mainhand, offhand, out var offhandLabel, false, right, left);
|
||||
if (offhand.DisplayApplication)
|
||||
|
|
@ -373,7 +380,7 @@ public class EquipmentDrawer
|
|||
DrawApply(offhand);
|
||||
}
|
||||
|
||||
WeaponHelpMarker(offhandLabel);
|
||||
WeaponHelpMarker(offhand is { IsDesign: true, HasAdvancedDyes: true }, offhandLabel);
|
||||
|
||||
DrawStain(offhand, false);
|
||||
if (offhand.DisplayApplication)
|
||||
|
|
@ -381,9 +388,9 @@ public class EquipmentDrawer
|
|||
ImGui.SameLine();
|
||||
DrawApplyStain(offhand);
|
||||
}
|
||||
else if (mainhand.IsState)
|
||||
else if (offhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand);
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand, offhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -400,6 +407,7 @@ public class EquipmentDrawer
|
|||
? _stainCombo.Draw($"##stain{data.Slot}", stain.RgbaColor, stain.Name, found, stain.Gloss)
|
||||
: _stainCombo.Draw($"##stain{data.Slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, width);
|
||||
|
||||
_itemCopy.HandleCopyPaste(data, index);
|
||||
if (!change)
|
||||
DrawStainDragDrop(data, index, stain, found);
|
||||
|
||||
|
|
@ -424,8 +432,8 @@ public class EquipmentDrawer
|
|||
using var dragSource = ImUtf8.DragDropSource();
|
||||
if (dragSource.Success)
|
||||
{
|
||||
if (DragDropSource.SetPayload("stainDragDrop"u8))
|
||||
_draggedStain = stain;
|
||||
DragDropSource.SetPayload("stainDragDrop"u8);
|
||||
_draggedStain = stain;
|
||||
ImUtf8.Text($"Dragging {stain.Name}...");
|
||||
}
|
||||
}
|
||||
|
|
@ -450,10 +458,12 @@ public class EquipmentDrawer
|
|||
using var disabled = ImRaii.Disabled(data.Locked);
|
||||
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||
_requiredComboWidth);
|
||||
DrawGearDragDrop(data);
|
||||
if (change)
|
||||
data.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0)
|
||||
data.SetItem(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant));
|
||||
_itemCopy.HandleCopyPaste(data);
|
||||
|
||||
if (ResetOrClear(data.Locked, clear, data.AllowRevert, true, data.CurrentItem, data.GameItem, ItemManager.NothingItem(data.Slot),
|
||||
out var item))
|
||||
|
|
@ -468,17 +478,71 @@ public class EquipmentDrawer
|
|||
UiHelpers.OpenCombo($"##{combo.Label}");
|
||||
|
||||
using var disabled = ImRaii.Disabled(data.Locked);
|
||||
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.Id.BonusItem, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.Id.BonusItem,
|
||||
small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||
_requiredComboWidth);
|
||||
if (ImGui.IsItemHovered() && ImGui.GetIO().KeyCtrl)
|
||||
{
|
||||
if (ImGui.IsKeyPressed(ImGuiKey.C))
|
||||
_itemCopy.Copy(combo.CurrentSelection);
|
||||
else if (ImGui.IsKeyPressed(ImGuiKey.V))
|
||||
_itemCopy.Paste(data.Slot.ToEquipType(), data.SetItem);
|
||||
}
|
||||
|
||||
if (change)
|
||||
data.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0)
|
||||
data.SetItem(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant));
|
||||
|
||||
if (ResetOrClear(data.Locked, clear, data.AllowRevert, true, data.CurrentItem, data.GameItem, EquipItem.BonusItemNothing(data.Slot), out var item))
|
||||
if (ResetOrClear(data.Locked, clear, data.AllowRevert, true, data.CurrentItem, data.GameItem, EquipItem.BonusItemNothing(data.Slot),
|
||||
out var item))
|
||||
data.SetItem(item);
|
||||
}
|
||||
|
||||
private void DrawGearDragDrop(in EquipDrawData data)
|
||||
{
|
||||
if (data.CurrentItem.Valid)
|
||||
{
|
||||
using var dragSource = ImUtf8.DragDropSource();
|
||||
if (dragSource.Success)
|
||||
{
|
||||
DragDropSource.SetPayload("equipDragDrop"u8);
|
||||
_draggedItem.Update(_items, data.CurrentItem, data.Slot);
|
||||
}
|
||||
}
|
||||
|
||||
using var dragTarget = ImUtf8.DragDropTarget();
|
||||
if (!dragTarget)
|
||||
return;
|
||||
|
||||
var item = _draggedItem[data.Slot];
|
||||
if (!item.Valid)
|
||||
return;
|
||||
|
||||
_dragTarget = data.Slot;
|
||||
if (!dragTarget.IsDropping("equipDragDrop"u8))
|
||||
return;
|
||||
|
||||
data.SetItem(item);
|
||||
_draggedItem.Clear();
|
||||
}
|
||||
|
||||
public unsafe void DrawDragDropTooltip()
|
||||
{
|
||||
var payload = ImGui.GetDragDropPayload().Handle;
|
||||
if (payload is null)
|
||||
return;
|
||||
|
||||
if (!MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)Unsafe.AsPointer(ref payload->DataType_0)).SequenceEqual("equipDragDrop"u8))
|
||||
return;
|
||||
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
if (_dragTarget is EquipSlot.Unknown)
|
||||
ImUtf8.Text($"Dragging {_draggedItem.Dragged.Name}...");
|
||||
else
|
||||
ImUtf8.Text($"Converting to {_draggedItem[_dragTarget].Name}...");
|
||||
}
|
||||
|
||||
private static bool ResetOrClear<T>(bool locked, bool clicked, bool allowRevert, bool allowClear,
|
||||
in T currentItem, in T revertItem, in T clearItem, out T? item) where T : IEquatable<T>
|
||||
{
|
||||
|
|
@ -502,7 +566,7 @@ public class EquipmentDrawer
|
|||
(false, true, _) => ("Right-click to clear.\nControl and mouse wheel to scroll.", clearItem, true),
|
||||
(false, false, _) => ("Control and mouse wheel to scroll.", default, false),
|
||||
};
|
||||
ImGuiUtil.HoverTooltip(tt);
|
||||
ImUtf8.HoverTooltip(tt);
|
||||
|
||||
return clicked && valid;
|
||||
}
|
||||
|
|
@ -527,8 +591,13 @@ public class EquipmentDrawer
|
|||
if (combo.Draw(mainhand.CurrentItem.Name, mainhand.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||
_requiredComboWidth))
|
||||
changedItem = combo.CurrentSelection;
|
||||
else if (ResetOrClear(mainhand.Locked || unknown, open, mainhand.AllowRevert, false, mainhand.CurrentItem, mainhand.GameItem,
|
||||
default, out var c))
|
||||
else if (combo.CustomVariant.Id > 0 && (drawAll || ItemData.ConvertWeaponId(combo.CustomSetId) == mainhand.CurrentItem.Type))
|
||||
changedItem = _items.Identify(mainhand.Slot, combo.CustomSetId, combo.CustomWeaponId, combo.CustomVariant);
|
||||
_itemCopy.HandleCopyPaste(mainhand);
|
||||
DrawGearDragDrop(mainhand);
|
||||
|
||||
if (ResetOrClear(mainhand.Locked || unknown, open, mainhand.AllowRevert, false, mainhand.CurrentItem, mainhand.GameItem,
|
||||
default, out var c))
|
||||
changedItem = c;
|
||||
|
||||
if (changedItem != null)
|
||||
|
|
@ -544,8 +613,9 @@ public class EquipmentDrawer
|
|||
}
|
||||
}
|
||||
|
||||
if (unknown && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
ImGui.SetTooltip("The weapon type could not be identified, thus changing it to other weapons of that type is not possible.");
|
||||
if (unknown)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled,
|
||||
"The weapon type could not be identified, thus changing it to other weapons of that type is not possible."u8);
|
||||
}
|
||||
|
||||
private void DrawOffhand(in EquipDrawData mainhand, in EquipDrawData offhand, out string label, bool small, bool clear, bool open)
|
||||
|
|
@ -565,6 +635,10 @@ public class EquipmentDrawer
|
|||
if (combo.Draw(offhand.CurrentItem.Name, offhand.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||
_requiredComboWidth))
|
||||
offhand.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0 && ItemData.ConvertWeaponId(combo.CustomSetId) == offhand.CurrentItem.Type)
|
||||
offhand.SetItem(_items.Identify(mainhand.Slot, combo.CustomSetId, combo.CustomWeaponId, combo.CustomVariant));
|
||||
_itemCopy.HandleCopyPaste(offhand);
|
||||
DrawGearDragDrop(offhand);
|
||||
|
||||
var defaultOffhand = _items.GetDefaultOffhand(mainhand.CurrentItem);
|
||||
if (ResetOrClear(locked, clear, offhand.AllowRevert, true, offhand.CurrentItem, offhand.GameItem, defaultOffhand, out var item))
|
||||
|
|
@ -595,14 +669,14 @@ public class EquipmentDrawer
|
|||
|
||||
#endregion
|
||||
|
||||
private static void WeaponHelpMarker(string label, string? type = null)
|
||||
private void WeaponHelpMarker(bool hasAdvancedDyes, string label, string? type = null)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker(
|
||||
"Changing weapons to weapons of different types can cause crashes, freezes, soft- and hard locks and cheating, "
|
||||
+ "thus it is only allowed to change weapons to other weapons of the same type.");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(label);
|
||||
DrawEquipLabel(hasAdvancedDyes, label);
|
||||
|
||||
if (type == null)
|
||||
return;
|
||||
|
||||
|
|
@ -610,4 +684,17 @@ public class EquipmentDrawer
|
|||
pos.Y += ImGui.GetFrameHeightWithSpacing();
|
||||
ImGui.GetWindowDrawList().AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), $"({type})");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
|
||||
private void DrawEquipLabel(bool hasAdvancedDyes, string label)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, _advancedMaterialColor, hasAdvancedDyes))
|
||||
{
|
||||
ImUtf8.Text(label);
|
||||
}
|
||||
|
||||
if (hasAdvancedDyes)
|
||||
ImUtf8.HoverTooltip("This design has advanced dyes setup for this slot."u8);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Lumina.Excel.Sheets;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
|
|
|
|||
73
Glamourer/Gui/Equipment/ItemCopyService.cs
Normal file
73
Glamourer/Gui/Equipment/ItemCopyService.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
using Glamourer.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public class ItemCopyService(ItemManager items, DictStain stainData) : IUiService
|
||||
{
|
||||
public EquipItem? Item { get; private set; }
|
||||
public Stain? Stain { get; private set; }
|
||||
|
||||
public void Copy(in EquipItem item)
|
||||
=> Item = item;
|
||||
|
||||
public void Copy(in Stain stain)
|
||||
=> Stain = stain;
|
||||
|
||||
public void Paste(int which, Action<int, StainId> setter)
|
||||
{
|
||||
if (Stain is { } stain)
|
||||
setter(which, stain.RowIndex);
|
||||
}
|
||||
|
||||
public void Paste(FullEquipType type, Action<EquipItem> setter)
|
||||
{
|
||||
if (Item is not { } item)
|
||||
return;
|
||||
|
||||
if (type != item.Type)
|
||||
{
|
||||
if (type.IsBonus())
|
||||
item = items.Identify(type.ToBonus(), item.PrimaryId, item.Variant);
|
||||
else if (type.IsEquipment() || type.IsAccessory())
|
||||
item = items.Identify(type.ToSlot(), item.PrimaryId, item.Variant);
|
||||
else
|
||||
item = items.Identify(type.ToSlot(), item.PrimaryId, item.SecondaryId, item.Variant);
|
||||
}
|
||||
|
||||
if (item.Valid && item.Type == type)
|
||||
setter(item);
|
||||
}
|
||||
|
||||
public void HandleCopyPaste(in EquipDrawData data)
|
||||
{
|
||||
if (ImGui.GetIO().KeyCtrl)
|
||||
{
|
||||
if (ImGui.IsItemHovered() && ImGui.IsMouseClicked(ImGuiMouseButton.Middle))
|
||||
Paste(data.CurrentItem.Type, data.SetItem);
|
||||
}
|
||||
else if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled) && ImGui.IsMouseClicked(ImGuiMouseButton.Middle))
|
||||
{
|
||||
Copy(data.CurrentItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleCopyPaste(in EquipDrawData data, int which)
|
||||
{
|
||||
if (ImGui.GetIO().KeyCtrl)
|
||||
{
|
||||
if (ImGui.IsItemHovered() && ImGui.IsMouseClicked(ImGuiMouseButton.Middle))
|
||||
Paste(which, data.SetStain);
|
||||
}
|
||||
else if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)
|
||||
&& ImGui.IsMouseClicked(ImGuiMouseButton.Middle)
|
||||
&& stainData.TryGetValue(data.CurrentStains[which].Id, out var stain))
|
||||
{
|
||||
Copy(stain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
|
|
@ -19,6 +19,10 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
private ItemId _currentItem;
|
||||
private float _innerWidth;
|
||||
|
||||
public PrimaryId CustomSetId { get; private set; }
|
||||
public SecondaryId CustomWeaponId { get; private set; }
|
||||
public Variant CustomVariant { get; private set; }
|
||||
|
||||
public WeaponCombo(ItemManager items, FullEquipType type, Logger log, FavoriteManager favorites)
|
||||
: base(() => GetWeapons(favorites, items, type), MouseWheelType.Control, log)
|
||||
{
|
||||
|
|
@ -46,8 +50,9 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
|
||||
public bool Draw(string previewName, ItemId previewIdx, float width, float innerWidth)
|
||||
{
|
||||
_innerWidth = innerWidth;
|
||||
_currentItem = previewIdx;
|
||||
_innerWidth = innerWidth;
|
||||
_currentItem = previewIdx;
|
||||
CustomVariant = 0;
|
||||
return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +79,24 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
return ret;
|
||||
}
|
||||
|
||||
protected override void OnClosePopup()
|
||||
{
|
||||
// If holding control while the popup closes, try to parse the input as a full tuple of set id, weapon id and variant, and set a custom item for that.
|
||||
if (!ImGui.GetIO().KeyCtrl)
|
||||
return;
|
||||
|
||||
var split = Filter.Text.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length != 3
|
||||
|| !ushort.TryParse(split[0], out var setId)
|
||||
|| !ushort.TryParse(split[1], out var weaponId)
|
||||
|| !byte.TryParse(split[2], out var variant))
|
||||
return;
|
||||
|
||||
CustomSetId = setId;
|
||||
CustomWeaponId = weaponId;
|
||||
CustomVariant = variant;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || Items[globalIndex].ModelString.StartsWith(filter.Lower);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Dalamud.Interface.Utility;
|
|||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Gui.Materials;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ public class GlamourerChangelog
|
|||
Add1_3_4_0(Changelog);
|
||||
Add1_3_5_0(Changelog);
|
||||
Add1_3_6_0(Changelog);
|
||||
Add1_3_7_0(Changelog);
|
||||
Add1_3_8_0(Changelog);
|
||||
Add1_4_0_0(Changelog);
|
||||
Add1_5_0_0(Changelog);
|
||||
Add1_5_1_0(Changelog);
|
||||
}
|
||||
|
||||
private (int, ChangeLogDisplayType) ConfigData()
|
||||
|
|
@ -60,32 +65,127 @@ public class GlamourerChangelog
|
|||
}
|
||||
}
|
||||
|
||||
private static void Add1_5_1_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.5.1.0")
|
||||
.RegisterHighlight("Added support for Penumbras PCP functionality to add the current state of the character as a design.")
|
||||
.RegisterEntry("On import, a design for the PCP is created and, if possible, applied to the character.", 1)
|
||||
.RegisterEntry("No automation is assigned.", 1)
|
||||
.RegisterEntry("Finer control about this can be found in the settings.", 1)
|
||||
.RegisterEntry("Fixed an issue with static visors not toggling through Glamourer (1.5.0.7).")
|
||||
.RegisterEntry("The advanced dye slot combo now contains glasses (1.5.0.7).")
|
||||
.RegisterEntry("Several fixes for patch-related issues (1.5.0.1 - 1.5.0.6");
|
||||
|
||||
private static void Add1_5_0_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.5.0.0")
|
||||
.RegisterImportant("Updated for game version 7.30 and Dalamud API13, which uses a new GUI backend. Some things may not work as expected. Please let me know any issues you encounter.")
|
||||
.RegisterHighlight("Added the new Viera Ears state to designs. Old designs will not apply the state.")
|
||||
.RegisterHighlight("Added the option to make newly created designs write-protected by default to the design defaults.")
|
||||
.RegisterEntry("Fixed issues with reverting state and IPC.")
|
||||
.RegisterEntry("Fixed an issue when using the mousewheel to scroll through designs (1.4.0.3).")
|
||||
.RegisterEntry("Fixed an issue with invalid bonus items (1.4.0.3).")
|
||||
.RegisterHighlight("Added drag & drop of equipment pieces which will try to match the corresponding model IDs in other slots if possible (1.4.0.2).")
|
||||
.RegisterEntry("Heavily optimized some issues when having many designs and creating new ones or updating them (1.4.0.2)")
|
||||
.RegisterEntry("Fixed an issue with staining templates (1.4.0.1).")
|
||||
.RegisterEntry("Fixed an issue with the QDB buttons not counting correctly (1.4.0.1).");
|
||||
|
||||
private static void Add1_4_0_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.4.0.0")
|
||||
.RegisterHighlight("The design selector width is now draggable within certain restrictions that depend on the total window width.")
|
||||
.RegisterEntry("The current behavior may not be final, let me know if you have any comments.", 1)
|
||||
.RegisterEntry("Regular customization colors can now be dragged & dropped onto other customizations.")
|
||||
.RegisterEntry(
|
||||
"If no identical color is available in the target slot, the most similar color available (for certain values of similar) will be chosen instead.",
|
||||
1)
|
||||
.RegisterEntry("Resetting advanced dyes and customizations has been split into two buttons for the quick design bar.")
|
||||
.RegisterEntry("Weapons now also support custom ID input in the combo search box.")
|
||||
.RegisterEntry("Added new IPC methods GetExtendedDesignData, AddDesign, DeleteDesign, GetDesignBase64, GetDesignJObject.")
|
||||
.RegisterEntry("Added the option to prevent immediate repeats for random design selection (Thanks Diorik!).")
|
||||
.RegisterEntry("Optimized some multi-design changes when selecting many designs and changing them at once.")
|
||||
.RegisterEntry("Fixed item combos not starting from the currently selected item when scrolling them via mouse wheel.")
|
||||
.RegisterEntry("Fixed some issue with Glamourer not searching mods by name for mod associations in some cases.")
|
||||
.RegisterEntry("Fixed the IPC methods SetMetaState and SetMetaStateName not working (Thanks Caraxi!).")
|
||||
.RegisterEntry("Added new IPC method GetDesignListExtended. (1.3.8.6)")
|
||||
.RegisterEntry(
|
||||
"Improved the naming of NPCs for identifiers by using Haselnussbombers new naming functionality (Thanks Hasel!). (1.3.8.6)")
|
||||
.RegisterEntry(
|
||||
"Added a modifier key separate from the delete modifier key that is used for less important key-checks, specifically toggling incognito mode. (1.3.8.5)")
|
||||
.RegisterEntry("Used better Penumbra IPC for some things. (1.3.8.5)")
|
||||
.RegisterEntry("Fixed an issue with advanced dyes for weapons. (1.3.8.5)")
|
||||
.RegisterEntry("Fixed an issue with NPC automation due to missing job detection. (1.3.8.1)");
|
||||
|
||||
private static void Add1_3_8_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.3.8.0")
|
||||
.RegisterImportant("Updated Glamourer for update 7.20 and Dalamud API 12.")
|
||||
.RegisterEntry(
|
||||
"This is not thoroughly tested, but I decided to push to stable instead of testing because otherwise a lot of people would just go to testing just for early access again despite having no business doing so.",
|
||||
1)
|
||||
.RegisterEntry(
|
||||
"I also do not use most of the functionality of Glamourer myself, so I am unable to even encounter most issues myself.", 1)
|
||||
.RegisterEntry("If you encounter any issues, please report them quickly on the discord.", 1)
|
||||
.RegisterEntry("Added a chat command to clear temporary settings applied by Glamourer to Penumbra.")
|
||||
.RegisterEntry("Fixed small issues with customizations not applicable to your race still applying.");
|
||||
|
||||
private static void Add1_3_7_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.3.7.0")
|
||||
.RegisterImportant(
|
||||
"The option to disable advanced customizations or advanced dyes has been removed. The functionality can no longer be disabled entirely, you can just decide not to use it, and to hide it.")
|
||||
.RegisterHighlight(
|
||||
"You can now configure which panels (like Customization, Equipment, Advanced Customization etc.) are displayed at all, and which are expanded by default. This does not disable any functionality.")
|
||||
.RegisterHighlight(
|
||||
"The Unlocks tab now shows whether items are modded in the currently selected collection in Penumbra in Overview mode and shows and can filter and sort for it in Detailed mode.")
|
||||
.RegisterEntry("Added an optional button to the Quick Design Bar to reset all temporary settings applied by Glamourer.")
|
||||
.RegisterHighlight(
|
||||
"Any existing advanced dyes will now be highlighted on the corresponding Advanced Dye buttons in the actors panel and on the corresponding equip slot name in the design panel.")
|
||||
.RegisterEntry("This also affects currently inactive advanced dyes, which can now be manually removed on the inactive materials.",
|
||||
1)
|
||||
.RegisterHighlight(
|
||||
"In the design list of an automation set, the design indices are now highlighted if a design contains advanced dyes, mod associations, or links to other designs.")
|
||||
.RegisterHighlight("Some quality of life improvements:")
|
||||
.RegisterEntry("Added some buttons for some application rule presets to the Application Rules panel.", 1)
|
||||
.RegisterEntry("Added some buttons to enable, disable or delete all advanced dyes in a design.", 1)
|
||||
.RegisterEntry("Some of those buttons are also available in multi-design selection to apply to all selected designs at once.", 1)
|
||||
.RegisterEntry(
|
||||
"A copied material color set from Penumbra should now be able to be imported into a advanced dye color set, as well as the other way around.")
|
||||
.RegisterEntry(
|
||||
"Automatically applied character updates when applying a design with mod associations and temporary settings are now skipped to prevent some issues with GPose. This should not affect anything else.")
|
||||
.RegisterEntry("Glamourer now differentiates between temporary settings applied through manual or automatic application.");
|
||||
|
||||
|
||||
private static void Add1_3_6_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.3.6.0")
|
||||
.RegisterHighlight("Added some new multi design selection functionality to change design settings of many designs at once.")
|
||||
.RegisterEntry("Also added the number of selected designs and folders to the multi design selection display.", 1)
|
||||
.RegisterEntry("Glamourer will now use temporary settings when saving mod associations, if they exist in Penumbra.")
|
||||
.RegisterEntry("Actually added the checkbox to reset all temporary settings to Automation Sets (functionality was there, just not exposed to the UI...).")
|
||||
.RegisterEntry("Adapted the behavior for identified copies of characters that have a different state than the character itself to deal with the associated Penumbra changes.")
|
||||
.RegisterEntry("Added '/glamour resetdesign' as a command, that re-applies automation but resets randomly chosen designs (Thanks Diorik).")
|
||||
.RegisterEntry(
|
||||
"Actually added the checkbox to reset all temporary settings to Automation Sets (functionality was there, just not exposed to the UI...).")
|
||||
.RegisterEntry(
|
||||
"Adapted the behavior for identified copies of characters that have a different state than the character itself to deal with the associated Penumbra changes.")
|
||||
.RegisterEntry(
|
||||
"Added '/glamour resetdesign' as a command, that re-applies automation but resets randomly chosen designs (Thanks Diorik).")
|
||||
.RegisterEntry("All existing facepaints should now be accepted in designs, including NPC facepaints.")
|
||||
.RegisterEntry("Overwriting a design with your characters current state will now discard any prior advanced dyes and only add those from the current state.")
|
||||
.RegisterEntry(
|
||||
"Overwriting a design with your characters current state will now discard any prior advanced dyes and only add those from the current state.")
|
||||
.RegisterEntry("Fixed an issue with racial mount and accessory scaling when changing zones on a changed race.")
|
||||
.RegisterEntry("Fixed issues with the detection of gear set changes in certain circumstances (Thanks Cordelia).")
|
||||
.RegisterEntry("Fixed an issue with the Force to Inherit checkbox in mod associations.")
|
||||
.RegisterEntry("Added a new IPC event that fires only when Glamourer finalizes its current changes to a character (for/from Cordelia).")
|
||||
.RegisterEntry(
|
||||
"Added a new IPC event that fires only when Glamourer finalizes its current changes to a character (for/from Cordelia).")
|
||||
.RegisterEntry("Added new IPC to set a meta flag on actors. (for/from Cordelia).");
|
||||
|
||||
private static void Add1_3_5_0(Changelog log)
|
||||
=> log.NextVersion("Version 1.3.5.0")
|
||||
.RegisterHighlight("Added the usage of the new Temporary Mod Setting functionality from Penumbra to apply mod associations. This is on by default but can be turned back to permanent changes in the settings.")
|
||||
.RegisterHighlight(
|
||||
"Added the usage of the new Temporary Mod Setting functionality from Penumbra to apply mod associations. This is on by default but can be turned back to permanent changes in the settings.")
|
||||
.RegisterEntry("Designs now have a setting to always reset all prior temporary settings made by Glamourer on application.", 1)
|
||||
.RegisterEntry("Automation Sets also have a setting to do this, independently of the designs contained in them.", 1)
|
||||
.RegisterEntry("Automation Sets also have a setting to do this, independently of the designs contained in them.", 1)
|
||||
.RegisterHighlight("More NPC customization options should now be accepted as valid for designs, regardless of clan/gender.")
|
||||
.RegisterHighlight("The 'Apply' chat command had the currently selected design and the current quick bar design added as choices.")
|
||||
.RegisterEntry("The application buttons for designs, NPCs or actors should now stick at the top of their respective panels even when scrolling down.")
|
||||
.RegisterEntry(
|
||||
"The application buttons for designs, NPCs or actors should now stick at the top of their respective panels even when scrolling down.")
|
||||
.RegisterHighlight("Randomly chosen designs should now stay across loading screens or redrawing. (1.3.4.3)")
|
||||
.RegisterEntry("In automation, Random designs now have an option to always choose another design, including during loading screens or redrawing.", 1)
|
||||
.RegisterEntry(
|
||||
"In automation, Random designs now have an option to always choose another design, including during loading screens or redrawing.",
|
||||
1)
|
||||
.RegisterEntry("Fixed an issue where disabling auto designs did not work as expected.")
|
||||
.RegisterEntry("Fixed the inversion of application flags in IPC calls.")
|
||||
.RegisterEntry("Fixed an issue with the scaling of the Advanced Dye popup with increased font sizes.")
|
||||
|
|
@ -110,15 +210,18 @@ public class GlamourerChangelog
|
|||
=> log.NextVersion("Version 1.3.2.0")
|
||||
.RegisterEntry("Fixed an issue with weapon hiding when leaving GPose or changing zones.")
|
||||
.RegisterEntry("Added support for unnamed items to be previewed from Penumbra.")
|
||||
.RegisterEntry("Item combos filters now check if the model string starts with the current filter, instead of checking if the primary ID contains the current filter.")
|
||||
.RegisterEntry(
|
||||
"Item combos filters now check if the model string starts with the current filter, instead of checking if the primary ID contains the current filter.")
|
||||
.RegisterEntry("Improved the handling of bonus items (glasses) in designs.")
|
||||
.RegisterEntry("Imported .chara files now import bonus items.")
|
||||
.RegisterEntry("Added a Debug Data rider in the Actors tab that is visible if Debug Mode is enabled and (currently) contains some IDs.")
|
||||
.RegisterEntry(
|
||||
"Added a Debug Data rider in the Actors tab that is visible if Debug Mode is enabled and (currently) contains some IDs.")
|
||||
.RegisterEntry("Fixed bonus items not reverting correctly in some cases.")
|
||||
.RegisterEntry("Fixed an issue with the RNG in cheat codes and events skipping some possible entries.")
|
||||
.RegisterEntry("Fixed the chat log context menu for glamourer Try-On.")
|
||||
.RegisterEntry("Fixed some issues with cheat code sets.")
|
||||
.RegisterEntry("Made the popped out Advanced Dye Window and Unlocks Window non-docking as that caused issues when docked to the main Glamourer window.")
|
||||
.RegisterEntry(
|
||||
"Made the popped out Advanced Dye Window and Unlocks Window non-docking as that caused issues when docked to the main Glamourer window.")
|
||||
.RegisterEntry("Refreshed NPC name associations.")
|
||||
.RegisterEntry("Removed a now useless cheat code.")
|
||||
.RegisterEntry("Added API for Bonus Items. (1.3.1.1)");
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using Glamourer.Gui.Tabs.NpcTab;
|
|||
using Glamourer.Gui.Tabs.SettingsTab;
|
||||
using Glamourer.Gui.Tabs.UnlocksTab;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Custom;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
|
|
@ -7,8 +8,7 @@ using FFXIVClientStructs.Interop;
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
using OtterGui.Text;
|
||||
|
|
@ -17,6 +17,7 @@ using Penumbra.GameData.Enums;
|
|||
using Penumbra.GameData.Files.MaterialStructs;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.String;
|
||||
using Notification = OtterGui.Classes.Notification;
|
||||
|
||||
namespace Glamourer.Gui.Materials;
|
||||
|
||||
|
|
@ -39,9 +40,6 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
|
||||
private bool ShouldBeDrawn()
|
||||
{
|
||||
if (!config.UseAdvancedDyes)
|
||||
return false;
|
||||
|
||||
if (_drawIndex is not { Valid: true })
|
||||
return false;
|
||||
|
||||
|
|
@ -51,28 +49,29 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
return true;
|
||||
}
|
||||
|
||||
public void DrawButton(EquipSlot slot)
|
||||
=> DrawButton(MaterialValueIndex.FromSlot(slot));
|
||||
public void DrawButton(EquipSlot slot, uint color)
|
||||
=> DrawButton(MaterialValueIndex.FromSlot(slot), color);
|
||||
|
||||
public void DrawButton(BonusItemFlag slot)
|
||||
=> DrawButton(MaterialValueIndex.FromSlot(slot));
|
||||
public void DrawButton(BonusItemFlag slot, uint color)
|
||||
=> DrawButton(MaterialValueIndex.FromSlot(slot), color);
|
||||
|
||||
private void DrawButton(MaterialValueIndex index)
|
||||
private void DrawButton(MaterialValueIndex index, uint color)
|
||||
{
|
||||
if (!config.UseAdvancedDyes)
|
||||
if (config.HideDesignPanel.HasFlag(DesignPanelFlag.AdvancedDyes))
|
||||
return;
|
||||
|
||||
ImGui.SameLine();
|
||||
using var id = ImRaii.PushId(index.SlotIndex | ((int)index.DrawObject << 8));
|
||||
using var id = ImUtf8.PushId(index.SlotIndex | ((int)index.DrawObject << 8));
|
||||
var isOpen = index == _drawIndex;
|
||||
|
||||
using (ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), isOpen)
|
||||
.Push(ImGuiCol.Text, ColorId.HeaderButtons.Value(), isOpen)
|
||||
.Push(ImGuiCol.Border, ColorId.HeaderButtons.Value(), isOpen))
|
||||
var (textColor, buttonColor) = isOpen
|
||||
? (ColorId.HeaderButtons.Value(), ImGui.GetColorU32(ImGuiCol.ButtonActive))
|
||||
: (color, 0u);
|
||||
|
||||
using (ImRaii.PushColor(ImGuiCol.Border, textColor, isOpen))
|
||||
{
|
||||
using var frame = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, isOpen);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Palette.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
|
||||
string.Empty, false, true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Palette, ""u8, default, false, textColor, buttonColor))
|
||||
{
|
||||
_forceFocus = true;
|
||||
_selectedMaterial = byte.MaxValue;
|
||||
|
|
@ -80,7 +79,7 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
}
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip("Open advanced dyes for this slot.");
|
||||
ImUtf8.HoverTooltip("Open advanced dyes for this slot."u8);
|
||||
}
|
||||
|
||||
private (string Path, string GamePath) ResourceName(MaterialValueIndex index)
|
||||
|
|
@ -92,20 +91,21 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
var modelHandle = model == null ? null : model->ModelResourceHandle;
|
||||
var path = materialHandle == null
|
||||
? string.Empty
|
||||
: ByteString.FromSpanUnsafe(materialHandle->ResourceHandle.FileName.AsSpan(), true).ToString();
|
||||
: ByteString.FromSpanUnsafe(materialHandle->FileName.AsSpan(), true).ToString();
|
||||
var gamePath = modelHandle == null
|
||||
? string.Empty
|
||||
: modelHandle->GetMaterialFileNameBySlotAsString(index.MaterialIndex);
|
||||
: modelHandle->GetMaterialFileNameBySlot(index.MaterialIndex).ToString();
|
||||
return (path, gamePath);
|
||||
}
|
||||
|
||||
private void DrawTabBar(ReadOnlySpan<Pointer<Texture>> textures, ReadOnlySpan<Pointer<Material>> materials, ref bool firstAvailable)
|
||||
{
|
||||
using var bar = ImRaii.TabBar("tabs");
|
||||
using var bar = ImUtf8.TabBar("tabs"u8);
|
||||
if (!bar)
|
||||
return;
|
||||
|
||||
var table = new ColorTable.Table();
|
||||
var table = new ColorTable.Table();
|
||||
var highLightColor = ColorId.AdvancedDyeActive.Value();
|
||||
for (byte i = 0; i < MaterialService.MaterialsPerModel; ++i)
|
||||
{
|
||||
var index = _drawIndex!.Value with { MaterialIndex = i };
|
||||
|
|
@ -124,17 +124,30 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
if (available)
|
||||
firstAvailable = false;
|
||||
|
||||
using var tab = _label.TabItem(i, select);
|
||||
var hasAdvancedDyes = _state.Materials.CheckExistenceMaterial(index);
|
||||
using var c = ImRaii.PushColor(ImGuiCol.Text, highLightColor, hasAdvancedDyes);
|
||||
using var tab = _label.TabItem(i, select);
|
||||
c.Pop();
|
||||
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
{
|
||||
using var enabled = ImRaii.Enabled();
|
||||
var (path, gamePath) = ResourceName(index);
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
|
||||
if (gamePath.Length == 0 || path.Length == 0)
|
||||
ImGui.SetTooltip("This material does not exist.");
|
||||
ImUtf8.Text("This material does not exist."u8);
|
||||
else if (!available)
|
||||
ImGui.SetTooltip($"This material does not have an associated color set.\n\n{gamePath}\n{path}");
|
||||
ImUtf8.Text($"This material does not have an associated color set.\n\n{gamePath}\n{path}");
|
||||
else
|
||||
ImGui.SetTooltip($"{gamePath}\n{path}");
|
||||
ImUtf8.Text($"{gamePath}\n{path}");
|
||||
|
||||
if (hasAdvancedDyes && !available)
|
||||
{
|
||||
ImUtf8.Text("\nRight-Click to remove ineffective advanced dyes."u8);
|
||||
if (ImGui.IsMouseClicked(ImGuiMouseButton.Right))
|
||||
for (byte row = 0; row < ColorTable.NumRows; ++row)
|
||||
stateManager.ResetMaterialValue(_state, index with { RowIndex = row }, ApplySettings.Game);
|
||||
}
|
||||
}
|
||||
|
||||
if ((tab.Success || select is ImGuiTabItemFlags.SetSelected) && available)
|
||||
|
|
@ -173,7 +186,7 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
DrawTabBar(textures, materials, ref firstAvailable);
|
||||
|
||||
if (firstAvailable)
|
||||
ImGui.TextUnformatted("No Editable Materials available.");
|
||||
ImUtf8.Text("No Editable Materials available."u8);
|
||||
}
|
||||
|
||||
private void DrawWindow(ReadOnlySpan<Pointer<Texture>> textures, ReadOnlySpan<Pointer<Material>> materials)
|
||||
|
|
@ -197,7 +210,7 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
var width = 7 * ImGui.GetFrameHeight() // Buttons
|
||||
+ 3 * ImGui.GetStyle().ItemSpacing.X // around text
|
||||
+ 7 * ImGui.GetStyle().ItemInnerSpacing.X
|
||||
+ 200 * ImGuiHelpers.GlobalScale // Drags
|
||||
+ 200 * ImGuiHelpers.GlobalScale // Drags
|
||||
+ 7 * UiBuilder.MonoFont.GetCharAdvance(' ') * ImGuiHelpers.GlobalScale // Row
|
||||
+ 2 * ImGui.GetStyle().WindowPadding.X;
|
||||
var height = 19 * ImGui.GetFrameHeightWithSpacing() + ImGui.GetStyle().WindowPadding.Y + 3 * ImGui.GetStyle().ItemSpacing.Y;
|
||||
|
|
@ -251,32 +264,89 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
DrawAllRow(materialIndex, table);
|
||||
}
|
||||
|
||||
private static void CopyToClipboard(in ColorTable.Table table)
|
||||
{
|
||||
try
|
||||
{
|
||||
fixed (ColorTable.Table* ptr = &table)
|
||||
{
|
||||
var data = new ReadOnlySpan<byte>(ptr, sizeof(ColorTable.Table));
|
||||
var base64 = Convert.ToBase64String(data);
|
||||
ImGui.SetClipboardText(base64);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Log.Error($"Could not copy color table to clipboard:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ImportFromClipboard(out ColorTable.Table table)
|
||||
{
|
||||
try
|
||||
{
|
||||
var base64 = ImGui.GetClipboardText();
|
||||
if (base64.Length > 0)
|
||||
{
|
||||
var data = Convert.FromBase64String(base64);
|
||||
if (sizeof(ColorTable.Table) <= data.Length)
|
||||
{
|
||||
table = new ColorTable.Table();
|
||||
fixed (ColorTable.Table* tPtr = &table)
|
||||
{
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
new ReadOnlySpan<byte>(ptr, sizeof(ColorTable.Table)).CopyTo(new Span<byte>(tPtr, sizeof(ColorTable.Table)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ColorRowClipboard.IsTableSet)
|
||||
{
|
||||
table = ColorRowClipboard.Table;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.AddMessage(new Notification(ex, "Could not paste color table from clipboard.",
|
||||
"Could not paste color table from clipboard.", NotificationType.Error));
|
||||
}
|
||||
|
||||
table = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void DrawAllRow(MaterialValueIndex materialIndex, in ColorTable.Table table)
|
||||
{
|
||||
using var id = ImRaii.PushId(100);
|
||||
var buttonSize = new Vector2(ImGui.GetFrameHeight());
|
||||
ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Crosshairs.ToIconString(), buttonSize, "Highlight all affected colors on the character.",
|
||||
false, true);
|
||||
ImUtf8.IconButton(FontAwesomeIcon.Crosshairs, "Highlight all affected colors on the character."u8, buttonSize);
|
||||
if (ImGui.IsItemHovered())
|
||||
preview.OnHover(materialIndex with { RowIndex = byte.MaxValue }, _actor.Index, table);
|
||||
ImGui.SameLine();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
using (ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
ImGui.TextUnformatted("All Color Row Pairs (1-16)");
|
||||
ImUtf8.Text("All Color Row Pairs (1-16)"u8);
|
||||
}
|
||||
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing.X;
|
||||
ImGui.SameLine(ImGui.GetWindowSize().X - 3 * buttonSize.X - 2 * spacing - ImGui.GetStyle().WindowPadding.X);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), buttonSize, "Export this table to your clipboard.", false,
|
||||
true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Clipboard, "Export this table to your clipboard."u8, buttonSize))
|
||||
{
|
||||
ColorRowClipboard.Table = table;
|
||||
CopyToClipboard(table);
|
||||
}
|
||||
|
||||
ImGui.SameLine(0, spacing);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), buttonSize,
|
||||
"Import an exported table from your clipboard onto this table.", !ColorRowClipboard.IsTableSet, true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Paste, "Import an exported table from your clipboard onto this table."u8, buttonSize)
|
||||
&& ImportFromClipboard(out var newTable))
|
||||
for (var idx = 0; idx < ColorTable.NumRows; ++idx)
|
||||
{
|
||||
var row = ColorRowClipboard.Table[idx];
|
||||
var row = newTable[idx];
|
||||
var internalRow = new ColorRow(row);
|
||||
var slot = materialIndex.ToEquipSlot();
|
||||
var weapon = slot is EquipSlot.MainHand or EquipSlot.OffHand
|
||||
|
|
@ -287,15 +357,14 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
}
|
||||
|
||||
ImGui.SameLine(0, spacing);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UndoAlt.ToIconString(), buttonSize, "Reset this table to game state.", !_anyChanged,
|
||||
true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.UndoAlt, "Reset this table to game state."u8, buttonSize, !_anyChanged))
|
||||
for (byte i = 0; i < ColorTable.NumRows; ++i)
|
||||
stateManager.ResetMaterialValue(_state, materialIndex with { RowIndex = i }, ApplySettings.Game);
|
||||
}
|
||||
|
||||
private void DrawRow(ref ColorTableRow row, MaterialValueIndex index, in ColorTable.Table table)
|
||||
{
|
||||
using var id = ImRaii.PushId(index.RowIndex);
|
||||
using var id = ImUtf8.PushId(index.RowIndex);
|
||||
var changed = _state.Materials.TryGetValue(index, out var value);
|
||||
if (!changed)
|
||||
{
|
||||
|
|
@ -305,8 +374,9 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
{
|
||||
EquipSlot.MainHand => _state.ModelData.Weapon(EquipSlot.MainHand),
|
||||
EquipSlot.OffHand => _state.ModelData.Weapon(EquipSlot.OffHand),
|
||||
EquipSlot.Unknown => _state.ModelData.BonusItem((index.SlotIndex - 16u).ToBonusSlot()).Armor().ToWeapon(0), // TODO: Handle better
|
||||
_ => _state.ModelData.Armor(slot).ToWeapon(0),
|
||||
EquipSlot.Unknown =>
|
||||
_state.ModelData.BonusItem((index.SlotIndex - 16u).ToBonusSlot()).Armor().ToWeapon(0), // TODO: Handle better
|
||||
_ => _state.ModelData.Armor(slot).ToWeapon(0),
|
||||
};
|
||||
value = new MaterialValueState(internalRow, internalRow, weapon, StateSource.Manual);
|
||||
}
|
||||
|
|
@ -317,8 +387,7 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
}
|
||||
|
||||
var buttonSize = new Vector2(ImGui.GetFrameHeight());
|
||||
ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Crosshairs.ToIconString(), buttonSize, "Highlight the affected colors on the character.",
|
||||
false, true);
|
||||
ImUtf8.IconButton(FontAwesomeIcon.Crosshairs, "Highlight the affected colors on the character."u8, buttonSize);
|
||||
if (ImGui.IsItemHovered())
|
||||
preview.OnHover(index, _actor.Index, table);
|
||||
|
||||
|
|
@ -328,28 +397,28 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
{
|
||||
var rowIndex = index.RowIndex / 2 + 1;
|
||||
var rowSuffix = (index.RowIndex & 1) == 0 ? 'A' : 'B';
|
||||
ImGui.TextUnformatted($"Row {rowIndex,2}{rowSuffix}");
|
||||
ImUtf8.Text($"Row {rowIndex,2}{rowSuffix}");
|
||||
}
|
||||
|
||||
ImGui.SameLine(0, ImGui.GetStyle().ItemSpacing.X * 2);
|
||||
var applied = ImGuiUtil.ColorPicker("##diffuse", "Change the diffuse value for this row.", value.Model.Diffuse,
|
||||
v => value.Model.Diffuse = v, "D");
|
||||
var applied = ImUtf8.ColorPicker("##diffuse"u8, "Change the diffuse value for this row."u8, value.Model.Diffuse,
|
||||
v => value.Model.Diffuse = v, "D"u8);
|
||||
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing;
|
||||
ImGui.SameLine(0, spacing.X);
|
||||
applied |= ImGuiUtil.ColorPicker("##specular", "Change the specular value for this row.", value.Model.Specular,
|
||||
v => value.Model.Specular = v, "S");
|
||||
applied |= ImUtf8.ColorPicker("##specular"u8, "Change the specular value for this row."u8, value.Model.Specular,
|
||||
v => value.Model.Specular = v, "S"u8);
|
||||
|
||||
ImGui.SameLine(0, spacing.X);
|
||||
applied |= ImGuiUtil.ColorPicker("##emissive", "Change the emissive value for this row.", value.Model.Emissive,
|
||||
v => value.Model.Emissive = v, "E");
|
||||
applied |= ImUtf8.ColorPicker("##emissive"u8, "Change the emissive value for this row."u8, value.Model.Emissive,
|
||||
v => value.Model.Emissive = v, "E"u8);
|
||||
|
||||
ImGui.SameLine(0, spacing.X);
|
||||
if (_mode is not ColorRow.Mode.Dawntrail)
|
||||
{
|
||||
ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale);
|
||||
applied |= DragGloss(ref value.Model.GlossStrength);
|
||||
ImGuiUtil.HoverTooltip("Change the gloss strength for this row.");
|
||||
ImUtf8.HoverTooltip("Change the gloss strength for this row."u8);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -361,7 +430,7 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
{
|
||||
ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale);
|
||||
applied |= DragSpecularStrength(ref value.Model.SpecularStrength);
|
||||
ImGuiUtil.HoverTooltip("Change the specular strength for this row.");
|
||||
ImUtf8.HoverTooltip("Change the specular strength for this row."u8);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -369,19 +438,18 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
}
|
||||
|
||||
ImGui.SameLine(0, spacing.X);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), buttonSize, "Export this row to your clipboard.", false,
|
||||
true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Clipboard, "Export this row to your clipboard."u8, buttonSize))
|
||||
ColorRowClipboard.Row = value.Model;
|
||||
ImGui.SameLine(0, spacing.X);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Paste.ToIconString(), buttonSize,
|
||||
"Import an exported row from your clipboard onto this row.", !ColorRowClipboard.IsSet, true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Paste, "Import an exported row from your clipboard onto this row."u8, buttonSize,
|
||||
!ColorRowClipboard.IsSet))
|
||||
{
|
||||
value.Model = ColorRowClipboard.Row;
|
||||
applied = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine(0, spacing.X);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UndoAlt.ToIconString(), buttonSize, "Reset this row to game state.", !changed, true))
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.UndoAlt, "Reset this row to game state."u8, buttonSize, !changed))
|
||||
stateManager.ResetMaterialValue(_state, index, ApplySettings.Game);
|
||||
|
||||
if (applied)
|
||||
|
|
@ -392,7 +460,8 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
{
|
||||
var tmp = value;
|
||||
var minValue = ImGui.GetIO().KeyCtrl ? 0f : (float)Half.Epsilon;
|
||||
if (!ImUtf8.DragScalar("##Gloss"u8, ref tmp, "%.1f G"u8, 0.001f, minValue, Math.Max(0.01f, 0.005f * value), ImGuiSliderFlags.AlwaysClamp))
|
||||
if (!ImUtf8.DragScalar("##Gloss"u8, ref tmp, "%.1f G"u8, 0.001f, minValue, Math.Max(0.01f, 0.005f * value),
|
||||
ImGuiSliderFlags.AlwaysClamp))
|
||||
return false;
|
||||
|
||||
var tmp2 = Math.Clamp(tmp, minValue, (float)Half.MaxValue);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Dalamud.Interface.Utility;
|
|||
using Dalamud.Interface.Utility.Raii;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Services;
|
||||
using OtterGui.Text;
|
||||
|
|
@ -18,7 +18,6 @@ public class MaterialDrawer(DesignManager _designManager, Configuration _config)
|
|||
public const float GlossWidth = 100;
|
||||
public const float SpecularStrengthWidth = 125;
|
||||
|
||||
private EquipSlot _newSlot = EquipSlot.Head;
|
||||
private int _newMaterialIdx;
|
||||
private int _newRowIdx;
|
||||
private MaterialValueIndex _newKey = MaterialValueIndex.FromSlot(EquipSlot.Head);
|
||||
|
|
@ -35,6 +34,10 @@ public class MaterialDrawer(DesignManager _designManager, Configuration _config)
|
|||
+ (GlossWidth + SpecularStrengthWidth) * ImGuiHelpers.GlobalScale
|
||||
+ 6 * _spacing
|
||||
+ ImUtf8.CalcTextSize("Revert"u8).X;
|
||||
DrawMultiButtons(design);
|
||||
ImUtf8.Dummy(0);
|
||||
ImGui.Separator();
|
||||
ImUtf8.Dummy(0);
|
||||
if (available > 1.95 * colorWidth)
|
||||
DrawSingleRow(design);
|
||||
else
|
||||
|
|
@ -42,9 +45,42 @@ public class MaterialDrawer(DesignManager _designManager, Configuration _config)
|
|||
DrawNew(design);
|
||||
}
|
||||
|
||||
private void DrawMultiButtons(Design design)
|
||||
{
|
||||
var any = design.Materials.Count > 0;
|
||||
var disabled = !_config.DeleteDesignModifier.IsActive();
|
||||
var size = new Vector2(200 * ImUtf8.GlobalScale, 0);
|
||||
if (ImUtf8.ButtonEx("Enable All Advanced Dyes"u8,
|
||||
any
|
||||
? "Enable the application of all contained advanced dyes without deleting them."u8
|
||||
: "This design does not contain any advanced dyes."u8, size,
|
||||
!any || disabled))
|
||||
_designManager.ChangeApplyMulti(design, null, null, null, null, null, null, true, null);
|
||||
;
|
||||
if (disabled && any)
|
||||
ImUtf8.HoverTooltip($"Hold {_config.DeleteDesignModifier} while clicking to enable.");
|
||||
ImGui.SameLine();
|
||||
if (ImUtf8.ButtonEx("Disable All Advanced Dyes"u8,
|
||||
any
|
||||
? "Disable the application of all contained advanced dyes without deleting them."u8
|
||||
: "This design does not contain any advanced dyes."u8, size,
|
||||
!any || disabled))
|
||||
_designManager.ChangeApplyMulti(design, null, null, null, null, null, null, false, null);
|
||||
if (disabled && any)
|
||||
ImUtf8.HoverTooltip($"Hold {_config.DeleteDesignModifier} while clicking to disable.");
|
||||
|
||||
if (ImUtf8.ButtonEx("Delete All Advanced Dyes"u8, any ? ""u8 : "This design does not contain any advanced dyes."u8, size,
|
||||
!any || disabled))
|
||||
while (design.Materials.Count > 0)
|
||||
_designManager.ChangeMaterialValue(design, MaterialValueIndex.FromKey(design.Materials[0].Item1), null);
|
||||
|
||||
if (disabled && any)
|
||||
ImUtf8.HoverTooltip($"Hold {_config.DeleteDesignModifier} while clicking to delete.");
|
||||
}
|
||||
|
||||
private void DrawName(MaterialValueIndex index)
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f));
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.05f, 0.5f));
|
||||
ImUtf8.TextFramed(index.ToString(), 0, new Vector2((GlossWidth + SpecularStrengthWidth) * ImGuiHelpers.GlobalScale + _spacing, 0),
|
||||
borderColor: ImGui.GetColorU32(ImGuiCol.Text));
|
||||
}
|
||||
|
|
@ -139,16 +175,44 @@ public class MaterialDrawer(DesignManager _designManager, Configuration _config)
|
|||
"If this is checked, Glamourer will try to revert the advanced dye row to its game state instead of applying a specific row."u8);
|
||||
}
|
||||
|
||||
public sealed class MaterialSlotCombo;
|
||||
public sealed class MaterialSlotCombo;
|
||||
|
||||
private void DrawSlotCombo()
|
||||
{
|
||||
var width = ImUtf8.CalcTextSize(EquipSlot.OffHand.ToName()).X + ImGui.GetFrameHeightWithSpacing();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
using var combo = ImUtf8.Combo("##slot"u8, _newKey.SlotName());
|
||||
if (combo)
|
||||
{
|
||||
var currentSlot = _newKey.ToEquipSlot();
|
||||
foreach (var tmpSlot in EquipSlotExtensions.FullSlots)
|
||||
{
|
||||
if (ImUtf8.Selectable(tmpSlot.ToName(), tmpSlot == currentSlot) && currentSlot != tmpSlot)
|
||||
_newKey = MaterialValueIndex.FromSlot(tmpSlot) with
|
||||
{
|
||||
MaterialIndex = (byte)_newMaterialIdx,
|
||||
RowIndex = (byte)_newRowIdx,
|
||||
};
|
||||
}
|
||||
|
||||
var currentBonus = _newKey.ToBonusSlot();
|
||||
foreach (var bonusSlot in BonusExtensions.AllFlags)
|
||||
{
|
||||
if (ImUtf8.Selectable(bonusSlot.ToName(), bonusSlot == currentBonus) && bonusSlot != currentBonus)
|
||||
_newKey = MaterialValueIndex.FromSlot(bonusSlot) with
|
||||
{
|
||||
MaterialIndex = (byte)_newMaterialIdx,
|
||||
RowIndex = (byte)_newRowIdx,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ImUtf8.HoverTooltip("Choose a slot for an advanced dye row."u8);
|
||||
}
|
||||
|
||||
public void DrawNew(Design design)
|
||||
{
|
||||
if (EquipSlotCombo.Draw("##slot", "Choose a slot for an advanced dye row.", ref _newSlot))
|
||||
_newKey = MaterialValueIndex.FromSlot(_newSlot) with
|
||||
{
|
||||
MaterialIndex = (byte)_newMaterialIdx,
|
||||
RowIndex = (byte)_newRowIdx,
|
||||
};
|
||||
DrawSlotCombo();
|
||||
ImUtf8.SameLineInner();
|
||||
DrawMaterialIdxDrag();
|
||||
ImUtf8.SameLineInner();
|
||||
|
|
@ -165,22 +229,27 @@ public class MaterialDrawer(DesignManager _designManager, Configuration _config)
|
|||
{
|
||||
ImGui.SetNextItemWidth(ImUtf8.CalcTextSize("Material AA"u8).X);
|
||||
var format = $"Material {(char)('A' + _newMaterialIdx)}";
|
||||
if (ImUtf8.DragScalar("##Material"u8, ref _newMaterialIdx, format, 0, MaterialService.MaterialsPerModel - 1, 0.01f))
|
||||
if (ImUtf8.DragScalar("##Material"u8, ref _newMaterialIdx, format, 0, MaterialService.MaterialsPerModel - 1, 0.01f,
|
||||
ImGuiSliderFlags.NoInput))
|
||||
{
|
||||
_newMaterialIdx = Math.Clamp(_newMaterialIdx, 0, MaterialService.MaterialsPerModel - 1);
|
||||
_newKey = _newKey with { MaterialIndex = (byte)_newMaterialIdx };
|
||||
}
|
||||
|
||||
ImUtf8.HoverTooltip("Drag this to the left or right to change its value."u8);
|
||||
}
|
||||
|
||||
private void DrawRowIdxDrag()
|
||||
{
|
||||
ImGui.SetNextItemWidth(ImUtf8.CalcTextSize("Row 0000"u8).X);
|
||||
var format = $"Row {_newRowIdx / 2 + 1}{(char)(_newRowIdx % 2 + 'A')}";
|
||||
if (ImUtf8.DragScalar("##Row"u8, ref _newRowIdx, format, 0, ColorTable.NumRows - 1, 0.01f))
|
||||
if (ImUtf8.DragScalar("##Row"u8, ref _newRowIdx, format, 0, ColorTable.NumRows - 1, 0.01f, ImGuiSliderFlags.NoInput))
|
||||
{
|
||||
_newRowIdx = Math.Clamp(_newRowIdx, 0, ColorTable.NumRows - 1);
|
||||
_newKey = _newKey with { RowIndex = (byte)_newRowIdx };
|
||||
}
|
||||
|
||||
ImUtf8.HoverTooltip("Drag this to the left or right to change its value."u8);
|
||||
}
|
||||
|
||||
private void DrawRow(Design design, MaterialValueIndex index, in ColorRow row, bool disabled)
|
||||
|
|
|
|||
|
|
@ -1,39 +1,40 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
public sealed class PenumbraChangedItemTooltip : IDisposable
|
||||
{
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly ItemManager _items;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly CustomizeService _customize;
|
||||
private readonly GPoseService _gpose;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly ItemManager _items;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly CustomizeService _customize;
|
||||
private readonly GPoseService _gpose;
|
||||
|
||||
private readonly EquipItem[] _lastItems = new EquipItem[EquipFlagExtensions.NumEquipFlags / 2];
|
||||
private readonly EquipItem[] _lastItems = new EquipItem[EquipFlagExtensions.NumEquipFlags / 2 + BonusExtensions.AllFlags.Count];
|
||||
|
||||
public IEnumerable<KeyValuePair<EquipSlot, EquipItem>> LastItems
|
||||
=> EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand).Zip(_lastItems)
|
||||
.Select(p => new KeyValuePair<EquipSlot, EquipItem>(p.First, p.Second));
|
||||
public IEnumerable<KeyValuePair<object, EquipItem>> LastItems
|
||||
=> EquipSlotExtensions.EqdpSlots.Cast<object>().Append(EquipSlot.MainHand).Append(EquipSlot.OffHand)
|
||||
.Concat(BonusExtensions.AllFlags.Cast<object>()).Zip(_lastItems)
|
||||
.Select(p => new KeyValuePair<object, EquipItem>(p.First, p.Second));
|
||||
|
||||
public ChangedItemType LastType { get; private set; } = ChangedItemType.None;
|
||||
public uint LastId { get; private set; } = 0;
|
||||
public uint LastId { get; private set; }
|
||||
public DateTime LastTooltip { get; private set; } = DateTime.MinValue;
|
||||
public DateTime LastClick { get; private set; } = DateTime.MinValue;
|
||||
|
||||
public PenumbraChangedItemTooltip(PenumbraService penumbra, StateManager stateManager, ItemManager items, ObjectManager objects,
|
||||
public PenumbraChangedItemTooltip(PenumbraService penumbra, StateManager stateManager, ItemManager items, ActorObjectManager objects,
|
||||
CustomizeService customize, GPoseService gpose)
|
||||
{
|
||||
_penumbra = penumbra;
|
||||
|
|
@ -72,6 +73,21 @@ public sealed class PenumbraChangedItemTooltip : IDisposable
|
|||
if (!Player())
|
||||
return;
|
||||
|
||||
var bonusSlot = item.Type.ToBonus();
|
||||
if (bonusSlot is not BonusItemFlag.Unknown)
|
||||
{
|
||||
// + 2 due to weapons.
|
||||
var glasses = _lastItems[bonusSlot.ToSlot() + 2];
|
||||
using (_ = !openTooltip ? null : ImRaii.Tooltip())
|
||||
{
|
||||
ImGui.TextUnformatted($"{prefix}Right-Click to apply to current actor.");
|
||||
if (glasses.Valid)
|
||||
ImGui.TextUnformatted($"{prefix}Control + Right-Click to re-apply {glasses.Name} to current actor.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = item.Type.ToSlot();
|
||||
var last = _lastItems[slot.ToIndex()];
|
||||
switch (slot)
|
||||
|
|
@ -109,6 +125,27 @@ public sealed class PenumbraChangedItemTooltip : IDisposable
|
|||
|
||||
public void ApplyItem(ActorState state, EquipItem item)
|
||||
{
|
||||
var bonusSlot = item.Type.ToBonus();
|
||||
if (bonusSlot is not BonusItemFlag.Unknown)
|
||||
{
|
||||
// + 2 due to weapons.
|
||||
var glasses = _lastItems[bonusSlot.ToSlot() + 2];
|
||||
if (ImGui.GetIO().KeyCtrl && glasses.Valid)
|
||||
{
|
||||
Glamourer.Log.Debug($"Re-Applying {glasses.Name} to {bonusSlot.ToName()}.");
|
||||
SetLastItem(bonusSlot, default, state);
|
||||
_stateManager.ChangeBonusItem(state, bonusSlot, glasses, ApplySettings.Manual);
|
||||
}
|
||||
else
|
||||
{
|
||||
Glamourer.Log.Debug($"Applying {item.Name} to {bonusSlot.ToName()}.");
|
||||
SetLastItem(bonusSlot, item, state);
|
||||
_stateManager.ChangeBonusItem(state, bonusSlot, item, ApplySettings.Manual);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = item.Type.ToSlot();
|
||||
var last = _lastItems[slot.ToIndex()];
|
||||
switch (slot)
|
||||
|
|
@ -265,7 +302,22 @@ public sealed class PenumbraChangedItemTooltip : IDisposable
|
|||
{
|
||||
var oldItem = state.ModelData.Item(slot);
|
||||
if (oldItem.Id != item.Id)
|
||||
_lastItems[slot.ToIndex()] = oldItem;
|
||||
last = oldItem;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLastItem(BonusItemFlag slot, EquipItem item, ActorState state)
|
||||
{
|
||||
ref var last = ref _lastItems[slot.ToSlot() + 2];
|
||||
if (!item.Valid)
|
||||
{
|
||||
last = default;
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldItem = state.ModelData.BonusItem(slot);
|
||||
if (oldItem.Id != item.Id)
|
||||
last = oldItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ using Glamourer.Gui.Customization;
|
|||
using Glamourer.Gui.Equipment;
|
||||
using Glamourer.Gui.Materials;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
|
|
@ -22,7 +21,6 @@ using Penumbra.GameData.Actors;
|
|||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
|
|
@ -35,7 +33,7 @@ public class ActorPanel
|
|||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly Configuration _config;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly DesignManager _designManager;
|
||||
private readonly ImportService _importService;
|
||||
private readonly ICondition _conditions;
|
||||
|
|
@ -53,13 +51,13 @@ public class ActorPanel
|
|||
AutoDesignApplier autoDesignApplier,
|
||||
Configuration config,
|
||||
DesignConverter converter,
|
||||
ObjectManager objects,
|
||||
ActorObjectManager objects,
|
||||
DesignManager designManager,
|
||||
ImportService importService,
|
||||
ICondition conditions,
|
||||
DictModelChara modelChara,
|
||||
CustomizeParameterDrawer parameterDrawer,
|
||||
AdvancedDyePopup advancedDyes,
|
||||
AdvancedDyePopup advancedDyes,
|
||||
EditorHistory editorHistory)
|
||||
{
|
||||
_selector = selector;
|
||||
|
|
@ -87,7 +85,7 @@ public class ActorPanel
|
|||
_rightButtons =
|
||||
[
|
||||
new LockedButton(this),
|
||||
new HeaderDrawer.IncognitoButton(_config.Ephemeral),
|
||||
new HeaderDrawer.IncognitoButton(_config),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +104,7 @@ public class ActorPanel
|
|||
{
|
||||
using var group = ImRaii.Group();
|
||||
(_identifier, _data) = _selector.Selection;
|
||||
_lockedRedraw = _identifier.Type is IdentifierType.Special
|
||||
_lockedRedraw = _identifier.Type is IdentifierType.Special || _objects.IsInLobby
|
||||
|| _conditions[ConditionFlag.OccupiedInCutSceneEvent];
|
||||
(_actorName, _actor) = GetHeaderName();
|
||||
DrawHeader();
|
||||
|
|
@ -157,6 +155,7 @@ public class ActorPanel
|
|||
using var table = ImUtf8.Table("##Panel", 1, ImGuiTableFlags.BordersOuter | ImGuiTableFlags.ScrollY, ImGui.GetContentRegionAvail());
|
||||
if (!table || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state))
|
||||
return;
|
||||
|
||||
ImGui.TableSetupScrollFreeze(0, 1);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Dummy(Vector2.Zero);
|
||||
|
|
@ -191,10 +190,14 @@ public class ActorPanel
|
|||
|
||||
private void DrawCustomizationsHeader()
|
||||
{
|
||||
if (_config.HideDesignPanel.HasFlag(DesignPanelFlag.Customization))
|
||||
return;
|
||||
|
||||
var header = _state!.ModelData.ModelId == 0
|
||||
? "Customization"
|
||||
: $"Customization (Model Id #{_state.ModelData.ModelId})###Customization";
|
||||
using var h = ImUtf8.CollapsingHeaderId(header);
|
||||
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
|
||||
using var h = ImUtf8.CollapsingHeaderId(header, expand ? ImGuiTreeNodeFlags.DefaultOpen : ImGuiTreeNodeFlags.None);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
|
|
@ -207,7 +210,7 @@ public class ActorPanel
|
|||
|
||||
private void DrawEquipmentHeader()
|
||||
{
|
||||
using var h = ImUtf8.CollapsingHeaderId("Equipment"u8);
|
||||
using var h = DesignPanelFlag.Equipment.Header(_config);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
|
|
@ -235,14 +238,12 @@ public class ActorPanel
|
|||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
DrawEquipmentMetaToggles();
|
||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
_equipmentDrawer.DrawDragDropTooltip();
|
||||
}
|
||||
|
||||
private void DrawParameterHeader()
|
||||
{
|
||||
if (!_config.UseAdvancedParameters)
|
||||
return;
|
||||
|
||||
using var h = ImUtf8.CollapsingHeaderId("Advanced Customizations"u8);
|
||||
using var h = DesignPanelFlag.AdvancedCustomizations.Header(_config);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
|
|
@ -254,7 +255,7 @@ public class ActorPanel
|
|||
if (!_config.DebugMode)
|
||||
return;
|
||||
|
||||
using var h = ImUtf8.CollapsingHeaderId("Debug Data"u8);
|
||||
using var h = DesignPanelFlag.DebugData.Header(_config);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
|
|
@ -304,6 +305,12 @@ public class ActorPanel
|
|||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.WeaponState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.OffHand, _stateManager, _state!));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.EarState, _stateManager, _state!));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMonsterPanel()
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
using System.Security.AccessControl;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public class ActorSelector(ObjectManager objects, ActorManager actors, EphemeralConfig config)
|
||||
public class ActorSelector(ActorObjectManager objects, ActorManager actors, EphemeralConfig config)
|
||||
{
|
||||
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
|
||||
|
||||
|
|
@ -89,11 +87,11 @@ public class ActorSelector(ObjectManager objects, ActorManager actors, Ephemeral
|
|||
if (!child)
|
||||
return;
|
||||
|
||||
objects.Update();
|
||||
_world = new WorldId(objects.Player.Valid ? objects.Player.HomeWorld : (ushort)0);
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight());
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(objects.Identifiers, skips, CheckFilter, DrawSelectable);
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight());
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(objects.Where(p => p.Value.Objects.Any(a => a.Model)), skips, CheckFilter,
|
||||
DrawSelectable);
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Widgets;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Widgets;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Custom;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using OtterGui.Custom;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Gui;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Glamourer.Automation;
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Special;
|
||||
using Glamourer.Events;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
|
|
@ -278,7 +278,7 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
private void LookupTooltip(IEnumerable<Design> designs)
|
||||
{
|
||||
using var _ = ImRaii.Tooltip();
|
||||
var tt = string.Join('\n', designs.Select(d => _designFileSystem.FindLeaf(d, out var l) ? l.FullName() : d.Name.Text).OrderBy(t => t));
|
||||
var tt = string.Join('\n', designs.Select(d => _designFileSystem.TryGetValue(d, out var l) ? l.FullName() : d.Name.Text).OrderBy(t => t));
|
||||
ImGui.TextUnformatted(tt.Length == 0
|
||||
? "Matches no currently existing designs."
|
||||
: "Matches the following designs:");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ using Glamourer.Designs.Special;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
|
|
@ -30,10 +31,10 @@ public class SetPanel(
|
|||
Configuration _config,
|
||||
RandomRestrictionDrawer _randomDrawer)
|
||||
{
|
||||
private readonly JobGroupCombo _jobGroupCombo = new(_manager, _jobs, Glamourer.Log);
|
||||
private readonly HeaderDrawer.Button[] _rightButtons = [new HeaderDrawer.IncognitoButton(_config.Ephemeral)];
|
||||
private string? _tempName;
|
||||
private int _dragIndex = -1;
|
||||
private readonly JobGroupCombo _jobGroupCombo = new(_manager, _jobs, Glamourer.Log);
|
||||
private readonly HeaderDrawer.Button[] _rightButtons = [new HeaderDrawer.IncognitoButton(_config)];
|
||||
private string? _tempName;
|
||||
private int _dragIndex = -1;
|
||||
|
||||
private Action? _endAction;
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ public class SetPanel(
|
|||
|
||||
private void DrawPanel()
|
||||
{
|
||||
using var child = ImRaii.Child("##Panel", -Vector2.One, true);
|
||||
using var child = ImUtf8.Child("##Panel"u8, -Vector2.One, true);
|
||||
if (!child || !_selector.HasSelection)
|
||||
return;
|
||||
|
||||
|
|
@ -63,20 +64,20 @@ public class SetPanel(
|
|||
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
{
|
||||
var enabled = Selection.Enabled;
|
||||
if (ImGui.Checkbox("##Enabled", ref enabled))
|
||||
if (ImUtf8.Checkbox("##Enabled"u8, ref enabled))
|
||||
_manager.SetState(_selector.SelectionIndex, enabled);
|
||||
ImGuiUtil.LabeledHelpMarker("Enabled",
|
||||
"Whether the designs in this set should be applied at all. Only one set can be enabled for a character at the same time.");
|
||||
ImUtf8.LabeledHelpMarker("Enabled"u8,
|
||||
"Whether the designs in this set should be applied at all. Only one set can be enabled for a character at the same time."u8);
|
||||
}
|
||||
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
{
|
||||
var useGame = _selector.Selection!.BaseState is AutoDesignSet.Base.Game;
|
||||
if (ImGui.Checkbox("##gameState", ref useGame))
|
||||
if (ImUtf8.Checkbox("##gameState"u8, ref useGame))
|
||||
_manager.ChangeBaseState(_selector.SelectionIndex, useGame ? AutoDesignSet.Base.Game : AutoDesignSet.Base.Current);
|
||||
ImGuiUtil.LabeledHelpMarker("Use Game State as Base",
|
||||
"When this is enabled, the designs matching conditions will be applied successively on top of what your character is supposed to look like for the game. "
|
||||
+ "Otherwise, they will be applied on top of the characters actual current look using Glamourer.");
|
||||
ImUtf8.LabeledHelpMarker("Use Game State as Base"u8,
|
||||
"When this is enabled, the designs matching conditions will be applied successively on top of what your character is supposed to look like for the game. "u8
|
||||
+ "Otherwise, they will be applied on top of the characters actual current look using Glamourer."u8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,14 +87,14 @@ public class SetPanel(
|
|||
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
{
|
||||
var editing = _config.ShowAutomationSetEditing;
|
||||
if (ImGui.Checkbox("##Show Editing", ref editing))
|
||||
if (ImUtf8.Checkbox("##Show Editing"u8, ref editing))
|
||||
{
|
||||
_config.ShowAutomationSetEditing = editing;
|
||||
_config.Save();
|
||||
}
|
||||
|
||||
ImGuiUtil.LabeledHelpMarker("Show Editing",
|
||||
"Show options to change the name or the associated character or NPC of this design set.");
|
||||
ImUtf8.LabeledHelpMarker("Show Editing"u8,
|
||||
"Show options to change the name or the associated character or NPC of this design set."u8);
|
||||
}
|
||||
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
|
|
@ -102,8 +103,8 @@ public class SetPanel(
|
|||
if (ImGui.Checkbox("##resetSettings", ref resetSettings))
|
||||
_manager.ChangeResetSettings(_selector.SelectionIndex, resetSettings);
|
||||
|
||||
ImGuiUtil.LabeledHelpMarker("Reset Temporary Settings",
|
||||
"Always reset all temporary settings applied by Glamourer when this automation set is applied, regardless of active designs.");
|
||||
ImUtf8.LabeledHelpMarker("Reset Temporary Settings"u8,
|
||||
"Always reset all temporary settings applied by Glamourer when this automation set is applied, regardless of active designs."u8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,42 +161,43 @@ public class SetPanel(
|
|||
(false, false) => 4,
|
||||
};
|
||||
|
||||
using var table = ImRaii.Table("SetTable", numRows, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY);
|
||||
using var table = ImUtf8.Table("SetTable"u8, numRows, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGui.TableSetupColumn("##del", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight());
|
||||
ImGui.TableSetupColumn("##Index", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
|
||||
ImUtf8.TableSetupColumn("##del"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight());
|
||||
ImUtf8.TableSetupColumn("##Index"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
|
||||
|
||||
if (singleRow)
|
||||
{
|
||||
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale);
|
||||
ImUtf8.TableSetupColumn("Design"u8, ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale);
|
||||
if (_config.ShowAllAutomatedApplicationRules)
|
||||
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed,
|
||||
ImUtf8.TableSetupColumn("Application"u8, ImGuiTableColumnFlags.WidthFixed,
|
||||
6 * ImGui.GetFrameHeight() + 10 * ImGuiHelpers.GlobalScale);
|
||||
else
|
||||
ImGui.TableSetupColumn("Use", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X);
|
||||
ImUtf8.TableSetupColumn("Use"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TableSetupColumn("Design / Job Restrictions", ImGuiTableColumnFlags.WidthFixed, 250 * ImGuiHelpers.GlobalScale);
|
||||
ImUtf8.TableSetupColumn("Design / Job Restrictions"u8, ImGuiTableColumnFlags.WidthFixed,
|
||||
250 * ImGuiHelpers.GlobalScale - (ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ScrollbarSize : 0));
|
||||
if (_config.ShowAllAutomatedApplicationRules)
|
||||
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed,
|
||||
ImUtf8.TableSetupColumn("Application"u8, ImGuiTableColumnFlags.WidthFixed,
|
||||
3 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale);
|
||||
else
|
||||
ImGui.TableSetupColumn("Use", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X);
|
||||
ImUtf8.TableSetupColumn("Use"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X);
|
||||
}
|
||||
|
||||
if (singleRow)
|
||||
ImGui.TableSetupColumn("Job Restrictions", ImGuiTableColumnFlags.WidthStretch);
|
||||
ImUtf8.TableSetupColumn("Job Restrictions"u8, ImGuiTableColumnFlags.WidthStretch);
|
||||
|
||||
if (_config.ShowUnlockedItemWarnings)
|
||||
ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, 2 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale);
|
||||
ImUtf8.TableSetupColumn(""u8, ImGuiTableColumnFlags.WidthFixed, 2 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale);
|
||||
|
||||
ImGui.TableHeadersRow();
|
||||
foreach (var (design, idx) in Selection.Designs.WithIndex())
|
||||
{
|
||||
using var id = ImRaii.PushId(idx);
|
||||
using var id = ImUtf8.PushId(idx);
|
||||
ImGui.TableNextColumn();
|
||||
var keyValid = _config.DeleteDesignModifier.IsActive();
|
||||
var tt = keyValid
|
||||
|
|
@ -205,8 +207,8 @@ public class SetPanel(
|
|||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), new Vector2(ImGui.GetFrameHeight()), tt, !keyValid, true))
|
||||
_endAction = () => _manager.DeleteDesign(Selection, idx);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Selectable($"#{idx + 1:D2}");
|
||||
DrawDragDrop(Selection, idx);
|
||||
DrawSelectable(idx, design.Design);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
DrawRandomEditing(Selection, design, idx);
|
||||
_designCombo.Draw(Selection, design, idx);
|
||||
|
|
@ -234,8 +236,7 @@ public class SetPanel(
|
|||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted("New");
|
||||
ImUtf8.TextFrameAligned("New"u8);
|
||||
ImGui.TableNextColumn();
|
||||
_designCombo.Draw(Selection, null, -1);
|
||||
ImGui.TableNextRow();
|
||||
|
|
@ -244,26 +245,64 @@ public class SetPanel(
|
|||
_endAction = null;
|
||||
}
|
||||
|
||||
private void DrawSelectable(int idx, IDesignStandIn design)
|
||||
{
|
||||
var highlight = 0u;
|
||||
var sb = new StringBuilder();
|
||||
if (design is Design d)
|
||||
{
|
||||
var count = design.AllLinks(true).Count();
|
||||
if (count > 1)
|
||||
{
|
||||
sb.AppendLine($"This design contains {count - 1} links to other designs.");
|
||||
highlight = ColorId.HeaderButtons.Value();
|
||||
}
|
||||
|
||||
count = d.AssociatedMods.Count;
|
||||
if (count > 0)
|
||||
{
|
||||
sb.AppendLine($"This design contains {count} mod associations.");
|
||||
highlight = ColorId.ModdedItemMarker.Value();
|
||||
}
|
||||
|
||||
count = design.GetMaterialData().Count(p => p.Item2.Enabled);
|
||||
if (count > 0)
|
||||
{
|
||||
sb.AppendLine($"This design contains {count} enabled advanced dyes.");
|
||||
highlight = ColorId.AdvancedDyeActive.Value();
|
||||
}
|
||||
}
|
||||
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, highlight, highlight != 0))
|
||||
{
|
||||
ImUtf8.Selectable($"#{idx + 1:D2}");
|
||||
}
|
||||
|
||||
ImUtf8.HoverTooltip($"{sb}");
|
||||
|
||||
DrawDragDrop(Selection, idx);
|
||||
}
|
||||
|
||||
private int _tmpGearset = int.MaxValue;
|
||||
private int _whichIndex = -1;
|
||||
|
||||
private void DrawConditions(AutoDesign design, int idx)
|
||||
{
|
||||
var usingGearset = design.GearsetIndex >= 0;
|
||||
if (ImGui.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset"))
|
||||
if (ImUtf8.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset"))
|
||||
{
|
||||
usingGearset = !usingGearset;
|
||||
_manager.ChangeGearsetCondition(Selection, idx, (short)(usingGearset ? 0 : -1));
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip("Click to switch between Job and Gearset restrictions.");
|
||||
ImUtf8.HoverTooltip("Click to switch between Job and Gearset restrictions."u8);
|
||||
|
||||
ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
|
||||
if (usingGearset)
|
||||
{
|
||||
var set = 1 + (_tmpGearset == int.MaxValue || _whichIndex != idx ? design.GearsetIndex : _tmpGearset);
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||
if (ImGui.InputInt("##whichGearset", ref set, 0, 0))
|
||||
if (ImUtf8.InputScalar("##whichGearset"u8, ref set))
|
||||
{
|
||||
_whichIndex = idx;
|
||||
_tmpGearset = Math.Clamp(set, 1, 100);
|
||||
|
|
@ -361,12 +400,12 @@ public class SetPanel(
|
|||
ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip(sb.ToString());
|
||||
ImUtf8.HoverTooltip($"{sb}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiUtil.DrawTextButton(string.Empty, size, 0);
|
||||
ImGuiUtil.HoverTooltip(good);
|
||||
ImUtf8.HoverTooltip(good);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -374,7 +413,7 @@ public class SetPanel(
|
|||
private void DrawDragDrop(AutoDesignSet set, int index)
|
||||
{
|
||||
const string dragDropLabel = "DesignDragDrop";
|
||||
using (var target = ImRaii.DragDropTarget())
|
||||
using (var target = ImUtf8.DragDropTarget())
|
||||
{
|
||||
if (target.Success && ImGuiUtil.IsDropping(dragDropLabel))
|
||||
{
|
||||
|
|
@ -388,15 +427,15 @@ public class SetPanel(
|
|||
}
|
||||
}
|
||||
|
||||
using (var source = ImRaii.DragDropSource())
|
||||
using (var source = ImUtf8.DragDropSource())
|
||||
{
|
||||
if (source)
|
||||
{
|
||||
ImGui.TextUnformatted($"Moving design #{index + 1:D2}...");
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0))
|
||||
ImUtf8.Text($"Moving design #{index + 1:D2}...");
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, null, 0))
|
||||
{
|
||||
_dragIndex = index;
|
||||
_selector._dragDesignIndex = index;
|
||||
_selector.DragDesignIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -415,16 +454,16 @@ public class SetPanel(
|
|||
}
|
||||
|
||||
style.Pop();
|
||||
ImGuiUtil.HoverTooltip("Toggle all application modes at once.");
|
||||
ImUtf8.HoverTooltip("Toggle all application modes at once."u8);
|
||||
if (_config.ShowAllAutomatedApplicationRules)
|
||||
{
|
||||
void Box(int idx)
|
||||
{
|
||||
var (type, description) = ApplicationTypeExtensions.Types[idx];
|
||||
var value = design.Type.HasFlag(type);
|
||||
if (ImGui.Checkbox($"##{(byte)type}", ref value))
|
||||
if (ImUtf8.Checkbox($"##{(byte)type}", ref value))
|
||||
newType = value ? newType | type : newType & ~type;
|
||||
ImGuiUtil.HoverTooltip(description);
|
||||
ImUtf8.HoverTooltip(description);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.String;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
|
|
@ -18,8 +18,7 @@ public class SetSelector : IDisposable
|
|||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly List<(AutoDesignSet, int)> _list = [];
|
||||
|
||||
public AutoDesignSet? Selection { get; private set; }
|
||||
|
|
@ -38,14 +37,13 @@ public class SetSelector : IDisposable
|
|||
private int _dragIndex = -1;
|
||||
private Action? _endAction;
|
||||
|
||||
internal int _dragDesignIndex = -1;
|
||||
internal int DragDesignIndex = -1;
|
||||
|
||||
public SetSelector(AutoDesignManager manager, AutomationChanged @event, Configuration config, ActorManager actors, ObjectManager objects)
|
||||
public SetSelector(AutoDesignManager manager, AutomationChanged @event, Configuration config, ActorObjectManager objects)
|
||||
{
|
||||
_manager = manager;
|
||||
_event = @event;
|
||||
_config = config;
|
||||
_actors = actors;
|
||||
_objects = objects;
|
||||
_event.Subscribe(OnAutomationChange, AutomationChanged.Priority.SetSelector);
|
||||
}
|
||||
|
|
@ -94,7 +92,7 @@ public class SetSelector : IDisposable
|
|||
}
|
||||
|
||||
private LowerString _filter = LowerString.Empty;
|
||||
private uint _enabledFilter = 0;
|
||||
private uint _enabledFilter;
|
||||
private float _width;
|
||||
private Vector2 _defaultItemSpacing;
|
||||
private Vector2 _selectableSize;
|
||||
|
|
@ -146,7 +144,7 @@ public class SetSelector : IDisposable
|
|||
ImGui.SameLine();
|
||||
var f = _enabledFilter;
|
||||
|
||||
if (ImGui.CheckboxFlags("##enabledFilter", ref f, 3))
|
||||
if (ImGui.CheckboxFlags("##enabledFilter", ref f, 3u))
|
||||
{
|
||||
_enabledFilter = _enabledFilter switch
|
||||
{
|
||||
|
|
@ -177,7 +175,6 @@ public class SetSelector : IDisposable
|
|||
UpdateList();
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
|
||||
_selectableSize = new Vector2(0, 2 * ImGui.GetTextLineHeight() + ImGui.GetStyle().ItemSpacing.Y);
|
||||
_objects.Update();
|
||||
ImGuiClip.ClippedDraw(_list, DrawSetSelectable, _selectableSize.Y + 2 * ImGui.GetStyle().ItemSpacing.Y);
|
||||
_endAction?.Invoke();
|
||||
_endAction = null;
|
||||
|
|
@ -186,7 +183,7 @@ public class SetSelector : IDisposable
|
|||
private void DrawSetSelectable((AutoDesignSet Set, int Index) pair)
|
||||
{
|
||||
using var id = ImRaii.PushId(pair.Index);
|
||||
using (var color = ImRaii.PushColor(ImGuiCol.Text, pair.Set.Enabled ? ColorId.EnabledAutoSet.Value() : ColorId.DisabledAutoSet.Value()))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, pair.Set.Enabled ? ColorId.EnabledAutoSet.Value() : ColorId.DisabledAutoSet.Value()))
|
||||
{
|
||||
if (ImGui.Selectable(GetSetName(pair.Set, pair.Index), pair.Set == Selection, ImGuiSelectableFlags.None, _selectableSize))
|
||||
{
|
||||
|
|
@ -285,9 +282,9 @@ public class SetSelector : IDisposable
|
|||
|
||||
private void NewSetButton(Vector2 size)
|
||||
{
|
||||
var id = _actors.GetCurrentPlayer();
|
||||
var id = _objects.Actors.GetCurrentPlayer();
|
||||
if (!id.IsValid)
|
||||
id = _actors.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), ushort.MaxValue);
|
||||
id = _objects.Actors.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), ushort.MaxValue);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size,
|
||||
$"Create a new Automatic Design Set for {id}. The associated player can be changed later.", !id.IsValid, true))
|
||||
_manager.AddDesignSet("New Automation Set", id);
|
||||
|
|
@ -332,15 +329,15 @@ public class SetSelector : IDisposable
|
|||
}
|
||||
else if (ImGuiUtil.IsDropping("DesignDragDrop"))
|
||||
{
|
||||
if (_dragDesignIndex >= 0)
|
||||
if (DragDesignIndex >= 0)
|
||||
{
|
||||
var idx = _dragDesignIndex;
|
||||
var idx = DragDesignIndex;
|
||||
var setTo = set;
|
||||
var setFrom = Selection!;
|
||||
_endAction = () => _manager.MoveDesignToSet(setFrom, idx, setTo);
|
||||
}
|
||||
|
||||
_dragDesignIndex = -1;
|
||||
DragDesignIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -350,7 +347,7 @@ public class SetSelector : IDisposable
|
|||
if (source)
|
||||
{
|
||||
ImGui.TextUnformatted($"Moving design set {GetSetName(set, index)} from position {index + 1}...");
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0))
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, null, 0))
|
||||
_dragIndex = index;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectManager) : IGameDataDrawer
|
||||
public class ActiveStatePanel(StateManager _stateManager, ActorObjectManager _objectManager) : IGameDataDrawer
|
||||
{
|
||||
public string Label
|
||||
=> $"Active Actors ({_stateManager.Count})###Active Actors";
|
||||
|
|
@ -22,8 +21,7 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
|
|||
|
||||
public void Draw()
|
||||
{
|
||||
_objectManager.Update();
|
||||
foreach (var (identifier, actors) in _objectManager.Identifiers)
|
||||
foreach (var (identifier, actors) in _objectManager)
|
||||
{
|
||||
if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.Trash.ToIconString()}##{actors.Label}", new Vector2(ImGui.GetFrameHeight()),
|
||||
string.Empty, !_stateManager.ContainsKey(identifier), true))
|
||||
|
|
@ -66,13 +64,15 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
|
|||
static string ItemString(in DesignData data, EquipSlot slot)
|
||||
{
|
||||
var item = data.Item(slot);
|
||||
return $"{item.Name} ({item.Id.ToDiscriminatingString()} {item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})";
|
||||
return
|
||||
$"{item.Name} ({item.Id.ToDiscriminatingString()} {item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})";
|
||||
}
|
||||
|
||||
static string BonusItemString(in DesignData data, BonusItemFlag slot)
|
||||
{
|
||||
var item = data.BonusItem(slot);
|
||||
return $"{item.Name} ({item.Id.ToDiscriminatingString()} {item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})";
|
||||
return
|
||||
$"{item.Name} ({item.Id.ToDiscriminatingString()} {item.PrimaryId.Id}{(item.SecondaryId != 0 ? $"-{item.SecondaryId.Id}" : string.Empty)}-{item.Variant})";
|
||||
}
|
||||
|
||||
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state.Sources[MetaIndex.ModelId]);
|
||||
|
|
@ -87,6 +87,9 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM
|
|||
PrintRow("Visor Toggled", state.BaseData.IsVisorToggled(), state.ModelData.IsVisorToggled(),
|
||||
state.Sources[MetaIndex.VisorState]);
|
||||
ImGui.TableNextRow();
|
||||
PrintRow("Viera Ears Visible", state.BaseData.AreEarsVisible(), state.ModelData.AreEarsVisible(),
|
||||
state.Sources[MetaIndex.EarState]);
|
||||
ImGui.TableNextRow();
|
||||
PrintRow("Weapon Visible", state.BaseData.IsWeaponVisible(), state.ModelData.IsWeaponVisible(),
|
||||
state.Sources[MetaIndex.WeaponState]);
|
||||
ImGui.TableNextRow();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class AdvancedCustomizationDrawer(ObjectManager objects) : IGameDataDrawer
|
||||
public unsafe class AdvancedCustomizationDrawer(ActorObjectManager objects) : IGameDataDrawer
|
||||
{
|
||||
public string Label
|
||||
=> "Advanced Customizations";
|
||||
|
|
@ -31,8 +31,8 @@ public unsafe class AdvancedCustomizationDrawer(ObjectManager objects) : IGameDa
|
|||
return;
|
||||
}
|
||||
|
||||
DrawCBuffer("Customize"u8, model.AsHuman->CustomizeParameterCBuffer, 0);
|
||||
DrawCBuffer("Decal"u8, model.AsHuman->DecalColorCBuffer, 1);
|
||||
DrawCBuffer("Customize"u8, model.AsHuman->CustomizeParameterCBuffer, 0);
|
||||
DrawCBuffer("Decal"u8, model.AsHuman->DecalColorCBuffer, 1);
|
||||
DrawCBuffer("Unk1"u8, *(ConstantBuffer**)((byte*)model.AsHuman + 0xBA0), 2);
|
||||
DrawCBuffer("Unk2"u8, *(ConstantBuffer**)((byte*)model.AsHuman + 0xBA8), 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Glamourer.Automation;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
using OtterGui.Widgets;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Glamourer.Gui.Tabs.DebugTab.IpcTester;
|
||||
using ImGuiNET;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
|
@ -36,6 +35,7 @@ public class DebugTabHeader(string label, params IGameDataDrawer[] subTrees)
|
|||
provider.GetRequiredService<ModelEvaluationPanel>(),
|
||||
provider.GetRequiredService<ObjectManagerPanel>(),
|
||||
provider.GetRequiredService<PenumbraPanel>(),
|
||||
provider.GetRequiredService<DynamisPanel>(),
|
||||
provider.GetRequiredService<IpcTesterPanel>(),
|
||||
provider.GetRequiredService<DatFilePanel>(),
|
||||
provider.GetRequiredService<GlamourPlatePanel>(),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Utility;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Designs;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
|
|
@ -18,6 +21,7 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
|
|||
|
||||
public void Draw()
|
||||
{
|
||||
DrawButtons();
|
||||
foreach (var (design, idx) in _designManager.Designs.WithIndex())
|
||||
{
|
||||
using var t = ImRaii.TreeNode($"{design.Name}##{idx}");
|
||||
|
|
@ -25,7 +29,8 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
|
|||
continue;
|
||||
|
||||
DrawDesign(design, _designFileSystem);
|
||||
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.Application.Equip, design.Application.Customize, design.Application.Meta,
|
||||
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.Application.Equip, design.Application.Customize,
|
||||
design.Application.Meta,
|
||||
design.WriteProtected());
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGuiUtil.TextWrapped(base64);
|
||||
|
|
@ -34,6 +39,26 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
|
|||
}
|
||||
}
|
||||
|
||||
private void DrawButtons()
|
||||
{
|
||||
if (ImUtf8.Button("Generate 500 Test Designs"u8))
|
||||
for (var i = 0; i < 500; ++i)
|
||||
{
|
||||
var design = _designManager.CreateEmpty($"Test Designs/Test Design {i}", true);
|
||||
_designManager.AddTag(design, "_DebugTest");
|
||||
}
|
||||
|
||||
ImUtf8.SameLineInner();
|
||||
if (ImUtf8.Button("Remove All Test Designs"u8))
|
||||
{
|
||||
var designs = _designManager.Designs.Where(d => d.Tags.Contains("_DebugTest")).ToArray();
|
||||
foreach (var design in designs)
|
||||
_designManager.Delete(design);
|
||||
if (_designFileSystem.Find("Test Designs", out var path) && path is DesignFileSystem.Folder { TotalChildren: 0 })
|
||||
_designFileSystem.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawDesign(DesignBase design, DesignFileSystem? fileSystem)
|
||||
{
|
||||
using var table = ImRaii.Table("##equip", 8, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
|
||||
|
|
@ -52,7 +77,7 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
|
|||
ImGui.TableNextRow();
|
||||
ImGuiUtil.DrawTableColumn("Design File System Path");
|
||||
if (fileSystem != null)
|
||||
ImGuiUtil.DrawTableColumn(fileSystem.FindLeaf(d, out var leaf) ? leaf.FullName() : "No Path Known");
|
||||
ImGuiUtil.DrawTableColumn(fileSystem.TryGetValue(d, out var leaf) ? leaf.FullName() : "No Path Known");
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Creation");
|
||||
|
|
@ -89,6 +114,7 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
|
|||
ImGuiUtil.DrawTableColumn(index.ToName());
|
||||
ImGuiUtil.DrawTableColumn(design.DesignData.GetMeta(index).ToString());
|
||||
ImGuiUtil.DrawTableColumn(design.DoApplyMeta(index) ? "Apply" : "Keep");
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Model ID");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
16
Glamourer/Gui/Tabs/DebugTab/DynamisPanel.cs
Normal file
16
Glamourer/Gui/Tabs/DebugTab/DynamisPanel.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class DynamisPanel(DynamisIpc dynamis) : IGameDataDrawer
|
||||
{
|
||||
public string Label
|
||||
=> "Dynamis Interop";
|
||||
|
||||
public void Draw()
|
||||
=> dynamis.DrawDebugInfo();
|
||||
|
||||
public bool Disabled
|
||||
=> false;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
|
|
|||
|
|
@ -3,24 +3,26 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class GlamourPlatePanel : IGameDataDrawer
|
||||
{
|
||||
private readonly DesignManager _design;
|
||||
private readonly ItemManager _items;
|
||||
private readonly StateManager _state;
|
||||
private readonly ObjectManager _objects;
|
||||
private readonly DesignManager _design;
|
||||
private readonly ItemManager _items;
|
||||
private readonly StateManager _state;
|
||||
private readonly ActorObjectManager _objects;
|
||||
|
||||
public string Label
|
||||
=> "Glamour Plates";
|
||||
|
|
@ -28,7 +30,8 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
public bool Disabled
|
||||
=> false;
|
||||
|
||||
public GlamourPlatePanel(IGameInteropProvider interop, ItemManager items, DesignManager design, StateManager state, ObjectManager objects)
|
||||
public GlamourPlatePanel(IGameInteropProvider interop, ItemManager items, DesignManager design, StateManager state,
|
||||
ActorObjectManager objects)
|
||||
{
|
||||
_items = items;
|
||||
_design = design;
|
||||
|
|
@ -42,24 +45,24 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
var manager = MirageManager.Instance();
|
||||
using (ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted("Address:");
|
||||
ImGui.TextUnformatted("Number of Glamour Plates:");
|
||||
ImGui.TextUnformatted("Glamour Plates Requested:");
|
||||
ImGui.TextUnformatted("Glamour Plates Loaded:");
|
||||
ImGui.TextUnformatted("Is Applying Glamour Plates:");
|
||||
ImUtf8.Text("Address:"u8);
|
||||
ImUtf8.Text("Number of Glamour Plates:"u8);
|
||||
ImUtf8.Text("Glamour Plates Requested:"u8);
|
||||
ImUtf8.Text("Glamour Plates Loaded:"u8);
|
||||
ImUtf8.Text("Is Applying Glamour Plates:"u8);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.Group())
|
||||
{
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)manager:X}");
|
||||
ImGui.TextUnformatted(manager == null ? "-" : manager->GlamourPlates.Length.ToString());
|
||||
ImGui.TextUnformatted(manager == null ? "-" : manager->GlamourPlatesRequested.ToString());
|
||||
ImUtf8.CopyOnClickSelectable($"0x{(ulong)manager:X}");
|
||||
ImUtf8.Text(manager == null ? "-" : manager->GlamourPlates.Length.ToString());
|
||||
ImUtf8.Text(manager == null ? "-" : manager->GlamourPlatesRequested.ToString());
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Request Update"))
|
||||
if (ImUtf8.SmallButton("Request Update"u8))
|
||||
RequestGlamour();
|
||||
ImGui.TextUnformatted(manager == null ? "-" : manager->GlamourPlatesLoaded.ToString());
|
||||
ImGui.TextUnformatted(manager == null ? "-" : manager->IsApplyingGlamourPlate.ToString());
|
||||
ImUtf8.Text(manager == null ? "-" : manager->GlamourPlatesLoaded.ToString());
|
||||
ImUtf8.Text(manager == null ? "-" : manager->IsApplyingGlamourPlate.ToString());
|
||||
}
|
||||
|
||||
if (manager == null)
|
||||
|
|
@ -71,12 +74,12 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
|
||||
for (var i = 0; i < manager->GlamourPlates.Length; ++i)
|
||||
{
|
||||
using var tree = ImRaii.TreeNode($"Plate #{i + 1:D2}");
|
||||
using var tree = ImUtf8.TreeNode($"Plate #{i + 1:D2}");
|
||||
if (!tree)
|
||||
continue;
|
||||
|
||||
ref var plate = ref manager->GlamourPlates[i];
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply to Player", Vector2.Zero, string.Empty, !enabled))
|
||||
if (ImUtf8.ButtonEx("Apply to Player"u8, ""u8, Vector2.Zero, !enabled))
|
||||
{
|
||||
var design = CreateDesign(plate);
|
||||
_state.ApplyDesign(state!, design, ApplySettings.Manual with { IsFinal = true });
|
||||
|
|
@ -85,14 +88,14 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
|
|||
using (ImRaii.Group())
|
||||
{
|
||||
foreach (var slot in EquipSlotExtensions.FullSlots)
|
||||
ImGui.TextUnformatted(slot.ToName());
|
||||
ImUtf8.Text(slot.ToName());
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.Group())
|
||||
{
|
||||
foreach (var (_, index) in EquipSlotExtensions.FullSlots.WithIndex())
|
||||
ImGui.TextUnformatted($"{plate.ItemIds[index]:D6}, {StainIds.FromGlamourPlate(plate, index)}");
|
||||
ImUtf8.Text($"{plate.ItemIds[index]:D6}, {StainIds.FromGlamourPlate(plate, index)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
|
@ -23,7 +23,7 @@ public unsafe class InventoryPanel : IGameDataDrawer
|
|||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)inventory:X}");
|
||||
|
||||
var equip = inventory->GetInventoryContainer(InventoryType.EquippedItems);
|
||||
if (equip == null || equip->Loaded == 0)
|
||||
if (equip == null || equip->IsLoaded)
|
||||
return;
|
||||
|
||||
ImGuiUtil.CopyOnClickSelectable($"0x{(ulong)equip:X}");
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ using Dalamud.Interface.Utility;
|
|||
using Dalamud.Plugin;
|
||||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Api.IpcSubscribers;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
using OtterGui.Text;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab.IpcTester;
|
||||
|
||||
|
|
@ -15,6 +16,7 @@ public class DesignIpcTester(IDalamudPluginInterface pluginInterface) : IUiServi
|
|||
private Dictionary<Guid, string> _designs = [];
|
||||
private int _gameObjectIndex;
|
||||
private string _gameObjectName = string.Empty;
|
||||
private string _designName = string.Empty;
|
||||
private uint _key;
|
||||
private ApplyFlag _flags = ApplyFlagEx.DesignDefault;
|
||||
private Guid? _design;
|
||||
|
|
@ -30,6 +32,7 @@ public class DesignIpcTester(IDalamudPluginInterface pluginInterface) : IUiServi
|
|||
IpcTesterHelpers.IndexInput(ref _gameObjectIndex);
|
||||
IpcTesterHelpers.KeyInput(ref _key);
|
||||
IpcTesterHelpers.NameInput(ref _gameObjectName);
|
||||
ImUtf8.InputText("##designName"u8, ref _designName, "Design Name..."u8);
|
||||
ImGuiUtil.GuidInput("##identifier", "Design Identifier...", string.Empty, ref _design, ref _designText,
|
||||
ImGui.GetContentRegionAvail().X);
|
||||
IpcTesterHelpers.DrawFlagInput(ref _flags);
|
||||
|
|
@ -54,6 +57,48 @@ public class DesignIpcTester(IDalamudPluginInterface pluginInterface) : IUiServi
|
|||
IpcTesterHelpers.DrawIntro(ApplyDesignName.Label);
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply##Name", Vector2.Zero, string.Empty, !_design.HasValue))
|
||||
_lastError = new ApplyDesignName(pluginInterface).Invoke(_design!.Value, _gameObjectName, _key, _flags);
|
||||
|
||||
IpcTesterHelpers.DrawIntro(GetExtendedDesignData.Label);
|
||||
if (_design.HasValue)
|
||||
{
|
||||
var (display, path, color, draw) = new GetExtendedDesignData(pluginInterface).Invoke(_design.Value);
|
||||
if (path.Length > 0)
|
||||
ImUtf8.Text($"{display} ({path}){(draw ? " in QDB"u8 : ""u8)}", color);
|
||||
else
|
||||
ImUtf8.Text("No Data"u8);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImUtf8.Text("No Data"u8);
|
||||
}
|
||||
|
||||
IpcTesterHelpers.DrawIntro(GetDesignBase64.Label);
|
||||
if (ImUtf8.Button("To Clipboard##Base64"u8) && _design.HasValue)
|
||||
{
|
||||
var data = new GetDesignBase64(pluginInterface).Invoke(_design.Value);
|
||||
ImUtf8.SetClipboardText(data);
|
||||
}
|
||||
|
||||
IpcTesterHelpers.DrawIntro(AddDesign.Label);
|
||||
if (ImUtf8.Button("Add from Clipboard"u8))
|
||||
try
|
||||
{
|
||||
var data = ImUtf8.GetClipboardText();
|
||||
_lastError = new AddDesign(pluginInterface).Invoke(data, _designName, out var newDesign);
|
||||
if (_lastError is GlamourerApiEc.Success)
|
||||
{
|
||||
_design = newDesign;
|
||||
_designText = newDesign.ToString();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_lastError = GlamourerApiEc.UnknownError;
|
||||
}
|
||||
|
||||
IpcTesterHelpers.DrawIntro(DeleteDesign.Label);
|
||||
if (ImUtf8.Button("Delete##Design"u8) && _design.HasValue)
|
||||
_lastError = new DeleteDesign(pluginInterface).Invoke(_design.Value);
|
||||
}
|
||||
|
||||
private void DrawDesignsPopup()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Designs;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using static Penumbra.GameData.Files.ShpkFile;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Api.IpcSubscribers;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab.IpcTester;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Plugin;
|
||||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Api.IpcSubscribers;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Services;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using Glamourer.Api.Enums;
|
|||
using Glamourer.Api.Helpers;
|
||||
using Glamourer.Api.IpcSubscribers;
|
||||
using Glamourer.Designs;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Glamourer.GameData;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
|
|
@ -11,13 +11,13 @@ using Penumbra.GameData.Enums;
|
|||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using ObjectManager = Glamourer.Interop.ObjectManager;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public unsafe class ModelEvaluationPanel(
|
||||
ObjectManager _objectManager,
|
||||
ActorObjectManager _objectManager,
|
||||
VisorService _visorService,
|
||||
VieraEarService _vieraEarService,
|
||||
UpdateSlotService _updateSlotService,
|
||||
ChangeCustomizeService _changeCustomizeService,
|
||||
CrestService _crestService,
|
||||
|
|
@ -34,7 +34,7 @@ public unsafe class ModelEvaluationPanel(
|
|||
public void Draw()
|
||||
{
|
||||
ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0);
|
||||
var actor = _objectManager[_gameObjectIndex];
|
||||
var actor = _objectManager.Objects[_gameObjectIndex];
|
||||
var model = actor.Model;
|
||||
using var table = ImRaii.Table("##evaluationTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
ImGui.TableNextColumn();
|
||||
|
|
@ -46,9 +46,10 @@ public unsafe class ModelEvaluationPanel(
|
|||
|
||||
ImGuiUtil.DrawTableColumn("Address");
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(actor.ToString());
|
||||
|
||||
Glamourer.Dynamis.DrawPointer(actor);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(model.ToString());
|
||||
Glamourer.Dynamis.DrawPointer(model);
|
||||
ImGui.TableNextColumn();
|
||||
if (actor.IsCharacter)
|
||||
{
|
||||
|
|
@ -84,6 +85,7 @@ public unsafe class ModelEvaluationPanel(
|
|||
ImGuiUtil.CopyOnClickSelectable(offhand.ToString());
|
||||
|
||||
DrawVisor(actor, model);
|
||||
DrawVieraEars(actor, model);
|
||||
DrawHatState(actor, model);
|
||||
DrawWeaponState(actor, model);
|
||||
DrawWetness(actor, model);
|
||||
|
|
@ -135,6 +137,26 @@ public unsafe class ModelEvaluationPanel(
|
|||
_visorService.SetVisorState(model, !VisorService.GetVisorState(model));
|
||||
}
|
||||
|
||||
private void DrawVieraEars(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Viera Ears");
|
||||
ImGuiUtil.DrawTableColumn("Viera Ears");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter ? actor.ShowVieraEars.ToString() : "No Character");
|
||||
ImGuiUtil.DrawTableColumn(model.IsHuman ? model.VieraEarsVisible.ToString() : "No Human");
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
||||
if (ImGui.SmallButton("Set True"))
|
||||
_vieraEarService.SetVieraEarState(model, true);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Set False"))
|
||||
_vieraEarService.SetVieraEarState(model, false);
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Toggle"))
|
||||
_vieraEarService.SetVieraEarState(model, !model.VieraEarsVisible);
|
||||
}
|
||||
|
||||
private void DrawHatState(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("HatState");
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ using Dalamud.Interface.Utility;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectManager _objectManager, DesignConverter _designConverter)
|
||||
public class NpcAppearancePanel(NpcCombo npcCombo, StateManager stateManager, ActorObjectManager objectManager, DesignConverter designConverter)
|
||||
: IGameDataDrawer
|
||||
{
|
||||
public string Label
|
||||
|
|
@ -28,9 +28,9 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
|
||||
public void Draw()
|
||||
{
|
||||
ImGui.Checkbox("Compare Customize (or Gear)", ref _customizeOrGear);
|
||||
ImUtf8.Checkbox("Compare Customize (or Gear)"u8, ref _customizeOrGear);
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||
var resetScroll = ImGui.InputTextWithHint("##npcFilter", "Filter...", ref _npcFilter, 64);
|
||||
var resetScroll = ImUtf8.InputText("##npcFilter"u8, ref _npcFilter, "Filter..."u8);
|
||||
|
||||
using var table = ImRaii.Table("npcs", 7, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
|
||||
new Vector2(-1, 400 * ImGuiHelpers.GlobalScale));
|
||||
|
|
@ -40,19 +40,19 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
if (resetScroll)
|
||||
ImGui.SetScrollY(0);
|
||||
|
||||
ImGui.TableSetupColumn("Button", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, ImGuiHelpers.GlobalScale * 300);
|
||||
ImGui.TableSetupColumn("Kind", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Id", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Model", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Visor", ImGuiTableColumnFlags.WidthFixed);
|
||||
ImGui.TableSetupColumn("Compare", ImGuiTableColumnFlags.WidthStretch);
|
||||
ImUtf8.TableSetupColumn("Button"u8, ImGuiTableColumnFlags.WidthFixed);
|
||||
ImUtf8.TableSetupColumn("Name"u8, ImGuiTableColumnFlags.WidthFixed, ImGuiHelpers.GlobalScale * 300);
|
||||
ImUtf8.TableSetupColumn("Kind"u8, ImGuiTableColumnFlags.WidthFixed);
|
||||
ImUtf8.TableSetupColumn("Id"u8, ImGuiTableColumnFlags.WidthFixed);
|
||||
ImUtf8.TableSetupColumn("Model"u8, ImGuiTableColumnFlags.WidthFixed);
|
||||
ImUtf8.TableSetupColumn("Visor"u8, ImGuiTableColumnFlags.WidthFixed);
|
||||
ImUtf8.TableSetupColumn("Compare"u8, ImGuiTableColumnFlags.WidthStretch);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetFrameHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
var idx = 0;
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_npcCombo.Items, skips,
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(npcCombo.Items, skips,
|
||||
d => d.Name.Contains(_npcFilter, StringComparison.OrdinalIgnoreCase), DrawData);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetFrameHeightWithSpacing());
|
||||
|
|
@ -61,43 +61,31 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
void DrawData(NpcData data)
|
||||
{
|
||||
using var id = ImRaii.PushId(idx++);
|
||||
var disabled = !_state.GetOrCreate(_objectManager.Player, out var state);
|
||||
var disabled = !stateManager.GetOrCreate(objectManager.Player, out var state);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply", Vector2.Zero, string.Empty, disabled))
|
||||
if (ImUtf8.ButtonEx("Apply"u8, ""u8, Vector2.Zero, disabled))
|
||||
{
|
||||
foreach (var (slot, item, stain) in _designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand, true))
|
||||
_state.ChangeEquip(state!, slot, item, stain, ApplySettings.Manual);
|
||||
_state.ChangeMetaState(state!, MetaIndex.VisorState, data.VisorToggled, ApplySettings.Manual);
|
||||
_state.ChangeEntireCustomize(state!, data.Customize, CustomizeFlagExtensions.All, ApplySettings.Manual);
|
||||
foreach (var (slot, item, stain) in designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand, true))
|
||||
stateManager.ChangeEquip(state!, slot, item, stain, ApplySettings.Manual);
|
||||
stateManager.ChangeMetaState(state!, MetaIndex.VisorState, data.VisorToggled, ApplySettings.Manual);
|
||||
stateManager.ChangeEntireCustomize(state!, data.Customize, CustomizeFlagExtensions.All, ApplySettings.Manual);
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.Name);
|
||||
ImUtf8.DrawFrameColumn(data.Name);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.Kind is ObjectKind.BattleNpc ? "B" : "E");
|
||||
ImUtf8.DrawFrameColumn(data.Kind is ObjectKind.BattleNpc ? "B" : "E");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.Id.Id.ToString());
|
||||
ImUtf8.DrawFrameColumn(data.Id.Id.ToString());
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.ModelId.ToString());
|
||||
ImUtf8.DrawFrameColumn(data.ModelId.ToString());
|
||||
|
||||
using (_ = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.VisorToggled ? FontAwesomeIcon.Check.ToIconString() : FontAwesomeIcon.Times.ToIconString());
|
||||
ImUtf8.DrawFrameColumn(data.VisorToggled ? FontAwesomeIcon.Check.ToIconString() : FontAwesomeIcon.Times.ToIconString());
|
||||
}
|
||||
|
||||
using var mono = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(_customizeOrGear ? data.Customize.ToString() : data.WriteGear());
|
||||
ImUtf8.DrawFrameColumn(_customizeOrGear ? data.Customize.ToString() : data.WriteGear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class ObjectManagerPanel(ObjectManager _objectManager, ActorManager _actors) : IGameDataDrawer
|
||||
public class ObjectManagerPanel(ActorObjectManager _objectManager, ActorManager _actors) : IGameDataDrawer
|
||||
{
|
||||
public string Label
|
||||
=> "Object Manager";
|
||||
|
|
@ -19,44 +19,45 @@ public class ObjectManagerPanel(ObjectManager _objectManager, ActorManager _acto
|
|||
|
||||
public void Draw()
|
||||
{
|
||||
_objectManager.Update();
|
||||
using (var table = ImRaii.Table("##data", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit))
|
||||
_objectManager.Objects.DrawDebug();
|
||||
|
||||
using (var table = ImUtf8.Table("##data"u8, 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit))
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Last Update");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.LastUpdate.ToString(CultureInfo.InvariantCulture));
|
||||
ImUtf8.DrawTableColumn("World"u8);
|
||||
ImUtf8.DrawTableColumn(_actors.Finished ? _actors.Data.ToWorldName(_objectManager.World) : "Service Missing");
|
||||
ImUtf8.DrawTableColumn(_objectManager.World.ToString());
|
||||
|
||||
ImUtf8.DrawTableColumn("Player Character"u8);
|
||||
ImUtf8.DrawTableColumn($"{_objectManager.Player.Utf8Name} ({_objectManager.Player.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImUtf8.CopyOnClickSelectable(_objectManager.Player.ToString());
|
||||
|
||||
ImUtf8.DrawTableColumn("In GPose"u8);
|
||||
ImUtf8.DrawTableColumn(_objectManager.IsInGPose.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("World");
|
||||
ImGuiUtil.DrawTableColumn(_actors.Finished ? _actors.Data.ToWorldName(_objectManager.World) : "Service Missing");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.World.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Player Character");
|
||||
ImGuiUtil.DrawTableColumn($"{_objectManager.Player.Utf8Name} ({_objectManager.Player.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(_objectManager.Player.ToString());
|
||||
|
||||
ImGuiUtil.DrawTableColumn("In GPose");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.IsInGPose.ToString());
|
||||
ImUtf8.DrawTableColumn("In Lobby"u8);
|
||||
ImUtf8.DrawTableColumn(_objectManager.IsInLobby.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
if (_objectManager.IsInGPose)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn("GPose Player");
|
||||
ImGuiUtil.DrawTableColumn($"{_objectManager.GPosePlayer.Utf8Name} ({_objectManager.GPosePlayer.Index})");
|
||||
ImUtf8.DrawTableColumn("GPose Player"u8);
|
||||
ImUtf8.DrawTableColumn($"{_objectManager.GPosePlayer.Utf8Name} ({_objectManager.GPosePlayer.Index})");
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.CopyOnClickSelectable(_objectManager.GPosePlayer.ToString());
|
||||
ImUtf8.CopyOnClickSelectable(_objectManager.GPosePlayer.ToString());
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Number of Players");
|
||||
ImGuiUtil.DrawTableColumn(_objectManager.Count.ToString());
|
||||
ImUtf8.DrawTableColumn("Number of Players"u8);
|
||||
ImUtf8.DrawTableColumn(_objectManager.Count.ToString());
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
|
||||
var filterChanged = ImGui.InputTextWithHint("##Filter", "Filter...", ref _objectFilter, 64);
|
||||
using var table2 = ImRaii.Table("##data2", 3,
|
||||
var filterChanged = ImUtf8.InputText("##Filter"u8, ref _objectFilter, "Filter..."u8);
|
||||
using var table2 = ImUtf8.Table("##data2"u8, 3,
|
||||
ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.ScrollY,
|
||||
new Vector2(-1, 20 * ImGui.GetTextLineHeightWithSpacing()));
|
||||
if (!table2)
|
||||
|
|
@ -69,13 +70,13 @@ public class ObjectManagerPanel(ObjectManager _objectManager, ActorManager _acto
|
|||
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
|
||||
ImGui.TableNextRow();
|
||||
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_objectManager.Identifiers, skips,
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_objectManager, skips,
|
||||
p => p.Value.Label.Contains(_objectFilter, StringComparison.OrdinalIgnoreCase), p
|
||||
=>
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(p.Key.ToString());
|
||||
ImGuiUtil.DrawTableColumn(p.Value.Label);
|
||||
ImGuiUtil.DrawTableColumn(string.Join(", ", p.Value.Objects.OrderBy(a => a.Index).Select(a => a.Index.ToString())));
|
||||
ImUtf8.DrawTableColumn(p.Key.ToString());
|
||||
ImUtf8.DrawTableColumn(p.Value.Label);
|
||||
ImUtf8.DrawTableColumn(string.Join(", ", p.Value.Objects.OrderBy(a => a.Index).Select(a => a.Index.ToString())));
|
||||
});
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeightWithSpacing());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.Api.Enums;
|
||||
|
|
@ -49,7 +49,7 @@ public unsafe class PenumbraPanel(PenumbraService _penumbra, PenumbraChangedItem
|
|||
ImGui.TableNextColumn();
|
||||
var address = _drawObject.Address;
|
||||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputScalar("##drawObjectPtr", ImGuiDataType.U64, (nint)(&address), nint.Zero, nint.Zero, "%llx",
|
||||
if (ImGui.InputScalar("##drawObjectPtr", ImGuiDataType.U64, ref address, nint.Zero, nint.Zero, "%llx",
|
||||
ImGuiInputTextFlags.CharsHexadecimal))
|
||||
_drawObject = address;
|
||||
ImGuiUtil.DrawTableColumn(_penumbra.Available
|
||||
|
|
@ -61,7 +61,7 @@ public unsafe class PenumbraPanel(PenumbraService _penumbra, PenumbraChangedItem
|
|||
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
|
||||
ImGui.InputInt("##CutsceneIndex", ref _gameObjectIndex, 0, 0);
|
||||
ImGuiUtil.DrawTableColumn(_penumbra.Available
|
||||
? _penumbra.CutsceneParent((ushort) _gameObjectIndex).ToString()
|
||||
? _penumbra.CutsceneParent((ushort)_gameObjectIndex).ToString()
|
||||
: "Penumbra Unavailable");
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Redraw Object");
|
||||
|
|
@ -76,7 +76,9 @@ public unsafe class PenumbraPanel(PenumbraService _penumbra, PenumbraChangedItem
|
|||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Last Tooltip Date");
|
||||
ImGuiUtil.DrawTableColumn(_penumbraTooltip.LastTooltip > DateTime.MinValue ? $"{_penumbraTooltip.LastTooltip.ToLongTimeString()} ({_penumbraTooltip.LastType} {_penumbraTooltip.LastId})" : "Never");
|
||||
ImGuiUtil.DrawTableColumn(_penumbraTooltip.LastTooltip > DateTime.MinValue
|
||||
? $"{_penumbraTooltip.LastTooltip.ToLongTimeString()} ({_penumbraTooltip.LastType} {_penumbraTooltip.LastId})"
|
||||
: "Never");
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGuiUtil.DrawTableColumn("Last Click Date");
|
||||
|
|
@ -87,7 +89,13 @@ public unsafe class PenumbraPanel(PenumbraService _penumbra, PenumbraChangedItem
|
|||
ImGui.Separator();
|
||||
foreach (var (slot, item) in _penumbraTooltip.LastItems)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn($"{slot.ToName()} Revert-Item");
|
||||
switch (slot)
|
||||
{
|
||||
case EquipSlot e: ImGuiUtil.DrawTableColumn($"{e.ToName()} Revert-Item"); break;
|
||||
case BonusItemFlag f: ImGuiUtil.DrawTableColumn($"{f.ToName()} Revert-Item"); break;
|
||||
default: ImGuiUtil.DrawTableColumn("Unk Revert-Item"); break;
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(item.Valid ? item.Name : "None");
|
||||
ImGui.TableNextColumn();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ using Glamourer.Interop.Structs;
|
|||
using Glamourer.State;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public class RetainedStatePanel(StateManager _stateManager, ObjectManager _objectManager) : IGameDataDrawer
|
||||
public class RetainedStatePanel(StateManager _stateManager, ActorObjectManager _objectManager) : IGameDataDrawer
|
||||
{
|
||||
public string Label
|
||||
=> "Retained States (Inactive Actors)";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue