From 61bbb1bc685f9f8549498455b0f994a6d569fa28 Mon Sep 17 00:00:00 2001 From: Misaki Date: Sat, 31 May 2025 01:45:34 +0900 Subject: [PATCH] Refactor project structure and enhance functionality Added `InternalsVisibleTo` attribute for "Ghost.Editor" in `AssemblyInfo.cs`. Added a binary file `Empty.zip` to the project. Added a new `ProjectMetadata` class in `ProjectMetadata.cs`. Added new states and interfaces for managing application states in `EditorState.cs`, `LandingState.cs`, and `IAppState.cs`. Added a notification service in `INotificationService.cs` and `StackedNotificationService.cs`. Added new XAML files for UI components, including `InspectorView.xaml` and `InternalControls.xaml`. Changed the `ProjectInfo` class in `ProjectInfo.cs` to include a `MetadataPath` property instead of `Path` and `EngineVersion`. Changed the `TemplateInfo` class in `TemplateInfo.cs` to use a struct instead of a class for `TemplateData`. Changed the `ProjectService` class to use the new `ProjectRepository` for managing project data. Removed several using directives and the entire `ProjectRepository` class from `ProjectRepository.cs`, replacing it with a new implementation. Removed old methods and properties in `EntityManager` and `World` classes to improve entity management and component handling. Updated the `Ghost.Data.csproj` file to include the new `Empty.zip` file as a content item. Updated the `ProjectRepository` class to manage project data using SQLite. Updated various XAML files to include new styles and controls, improving the overall UI design. Updated the `CreateProjectViewModel` to include a notification service and handle project creation logic. Updated the test project to include references to the new `Ghost.Graphics` project and modified test cases to align with the new structure. --- Ghost.Data/AssemblyInfo.cs | 3 + Ghost.Data/Assets/ProjectTemplates/Empty.zip | Bin 0 -> 174271 bytes Ghost.Data/DataContext/ProjectRepository.cs | 101 ------- Ghost.Data/Ghost.Data.csproj | 6 + Ghost.Data/JsonContext.cs | 1 + Ghost.Data/Models/ProjectInfo.cs | 14 +- Ghost.Data/Models/ProjectMetadata.cs | 51 ++++ Ghost.Data/Models/Result.cs | 53 ++++ Ghost.Data/Models/TemplateInfo.cs | 8 +- Ghost.Data/Repository/ProjectRepository.cs | 99 +++++++ Ghost.Data/Resources/AssetsPath.cs | 2 +- Ghost.Data/Resources/DataPath.cs | 4 +- Ghost.Data/Services/ProjectService.cs | 179 +++++++++--- Ghost.Editor/ActivationHandler.cs | 10 +- Ghost.Editor/App.xaml | 2 + Ghost.Editor/App.xaml.cs | 55 ++-- Ghost.Editor/AppStates/EditorState.cs | 54 ++++ Ghost.Editor/AppStates/LandingState.cs | 47 +++ Ghost.Editor/AppStates/StateKey.cs | 8 + Ghost.Editor/Contracts/IAppState.cs | 33 +++ .../Contracts/INotificationService.cs | 14 + Ghost.Editor/Controls/EditorControls.xaml | 1 + .../Controls/Internal/InspectorView.cs | 24 ++ .../Controls/Internal/InspectorView.xaml | 41 +++ .../Controls/Internal/InternalControls.xaml | 4 + Ghost.Editor/Ghost.Editor.csproj | 56 +++- Ghost.Editor/Helpers/ComponentTypeCache.cs | 30 ++ .../Converters/GetDirectoryNameConverter .cs | 17 ++ Ghost.Editor/Helpers/HostHelpers.Page.cs | 10 +- Ghost.Editor/Helpers/SystemUtilities.cs | 20 +- Ghost.Editor/Models/GameObject.cs | 269 ++++++++++++++++++ .../Models/Scene.cs | 10 +- Ghost.Editor/Services/AppStateService.cs | 35 +++ .../Services/StackedNotificationService.cs | 50 ++++ Ghost.Editor/Themes/Dark.xaml | 8 + Ghost.Editor/Themes/Light.xaml | 8 + .../View/Pages/EngineEditor/ConsolePage.xaml | 73 +++++ .../Pages/EngineEditor/ConsolePage.xaml.cs | 11 + .../View/Pages/EngineEditor/ProjectPage.xaml | 71 +++++ .../Pages/EngineEditor/ProjectPage.xaml.cs | 30 ++ .../View/Pages/Landing/CreateProjectPage.xaml | 17 +- .../View/Pages/Landing/OpenProjectPage.xaml | 194 ++++++++----- .../Pages/Landing/OpenProjectPage.xaml.cs | 109 +++++-- .../View/Windows/EngineEditorWindow.xaml | 43 +-- .../View/Windows/EngineEditorWindow.xaml.cs | 24 +- Ghost.Editor/View/Windows/LandingWindow.xaml | 19 +- .../View/Windows/LandingWindow.xaml.cs | 21 +- .../Pages/EngineEditor/ProjectViewModel.cs | 5 + .../Pages/Landing/CreateProjectViewModel.cs | 47 ++- .../Windows/EngineEditorViewModel.cs | 4 +- Ghost.Engine/GameObject.cs | 190 ------------- Ghost.Engine/Resources/EngineData.cs | 2 +- Ghost.Engine/Services/PlayerLoopService.cs | 50 ++-- Ghost.Engine/Services/SceneManager.cs | 68 +++-- Ghost.Entities/AssemblyInfo.cs | 1 + Ghost.Entities/Component.cs | 69 ++++- Ghost.Entities/Entity.cs | 78 +++-- Ghost.Entities/Helpers/EntityHelpers.cs | 4 +- Ghost.Entities/Query/QueryFilter.cs | 6 +- Ghost.Entities/ScriptComponent.cs | 24 +- Ghost.Entities/System.cs | 56 +++- Ghost.Entities/Utilities/Box.cs | 19 -- Ghost.Entities/Utilities/ComponentMask.cs | 64 ----- Ghost.Entities/World.cs | 24 +- Ghost.Test/Ghost.Test.csproj | 2 +- Ghost.Test/Program.cs | 4 +- 66 files changed, 1923 insertions(+), 733 deletions(-) create mode 100644 Ghost.Data/AssemblyInfo.cs create mode 100644 Ghost.Data/Assets/ProjectTemplates/Empty.zip delete mode 100644 Ghost.Data/DataContext/ProjectRepository.cs create mode 100644 Ghost.Data/Models/ProjectMetadata.cs create mode 100644 Ghost.Data/Models/Result.cs create mode 100644 Ghost.Data/Repository/ProjectRepository.cs create mode 100644 Ghost.Editor/AppStates/EditorState.cs create mode 100644 Ghost.Editor/AppStates/LandingState.cs create mode 100644 Ghost.Editor/AppStates/StateKey.cs create mode 100644 Ghost.Editor/Contracts/IAppState.cs create mode 100644 Ghost.Editor/Contracts/INotificationService.cs create mode 100644 Ghost.Editor/Controls/Internal/InspectorView.cs create mode 100644 Ghost.Editor/Controls/Internal/InspectorView.xaml create mode 100644 Ghost.Editor/Controls/Internal/InternalControls.xaml create mode 100644 Ghost.Editor/Helpers/ComponentTypeCache.cs create mode 100644 Ghost.Editor/Helpers/Converters/GetDirectoryNameConverter .cs create mode 100644 Ghost.Editor/Models/GameObject.cs rename {Ghost.Engine => Ghost.Editor}/Models/Scene.cs (65%) create mode 100644 Ghost.Editor/Services/AppStateService.cs create mode 100644 Ghost.Editor/Services/StackedNotificationService.cs create mode 100644 Ghost.Editor/Themes/Dark.xaml create mode 100644 Ghost.Editor/Themes/Light.xaml create mode 100644 Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml create mode 100644 Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml.cs create mode 100644 Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml create mode 100644 Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml.cs create mode 100644 Ghost.Editor/ViewModel/Pages/EngineEditor/ProjectViewModel.cs delete mode 100644 Ghost.Engine/GameObject.cs delete mode 100644 Ghost.Entities/Utilities/Box.cs delete mode 100644 Ghost.Entities/Utilities/ComponentMask.cs diff --git a/Ghost.Data/AssemblyInfo.cs b/Ghost.Data/AssemblyInfo.cs new file mode 100644 index 0000000..9092fb4 --- /dev/null +++ b/Ghost.Data/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Ghost.Editor")] diff --git a/Ghost.Data/Assets/ProjectTemplates/Empty.zip b/Ghost.Data/Assets/ProjectTemplates/Empty.zip new file mode 100644 index 0000000000000000000000000000000000000000..07d03d4445af49f0f92bba0f71a6ccaf9ae7990b GIT binary patch literal 174271 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�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

