Project user settings, load recent scenes, properly cleanup ScriptEngine when switching scenes

This commit is contained in:
Simon Lübeß
2023-07-31 20:09:56 +02:00
parent 3298053d9d
commit 5d8c1b111a
7 changed files with 250 additions and 55 deletions
+1
View File
@@ -0,0 +1 @@
project_user.bon
@@ -30,10 +30,10 @@
}
},
MeshComponent = {
Mesh = "Models/sphere.glb"
Mesh = "Assets/Models/sphere.glb"
},
MeshRendererComponent = {
Material = "Textures/TestMaterial.mat"
Material = "Assets/Textures/TestMaterial.mat"
}
},
{
@@ -49,12 +49,12 @@
},
Rotation = {
X = 0.614328027,
Y = 0.239776045,
Y = 0.23977606,
Z = 0.0315669999,
W = 0.751073837
W = 0.751073778
},
Scale = {
X = 0.999998868,
X = 0.999998808,
Y = 1,
Z = 1.00000095
},
@@ -70,7 +70,7 @@
Color = {
R = 1,
G = 0.991771996,
B = 0.74086225
B = 0.74086231
}
}
},
@@ -103,10 +103,10 @@
}
},
MeshComponent = {
Mesh = "Models/plane.glb"
Mesh = "Assets/Models/plane.glb"
},
MeshRendererComponent = {
Material = "Textures/TestMaterial.mat"
Material = "Assets/Textures/TestMaterial.mat"
}
},
{
@@ -146,7 +146,7 @@
OrthographicHeight = 10,
OrthographicNearPlane = 0,
OrthographicFarPlane = 10,
AspectRatio = 2.19888878,
AspectRatio = 1.87453413,
FixedAspectRatio = false
}
},
@@ -164,7 +164,7 @@
Rotation = {
X = 0.18301262,
Y = -0.683013558,
Z = 0.683012128,
Z = 0.683012187,
W = 0.183013007
},
Scale = {
@@ -173,13 +173,13 @@
Z = 1
},
EditorEulerRotation = {
X = 1.57079446,
Y = -2.61799312,
X = 1.57079458,
Y = -2.61799288,
Z = 0
}
},
MeshComponent = {
Mesh = "Models/plane.glb"
Mesh = ""
},
MeshRendererComponent = {
Material = ""
@@ -192,32 +192,32 @@
},
TransformComponent = {
Position = {
X = 2.37353587,
X = 2.37353563,
Y = 0.629615188,
Z = -1.34831977
},
Rotation = {
X = 0.270598024,
Y = -0.65328145,
Y = -0.65328151,
Z = 0.65328151,
W = 0.270598054
},
Scale = {
X = 0.999999881,
Y = 0.999999821,
X = 0.999999821,
Y = 0.999999762,
Z = 0.999999702
},
EditorEulerRotation = {
X = 1.57079637,
Y = -2.3561945,
Z = 8.94069743e-08
X = 1.57079649,
Y = -2.35619426,
Z = 8.94069601e-08
}
},
MeshComponent = {
Mesh = "Models/plane.glb"
Mesh = "Assets/Models/plane.glb"
},
MeshRendererComponent = {
Material = "Textures/RocketMaterial.mat"
Material = "Assets/Textures/RocketMaterial.mat"
}
}
]
@@ -0,0 +1 @@
project_user.bon
+73 -22
View File
@@ -62,6 +62,8 @@ namespace GlitchyEditor
SettingsWindow _settingsWindow = new .() ~ delete _;
ProjectUserSettings _projectUserSettings;
EditorCamera _camera ~ _.Dispose();
EditorIcons _editorIcons ~ _.ReleaseRef();
@@ -135,6 +137,11 @@ namespace GlitchyEditor
CreateAndOpenNewScene();
}
public ~this()
{
CloseCurrentProject();
}
private void RegisterAssetCreators()
{
Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Scene", "New Scene.scene", new (path) =>
@@ -393,6 +400,12 @@ namespace GlitchyEditor
Renderer2D.DrawCircle(transform.WorldTransform * Matrix.Translation(collider.Offset.X, collider.Offset.Y, 0) * Matrix.Scaling(collider.Radius * 2), (Texture2D)null, ColorRGBA(0f, 1f, 0f), 0.01f);
}
}
/// Updates the title of the window.
private void UpdateWindowTitle()
{
Application.Instance.Window.Title = scope $"Glitchy Engine - {_currentProject.Name}";
}
#region Project Management
@@ -605,11 +618,11 @@ namespace GlitchyEditor
private void CloseCurrentProject()
{
OnSceneStop();
CloseCurrentScene();
SetReference!(_editorScene, null);
SetReference!(_activeScene, null);
_editor.CurrentScene = null;
SetEditorScene(null);
_currentProject?.SaveUserSettings();
// TODO: Do actual work here!
delete _currentProject;
@@ -629,6 +642,7 @@ namespace GlitchyEditor
return .Ok;
}
/// Opens the given project and makes it the current project.
private Result<void> OpenProject(Project project)
{
if (project == null)
@@ -645,8 +659,19 @@ namespace GlitchyEditor
ScriptEngine.SetAppAssemblyPath(appAssemblyPath);
// TODO: Load last opened scene
CreateAndOpenNewScene();
if (!_currentProject.UserSettings.LastOpenedScene.IsWhiteSpace)
{
String lastSceneFile = _currentProject.GetScopedPath!(_currentProject.UserSettings.LastOpenedScene);
if (File.Exists(lastSceneFile))
LoadSceneFile(lastSceneFile);
else
CreateAndOpenNewScene();
}
else
CreateAndOpenNewScene();
UpdateWindowTitle();
return .Ok;
}
@@ -737,11 +762,18 @@ namespace GlitchyEditor
}
}
/// Stops the scene and cleans up the subsystems to allow loading another scene.
private void CloseCurrentScene()
{
OnSceneStop();
ScriptEngine.ClearEntityScriptFields();
}
/// Creates a new scene and openes it.
private void CreateAndOpenNewScene()
{
OnSceneStop();
CloseCurrentScene();
SceneFilePath = null;
@@ -749,13 +781,19 @@ namespace GlitchyEditor
{
_camera.Position = .(-1.5f, 1.5f, -2.5f);
_camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0);
SetReference!(_editorScene, newScene);
_editor.CurrentScene = _editorScene;
SetReference!(_activeScene, _editorScene);
SetEditorScene(newScene);
}
}
/// Sets the current editor scene
private void SetEditorScene(Scene scene)
{
SetReference!(_editorScene, scene);
_editor.CurrentScene = _editorScene;
SetReference!(_activeScene, _editorScene);
}
/// Creates a new default scene.
private static Scene CreateNewScene()
{
@@ -801,6 +839,11 @@ namespace GlitchyEditor
{
SaveScene(_editorScene, SceneFilePath);
}
// Note: We only update the last opened scene if the CURRENT scene is saved, NOT when ANY scene is saved.
String relativePath = scope .();
Path.GetRelativePath(SceneFilePath, _currentProject.WorkspacePath, relativePath);
_currentProject.UserSettings.LastOpenedScene = relativePath;
}
/// Saves the given scene with the specified file name.
@@ -838,7 +881,9 @@ namespace GlitchyEditor
/// Loads the given scene file and opens it as the current scene.
private void LoadSceneFile(StringView filename)
{
OnSceneStop();
CloseCurrentScene();
ScriptEngine.ClearEntityScriptFields();
SceneFilePath = scope String(filename);
@@ -850,9 +895,11 @@ namespace GlitchyEditor
// Make sure we actually loaded something!
if (result case .Ok)
{
SetReference!(_editorScene, newScene);
_editor.CurrentScene = _editorScene;
SetReference!(_activeScene, _editorScene);
SetEditorScene(newScene);
String relativePath = scope .();
Path.GetRelativePath(filename, _currentProject.WorkspacePath, relativePath);
_currentProject.UserSettings.LastOpenedScene = relativePath;
}
else
{
@@ -1042,22 +1089,26 @@ namespace GlitchyEditor
private void ShowOpenRecentSceneMenu()
{
if (_currentProject == null)
return;
int i = 0;
for (let (name, path) in _recentScenePaths)
for (let scenePath in _currentProject.UserSettings.RecentScenes)
{
i++;
if (i >= 10)
break;
if (!File.Exists(path))
String fullScenePath = _currentProject.GetScopedPath!(scenePath);
if (!File.Exists(fullScenePath))
{
// TODO!
delete scenePath;
@scenePath.Remove();
}
if (ImGui.MenuItem(scope $"{i}: {name} ({path})"))
if (ImGui.MenuItem(scope $"{i}: {scenePath}"))
{
LoadSceneFile(path);
LoadSceneFile(fullScenePath);
}
}
}
+55 -1
View File
@@ -19,12 +19,17 @@ class Project
[BonIgnore]
private String _scriptFolder ~ delete _;
[BonIgnore]
private ProjectUserSettings _userSettings ~ delete _;
public StringView Name => _projectName;
public StringView WorkspacePath => _workspacePath;
public StringView AssetsFolder => _assetsFolder;
public ProjectUserSettings UserSettings => _userSettings;
[AllowAppend]
private this(StringView workspacePath)
{
@@ -32,13 +37,62 @@ class Project
_assetsFolder = new String();
PathInProject(_assetsFolder, "Assets");
}
InitUserSettings();
}
/// Writes the the absolute path of the give project-file into target.
/// @param target The string that will contain the full path.
/// @param relativePath The path of the file relative to the workspace folder.
public void PathInProject(String target, StringView relativePath)
{
Path.Combine(target, WorkspacePath, relativePath);
}
/// Creates a new scoped string that contains the absolute path of the give project-file
/// @param relativePath The path of the file relative to the workspace folder.
public mixin GetScopedPath(StringView relativePath)
{
String target = scope:mixin String();
PathInProject(target, relativePath);
target
}
/// Loads or creates the user specific settings for this project.
private void InitUserSettings()
{
_userSettings = new ProjectUserSettings();
String userSettingsFile = scope .();
PathInProject(userSettingsFile, ProjectUserSettings.FileName);
// It's not a problem if we couldn't find or deserialize the settings. We will simply restore the defaults.
if (Bon.DeserializeFromFile(ref _userSettings, userSettingsFile) case .Err)
{
// Log anyway, just in case...
Log.EngineLogger.Info($"Failed to deserialize project user settings file \"{userSettingsFile}\".");
_userSettings.RestoreDefaults();
}
}
public void SaveUserSettings()
{
if (_userSettings == null || !_userSettings.SettignsDirty)
return;
String userSettingsFile = scope .();
PathInProject(userSettingsFile, ProjectUserSettings.FileName);
// It's not a big problem, if we fail to serialize this file.
if (Bon.SerializeIntoFile(_userSettings, userSettingsFile) case .Err)
{
// Log anyway, just in case...
Log.EngineLogger.Error($"Failed to deserialize project user settings file \"{userSettingsFile}\".");
}
}
/// Creates a new project with the given directory and name.
public static Project CreateNew(StringView projectDirectory, StringView projectName)
{
+79
View File
@@ -0,0 +1,79 @@
using Bon;
using System;
using System.Collections;
namespace GlitchyEditor;
/// The user settings of this project
[BonTarget]
class ProjectUserSettings
{
public static StringView FileName = "project_user.bon";
/*[BonInclude]
private String _lastOpenedScene ~ delete _;*/
[BonInclude]
private List<String> _recentScenes ~ DeleteContainerAndItems!(_);
[BonIgnore]
private bool _settingsDirty;
/// Gets or sets the path of the Scene that was last open. (Relative to the workspace)
public StringView LastOpenedScene
{
get
{
if (_recentScenes == null || _recentScenes.Count == 0)
return "";
return _recentScenes[0];
}
set
{
if (_recentScenes == null)
_recentScenes = new List<String>();
// Remove duplicates
for (var entry in _recentScenes)
{
if (entry == value)
{
delete entry;
@entry.Remove();
}
}
_recentScenes.Insert(0, new String(value));
if (_recentScenes.Count > 10)
{
// We only store 10 entries, delete the rest
for (int i = 10; i < _recentScenes.Count; i++)
{
delete _recentScenes[i];
}
_recentScenes.Count = 10;
}
}
}
/// The scenes that were recently used.
public List<String> RecentScenes => _recentScenes;
public bool SettignsDirty
{
get => _settingsDirty;
set => _settingsDirty = value;
}
public void RestoreDefaults()
{
//_lastOpenedScene?.Clear();
if (_recentScenes != null)
ClearAndDeleteItems!(_recentScenes);
_settingsDirty = true;
}
}
+19 -10
View File
@@ -189,6 +189,17 @@ static class ScriptEngine
_userAssemblyWatcher.StartRaisingEvents();
}
/// Gets rid of all entity fields.
public static void ClearEntityScriptFields()
{
for (var value in _entityFields.Values)
{
DeleteDictionaryAndKeys!(value);
}
_entityFields.Clear();
}
static void LoadScriptAssemblies()
{
CreateAppDomain("GlitchyEngineScriptRuntime");
@@ -201,11 +212,13 @@ static class ScriptEngine
s_AppAssembly = null;
s_AppAssemblyImage = null;
}
ClearDictionaryAndReleaseValues!(_sharpClasses);
GetCoreAttributes();
GetCoreClasses();
ClearDictionaryAndReleaseValues!(_sharpClasses);
ClearDictionaryAndReleaseValues!(_componentClasses);
ClearDictionaryAndReleaseValues!(_entityScripts);
GetComponentsFromAssemblies();
@@ -366,9 +379,9 @@ static class ScriptEngine
/// Retrieves the base classes from which every Component or Entity inherits
static void GetCoreClasses()
{
s_EngineObject?.ReleaseRef();
s_EntityRoot?.ReleaseRef();
s_ComponentRoot?.ReleaseRef();
ReleaseRefAndNullify!(s_EngineObject);
ReleaseRefAndNullify!(s_EntityRoot);
ReleaseRefAndNullify!(s_ComponentRoot);
s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject", s_CoreAssemblyImage, .Class);
s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity", s_CoreAssemblyImage, .Entity);
@@ -383,8 +396,6 @@ static class ScriptEngine
private static void GetEntitiesFromAssemblies()
{
ClearDictionaryAndReleaseValues!(_entityScripts);
if (s_AppAssemblyImage == null)
return;
@@ -413,8 +424,6 @@ static class ScriptEngine
}
private static void GetComponentsFromAssemblies()
{
ClearDictionaryAndReleaseValues!(_componentClasses);
MonoTableInfo* typeDefinitionsTable = Mono.mono_image_get_table_info(s_CoreAssemblyImage, .MONO_TABLE_TYPEDEF);
int32 numTypes = Mono.mono_table_info_get_rows(typeDefinitionsTable);