New actor assignment ui experiments
This commit is contained in:
@@ -21,13 +21,19 @@ namespace CustomizePlus.Profiles.Data;
|
||||
/// </summary>
|
||||
public sealed class Profile : ISavable
|
||||
{
|
||||
public const int Version = 4;
|
||||
|
||||
private static int _nextGlobalId;
|
||||
|
||||
private readonly int _localId;
|
||||
|
||||
public List<Armature> Armatures = new();
|
||||
|
||||
[Obsolete("To be removed")]
|
||||
public LowerString CharacterName { get; set; } = LowerString.Empty;
|
||||
|
||||
public ActorIdentifier Character { get; set; } = ActorIdentifier.Invalid;
|
||||
|
||||
public LowerString Name { get; set; } = LowerString.Empty;
|
||||
|
||||
/// <summary>
|
||||
@@ -35,8 +41,6 @@ public sealed class Profile : ISavable
|
||||
/// </summary>
|
||||
public bool LimitLookupToOwnedObjects { get; set; } = false;
|
||||
|
||||
public int Version { get; set; } = Constants.ConfigurationVersion;
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
public DateTimeOffset CreationDate { get; set; } = DateTime.UtcNow;
|
||||
public DateTimeOffset ModifiedDate { get; set; } = DateTime.UtcNow;
|
||||
@@ -99,6 +103,7 @@ public sealed class Profile : ISavable
|
||||
["CreationDate"] = CreationDate,
|
||||
["ModifiedDate"] = ModifiedDate,
|
||||
["CharacterName"] = CharacterName.Text,
|
||||
//["Character"] = Character.ToJson(),
|
||||
["Name"] = Name.Text,
|
||||
["LimitLookupToOwnedObjects"] = LimitLookupToOwnedObjects,
|
||||
["Enabled"] = Enabled,
|
||||
@@ -124,62 +129,7 @@ public sealed class Profile : ISavable
|
||||
|
||||
#endregion
|
||||
|
||||
#region Deserialization
|
||||
|
||||
public static Profile Load(TemplateManager templateManager, JObject obj)
|
||||
{
|
||||
var version = obj["Version"]?.ToObject<int>() ?? 0;
|
||||
return version switch
|
||||
{
|
||||
//Ignore everything below v4 for now
|
||||
4 => LoadV4(templateManager, obj),
|
||||
_ => throw new Exception("The design to be loaded has no valid Version."),
|
||||
};
|
||||
}
|
||||
|
||||
private static Profile LoadV4(TemplateManager templateManager, JObject obj)
|
||||
{
|
||||
var creationDate = obj["CreationDate"]?.ToObject<DateTimeOffset>() ?? throw new ArgumentNullException("CreationDate");
|
||||
|
||||
var profile = new Profile()
|
||||
{
|
||||
CreationDate = creationDate,
|
||||
UniqueId = obj["UniqueId"]?.ToObject<Guid>() ?? throw new ArgumentNullException("UniqueId"),
|
||||
Name = new LowerString(obj["Name"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("Name")),
|
||||
CharacterName = new LowerString(obj["CharacterName"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("CharacterName")),
|
||||
LimitLookupToOwnedObjects = obj["LimitLookupToOwnedObjects"]?.ToObject<bool>() ?? throw new ArgumentNullException("LimitLookupToOwnedObjects"),
|
||||
Enabled = obj["Enabled"]?.ToObject<bool>() ?? throw new ArgumentNullException("Enabled"),
|
||||
ModifiedDate = obj["ModifiedDate"]?.ToObject<DateTimeOffset>() ?? creationDate,
|
||||
IsWriteProtected = obj["IsWriteProtected"]?.ToObject<bool>() ?? false,
|
||||
Templates = new List<Template>()
|
||||
};
|
||||
if (profile.ModifiedDate < creationDate)
|
||||
profile.ModifiedDate = creationDate;
|
||||
|
||||
if (obj["Templates"] is not JArray templateArray)
|
||||
return profile;
|
||||
|
||||
foreach (var templateObj in templateArray)
|
||||
{
|
||||
if (templateObj is not JObject templateObjCast)
|
||||
{
|
||||
//todo: warning
|
||||
continue;
|
||||
}
|
||||
|
||||
var templateId = templateObjCast["TemplateId"]?.ToObject<Guid>();
|
||||
if (templateId == null)
|
||||
continue; //todo: error
|
||||
|
||||
var template = templateManager.GetTemplate((Guid)templateId);
|
||||
if (template != null)
|
||||
profile.Templates.Add(template);
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
#endregion
|
||||
//Loading is in ProfileManager
|
||||
|
||||
#region ISavable
|
||||
|
||||
|
||||
155
CustomizePlus/Profiles/ProfileManager.ProfileLoading.cs
Normal file
155
CustomizePlus/Profiles/ProfileManager.ProfileLoading.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using CustomizePlus.Profiles.Data;
|
||||
using CustomizePlus.Profiles.Events;
|
||||
using CustomizePlus.Templates.Data;
|
||||
using CustomizePlus.Templates;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Penumbra.String;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace CustomizePlus.Profiles;
|
||||
|
||||
public partial class ProfileManager : IDisposable
|
||||
{
|
||||
public void LoadProfiles()
|
||||
{
|
||||
_logger.Information("Loading profiles...");
|
||||
|
||||
//todo: hot reload was not tested
|
||||
//save temp profiles
|
||||
var temporaryProfiles = Profiles.Where(x => x.IsTemporary).ToList();
|
||||
|
||||
Profiles.Clear();
|
||||
List<(Profile, string)> invalidNames = new();
|
||||
foreach (var file in _saveService.FileNames.Profiles())
|
||||
{
|
||||
_logger.Debug($"Reading profile {file.FullName}");
|
||||
|
||||
try
|
||||
{
|
||||
var text = File.ReadAllText(file.FullName);
|
||||
var data = JObject.Parse(text);
|
||||
var profile = LoadIndividualProfile(data);
|
||||
if (profile.UniqueId.ToString() != Path.GetFileNameWithoutExtension(file.Name))
|
||||
invalidNames.Add((profile, file.FullName));
|
||||
if (Profiles.Any(f => f.UniqueId == profile.UniqueId))
|
||||
throw new Exception($"ID {profile.UniqueId} was not unique.");
|
||||
|
||||
Profiles.Add(profile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Could not load profile, skipped:\n{ex}");
|
||||
//++skipped;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var profile in Profiles)
|
||||
{
|
||||
//This will solve any issues if file on disk was manually edited and we have more than a single active profile
|
||||
if (profile.Enabled)
|
||||
SetEnabled(profile, true, true);
|
||||
|
||||
if (_configuration.DefaultProfile == profile.UniqueId)
|
||||
DefaultProfile = profile;
|
||||
}
|
||||
|
||||
//insert temp profiles back into profile list
|
||||
if (temporaryProfiles.Count > 0)
|
||||
{
|
||||
Profiles.AddRange(temporaryProfiles);
|
||||
Profiles.Sort((x, y) => y.IsTemporary.CompareTo(x.IsTemporary));
|
||||
}
|
||||
|
||||
var failed = MoveInvalidNames(invalidNames);
|
||||
if (invalidNames.Count > 0)
|
||||
_logger.Information(
|
||||
$"Moved {invalidNames.Count - failed} profiles to correct names.{(failed > 0 ? $" Failed to move {failed} profiles to correct names." : string.Empty)}");
|
||||
|
||||
_logger.Information("Profiles load complete");
|
||||
_event.Invoke(ProfileChanged.Type.ReloadedAll, null, null);
|
||||
}
|
||||
|
||||
private Profile LoadIndividualProfile(JObject obj)
|
||||
{
|
||||
var version = obj["Version"]?.ToObject<int>() ?? 0;
|
||||
return version switch
|
||||
{
|
||||
//Ignore everything below v4
|
||||
// 4 => LoadV4(obj),
|
||||
// 5 => LoadV5(obj),
|
||||
4 => LoadV5(obj),
|
||||
_ => throw new Exception("The profile to be loaded has no valid Version."),
|
||||
};
|
||||
}
|
||||
|
||||
private Profile LoadV4(JObject obj)
|
||||
{
|
||||
var characterName = new LowerString(obj["CharacterName"]?.ToObject<string>()?.Trim() ?? throw new ArgumentNullException("CharacterName"));
|
||||
|
||||
ByteString.FromString(characterName, out var nameByteString);
|
||||
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;
|
||||
}
|
||||
|
||||
private Profile LoadV5(JObject obj)
|
||||
{
|
||||
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()
|
||||
{
|
||||
CreationDate = creationDate,
|
||||
UniqueId = obj["UniqueId"]?.ToObject<Guid>() ?? throw new ArgumentNullException("UniqueId"),
|
||||
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"),
|
||||
Enabled = obj["Enabled"]?.ToObject<bool>() ?? throw new ArgumentNullException("Enabled"),
|
||||
ModifiedDate = obj["ModifiedDate"]?.ToObject<DateTimeOffset>() ?? creationDate,
|
||||
IsWriteProtected = obj["IsWriteProtected"]?.ToObject<bool>() ?? false,
|
||||
Templates = new List<Template>()
|
||||
};
|
||||
if (profile.ModifiedDate < creationDate)
|
||||
profile.ModifiedDate = creationDate;
|
||||
|
||||
if (obj["Templates"] is not JArray templateArray)
|
||||
return profile;
|
||||
|
||||
foreach (var templateObj in templateArray)
|
||||
{
|
||||
if (templateObj is not JObject templateObjCast)
|
||||
{
|
||||
//todo: warning
|
||||
continue;
|
||||
}
|
||||
|
||||
var templateId = templateObjCast["TemplateId"]?.ToObject<Guid>();
|
||||
if (templateId == null)
|
||||
continue; //todo: error
|
||||
|
||||
var template = _templateManager.GetTemplate((Guid)templateId);
|
||||
if (template != null)
|
||||
profile.Templates.Add(template);
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace CustomizePlus.Profiles;
|
||||
/// <summary>
|
||||
/// Container class for administrating <see cref="Profile" />s during runtime.
|
||||
/// </summary>
|
||||
public class ProfileManager : IDisposable
|
||||
public partial class ProfileManager : IDisposable
|
||||
{
|
||||
private readonly TemplateManager _templateManager;
|
||||
private readonly TemplateEditorManager _templateEditorManager;
|
||||
@@ -93,65 +93,6 @@ public class ProfileManager : IDisposable
|
||||
_templateChangedEvent.Unsubscribe(OnTemplateChange);
|
||||
}
|
||||
|
||||
public void LoadProfiles()
|
||||
{
|
||||
_logger.Information("Loading profiles...");
|
||||
|
||||
//todo: hot reload was not tested
|
||||
//save temp profiles
|
||||
var temporaryProfiles = Profiles.Where(x => x.IsTemporary).ToList();
|
||||
|
||||
Profiles.Clear();
|
||||
List<(Profile, string)> invalidNames = new();
|
||||
foreach (var file in _saveService.FileNames.Profiles())
|
||||
{
|
||||
_logger.Debug($"Reading profile {file.FullName}");
|
||||
|
||||
try
|
||||
{
|
||||
var text = File.ReadAllText(file.FullName);
|
||||
var data = JObject.Parse(text);
|
||||
var profile = Profile.Load(_templateManager, data);
|
||||
if (profile.UniqueId.ToString() != Path.GetFileNameWithoutExtension(file.Name))
|
||||
invalidNames.Add((profile, file.FullName));
|
||||
if (Profiles.Any(f => f.UniqueId == profile.UniqueId))
|
||||
throw new Exception($"ID {profile.UniqueId} was not unique.");
|
||||
|
||||
Profiles.Add(profile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Could not load profile, skipped:\n{ex}");
|
||||
//++skipped;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var profile in Profiles)
|
||||
{
|
||||
//This will solve any issues if file on disk was manually edited and we have more than a single active profile
|
||||
if (profile.Enabled)
|
||||
SetEnabled(profile, true, true);
|
||||
|
||||
if (_configuration.DefaultProfile == profile.UniqueId)
|
||||
DefaultProfile = profile;
|
||||
}
|
||||
|
||||
//insert temp profiles back into profile list
|
||||
if (temporaryProfiles.Count > 0)
|
||||
{
|
||||
Profiles.AddRange(temporaryProfiles);
|
||||
Profiles.Sort((x, y) => y.IsTemporary.CompareTo(x.IsTemporary));
|
||||
}
|
||||
|
||||
var failed = MoveInvalidNames(invalidNames);
|
||||
if (invalidNames.Count > 0)
|
||||
_logger.Information(
|
||||
$"Moved {invalidNames.Count - failed} profiles to correct names.{(failed > 0 ? $" Failed to move {failed} profiles to correct names." : string.Empty)}");
|
||||
|
||||
_logger.Information("Profiles load complete");
|
||||
_event.Invoke(ProfileChanged.Type.ReloadedAll, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main rendering function, called from rendering hook after calling ArmatureManager.OnRender
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user