=%VyyKPX5GxR?5Zd4Xi4!z`YH9}dd;dq{V# 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 string.Format(Command.CONNECTION_STRING, DataPath.APPLICATION_DATA_FOLDER); - - private static async Task EnsureTableCreatedAsync(SQLiteConnection connection) - { - using var createCommand = connection.CreateCommand(); - createCommand.CommandText = Command.CREATE_PROJECT_TABLE_STRING; - await createCommand.ExecuteNonQueryAsync(); - } - - public static async IAsyncEnumerable LoadProjectsAsync() - { - using var connection = new SQLiteConnection(GetConnectionString()); - await connection.OpenAsync(); - - await EnsureTableCreatedAsync(connection); - - using var command = connection.CreateCommand(); - command.CommandText = Command.SELECT_PROJECT_STRING; - - using var reader = command.ExecuteReader(); - while (await reader.ReadAsync()) - { - var project = new ProjectInfo - { - ID = reader.GetInt32(0), - Name = reader.GetString(1), - Path = reader.GetString(2), - EngineVersion = new Version(reader.GetString(3)), - LastOpened = reader.GetDateTime(4) - }; - - yield return project; - } - } - - public static async Task AddProjectAsync(ProjectInfo project) - { - using var connection = new SQLiteConnection(GetConnectionString()); - await connection.OpenAsync(); - - await EnsureTableCreatedAsync(connection); - - using var command = connection.CreateCommand(); - command.CommandText = Command.INSERT_PROJECT_STRING; - - command.Parameters.AddWithValue("@Name", project.Name); - command.Parameters.AddWithValue("@Path", project.Path); - command.Parameters.AddWithValue("@EngineVersion", project.EngineVersion.ToString()); - command.Parameters.AddWithValue("@LastOpened", project.LastOpened); - - await command.ExecuteNonQueryAsync(); - } - - public static async Task RemoveProjectAsync(ProjectInfo project) - { - using var connection = new SQLiteConnection(GetConnectionString()); - await connection.OpenAsync(); - - using var command = connection.CreateCommand(); - command.CommandText = Command.REMOVE_PROJECT_STRING; - - command.Parameters.AddWithValue("@ID", project.ID); - - await command.ExecuteNonQueryAsync(); - } - - public static async Task UpdateProjectAsync(ProjectInfo project) - { - using var connection = new SQLiteConnection(GetConnectionString()); - await connection.OpenAsync(); - - using var command = connection.CreateCommand(); - command.CommandText = Command.UPDATE_PROJECT_STRING; - - command.Parameters.AddWithValue("@Name", project.Name); - command.Parameters.AddWithValue("@Path", project.Path); - command.Parameters.AddWithValue("@EngineVersion", project.EngineVersion.ToString()); - command.Parameters.AddWithValue("@LastOpened", project.LastOpened); - command.Parameters.AddWithValue("@ID", project.ID); // Ensure the ID parameter is added - - await command.ExecuteNonQueryAsync(); - } -} \ No newline at end of file diff --git a/Ghost.Data/Ghost.Data.csproj b/Ghost.Data/Ghost.Data.csproj index a1e8b61..d2c294e 100644 --- a/Ghost.Data/Ghost.Data.csproj +++ b/Ghost.Data/Ghost.Data.csproj @@ -20,4 +20,10 @@ + + + PreserveNewest + + + diff --git a/Ghost.Data/JsonContext.cs b/Ghost.Data/JsonContext.cs index 330ecc2..ec6f6b1 100644 --- a/Ghost.Data/JsonContext.cs +++ b/Ghost.Data/JsonContext.cs @@ -5,6 +5,7 @@ namespace Ghost.Data; [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(TemplateInfo))] +[JsonSerializable(typeof(ProjectMetadata))] internal partial class JsonContext : JsonSerializerContext { } \ No newline at end of file diff --git a/Ghost.Data/Models/ProjectInfo.cs b/Ghost.Data/Models/ProjectInfo.cs index b44ca12..ba10f9a 100644 --- a/Ghost.Data/Models/ProjectInfo.cs +++ b/Ghost.Data/Models/ProjectInfo.cs @@ -2,7 +2,7 @@ namespace Ghost.Data.Models; -public class ProjectInfo +internal class ProjectInfo { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID @@ -15,17 +15,7 @@ public class ProjectInfo get; set; } - public required string Path - { - get; set; - } - - public required Version EngineVersion - { - get; set; - } - - public required DateTime LastOpened + public required string MetadataPath { get; set; } diff --git a/Ghost.Data/Models/ProjectMetadata.cs b/Ghost.Data/Models/ProjectMetadata.cs new file mode 100644 index 0000000..15b6aee --- /dev/null +++ b/Ghost.Data/Models/ProjectMetadata.cs @@ -0,0 +1,51 @@ +namespace Ghost.Data.Models; + +public class ProjectMetadata +{ + public const string PROJECT_EXTENSION = "ghostproj"; + + public Guid ID + { + get; set; + } + + public string Name + { + get; set; + } + + public Version EngineVersion + { + get; set; + } + + public DateTime CreatedAt + { + get; set; + } + + public DateTime LastOpened + { + get; set; + } + + public ProjectMetadata(string name, Version engineVersion) + { + ID = Guid.NewGuid(); + Name = name; + EngineVersion = engineVersion; + CreatedAt = DateTime.UtcNow; + LastOpened = DateTime.UtcNow; + } + + // Parameterless constructor for deserialization + public ProjectMetadata() + { + } +} + +public readonly struct ProjectMetadataInfo(string path, ProjectMetadata metadata) +{ + public readonly string Path => path; + public readonly ProjectMetadata Metadata => metadata; +} \ No newline at end of file diff --git a/Ghost.Data/Models/Result.cs b/Ghost.Data/Models/Result.cs new file mode 100644 index 0000000..134cca9 --- /dev/null +++ b/Ghost.Data/Models/Result.cs @@ -0,0 +1,53 @@ +namespace Ghost.Data.Models; + +public readonly struct Result +{ + public readonly bool success; + + public readonly string? message; + + public Result(bool success, string? message = null) + { + this.success = success; + this.message = message; + } + + public static Result OK() + { + return new Result(true); + } + + public static Result Error(string? message) + { + return new Result(false, message); + } + + public override string ToString() => success ? "OK" : $"Error: {message}"; +} + +public readonly struct Result +{ + public readonly bool success; + public readonly T? data; + + public readonly string? message; + + public Result(bool success, T? data, string? message = null) + { + this.success = success; + this.data = data; + this.message = message; + } + + public static Result OK(T data) + { + return new Result(true, data); + } + + public static Result Error(string? message) + { + return new Result(false, default, message); + } + + public override string ToString() => success ? $"OK: {data}" : $"Error: {message}"; +} diff --git a/Ghost.Data/Models/TemplateInfo.cs b/Ghost.Data/Models/TemplateInfo.cs index 3585b50..4b8ee71 100644 --- a/Ghost.Data/Models/TemplateInfo.cs +++ b/Ghost.Data/Models/TemplateInfo.cs @@ -23,21 +23,21 @@ public class TemplateInfo } } -public class TemplateData(string templatePath, TemplateInfo info) +public struct TemplateData(string templatePath, TemplateInfo info) { private const string _ICON_NAME = "icon.png"; private const string _PREVIEW_NAME = "preview.png"; public string directory = Path.GetDirectoryName(templatePath)!; - public TemplateInfo Info => info; + public readonly TemplateInfo Info => info; - public Uri GetIconURI() + public readonly Uri GetIconURI() { return new Uri(Path.Combine(directory, _ICON_NAME)); } - public Uri GetPreviewURI() + public readonly Uri GetPreviewURI() { return new Uri(Path.Combine(directory, _PREVIEW_NAME)); } diff --git a/Ghost.Data/Repository/ProjectRepository.cs b/Ghost.Data/Repository/ProjectRepository.cs new file mode 100644 index 0000000..a45755e --- /dev/null +++ b/Ghost.Data/Repository/ProjectRepository.cs @@ -0,0 +1,99 @@ +using Ghost.Data.Models; +using System.Data; +using System.Data.SQLite; + +namespace Ghost.Data.Repository; + +internal class ProjectRepository : IDisposable +{ + private readonly SQLiteConnection _connection; + + public ProjectRepository(string sourceDirectory) + { + _connection = new SQLiteConnection(string.Format(Command.CONNECTION_STRING, sourceDirectory)); + _connection.Open(); + } + + private static class Command + { + public const string CONNECTION_STRING = "Data Source={0}\\projects.db;Version=3;"; + public const string CREATE_PROJECT_TABLE_STRING = "CREATE TABLE IF NOT EXISTS Projects (ID INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT, MetadataPath TEXT);"; + public const string SELECT_PROJECT_STRING = "SELECT * FROM Projects"; + public const string INSERT_PROJECT_STRING = "INSERT INTO Projects (Name, MetadataPath) VALUES (@Name, @MetadataPath);"; + public const string REMOVE_PROJECT_STRING = "DELETE FROM Projects WHERE ID = @ID;"; + public const string UPDATE_PROJECT_STRING = "UPDATE Projects SET Name = @Name, MetadataPath = @MetadataPath WHERE ID = @ID;"; + } + + private async Task EnsureTableCreatedAsync() + { + using var createCommand = _connection.CreateCommand(); + createCommand.CommandText = Command.CREATE_PROJECT_TABLE_STRING; + await createCommand.ExecuteNonQueryAsync(); + } + + public async IAsyncEnumerable LoadProjectsAsync() + { + await EnsureTableCreatedAsync(); + + using var command = _connection.CreateCommand(); + command.CommandText = Command.SELECT_PROJECT_STRING; + + using var reader = command.ExecuteReader(); + while (await reader.ReadAsync()) + { + var project = new ProjectInfo + { + ID = reader.GetInt32(0), + Name = reader.GetString(1), + MetadataPath = reader.GetString(2), + }; + + yield return project; + } + } + + public async Task AddProjectAsync(ProjectInfo project) + { + await EnsureTableCreatedAsync(); + + using var command = _connection.CreateCommand(); + command.CommandText = Command.INSERT_PROJECT_STRING; + + command.Parameters.AddWithValue("@Name", project.Name); + command.Parameters.AddWithValue("@MetadataPath", project.MetadataPath); + + await command.ExecuteNonQueryAsync(); + } + + public async Task RemoveProjectAsync(ProjectInfo project) + { + using var command = _connection.CreateCommand(); + command.CommandText = Command.REMOVE_PROJECT_STRING; + + command.Parameters.AddWithValue("@ID", project.ID); + + await command.ExecuteNonQueryAsync(); + } + + public async Task UpdateProjectAsync(ProjectInfo project) + { + using var command = _connection.CreateCommand(); + command.CommandText = Command.UPDATE_PROJECT_STRING; + + command.Parameters.AddWithValue("@Name", project.Name); + command.Parameters.AddWithValue("@MetadataPath", project.MetadataPath); + command.Parameters.AddWithValue("@ID", project.ID); + + await command.ExecuteNonQueryAsync(); + } + + public void Dispose() + { + if (_connection.State == ConnectionState.Open) + { + _connection.Close(); + } + + _connection.Dispose(); + } +} \ No newline at end of file diff --git a/Ghost.Data/Resources/AssetsPath.cs b/Ghost.Data/Resources/AssetsPath.cs index e800f20..2c3f7d2 100644 --- a/Ghost.Data/Resources/AssetsPath.cs +++ b/Ghost.Data/Resources/AssetsPath.cs @@ -4,5 +4,5 @@ public static class AssetsPath { public const string ASSETS_FOLDER = "Assets"; - public readonly static string AppIconPath = Path.Combine(AppContext.BaseDirectory, $"{ASSETS_FOLDER}/Icon-256.ico"); + public readonly static string s_appIconPath = Path.Combine(AppContext.BaseDirectory, $"{ASSETS_FOLDER}/Icon-256.ico"); } \ No newline at end of file diff --git a/Ghost.Data/Resources/DataPath.cs b/Ghost.Data/Resources/DataPath.cs index 486a2bd..a8d9b51 100644 --- a/Ghost.Data/Resources/DataPath.cs +++ b/Ghost.Data/Resources/DataPath.cs @@ -4,6 +4,6 @@ public class DataPath { public const string ENGINE_DATA_FOLDER_NAME = "GhostEngine"; - public readonly static string APPLICATION_DATA_FOLDER = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ENGINE_DATA_FOLDER_NAME); - public readonly static string PROJECT_TEMPLATES_FOLDER = Path.Combine(APPLICATION_DATA_FOLDER, "ProjectTemplates"); + public readonly static string s_applicationDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ENGINE_DATA_FOLDER_NAME); + public readonly static string s_projectTemplateFolder = Path.Combine(s_applicationDataFolder, "ProjectTemplates"); } \ No newline at end of file diff --git a/Ghost.Data/Services/ProjectService.cs b/Ghost.Data/Services/ProjectService.cs index 42b1633..1a07763 100644 --- a/Ghost.Data/Services/ProjectService.cs +++ b/Ghost.Data/Services/ProjectService.cs @@ -1,25 +1,38 @@ -using Ghost.Data.DataContext; -using Ghost.Data.Models; +using Ghost.Data.Models; +using Ghost.Data.Repository; using Ghost.Data.Resources; using System.IO.Compression; using System.Text.Json; namespace Ghost.Data.Services; -public class ProjectService +internal partial class ProjectService { private const string _ASSETS_FOLDER = "Assets"; + private const string _CONFIG_FOLDER = "ProjectConfig"; private const string _TEMPLATE_CONTENT_FILE = "content.zip"; - public async IAsyncEnumerable<(string path, TemplateInfo info)> GetProjectTemplatesAsync() + public static void EnsureDefaultTemplate() { - var templatesFolder = DataPath.PROJECT_TEMPLATES_FOLDER; + var templates = Directory.GetFiles(DataPath.s_projectTemplateFolder, "template.json", SearchOption.AllDirectories); + if (templates.Length > 0) + { + return; // Default template already exists + } + + var defaultTemplatePath = Path.Combine(AppContext.BaseDirectory, "Assets/ProjectTemplates/Empty.zip"); + ZipFile.ExtractToDirectory(defaultTemplatePath, DataPath.s_projectTemplateFolder, true); + } + + public static async IAsyncEnumerable<(string path, TemplateInfo info)> GetProjectTemplatesAsync() + { + var templatesFolder = DataPath.s_projectTemplateFolder; if (!Directory.Exists(templatesFolder)) { yield break; } - var templates = Directory.GetFiles(DataPath.PROJECT_TEMPLATES_FOLDER, "template.json", SearchOption.AllDirectories); + var templates = Directory.GetFiles(DataPath.s_projectTemplateFolder, "template.json", SearchOption.AllDirectories); foreach (var templatePath in templates) { var fileStream = File.OpenRead(templatePath); @@ -33,68 +46,152 @@ public class ProjectService } } - private Task SetupAssetsFolder(string projectPath, string templatePath) + public static async Task CreateMetadataFileAsync(string path, ProjectMetadata metadata) { - return Task.Run(() => - { - var templateContentPath = Path.Combine(templatePath, _TEMPLATE_CONTENT_FILE); - var projectAssetsPath = Path.Combine(projectPath, _ASSETS_FOLDER); - - Directory.CreateDirectory(projectAssetsPath); - - if (!File.Exists(templateContentPath)) - { - return; - } - - ZipFile.ExtractToDirectory(templateContentPath, projectAssetsPath); - }); + await using var fileStream = File.Create(path); + await JsonSerializer.SerializeAsync(fileStream, metadata, JsonContext.Default.ProjectMetadata); } - public IAsyncEnumerable LoadAllProjectAsync() + public static async Task LoadMetadataAsync(string ghostprojPath) { - return ProjectRepository.LoadProjectsAsync(); - } - - public async Task CreateProjectAsync(string projectName, string projectDirectory, string templatePath) - { - var projectPath = Path.Combine(projectDirectory, projectName); - if (!Directory.Exists(projectPath)) + if (!File.Exists(ghostprojPath)) { - Directory.CreateDirectory(projectPath); + throw new FileNotFoundException("Project metadata file not found.", ghostprojPath); } - await SetupAssetsFolder(projectPath, templatePath); - - return projectPath; + await using var fileStream = File.OpenRead(ghostprojPath); + return await JsonSerializer.DeserializeAsync(fileStream, JsonContext.Default.ProjectMetadata); } + public static async Task> ValidateProjectDirectoryAsync(string? projectDirectory) + { + if (string.IsNullOrWhiteSpace(projectDirectory) || !Directory.Exists(projectDirectory)) + { + return Result.Error("Project directory is invalid or does not exist."); + } + + var projectAssetsPath = Path.Combine(projectDirectory, _ASSETS_FOLDER); + var projectConfigPath = Path.Combine(projectDirectory, _CONFIG_FOLDER); + if (!Directory.Exists(projectAssetsPath) || !Directory.Exists(projectConfigPath)) + { + return Result.Error("Project folder structure is invalid."); + } + + var metadataPath = Directory.GetFiles(projectDirectory, $"*.{ProjectMetadata.PROJECT_EXTENSION}", SearchOption.TopDirectoryOnly).FirstOrDefault(); + if (string.IsNullOrWhiteSpace(metadataPath) || !File.Exists(metadataPath)) + { + return Result.Error("Project metadata file not found."); + } + + var metadata = await LoadMetadataAsync(metadataPath); + if (metadata == null) + { + return Result.Error("Project metadata file is corrupted or invalid."); + } + + return Result.OK(new(metadataPath, metadata)); + } + + private static async ValueTask SetupRequestFolderAsync(string projectDirectory, string templateDirectory) + { + var projectAssetsPath = Path.Combine(projectDirectory, _ASSETS_FOLDER); + var projectConfigPath = Path.Combine(projectDirectory, _CONFIG_FOLDER); + var templateContentPath = Path.Combine(templateDirectory, _TEMPLATE_CONTENT_FILE); + + Directory.CreateDirectory(projectAssetsPath); + if (File.Exists(templateContentPath)) + { + await Task.Run(() => + { + ZipFile.ExtractToDirectory(templateContentPath, projectAssetsPath); + }); + } + + Directory.CreateDirectory(projectConfigPath); + } +} + +internal partial class ProjectService : IDisposable +{ + private readonly ProjectRepository _repository = new(DataPath.s_applicationDataFolder); + public Task AddProjectAsync(ProjectInfo project) { - return ProjectRepository.AddProjectAsync(project); + return _repository.AddProjectAsync(project); } - public async Task AddProjectAsync(string name, string path, Version version) + public async Task AddProjectAsync(string name, string path) { var project = new ProjectInfo { Name = name, - Path = path, - EngineVersion = version, - LastOpened = DateTime.Now + MetadataPath = path, }; - await ProjectRepository.AddProjectAsync(project); + await _repository.AddProjectAsync(project); return project; } public Task RemoveProjectAsync(ProjectInfo project) { - return ProjectRepository.RemoveProjectAsync(project); + return _repository.RemoveProjectAsync(project); } public Task UpdateProjectAsync(ProjectInfo project) { - return ProjectRepository.UpdateProjectAsync(project); + return _repository.UpdateProjectAsync(project); + } + + public IAsyncEnumerable LoadAllProjectAsync() + { + return _repository.LoadProjectsAsync(); + } + + public async Task> CreateProjectAsync(string projectName, string projectDirectory, Version engineVersion, string templatePath) + { + try + { + var projectPath = Path.Combine(projectDirectory, projectName); + if (!Directory.Exists(projectPath)) + { + Directory.CreateDirectory(projectPath); + } + else + { + // Check if folder is empty + if (Directory.EnumerateFiles(projectPath, "*", SearchOption.AllDirectories).Any()) + { + return new(false, null, "Directory is not empty"); + } + } + + var metadata = new ProjectMetadata(projectName, engineVersion); + var metadataPath = Path.Combine(projectPath, $"{projectName}.{ProjectMetadata.PROJECT_EXTENSION}"); + await CreateMetadataFileAsync(metadataPath, metadata); + await SetupRequestFolderAsync(projectPath, templatePath); + + var info = await AddProjectAsync(projectName, metadataPath); + return new(true, info); + } + catch (Exception e) + { + return Result.Error($"Failed to create project: {e.Message}"); + } + } + + public async Task> AddProjectFromDirectoryAsync(string projectDirectory) + { + var result = await ValidateProjectDirectoryAsync(projectDirectory); + if (result.success) + { + await AddProjectAsync(result.data.Metadata.Name, result.data.Path); + } + + return result; + } + + public void Dispose() + { + _repository.Dispose(); } } \ No newline at end of file diff --git a/Ghost.Editor/ActivationHandler.cs b/Ghost.Editor/ActivationHandler.cs index b920373..03e16e5 100644 --- a/Ghost.Editor/ActivationHandler.cs +++ b/Ghost.Editor/ActivationHandler.cs @@ -1,4 +1,5 @@ using Ghost.Data.Resources; +using Ghost.Data.Services; using Microsoft.UI.Xaml; using System.IO; @@ -8,19 +9,20 @@ internal static class ActivationHandler { private static void FolderInitialization() { - if (!Directory.Exists(DataPath.APPLICATION_DATA_FOLDER)) + if (!Directory.Exists(DataPath.s_applicationDataFolder)) { - Directory.CreateDirectory(DataPath.APPLICATION_DATA_FOLDER); + Directory.CreateDirectory(DataPath.s_applicationDataFolder); } - if (!Directory.Exists(DataPath.PROJECT_TEMPLATES_FOLDER)) + if (!Directory.Exists(DataPath.s_projectTemplateFolder)) { - Directory.CreateDirectory(DataPath.PROJECT_TEMPLATES_FOLDER); + Directory.CreateDirectory(DataPath.s_projectTemplateFolder); } } public static void Handle(LaunchActivatedEventArgs args) { FolderInitialization(); + ProjectService.EnsureDefaultTemplate(); } } \ No newline at end of file diff --git a/Ghost.Editor/App.xaml b/Ghost.Editor/App.xaml index 379f5c5..b414503 100644 --- a/Ghost.Editor/App.xaml +++ b/Ghost.Editor/App.xaml @@ -9,6 +9,8 @@ + + diff --git a/Ghost.Editor/App.xaml.cs b/Ghost.Editor/App.xaml.cs index 6c28d67..434e791 100644 --- a/Ghost.Editor/App.xaml.cs +++ b/Ghost.Editor/App.xaml.cs @@ -1,6 +1,6 @@ -using Ghost.Data.Services; +using Ghost.Editor.AppStates; using Ghost.Editor.Helpers; -using Ghost.Editor.View.Windows; +using Ghost.Editor.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.UI.Xaml; @@ -18,6 +18,18 @@ namespace Ghost.Editor { private Window? _window; + internal static Window? Window + { + get => (Current as App)?._window; + set + { + if (Current is App app) + { + app._window = value; + } + } + } + internal IHost Host { get; @@ -36,27 +48,29 @@ namespace Ghost.Editor UseContentRoot(AppContext.BaseDirectory). ConfigureServices((context, services) => { - services.AddSingleton(); + services.AddSingleton(sp => + { + return new AppStateService( + new LandingState(), + new EditorState()); + }); - HostHelper.SetupPageService(context, services); + HostHelper.AddLandingScope(context, services); + HostHelper.AddEngineScope(context, services); + + services.AddSingleton(); }) .Build(); + + UnhandledException += App_UnhandledException; } - internal static Window? GetWindow() + internal static IServiceScope CreateScope() { - return (Current as App)?._window; + return (Current as App)!.Host.Services.CreateScope(); } - internal static void SetWindow(Window window) - { - if (Current is App app) - { - app._window = window; - } - } - - internal static T GetService() where T : class + public static T GetService() where T : class { if ((Current as App)!.Host.Services.GetService(typeof(T)) is not T service) { @@ -70,7 +84,7 @@ namespace Ghost.Editor /// Invoked when the application is launched. /// /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs args) + protected override async void OnLaunched(LaunchActivatedEventArgs args) { base.OnLaunched(args); @@ -78,8 +92,13 @@ namespace Ghost.Editor Host.Start(); - _window = GetService(); - _window.Activate(); + await GetService().TransitionToAsync(StateKey.Landing); + } + + private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) + { + // TODO: Log and handle exceptions as appropriate. + // https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception. } } } \ No newline at end of file diff --git a/Ghost.Editor/AppStates/EditorState.cs b/Ghost.Editor/AppStates/EditorState.cs new file mode 100644 index 0000000..46e3055 --- /dev/null +++ b/Ghost.Editor/AppStates/EditorState.cs @@ -0,0 +1,54 @@ +using Ghost.Data.Models; +using Ghost.Editor.Contracts; +using Ghost.Editor.View.Windows; +using System.Threading.Tasks; + +namespace Ghost.Editor.AppStates; + +internal class EditorState : IAppState +{ + private EngineEditorWindow? _window; + + public StateKey StateKy => StateKey.EngineEditor; + + public Task OnExitingAsync() + { + if (App.Window == _window) + { + App.Window = null; + } + return Task.CompletedTask; + } + + public Task OnEnteringAsync(object? parameter) + { + if (parameter is not ProjectMetadata metadata) + { + throw new System.ArgumentException("Parameter must be of type ProjectMetadata.", nameof(parameter)); + } + + _window = App.GetService(); + _window.ViewModel.CurrentProject = metadata; + _window.Activate(); + + App.Window = _window; + return Task.CompletedTask; + } + + public Task OnExitedAsync() + { + if (App.Window == _window) + { + App.Window = null; + } + + _window?.Close(); + _window = null; + return Task.CompletedTask; + } + + public Task OnEnteredAsync(object? parameter) + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Ghost.Editor/AppStates/LandingState.cs b/Ghost.Editor/AppStates/LandingState.cs new file mode 100644 index 0000000..fd0de78 --- /dev/null +++ b/Ghost.Editor/AppStates/LandingState.cs @@ -0,0 +1,47 @@ +using Ghost.Editor.Contracts; +using Ghost.Editor.View.Windows; +using System.Threading.Tasks; + +namespace Ghost.Editor.AppStates; + +internal class LandingState : IAppState +{ + private LandingWindow? _window; + + public StateKey StateKy => StateKey.Landing; + + public Task OnExitingAsync() + { + if (App.Window == _window) + { + App.Window = null; + } + return Task.CompletedTask; + } + + public Task OnEnteringAsync(object? parameter) + { + _window = App.GetService(); + App.Window = _window; + + _window.Activate(); + return Task.CompletedTask; + } + + public Task OnExitedAsync() + { + if (App.Window == _window) + { + App.Window = null; + } + + _window?.Close(); + _window = null; + return Task.CompletedTask; + } + + public Task OnEnteredAsync(object? parameter) + { + return Task.CompletedTask; + } +} diff --git a/Ghost.Editor/AppStates/StateKey.cs b/Ghost.Editor/AppStates/StateKey.cs new file mode 100644 index 0000000..c4eb4b2 --- /dev/null +++ b/Ghost.Editor/AppStates/StateKey.cs @@ -0,0 +1,8 @@ +namespace Ghost.Editor.AppStates; + +internal enum StateKey +{ + None, + Landing, + EngineEditor, +} \ No newline at end of file diff --git a/Ghost.Editor/Contracts/IAppState.cs b/Ghost.Editor/Contracts/IAppState.cs new file mode 100644 index 0000000..511ec2f --- /dev/null +++ b/Ghost.Editor/Contracts/IAppState.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; + +namespace Ghost.Editor.Contracts; + +internal interface IAppState +{ + public Key StateKy + { + get; + } + + ///

+ /// Called when exiting the state. + /// + public Task OnExitingAsync(); + + /// + /// Called when entering the state, right after OnEnteringAsync. + /// can be used to pass data into the state, such as a project to load. + /// + public Task OnEnteringAsync(object? parameter); + + /// + /// Called when exiting the state, specifically for pose transitions. + /// + public Task OnExitedAsync(); + + /// + /// Called when entered the state, specifically after the state has been fully initialized and is ready for interaction. + /// + /// can be used to pass data into the state, such as a project to load. + public Task OnEnteredAsync(object? parameter); +} \ No newline at end of file diff --git a/Ghost.Editor/Contracts/INotificationService.cs b/Ghost.Editor/Contracts/INotificationService.cs new file mode 100644 index 0000000..8669e48 --- /dev/null +++ b/Ghost.Editor/Contracts/INotificationService.cs @@ -0,0 +1,14 @@ +using Microsoft.UI.Xaml.Controls; + +namespace Ghost.Editor.Contracts; + +internal interface INotificationService +{ + public void ShowNotification(string? message, InfoBarSeverity severity, int duration = 5, string? title = null); +} + +internal interface INotificationService : INotificationService +{ + public void Initialize(T notificationQueue); + public void ClearQueueReference(); +} \ No newline at end of file diff --git a/Ghost.Editor/Controls/EditorControls.xaml b/Ghost.Editor/Controls/EditorControls.xaml index f3768a7..ac96cd7 100644 --- a/Ghost.Editor/Controls/EditorControls.xaml +++ b/Ghost.Editor/Controls/EditorControls.xaml @@ -2,5 +2,6 @@ + diff --git a/Ghost.Editor/Controls/Internal/InspectorView.cs b/Ghost.Editor/Controls/Internal/InspectorView.cs new file mode 100644 index 0000000..e87b7d6 --- /dev/null +++ b/Ghost.Editor/Controls/Internal/InspectorView.cs @@ -0,0 +1,24 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Ghost.Editor.Controls.Internal; + +internal sealed partial class InspectorView : ContentControl +{ + public UIElement? Header + { + get => (UIElement)GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( + nameof(Header), + typeof(UIElement), + typeof(InspectorView), + new PropertyMetadata(null)); + + public InspectorView() + { + DefaultStyleKey = typeof(InspectorView); + } +} diff --git a/Ghost.Editor/Controls/Internal/InspectorView.xaml b/Ghost.Editor/Controls/Internal/InspectorView.xaml new file mode 100644 index 0000000..9dccfeb --- /dev/null +++ b/Ghost.Editor/Controls/Internal/InspectorView.xaml @@ -0,0 +1,41 @@ + + + + diff --git a/Ghost.Editor/Controls/Internal/InternalControls.xaml b/Ghost.Editor/Controls/Internal/InternalControls.xaml new file mode 100644 index 0000000..795c1fb --- /dev/null +++ b/Ghost.Editor/Controls/Internal/InternalControls.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/Ghost.Editor/Ghost.Editor.csproj b/Ghost.Editor/Ghost.Editor.csproj index b669583..4f27c93 100644 --- a/Ghost.Editor/Ghost.Editor.csproj +++ b/Ghost.Editor/Ghost.Editor.csproj @@ -42,6 +42,12 @@ + + + + + + @@ -69,12 +75,13 @@ - - - + + + + - - + + @@ -98,10 +105,43 @@ - - + - + + + + ..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.Unsafe\bin\Release\net9.0\Misaki.HighPerformance.Unsafe.dll + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + diff --git a/Ghost.Editor/Helpers/ComponentTypeCache.cs b/Ghost.Editor/Helpers/ComponentTypeCache.cs new file mode 100644 index 0000000..8722e94 --- /dev/null +++ b/Ghost.Editor/Helpers/ComponentTypeCache.cs @@ -0,0 +1,30 @@ +using Ghost.Entities; +using System; +using System.Linq; + +namespace Ghost.Editor.Helpers; + +public static class ComponentTypeCache +{ + private static readonly Type?[][] _componentTypes; + + static ComponentTypeCache() + { + _componentTypes = new Type[World.WorldCount][]; + for (var i = 0; i < World.WorldCount; i++) + { + var world = World.GetWorld(i); + var typeHandles = world.ComponentStorage.ComponentPools.Keys; + _componentTypes[i] = typeHandles.Select(handle => Type.GetTypeFromHandle(RuntimeTypeHandle.FromIntPtr(handle))).ToArray(); + } + } + + public static Type?[] GetComponentTypes(int worldIndex) + { + if (worldIndex < 0 || worldIndex >= _componentTypes.Length) + { + throw new ArgumentOutOfRangeException(nameof(worldIndex), "Invalid world index."); + } + return _componentTypes[worldIndex]; + } +} \ No newline at end of file diff --git a/Ghost.Editor/Helpers/Converters/GetDirectoryNameConverter .cs b/Ghost.Editor/Helpers/Converters/GetDirectoryNameConverter .cs new file mode 100644 index 0000000..94eb597 --- /dev/null +++ b/Ghost.Editor/Helpers/Converters/GetDirectoryNameConverter .cs @@ -0,0 +1,17 @@ +using Microsoft.UI.Xaml.Data; +using System; + +namespace Ghost.Editor.Helpers.Converters; + +public partial class GetDirectoryNameConverter : IValueConverter +{ + public object? Convert(object value, Type targetType, object parameter, string language) + { + return value is string path ? System.IO.Path.GetDirectoryName(path) : null; + } + + public object? ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Ghost.Editor/Helpers/HostHelpers.Page.cs b/Ghost.Editor/Helpers/HostHelpers.Page.cs index 423d0c2..0f3e9ab 100644 --- a/Ghost.Editor/Helpers/HostHelpers.Page.cs +++ b/Ghost.Editor/Helpers/HostHelpers.Page.cs @@ -1,4 +1,5 @@ -using Ghost.Editor.View.Pages.Landing; +using Ghost.Data.Services; +using Ghost.Editor.View.Pages.Landing; using Ghost.Editor.View.Windows; using Ghost.Editor.ViewModel.Pages.Landing; using Ghost.Editor.ViewModel.Windows; @@ -9,7 +10,7 @@ namespace Ghost.Editor.Helpers; internal static partial class HostHelper { - public static void SetupPageService(HostBuilderContext context, IServiceCollection services) + public static void AddLandingScope(HostBuilderContext context, IServiceCollection services) { services.AddSingleton(); @@ -18,6 +19,11 @@ internal static partial class HostHelper services.AddTransient(); + services.AddTransient(); + } + + public static void AddEngineScope(HostBuilderContext context, IServiceCollection services) + { services.AddSingleton(); services.AddSingleton(); } diff --git a/Ghost.Editor/Helpers/SystemUtilities.cs b/Ghost.Editor/Helpers/SystemUtilities.cs index 88b838b..b56d413 100644 --- a/Ghost.Editor/Helpers/SystemUtilities.cs +++ b/Ghost.Editor/Helpers/SystemUtilities.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Windows.Storage; using Windows.Storage.Pickers; @@ -11,7 +12,7 @@ public static class SystemUtilities public static async Task OpenFolderPickerAsync(PickerLocationId startLocation = PickerLocationId.DocumentsLibrary, string settingsIdentifier = "") { var openPicker = new FolderPicker(); - var hWnd = WindowNative.GetWindowHandle(App.GetWindow()); + var hWnd = WindowNative.GetWindowHandle(App.Window); InitializeWithWindow.Initialize(openPicker, hWnd); openPicker.SuggestedStartLocation = startLocation; @@ -21,4 +22,21 @@ public static class SystemUtilities var folder = await openPicker.PickSingleFolderAsync(); return folder; } + + public static async Task OpenFilePickerAsync(PickerLocationId startLocation = PickerLocationId.DocumentsLibrary, string settingsIdentifier = "", params IEnumerable filter) + { + var openPicker = new FileOpenPicker(); + var hWnd = WindowNative.GetWindowHandle(App.Window); + InitializeWithWindow.Initialize(openPicker, hWnd); + + openPicker.SuggestedStartLocation = startLocation; + openPicker.SettingsIdentifier = settingsIdentifier; + foreach (var fileType in filter) + { + openPicker.FileTypeFilter.Add(fileType); + } + + var file = await openPicker.PickSingleFileAsync(); + return file; + } } \ No newline at end of file diff --git a/Ghost.Editor/Models/GameObject.cs b/Ghost.Editor/Models/GameObject.cs new file mode 100644 index 0000000..56d077a --- /dev/null +++ b/Ghost.Editor/Models/GameObject.cs @@ -0,0 +1,269 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Ghost.Entities; +using Ghost.Entities.Helpers; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Ghost.Editor.Models; + +public partial class GameObject : ObservableObject +{ + [ObservableProperty] + public partial bool IsActive + { + get; + set; + } + + [ObservableProperty] + public partial bool IsActiveHierarchy + { + get; + set; + } + + public Entity Entity + { + get; + } + + public Scene Scene + { + get; + internal set; + } + + public GameObject? Parent + { + get; + internal set; + } + + public string Name + { + get; + set; + } + + [ObservableProperty] + public partial ObservableCollection? Components + { + get; + private set; + } + + [ObservableProperty] + public partial IEnumerable? ScriptComponents + { + get; + private set; + } + + [ObservableProperty] + public partial ObservableCollection? Children + { + get; + private set; + } + + public GameObject(Scene scene, string name) + { + Entity = scene.World.EntityManager.CreateEntity(); + Scene = scene; + Name = name; + IsActive = true; + } + + partial void OnIsActiveChanged(bool value) + { + IsActiveHierarchy = value && (Parent?.IsActiveHierarchy ?? true); + HandleActiveStateChanged(); + + if (Children != null) + { + foreach (var child in Children) + { + child.IsActiveHierarchy = value && IsActiveHierarchy; + } + } + } + + partial void OnIsActiveHierarchyChanged(bool value) + { + HandleActiveStateChanged(); + } + + private void HandleActiveStateChanged() + { + if (IsActive && IsActiveHierarchy) + { + OnEnable(); + } + else + { + OnDisable(); + } + } + + internal void OnEnable() + { + if (ScriptComponents != null) + { + foreach (var script in ScriptComponents) + { + if (!script.Enable) + { + continue; + } + script.OnEnable(); + } + } + } + + internal void OnDisable() + { + if (ScriptComponents != null) + { + foreach (var script in ScriptComponents) + { + if (!script.Enable) + { + continue; + } + script.OnDisable(); + } + } + } + + public void AddChild(GameObject child) + { + if (child.Scene != Scene) + { + throw new InvalidOperationException("Child GameObject must belong to the same Scene."); + } + + Children ??= new(); + Children.Add(child); + child.Parent = this; + } + + public bool RemoveChild(GameObject child) + { + if (Children is null) + { + return false; + } + + if (!Children.Remove(child)) + { + return false; + } + + child.Parent = null; + return true; + } + + public void Destroy() + { + if (ScriptComponents != null) + { + foreach (var component in ScriptComponents) + { + if (!component.Enable) + { + continue; + } + component.OnDestroy(); + } + } + + if (Children != null) + { + foreach (var child in Children) + { + child.Destroy(); + } + + Children.Clear(); + } + + Parent?.Children?.Remove(this); + Entity.Destroy(); + } +} + +public partial class GameObject +{ + // TODO: Implement a more efficient synchronization mechanism for components + internal void SyncComponents() + { + foreach (var (typeHandle, mask) in Scene.World.ComponentStorage.ComponentEntityMasks) + { + if (!mask.IsSet(Entity.ID)) + { + continue; + } + + var pool = Scene.World.ComponentStorage.ComponentPools[typeHandle]; + } + } + + internal void SyncScripts() + { + var scriptsPool = Scene.World.ComponentStorage.ScriptComponentPool.ScriptComponents; + if (scriptsPool == null) + { + return; + } + + scriptsPool.TryGetValue(Entity, out var scripts); + ScriptComponents = scripts; + } + + public void AddComponent(T component) + where T : struct, IComponentData + { + Entity.AddComponent(component); + SyncComponents(); + } + + public bool RemoveComponent() + where T : struct, IComponentData + { + var result = Entity.RemoveComponent(); + SyncComponents(); + + return result; + } + + public void AddScript() + where T : ScriptComponent, new() + { + Entity.AddScript(); + SyncScripts(); + } + + public void AddScript(Type type) + { + Entity.AddScript(type); + SyncScripts(); + } + + public bool RemoveScript() + where T : ScriptComponent + { + var result = Scene.World.EntityManager.RemoveScript(Entity); + SyncScripts(); + + return result; + } + + public bool RemoveScriptAt(int index) + { + var result = Scene.World.EntityManager.RemoveScriptAt(Entity, index); + SyncScripts(); + + return result; + } +} \ No newline at end of file diff --git a/Ghost.Engine/Models/Scene.cs b/Ghost.Editor/Models/Scene.cs similarity index 65% rename from Ghost.Engine/Models/Scene.cs rename to Ghost.Editor/Models/Scene.cs index 0a372bd..3e38716 100644 --- a/Ghost.Engine/Models/Scene.cs +++ b/Ghost.Editor/Models/Scene.cs @@ -1,10 +1,15 @@ -namespace Ghost.Engine.Models; +using Ghost.Entities; +using System.Collections.Generic; + +namespace Ghost.Editor.Models; public class Scene { private readonly HashSet _rootObjects = new(); + private readonly World _world = World.Create(); public IEnumerable RootObjects => _rootObjects; + public World World => _world; internal Scene() { @@ -14,7 +19,7 @@ public class Scene { foreach (var gameObject in _rootObjects) { - gameObject.Start(); + gameObject.OnEnable(); } } @@ -22,6 +27,7 @@ public class Scene { foreach (var gameObject in _rootObjects) { + gameObject.OnDisable(); gameObject.Destroy(); } diff --git a/Ghost.Editor/Services/AppStateService.cs b/Ghost.Editor/Services/AppStateService.cs new file mode 100644 index 0000000..6ac3760 --- /dev/null +++ b/Ghost.Editor/Services/AppStateService.cs @@ -0,0 +1,35 @@ +using Ghost.Editor.AppStates; +using Ghost.Editor.Contracts; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ghost.Editor.Services; + +internal class AppStateService(params IEnumerable> states) +{ + private readonly Dictionary> _states = states.ToDictionary(s => s.StateKy, s => s); + private IAppState? _current; + + public async Task TransitionToAsync(StateKey stateKey, object? parameter = null) + { + var previous = _current; + var next = _states[stateKey]; + + if (previous != null) + { + await previous.OnExitingAsync(); + } + + await next.OnEnteringAsync(parameter); + + if (previous != null) + { + await previous.OnExitedAsync(); + } + + await next.OnEnteredAsync(parameter); + + _current = next; + } +} \ No newline at end of file diff --git a/Ghost.Editor/Services/StackedNotificationService.cs b/Ghost.Editor/Services/StackedNotificationService.cs new file mode 100644 index 0000000..e3e1532 --- /dev/null +++ b/Ghost.Editor/Services/StackedNotificationService.cs @@ -0,0 +1,50 @@ +using CommunityToolkit.WinUI.Behaviors; +using Microsoft.UI.Xaml.Controls; +using System; + +namespace Ghost.Editor.Services; + +public class StackedNotificationService +{ + private InfoBar? _infoBar; + private StackedNotificationsBehavior? _notificationQueue; + + internal void SetReference(InfoBar infoBar, StackedNotificationsBehavior notificationQueue) + { + _infoBar = infoBar; + _notificationQueue = notificationQueue; + } + + internal void ClearReference() + { + if (_infoBar != null) + { + _infoBar.IsOpen = false; + } + _infoBar = null; + _notificationQueue = null; + } + + public void ShowNotification(string? message, InfoBarSeverity severity, int duration = 5, string? title = null) + { + if (string.IsNullOrWhiteSpace(message)) + { + return; + } + + var notification = new Notification + { + Message = message, + Severity = severity, + Duration = TimeSpan.FromSeconds(duration), + Title = title + }; + + ShowNotification(notification); + } + + public void ShowNotification(Notification notification) + { + _notificationQueue?.Show(notification); + } +} \ No newline at end of file diff --git a/Ghost.Editor/Themes/Dark.xaml b/Ghost.Editor/Themes/Dark.xaml new file mode 100644 index 0000000..8f22c98 --- /dev/null +++ b/Ghost.Editor/Themes/Dark.xaml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Ghost.Editor/Themes/Light.xaml b/Ghost.Editor/Themes/Light.xaml new file mode 100644 index 0000000..8527c05 --- /dev/null +++ b/Ghost.Editor/Themes/Light.xaml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml b/Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml new file mode 100644 index 0000000..06dde5f --- /dev/null +++ b/Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml.cs b/Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml.cs new file mode 100644 index 0000000..c690558 --- /dev/null +++ b/Ghost.Editor/View/Pages/EngineEditor/ConsolePage.xaml.cs @@ -0,0 +1,11 @@ +using Microsoft.UI.Xaml.Controls; + +namespace Ghost.Editor.View.Pages.EngineEditor; + +public sealed partial class ConsolePage : Page +{ + public ConsolePage() + { + InitializeComponent(); + } +} diff --git a/Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml b/Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml new file mode 100644 index 0000000..daa13cf --- /dev/null +++ b/Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml.cs b/Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml.cs new file mode 100644 index 0000000..cd80545 --- /dev/null +++ b/Ghost.Editor/View/Pages/EngineEditor/ProjectPage.xaml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Ghost.Editor.View.Pages.EngineEditor; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public sealed partial class ProjectPage : Page +{ + public ProjectPage() + { + InitializeComponent(); + } +} diff --git a/Ghost.Editor/View/Pages/Landing/CreateProjectPage.xaml b/Ghost.Editor/View/Pages/Landing/CreateProjectPage.xaml index cac6740..c448a62 100644 --- a/Ghost.Editor/View/Pages/Landing/CreateProjectPage.xaml +++ b/Ghost.Editor/View/Pages/Landing/CreateProjectPage.xaml @@ -8,6 +8,7 @@ xmlns:editor="using:Ghost.Editor.Controls" xmlns:local="using:Ghost.Editor.View.Pages.Landing" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + NavigationCacheMode="Enabled" mc:Ignorable="d"> @@ -46,7 +47,7 @@ Width="24" Height="24"> - + - + + MaxHeight="100" + VerticalAlignment="Bottom" + Background="{ThemeResource ControlOnImageFillColorDefaultBrush}"> + Foreground="{ThemeResource TextFillColorTertiaryBrush}" + Text="{x:Bind ViewModel.SelectedTemplate.Value.Info.Description, Mode=OneWay}" /> @@ -95,7 +96,7 @@ + Text="{x:Bind ViewModel.SelectedTemplate.Value.Info.Name, Mode=OneWay}" /> - + + + + + + - + + + + + + + - + + Style="{StaticResource CaptionTextBlockStyle}" + Text="NAME" /> + HorizontalAlignment="Right" + Style="{StaticResource CaptionTextBlockStyle}" + Text="LAST OPEN" /> + HorizontalAlignment="Right" + Style="{StaticResource CaptionTextBlockStyle}" + Text="ENGINE VERSION" /> - + - - - - - - - - - + AllowDrop="True" + DragEnter="ProjectContainer_DragEnter" + DragLeave="ProjectContainer_DragLeave" + DragOver="ProjectContainer_DragOver" + Drop="ProjectContainer_Drop"> + + + + + + + + + + - - - - - + + + + + + + + + + Grid.Column="1" + Margin="16,4" + HorizontalAlignment="Right" + VerticalAlignment="Center" + Text="{x:Bind Metadata.LastOpened}" /> + Grid.Column="2" + Margin="16,4" + HorizontalAlignment="Right" + VerticalAlignment="Center" + Text="{x:Bind Metadata.EngineVersion}" /> + + + + - - - - - - - + + + + + - + + + + \ No newline at end of file diff --git a/Ghost.Editor/View/Pages/Landing/OpenProjectPage.xaml.cs b/Ghost.Editor/View/Pages/Landing/OpenProjectPage.xaml.cs index 69664fc..89f0b62 100644 --- a/Ghost.Editor/View/Pages/Landing/OpenProjectPage.xaml.cs +++ b/Ghost.Editor/View/Pages/Landing/OpenProjectPage.xaml.cs @@ -1,56 +1,133 @@ using Ghost.Data.Models; using Ghost.Data.Services; -using Ghost.Editor.View.Windows; +using Ghost.Editor.AppStates; +using Ghost.Editor.Services; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; +using System; using System.Collections.ObjectModel; - -// To learn more about WinUI, the WinUI project structure, -// and more about our project templates, see: http://aka.ms/winui-project-info. +using System.Linq; +using Windows.ApplicationModel.DataTransfer; +using Windows.Storage; namespace Ghost.Editor.View.Pages.Landing; internal sealed partial class OpenProjectPage : Page { private readonly ProjectService _projectService; + private readonly StackedNotificationService _notificationService; + private readonly AppStateService _stateService; - public readonly ObservableCollection projects = new(); + public readonly ObservableCollection projects = new(); public OpenProjectPage() { + _notificationService = App.GetService(); _projectService = App.GetService(); - + _stateService = App.GetService(); InitializeComponent(); } + private void UpdateEmptyPlaceHolderVisibility() + { + EmptyPlaceHolder.Visibility = projects.Count == 0 ? Visibility.Visible : Visibility.Collapsed; + } + protected override async void OnNavigatedTo(NavigationEventArgs e) { - await foreach (var project in _projectService.LoadAllProjectAsync()) + base.OnNavigatedTo(e); + + projects.Clear(); + await foreach (var projectInfo in _projectService.LoadAllProjectAsync()) { - projects.Add(project); + var metadata = await ProjectService.LoadMetadataAsync(projectInfo.MetadataPath); + if (metadata == null) + { + continue; + } + + projects.Add(new(projectInfo.MetadataPath, metadata)); } - if (projects.Count == 0) + UpdateEmptyPlaceHolderVisibility(); + } + + private void ProjectContainer_DragEnter(object sender, DragEventArgs e) + { + DragVisual.Visibility = Visibility.Visible; + EmptyPlaceHolder.Visibility = Visibility.Collapsed; + } + + private void ProjectContainer_DragLeave(object sender, DragEventArgs e) + { + DragVisual.Visibility = Visibility.Collapsed; + UpdateEmptyPlaceHolderVisibility(); + } + + private void ProjectContainer_DragOver(object sender, DragEventArgs e) + { + if (e.DataView.Contains(StandardDataFormats.StorageItems)) { - PlaceHolderText.Visibility = Visibility.Visible; - ProjectListView.Visibility = Visibility.Collapsed; + e.AcceptedOperation = DataPackageOperation.Link; } + else + { + e.AcceptedOperation = DataPackageOperation.None; + } + } + + private async void ProjectContainer_Drop(object sender, DragEventArgs e) + { + var errorMessage = string.Empty; + if (e.DataView.Contains(StandardDataFormats.StorageItems)) + { + var items = await e.DataView.GetStorageItemsAsync(); + var rootFolder = items.OfType().FirstOrDefault(); + if (rootFolder != null) + { + var result = await _projectService.AddProjectFromDirectoryAsync(rootFolder.Path); + if (result.success) + { + projects.Add(result.data); + DragVisual.Visibility = Visibility.Collapsed; + goto CloseDropPanel; + } + else + { + errorMessage = result.message; + } + } + } + else + { + errorMessage = "Unsupported data format. Please drop a folder containing a project."; + } + + _notificationService.ShowNotification(errorMessage, InfoBarSeverity.Error); + + CloseDropPanel: + DragVisual.Visibility = Visibility.Collapsed; + UpdateEmptyPlaceHolderVisibility(); } private async void ListView_ItemClick(object sender, ItemClickEventArgs e) { - if (e.ClickedItem is not ProjectInfo project) + if (e.ClickedItem is not ProjectMetadataInfo project) { return; } - if (EngineEditorWindow.TryLoadProject(project)) + try { - App.GetService().Close(); + project.Metadata.LastOpened = DateTime.Now; + await ProjectService.CreateMetadataFileAsync(project.Path, project.Metadata); - project.LastOpened = System.DateTime.Now; - await _projectService.UpdateProjectAsync(project); + await _stateService.TransitionToAsync(StateKey.EngineEditor, project.Metadata); + } + catch (Exception exp) + { + _notificationService.ShowNotification($"Failed to load project: {exp.Message}", InfoBarSeverity.Error); } } } \ No newline at end of file diff --git a/Ghost.Editor/View/Windows/EngineEditorWindow.xaml b/Ghost.Editor/View/Windows/EngineEditorWindow.xaml index 86e6ab6..0928334 100644 --- a/Ghost.Editor/View/Windows/EngineEditorWindow.xaml +++ b/Ghost.Editor/View/Windows/EngineEditorWindow.xaml @@ -5,16 +5,18 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:ee="using:Ghost.Editor.View.Pages.EngineEditor" xmlns:local="using:Ghost.Editor.View.Windows" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:winex="using:WinUIEx" + Activated="WindowEx_Activated" mc:Ignorable="d"> - + @@ -41,7 +43,7 @@ Margin="8,0,0,0" VerticalAlignment="Center" Style="{StaticResource CaptionTextBlockStyle}" - Text="{x:Bind ViewModel.CurrentProject.Name}" /> + Text="{x:Bind ViewModel.CurrentProject.Name, Mode=OneWay}" /> @@ -85,32 +87,41 @@ Grid.Column="0" Width="350" Background="Aquamarine" /> - + + + - - - - - - - - - + + + + + + + + + + + + + + + + + Background="{ThemeResource SolidBackgroundFillColorBaseAltBrush}"> diff --git a/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs b/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs index 90f60f3..e03e83f 100644 --- a/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs +++ b/Ghost.Editor/View/Windows/EngineEditorWindow.xaml.cs @@ -1,5 +1,4 @@ -using Ghost.Data.Models; -using Ghost.Data.Resources; +using Ghost.Data.Resources; using Ghost.Editor.ViewModel.Windows; using Ghost.Engine.Resources; using WinUIEx; @@ -22,7 +21,7 @@ internal sealed partial class EngineEditorWindow : WindowEx { ViewModel = App.GetService(); - AppWindow.SetIcon(AssetsPath.AppIconPath); + AppWindow.SetIcon(AssetsPath.s_appIconPath); Title = EngineData.ENGINE_NAME; ExtendsContentIntoTitleBar = true; @@ -31,23 +30,8 @@ internal sealed partial class EngineEditorWindow : WindowEx this.CenterOnScreen(); } - public static bool TryLoadProject(ProjectInfo project) + private void WindowEx_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args) { - try - { - var window = App.GetService(); - window.ViewModel.CurrentProject = project; - - window.Activate(); - window.Bindings.Update(); - - App.SetWindow(window); - - return true; - } - catch (System.Exception) - { - return false; - } + Bindings.Update(); } } \ No newline at end of file diff --git a/Ghost.Editor/View/Windows/LandingWindow.xaml b/Ghost.Editor/View/Windows/LandingWindow.xaml index 46ee4f6..d05367c 100644 --- a/Ghost.Editor/View/Windows/LandingWindow.xaml +++ b/Ghost.Editor/View/Windows/LandingWindow.xaml @@ -3,10 +3,14 @@ x:Class="Ghost.Editor.View.Windows.LandingWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:behaviors="using:CommunityToolkit.WinUI.Behaviors" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:local="using:Ghost.Editor.View.Windows" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:winex="using:WinUIEx" + Activated="WindowEx_Activated" + Closed="WindowEx_Closed" IsResizable="False" mc:Ignorable="d"> @@ -55,8 +59,19 @@ Grid.Row="1" Padding="8" CacheMode="BitmapCache" - CacheSize="10" - IsNavigationStackEnabled="False" /> + CacheSize="10" /> + + + + + + + + + diff --git a/Ghost.Editor/View/Windows/LandingWindow.xaml.cs b/Ghost.Editor/View/Windows/LandingWindow.xaml.cs index 66e4446..87262a0 100644 --- a/Ghost.Editor/View/Windows/LandingWindow.xaml.cs +++ b/Ghost.Editor/View/Windows/LandingWindow.xaml.cs @@ -1,6 +1,8 @@ using Ghost.Data.Resources; +using Ghost.Editor.Services; using Ghost.Editor.View.Pages.Landing; using Ghost.Engine.Resources; +using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Animation; using WinUIEx; @@ -9,11 +11,13 @@ namespace Ghost.Editor.View.Windows; internal sealed partial class LandingWindow : WindowEx { + private IServiceScope? _landingScope; + private int _previousSelectedIndex; public LandingWindow() { - AppWindow.SetIcon(AssetsPath.AppIconPath); + AppWindow.SetIcon(AssetsPath.s_appIconPath); Title = EngineData.ENGINE_NAME; InitializeComponent(); @@ -24,6 +28,19 @@ internal sealed partial class LandingWindow : WindowEx ExtendsContentIntoTitleBar = true; } + private void WindowEx_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args) + { + _landingScope?.Dispose(); + _landingScope = App.CreateScope(); + App.GetService().SetReference(InfoBar, NotificationQueue); + } + + private void WindowEx_Closed(object sender, Microsoft.UI.Xaml.WindowEventArgs args) + { + _landingScope?.Dispose(); + App.GetService().ClearReference(); + } + private void SelectorBar_SelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs e) { var selectedItem = sender.SelectedItem; @@ -37,7 +54,7 @@ internal sealed partial class LandingWindow : WindowEx var slideNavigationTransitionEffect = currentSelectedIndex - _previousSelectedIndex > 0 ? SlideNavigationTransitionEffect.FromRight : SlideNavigationTransitionEffect.FromLeft; - ContentFrame.Navigate(pageType, null, new SlideNavigationTransitionInfo() { Effect = slideNavigationTransitionEffect }); + ContentFrame.Navigate(pageType, _landingScope, new SlideNavigationTransitionInfo() { Effect = slideNavigationTransitionEffect }); _previousSelectedIndex = currentSelectedIndex; } diff --git a/Ghost.Editor/ViewModel/Pages/EngineEditor/ProjectViewModel.cs b/Ghost.Editor/ViewModel/Pages/EngineEditor/ProjectViewModel.cs new file mode 100644 index 0000000..33d74c3 --- /dev/null +++ b/Ghost.Editor/ViewModel/Pages/EngineEditor/ProjectViewModel.cs @@ -0,0 +1,5 @@ +namespace Ghost.Editor.ViewModel.Pages.EngineEditor; + +internal class ProjectViewModel +{ +} diff --git a/Ghost.Editor/ViewModel/Pages/Landing/CreateProjectViewModel.cs b/Ghost.Editor/ViewModel/Pages/Landing/CreateProjectViewModel.cs index b690bf1..9a0cce6 100644 --- a/Ghost.Editor/ViewModel/Pages/Landing/CreateProjectViewModel.cs +++ b/Ghost.Editor/ViewModel/Pages/Landing/CreateProjectViewModel.cs @@ -2,18 +2,20 @@ using CommunityToolkit.Mvvm.Input; using Ghost.Data.Models; using Ghost.Data.Services; +using Ghost.Editor.AppStates; using Ghost.Editor.Contracts; using Ghost.Editor.Helpers; -using Ghost.Editor.View.Windows; +using Ghost.Editor.Services; +using Ghost.Engine.Resources; +using Microsoft.UI.Xaml.Controls; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading.Tasks; -using Windows.ApplicationModel; namespace Ghost.Editor.ViewModel.Pages.Landing; -internal partial class CreateProjectViewModel(ProjectService projectService) : ObservableRecipient, INavigationAware +internal partial class CreateProjectViewModel(StackedNotificationService notificationService, ProjectService projectService, AppStateService stateService) : ObservableRecipient, INavigationAware { public ObservableCollection templates = new(); @@ -25,14 +27,14 @@ internal partial class CreateProjectViewModel(ProjectService projectService) : O } [ObservableProperty] - public partial string ProjectName + public partial string? ProjectName { get; set; } [ObservableProperty] - public partial string ProjectLocation + public partial string? ProjectLocation { get; set; @@ -40,7 +42,8 @@ internal partial class CreateProjectViewModel(ProjectService projectService) : O public async void OnNavigatedTo(object? parameter) { - await foreach (var (path, info) in projectService.GetProjectTemplatesAsync()) + templates.Clear(); + await foreach (var (path, info) in ProjectService.GetProjectTemplatesAsync()) { templates.Add(new(path, info)); } @@ -55,25 +58,39 @@ internal partial class CreateProjectViewModel(ProjectService projectService) : O [RelayCommand] private async Task SelectionProjectLocation() { - ProjectLocation = (await SystemUtilities.OpenFolderPickerAsync())?.Path ?? string.Empty; + var folder = await SystemUtilities.OpenFolderPickerAsync(); + if (folder != null) + { + ProjectLocation = folder.Path; + } } [RelayCommand] private async Task CreateProject() { - if (string.IsNullOrWhiteSpace(ProjectName) || !Directory.Exists(ProjectLocation) || SelectedTemplate == null) + if (string.IsNullOrWhiteSpace(ProjectName) + || !Directory.Exists(ProjectLocation) + || !SelectedTemplate.HasValue) { + notificationService.ShowNotification("Incorrect project info", InfoBarSeverity.Error); return; } - var projectPath = await projectService.CreateProjectAsync(ProjectName, ProjectLocation, SelectedTemplate.directory); - - var packageVersion = Package.Current.Id.Version; - var newProject = await projectService.AddProjectAsync(ProjectName, projectPath, new System.Version(packageVersion.Major, packageVersion.Minor, packageVersion.Build)); - - if (EngineEditorWindow.TryLoadProject(newProject)) + var result = await projectService.CreateProjectAsync(ProjectName, ProjectLocation, EngineData.s_engineVersion, SelectedTemplate.Value.directory); + if (!result.success || result.data == null) { - App.GetService().Close(); + notificationService.ShowNotification(result.message, InfoBarSeverity.Error); + return; + } + + var metadata = await ProjectService.LoadMetadataAsync(result.data.MetadataPath); // Metadata should not be null here if create project succeeded + try + { + await stateService.TransitionToAsync(StateKey.EngineEditor, metadata); + } + catch (System.Exception e) + { + notificationService.ShowNotification($"Failed to load project: {e.Message}", InfoBarSeverity.Error); } } } \ No newline at end of file diff --git a/Ghost.Editor/ViewModel/Windows/EngineEditorViewModel.cs b/Ghost.Editor/ViewModel/Windows/EngineEditorViewModel.cs index 6d278c7..91b50eb 100644 --- a/Ghost.Editor/ViewModel/Windows/EngineEditorViewModel.cs +++ b/Ghost.Editor/ViewModel/Windows/EngineEditorViewModel.cs @@ -6,10 +6,10 @@ namespace Ghost.Editor.ViewModel.Windows; internal partial class EngineEditorViewModel : ObservableRecipient { - public string engineVersionDescriptor = $"{EngineData.ENGINE_NAME} - {EngineData.ENGINE_VERSION}"; + public string engineVersionDescriptor = $"{EngineData.ENGINE_NAME} - {EngineData.s_engineVersion}"; [ObservableProperty] - public partial ProjectInfo CurrentProject + public partial ProjectMetadata CurrentProject { get; set; diff --git a/Ghost.Engine/GameObject.cs b/Ghost.Engine/GameObject.cs deleted file mode 100644 index 214a8c4..0000000 --- a/Ghost.Engine/GameObject.cs +++ /dev/null @@ -1,190 +0,0 @@ -using Ghost.Engine.Models; -using Ghost.Entities; -using System.ComponentModel; - -namespace Ghost.Engine; - -public unsafe class GameObject : INotifyPropertyChanged -{ - private readonly Dictionary _components = new(); - private readonly List _children = new(); - - public event PropertyChangedEventHandler? PropertyChanged; - - public Entity Entity - { - get; - } - - public Scene Scene - { - get; - internal set; - } - - public GameObject? Parent - { - get; - internal set; - } - - public string Name - { - get; - set; - } - - public bool IsActive - { - get; - set; - } - - public IEnumerable Components => _components.Values; - public IEnumerable Children => _children; - - public GameObject(Scene scene, string name) - { - // TODO: Initialize Entity properly - //Entity = - Scene = scene; - Name = name; - IsActive = true; - } - - public void AddComponent(T component) - where T : ScriptComponent - { - _components.Add(typeof(T), component); - component.Owner = Entity; - - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Components))); - } - - public void RemoveComponent() - where T : ScriptComponent - { - var key = typeof(T); - if (_components.Remove(key, out var component)) - { - component.OnDestroy(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Components))); - } - } - - public T? GetComponent() - where T : ScriptComponent - { - if (_components.TryGetValue(typeof(T), out var component)) - { - return (T)component; - } - - return null; - } - - public void AddChild(GameObject child) - { - if (child.Scene != Scene) - { - throw new InvalidOperationException("Child GameObject must belong to the same Scene."); - } - - _children.Add(child); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Children))); - } - - public void RemoveChild(GameObject child) - { - if (_children.Remove(child)) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Children))); - } - } - - internal void OnEnable() - { - foreach (var component in Components) - { - if (!component.Enable) - { - continue; - } - component.OnEnable(); - } - - foreach (var child in _children) - { - child.OnEnable(); - } - } - - internal void Start() - { - foreach (var component in Components) - { - if (!component.Enable) - { - continue; - } - component.Start(); - } - } - - internal void Update() - { - foreach (var component in Components) - { - if (!component.Enable) - { - continue; - } - component.Update(); - } - } - - internal void LateUpdate() - { - foreach (var component in Components) - { - if (!component.Enable) - { - continue; - } - component.LateUpdate(); - } - } - - internal void FixedUpdate() - { - foreach (var component in Components) - { - if (!component.Enable) - { - continue; - } - component.FixedUpdate(); - } - } - - public void Destroy() - { - foreach (var component in Components) - { - if (!component.Enable) - { - continue; - } - component.OnDestroy(); - } - - foreach (var child in _children) - { - child.Destroy(); - } - - _children.Clear(); - _components.Clear(); - Parent?._children.Remove(this); - } -} \ No newline at end of file diff --git a/Ghost.Engine/Resources/EngineData.cs b/Ghost.Engine/Resources/EngineData.cs index 2f1bece..7f13c42 100644 --- a/Ghost.Engine/Resources/EngineData.cs +++ b/Ghost.Engine/Resources/EngineData.cs @@ -4,5 +4,5 @@ internal class EngineData { public const string ENGINE_NAME = "Ghost Engine"; - public readonly static Version ENGINE_VERSION = new(0, 1, 0); + public readonly static Version s_engineVersion = new(0, 1, 0); } \ No newline at end of file diff --git a/Ghost.Engine/Services/PlayerLoopService.cs b/Ghost.Engine/Services/PlayerLoopService.cs index adb76b1..3b7052b 100644 --- a/Ghost.Engine/Services/PlayerLoopService.cs +++ b/Ghost.Engine/Services/PlayerLoopService.cs @@ -10,43 +10,43 @@ internal static class PlayerLoopService public static void Start() { - if (_isRunning) - { - return; - } + //if (_isRunning) + //{ + // return; + //} - foreach (var gameObject in SceneManager.QueryRootGameObjects()) - { - gameObject.Start(); - } + //foreach (var gameObject in SceneManager.QueryRootGameObjects()) + //{ + // gameObject.Start(); + //} - _timer ??= new Timer(FixedUpdate, null, 0, (int)(fixedDeltaTime * 1000)); + //_timer ??= new Timer(FixedUpdate, null, 0, (int)(fixedDeltaTime * 1000)); - while (_isRunning) - { - Update(); - } + //while (_isRunning) + //{ + // Update(); + //} } private static void Update() { - foreach (var gameObject in SceneManager.QueryRootGameObjects()) - { - gameObject.Update(); - } + //foreach (var gameObject in SceneManager.QueryRootGameObjects()) + //{ + // gameObject.Update(); + //} - foreach (var gameObject in SceneManager.QueryRootGameObjects()) - { - gameObject.LateUpdate(); - } + //foreach (var gameObject in SceneManager.QueryRootGameObjects()) + //{ + // gameObject.LateUpdate(); + //} } private static void FixedUpdate(object? state) { - foreach (var gameObject in SceneManager.QueryRootGameObjects()) - { - gameObject.FixedUpdate(); - } + //foreach (var gameObject in SceneManager.QueryRootGameObjects()) + //{ + // gameObject.FixedUpdate(); + //} } public static void Stop() diff --git a/Ghost.Engine/Services/SceneManager.cs b/Ghost.Engine/Services/SceneManager.cs index 8087048..0f84469 100644 --- a/Ghost.Engine/Services/SceneManager.cs +++ b/Ghost.Engine/Services/SceneManager.cs @@ -1,6 +1,4 @@ -using Ghost.Engine.Models; - -namespace Ghost.Engine.Services; +namespace Ghost.Engine.Services; public enum SceneLoadMode { @@ -10,41 +8,41 @@ public enum SceneLoadMode public static class SceneManager { - private readonly static HashSet _activeScenes = new(); + //private readonly static HashSet _activeScenes = new(); - internal static IEnumerable QueryRootGameObjects() - { - foreach (var scene in _activeScenes) - { - foreach (var gameObject in scene.RootObjects) - { - if (!gameObject.IsActive) - { - continue; - } + //internal static IEnumerable QueryRootGameObjects() + //{ + // foreach (var scene in _activeScenes) + // { + // foreach (var gameObject in scene.RootObjects) + // { + // if (!gameObject.IsActive) + // { + // continue; + // } - yield return gameObject; - } - } - } + // yield return gameObject; + // } + // } + //} - public static void LoadScene(Scene scene, SceneLoadMode loadMode) - { - if (loadMode == SceneLoadMode.Single) - { - foreach (var activeScene in _activeScenes) - { - activeScene.Unload(); - } - _activeScenes.Clear(); - } + //public static void LoadScene(Scene scene, SceneLoadMode loadMode) + //{ + // if (loadMode == SceneLoadMode.Single) + // { + // foreach (var activeScene in _activeScenes) + // { + // activeScene.Unload(); + // } + // _activeScenes.Clear(); + // } - _activeScenes.Add(scene); - scene.Load(); - } + // _activeScenes.Add(scene); + // scene.Load(); + //} - public static Task LoadSceneAsync(Scene scene, SceneLoadMode loadMode) - { - return Task.Run(() => LoadScene(scene, loadMode)); - } + //public static Task LoadSceneAsync(Scene scene, SceneLoadMode loadMode) + //{ + // return Task.Run(() => LoadScene(scene, loadMode)); + //} } \ No newline at end of file diff --git a/Ghost.Entities/AssemblyInfo.cs b/Ghost.Entities/AssemblyInfo.cs index b9f7d98..f4854ec 100644 --- a/Ghost.Entities/AssemblyInfo.cs +++ b/Ghost.Entities/AssemblyInfo.cs @@ -5,4 +5,5 @@ global using WorldID = System.UInt16; using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Ghost.Engine")] +[assembly: InternalsVisibleTo("Ghost.Editor")] [assembly: InternalsVisibleTo("Ghost.Test")] \ No newline at end of file diff --git a/Ghost.Entities/Component.cs b/Ghost.Entities/Component.cs index 47eff32..d0a2c74 100644 --- a/Ghost.Entities/Component.cs +++ b/Ghost.Entities/Component.cs @@ -23,11 +23,12 @@ internal interface IComponentPool : IDisposable get; } - public void Remove(Entity entity); + public bool Remove(Entity entity); public bool Has(Entity entity); } internal interface IComponentPool : IComponentPool + where T : IComponentData { public void Add(Entity entity, T Component); } @@ -115,8 +116,10 @@ internal class ComponentPool : IComponentPool _nextId++; } - public void Remove(Entity entity) + public bool Remove(Entity entity) { + // We do not remove anything here, the generation of the entity will be used to determine if the component is valid. + return true; } public ref T GetRef(Entity entity) @@ -213,13 +216,62 @@ internal class ScriptComponentPool : IComponentPool component.Owner = entity; } - public void Remove(Entity entity) + public bool Remove(Entity entity) + where T : ScriptComponent { if (!Has(entity) || !_scriptComponents!.TryGetValue(entity, out var scriptList) || scriptList == null) { - return; + return false; + } + + var scriptToRemove = scriptList.FirstOrDefault(script => script is T); + if (scriptToRemove == null) + { + return false; + } + + scriptToRemove.OnDestroy(); + scriptList.Remove(scriptToRemove); + if (scriptList.Count == 0) + { + _scriptComponents.Remove(entity); + } + + return true; + } + + public bool RemoveAt(Entity entity, int index) + { + if (!Has(entity) + || !_scriptComponents!.TryGetValue(entity, out var scriptList) + || scriptList == null) + { + return false; + } + + if (index < 0 || index > scriptList.Count) + { + return false; + } + + scriptList.RemoveAt(index); + if (scriptList.Count == 0) + { + _scriptComponents.Remove(entity); + } + + return true; + } + + public bool Remove(Entity entity) + { + if (!Has(entity) + || !_scriptComponents!.TryGetValue(entity, out var scriptList) + || scriptList == null) + { + return false; } foreach (var script in scriptList) @@ -228,6 +280,7 @@ internal class ScriptComponentPool : IComponentPool } _scriptComponents.Remove(entity); + return true; } public bool Has(Entity entity) @@ -287,7 +340,15 @@ internal class ComponentStorage : IDisposable private readonly Dictionary _componentEntityMasks = new(); private readonly ScriptComponentPool _scriptComponentPool = new(); + private readonly World _world; + + internal ComponentStorage(World world) + { + _world = world; + } + internal Dictionary ComponentPools => _componentPools; + internal Dictionary ComponentEntityMasks => _componentEntityMasks; internal ScriptComponentPool ScriptComponentPool => _scriptComponentPool; [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Ghost.Entities/Entity.cs b/Ghost.Entities/Entity.cs index 08a8ac9..539ada3 100644 --- a/Ghost.Entities/Entity.cs +++ b/Ghost.Entities/Entity.cs @@ -112,6 +112,11 @@ public class EntityManager : IDisposable public int EntityCount => _entities.Count; public ReadOnlySpan Entities => CollectionsMarshal.AsSpan(_entities); + public event Action? OnComponentAdded; + public event Action? OnComponentRemoved; + public event Action? OnEntityCreated; + public event Action? OnEntityRemoved; + internal EntityManager(World world, int initialCapacity) { _entities = new(initialCapacity); @@ -125,17 +130,20 @@ public class EntityManager : IDisposable /// The created . public Entity CreateEntity() { + Entity entity; if (_freeEntitySlots.TryDequeue(out var id)) { - return _entities[id]; + entity = _entities[id]; } else { id = _entities.Count; - var entity = new Entity(id, 0, _world.ID); + entity = new Entity(id, 0, _world.ID); _entities.Add(entity); - return entity; } + + OnEntityCreated?.Invoke(entity); + return entity; } /// @@ -149,13 +157,14 @@ public class EntityManager : IDisposable return; } - _world._componentStorage.Remove(entity); + _world.ComponentStorage.Remove(entity); var slot = _entities[entity.ID]; slot.IncrementGeneration(); _entities[entity.ID] = slot; _freeEntitySlots.Enqueue(entity.ID); + OnEntityRemoved?.Invoke(entity.ID); entity = Entity.Invalid; } @@ -187,8 +196,9 @@ public class EntityManager : IDisposable public void AddComponent(Entity entity, T component) where T : struct, IComponentData { - _world._componentStorage.GetOrCreateComponentPool().Add(entity, component); - _world._componentStorage.GetOrCreateMask(TypeHandle.Value).SetBit(entity.ID); + _world.ComponentStorage.GetOrCreateComponentPool().Add(entity, component); + _world.ComponentStorage.GetOrCreateMask(TypeHandle.Value).SetBit(entity.ID); + OnComponentAdded?.Invoke(entity, typeof(T)); } /// @@ -197,14 +207,23 @@ public class EntityManager : IDisposable /// The type of the component to remove. /// The entity for which the component is to be remove. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveComponent(Entity entity) + public bool RemoveComponent(Entity entity) where T : struct, IComponentData { - if (_world._componentStorage.TryGetPool(out var pool) && pool.Has(entity)) + if (!_world.ComponentStorage.TryGetPool(out var pool) || !pool.Has(entity)) { - pool.Remove(entity); - _world._componentStorage.GetOrCreateMask(TypeHandle.Value).ClearBit(entity.ID); + return false; } + + if (!pool.Remove(entity)) + { + return false; + } + + _world.ComponentStorage.GetOrCreateMask(TypeHandle.Value).ClearBit(entity.ID); + OnComponentRemoved?.Invoke(entity, typeof(T)); + + return true; } /// @@ -217,7 +236,7 @@ public class EntityManager : IDisposable public void SetComponent(Entity entity, T component) where T : struct, IComponentData { - _world._componentStorage.GetOrCreateComponentPool().Set(entity, component); + _world.ComponentStorage.GetOrCreateComponentPool().Set(entity, component); } /// @@ -229,7 +248,7 @@ public class EntityManager : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasComponent(Entity entity, nint typeHandle) { - return _world._componentStorage.TryGetMask(typeHandle, out var bitSet) && bitSet.IsSet(entity.ID); + return _world.ComponentStorage.TryGetMask(typeHandle, out var bitSet) && bitSet.IsSet(entity.ID); } /// @@ -242,7 +261,7 @@ public class EntityManager : IDisposable public Ref GetComponent(Entity entity) where T : struct, IComponentData { - if (_world._componentStorage.TryGetPool(out var pool) && pool.Has(entity)) + if (_world.ComponentStorage.TryGetPool(out var pool) && pool.Has(entity)) { return new Ref(ref pool.GetRef(entity)); } @@ -261,7 +280,8 @@ public class EntityManager : IDisposable public void AddScript(Entity entity) where T : ScriptComponent, new() { - _world._componentStorage.ScriptComponentPool.Add(entity, new T()); + _world.ComponentStorage.ScriptComponentPool.Add(entity, new T()); + OnComponentAdded?.Invoke(entity, typeof(ScriptComponent)); } /// @@ -280,7 +300,31 @@ public class EntityManager : IDisposable } var instance = (ScriptComponent?)Activator.CreateInstance(type) ?? throw new InvalidOperationException($"Failed to create instance of {type}."); - _world._componentStorage.ScriptComponentPool.Add(entity, instance); + _world.ComponentStorage.ScriptComponentPool.Add(entity, instance); + OnComponentAdded?.Invoke(entity, typeof(ScriptComponent)); + } + + public bool RemoveScript(Entity entity) + where T : ScriptComponent + { + if (!_world.ComponentStorage.ScriptComponentPool.Remove(entity)) + { + return false; + } + + OnComponentRemoved?.Invoke(entity, typeof(ScriptComponent)); + return true; + } + + public bool RemoveScriptAt(Entity entity, int index) + { + if (!_world.ComponentStorage.ScriptComponentPool.RemoveAt(entity, index)) + { + return false; + } + + OnComponentRemoved?.Invoke(entity, typeof(ScriptComponent)); + return true; } /// @@ -292,7 +336,7 @@ public class EntityManager : IDisposable public T? GetScript(Entity entity) where T : ScriptComponent { - return (T?)_world._componentStorage.ScriptComponentPool.Get(entity)? + return (T?)_world.ComponentStorage.ScriptComponentPool.Get(entity)? .FirstOrDefault(script => script is T tScript); } @@ -305,7 +349,7 @@ public class EntityManager : IDisposable public IEnumerable GetScripts(Entity entity) where T : ScriptComponent { - return (IEnumerable?)_world._componentStorage.ScriptComponentPool.Get(entity)?.Where(script => script is T tScript) ?? Enumerable.Empty(); + return (IEnumerable?)_world.ComponentStorage.ScriptComponentPool.Get(entity)?.Where(script => script is T tScript) ?? Enumerable.Empty(); } public void Dispose() diff --git a/Ghost.Entities/Helpers/EntityHelpers.cs b/Ghost.Entities/Helpers/EntityHelpers.cs index cd20742..01f348a 100644 --- a/Ghost.Entities/Helpers/EntityHelpers.cs +++ b/Ghost.Entities/Helpers/EntityHelpers.cs @@ -33,11 +33,11 @@ public static class EntityHelpers /// The type of the component to remove. /// The entity for which the component is to be remove. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void RemoveComponent(this Entity entity) + public static bool RemoveComponent(this Entity entity) where T : struct, IComponentData { var world = entity.GetWorld(); - world.EntityManager.RemoveComponent(entity); + return world.EntityManager.RemoveComponent(entity); } /// diff --git a/Ghost.Entities/Query/QueryFilter.cs b/Ghost.Entities/Query/QueryFilter.cs index 9078d98..7d05598 100644 --- a/Ghost.Entities/Query/QueryFilter.cs +++ b/Ghost.Entities/Query/QueryFilter.cs @@ -37,7 +37,7 @@ internal struct QueryFilter() // Compute All mask (intersection) foreach (var typeHandle in _all) { - var mask = world._componentStorage.GetOrCreateMask(typeHandle); + var mask = world.ComponentStorage.GetOrCreateMask(typeHandle); if (!hasAll) { @@ -52,7 +52,7 @@ internal struct QueryFilter() // Compute Any mask (union) foreach (var typeHandle in _any) { - var mask = world._componentStorage.GetOrCreateMask(typeHandle); + var mask = world.ComponentStorage.GetOrCreateMask(typeHandle); if (!hasAny) { @@ -66,7 +66,7 @@ internal struct QueryFilter() // Compute Absent mask (union for exclusion) foreach (var typeHandle in _absent) { - var mask = world._componentStorage.GetOrCreateMask(typeHandle); + var mask = world.ComponentStorage.GetOrCreateMask(typeHandle); if (!hasAbsent) { diff --git a/Ghost.Entities/ScriptComponent.cs b/Ghost.Entities/ScriptComponent.cs index 5339f05..3aae5b0 100644 --- a/Ghost.Entities/ScriptComponent.cs +++ b/Ghost.Entities/ScriptComponent.cs @@ -2,14 +2,32 @@ public abstract class ScriptComponent : IComponentData { + private bool _enable = true; + /// /// Gets or sets a value indicating whether this script component is enabled. /// public bool Enable { - get; - set; - } = true; + get => _enable; + set + { + if (_enable == value) + { + return; + } + + _enable = value; + if (_enable) + { + OnEnable(); + } + else + { + OnDisable(); + } + } + } /// /// Gets the entity that owns this script component. diff --git a/Ghost.Entities/System.cs b/Ghost.Entities/System.cs index 4ebfe09..2261dba 100644 --- a/Ghost.Entities/System.cs +++ b/Ghost.Entities/System.cs @@ -1,19 +1,30 @@ -namespace Ghost.Entities; +using System.Runtime.CompilerServices; + +namespace Ghost.Entities; public abstract class SystemBase { + /// + /// Gets the execution order of the current operation or component. + /// public virtual int ExecutionOrder => 0; + /// + /// Gets or sets a value indicating whether the feature is enabled. + /// public virtual bool Enable { get; set; } = true; + /// + /// The world that this system belongs to. + /// public World World { get; - init; + internal set; } = null!; public virtual void OnCreate() @@ -29,38 +40,73 @@ public abstract class SystemBase } } -internal class SystemStorage : IDisposable +public class SystemStorage : IDisposable { private readonly List _systems = new(); private readonly List _executionList = new(); + private readonly World _world; + + public event Action? SystemAdded; + public event Action? SystemRemoved; + + internal SystemStorage(World world) + { + _world = world; + } + public void AddSystem(T system) where T : SystemBase { _systems.Add(system); + system.World = _world; if (system.Enable) { system.OnCreate(); } + + SystemAdded?.Invoke(system); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddSystem() + where T : SystemBase, new() + { + AddSystem(new T()); } public void RemoveSystem(T system) where T : SystemBase { + system.World = null!; _systems.Remove(system); if (system.Enable) { system.OnDestroy(); } + + SystemRemoved?.Invoke(system); } - public void RebuildExecutionList() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveSystem() + where T : SystemBase, new() + { + var system = _systems.FirstOrDefault(s => s is T); + if (system != null) + { + RemoveSystem(system); + } + } + + internal void RebuildExecutionList() { _executionList.Clear(); _executionList.AddRange(_systems.OrderBy(s => s.ExecutionOrder)); } - public void UpdateSystems() + internal void UpdateSystems() { foreach (var system in _systems) { diff --git a/Ghost.Entities/Utilities/Box.cs b/Ghost.Entities/Utilities/Box.cs deleted file mode 100644 index 0e45025..0000000 --- a/Ghost.Entities/Utilities/Box.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ghost.Entities.Utilities; - -internal class Box - where T : struct -{ - public T Value - { - get; - set; - } - - public Box(T value) - { - Value = value; - } - - public static implicit operator T(Box box) => box.Value; - public static implicit operator Box(T value) => new(value); -} \ No newline at end of file diff --git a/Ghost.Entities/Utilities/ComponentMask.cs b/Ghost.Entities/Utilities/ComponentMask.cs deleted file mode 100644 index 90c1d78..0000000 --- a/Ghost.Entities/Utilities/ComponentMask.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Numerics; - -namespace Ghost.Entities.Utilities; - -internal readonly struct ComponentMask -{ - private readonly ulong[] _words; - - public ComponentMask(int entityCapacity) - { - _words = new ulong[(entityCapacity + 63) / 64]; - } - - public void Set(int entityIndex) - => _words[entityIndex >> 6] |= 1UL << (entityIndex & 63); - - public void Clear(int entityIndex) - => _words[entityIndex >> 6] &= ~(1UL << (entityIndex & 63)); - - public bool Get(int entityIndex) - => ((_words[entityIndex >> 6] >> (entityIndex & 63)) & 1) != 0; - - // Bitwise AND - public ComponentMask And(in ComponentMask other) - { - var result = new ComponentMask(_words.Length * 64); - for (var i = 0; i < _words.Length; i++) - result._words[i] = _words[i] & other._words[i]; - return result; - } - - // Bitwise OR - public ComponentMask Or(in ComponentMask other) - { - var result = new ComponentMask(_words.Length * 64); - for (var i = 0; i < _words.Length; i++) - result._words[i] = _words[i] | other._words[i]; - return result; - } - - // Bitwise NOT - public ComponentMask Not() - { - var result = new ComponentMask(_words.Length * 64); - for (var i = 0; i < _words.Length; i++) - result._words[i] = ~_words[i]; - return result; - } - - // Iterate set bits (fast scan) - public IEnumerable GetEntityIndices() - { - for (var word = 0; word < _words.Length; word++) - { - var bits = _words[word]; - while (bits != 0) - { - var lowBit = BitOperations.TrailingZeroCount(bits); - yield return (word << 6) + lowBit; - bits &= bits - 1; // clear lowest set bit - } - } - } -} diff --git a/Ghost.Entities/World.cs b/Ghost.Entities/World.cs index 4a354cf..e634975 100644 --- a/Ghost.Entities/World.cs +++ b/Ghost.Entities/World.cs @@ -12,6 +12,8 @@ public partial class World private static int s_maxWorldCount = (int)MathF.Pow(2, Entity.WORLD_INDEX_BITS); + public static int WorldCount => s_worlds.Count - s_freeWorldSlots.Count; + public static World Create(int entityCapacity = 16) { lock (s_worlds) @@ -46,31 +48,21 @@ public partial class World : IDisposable { private readonly WorldID _id; private readonly EntityManager _entityManager; + private readonly ComponentStorage _componentStorage; + private readonly SystemStorage _systemStorage; - internal readonly ComponentStorage _componentStorage; - internal readonly SystemStorage _systemStorage; + internal ComponentStorage ComponentStorage => _componentStorage; public WorldID ID => _id; public EntityManager EntityManager => _entityManager; + public SystemStorage SystemStorage => _systemStorage; private World(WorldID id, int entityCapacity) { _id = id; _entityManager = new EntityManager(this, entityCapacity); - _componentStorage = new ComponentStorage(); - _systemStorage = new SystemStorage(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddSystem() - where T : SystemBase, new() - { - var instance = new T - { - World = this - }; - - _systemStorage.AddSystem(instance); + _componentStorage = new ComponentStorage(this); + _systemStorage = new SystemStorage(this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Ghost.Test/Ghost.Test.csproj b/Ghost.Test/Ghost.Test.csproj index 85cad08..5a965f8 100644 --- a/Ghost.Test/Ghost.Test.csproj +++ b/Ghost.Test/Ghost.Test.csproj @@ -8,9 +8,9 @@ - + diff --git a/Ghost.Test/Program.cs b/Ghost.Test/Program.cs index f66dfab..c470c53 100644 --- a/Ghost.Test/Program.cs +++ b/Ghost.Test/Program.cs @@ -44,8 +44,8 @@ public partial class Test entity4.AddComponent(new Mesh { index = 44 }); entity4.AddScript(); - world.AddSystem(); - world._systemStorage.UpdateSystems(); + world.SystemStorage.AddSystem(); + world.SystemStorage.UpdateSystems(); //world.SystemStorage.RebuildExecutionList(); //world.ComponentStorage.RebuildExecutionList();