UI/session component for the character editor. Manages library, editing state, current draft/target avatar, view switching, save/import/delete/favorite operations and scene opening.
using System;
namespace CharacterEditor;
public sealed class StudioSession : Component
{
[Property]
public bool StartInPlaza { get; set; }
[Property]
public bool Embedded { get; set; }
[Property]
public bool EnableFaceLab { get; set; }
[Property]
public bool EnableEscapeMenu { get; set; }
public static void OpenScene(string path)
{
var options = new SceneLoadOptions
{
ShowLoadingScreen = false
};
options.SetScene(path);
Game.ChangeScene(options);
}
public CharacterLibrary Library { get; } = new();
public CharacterPreset Draft { get; private set; }
public CharacterAvatar Target { get; private set; }
public string View { get; set; } = "library";
public string Message { get; set; }
public int Revision { get; private set; }
public bool IsNew { get; private set; }
public string SelectedId { get; set; }
public CharacterPreset Selected => Library.Items.FirstOrDefault(x => x.Id == SelectedId);
public CharacterPlaza Plaza => Scene.GetAllComponents<CharacterPlaza>().FirstOrDefault();
bool loaded;
string previousView = "library";
public void EnsureLoaded()
{
if (loaded)
return;
loaded = true;
Library.Reload();
if (Embedded)
View = "hidden";
else if (StartInPlaza)
View = "plaza";
}
protected override void OnStart()
{
EnsureLoaded();
}
public void Edit(CharacterPreset preset = null, CharacterAvatar target = null)
{
EnsureLoaded();
previousView = View == "editor" ? "library" : View;
Target = target;
IsNew = preset is null;
Draft = preset?.DeepCopy() ?? new CharacterPreset
{
Appearance = AppearanceCatalog.CreateDefault()
};
if (preset is null)
UnifiedHuman.Enable(Draft.Appearance);
View = "editor";
Revision++;
Message = null;
}
public string Save(string name, CharacterAppearanceData appearance, bool asCopy = false)
{
try
{
var value = Draft.DeepCopy();
value.Name = name;
value.Appearance = appearance.DeepCopy();
if (asCopy)
value.Id = Guid.NewGuid().ToString("N");
Library.Save(value);
if (Target.IsValid())
Target.Apply(value);
SelectedId = value.Id;
Draft = null;
Target = null;
View = previousView;
Revision++;
Message = $"Saved {value.Name}.";
Plaza?.Refresh();
return null;
}
catch (Exception e)
{
return e.Message;
}
}
public void CloseEditor()
{
Draft = null;
Target = null;
View = previousView;
Revision++;
}
public void Favorite(CharacterPreset preset)
{
try
{
var copy = preset.DeepCopy();
copy.Favorite = !copy.Favorite;
Library.Save(copy);
}
catch (Exception e)
{
Message = e.Message;
}
}
public void Delete(CharacterPreset preset)
{
try
{
Library.Delete(preset.Id);
SelectedId = null;
Plaza?.Refresh();
Message = $"Deleted {preset.Name}.";
}
catch (Exception e)
{
Message = e.Message;
}
}
public void Import(string json)
{
try
{
var value = Library.Import(json);
SelectedId = value.Id;
Message = $"Imported {value.Name} as a new character.";
Plaza?.Refresh();
}
catch (Exception e)
{
Message = e.Message;
}
}
public void ShowPlaza()
{
View = "plaza";
Plaza?.Refresh();
}
}