From 7ff91a8836e4059a2e433c2128f07118a565d7d3 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 16 Mar 2025 00:17:04 +0200 Subject: [PATCH 1/3] Initial project set --- Editor/EditorWindow.cs | 9 +++++++-- Editor/Program.cs | 7 ++++--- Editor/Windows/ActionsMenuWindow.cs | 8 ++++++++ Editor/Windows/ImGuiWindowBase.cs | 10 ++++++++-- SharpEngine.Shared/Project.cs | 12 ++++++++++++ 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index 167d5a7..a519dbd 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -18,7 +18,7 @@ namespace SharpEngine.Editor; /// public class EditorWindow : Window { - private Project _project = new Project() { Path = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\Examples\Minimal"), Name = "Minimal" }; + private Project _project; private readonly List _windows = []; private ContextMenuWindow? _contextMenuWindow; @@ -29,7 +29,10 @@ public class EditorWindow : Window /// /// Represents the current scene to be displayed in the editor window. /// Contains configuration options for how the view should be rendered. - public EditorWindow(Scene scene, IViewSettings settings) : base(scene, settings) { } + public EditorWindow(Scene scene, Project project, IViewSettings settings) : base(scene, settings) + { + _project = project; + } /// public override void OnLoad() @@ -50,6 +53,7 @@ public override void OnLoad() // Initialize all ImGuiWindowBase implementations for (int i = 0; i < windowTypes.Length; i++) + { try { var type = windowTypes[i]; @@ -66,6 +70,7 @@ public override void OnLoad() { Debug.LogInformation(e.Message, e); } + } _contextMenuWindow = (ContextMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ContextMenuWindow)); if (_contextMenuWindow is null) diff --git a/Editor/Program.cs b/Editor/Program.cs index dd32e86..f051744 100644 --- a/Editor/Program.cs +++ b/Editor/Program.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Entities.Views.Settings; +using Launcher.UI; +using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; using SharpEngine.Editor.Windows; @@ -16,10 +17,10 @@ public static class Program [STAThread] public static void Main(string[] args) { - //var editor = new Editor(); var scene = args.Length > 0 ? Scene.LoadScene(args[0]) : new Scene(); + var project = args.Length > 0 ? Project.LoadProject(args[1]) : new Project() { Path = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\Examples\Minimal"), Name = "Minimal" }; - using var window = new EditorWindow(scene, new DefaultViewSettings()); + using var window = new EditorWindow(scene, project, new DefaultViewSettings()); window.OnLoaded += () => Console.WriteLine("test"); window.Run(); diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index 2240509..36ae25b 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -36,6 +36,14 @@ public override void Render() private void StartGame() { + if (Project is null) + { + // TODO: This should never be possible. If the Project is null when it's loaded we should make sure it's initialized. + // Editor service probably needs to be made shared so that we can initialize the project / solution when the editor is opened. + + // TODO: Do we want to save here automatically or prompt the user to save? + } + Debug.LogInformation($"Starting {Project.Name}."); Thread thread = new Thread(() => diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index 8c9c308..62324b3 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -11,10 +11,16 @@ namespace SharpEngine.Editor.Windows public abstract class ImGuiWindowBase { /// Gets or sets the currently active project. - public Project? Project { get; set; } + public Project Project { get; set; } /// Gets or sets the currently active scene. - public Scene? Scene { get; private set; } + public Scene Scene { get; private set; } + + public ImGuiWindowBase() + { + Scene = new Scene(); + Project = new Project(); + } private readonly Dictionary _previousDockingStates = []; diff --git a/SharpEngine.Shared/Project.cs b/SharpEngine.Shared/Project.cs index aad3658..5cac973 100644 --- a/SharpEngine.Shared/Project.cs +++ b/SharpEngine.Shared/Project.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json; using System.Text.Json.Serialization; namespace Launcher.UI; @@ -30,4 +31,15 @@ public class Project /// [JsonIgnore] public DateTime LastModified { get; set; } = DateTime.Now; + + /// + /// Loads the given project file. + /// + /// The file containing the project to load. + /// The loaded project. If unable to load, . + public static Project? LoadProject(string projectFile) + { + var json = File.ReadAllText(projectFile); + return JsonSerializer.Deserialize(json); + } } From c0dbe3c44f238baa6c7c0a90f8a884d41c899114 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 16 Mar 2025 15:26:42 +0200 Subject: [PATCH 2/3] Fix launcher Launcher notifications no longer stack on top of each other, "open in editor" now works, and more --- Core/Entities/GameObject.cs | 7 ++- Core/Entities/Lights/DirectionalLight.cs | 3 +- Core/Entities/Lights/PointLight.cs | 5 +- Core/Entities/Lights/SpotLight.cs | 5 +- Core/Extensions/PathExtensions.cs | 10 ++++ Core/Primitives/PrimitiveFactory.cs | 10 ++-- Core/Scenes/Scene.cs | 11 ++++- Core/Shaders/LampShader.cs | 3 +- Core/Shaders/LightingShader.cs | 3 +- Core/Shaders/UIShader.cs | 5 +- Editor/EditorWindow.cs | 3 ++ Editor/Program.cs | 36 ++++++++++++-- Editor/Windows/ActionsMenuWindow.cs | 39 ++++++--------- Examples/MinecraftClone/Block/Dirt.cs | 13 +++-- Examples/MinecraftClone/Block/Stone.cs | 9 ++-- Launcher/Launcher.csproj | 2 +- Launcher/Platforms/Android/MainApplication.cs | 3 +- Launcher/Services/EditorService.cs | 15 +++--- Launcher/Services/NotificationService.cs | 31 ++++++++++-- .../UI/Components/Dialogs/Notification.razor | 13 +++-- Launcher/wwwroot/css/app.css | 5 ++ SharpEngine.Shared/EnvironmentVariables.cs | 12 +++++ SharpEngine.Shared/ProcessExtensions.cs | 48 +++++++++++++++++-- 23 files changed, 215 insertions(+), 76 deletions(-) create mode 100644 Core/Extensions/PathExtensions.cs create mode 100644 SharpEngine.Shared/EnvironmentVariables.cs diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 7d5d0ce..d8a94ed 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -1,12 +1,15 @@ using SharpEngine.Core.Attributes; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Extensions; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Textures; using Silk.NET.OpenGL; using System.Collections.Generic; +using System.IO; +using System.Reflection; using System.Threading.Tasks; namespace SharpEngine.Core.Entities; @@ -21,8 +24,8 @@ public class GameObject : SceneNode /// public GameObject() { - var shader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/lighting.frag", "lighting"); - var diffuse = TextureService.Instance.LoadTexture("Textures/DefaultTextures/debug.JPG"); + var shader = ShaderService.Instance.LoadShader(PathExtensions.GetPath("Shaders/shader.vert"), PathExtensions.GetPath("Shaders/lighting.frag"), "lighting"); + var diffuse = TextureService.Instance.LoadTexture(PathExtensions.GetPath("Textures/DefaultTextures/debug.JPG")); Material = new(shader, diffuse); BoundingBox = BoundingBox.CalculateBoundingBox(Transform); diff --git a/Core/Entities/Lights/DirectionalLight.cs b/Core/Entities/Lights/DirectionalLight.cs index 7bca777..873ec2c 100644 --- a/Core/Entities/Lights/DirectionalLight.cs +++ b/Core/Entities/Lights/DirectionalLight.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; using System.Numerics; using System.Threading.Tasks; @@ -23,7 +24,7 @@ public DirectionalLight() Diffuse = new Vector3(0.4f, 0.4f, 0.4f); Specular = new Vector3(0.5f, 0.5f, 0.5f); - Material.Shader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/lighting.frag", "lighting"); + Material.Shader = ShaderService.Instance.LoadShader(PathExtensions.GetPath("Shaders/shader.vert"), PathExtensions.GetPath("Shaders/lighting.frag"), "lighting"); } /// diff --git a/Core/Entities/Lights/PointLight.cs b/Core/Entities/Lights/PointLight.cs index 1f6f71c..1df38d8 100644 --- a/Core/Entities/Lights/PointLight.cs +++ b/Core/Entities/Lights/PointLight.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Shaders; +using SharpEngine.Core.Extensions; +using SharpEngine.Core.Shaders; using System.Numerics; using System.Threading.Tasks; @@ -24,7 +25,7 @@ public PointLight(Vector3 position, int index) _index = index; - Material.Shader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/lighting.frag", "lighting"); + Material.Shader = ShaderService.Instance.LoadShader(PathExtensions.GetPath("Shaders/shader.vert"), PathExtensions.GetPath("Shaders/lighting.frag"), "lighting"); LampShader = new LampShader(); } diff --git a/Core/Entities/Lights/SpotLight.cs b/Core/Entities/Lights/SpotLight.cs index 7ebe370..dffdaa0 100644 --- a/Core/Entities/Lights/SpotLight.cs +++ b/Core/Entities/Lights/SpotLight.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Shaders; +using SharpEngine.Core.Extensions; +using SharpEngine.Core.Shaders; using System.Numerics; using System.Threading.Tasks; @@ -21,7 +22,7 @@ public SpotLight() Linear = 0.09f; Quadratic = 0.032f; - Material.Shader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/lighting.frag", "lighting"); + Material.Shader = ShaderService.Instance.LoadShader(PathExtensions.GetPath("Shaders/shader.vert"), PathExtensions.GetPath("Shaders/lighting.frag"), "lighting"); } /// diff --git a/Core/Extensions/PathExtensions.cs b/Core/Extensions/PathExtensions.cs new file mode 100644 index 0000000..554c802 --- /dev/null +++ b/Core/Extensions/PathExtensions.cs @@ -0,0 +1,10 @@ +using System; +using System.IO; +using System.Reflection; + +namespace SharpEngine.Core.Extensions; +public static class PathExtensions +{ + public static string GetPath(string file) + => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file); +} diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index b72f9b9..981c616 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -1,6 +1,6 @@ using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; - +using SharpEngine.Core.Extensions; using System; using System.Numerics; @@ -11,13 +11,17 @@ namespace SharpEngine.Core.Primitives; /// public static class PrimitiveFactory { + private static string DebugTexture => PathExtensions.GetPath("Textures/DefaultTextures/debug.JPG"); + private static string DefaultVertexShader => PathExtensions.GetPath("Shaders/shader.vert"); + private static string DefaultFragmentShader => PathExtensions.GetPath("Shaders/lighting.frag"); + /// /// Creates a new by the given primitive type. /// /// The type of primitive to create. /// Where the game object should be placed. public static GameObject Create(PrimitiveType primitiveType, Vector3 position) - => Create(primitiveType, position, "Textures/DefaultTextures/debug.JPG"); + => Create(primitiveType, position, DebugTexture); /// /// The type of primitive to be created. @@ -29,7 +33,7 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position) /// A new game object. /// Thrown when the specified primitive type does not exist. public static GameObject Create(PrimitiveType primitiveType, Vector3 position, string diffuseMapFile, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) - => new(diffuseMapFile, specularMapFile ?? "Textures/DefaultTextures/debug.JPG", vertShaderFile ?? "Shaders/shader.vert", fragShaderFile ?? "Shaders/lighting.frag") + => new(diffuseMapFile, specularMapFile ?? DebugTexture, vertShaderFile ?? DefaultVertexShader, fragShaderFile ?? DefaultFragmentShader) { Transform = new Transform { Position = position }, Mesh = primitiveType switch diff --git a/Core/Scenes/Scene.cs b/Core/Scenes/Scene.cs index e90a80e..fc4a87e 100644 --- a/Core/Scenes/Scene.cs +++ b/Core/Scenes/Scene.cs @@ -180,6 +180,8 @@ public IEnumerable IterateAsync(List elements, FuncThe scene from the given file. Loads an empty scene if unable to load the scene. public static Scene LoadScene(string sceneFile) { + Console.WriteLine(sceneFile); + var loadedScene = JsonSerializer.Deserialize(sceneFile); if (loadedScene is not null) @@ -191,7 +193,7 @@ public static Scene LoadScene(string sceneFile) return new(); } - private void SetFileFullPath(string sceneFile) + public void SetFileFullPath(string sceneFile) { _fileFullPath = sceneFile; Name = System.IO.Path.GetFileNameWithoutExtension(sceneFile); @@ -204,6 +206,13 @@ private void SetFileFullPath(string sceneFile) public bool HasSaveFile() => _fileFullPath is not null; + /// + /// Saves the scene. + /// + /// A representing an asynchronous operation. + public async Task SaveScene() + => await SaveScene(_fileFullPath!); + /// /// Saves the scene to the given . /// diff --git a/Core/Shaders/LampShader.cs b/Core/Shaders/LampShader.cs index 38f24e6..4e641f4 100644 --- a/Core/Shaders/LampShader.cs +++ b/Core/Shaders/LampShader.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Extensions; using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; @@ -7,7 +8,7 @@ internal class LampShader : ShaderBase { public LampShader() { - Shader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/shader.frag", "lamp"); + Shader = ShaderService.Instance.LoadShader(PathExtensions.GetPath("Shaders/shader.vert"), PathExtensions.GetPath("Shaders/shader.frag"), "lamp"); Vao = Window.GL.GenVertexArray(); Window.GL.BindVertexArray(Vao); diff --git a/Core/Shaders/LightingShader.cs b/Core/Shaders/LightingShader.cs index f822488..37caae1 100644 --- a/Core/Shaders/LightingShader.cs +++ b/Core/Shaders/LightingShader.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Extensions; using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; @@ -7,7 +8,7 @@ internal class LightingShader : ShaderBase { public LightingShader() { - Shader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/lighting.frag", "lighting"); + Shader = ShaderService.Instance.LoadShader(PathExtensions.GetPath("Shaders/shader.vert"), PathExtensions.GetPath("Shaders/lighting.frag"), "lighting"); Vao = Window.GL.GenVertexArray(); Window.GL.BindVertexArray(Vao); diff --git a/Core/Shaders/UIShader.cs b/Core/Shaders/UIShader.cs index f0d7508..eea3bfb 100644 --- a/Core/Shaders/UIShader.cs +++ b/Core/Shaders/UIShader.cs @@ -1,4 +1,5 @@ -using Silk.NET.OpenGL; +using SharpEngine.Core.Extensions; +using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; @@ -6,7 +7,7 @@ internal class UIShader : ShaderBase { public UIShader() { - Shader = new Shader("Shaders/uiShader.vert", "Shaders/uiShader.frag", "ui"); + Shader = new Shader(PathExtensions.GetPath("Shaders/uiShader.vert"), PathExtensions.GetPath("Shaders/uiShader.frag"), "ui"); } /// diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index a519dbd..5ed6796 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -28,6 +28,7 @@ public class EditorWindow : Window /// Initializes an editor window with a specified scene and view settings. /// /// Represents the current scene to be displayed in the editor window. + /// The project loaded to the editor. /// Contains configuration options for how the view should be rendered. public EditorWindow(Scene scene, Project project, IViewSettings settings) : base(scene, settings) { @@ -79,6 +80,8 @@ public override void OnLoad() _actionsMenuWindow = (ActionsMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ActionsMenuWindow)); if (_actionsMenuWindow is null) Debug.LogInformation("ActionsMenuWindow not found."); + else + _actionsMenuWindow.OnSceneLoaded += SetScene; } /// diff --git a/Editor/Program.cs b/Editor/Program.cs index f051744..a9cad09 100644 --- a/Editor/Program.cs +++ b/Editor/Program.cs @@ -1,7 +1,10 @@ using Launcher.UI; +using SharpEngine.Core; using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; using SharpEngine.Editor.Windows; +using SharpEngine.Shared; +using System.Reflection; namespace SharpEngine.Editor; @@ -17,12 +20,35 @@ public static class Program [STAThread] public static void Main(string[] args) { - var scene = args.Length > 0 ? Scene.LoadScene(args[0]) : new Scene(); - var project = args.Length > 0 ? Project.LoadProject(args[1]) : new Project() { Path = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\Examples\Minimal"), Name = "Minimal" }; + try + { + var editorPath = Environment.GetEnvironmentVariable(EnvironmentVariables.EDITOR_PATH_ENVIRONMENT_VARIABLE); + if (string.IsNullOrWhiteSpace(editorPath)) + Environment.SetEnvironmentVariable(EnvironmentVariables.EDITOR_PATH_ENVIRONMENT_VARIABLE, System.Environment.ProcessPath, EnvironmentVariableTarget.User); - using var window = new EditorWindow(scene, project, new DefaultViewSettings()); - window.OnLoaded += () => Console.WriteLine("test"); + string? sceneFile = null; + string? projectFile = null; - window.Run(); + foreach (var arg in args) + { + if (arg.EndsWith(".sharpscene", StringComparison.OrdinalIgnoreCase)) + sceneFile = arg; + + else if (arg.EndsWith(".sharpproject", StringComparison.OrdinalIgnoreCase)) + projectFile = arg; + } + + var scene = !string.IsNullOrEmpty(sceneFile) ? Scene.LoadScene(sceneFile) : new Scene(); + var project = !string.IsNullOrEmpty(projectFile) ? Project.LoadProject(projectFile) : new Project(); + + using var window = new EditorWindow(scene, project!, new DefaultViewSettings()); + window.OnLoaded += () => Console.WriteLine("test"); + + window.Run(); + } + catch (Exception e) + { + Debug.LogInformation($"Failed to start the editor: {e.Message}", e, true); + } } } \ No newline at end of file diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index 36ae25b..1301ea8 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -17,7 +17,7 @@ public class ActionsMenuWindow : ImGuiWindowBase /// /// An event executed when a new scene is loaded. /// - public event Action? OnSceneLoaded; + public event Action? OnSceneLoaded; /// public override void Render() @@ -45,40 +45,27 @@ private void StartGame() } Debug.LogInformation($"Starting {Project.Name}."); - - Thread thread = new Thread(() => - { - var process = ProcessExtensions.GetProcess($"dotnet run --project {Project.Path}/{Project.Name}.csproj", true); - process.ErrorDataReceived += (sender, e) => Debug.LogInformation(e.Data); - process.OutputDataReceived += (sender, e) => Debug.LogInformation(e.Data); - process.Exited += (sender, e) => Debug.LogInformation("Process exited."); - - process.Start(); - - // Read and display output - string output = process.StandardOutput.ReadToEnd(); - string error = process.StandardError.ReadToEnd(); - - if (!string.IsNullOrWhiteSpace(output)) - Debug.LogInformation(output); - - if (!string.IsNullOrWhiteSpace(error)) - Debug.LogInformation(error); - }); - - thread.Start(); + ProcessExtensions.RunProcess($"dotnet run --project {Project.Path}/{Project.Name}.csproj", true, msg => Debug.LogInformation(msg)); } - private static void SaveScene(Scene scene) + private void SaveScene(Scene scene) { Console.WriteLine("Saving.."); - if (!scene.HasUnsavedChanges && !scene.HasSaveFile()) + if (!scene.HasUnsavedChanges && scene.HasSaveFile()) { Console.WriteLine("No changes to save."); return; } + if (scene.HasSaveFile()) + { + scene.SaveScene().Wait(); + OnSceneLoaded?.Invoke(scene); + Console.WriteLine("File saved successfully!"); + return; + } + using var dialog = new SaveFileDialog() { Filter = $"Scene files (*.{Scene.SceneFileExtension})|*.{Scene.SceneFileExtension}", @@ -92,6 +79,8 @@ private static void SaveScene(Scene scene) if (dialogResult == DialogResult.OK) { scene.SaveScene(dialog.FileName).Wait(); + Scene.SetFileFullPath(dialog.FileName); + Console.WriteLine("File saved successfully!"); } else diff --git a/Examples/MinecraftClone/Block/Dirt.cs b/Examples/MinecraftClone/Block/Dirt.cs index 2d1397e..9b0a77e 100644 --- a/Examples/MinecraftClone/Block/Dirt.cs +++ b/Examples/MinecraftClone/Block/Dirt.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using SharpEngine.Core.Extensions; +using System.Numerics; namespace Minecraft.Block; @@ -10,10 +11,12 @@ internal class Dirt : BlockBase /// /// Initializes a new block. /// - /// - /// - public Dirt(Vector3 position, string name) - : base(position, name, "Resources/grass.jpg", "Resources/container2_specular.png", "Shaders/shader.vert", "Shaders/lighting.frag") { } + /// The position where the block should be initialized. + /// The name of the block to initialize. + public Dirt(Vector3 position, string name) : base(position, name, PathExtensions.GetPath("Resources/grass.jpg"), + PathExtensions.GetPath("Resources/container2_specular.png"), + PathExtensions.GetPath("Shaders/shader.vert"), + PathExtensions.GetPath("Shaders/lighting.frag")) { } /// public override BlockType BlockType => BlockType.Dirt; diff --git a/Examples/MinecraftClone/Block/Stone.cs b/Examples/MinecraftClone/Block/Stone.cs index d660b77..8c24140 100644 --- a/Examples/MinecraftClone/Block/Stone.cs +++ b/Examples/MinecraftClone/Block/Stone.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using SharpEngine.Core.Extensions; +using System.Numerics; namespace Minecraft.Block; @@ -12,8 +13,10 @@ internal class Stone : BlockBase /// /// The position where the block is created. /// The name of the object in the scene. - public Stone(Vector3 position, string name) - : base(position, name, "Resources/container2.png", "Resources/container2_specular.png", "Shaders/shader.vert", "Shaders/lighting.frag") { } + public Stone(Vector3 position, string name) : base(position, name, PathExtensions.GetPath("Resources/container2.png"), + PathExtensions.GetPath("Resources/container2_specular.png"), + PathExtensions.GetPath("Shaders/shader.vert"), + PathExtensions.GetPath("Shaders/lighting.frag")) { } /// public override BlockType BlockType => BlockType.Stone; diff --git a/Launcher/Launcher.csproj b/Launcher/Launcher.csproj index 46bbdbf..60f9fea 100644 --- a/Launcher/Launcher.csproj +++ b/Launcher/Launcher.csproj @@ -30,7 +30,7 @@ Launcher - com.companyname.launcher + com.sharpengine.launcher 1.0 diff --git a/Launcher/Platforms/Android/MainApplication.cs b/Launcher/Platforms/Android/MainApplication.cs index 8f7e094..c1afefe 100644 --- a/Launcher/Platforms/Android/MainApplication.cs +++ b/Launcher/Platforms/Android/MainApplication.cs @@ -11,5 +11,6 @@ public MainApplication(IntPtr handle, JniHandleOwnership ownership) { } - protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + /// + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } diff --git a/Launcher/Services/EditorService.cs b/Launcher/Services/EditorService.cs index 246cc81..22142f6 100644 --- a/Launcher/Services/EditorService.cs +++ b/Launcher/Services/EditorService.cs @@ -118,6 +118,8 @@ private void CreateSolution(Project project) /// public void OpenInEditor(Project project) { + _notificationService.Show($"Starting {project.Name}.."); + if (!Path.Exists(project.Path)) { _notificationService.Show($"The project file '{project.Path}' no longer exists."); @@ -126,22 +128,17 @@ public void OpenInEditor(Project project) try { - const string editorPathEnvironmentVariable = "SHARPENGINE_EDITOR_PATH"; - string? editorPath = Environment.GetEnvironmentVariable(editorPathEnvironmentVariable); - if (editorPath is null) + string? editorExecutableFilePath = Environment.GetEnvironmentVariable(EnvironmentVariables.EDITOR_PATH_ENVIRONMENT_VARIABLE); + if (editorExecutableFilePath is null) { _notificationService.Show("Editor variable not found"); return; } - const string editorExecutable = "SharpEngine.Editor.exe"; - string projectFile = project.Path.EndsWith(SHARP_ENGINE_PROJECT_EXTENSION) ? - project.Path : $"{project.Path}/{project.Name}.{SHARP_ENGINE_PROJECT_EXTENSION}"; + project.Path : $"{project.Path}\\{project.Name}.{SHARP_ENGINE_PROJECT_EXTENSION}"; - var process = ProcessExtensions.GetProcess($"{editorPath}/{editorExecutable} {projectFile}"); - process.Start(); - process.WaitForExit(); + ProcessExtensions.RunProcess($"{editorExecutableFilePath} {projectFile}", true, msg => _notificationService.ShowAsync(msg)); } catch (Exception ex) { diff --git a/Launcher/Services/NotificationService.cs b/Launcher/Services/NotificationService.cs index 0d492b7..b28fd35 100644 --- a/Launcher/Services/NotificationService.cs +++ b/Launcher/Services/NotificationService.cs @@ -14,6 +14,8 @@ public interface INotificationService /// Sets the event executed when the notifications are changed. void SetOnNotificationsChanged(Action action); + void SetInvokeAsync(Func, Task> action); + /// /// Discards a notification message from the UI. /// @@ -27,6 +29,7 @@ public interface INotificationService /// Determines whether the message should be logged to a file. /// The details that should be logged with the message. void Show(string message, bool writeToFile = false, params object?[] details); + Task ShowAsync(string message, bool writeToFile = false, params object?[] details); } /// @@ -40,6 +43,8 @@ public class NotificationService : INotificationService private event Action? OnNotificationsChanged; private readonly Logger _log; + public Func, Task>? InvokeAsync; + /// /// Initializes a new instance of . /// @@ -54,8 +59,31 @@ public NotificationService() public void SetOnNotificationsChanged(Action action) => OnNotificationsChanged = action; + public void SetInvokeAsync(Func, Task> action) + => InvokeAsync = action; + + public async Task ShowAsync(string message, bool writeToFile = false, params object?[] details) + { + ShowMessage(message, writeToFile, details); + + if (InvokeAsync is not null) + await InvokeAsync(() => + { + OnNotificationsChanged?.Invoke(); + return Task.CompletedTask; + }); + } + /// public void Show(string message, bool writeToFile = false, params object?[] details) + { + ShowMessage(message, writeToFile, details); + + // Notify UI about the change + OnNotificationsChanged?.Invoke(); + } + + private void ShowMessage(string message, bool writeToFile = false, params object?[] details) { if (writeToFile) _log.Information(message, details); @@ -64,9 +92,6 @@ public void Show(string message, bool writeToFile = false, params object?[] deta Notifications[message] = count + 1; else Notifications.Add(message, 1); - - // Notify UI about the change - OnNotificationsChanged?.Invoke(); } /// diff --git a/Launcher/UI/Components/Dialogs/Notification.razor b/Launcher/UI/Components/Dialogs/Notification.razor index 4943980..8a40e57 100644 --- a/Launcher/UI/Components/Dialogs/Notification.razor +++ b/Launcher/UI/Components/Dialogs/Notification.razor @@ -3,14 +3,16 @@ @inject INotificationService NotificationService -
+
+
@foreach (var notification in NotificationService.Notifications) { -
@code { @@ -20,5 +22,8 @@ /// protected override void OnInitialized() - => NotificationService.SetOnNotificationsChanged(StateHasChanged); + { + NotificationService.SetInvokeAsync(InvokeAsync); + NotificationService.SetOnNotificationsChanged(StateHasChanged); + } } diff --git a/Launcher/wwwroot/css/app.css b/Launcher/wwwroot/css/app.css index 330049c..aad5a54 100644 --- a/Launcher/wwwroot/css/app.css +++ b/Launcher/wwwroot/css/app.css @@ -96,4 +96,9 @@ p, h1, h4, a, td, tr, div, .prevent-select { -webkit-user-select: none; /* Safari */ -ms-user-select: none; /* IE 10 and IE 11 */ user-select: none; /* Standard syntax */ +} + +.page { + height: 100%; + display: flow-root; } \ No newline at end of file diff --git a/SharpEngine.Shared/EnvironmentVariables.cs b/SharpEngine.Shared/EnvironmentVariables.cs new file mode 100644 index 0000000..3d18fd1 --- /dev/null +++ b/SharpEngine.Shared/EnvironmentVariables.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Shared; +public static class EnvironmentVariables +{ + public const string EDITOR_PATH_ENVIRONMENT_VARIABLE = "SHARPENGINE_EDITOR_PATH"; + +} diff --git a/SharpEngine.Shared/ProcessExtensions.cs b/SharpEngine.Shared/ProcessExtensions.cs index 03a72d9..4df59f7 100644 --- a/SharpEngine.Shared/ProcessExtensions.cs +++ b/SharpEngine.Shared/ProcessExtensions.cs @@ -22,11 +22,49 @@ public static Process GetProcess(string arguments, bool createWindow = false) StartInfo = new ProcessStartInfo { FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "cmd.exe" : "/bin/sh", - Arguments = arguments, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - CreateNoWindow = createWindow + Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"/k {arguments}" : $"-k \"{arguments}\"", + UseShellExecute = true, + RedirectStandardOutput = false, + CreateNoWindow = false, + WindowStyle = ProcessWindowStyle.Normal } }; + + public static void RunProcess(string arguments, bool createWindow = true, Action? onMessage = null) + { + void SendMessage(string msg) + { + if (!string.IsNullOrWhiteSpace(msg)) + onMessage?.Invoke(msg); + } + + var process = GetProcess(arguments, createWindow); + process.ErrorDataReceived += (sender, e) => SendMessage(e.Data); + process.OutputDataReceived += (sender, e) => SendMessage(e.Data); + process.Exited += (sender, e) => SendMessage("Process exited."); + + var start = new ThreadStart(() => + { + try + { + process.Start(); + + // Start reading output and error streams + // process.BeginOutputReadLine(); + // process.BeginErrorReadLine(); + + // Wait for the process to exit + process.WaitForExit(); + } + catch (Exception ex) + { + SendMessage($"Exception occurred: {ex.Message}"); + } + }); + + Thread thread = new Thread(start); + thread.Start(); + + SendMessage("Editor launched."); + } } From f33a779a032afb9c1c7bd9656c2d1c34b526411d Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 16 Mar 2025 15:33:24 +0200 Subject: [PATCH 3/3] Add debug option for testing purposes --- Editor/Program.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Editor/Program.cs b/Editor/Program.cs index a9cad09..1dd9670 100644 --- a/Editor/Program.cs +++ b/Editor/Program.cs @@ -39,8 +39,13 @@ public static void Main(string[] args) } var scene = !string.IsNullOrEmpty(sceneFile) ? Scene.LoadScene(sceneFile) : new Scene(); - var project = !string.IsNullOrEmpty(projectFile) ? Project.LoadProject(projectFile) : new Project(); - + var project = !string.IsNullOrEmpty(projectFile) ? Project.LoadProject(projectFile) +#if DEBUG + // TODO: We should create an additional getter for the .sharpproject file. + : new Project() { Path = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\Examples\Minimal"), Name = "Minimal" }; +#else + : new Project(); +#endif using var window = new EditorWindow(scene, project!, new DefaultViewSettings()); window.OnLoaded += () => Console.WriteLine("test");