More work on profile character assignment rewrite.
Added ability to apply profile to any currently logged in character Functional UI for player character, retainers and mannequins Almost completely switched to using ActorIdentifier instead of character name Migration code for ActorIdentifier instead of character names IPC is not functional for now (see todos)
This commit is contained in:
@@ -46,7 +46,7 @@ public partial class CustomizePlusIpc
|
|||||||
.Select(x =>
|
.Select(x =>
|
||||||
{
|
{
|
||||||
string path = _profileFileSystem.FindLeaf(x, out var leaf) ? leaf.FullName() : x.Name.Text;
|
string path = _profileFileSystem.FindLeaf(x, out var leaf) ? leaf.FullName() : x.Name.Text;
|
||||||
return (x.UniqueId, x.Name.Text, path, x.CharacterName.Text, x.Enabled);
|
return (x.UniqueId, x.Name.Text, path, x.Character.ToNameWithoutOwnerName(), x.Enabled); //todo: proper update to v5
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ public partial class CustomizePlusIpc
|
|||||||
if (actor == null || !actor.Value.Valid || !actor.Value.IsCharacter)
|
if (actor == null || !actor.Value.Valid || !actor.Value.IsCharacter)
|
||||||
return ((int)ErrorCode.InvalidCharacter, null);
|
return ((int)ErrorCode.InvalidCharacter, null);
|
||||||
|
|
||||||
var profile = _profileManager.GetProfileByCharacterName(actor.Value.Utf8Name.ToString(), true);
|
var profile = _profileManager.GetProfileByActor(actor.Value, true);
|
||||||
|
|
||||||
if (profile == null)
|
if (profile == null)
|
||||||
return ((int)ErrorCode.ProfileNotFound, null);
|
return ((int)ErrorCode.ProfileNotFound, null);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using CustomizePlus.Configuration.Data.Version3;
|
using CustomizePlus.Configuration.Data.Version3;
|
||||||
using CustomizePlus.Core.Data;
|
using CustomizePlus.Core.Data;
|
||||||
|
using CustomizePlus.GameData.Extensions;
|
||||||
using CustomizePlus.Profiles.Data;
|
using CustomizePlus.Profiles.Data;
|
||||||
using CustomizePlus.Templates.Data;
|
using CustomizePlus.Templates.Data;
|
||||||
using System;
|
using System;
|
||||||
@@ -23,7 +24,7 @@ public class IPCCharacterProfile
|
|||||||
{
|
{
|
||||||
var ipcProfile = new IPCCharacterProfile
|
var ipcProfile = new IPCCharacterProfile
|
||||||
{
|
{
|
||||||
CharacterName = profile.CharacterName,
|
CharacterName = profile.Character.ToNameWithoutOwnerName(), //todo: proper update to v5
|
||||||
Bones = new Dictionary<string, IPCBoneTransform>()
|
Bones = new Dictionary<string, IPCBoneTransform>()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ public class IPCCharacterProfile
|
|||||||
var fullProfile = new Profile
|
var fullProfile = new Profile
|
||||||
{
|
{
|
||||||
Name = $"{profile.CharacterName}'s IPC profile",
|
Name = $"{profile.CharacterName}'s IPC profile",
|
||||||
CharacterName = profile.CharacterName,
|
// CharacterName = profile.CharacterName, //todo: proper update to v5
|
||||||
CreationDate = DateTimeOffset.UtcNow,
|
CreationDate = DateTimeOffset.UtcNow,
|
||||||
ModifiedDate = DateTimeOffset.UtcNow,
|
ModifiedDate = DateTimeOffset.UtcNow,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
|||||||
@@ -443,9 +443,10 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
type is not ProfileChanged.Type.Deleted &&
|
type is not ProfileChanged.Type.Deleted &&
|
||||||
type is not ProfileChanged.Type.TemporaryProfileAdded &&
|
type is not ProfileChanged.Type.TemporaryProfileAdded &&
|
||||||
type is not ProfileChanged.Type.TemporaryProfileDeleted &&
|
type is not ProfileChanged.Type.TemporaryProfileDeleted &&
|
||||||
type is not ProfileChanged.Type.ChangedCharacterName &&
|
type is not ProfileChanged.Type.ChangedCharacter &&
|
||||||
type is not ProfileChanged.Type.ChangedDefaultProfile &&
|
type is not ProfileChanged.Type.ChangedDefaultProfile &&
|
||||||
type is not ProfileChanged.Type.LimitLookupToOwnedChanged)
|
type is not ProfileChanged.Type.LimitLookupToOwnedChanged &&
|
||||||
|
type is not ProfileChanged.Type.ApplyToCurrentlyActiveCharacterChanged)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (type == ProfileChanged.Type.ChangedDefaultProfile)
|
if (type == ProfileChanged.Type.ChangedDefaultProfile)
|
||||||
@@ -488,10 +489,10 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(profile.CharacterName))
|
if (!profile.Character.IsValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var armature in GetArmaturesForCharacterName(profile.CharacterName))
|
foreach (var armature in GetArmaturesForCharacter(profile.Character))
|
||||||
{
|
{
|
||||||
armature.IsPendingProfileRebind = true;
|
armature.IsPendingProfileRebind = true;
|
||||||
_logger.Debug($"ArmatureManager.OnProfileChange profile {profile} toggled, planning rebind for armature {armature}");
|
_logger.Debug($"ArmatureManager.OnProfileChange profile {profile} toggled, planning rebind for armature {armature}");
|
||||||
@@ -502,10 +503,10 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
|
|
||||||
if (type == ProfileChanged.Type.TemporaryProfileAdded)
|
if (type == ProfileChanged.Type.TemporaryProfileAdded)
|
||||||
{
|
{
|
||||||
if (!profile.TemporaryActor.IsValid || !Armatures.ContainsKey(profile.TemporaryActor))
|
if (!profile.Character.IsValid || !Armatures.ContainsKey(profile.Character)) //todo: any world support
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var armature = Armatures[profile.TemporaryActor];
|
var armature = Armatures[profile.Character];
|
||||||
if (armature.Profile == profile)
|
if (armature.Profile == profile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -518,10 +519,11 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ProfileChanged.Type.ChangedCharacterName ||
|
if (type == ProfileChanged.Type.ChangedCharacter ||
|
||||||
type == ProfileChanged.Type.Deleted ||
|
type == ProfileChanged.Type.Deleted ||
|
||||||
type == ProfileChanged.Type.TemporaryProfileDeleted ||
|
type == ProfileChanged.Type.TemporaryProfileDeleted ||
|
||||||
type == ProfileChanged.Type.LimitLookupToOwnedChanged)
|
type == ProfileChanged.Type.LimitLookupToOwnedChanged ||
|
||||||
|
type == ProfileChanged.Type.ApplyToCurrentlyActiveCharacterChanged)
|
||||||
{
|
{
|
||||||
if (profile.Armatures.Count == 0)
|
if (profile.Armatures.Count == 0)
|
||||||
return;
|
return;
|
||||||
@@ -534,7 +536,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
armature.IsPendingProfileRebind = true;
|
armature.IsPendingProfileRebind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug($"ArmatureManager.OnProfileChange CCN/DEL/TPD/LLTOC, armature rebind scheduled: {type}, data payload: {arg3?.ToString()?.Incognify()}, profile: {profile.Name.Text.Incognify()}->{profile.Enabled}");
|
_logger.Debug($"ArmatureManager.OnProfileChange CC/DEL/TPD/LLTOC/ATCACC, armature rebind scheduled: {type}, data payload: {arg3?.ToString()?.Incognify()}, profile: {profile.Name.Text.Incognify()}->{profile.Enabled}");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -558,4 +560,15 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
yield return kvPair.Value;
|
yield return kvPair.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Armature> GetArmaturesForCharacter(ActorIdentifier actorIdentifier)
|
||||||
|
{
|
||||||
|
foreach (var kvPair in Armatures)
|
||||||
|
{
|
||||||
|
(var armatureActorIdentifier, _) = _gameObjectService.GetTrueActorForSpecialTypeActor(kvPair.Key);
|
||||||
|
|
||||||
|
if (armatureActorIdentifier.IsValid && armatureActorIdentifier.Matches(armatureActorIdentifier))
|
||||||
|
yield return kvPair.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,8 @@ public static class ServiceManagerBuilder
|
|||||||
.AddSingleton<CutsceneService>()
|
.AddSingleton<CutsceneService>()
|
||||||
.AddSingleton<GameEventManager>()
|
.AddSingleton<GameEventManager>()
|
||||||
.AddSingleton(p => new CutsceneResolver(idx => (short)p.GetRequiredService<CutsceneService>().GetParentIndex(idx)))
|
.AddSingleton(p => new CutsceneResolver(idx => (short)p.GetRequiredService<CutsceneService>().GetParentIndex(idx)))
|
||||||
.AddSingleton<ObjectManager>();
|
.AddSingleton<ObjectManager>()
|
||||||
|
.AddSingleton< DictBNpcENpc>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ public class GameObjectService
|
|||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActorIdentifier GetCurrentPlayerActorIdentifier()
|
||||||
|
{
|
||||||
|
return _objectManager.PlayerData.Identifier;
|
||||||
|
}
|
||||||
|
|
||||||
public string GetCurrentPlayerName()
|
public string GetCurrentPlayerName()
|
||||||
{
|
{
|
||||||
return _objectManager.PlayerData.Identifier.ToName();
|
return _objectManager.PlayerData.Identifier.ToName();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace CustomizePlus.Profiles.Data;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Profile : ISavable
|
public sealed class Profile : ISavable
|
||||||
{
|
{
|
||||||
public const int Version = 4;
|
public const int Version = 5;
|
||||||
|
|
||||||
private static int _nextGlobalId;
|
private static int _nextGlobalId;
|
||||||
|
|
||||||
@@ -29,10 +29,11 @@ public sealed class Profile : ISavable
|
|||||||
|
|
||||||
public List<Armature> Armatures = new();
|
public List<Armature> Armatures = new();
|
||||||
|
|
||||||
[Obsolete("To be removed")]
|
[Obsolete("To be removed in the future versions")]
|
||||||
public LowerString CharacterName { get; set; } = LowerString.Empty;
|
public LowerString CharacterName { get; set; } = LowerString.Empty;
|
||||||
|
|
||||||
public ActorIdentifier Character { get; set; } = ActorIdentifier.Invalid;
|
public ActorIdentifier Character { get; set; } = ActorIdentifier.Invalid;
|
||||||
|
public bool ApplyToCurrentlyActiveCharacter { get; set; }
|
||||||
|
|
||||||
public LowerString Name { get; set; } = LowerString.Empty;
|
public LowerString Name { get; set; } = LowerString.Empty;
|
||||||
|
|
||||||
@@ -59,10 +60,10 @@ public sealed class Profile : ISavable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsTemporary => ProfileType == ProfileType.Temporary;
|
public bool IsTemporary => ProfileType == ProfileType.Temporary;
|
||||||
|
|
||||||
/// <summary>
|
/* /// <summary>
|
||||||
/// Identificator specifying specific actor this profile applies to, only works for temporary profiles
|
/// Identificator specifying specific actor this profile applies to, only works for temporary profiles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ActorIdentifier TemporaryActor { get; set; } = ActorIdentifier.Invalid;
|
public ActorIdentifier TemporaryActor { get; set; } = ActorIdentifier.Invalid;*/
|
||||||
|
|
||||||
public string Incognito
|
public string Incognito
|
||||||
=> UniqueId.ToString()[..8];
|
=> UniqueId.ToString()[..8];
|
||||||
@@ -78,8 +79,9 @@ public sealed class Profile : ISavable
|
|||||||
/// <param name="original"></param>
|
/// <param name="original"></param>
|
||||||
public Profile(Profile original) : this()
|
public Profile(Profile original) : this()
|
||||||
{
|
{
|
||||||
CharacterName = original.CharacterName;
|
Character = original.Character;
|
||||||
LimitLookupToOwnedObjects = original.LimitLookupToOwnedObjects;
|
LimitLookupToOwnedObjects = original.LimitLookupToOwnedObjects;
|
||||||
|
ApplyToCurrentlyActiveCharacter = original.ApplyToCurrentlyActiveCharacter;
|
||||||
|
|
||||||
foreach (var template in original.Templates)
|
foreach (var template in original.Templates)
|
||||||
{
|
{
|
||||||
@@ -89,7 +91,7 @@ public sealed class Profile : ISavable
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Profile '{Name.Text.Incognify()}' on {CharacterName.Text.Incognify()} [{UniqueId}]";
|
return $"Profile '{Name.Text.Incognify()}' on {Character.Incognito(null)} [{UniqueId}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Serialization
|
#region Serialization
|
||||||
@@ -103,7 +105,8 @@ public sealed class Profile : ISavable
|
|||||||
["CreationDate"] = CreationDate,
|
["CreationDate"] = CreationDate,
|
||||||
["ModifiedDate"] = ModifiedDate,
|
["ModifiedDate"] = ModifiedDate,
|
||||||
["CharacterName"] = CharacterName.Text,
|
["CharacterName"] = CharacterName.Text,
|
||||||
//["Character"] = Character.ToJson(),
|
["Character"] = Character.ToJson(),
|
||||||
|
["ApplyToCurrentlyActiveCharacter"] = ApplyToCurrentlyActiveCharacter,
|
||||||
["Name"] = Name.Text,
|
["Name"] = Name.Text,
|
||||||
["LimitLookupToOwnedObjects"] = LimitLookupToOwnedObjects,
|
["LimitLookupToOwnedObjects"] = LimitLookupToOwnedObjects,
|
||||||
["Enabled"] = Enabled,
|
["Enabled"] = Enabled,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public sealed class ProfileChanged() : EventWrapper<ProfileChanged.Type, Profile
|
|||||||
Deleted,
|
Deleted,
|
||||||
Renamed,
|
Renamed,
|
||||||
Toggled,
|
Toggled,
|
||||||
ChangedCharacterName,
|
ChangedCharacter,
|
||||||
AddedTemplate,
|
AddedTemplate,
|
||||||
RemovedTemplate,
|
RemovedTemplate,
|
||||||
MovedTemplate,
|
MovedTemplate,
|
||||||
@@ -23,6 +23,7 @@ public sealed class ProfileChanged() : EventWrapper<ProfileChanged.Type, Profile
|
|||||||
ReloadedAll,
|
ReloadedAll,
|
||||||
WriteProtection,
|
WriteProtection,
|
||||||
LimitLookupToOwnedChanged,
|
LimitLookupToOwnedChanged,
|
||||||
|
ApplyToCurrentlyActiveCharacterChanged,
|
||||||
ChangedDefaultProfile,
|
ChangedDefaultProfile,
|
||||||
TemporaryProfileAdded,
|
TemporaryProfileAdded,
|
||||||
TemporaryProfileDeleted,
|
TemporaryProfileDeleted,
|
||||||
|
|||||||
@@ -81,46 +81,44 @@ public partial class ProfileManager : IDisposable
|
|||||||
return version switch
|
return version switch
|
||||||
{
|
{
|
||||||
//Ignore everything below v4
|
//Ignore everything below v4
|
||||||
// 4 => LoadV4(obj),
|
4 => LoadV4(obj),
|
||||||
// 5 => LoadV5(obj),
|
5 => LoadV5(obj),
|
||||||
4 => LoadV5(obj),
|
|
||||||
_ => throw new Exception("The profile to be loaded has no valid Version."),
|
_ => throw new Exception("The profile to be loaded has no valid Version."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Profile LoadV4(JObject obj)
|
private Profile LoadV4(JObject obj)
|
||||||
{
|
{
|
||||||
var characterName = new LowerString(obj["CharacterName"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("CharacterName"));
|
var profile = LoadProfileV4V5(obj);
|
||||||
|
|
||||||
ByteString.FromString(characterName, out var nameByteString);
|
profile.CharacterName = new LowerString(obj["CharacterName"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("CharacterName"));
|
||||||
var character = _actorManager.CreatePlayer(nameByteString, WorldId.AnyWorld); //todo: detect type
|
|
||||||
|
|
||||||
obj["Character"] = character.ToJson();
|
|
||||||
|
|
||||||
var profile = LoadV5(obj);
|
|
||||||
|
|
||||||
profile.ModifiedDate = DateTimeOffset.UtcNow;
|
|
||||||
_saveService.ImmediateSave(profile);
|
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Profile LoadV5(JObject obj)
|
private Profile LoadV5(JObject obj)
|
||||||
|
{
|
||||||
|
var profile = LoadProfileV4V5(obj);
|
||||||
|
|
||||||
|
var character = _actorManager.FromJson(obj["Character"] as JObject);
|
||||||
|
|
||||||
|
profile.Character = character;
|
||||||
|
profile.ApplyToCurrentlyActiveCharacter = obj["ApplyToCurrentlyActiveCharacter"]?.ToObject<bool>() ?? false;
|
||||||
|
profile.CharacterName = new LowerString(obj["CharacterName"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("CharacterName")); //temp
|
||||||
|
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
//V4 and V5 are mostly not different, so common loading logic is here
|
||||||
|
private Profile LoadProfileV4V5(JObject obj)
|
||||||
{
|
{
|
||||||
var creationDate = obj["CreationDate"]?.ToObject<DateTimeOffset>() ?? throw new ArgumentNullException("CreationDate");
|
var creationDate = obj["CreationDate"]?.ToObject<DateTimeOffset>() ?? throw new ArgumentNullException("CreationDate");
|
||||||
|
|
||||||
/*var character = _actorManager.FromJson(obj["Character"] as JObject);
|
|
||||||
|
|
||||||
if (!character.IsValid)
|
|
||||||
throw new ArgumentException("Character");*/
|
|
||||||
|
|
||||||
var profile = new Profile()
|
var profile = new Profile()
|
||||||
{
|
{
|
||||||
CreationDate = creationDate,
|
CreationDate = creationDate,
|
||||||
UniqueId = obj["UniqueId"]?.ToObject<Guid>() ?? throw new ArgumentNullException("UniqueId"),
|
UniqueId = obj["UniqueId"]?.ToObject<Guid>() ?? throw new ArgumentNullException("UniqueId"),
|
||||||
Name = new LowerString(obj["Name"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("Name")),
|
Name = new LowerString(obj["Name"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("Name")),
|
||||||
//Character = character,
|
|
||||||
CharacterName = new LowerString(obj["CharacterName"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("CharacterName")),
|
|
||||||
LimitLookupToOwnedObjects = obj["LimitLookupToOwnedObjects"]?.ToObject<bool>() ?? throw new ArgumentNullException("LimitLookupToOwnedObjects"),
|
LimitLookupToOwnedObjects = obj["LimitLookupToOwnedObjects"]?.ToObject<bool>() ?? throw new ArgumentNullException("LimitLookupToOwnedObjects"),
|
||||||
Enabled = obj["Enabled"]?.ToObject<bool>() ?? throw new ArgumentNullException("Enabled"),
|
Enabled = obj["Enabled"]?.ToObject<bool>() ?? throw new ArgumentNullException("Enabled"),
|
||||||
ModifiedDate = obj["ModifiedDate"]?.ToObject<DateTimeOffset>() ?? creationDate,
|
ModifiedDate = obj["ModifiedDate"]?.ToObject<DateTimeOffset>() ?? creationDate,
|
||||||
|
|||||||
@@ -168,26 +168,24 @@ public partial class ProfileManager : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change character name for profile
|
/// Change character associated with profile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ChangeCharacterName(Profile profile, string newName)
|
public void ChangeCharacter(Profile profile, ActorIdentifier actorIdentifier)
|
||||||
{
|
{
|
||||||
newName = newName.Trim();
|
if (!actorIdentifier.IsValid || actorIdentifier.Matches(profile.Character))
|
||||||
|
|
||||||
var oldName = profile.CharacterName.Text;
|
|
||||||
if (oldName == newName)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
profile.CharacterName = newName;
|
var oldCharacter = profile.Character;
|
||||||
|
profile.Character = actorIdentifier;
|
||||||
|
|
||||||
//Called so all other active profiles for new character name get disabled
|
//Called so all other active profiles for new character name get disabled
|
||||||
//saving is performed there
|
//saving is performed there
|
||||||
SetEnabled(profile, profile.Enabled, true);
|
//SetEnabled(profile, profile.Enabled, true); //todo
|
||||||
|
|
||||||
SaveProfile(profile);
|
SaveProfile(profile);
|
||||||
|
|
||||||
_logger.Debug($"Changed character name for profile {profile.UniqueId}.");
|
_logger.Debug($"Changed character for profile {profile.UniqueId}.");
|
||||||
_event.Invoke(ProfileChanged.Type.ChangedCharacterName, profile, oldName);
|
_event.Invoke(ProfileChanged.Type.ChangedCharacter, profile, oldCharacter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -229,7 +227,7 @@ public partial class ProfileManager : IDisposable
|
|||||||
_logger.Debug($"Setting {profile} as enabled...");
|
_logger.Debug($"Setting {profile} as enabled...");
|
||||||
|
|
||||||
foreach (var otherProfile in Profiles
|
foreach (var otherProfile in Profiles
|
||||||
.Where(x => x.CharacterName == profile.CharacterName && x != profile && x.Enabled && !x.IsTemporary))
|
.Where(x => x.Character.Matches(profile.Character) && x != profile && x.Enabled && !x.IsTemporary))
|
||||||
{
|
{
|
||||||
_logger.Debug($"\t-> {otherProfile} disabled");
|
_logger.Debug($"\t-> {otherProfile} disabled");
|
||||||
SetEnabled(otherProfile, false);
|
SetEnabled(otherProfile, false);
|
||||||
@@ -268,6 +266,18 @@ public partial class ProfileManager : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetApplyToCurrentlyActiveCharacter(Profile profile, bool value)
|
||||||
|
{
|
||||||
|
if (profile.ApplyToCurrentlyActiveCharacter != value)
|
||||||
|
{
|
||||||
|
profile.ApplyToCurrentlyActiveCharacter = value;
|
||||||
|
|
||||||
|
SaveProfile(profile);
|
||||||
|
|
||||||
|
_event.Invoke(ProfileChanged.Type.ApplyToCurrentlyActiveCharacterChanged, profile, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteTemplate(Profile profile, int templateIndex)
|
public void DeleteTemplate(Profile profile, int templateIndex)
|
||||||
{
|
{
|
||||||
_logger.Debug($"Deleting template #{templateIndex} from {profile}...");
|
_logger.Debug($"Deleting template #{templateIndex} from {profile}...");
|
||||||
@@ -342,6 +352,7 @@ public partial class ProfileManager : IDisposable
|
|||||||
_event.Invoke(ProfileChanged.Type.ChangedDefaultProfile, profile, previousProfile);
|
_event.Invoke(ProfileChanged.Type.ChangedDefaultProfile, profile, previousProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//warn: temporary profile system does not support any world identifiers
|
||||||
public void AddTemporaryProfile(Profile profile, Actor actor/*, Template template*/)
|
public void AddTemporaryProfile(Profile profile, Actor actor/*, Template template*/)
|
||||||
{
|
{
|
||||||
if (!actor.Identifier(_actorManager, out var identifier))
|
if (!actor.Identifier(_actorManager, out var identifier))
|
||||||
@@ -349,14 +360,13 @@ public partial class ProfileManager : IDisposable
|
|||||||
|
|
||||||
profile.Enabled = true;
|
profile.Enabled = true;
|
||||||
profile.ProfileType = ProfileType.Temporary;
|
profile.ProfileType = ProfileType.Temporary;
|
||||||
profile.TemporaryActor = identifier;
|
profile.Character = identifier;
|
||||||
profile.CharacterName = identifier.ToNameWithoutOwnerName();
|
|
||||||
profile.LimitLookupToOwnedObjects = false;
|
profile.LimitLookupToOwnedObjects = false;
|
||||||
|
|
||||||
var existingProfile = Profiles.FirstOrDefault(x => x.CharacterName.Lower == profile.CharacterName.Lower && x.IsTemporary);
|
var existingProfile = Profiles.FirstOrDefault(x => x.Character.Matches(profile.Character) && x.IsTemporary);
|
||||||
if (existingProfile != null)
|
if (existingProfile != null)
|
||||||
{
|
{
|
||||||
_logger.Debug($"Temporary profile for {existingProfile.CharacterName} already exists, removing...");
|
_logger.Debug($"Temporary profile for {existingProfile.Character.Incognito(null)} already exists, removing...");
|
||||||
Profiles.Remove(existingProfile);
|
Profiles.Remove(existingProfile);
|
||||||
_event.Invoke(ProfileChanged.Type.TemporaryProfileDeleted, existingProfile, null);
|
_event.Invoke(ProfileChanged.Type.TemporaryProfileDeleted, existingProfile, null);
|
||||||
}
|
}
|
||||||
@@ -375,7 +385,7 @@ public partial class ProfileManager : IDisposable
|
|||||||
if (!Profiles.Remove(profile))
|
if (!Profiles.Remove(profile))
|
||||||
throw new ProfileNotFoundException();
|
throw new ProfileNotFoundException();
|
||||||
|
|
||||||
_logger.Debug($"Removed temporary profile for {profile.CharacterName}");
|
_logger.Debug($"Removed temporary profile for {profile.Character.Incognito(null)}");
|
||||||
|
|
||||||
_event.Invoke(ProfileChanged.Type.TemporaryProfileDeleted, profile, null);
|
_event.Invoke(ProfileChanged.Type.TemporaryProfileDeleted, profile, null);
|
||||||
}
|
}
|
||||||
@@ -394,7 +404,7 @@ public partial class ProfileManager : IDisposable
|
|||||||
if (!actor.Identifier(_actorManager, out var identifier))
|
if (!actor.Identifier(_actorManager, out var identifier))
|
||||||
throw new ActorNotFoundException();
|
throw new ActorNotFoundException();
|
||||||
|
|
||||||
var profile = Profiles.FirstOrDefault(x => x.TemporaryActor == identifier && x.IsTemporary);
|
var profile = Profiles.FirstOrDefault(x => x.Character == identifier && x.IsTemporary);
|
||||||
if (profile == null)
|
if (profile == null)
|
||||||
throw new ProfileNotFoundException();
|
throw new ProfileNotFoundException();
|
||||||
|
|
||||||
@@ -402,17 +412,16 @@ public partial class ProfileManager : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return profile by character name, does not return temporary profiles
|
/// Return profile by actor identifier, does not return temporary profiles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"></param>
|
public Profile? GetProfileByActor(Actor actor, bool enabledOnly = false)
|
||||||
/// <param name="enabledOnly"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Profile? GetProfileByCharacterName(string name, bool enabledOnly = false)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
var actorIdentifier = actor.GetIdentifier(_actorManager);
|
||||||
|
|
||||||
|
if (!actorIdentifier.IsValid)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var query = Profiles.Where(x => x.CharacterName == name);
|
var query = Profiles.Where(x => x.Character.Matches(actorIdentifier) && !x.IsTemporary);
|
||||||
if (enabledOnly)
|
if (enabledOnly)
|
||||||
query = query.Where(x => x.Enabled);
|
query = query.Where(x => x.Enabled);
|
||||||
|
|
||||||
@@ -447,7 +456,16 @@ public partial class ProfileManager : IDisposable
|
|||||||
if (profile == DefaultProfile)
|
if (profile == DefaultProfile)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return profile.CharacterName.Text == name &&
|
if (profile.ApplyToCurrentlyActiveCharacter)
|
||||||
|
{
|
||||||
|
if (_objectManager.IsInLobby)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var currentPlayer = _actorManager.GetCurrentPlayer();
|
||||||
|
return currentPlayer.IsValid && _actorManager.GetCurrentPlayer().Matches(actorIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (profile.CharacterName.Text == name || profile.Character.Matches(actorIdentifier)) &&
|
||||||
(!profile.LimitLookupToOwnedObjects ||
|
(!profile.LimitLookupToOwnedObjects ||
|
||||||
(actorIdentifier.Type == IdentifierType.Owned &&
|
(actorIdentifier.Type == IdentifierType.Owned &&
|
||||||
actorIdentifier.PlayerName == _actorManager.GetCurrentPlayer().PlayerName));
|
actorIdentifier.PlayerName == _actorManager.GetCurrentPlayer().PlayerName));
|
||||||
@@ -458,9 +476,20 @@ public partial class ProfileManager : IDisposable
|
|||||||
|
|
||||||
foreach (var profile in Profiles)
|
foreach (var profile in Profiles)
|
||||||
{
|
{
|
||||||
if (IsProfileAppliesToCurrentActor(profile) && profile.Enabled)
|
if(IsProfileAppliesToCurrentActor(profile))
|
||||||
|
{
|
||||||
|
//todo: temp for migrations to v5
|
||||||
|
if (!profile.Character.IsValid)
|
||||||
|
{
|
||||||
|
_logger.Warning($"No character for profile {profile}, but character has been found as: {actorIdentifier}, will set.");
|
||||||
|
profile.Character = actorIdentifier;
|
||||||
|
_saveService.QueueSave(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile.Enabled)
|
||||||
yield return profile;
|
yield return profile;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (DefaultProfile != null &&
|
if (DefaultProfile != null &&
|
||||||
DefaultProfile.Enabled &&
|
DefaultProfile.Enabled &&
|
||||||
@@ -553,7 +582,7 @@ public partial class ProfileManager : IDisposable
|
|||||||
if (!Profiles.Remove(profile))
|
if (!Profiles.Remove(profile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_logger.Debug($"ProfileManager.OnArmatureChange: Removed unused temporary profile for {profile.CharacterName}");
|
_logger.Debug($"ProfileManager.OnArmatureChange: Removed unused temporary profile for {profile.Character.Incognito(null)}");
|
||||||
|
|
||||||
_event.Invoke(ProfileChanged.Type.TemporaryProfileDeleted, profile, null);
|
_event.Invoke(ProfileChanged.Type.TemporaryProfileDeleted, profile, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,67 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using System;
|
||||||
using ImGuiNET;
|
using System.Collections.Frozen;
|
||||||
using OtterGui.Custom;
|
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
using Penumbra.GameData.Enums;
|
|
||||||
using Penumbra.GameData.Gui;
|
|
||||||
using Penumbra.GameData.Interop;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using ImGuiNET;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
using OtterGui.Custom;
|
||||||
|
using OtterGui.Log;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.GameData.Data;
|
||||||
|
using Penumbra.GameData.DataContainers.Bases;
|
||||||
|
using Penumbra.GameData.Gui;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
using Penumbra.String;
|
||||||
|
|
||||||
namespace CustomizePlus.UI.Windows.Controls;
|
namespace CustomizePlus.UI.Windows.Controls;
|
||||||
|
|
||||||
public class ActorAssignmentUi : IDisposable
|
public class ActorAssignmentUi
|
||||||
{
|
{
|
||||||
private readonly ActorManager _actorManager;
|
private readonly ActorManager _actorManager;
|
||||||
|
private readonly DictBNpcENpc _dictBnpcEnpc;
|
||||||
|
|
||||||
private WorldCombo _worldCombo = null!;
|
private WorldCombo _worldCombo = null!;
|
||||||
private NpcCombo _mountCombo = null!;
|
private Penumbra.GameData.Gui.NpcCombo _mountCombo = null!;
|
||||||
private NpcCombo _companionCombo = null!;
|
private Penumbra.GameData.Gui.NpcCombo _companionCombo = null!;
|
||||||
private NpcCombo _ornamentCombo = null!;
|
//private BattleEventNpcCombo _npcCombo = null!;
|
||||||
private NpcCombo _bnpcCombo = null!;
|
private Penumbra.GameData.Gui.NpcCombo _npcCombo = null!;
|
||||||
private NpcCombo _enpcCombo = null!;
|
|
||||||
|
|
||||||
private bool _ready;
|
private bool _ready;
|
||||||
|
|
||||||
private string _newCharacterName = string.Empty;
|
private string _newCharacterName = string.Empty;
|
||||||
private ObjectKind _newKind = ObjectKind.BattleNpc;
|
private ObjectKind _newKind = ObjectKind.BattleNpc;
|
||||||
|
|
||||||
public ActorAssignmentUi(ActorManager actorManager)
|
/* public string CharacterName { get => _newCharacterName; }
|
||||||
|
public WorldId SelectedWorld { get => _worldCombo.CurrentSelection.Key; }
|
||||||
|
*/
|
||||||
|
public ActorIdentifier NpcIdentifier { get; private set; } = ActorIdentifier.Invalid;
|
||||||
|
public ActorIdentifier PlayerIdentifier { get; private set; } = ActorIdentifier.Invalid;
|
||||||
|
public ActorIdentifier RetainerIdentifier { get; private set; } = ActorIdentifier.Invalid;
|
||||||
|
public ActorIdentifier MannequinIdentifier { get; private set; } = ActorIdentifier.Invalid;
|
||||||
|
|
||||||
|
public bool CanSetPlayer
|
||||||
|
=> PlayerIdentifier.IsValid;
|
||||||
|
|
||||||
|
public bool CanSetRetainer
|
||||||
|
=> RetainerIdentifier.IsValid;
|
||||||
|
|
||||||
|
public bool CanSetMannequin
|
||||||
|
=> MannequinIdentifier.IsValid;
|
||||||
|
|
||||||
|
public bool CanSetNpc
|
||||||
|
=> NpcIdentifier.IsValid;
|
||||||
|
|
||||||
|
public ActorAssignmentUi(ActorManager actorManager, DictBNpcENpc dictBnpcEnpc)
|
||||||
{
|
{
|
||||||
_actorManager = actorManager;
|
_actorManager = actorManager;
|
||||||
|
_dictBnpcEnpc = dictBnpcEnpc;
|
||||||
|
|
||||||
_actorManager.Awaiter.ContinueWith(_ => SetupCombos(), TaskScheduler.Default);
|
_actorManager.Awaiter.ContinueWith(_ => dictBnpcEnpc.Awaiter.ContinueWith(_ => SetupCombos(), TaskScheduler.Default), TaskScheduler.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawWorldCombo(float width)
|
public void DrawWorldCombo(float width)
|
||||||
@@ -64,6 +92,12 @@ public class ActorAssignmentUi : IDisposable
|
|||||||
if (!_ready)
|
if (!_ready)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* if(_newKind == ObjectKind.BattleNpc || _newKind == ObjectKind.EventNpc)
|
||||||
|
{
|
||||||
|
if (_npcCombo.Draw(width))
|
||||||
|
UpdateIdentifiersInternal();
|
||||||
|
}*/
|
||||||
|
|
||||||
var combo = GetNpcCombo(_newKind);
|
var combo = GetNpcCombo(_newKind);
|
||||||
if (combo.Draw(width))
|
if (combo.Draw(width))
|
||||||
UpdateIdentifiersInternal();
|
UpdateIdentifiersInternal();
|
||||||
@@ -75,17 +109,15 @@ public class ActorAssignmentUi : IDisposable
|
|||||||
ObjectKind.EventNpc,
|
ObjectKind.EventNpc,
|
||||||
ObjectKind.Companion,
|
ObjectKind.Companion,
|
||||||
ObjectKind.MountType,
|
ObjectKind.MountType,
|
||||||
ObjectKind.Ornament,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private NpcCombo GetNpcCombo(ObjectKind kind)
|
private Penumbra.GameData.Gui.NpcCombo GetNpcCombo(ObjectKind kind)
|
||||||
=> kind switch
|
=> kind switch
|
||||||
{
|
{
|
||||||
ObjectKind.BattleNpc => _bnpcCombo,
|
ObjectKind.BattleNpc => _npcCombo,
|
||||||
ObjectKind.EventNpc => _enpcCombo,
|
ObjectKind.EventNpc => _npcCombo,
|
||||||
ObjectKind.MountType => _mountCombo,
|
ObjectKind.MountType => _mountCombo,
|
||||||
ObjectKind.Companion => _companionCombo,
|
ObjectKind.Companion => _companionCombo,
|
||||||
ObjectKind.Ornament => _ornamentCombo,
|
|
||||||
_ => throw new NotImplementedException(),
|
_ => throw new NotImplementedException(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,63 +125,57 @@ public class ActorAssignmentUi : IDisposable
|
|||||||
private void SetupCombos()
|
private void SetupCombos()
|
||||||
{
|
{
|
||||||
_worldCombo = new WorldCombo(_actorManager.Data.Worlds, Plugin.Logger);
|
_worldCombo = new WorldCombo(_actorManager.Data.Worlds, Plugin.Logger);
|
||||||
_mountCombo = new NpcCombo("##mountCombo", _actorManager.Data.Mounts, Plugin.Logger);
|
_mountCombo = new Penumbra.GameData.Gui.NpcCombo("##mountCombo", _actorManager.Data.Mounts, Plugin.Logger);
|
||||||
_companionCombo = new NpcCombo("##companionCombo", _actorManager.Data.Companions, Plugin.Logger);
|
_companionCombo = new Penumbra.GameData.Gui.NpcCombo("##companionCombo", _actorManager.Data.Companions, Plugin.Logger);
|
||||||
_ornamentCombo = new NpcCombo("##ornamentCombo", _actorManager.Data.Ornaments, Plugin.Logger);
|
//_bnpcCombo = new Penumbra.GameData.Gui.NpcCombo("##bnpcCombo", _actorManager.Data.BNpcs, Plugin.Logger);
|
||||||
_bnpcCombo = new NpcCombo("##bnpcCombo", _actorManager.Data.BNpcs, Plugin.Logger);
|
//_enpcCombo = new Penumbra.GameData.Gui.NpcCombo("##enpcCombo", _actorManager.Data.ENpcs, Plugin.Logger);
|
||||||
_enpcCombo = new NpcCombo("##enpcCombo", _actorManager.Data.ENpcs, Plugin.Logger);
|
_npcCombo = new Penumbra.GameData.Gui.NpcCombo("##npcCombo", _dictBnpcEnpc, Plugin.Logger);
|
||||||
_ready = true;
|
_ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateIdentifiersInternal()
|
private void UpdateIdentifiersInternal()
|
||||||
{
|
{
|
||||||
/* var combo = GetNpcCombo(_newKind);
|
if (ByteString.FromString(_newCharacterName, out var byteName))
|
||||||
PlayerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Player, _newCharacterName,
|
|
||||||
_worldCombo.CurrentSelection.Key, ObjectKind.None, [], out _playerIdentifiers) switch
|
|
||||||
{
|
{
|
||||||
_ when _newCharacterName.Length == 0 => NewPlayerTooltipEmpty,
|
PlayerIdentifier = _actorManager.CreatePlayer(byteName, _worldCombo.CurrentSelection.Key);
|
||||||
IndividualCollections.AddResult.Invalid => NewPlayerTooltipInvalid,
|
RetainerIdentifier = _actorManager.CreateRetainer(byteName, ActorIdentifier.RetainerType.Bell);
|
||||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
MannequinIdentifier = _actorManager.CreateRetainer(byteName, ActorIdentifier.RetainerType.Mannequin);
|
||||||
_ => string.Empty,
|
}
|
||||||
};
|
|
||||||
RetainerTooltip =
|
|
||||||
_collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None, [],
|
|
||||||
out _retainerIdentifiers) switch
|
|
||||||
{
|
|
||||||
_ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty,
|
|
||||||
IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid,
|
|
||||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
|
||||||
_ => string.Empty,
|
|
||||||
};
|
|
||||||
if (combo.CurrentSelection.Ids != null)
|
|
||||||
{
|
|
||||||
NpcTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Npc, string.Empty, ushort.MaxValue, _newKind,
|
|
||||||
combo.CurrentSelection.Ids, out _npcIdentifiers) switch
|
|
||||||
{
|
|
||||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
|
||||||
_ => string.Empty,
|
|
||||||
};
|
|
||||||
OwnedTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Owned, _newCharacterName,
|
|
||||||
_worldCombo.CurrentSelection.Key, _newKind,
|
|
||||||
combo.CurrentSelection.Ids, out _ownedIdentifiers) switch
|
|
||||||
{
|
|
||||||
_ when _newCharacterName.Length == 0 => NewPlayerTooltipEmpty,
|
|
||||||
IndividualCollections.AddResult.Invalid => NewPlayerTooltipInvalid,
|
|
||||||
IndividualCollections.AddResult.AlreadySet => AlreadyAssigned,
|
|
||||||
_ => string.Empty,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
NpcTooltip = NewNpcTooltipEmpty;
|
|
||||||
OwnedTooltip = NewNpcTooltipEmpty;
|
|
||||||
_npcIdentifiers = [];
|
|
||||||
_ownedIdentifiers = [];
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
//Todo: Temp
|
||||||
|
/// <summary> A dictionary that matches BNpcNameId to names. </summary>
|
||||||
|
public sealed class DictBNpcENpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
|
||||||
|
: NameDictionary(pluginInterface, log, gameData, "BNpcsENpcs", 7, () => CreateData(gameData))
|
||||||
{
|
{
|
||||||
//throw new NotImplementedException();
|
/// <summary> Create the data. </summary>
|
||||||
|
private static IReadOnlyDictionary<uint, string> CreateData(IDataManager gameData)
|
||||||
|
{
|
||||||
|
|
||||||
|
var sheet = gameData.GetExcelSheet<BNpcName>(gameData.Language)!;
|
||||||
|
var sheet2 = gameData.GetExcelSheet<ENpcResident>(gameData.Language)!;
|
||||||
|
|
||||||
|
var dict = new Dictionary<uint, string>((int)sheet.RowCount + (int)sheet2.RowCount);
|
||||||
|
|
||||||
|
foreach (var n in sheet.Where(n => n.Singular.RawData.Length > 0))
|
||||||
|
dict.TryAdd(n.RowId, DataUtility.ToTitleCaseExtended(n.Singular, n.Article));
|
||||||
|
foreach (var n in sheet2.Where(e => e.Singular.RawData.Length > 0))
|
||||||
|
dict.TryAdd(n.RowId, DataUtility.ToTitleCaseExtended(n.Singular, n.Article));
|
||||||
|
|
||||||
|
return dict.ToFrozenDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="NameDictionary.ContainsKey"/>
|
||||||
|
public bool ContainsKey(BNpcNameId key)
|
||||||
|
=> Value.ContainsKey(key.Id);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="NameDictionary.TryGetValue"/>
|
||||||
|
public bool TryGetValue(BNpcNameId key, [NotNullWhen(true)] out string? value)
|
||||||
|
=> Value.TryGetValue(key.Id, out value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="NameDictionary.this"/>
|
||||||
|
public string this[BNpcNameId key]
|
||||||
|
=> Value[key.Id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
|||||||
case ProfileChanged.Type.Deleted:
|
case ProfileChanged.Type.Deleted:
|
||||||
case ProfileChanged.Type.Renamed:
|
case ProfileChanged.Type.Renamed:
|
||||||
case ProfileChanged.Type.Toggled:
|
case ProfileChanged.Type.Toggled:
|
||||||
case ProfileChanged.Type.ChangedCharacterName:
|
case ProfileChanged.Type.ChangedCharacter:
|
||||||
case ProfileChanged.Type.ReloadedAll:
|
case ProfileChanged.Type.ReloadedAll:
|
||||||
SetFilterDirty();
|
SetFilterDirty();
|
||||||
break;
|
break;
|
||||||
@@ -239,9 +239,9 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (leaf.Value.Enabled)
|
if (leaf.Value.Enabled)
|
||||||
state.Color = leaf.Value.CharacterName == _gameObjectService.GetCurrentPlayerName() ? ColorId.LocalCharacterEnabledProfile : ColorId.EnabledProfile;
|
state.Color = leaf.Value.Character.Matches(_gameObjectService.GetCurrentPlayerActorIdentifier()) ? ColorId.LocalCharacterEnabledProfile : ColorId.EnabledProfile;
|
||||||
else
|
else
|
||||||
state.Color = leaf.Value.CharacterName == _gameObjectService.GetCurrentPlayerName() ? ColorId.LocalCharacterDisabledProfile : ColorId.DisabledProfile;
|
state.Color = leaf.Value.Character.Matches(_gameObjectService.GetCurrentPlayerActorIdentifier()) ? ColorId.LocalCharacterDisabledProfile : ColorId.DisabledProfile;
|
||||||
|
|
||||||
return ApplyStringFilters(leaf, leaf.Value);
|
return ApplyStringFilters(leaf, leaf.Value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ using CustomizePlus.UI.Windows.Controls;
|
|||||||
using CustomizePlus.Templates;
|
using CustomizePlus.Templates;
|
||||||
using CustomizePlus.Core.Data;
|
using CustomizePlus.Core.Data;
|
||||||
using CustomizePlus.Templates.Events;
|
using CustomizePlus.Templates.Events;
|
||||||
|
using Penumbra.GameData.Actors;
|
||||||
|
using Penumbra.String;
|
||||||
|
using static FFXIVClientStructs.FFXIV.Client.LayoutEngine.ILayoutInstance;
|
||||||
|
|
||||||
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
|
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
|
||||||
|
|
||||||
@@ -24,10 +27,11 @@ public class ProfilePanel
|
|||||||
private readonly TemplateCombo _templateCombo;
|
private readonly TemplateCombo _templateCombo;
|
||||||
private readonly TemplateEditorManager _templateEditorManager;
|
private readonly TemplateEditorManager _templateEditorManager;
|
||||||
private readonly ActorAssignmentUi _actorAssignmentUi;
|
private readonly ActorAssignmentUi _actorAssignmentUi;
|
||||||
|
private readonly ActorManager _actorManager;
|
||||||
private readonly TemplateEditorEvent _templateEditorEvent;
|
private readonly TemplateEditorEvent _templateEditorEvent;
|
||||||
|
|
||||||
private string? _newName;
|
private string? _newName;
|
||||||
private string? _newCharacterName;
|
//private string? _newCharacterName;
|
||||||
private Profile? _changedProfile;
|
private Profile? _changedProfile;
|
||||||
|
|
||||||
private Action? _endAction;
|
private Action? _endAction;
|
||||||
@@ -44,6 +48,7 @@ public class ProfilePanel
|
|||||||
TemplateCombo templateCombo,
|
TemplateCombo templateCombo,
|
||||||
TemplateEditorManager templateEditorManager,
|
TemplateEditorManager templateEditorManager,
|
||||||
ActorAssignmentUi actorAssignmentUi,
|
ActorAssignmentUi actorAssignmentUi,
|
||||||
|
ActorManager actorManager,
|
||||||
TemplateEditorEvent templateEditorEvent)
|
TemplateEditorEvent templateEditorEvent)
|
||||||
{
|
{
|
||||||
_selector = selector;
|
_selector = selector;
|
||||||
@@ -52,6 +57,7 @@ public class ProfilePanel
|
|||||||
_templateCombo = templateCombo;
|
_templateCombo = templateCombo;
|
||||||
_templateEditorManager = templateEditorManager;
|
_templateEditorManager = templateEditorManager;
|
||||||
_actorAssignmentUi = actorAssignmentUi;
|
_actorAssignmentUi = actorAssignmentUi;
|
||||||
|
_actorManager = actorManager;
|
||||||
_templateEditorEvent = templateEditorEvent;
|
_templateEditorEvent = templateEditorEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +223,14 @@ public class ProfilePanel
|
|||||||
ImGuiUtil.DrawFrameColumn("Character");
|
ImGuiUtil.DrawFrameColumn("Character");
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
width = new Vector2(ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize("Limit to my creatures").X - 68, 0);
|
width = new Vector2(ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize("Limit to my creatures").X - 68, 0);
|
||||||
name = _newCharacterName ?? _selector.Selected!.CharacterName;
|
//name = _newCharacterName ?? _selector.Selected!.CharacterName;
|
||||||
ImGui.SetNextItemWidth(width.X);
|
ImGui.SetNextItemWidth(width.X);
|
||||||
|
|
||||||
if(_manager.DefaultProfile != _selector.Selected)
|
if(_manager.DefaultProfile != _selector.Selected)
|
||||||
{
|
{
|
||||||
if (!_selector.IncognitoMode)
|
if (!_selector.IncognitoMode)
|
||||||
|
{
|
||||||
|
if(!_selector.Selected!.ApplyToCurrentlyActiveCharacter)
|
||||||
{
|
{
|
||||||
/* if (ImGui.InputText("##CharacterName", ref name, 128))
|
/* if (ImGui.InputText("##CharacterName", ref name, 128))
|
||||||
{
|
{
|
||||||
@@ -235,19 +243,56 @@ public class ProfilePanel
|
|||||||
_manager.ChangeCharacterName(_changedProfile, name);
|
_manager.ChangeCharacterName(_changedProfile, name);
|
||||||
_newCharacterName = null;
|
_newCharacterName = null;
|
||||||
_changedProfile = null;
|
_changedProfile = null;
|
||||||
}*/
|
}
|
||||||
|
ImGui.Separator();*/
|
||||||
|
ImGui.Text($"Character: {(_selector.Selected?.Character.ToString() ?? "Character field empty")}");
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
_actorAssignmentUi.DrawWorldCombo(width.X / 2);
|
_actorAssignmentUi.DrawWorldCombo(width.X / 2);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
_actorAssignmentUi.DrawPlayerInput(width.X);
|
_actorAssignmentUi.DrawPlayerInput(width.X / 2);
|
||||||
|
|
||||||
|
var buttonWidth = new Vector2(165 * ImGuiHelpers.GlobalScale - ImGui.GetStyle().ItemSpacing.X / 2, 0);
|
||||||
|
|
||||||
|
if (ImGuiUtil.DrawDisabledButton("Apply to player character", buttonWidth, string.Empty, !_actorAssignmentUi.CanSetPlayer))
|
||||||
|
_manager.ChangeCharacter(_selector.Selected!, _actorAssignmentUi.PlayerIdentifier);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGuiUtil.DrawDisabledButton("Apply to retainer", buttonWidth, string.Empty, !_actorAssignmentUi.CanSetRetainer))
|
||||||
|
_manager.ChangeCharacter(_selector.Selected!, _actorAssignmentUi.RetainerIdentifier);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGuiUtil.DrawDisabledButton("Apply to mannequin", buttonWidth, string.Empty, !_actorAssignmentUi.CanSetMannequin))
|
||||||
|
_manager.ChangeCharacter(_selector.Selected!, _actorAssignmentUi.MannequinIdentifier);
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
_actorAssignmentUi.DrawObjectKindCombo(width.X / 2);
|
_actorAssignmentUi.DrawObjectKindCombo(width.X / 2);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
_actorAssignmentUi.DrawNpcInput(width.X);
|
_actorAssignmentUi.DrawNpcInput(width.X / 2);
|
||||||
|
|
||||||
|
if (ImGui.Button("Apply to selected non-player character"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted("Any character you are logged in with");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ImGui.TextUnformatted("Incognito active");
|
ImGui.TextUnformatted("Incognito active");
|
||||||
|
|
||||||
ImGui.SameLine();
|
var anyActiveCharaBool = _selector.Selected?.ApplyToCurrentlyActiveCharacter ?? false;
|
||||||
|
if (ImGui.Checkbox("##ApplyToCurrentlyActiveCharacter", ref anyActiveCharaBool))
|
||||||
|
_manager.SetApplyToCurrentlyActiveCharacter(_selector.Selected!, anyActiveCharaBool);
|
||||||
|
ImGuiUtil.LabeledHelpMarker("Apply to any character you are logged in with",
|
||||||
|
"When enabled applies this profile to any character you are currently logged in with.");
|
||||||
|
|
||||||
|
//ImGui.SameLine();
|
||||||
var enabled = _selector.Selected?.LimitLookupToOwnedObjects ?? false;
|
var enabled = _selector.Selected?.LimitLookupToOwnedObjects ?? false;
|
||||||
if (ImGui.Checkbox("##LimitLookupToOwnedObjects", ref enabled))
|
if (ImGui.Checkbox("##LimitLookupToOwnedObjects", ref enabled))
|
||||||
_manager.SetLimitLookupToOwned(_selector.Selected!, enabled);
|
_manager.SetLimitLookupToOwned(_selector.Selected!, enabled);
|
||||||
@@ -353,4 +398,9 @@ public class ProfilePanel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateIdentifiers()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user