Updated to Risa's changes

This commit is contained in:
2025-08-10 12:48:02 +03:00
parent 0a0ae4bee9
commit 9730de1ba4
59 changed files with 302 additions and 2810 deletions

View File

@@ -48,7 +48,7 @@ public partial class CustomizePlusIpc
.Where(x => x.ProfileType == ProfileType.Normal)
.Select(x =>
{
string path = _profileFileSystem.FindLeaf(x, out var leaf) ? leaf.FullName() : x.Name.Text;
string path = _profileFileSystem.TryGetValue(x, out var leaf) ? leaf.FullName() : x.Name.Text;
var charactersList = new List<IPCCharacterDataTuple>(x.Characters.Count);
foreach (var character in x.Characters)

View File

@@ -147,6 +147,12 @@ public unsafe sealed class ArmatureManager : IDisposable
foreach (var obj in _objectManager)
{
var actorIdentifier = obj.Key.CreatePermanent();
//warn: in cutscenes the game creates a copy of your character and object #0,
//so we need to check if there is at least one object being rendered
if (obj.Value.Objects == null || obj.Value.Objects.Count == 0 || !obj.Value.Objects.Any(x => x.IsRenderedByGame()))
continue;
if (!Armatures.ContainsKey(actorIdentifier))
{
var activeProfile = _profileManager.GetEnabledProfilesByActor(actorIdentifier).FirstOrDefault();
@@ -173,7 +179,8 @@ public unsafe sealed class ArmatureManager : IDisposable
var activeProfile = _profileManager.GetEnabledProfilesByActor(actorIdentifier).FirstOrDefault();
Profile? oldProfile = armature.Profile;
if (activeProfile != armature.Profile)
bool profileChange = activeProfile != armature.Profile;
if (profileChange)
{
if (activeProfile == null)
{
@@ -197,11 +204,27 @@ public unsafe sealed class ArmatureManager : IDisposable
armature.RebuildBoneTemplateBinding();
//warn: might be a bit of a performance hit on profiles with a lot of templates/bones
//warn: this must be done after RebuildBoneTemplateBinding or it will not work
if (profileChange &&
oldProfile.Templates.Where(x => x.Bones.ContainsKey("n_root")).Any())
{
_logger.Debug($"Resetting root transform for {armature} because new profile doesn't have root edits");
if (obj.Value.Objects != null)
{
//Reset root translation
foreach (var actor in obj.Value.Objects)
ApplyRootTranslation(armature, actor, true);
}
}
_event.Invoke(ArmatureChanged.Type.Updated, armature, (activeProfile, oldProfile));
}
//Needed because skeleton sometimes appears to be not ready when armature is created
//and also because we want to keep armature up to date with any character skeleton changes
//Needed because:
//* Skeleton sometimes appears to be not ready when armature is created
//* We want to keep armature up to date with any character skeleton changes
TryLinkSkeleton(armature);
}
}
@@ -240,10 +263,10 @@ public unsafe sealed class ArmatureManager : IDisposable
/// </summary>
private bool TryLinkSkeleton(Armature armature)
{
if (!_objectManager.ContainsKey(armature.ActorIdentifier))
return false;
//we assume that all other objects are a copy of object #0
var actor = _objectManager[armature.ActorIdentifier].Objects[0];
if (!armature.IsBuilt || armature.IsSkeletonUpdated(actor.Model.AsCharacterBase))
@@ -329,7 +352,7 @@ public unsafe sealed class ArmatureManager : IDisposable
}
/// <summary>
/// Apply root bone translation. If reset = true then this will only reset translation if it was edited in supplied armature.
/// Apply root bone translation. If reset = true then this will forcibly reset translation to in-game value.
/// </summary>
private void ApplyRootTranslation(Armature arm, Actor actor, bool reset = false)
{
@@ -341,18 +364,18 @@ public unsafe sealed class ArmatureManager : IDisposable
var cBase = actor.Model.AsCharacterBase;
if (cBase != null)
{
//warn: hotpath for characters with n_root edits. IsApproximately might have some performance hit.
var rootBoneTransform = arm.GetAppliedBoneTransform("n_root");
if (rootBoneTransform == null ||
rootBoneTransform.Translation.IsApproximately(Vector3.Zero, 0.00001f))
return;
if (reset)
{
cBase->DrawObject.Object.Position = actor.AsObject->Position;
return;
}
//warn: hotpath for characters with n_root edits. IsApproximately might have some performance hit.
var rootBoneTransform = arm.GetAppliedBoneTransform("n_root");
if (rootBoneTransform == null ||
rootBoneTransform.Translation.IsApproximately(Vector3.Zero, 0.00001f))
return;
if (rootBoneTransform.Translation.X == 0 &&
rootBoneTransform.Translation.Y == 0 &&
rootBoneTransform.Translation.Z == 0)

View File

@@ -63,6 +63,18 @@ public class PluginConfiguration : IPluginConfiguration, ISavable
public bool IncognitoMode { get; set; } = false;
public float CurrentTemplateSelectorWidth { get; set; } = 200f;
public float TemplateSelectorMinimumScale { get; set; } = 0.1f;
public float TemplateSelectorMaximumScale { get; set; } = 0.5f;
public float CurrentProfileSelectorWidth { get; set; } = 200f;
public float ProfileSelectorMinimumScale { get; set; } = 0.1f;
public float ProfileSelectorMaximumScale { get; set; } = 0.5f;
public List<string> ViewedMessageWindows { get; set; } = new();
}

View File

@@ -81,6 +81,7 @@ internal static class Constants
/// <summary>
/// Movement hook address, used for position offset and other changes which cannot be done in main hook
/// Client::Game::Object::GameObject_UpdateVisualPosition
/// </summary>
public const string MovementHookAddress = "E8 ?? ?? ?? ?? 84 DB 74 3A";

View File

@@ -2,7 +2,6 @@
using Dalamud.Interface;
using Dalamud.Utility;
using Dalamud.Bindings.ImGui;
using System.Text;
namespace CustomizePlus.Core.Helpers;
@@ -67,21 +66,15 @@ public static class CtrlHelper
}
public static bool ArrowToggle(string label, ref bool value)
{//ImGuiNative.ArrowButton(label, value ? ImGuiDir.Down : ImGuiDir.Right);
unsafe // temporary fix
{
var toggled = ImGui.ArrowButton(label, value ? ImGuiDir.Down : ImGuiDir.Right);
if (toggled)
{
var utf8Label = Encoding.UTF8.GetBytes(label + "\0");
fixed (byte* labelPtr = utf8Label)
{
bool toggled = ImGuiNative.ArrowButton(labelPtr, value ? ImGuiDir.Down : ImGuiDir.Right) != 0;
if (toggled)
value = !value;
return value;
}
value = !value;
}
return value;
}
public static void AddHoverText(string text)

View File

@@ -25,7 +25,6 @@ using CustomizePlus.UI.Windows.MainWindow.Tabs.Debug;
using CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
using CustomizePlus.UI.Windows.MainWindow.Tabs.Templates;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.DependencyInjection;
using OtterGui.Classes;
using OtterGui.Log;
@@ -59,10 +58,10 @@ public static class ServiceManagerBuilder
.AddApi();
DalamudServices.AddServices(services, pi);
services.AddDalamudService<ISeStringEvaluator>(pi);
services.AddIServices(typeof(EquipItem).Assembly);
services.AddIServices(typeof(Plugin).Assembly);
services.AddIServices(typeof(CutsceneService).Assembly);
services.AddIServices(typeof(CutsceneService).Assembly);
services.AddIServices(typeof(ImRaii).Assembly);
services.CreateProvider();

View File

@@ -8,6 +8,8 @@ using OtterGui.Services;
namespace CustomizePlus.Core.Services.Dalamud;
#pragma warning disable SeStringEvaluator
public class DalamudServices
{
public static void AddServices(ServiceManager services, IDalamudPluginInterface pi)
@@ -27,6 +29,7 @@ public class DalamudServices
.AddDalamudService<IPluginLog>(pi)
.AddDalamudService<ITargetManager>(pi)
.AddDalamudService<INotificationManager>(pi)
.AddDalamudService<IContextMenu>(pi);
.AddDalamudService<IContextMenu>(pi)
.AddDalamudService<ISeStringEvaluator>(pi);
}
}

View File

@@ -25,7 +25,6 @@ public class HookingService : IDisposable
private readonly ProfileManager _profileManager;
private readonly ArmatureManager _armatureManager;
private readonly GameStateService _gameStateService;
private readonly DalamudBranchService _dalamudBranchService;
private readonly Logger _logger;
private Hook<RenderDelegate>? _renderManagerHook;
@@ -46,7 +45,6 @@ public class HookingService : IDisposable
ProfileManager profileManager,
ArmatureManager armatureManager,
GameStateService gameStateService,
DalamudBranchService dalamudBranchService,
Logger logger)
{
_configuration = configuration;
@@ -55,7 +53,6 @@ public class HookingService : IDisposable
_profileManager = profileManager;
_armatureManager = armatureManager;
_gameStateService = gameStateService;
_dalamudBranchService = dalamudBranchService;
_logger = logger;
ReloadHooks();
@@ -75,12 +72,6 @@ public class HookingService : IDisposable
RenderHookFailed = false;
MovementHookFailed = false;
if(!_dalamudBranchService.AllowPluginToRun)
{
_logger.Error("Not reloading hooks because the plugin is not allowed to run. (Branch Service)");
return;
}
try
{
if (_configuration.PluginEnabled)

View File

@@ -21,22 +21,18 @@ public class SupportLogBuilderService
private readonly ProfileManager _profileManager;
private readonly ArmatureManager _armatureManager;
private readonly IDalamudPluginInterface _dalamudPluginInterface;
private readonly DalamudBranchService _dalamudBranchService;
public SupportLogBuilderService(
PluginConfiguration configuration,
TemplateManager templateManager,
ProfileManager profileManager,
ArmatureManager armatureManager,
IDalamudPluginInterface dalamudPluginInterface,
DalamudBranchService dalamudBranchService)
IDalamudPluginInterface dalamudPluginInterface)
{
_configuration = configuration;
_templateManager = templateManager;
_profileManager = profileManager;
_armatureManager = armatureManager;
_dalamudPluginInterface = dalamudPluginInterface;
_dalamudBranchService = dalamudBranchService;
}
public string BuildSupportLog()
@@ -45,7 +41,6 @@ public class SupportLogBuilderService
sb.AppendLine("**Settings**");
sb.Append($"> **`Plugin Version: `** {VersionHelper.Version}\n");
sb.Append($"> **`Commit Hash: `** {ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}\n");
sb.Append($"> **`Dalamud Branch: `** {_dalamudBranchService.CurrentBranchName} ({_dalamudBranchService.CurrentBranch})\n");
sb.Append($"> **`Plugin enabled: `** {_configuration.PluginEnabled}\n");
sb.AppendLine("**Settings -> Editor Settings**");
sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacter.Incognito(null)}\n");

View File

@@ -12,18 +12,15 @@ public class UserNotifierService : IDisposable
{
private readonly IClientState _clientState;
private readonly ChatService _chatService;
private readonly DalamudBranchService _dalamudBranchService;
private readonly PopupSystem _popupSystem;
public UserNotifierService(
IClientState clientState,
ChatService chatService,
DalamudBranchService dalamudBranchService,
PopupSystem popupSystem)
{
_clientState = clientState;
_chatService = chatService;
_dalamudBranchService = dalamudBranchService;
_popupSystem = popupSystem;
NotifyUser(true);
@@ -46,17 +43,5 @@ public class UserNotifierService : IDisposable
if (VersionHelper.IsTesting)
_chatService.PrintInChat($"You are running testing version of Customize+! Some features like integration with other plugins might not function correctly.",
ChatService.ChatMessageColor.Warning);
if (!_dalamudBranchService.AllowPluginToRun)
{
_chatService.PrintInChat(DalamudBranchService.PluginDisabledMessage,
ChatService.ChatMessageColor.Error);
if (displayOptionalMessages)
{
if(_popupSystem.ShowPopup(PopupSystem.Messages.PluginDisabledNonReleaseDalamud))
UIGlobals.PlayChatSoundEffect(11);
}
}
}
}

View File

@@ -3,7 +3,7 @@
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
<PropertyGroup>
<AssemblyTitle>CustomizePlus</AssemblyTitle>
<Version>2.0.0.1</Version>
<Version>2.0.0.0</Version>
<Description>Customize+</Description>
<Copyright></Copyright>
<PackageProjectUrl>https://github.com/Aether-Tools/CustomizePlus</PackageProjectUrl>
@@ -36,10 +36,6 @@
<ProjectReference Include="..\CustomizePlus.GameData\CustomizePlus.GameData.csproj" />
<ProjectReference Include="..\submodules\ECommonsLite\ECommonsLite\ECommonsLite.csproj" />
<ProjectReference Include="..\submodules\OtterGui\OtterGui.csproj" />
<Reference Include="Dalamud.Bindings.ImGui">
<Private>false</Private>
<HintPath>$(DalamudLibPath)\Dalamud.Bindings.ImGui.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -48,10 +44,6 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Update="DalamudPackager" Version="13.0.0" />
</ItemGroup>
<!--<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>INCOGNIFY_STRINGS</DefineConstants>
</PropertyGroup>-->

View File

@@ -5,7 +5,7 @@
"Description": "A plugin that allows you to customize your character beyond FFXIV limitations by directly editing bone parameters.",
"InternalName": "CustomizePlus",
"ApplicableVersion": "any",
"AssemblyVersion": "2.0.0.1",
"AssemblyVersion": "2.0.0.0",
"DalamudApiLevel": 13,
"TestingDalamudApiLevel": 13,
"Tags": [

View File

@@ -46,15 +46,6 @@ public class ProfileFileSystem : FileSystem<Profile>, IDisposable, ISavable
_profileChanged.Unsubscribe(OnProfileChange);
}
// Search the entire filesystem for the leaf corresponding to a profile.
public bool FindLeaf(Profile profile, [NotNullWhen(true)] out Leaf? leaf)
{
leaf = Root.GetAllDescendants(ISortMode<Profile>.Lexicographical)
.OfType<Leaf>()
.FirstOrDefault(l => l.Value == profile);
return leaf != null;
}
private void OnProfileChange(ProfileChanged.Type type, Profile? profile, object? data)
{
switch (type)
@@ -75,14 +66,14 @@ public class ProfileFileSystem : FileSystem<Profile>, IDisposable, ISavable
return;
case ProfileChanged.Type.Deleted:
if (FindLeaf(profile, out var leaf1))
if (TryGetValue(profile, out var leaf1))
Delete(leaf1);
return;
case ProfileChanged.Type.ReloadedAll:
Reload();
return;
case ProfileChanged.Type.Renamed when data is string oldName:
if (!FindLeaf(profile, out var leaf2))
if (!TryGetValue(profile, out var leaf2))
return;
var old = oldName.FixName();

View File

@@ -47,15 +47,6 @@ public sealed class TemplateFileSystem : FileSystem<Template>, IDisposable, ISav
_templateChanged.Unsubscribe(OnTemplateChange);
}
// Search the entire filesystem for the leaf corresponding to a template.
public bool FindLeaf(Template template, [NotNullWhen(true)] out Leaf? leaf)
{
leaf = Root.GetAllDescendants(ISortMode<Template>.Lexicographical)
.OfType<Leaf>()
.FirstOrDefault(l => l.Value == template);
return leaf != null;
}
private void OnTemplateChange(TemplateChanged.Type type, Template? template, object? data)
{
switch (type)
@@ -76,14 +67,14 @@ public sealed class TemplateFileSystem : FileSystem<Template>, IDisposable, ISav
return;
case TemplateChanged.Type.Deleted:
if (FindLeaf(template, out var leaf1))
if (TryGetValue(template, out var leaf1))
Delete(leaf1);
return;
case TemplateChanged.Type.ReloadedAll:
Reload();
return;
case TemplateChanged.Type.Renamed when data is string oldName:
if (!FindLeaf(template, out var leaf2))
if (!TryGetValue(template, out var leaf2))
return;
var old = oldName.FixName();

View File

@@ -29,6 +29,7 @@ public class CPlusChangeLog
Add2_0_7_9(Changelog);
Add2_0_7_15(Changelog);
Add2_0_7_16(Changelog);
Add2_0_7_23(Changelog);
}
private (int, ChangeLogDisplayType) ConfigData()
@@ -41,6 +42,18 @@ public class CPlusChangeLog
_config.Save();
}
private static void Add2_0_7_23(Changelog log)
=> log.NextVersion("Version 2.0.7.23")
.RegisterImportant("Support for 7.3 and Dalamud API 13.")
.RegisterEntry("IPC version updated to 6.1. (2.0.7.20)")
.RegisterEntry("Added Profile.AddPlayerCharacter and Profile.RemovePlayerCharacter IPC endpoints. (by Caraxi)", 1)
.RegisterEntry("Left side selectors in \"Templates\" and \"Profiles\" tabs can now be resized.")
.RegisterEntry("Fixed crashes on login/logout.")
.RegisterEntry("This usually happened when when \"Apply Profiles on Character Select Screen\" and/or \"Automatically Set Current Character as Editor Preview Character\" options are enabled in settings.", 1)
.RegisterEntry("Fixed root transforms sometimes not resetting when toggling between profiles until character is moved.")
.RegisterEntry("Fixed an issue where profiles would attempt to be applied to objects not currently drawn on the screen.")
.RegisterEntry("Slight refactoring of user interface code.");
private static void Add2_0_7_16(Changelog log)
=> log.NextVersion("Version 2.0.7.16")
.RegisterImportant("Support for update 7.2 and Dalamud API 12.");

View File

@@ -20,22 +20,19 @@ public class PluginStateBlock
private readonly GameStateService _gameStateService;
private readonly HookingService _hookingService;
private readonly CustomizePlusIpc _ipcService;
private readonly DalamudBranchService _dalamudBranchService;
public PluginStateBlock(
BoneEditorPanel boneEditorPanel,
PluginConfiguration configuration,
GameStateService gameStateService,
HookingService hookingService,
CustomizePlusIpc ipcService,
DalamudBranchService dalamudBranchService)
CustomizePlusIpc ipcService)
{
_boneEditorPanel = boneEditorPanel;
_configuration = configuration;
_gameStateService = gameStateService;
_hookingService = hookingService;
_ipcService = ipcService;
_dalamudBranchService = dalamudBranchService;
}
public void Draw(float yPos)
@@ -79,12 +76,6 @@ public class PluginStateBlock
severity = PluginStateSeverity.Error;
message = "Detected failure in IPC. Integrations with other plugins will not function.";
}
else if (!_dalamudBranchService.AllowPluginToRun)
{
severity = PluginStateSeverity.Error;
message = "You are running unsupported version of Dalamud, hover for more information.";
hoverInfo = "Regular users are not supposed to run Customize+ on development or testing versions of Dalamud.\nThis is not supported and therefore Customize+ has disabled itself.";
}
else if(VersionHelper.IsTesting)
{
severity = PluginStateSeverity.Warning;

View File

@@ -15,6 +15,7 @@ using CustomizePlus.Profiles.Data;
using CustomizePlus.Templates.Events;
using CustomizePlus.Templates.Data;
using OtterGui.Extensions;
using OtterGui.Raii;
namespace CustomizePlus.UI.Windows.Controls;
@@ -23,6 +24,10 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
private readonly PluginConfiguration _configuration;
private readonly TemplateChanged _templateChanged;
// protected readonly TabSelected TabSelected;
private bool _isCurrentSelectionDirty;
private Template? _currentTemplate;
protected float InnerWidth;
protected TemplateComboBase(
@@ -47,31 +52,27 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
protected override bool DrawSelectable(int globalIdx, bool selected)
{
var ret = base.DrawSelectable(globalIdx, selected);
var (design, path) = Items[globalIdx];
if (path.Length > 0 && design.Name != path)
{
var start = ImGui.GetItemRectMin();
var pos = start.X + ImGui.CalcTextSize(design.Name.ToString()).X;
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
var remainingSpace = maxSize - pos;
var requiredSize = ImGui.CalcTextSize(path).X + ImGui.GetStyle().ItemInnerSpacing.X;
var offset = remainingSpace - requiredSize;
if (ImGui.GetScrollMaxY() == 0)
offset -= ImGui.GetStyle().ItemInnerSpacing.X;
if (offset < ImGui.GetStyle().ItemSpacing.X)
ImGuiUtil.HoverTooltip(path);
else
ImGui.GetWindowDrawList().AddText(start with { X = pos + offset },
ImGui.GetColorU32(ImGuiCol.TextDisabled), path);
}
var (template, path) = Items[globalIdx];
bool ret;
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.UsedTemplate.Value());
ret = base.DrawSelectable(globalIdx, selected);
DrawPath(path, template);
return ret;
}
private static void DrawPath(string path, Template template)
{
if (path.Length <= 0 || template.Name == path)
return;
DrawRightAligned(template.Name, path, ImGui.GetColorU32(ImGuiCol.TextDisabled));
}
protected bool Draw(Template? currentTemplate, string? label, float width)
{
_currentTemplate = currentTemplate;
UpdateCurrentSelection();
InnerWidth = 400 * ImGuiHelpers.GlobalScale;
CurrentSelectionIdx = Math.Max(Items.IndexOf(p => currentTemplate == p.Item1), 0);
CurrentSelection = Items[CurrentSelectionIdx];
@@ -79,9 +80,54 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
var ret = Draw("##template", name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing())
&& CurrentSelection != null;
_currentTemplate = null;
return ret;
}
protected override void OnMouseWheel(string preview, ref int _2, int steps)
{
if (!ReferenceEquals(_currentTemplate, CurrentSelection?.Item1))
CurrentSelectionIdx = -1;
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 => _currentTemplate == p.Item1);
UpdateSelection(CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : null);
return CurrentSelectionIdx;
}
protected override string ToString(Tuple<Template, string> obj)
=> obj.Item1.Name.Text;
@@ -96,22 +142,31 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
private void OnTemplateChange(TemplateChanged.Type type, Template template, object? data = null)
{
switch (type)
_isCurrentSelectionDirty = type switch
{
case TemplateChanged.Type.Created:
case TemplateChanged.Type.Renamed:
Cleanup();
break;
case TemplateChanged.Type.Deleted:
Cleanup();
if (CurrentSelection?.Item1 == template)
{
CurrentSelectionIdx = -1;
CurrentSelection = null;
}
TemplateChanged.Type.Created => true,
TemplateChanged.Type.Renamed => true,
TemplateChanged.Type.Deleted => true,
_ => _isCurrentSelectionDirty,
};
}
break;
}
private static void DrawRightAligned(string leftText, string text, uint color)
{
var start = ImGui.GetItemRectMin();
var pos = start.X + ImGui.CalcTextSize(leftText).X;
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
var remainingSpace = maxSize - pos;
var requiredSize = ImGui.CalcTextSize(text).X + ImGui.GetStyle().ItemInnerSpacing.X;
var offset = remainingSpace - requiredSize;
if (ImGui.GetScrollMaxY() == 0)
offset -= ImGui.GetStyle().ItemInnerSpacing.X;
if (offset < ImGui.GetStyle().ItemSpacing.X)
ImGuiUtil.HoverTooltip(text);
else
ImGui.GetWindowDrawList().AddText(start with { X = pos + offset },
color, text);
}
}
@@ -129,7 +184,7 @@ public sealed class TemplateCombo : TemplateComboBase
PluginConfiguration configuration)
: base(
() => templateManager.Templates
.Select(d => new Tuple<Template, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
.Select(d => new Tuple<Template, string>(d, fileSystem.TryGetValue(d, out var l) ? l.FullName() : string.Empty))
.OrderBy(d => d.Item2)
.ToList(), logger, templateChanged,/* tabSelected, */configuration)
{

View File

@@ -38,7 +38,6 @@ public class MainWindow : Window, IDisposable
private readonly TemplateEditorManager _templateEditorManager;
private readonly PluginConfiguration _configuration;
private readonly HookingService _hookingService;
private readonly DalamudBranchService _dalamudBranchService;
private readonly TemplateEditorEvent _templateEditorEvent;
@@ -61,7 +60,6 @@ public class MainWindow : Window, IDisposable
TemplateEditorManager templateEditorManager,
PluginConfiguration configuration,
HookingService hookingService,
DalamudBranchService dalamudBranchService,
TemplateEditorEvent templateEditorEvent
) : base($"Customize+ {VersionHelper.Version}###CPlusMainWindow")
{
@@ -77,7 +75,6 @@ public class MainWindow : Window, IDisposable
_templateEditorManager = templateEditorManager;
_configuration = configuration;
_hookingService = hookingService;
_dalamudBranchService = dalamudBranchService;
_templateEditorEvent = templateEditorEvent;
@@ -101,7 +98,7 @@ public class MainWindow : Window, IDisposable
{
var yPos = ImGui.GetCursorPosY();
using (var disabled = ImRaii.Disabled(_hookingService.RenderHookFailed || _hookingService.MovementHookFailed || !_dalamudBranchService.AllowPluginToRun))
using (var disabled = ImRaii.Disabled(_hookingService.RenderHookFailed || _hookingService.MovementHookFailed))
{
LockWindowClosureIfNeeded();
ImGuiEx.EzTabBar("##tabs", null, _switchToTab, [

View File

@@ -96,7 +96,7 @@ public class StateMonitoringTab
{
foreach (var kvPair in _objectManager)
{
var show = ImGui.CollapsingHeader($"{kvPair.Key} ({kvPair.Value.Objects.Count} objects)###object-{kvPair.Key}");
var show = ImGui.CollapsingHeader($"{kvPair.Key} ({kvPair.Value.Objects.Count} objects [{kvPair.Value.Objects.Count(x => x.IsRenderedByGame())} rendered])###object-{kvPair.Key}");
if (!show)
continue;
@@ -124,7 +124,7 @@ public class StateMonitoringTab
ImGui.Text($"Count: {kvPair.Value.Objects.Count}");
foreach (var item in kvPair.Value.Objects)
{
ImGui.Text($"[{item.Index}] - {item}, valid: {item.Valid}");
ImGui.Text($"[{item.Index}] - {item}, valid: {item.Valid}, rendered: {item.IsRenderedByGame()}");
}
ImGui.Spacing();

View File

@@ -1,24 +1,24 @@
using Dalamud.Interface;
using CustomizePlus.Configuration.Data;
using CustomizePlus.Game.Services;
using CustomizePlus.GameData.Extensions;
using CustomizePlus.Profiles;
using CustomizePlus.Profiles.Data;
using CustomizePlus.Profiles.Events;
using Dalamud.Interface;
using Dalamud.Plugin.Services;
using Dalamud.Bindings.ImGui;
using OtterGui.Classes;
using OtterGui.FileSystem.Selector;
using OtterGui.Filesystem;
using OtterGui.Log;
using OtterGui;
using System;
using static CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles.ProfileFileSystemSelector;
using OtterGui.Classes;
using OtterGui.Filesystem;
using OtterGui.FileSystem.Selector;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Text;
using System;
using System.Linq;
using System.Numerics;
using System.Reflection;
using CustomizePlus.Profiles;
using CustomizePlus.Configuration.Data;
using CustomizePlus.Profiles.Data;
using CustomizePlus.Game.Services;
using CustomizePlus.Profiles.Events;
using CustomizePlus.GameData.Extensions;
using System.Linq;
using OtterGui.Text;
using static CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles.ProfileFileSystemSelector;
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
@@ -48,18 +48,27 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
public ColorId Color;
}
protected override float CurrentWidth
=> _configuration.UISettings.CurrentProfileSelectorWidth * ImUtf8.GlobalScale;
protected override float MinimumAbsoluteRemainder
=> 670 * ImUtf8.GlobalScale;
=> 470 * ImUtf8.GlobalScale;
protected override float MinimumScaling
=> _configuration.UISettings.ProfileSelectorMinimumScale;
protected override float MaximumScaling
=> _configuration.UISettings.ProfileSelectorMaximumScale;
protected override void SetSize(Vector2 size)
{
base.SetSize(size);
var adaptedSize = MathF.Round(size.X / ImUtf8.GlobalScale);
if (adaptedSize == _configuration.UISettings.CurrentProfileSelectorWidth)
return;
_configuration.UISettings.CurrentProfileSelectorWidth = adaptedSize;
_configuration.Save();
}
public ProfileFileSystemSelector(

View File

@@ -20,7 +20,6 @@ using CustomizePlus.GameData.Extensions;
using CustomizePlus.Core.Extensions;
using Dalamud.Interface.Components;
using OtterGui.Extensions;
using OtterGui.Text;
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
@@ -68,7 +67,7 @@ public class ProfilePanel
public void Draw()
{
using var group = ImUtf8.Group();
using var group = ImRaii.Group();
if (_selector.SelectedPaths.Count > 1)
{
DrawMultiSelection();
@@ -194,7 +193,7 @@ public class ProfilePanel
{
using (var table = ImRaii.Table("BasicSettings", 2))
{
ImGui.TableSetupColumn("BasicCol1", ImGuiTableColumnFlags.WidthFixed, 200);
ImGui.TableSetupColumn("BasicCol1", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("lorem ipsum dolor").X);
ImGui.TableSetupColumn("BasicCol2", ImGuiTableColumnFlags.WidthStretch);
ImGuiUtil.DrawFrameColumn("Profile Name");
@@ -506,7 +505,7 @@ public class ProfilePanel
if (source)
{
ImGui.TextUnformatted($"Moving template #{index + 1:D2}...");
if (ImGui.SetDragDropPayload(dragDropLabel, ReadOnlySpan<byte>.Empty, 0))
if (ImGui.SetDragDropPayload(dragDropLabel, null, 0))
{
_dragIndex = index;
}

View File

@@ -368,10 +368,12 @@ public class SettingsTab
xPos -= ImGui.GetStyle().ScrollbarSize + ImGui.GetStyle().FramePadding.X;
ImGui.SetCursorPos(new Vector2(xPos, 0));
DrawUrlButton("Join Discord for Support", "https://discord.gg/KvGJCCnG8t", DiscordColor, width);
DrawUrlButton("Join Discord for Support", "https://discord.gg/KvGJCCnG8t", DiscordColor, width,
"Join Discord server run by community volunteers who can help you with your questions. Opens https://discord.gg/KvGJCCnG8t in your web browser.");
ImGui.SetCursorPos(new Vector2(xPos, ImGui.GetFrameHeightWithSpacing()));
DrawUrlButton("Support developer using Ko-fi", "https://ko-fi.com/risadev", DonateColor, width);
DrawUrlButton("Support developer using Ko-fi", "https://ko-fi.com/risadev", DonateColor, width,
"Any donations made are voluntary and treated as a token of gratitude for work done on Customize+. Opens https://ko-fi.com/risadev in your web browser.");
ImGui.SetCursorPos(new Vector2(xPos, 2 * ImGui.GetFrameHeightWithSpacing()));
if (ImGui.Button("Copy Support Info to Clipboard"))
@@ -387,7 +389,7 @@ public class SettingsTab
}
/// <summary> Draw a button to open some url. </summary>
private void DrawUrlButton(string text, string url, uint buttonColor, float width)
private void DrawUrlButton(string text, string url, uint buttonColor, float width, string? description = null)
{
using var color = ImRaii.PushColor(ImGuiCol.Button, buttonColor);
if (ImGui.Button(text, new Vector2(width, 0)))
@@ -404,7 +406,7 @@ public class SettingsTab
_messageService.NotificationMessage($"Unable to open url {url}.", NotificationType.Error, false);
}
ImGuiUtil.HoverTooltip($"Open {url}");
ImGuiUtil.HoverTooltip(description ?? $"Open {url}");
}
#endregion
}

View File

@@ -1,33 +1,33 @@
using Dalamud.Interface;
using CustomizePlus.Anamnesis;
using CustomizePlus.Configuration.Data;
using CustomizePlus.Configuration.Data.Version2;
using CustomizePlus.Configuration.Data.Version3;
using CustomizePlus.Configuration.Helpers;
using CustomizePlus.Core.Helpers;
using CustomizePlus.Profiles;
using CustomizePlus.Profiles.Data;
using CustomizePlus.Profiles.Events;
using CustomizePlus.Templates;
using CustomizePlus.Templates.Data;
using CustomizePlus.Templates.Events;
using Dalamud.Interface;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Plugin.Services;
using Dalamud.Bindings.ImGui;
using Newtonsoft.Json;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Filesystem;
using OtterGui.FileSystem.Selector;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Text;
using System;
using System.IO;
using System.Linq;
using System.Numerics;
using static CustomizePlus.UI.Windows.MainWindow.Tabs.Templates.TemplateFileSystemSelector;
using Newtonsoft.Json;
using System.Linq;
using Dalamud.Interface.ImGuiFileDialog;
using System.IO;
using CustomizePlus.Templates;
using CustomizePlus.Configuration.Data;
using CustomizePlus.Profiles;
using CustomizePlus.Core.Helpers;
using CustomizePlus.Anamnesis;
using CustomizePlus.Profiles.Data;
using CustomizePlus.Templates.Events;
using CustomizePlus.Profiles.Events;
using CustomizePlus.Templates.Data;
using CustomizePlus.Configuration.Helpers;
using CustomizePlus.Configuration.Data.Version3;
using CustomizePlus.Configuration.Data.Version2;
using Dalamud.Interface.ImGuiNotification;
using OtterGui.Text;
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Templates;
@@ -66,18 +66,29 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
public ColorId Color;
}
protected override float CurrentWidth
=> _configuration.UISettings.CurrentTemplateSelectorWidth * ImUtf8.GlobalScale;
protected override float MinimumAbsoluteRemainder
=> 670 * ImUtf8.GlobalScale;
=> 470 * ImUtf8.GlobalScale;
protected override float MinimumScaling
=> _configuration.UISettings.TemplateSelectorMinimumScale;
protected override float MaximumScaling
=> _configuration.UISettings.TemplateSelectorMaximumScale;
protected override void SetSize(Vector2 size)
{
base.SetSize(size);
var adaptedSize = MathF.Round(size.X / ImUtf8.GlobalScale);
if (adaptedSize == _configuration.UISettings.CurrentTemplateSelectorWidth)
return;
_configuration.UISettings.CurrentTemplateSelectorWidth = adaptedSize;
_configuration.Save();
}
public TemplateFileSystemSelector(
TemplateFileSystem fileSystem,
IKeyState keyState,
@@ -215,7 +226,6 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
}
}
private void DrawStealTemplatePopup()
{
if (!ImGuiUtil.OpenNameField("##StealTemplate", ref _newName))
@@ -230,7 +240,7 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
foreach (var template in profile.Templates)
{
if(profile.Characters.First().PlayerName.ToString().ToLower() == _playerNameSteal.ToLower())
if (profile.Characters.First().PlayerName.ToString().ToLower() == _playerNameSteal.ToLower())
{
var copiedTemplate = new Template(template);
_templateManager.Clone(copiedTemplate, _newName, true);
@@ -327,29 +337,6 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
ImGui.OpenPopup("##NewTemplate");
}
private void ClipboardImportButton(Vector2 size)
{
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), size, "Try to import a template from your clipboard.", false,
true))
return;
if (_editorManager.IsEditorActive)
{
ShowEditorWarningPopup();
return;
}
try
{
_clipboardText = ImGui.GetClipboardText();
ImGui.OpenPopup("##NewTemplate");
}
catch
{
_messageService.NotificationMessage("Could not import data from clipboard.", NotificationType.Error, false);
}
}
private void StealButton(Vector2 size)
{
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Baby.ToIconString(), size, "Steal from targeted player", false,
@@ -395,6 +382,29 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
}
}
private void ClipboardImportButton(Vector2 size)
{
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), size, "Try to import a template from your clipboard.", false,
true))
return;
if (_editorManager.IsEditorActive)
{
ShowEditorWarningPopup();
return;
}
try
{
_clipboardText = ImGui.GetClipboardText();
ImGui.OpenPopup("##NewTemplate");
}
catch
{
_messageService.NotificationMessage("Could not import data from clipboard.", NotificationType.Error, false);
}
}
private void AnamnesisImportButton(Vector2 size)
{
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.FileImport.ToIconString(), size, "Import a template from anamnesis pose file (scaling only)", false,

View File

@@ -49,7 +49,5 @@ public partial class PopupSystem
RegisterPopup(Messages.ClipboardDataUnsupported, "Clipboard data you are trying to use cannot be used in this version of Customize+.");
RegisterPopup(Messages.ClipboardDataNotLongTerm, "Warning: clipboard data is not designed to be used as long-term way of storing your templates.\nCompatibility of copied data between different Customize+ versions is not guaranteed.", true, new Vector2(5, 10));
RegisterPopup(Messages.PluginDisabledNonReleaseDalamud, DalamudBranchService.PluginDisabledMessage + "\nThis notification will not be shown again.", true, new Vector2(5, 6));
}
}