From 75f151543f5945655a32d2e5db3112342bac8a49 Mon Sep 17 00:00:00 2001 From: Donovan Prezeau Date: Thu, 8 May 2025 15:04:01 -0600 Subject: [PATCH 01/92] initial PoC --- build/Stride.sln | 15 ++++ sources/Directory.Packages.props | 4 +- .../Engine/Builder/GameBuilder.cs | 51 +++++++++++++ .../Engine/Builder/GameBuilderExtensions.cs | 72 +++++++++++++++++++ .../Engine/Builder/IGameBuilder.cs | 16 +++++ .../Engine/Builder/MinimalGame.cs | 43 +++++++++++ .../Engine/Design/GameSettings.cs | 2 - sources/engine/Stride.Games/GameBase.cs | 4 +- .../Stride.Games/GraphicsDeviceManager.cs | 2 +- sources/engine/Stride.Games/IGame.cs | 1 - sources/engine/Stride.Hosting/BasicGame.cs | 42 +++++++++++ .../Stride.Hosting/IStrideGameBuilder.cs | 16 +++++ .../Stride.Hosting/Stride.Hosting.csproj | 28 ++++++++ .../Stride.Hosting/StrideGameBuilder.cs | 39 ++++++++++ 14 files changed, 328 insertions(+), 7 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs create mode 100644 sources/engine/Stride.Hosting/BasicGame.cs create mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs create mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj create mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/build/Stride.sln b/build/Stride.sln index 65dbc5b24f..969e630fb4 100644 --- a/build/Stride.sln +++ b/build/Stride.sln @@ -338,6 +338,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\so EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Tests", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Tests\Stride.BepuPhysics.Tests.csproj", "{7B70C783-4085-4702-B3C6-6570FD85CB8F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stride.Hosting", "..\sources\engine\Stride.Hosting\Stride.Hosting.csproj", "{A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1523,6 +1525,18 @@ Global {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.ActiveCfg = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.Build.0 = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.ActiveCfg = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.Build.0 = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.Build.0 = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.ActiveCfg = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1652,6 +1666,7 @@ Global {7715D094-DF59-4D91-BC9A-9A5118039ECB} = {DE048114-9AE4-467E-A879-188DC0D88A59} {66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C} {7B70C783-4085-4702-B3C6-6570FD85CB8F} = {DE048114-9AE4-467E-A879-188DC0D88A59} + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715} = {4C142567-C42B-40F5-B092-798882190209} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2} diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 28607e25a4..633d58c70b 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,6 +11,8 @@ + + @@ -144,4 +146,4 @@ - + \ No newline at end of file diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs new file mode 100644 index 0000000000..dd5a1b202d --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Engine.Builder; + +/// +/// Helps build the game and preps it to be able to run after built. +/// +/// +public class GameBuilder : IGameBuilder where T : IGame +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal GameBuilder() + { + Game = new MinimalGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static GameBuilder Create() + { + return new GameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} + +/// +/// Creates a default GameBuilder for a . +/// +public class GameBuilder : GameBuilder +{ + +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs new file mode 100644 index 0000000000..ead167468a --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -0,0 +1,72 @@ +using System; +using Stride.Core.Diagnostics; +using Stride.Core.IO; +using Stride.Core.Storage; +using Stride.Games; +using Stride.Rendering; +using Stride.Shaders.Compiler; + +namespace Stride.Engine.Builder; +public static class GameBuilderExtensions +{ + public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gameSystem) where T : IGameSystemBase + { + gameBuilder.GameSystems.Add(gameSystem); + return gameBuilder; + } + + public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class + { + gameBuilder.Services.AddService(service); + return gameBuilder; + } + + public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogListener logListener) + { + gameBuilder.LogListeners.Add(logListener); + return gameBuilder; + } + + public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) + { + // Gets initialized by the GameBase constructor. + var dataBase = gameBuilder.Services.GetService(); + // There should probably be a change to the interface to avoid the below casting. + ((DatabaseFileProviderService)dataBase).FileProvider = provider; + return gameBuilder; + } + + public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) + { + using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) + { + // Create and mount database file system + var objDatabase = ObjectDatabase.CreateDefaultDatabase(); + + // Only set a mount path if not mounted already + var mountPath = VirtualFileSystem.ResolveProviderUnsafe("/asset", true).Provider == null ? "/asset" : null; + var result = new DatabaseFileProvider(objDatabase, mountPath); + + gameBuilder.AddDbFileProvider(result); + } + + return gameBuilder; + } + + public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) + { + EffectCompilerBase compiler = new EffectCompiler(fileProvider) + { + SourceDirectories = { EffectCompilerBase.DefaultSourceShaderFolder }, + }; + + if(fileProvider is DatabaseFileProvider databaseFileProvider) + { + effectCompiler.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); + return effectCompiler; + } + + throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); + } + +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs new file mode 100644 index 0000000000..f658479a7b --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Core; +using Stride.Games; + +namespace Stride.Engine.Builder; +public interface IGameBuilder +{ + IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs new file mode 100644 index 0000000000..b13acc624b --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -0,0 +1,43 @@ +using System; +using Stride.Core.Serialization; +using Stride.Core.Streaming; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Engine.Builder; +public class MinimalGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public MinimalGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Context.RequestedWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Context.RequestedHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs b/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs index a012e43d9d..7bfd6fab92 100644 --- a/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs +++ b/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs @@ -1,12 +1,10 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; using Stride.Core; using Stride.Core.Mathematics; using Stride.Core.Serialization.Contents; using Stride.Data; -using Stride.Graphics; namespace Stride.Engine.Design { diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9fd977372d..97df14822d 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -59,7 +59,7 @@ public abstract class GameBase : ComponentBase, IGame private bool isMouseVisible; - internal object TickLock = new object(); + internal object TickLock = new(); #endregion @@ -402,7 +402,7 @@ internal void InitializeBeforeRun() /// /// The window Context for this game. /// Cannot run this instance while it is already running - public void Run(GameContext gameContext = null) + public virtual void Run(GameContext gameContext = null) { if (IsRunning) { diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 86cfab0220..90c47f779f 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - internal GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index c8da0cf304..6456ee6927 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -4,7 +4,6 @@ using Stride.Core; using Stride.Core.Serialization.Contents; -using Stride.Games.Time; using Stride.Graphics; namespace Stride.Games diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs new file mode 100644 index 0000000000..1b599d454c --- /dev/null +++ b/sources/engine/Stride.Hosting/BasicGame.cs @@ -0,0 +1,42 @@ +using System; +using Stride.Core.Serialization; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Hosting; +public class BasicGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public BasicGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs new file mode 100644 index 0000000000..3326ba14fb --- /dev/null +++ b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Hosting; +public interface IStrideGameBuilder +{ + public IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj new file mode 100644 index 0000000000..dbf6858a2e --- /dev/null +++ b/sources/engine/Stride.Hosting/Stride.Hosting.csproj @@ -0,0 +1,28 @@ + + + + true + + + + true + true + * + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs new file mode 100644 index 0000000000..0ba4f91eda --- /dev/null +++ b/sources/engine/Stride.Hosting/StrideGameBuilder.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Games; +using Stride.Core; + +namespace Stride.Hosting; +public class StrideGameBuilder : IStrideGameBuilder +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal StrideGameBuilder() + { + Game = new BasicGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static StrideGameBuilder Create() + { + return new StrideGameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} From 2372862ca222c1dbab81b3b62b5b56389c49c329 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:02:01 -0600 Subject: [PATCH 02/92] reorganizing code to work with GameStudio --- .../MicrothreadLocalDatabases.cs | 7 +- .../IO/IDatabaseFileProviderService.cs | 4 +- .../Game/EntityHierarchyEditorGame.cs | 3 +- .../EditorGame/Game/EditorServiceGame.cs | 5 + .../Stride.Editor/Engine/EmbeddedGame.cs | 3 +- .../Preview/GameStudioPreviewService.cs | 2 +- .../Stride.Editor/Preview/PreviewGame.cs | 3 +- .../Engine/Builder/GameBuilder.cs | 16 +- .../Engine/Builder/GameBuilderExtensions.cs | 36 +++++ .../Engine/Builder/MinimalGame.cs | 38 ++++- sources/engine/Stride.Engine/Engine/Game.cs | 21 ++- .../Android/GamePlatformAndroid.cs | 2 +- .../Desktop/GamePlatformDesktop.cs | 2 +- sources/engine/Stride.Games/GameBase.cs | 147 ++++++++++++------ sources/engine/Stride.Games/GameContext.cs | 10 +- sources/engine/Stride.Games/GamePlatform.cs | 38 +++-- .../Stride.Games/GraphicsDeviceManager.cs | 3 +- sources/engine/Stride.Games/IGame.cs | 4 + sources/engine/Stride.Games/IGamePlatform.cs | 3 + .../WindowsStore/GamePlatformUWP.cs | 4 +- .../Stride.Games/iOS/GamePlatformiOS.cs | 2 +- sources/engine/Stride.Input/InputManager.cs | 3 +- 22 files changed, 262 insertions(+), 94 deletions(-) diff --git a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs index 8c892bea0e..1a99c7f97f 100644 --- a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs +++ b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs @@ -113,6 +113,11 @@ private static DatabaseFileProvider CreateDatabase(BuildTransaction transaction) private class MicroThreadLocalProviderService : IDatabaseFileProviderService { - public DatabaseFileProvider FileProvider => MicroThreadLocalDatabaseFileProvider.Value; + public DatabaseFileProvider FileProvider + { + get => MicroThreadLocalDatabaseFileProvider.Value; + set => MicroThreadLocalDatabaseFileProvider.Value = value; + //throw new InvalidOperationException($"Can not change the value of a {nameof(MicroThreadLocalProviderService.FileProvider)}"); + } } } diff --git a/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs b/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs index 93c36db2f8..7d251cd2c2 100644 --- a/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs +++ b/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs @@ -5,5 +5,5 @@ namespace Stride.Core.IO; public interface IDatabaseFileProviderService { - DatabaseFileProvider FileProvider { get; } -} \ No newline at end of file + DatabaseFileProvider FileProvider { get; set; } +} diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs index 589ceaeccb..b0059ad35d 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs @@ -48,7 +48,8 @@ public abstract class EntityHierarchyEditorGame : EditorServiceGame private Material fallbackColorMaterial; private Material fallbackTextureMaterial; - protected EntityHierarchyEditorGame(TaskCompletionSource gameContentLoadedTaskSource, IEffectCompiler effectCompiler, string effectLogPath) + protected EntityHierarchyEditorGame(TaskCompletionSource gameContentLoadedTaskSource, IEffectCompiler effectCompiler, string effectLogPath, GameContext context = null) + : base(context) { this.gameContentLoadedTaskSource = gameContentLoadedTaskSource; this.effectCompiler = effectCompiler; diff --git a/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs b/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs index bd04fdc2b0..25a80860c5 100644 --- a/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs +++ b/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs @@ -99,6 +99,11 @@ public bool IsEditorHidden public event EventHandler ExceptionThrown; + public EditorServiceGame(GameContext context) : base(context) + { + + } + /// /// Calculates and returns the position of the mouse in the scene. /// diff --git a/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs b/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs index 5eab6d24fc..66d262c9c3 100644 --- a/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs +++ b/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs @@ -3,6 +3,7 @@ using Stride.Core.Diagnostics; using Stride.Engine; +using Stride.Games; using Stride.Graphics; namespace Stride.Editor.Engine @@ -17,7 +18,7 @@ public class EmbeddedGame : Game /// public static bool DebugMode { get; set; } - public EmbeddedGame() + public EmbeddedGame(GameContext context) : base(context) { GraphicsDeviceManager.PreferredGraphicsProfile = new [] { GraphicsProfile.Level_11_0, GraphicsProfile.Level_10_1, GraphicsProfile.Level_10_0 }; GraphicsDeviceManager.PreferredBackBufferWidth = 64; diff --git a/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs b/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs index 522b71f911..99047e09fa 100644 --- a/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs +++ b/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs @@ -137,8 +137,8 @@ private void StrideUIThread() initializationSignal.Set(); - PreviewGame = new PreviewGame(AssetBuilderService.EffectCompiler); var context = new GameContextWinforms(gameForm) { InitializeDatabase = false }; + PreviewGame = new PreviewGame(AssetBuilderService.EffectCompiler, context); // Wait for shaders to be loaded AssetBuilderService.WaitForShaders(); diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index c88ac25032..143ab1c307 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -14,6 +14,7 @@ using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; +using Stride.Games; namespace Stride.Editor.Preview { @@ -43,7 +44,7 @@ public class PreviewGame : EditorGame.Game.EditorServiceGame private Scene previewScene; - public PreviewGame(IEffectCompiler effectCompiler) + public PreviewGame(IEffectCompiler effectCompiler, GameContext context) : base(context) { this.effectCompiler = effectCompiler; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index dd5a1b202d..28001c7729 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -9,7 +9,7 @@ namespace Stride.Engine.Builder; /// Helps build the game and preps it to be able to run after built. /// /// -public class GameBuilder : IGameBuilder where T : IGame +public class GameBuilder : IGameBuilder { public IServiceRegistry Services { get; protected set; } @@ -21,14 +21,14 @@ public class GameBuilder : IGameBuilder where T : IGame internal GameBuilder() { - Game = new MinimalGame(); + Game = new MinimalGame(null); Services = Game.Services; GameSystems = Game.GameSystems; } - public static GameBuilder Create() + public static GameBuilder Create() { - return new GameBuilder(); + return new GameBuilder(); } public virtual GameBase Build() @@ -41,11 +41,3 @@ public virtual GameBase Build() return Game; } } - -/// -/// Creates a default GameBuilder for a . -/// -public class GameBuilder : GameBuilder -{ - -} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index ead167468a..ba96b7864a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,6 +1,8 @@ using System; +using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; +using Stride.Core.Serialization.Contents; using Stride.Core.Storage; using Stride.Games; using Stride.Rendering; @@ -27,6 +29,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + /// + /// Allows the user to add a custom database file provider to the game. + /// + /// + /// + /// public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. @@ -36,6 +44,11 @@ public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, Data return gameBuilder; } + /// + /// Creates a default database to be used in the game. + /// + /// + /// public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) { using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) @@ -53,6 +66,22 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) return gameBuilder; } + public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services; + var content = new ContentManager(services); + services.AddService(content); + services.AddService(content); + return gameBuilder; + } + + /// + /// Adds a default effect compiler to the game. This is used to compile shaders and effects. + /// + /// + /// + /// + /// public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) { EffectCompilerBase compiler = new EffectCompiler(fileProvider) @@ -69,4 +98,11 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); } + public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + + return gameBuilder; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index b13acc624b..8042319f43 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,6 +1,7 @@ using System; +using Stride.Core.Diagnostics; using Stride.Core.Serialization; -using Stride.Core.Streaming; +using Stride.Core.Serialization.Contents; using Stride.Games; using Stride.Graphics; @@ -14,10 +15,25 @@ public class MinimalGame : GameBase /// The graphics device manager. public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - public MinimalGame() + public MinimalGame(GameContext gameContext) : base() { + Context = gameContext ?? DetectDefaultContext(); + Context.CurrentGame = this; + + // Create Platform + Context.GamePlatform = GamePlatform.Create(Context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + // Setup registry + Services.AddService(this); + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } @@ -40,4 +56,20 @@ protected override void Initialize() Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); } + + protected override void PrepareContext() + { + //Allow the user to add their own ContentManager + var contentManager = Services.GetService(); + + if (contentManager is null) + { + Log.Info("No ContentManager found, creating default ContentManager"); + contentManager = new ContentManager(Services); + Services.AddService(contentManager); + Services.AddService(contentManager); + } + + Content = contentManager; + } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 6c4c162ed5..7e06b1ba2d 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -188,8 +188,23 @@ public LogMessageType ConsoleLogLevel /// /// Initializes a new instance of the class. /// - public Game() + public Game(GameContext context = null) : base() { + Context = context ?? DetectDefaultContext(); + Context.CurrentGame = this; + + // Create Platform + Context.GamePlatform = GamePlatform.Create(Context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + // Setup registry + Services.AddService(this); + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + // Register the logger backend before anything else logListener = GetLogListener(); @@ -227,7 +242,7 @@ public Game() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, context); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); @@ -256,7 +271,7 @@ protected override void PrepareContext() if (Context.InitializeDatabase) { databaseFileProvider = InitializeAssetDatabase(); - ((DatabaseFileProviderService)Services.GetService()).FileProvider = databaseFileProvider; + Services.GetService().FileProvider = databaseFileProvider; var renderingSettings = new RenderingSettings(); if (Content.Exists(GameSettings.AssetUrl)) diff --git a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs index 167afa863d..5db252837c 100644 --- a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs +++ b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs @@ -28,7 +28,7 @@ private void PopulateFullName() FullName = $"{manufacturer} - {model}"; } - public GamePlatformAndroid(GameBase game) : base(game) + public GamePlatformAndroid(GameContext context) : base(context) { PopulateFullName(); } diff --git a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs index 7d48fae49e..c3911ba734 100644 --- a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs +++ b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs @@ -29,7 +29,7 @@ namespace Stride.Games { internal class GamePlatformDesktop : GamePlatform { - public GamePlatformDesktop(GameBase game) : base(game) + public GamePlatformDesktop(GameContext context) : base(context) { IsBlockingRun = true; #if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 97df14822d..05de63e24d 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -41,7 +41,7 @@ public abstract class GameBase : ComponentBase, IGame { #region Fields - private readonly GamePlatform gamePlatform; + private GamePlatform gamePlatform => Context.GamePlatform; private IGraphicsDeviceService graphicsDeviceService; protected IGraphicsDeviceManager graphicsDeviceManager; private ResumeManager resumeManager; @@ -95,21 +95,23 @@ protected GameBase() GameSystems = new GameSystemCollection(Services); Services.AddService(GameSystems); - // Create Platform - gamePlatform = GamePlatform.Create(this); - gamePlatform.Activated += GamePlatform_Activated; - gamePlatform.Deactivated += GamePlatform_Deactivated; - gamePlatform.Exiting += GamePlatform_Exiting; - gamePlatform.WindowCreated += GamePlatformOnWindowCreated; - - // Setup registry - Services.AddService(this); - Services.AddService(gamePlatform); - Services.AddService(gamePlatform); - IsActive = true; } + protected static GameContext DetectDefaultContext() + { +#if STRIDE_PLATFORM_UWP + return GameContextFactory.NewGameContextUWPXaml(); +#elif STRIDE_PLATFORM_ANDROID + return GameContextFactory.NewGameContextAndroid(); +#elif STRIDE_PLATFORM_IOS + return GameContextFactory.NewGameContextiOS(); +#else + // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... + return GameContextFactory.NewGameContextDesktop(); +#endif + } + #endregion #region Public Events @@ -165,7 +167,7 @@ protected GameBase() /// /// Gets the . /// - public ContentManager Content { get; private set; } + public ContentManager Content { get; protected set; } /// /// Gets the game components registered by this game. @@ -177,15 +179,15 @@ protected GameBase() /// Gets the game context. /// /// The game context. - public GameContext Context { get; private set; } + public GameContext Context { get; protected set; } /// /// Gets the graphics device. /// /// The graphics device. - public GraphicsDevice GraphicsDevice { get; private set; } + public GraphicsDevice GraphicsDevice { get; protected set; } - public GraphicsContext GraphicsContext { get; private set; } + public GraphicsContext GraphicsContext { get; protected set; } /// /// Gets or sets the time between each when is false. @@ -197,13 +199,13 @@ protected GameBase() /// Gets a value indicating whether this instance is active. /// /// true if this instance is active; otherwise, false. - public bool IsActive { get; private set; } + public bool IsActive { get; protected set; } /// /// Gets a value indicating whether this instance is exiting. /// /// true if this instance is exiting; otherwise, false. - public bool IsExiting{ get; private set; } + public bool IsExiting{ get; protected set; } /// /// Gets or sets a value indicating whether the elapsed time between each update should be constant, @@ -295,6 +297,7 @@ public bool IsMouseVisible /// Gets the abstract window. /// /// The window. + [Obsolete("Use GameContext.GameWindow instead.")] public GameWindow Window { get @@ -416,22 +419,40 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } + if(gameContext != null) + { + gameContext.GamePlatform = Context.GamePlatform; + Context = gameContext; + Context.CurrentGame = this; + + // Overwrite Platform + if (gamePlatform != null) + { + Context.GamePlatform.Activated -= GamePlatform_Activated; + Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; + Context.GamePlatform.Exiting -= GamePlatform_Exiting; + Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; + + Services.RemoveService(); + Services.RemoveService(); + } + + Context.GamePlatform = GamePlatform.Create(gameContext); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + } + // Gets the GameWindow Context - if (gameContext == null) + EnsureGameContextIsSet(); + if(gameContext is null) { - AppContextType c; - if (OperatingSystem.IsWindows()) - c = AppContextType.Desktop; - else if (OperatingSystem.IsAndroid()) - c = AppContextType.Android; - else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) - c = AppContextType.iOS; - else - c = AppContextType.DesktopSDL; - gameContext = GameContextFactory.NewGameContext(c); + throw new InvalidOperationException("No GameContext found"); } - - Context = gameContext; PrepareContext(); @@ -446,7 +467,7 @@ public virtual void Run(GameContext gameContext = null) Context.RequestedGraphicsProfile = graphicsDeviceManagerImpl.PreferredGraphicsProfile; Context.DeviceCreationFlags = graphicsDeviceManagerImpl.DeviceCreationFlags; - gamePlatform.Run(Context); + gamePlatform.Run(); if (gamePlatform.IsBlockingRun) { @@ -468,6 +489,28 @@ public virtual void Run(GameContext gameContext = null) } } + /// + /// Attempts to get GameContext based on the current platform. + /// + private void EnsureGameContextIsSet() + { + // Gets the GameWindow Context + if (Context == null) + { + AppContextType c; + if (OperatingSystem.IsWindows()) + c = AppContextType.Desktop; + else if (OperatingSystem.IsAndroid()) + c = AppContextType.Android; + else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) + c = AppContextType.iOS; + else + c = AppContextType.DesktopSDL; + + Context = GameContextFactory.NewGameContext(c); + } + } + /// /// Creates or updates before window and device are created. /// @@ -512,6 +555,26 @@ public void Tick() } } + public virtual void SetWindow(GameWindow window) + { + if (IsRunning) + { + throw new InvalidOperationException("Cannot set the game window while the game is running"); + } + + Context.GameWindow = window; + //Window = window; + } + + public virtual void SetGameContext(GameContext context) + { + if(IsRunning) + { + throw new InvalidOperationException("Cannot set the game context while the game is running"); + } + Context = context; + } + /// /// Calls automatically based on this game's setup, override it to implement your own system. /// @@ -586,7 +649,7 @@ protected virtual void RawTickProducer() RawTick(singleFrameElapsedTime, updateCount, drawLag / (float)TargetElapsedTime.Ticks, drawFrame); - var window = gamePlatform.MainWindow; + var window = Window; if (gamePlatform.IsBlockingRun) // throttle fps if Game.Tick() called from internal main loop { if (window.IsMinimized || window.Visible == false || (window.Focused == false && TreatNotFocusedLikeMinimized)) @@ -717,17 +780,13 @@ protected override void Destroy() for (int i = 0; i < array.Length; i++) { var disposable = array[i] as IDisposable; - if (disposable != null) - { - disposable.Dispose(); - } + disposable?.Dispose(); } // Reset graphics context GraphicsContext = null; - var disposableGraphicsManager = graphicsDeviceManager as IDisposable; - if (disposableGraphicsManager != null) + if (graphicsDeviceManager is IDisposable disposableGraphicsManager) { disposableGraphicsManager.Dispose(); } @@ -888,7 +947,7 @@ protected virtual void OnWindowCreated() WindowCreated?.Invoke(this, EventArgs.Empty); } - private void GamePlatformOnWindowCreated(object sender, EventArgs eventArgs) + protected void GamePlatformOnWindowCreated(object sender, EventArgs eventArgs) { Window.IsMouseVisible = isMouseVisible; OnWindowCreated(); @@ -912,7 +971,7 @@ protected virtual void UnloadContent() GameSystems.UnloadContent(); } - private void GamePlatform_Activated(object sender, EventArgs e) + protected void GamePlatform_Activated(object sender, EventArgs e) { if (!IsActive) { @@ -921,7 +980,7 @@ private void GamePlatform_Activated(object sender, EventArgs e) } } - private void GamePlatform_Deactivated(object sender, EventArgs e) + protected void GamePlatform_Deactivated(object sender, EventArgs e) { if (IsActive) { @@ -930,7 +989,7 @@ private void GamePlatform_Deactivated(object sender, EventArgs e) } } - private void GamePlatform_Exiting(object sender, EventArgs e) + protected void GamePlatform_Exiting(object sender, EventArgs e) { OnExiting(this, EventArgs.Empty); } diff --git a/sources/engine/Stride.Games/GameContext.cs b/sources/engine/Stride.Games/GameContext.cs index 8e2338269e..4fd1a2bc8a 100644 --- a/sources/engine/Stride.Games/GameContext.cs +++ b/sources/engine/Stride.Games/GameContext.cs @@ -30,7 +30,7 @@ namespace Stride.Games { /// - /// Contains context used to render the game (Control for WinForm, a DrawingSurface for WP8...etc.). + /// Contains context for the game and its core modules. /// public abstract class GameContext { @@ -56,6 +56,14 @@ public abstract class GameContext /// The run loop. public Action ExitCallback { get; internal set; } + public GameBase CurrentGame { get; set; } + + public GamePlatform GamePlatform { get; set; } + + public GameWindow GameWindow { get; set; } + + public IServiceRegistry Services { get; set; } + // TODO: remove these requested values. /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index 36848ae436..c5eab1e0e9 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -30,35 +30,38 @@ namespace Stride.Games { - internal abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform + public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform { private bool hasExitRan = false; - protected readonly GameBase game; - protected readonly IServiceRegistry Services; - protected GameWindow gameWindow; + protected GameBase game => context.CurrentGame; + + protected GameWindow gameWindow => context.GameWindow; + + protected GameContext context; public string FullName { get; protected set; } = string.Empty; - protected GamePlatform(GameBase game) + protected GamePlatform(GameContext context) { - this.game = game; - Services = game.Services; + Services = context.Services; + this.context = context; + this.context.GamePlatform = this; } - public static GamePlatform Create(GameBase game) + public static GamePlatform Create(GameContext context) { #if STRIDE_PLATFORM_UWP - return new GamePlatformUWP(game); + return new GamePlatformUWP(context); #elif STRIDE_PLATFORM_ANDROID - return new GamePlatformAndroid(game); + return new GamePlatformAndroid(context); #elif STRIDE_PLATFORM_IOS - return new GamePlatformiOS(game); + return new GamePlatformiOS(context); #else // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... - return new GamePlatformDesktop(game); + return new GamePlatformDesktop(context); #endif } @@ -103,6 +106,7 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); + context.GameWindow = window; return window; } @@ -115,11 +119,11 @@ public virtual GameWindow CreateWindow(GameContext gameContext) /// public bool IsBlockingRun { get; protected set; } - public void Run(GameContext gameContext) + public void Run() { - IsBlockingRun = !gameContext.IsUserManagingRun; + IsBlockingRun = !context.IsUserManagingRun; - gameWindow = CreateWindow(gameContext); + context.GameWindow = CreateWindow(context); // Register on Activated gameWindow.Activated += OnActivated; @@ -293,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = MainWindow.NativeWindow, + DeviceWindowHandle = context.GameWindow.NativeWindow, ColorSpace = preferredParameters.ColorSpace, }, }; @@ -380,7 +384,7 @@ protected override void Destroy() if (gameWindow != null) { gameWindow.Dispose(); - gameWindow = null; + context.GameWindow = null; } Activated = null; diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 90c47f779f..00be755193 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game, GameContext context = null) { this.game = game; if (this.game == null) @@ -661,6 +661,7 @@ protected virtual GraphicsDeviceInformation FindBestDevice(bool anySuitableDevic preferredParameters.PreferredBackBufferHeight = resizedBackBufferHeight; } + graphicsDeviceFactory = game.Services.GetService(); var devices = graphicsDeviceFactory.FindBestDevices(preferredParameters); if (devices.Count == 0) { diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index 6456ee6927..8e55414ba2 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -139,5 +139,9 @@ public interface IGame /// /// The window. GameWindow Window { get; } + + public void SetWindow(GameWindow window); + + public void SetGameContext(GameContext context); } } diff --git a/sources/engine/Stride.Games/IGamePlatform.cs b/sources/engine/Stride.Games/IGamePlatform.cs index 9db9b9618f..ea4671c2dc 100644 --- a/sources/engine/Stride.Games/IGamePlatform.cs +++ b/sources/engine/Stride.Games/IGamePlatform.cs @@ -1,5 +1,7 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +using System; + namespace Stride.Games { /// @@ -17,6 +19,7 @@ public interface IGamePlatform /// Gets the main window. /// /// The main window. + [Obsolete("Use GameContext.MainWindow instead. This property will be removed in a future version.")] GameWindow MainWindow { get; } /// diff --git a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs index 466ac7fc17..87cfa1bbc7 100644 --- a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs +++ b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. // // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel @@ -32,7 +32,7 @@ namespace Stride.Games { internal class GamePlatformUWP : GamePlatform { - public GamePlatformUWP(GameBase game) : base(game) + public GamePlatformUWP(GameContext context) : base(context) { // Application lifecycle reference: // https://docs.microsoft.com/en-us/windows/uwp/launch-resume/app-lifecycle diff --git a/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs b/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs index 70f2c9ddbd..5ca80248c4 100644 --- a/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs +++ b/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs @@ -27,7 +27,7 @@ private unsafe void PopulateFullName() Marshal.FreeHGlobal(output); } - public GamePlatformiOS(GameBase game) : base(game) + public GamePlatformiOS(GameContext context) : base(context) { PopulateFullName(); } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 5b16714c14..7c91017ac3 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -704,7 +704,8 @@ private void AddSources() #endif break; default: - throw new InvalidOperationException("GameContext type is not supported by the InputManager"); + Logger.Warning("GameContext type is not supported by the InputManager. Register your own for input to be handled properly."); + break; } } From 2f7f21327132b73040b4aca938d642f32c27277d Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:17:34 -0600 Subject: [PATCH 03/92] clean up --- build/Stride.sln | 15 ------- sources/engine/Stride.Games/GameBase.cs | 4 +- sources/engine/Stride.Hosting/BasicGame.cs | 42 ------------------- .../Stride.Hosting/IStrideGameBuilder.cs | 16 ------- .../Stride.Hosting/Stride.Hosting.csproj | 28 ------------- .../Stride.Hosting/StrideGameBuilder.cs | 39 ----------------- 6 files changed, 2 insertions(+), 142 deletions(-) delete mode 100644 sources/engine/Stride.Hosting/BasicGame.cs delete mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs delete mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj delete mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/build/Stride.sln b/build/Stride.sln index 969e630fb4..65dbc5b24f 100644 --- a/build/Stride.sln +++ b/build/Stride.sln @@ -338,8 +338,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\so EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Tests", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Tests\Stride.BepuPhysics.Tests.csproj", "{7B70C783-4085-4702-B3C6-6570FD85CB8F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stride.Hosting", "..\sources\engine\Stride.Hosting\Stride.Hosting.csproj", "{A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1525,18 +1523,6 @@ Global {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.ActiveCfg = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.Build.0 = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.ActiveCfg = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.Build.0 = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.Build.0 = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.ActiveCfg = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1666,7 +1652,6 @@ Global {7715D094-DF59-4D91-BC9A-9A5118039ECB} = {DE048114-9AE4-467E-A879-188DC0D88A59} {66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C} {7B70C783-4085-4702-B3C6-6570FD85CB8F} = {DE048114-9AE4-467E-A879-188DC0D88A59} - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715} = {4C142567-C42B-40F5-B092-798882190209} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2} diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 05de63e24d..9531bf2332 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -419,7 +419,7 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } - if(gameContext != null) + if(Context is not null && gameContext is not null) { gameContext.GamePlatform = Context.GamePlatform; Context = gameContext; @@ -449,7 +449,7 @@ public virtual void Run(GameContext gameContext = null) // Gets the GameWindow Context EnsureGameContextIsSet(); - if(gameContext is null) + if(Context is null) { throw new InvalidOperationException("No GameContext found"); } diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs deleted file mode 100644 index 1b599d454c..0000000000 --- a/sources/engine/Stride.Hosting/BasicGame.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Stride.Core.Serialization; -using Stride.Games; -using Stride.Graphics; - -namespace Stride.Hosting; -public class BasicGame : GameBase -{ - - /// - /// Gets the graphics device manager. - /// - /// The graphics device manager. - public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - - public BasicGame() - { - // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); - Services.AddService(GraphicsDeviceManager); - Services.AddService(GraphicsDeviceManager); - } - - public override void ConfirmRenderingSettings(bool gameCreation) - { - var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; - - if (gameCreation) - { - //if our device width or height is actually smaller then requested we use the device one - deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); - deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); - } - } - - protected override void Initialize() - { - base.Initialize(); - - Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); - } -} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs deleted file mode 100644 index 3326ba14fb..0000000000 --- a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Games; - -namespace Stride.Hosting; -public interface IStrideGameBuilder -{ - public IServiceRegistry Services { get; } - - GameSystemCollection GameSystems { get; } - - List LogListeners { get; } - - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj deleted file mode 100644 index dbf6858a2e..0000000000 --- a/sources/engine/Stride.Hosting/Stride.Hosting.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - true - - - - true - true - * - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs deleted file mode 100644 index 0ba4f91eda..0000000000 --- a/sources/engine/Stride.Hosting/StrideGameBuilder.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using Stride.Core.Diagnostics; -using Stride.Games; -using Stride.Core; - -namespace Stride.Hosting; -public class StrideGameBuilder : IStrideGameBuilder -{ - public IServiceRegistry Services { get; protected set; } - - public GameSystemCollection GameSystems { get; protected set; } - - public List LogListeners { get; protected set; } = []; - - public GameBase Game { get; protected set; } - - internal StrideGameBuilder() - { - Game = new BasicGame(); - Services = Game.Services; - GameSystems = Game.GameSystems; - } - - public static StrideGameBuilder Create() - { - return new StrideGameBuilder(); - } - - public virtual GameBase Build() - { - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - - return Game; - } -} From 5e82aa1415c843bd6f07e1d26d171391de5f0915 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sat, 10 May 2025 14:06:08 -0600 Subject: [PATCH 04/92] fixing input issues --- .../Engine/Builder/GameBuilderExtensions.cs | 25 +++++- .../Engine/Builder/MinimalGame.cs | 17 +++- sources/engine/Stride.Engine/Engine/Game.cs | 48 ++++++++++- sources/engine/Stride.Games/GameBase.cs | 80 +++++++++---------- sources/engine/Stride.Games/GamePlatform.cs | 4 +- .../Stride.Games/GraphicsDeviceManager.cs | 12 +-- sources/engine/Stride.Games/IGame.cs | 6 +- sources/engine/Stride.Input/InputManager.cs | 7 +- .../engine/Stride.Input/SDL/InputSourceSDL.cs | 2 +- .../Windows/InputSourceWinforms.cs | 2 +- 10 files changed, 137 insertions(+), 66 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index ba96b7864a..0b45d86da8 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,10 +1,10 @@ using System; -using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; using Stride.Games; +using Stride.Input; using Stride.Rendering; using Stride.Shaders.Compiler; @@ -29,6 +29,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + return gameBuilder; + } + /// /// Allows the user to add a custom database file provider to the game. /// @@ -39,8 +45,7 @@ public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, Data { // Gets initialized by the GameBase constructor. var dataBase = gameBuilder.Services.GetService(); - // There should probably be a change to the interface to avoid the below casting. - ((DatabaseFileProviderService)dataBase).FileProvider = provider; + dataBase.FileProvider = provider; return gameBuilder; } @@ -105,4 +110,18 @@ public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameCon return gameBuilder; } + public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) + { + var inputManager = gameBuilder.Services.GetService(); + + if (inputManager == null) + { + throw new InvalidOperationException("InputManager is not registered in the service registry."); + } + + inputManager.Sources.Add(inputSource); + + return gameBuilder; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 8042319f43..62e77076ea 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -4,8 +4,13 @@ using Stride.Core.Serialization.Contents; using Stride.Games; using Stride.Graphics; +using Stride.Input; namespace Stride.Engine.Builder; + +/// +/// A game class with no registered systems by default. +/// public class MinimalGame : GameBase { @@ -17,7 +22,7 @@ public class MinimalGame : GameBase public MinimalGame(GameContext gameContext) : base() { - Context = gameContext ?? DetectDefaultContext(); + Context = gameContext ?? GetDefaultContext(); Context.CurrentGame = this; // Create Platform @@ -33,7 +38,7 @@ public MinimalGame(GameContext gameContext) : base() Services.AddService(Context.GamePlatform); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } @@ -55,6 +60,14 @@ protected override void Initialize() base.Initialize(); Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + + // Add window specific input source + var inputManager = Services.GetService(); + if (inputManager is not null) + { + var windowInputSource = InputSourceFactory.NewWindowInputSource(Context); + inputManager.Sources.Add(windowInputSource); + } } protected override void PrepareContext() diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7e06b1ba2d..0094175372 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -190,7 +190,7 @@ public LogMessageType ConsoleLogLevel /// public Game(GameContext context = null) : base() { - Context = context ?? DetectDefaultContext(); + Context = context ?? GetDefaultContext(); Context.CurrentGame = this; // Create Platform @@ -242,7 +242,7 @@ public Game(GameContext context = null) : base() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, context); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); @@ -357,6 +357,7 @@ protected override void Initialize() Input = inputSystem.Manager; Services.AddService(Input); GameSystems.Add(inputSystem); + SetInitialInputSources(Input); // Initialize the systems base.Initialize(); @@ -408,6 +409,49 @@ protected override void Initialize() OnGameStarted(this); } + private void SetInitialInputSources(InputManager inputManager) + { + // Add window specific input source + var windowInputSource = InputSourceFactory.NewWindowInputSource(Context); + inputManager.Sources.Add(windowInputSource); + + // Add platform specific input sources + switch (Context.ContextType) + { +#if STRIDE_UI_SDL + case AppContextType.DesktopSDL: + break; +#endif +#if STRIDE_PLATFORM_ANDROID + case AppContextType.Android: + break; +#endif +#if STRIDE_PLATFORM_IOS + case AppContextType.iOS: + break; +#endif +#if STRIDE_PLATFORM_UWP + case AppContextType.UWPXaml: + case AppContextType.UWPCoreWindow: + break; +#endif + case AppContextType.Desktop: +#if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) + inputManager.Sources.Add(new InputSourceWindowsDirectInput()); + if (InputSourceWindowsXInput.IsSupported()) + inputManager.Sources.Add(new InputSourceWindowsXInput()); +#if STRIDE_INPUT_RAWINPUT + if (rawInputEnabled && context is GameContextWinforms gameContextWinforms) + inputManager.Sources.Add(new InputSourceWindowsRawInput(gameContextWinforms.Control)); +#endif +#endif + break; + default: + Log.Warning("GameContext type is not supported by the InputManager. Register your own for input to be handled properly."); + break; + } + } + internal static DatabaseFileProvider InitializeAssetDatabase() { using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9531bf2332..9cb2262684 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -98,7 +98,7 @@ protected GameBase() IsActive = true; } - protected static GameContext DetectDefaultContext() + protected static GameContext GetDefaultContext() { #if STRIDE_PLATFORM_UWP return GameContextFactory.NewGameContextUWPXaml(); @@ -302,9 +302,9 @@ public GameWindow Window { get { - if (gamePlatform != null) + if (Context != null) { - return gamePlatform.MainWindow; + return Context.GameWindow; } return null; } @@ -419,35 +419,7 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } - if(Context is not null && gameContext is not null) - { - gameContext.GamePlatform = Context.GamePlatform; - Context = gameContext; - Context.CurrentGame = this; - - // Overwrite Platform - if (gamePlatform != null) - { - Context.GamePlatform.Activated -= GamePlatform_Activated; - Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; - Context.GamePlatform.Exiting -= GamePlatform_Exiting; - Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; - - Services.RemoveService(); - Services.RemoveService(); - } - - Context.GamePlatform = GamePlatform.Create(gameContext); - Context.GamePlatform.Activated += GamePlatform_Activated; - Context.GamePlatform.Deactivated += GamePlatform_Deactivated; - Context.GamePlatform.Exiting += GamePlatform_Exiting; - Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; - - Services.AddService(Context.GamePlatform); - Services.AddService(Context.GamePlatform); - } - - // Gets the GameWindow Context + SetGameContext(gameContext); EnsureGameContextIsSet(); if(Context is null) { @@ -494,7 +466,7 @@ public virtual void Run(GameContext gameContext = null) /// private void EnsureGameContextIsSet() { - // Gets the GameWindow Context + // Gets the Game Context if (Context == null) { AppContextType c; @@ -555,24 +527,44 @@ public void Tick() } } - public virtual void SetWindow(GameWindow window) + public virtual void SetGameContext(GameContext context) { - if (IsRunning) + if(IsRunning) { - throw new InvalidOperationException("Cannot set the game window while the game is running"); + throw new InvalidOperationException("Cannot set the game context while the game is running"); } - Context.GameWindow = window; - //Window = window; - } + if (Context is not null && context is not null) + { + context.GamePlatform = Context.GamePlatform; + Context = context; + Context.CurrentGame = this; - public virtual void SetGameContext(GameContext context) - { - if(IsRunning) + // Overwrite Platform + if (gamePlatform != null) + { + Context.GamePlatform.Activated -= GamePlatform_Activated; + Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; + Context.GamePlatform.Exiting -= GamePlatform_Exiting; + Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; + + Services.RemoveService(); + Services.RemoveService(); + } + + Context.GamePlatform = GamePlatform.Create(context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + } + else if (context is not null) { - throw new InvalidOperationException("Cannot set the game context while the game is running"); + Context = context; } - Context = context; } /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index c5eab1e0e9..d6fa19874d 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -106,7 +106,6 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); - context.GameWindow = window; return window; } @@ -123,7 +122,8 @@ public void Run() { IsBlockingRun = !context.IsUserManagingRun; - context.GameWindow = CreateWindow(context); + // Create the game window if not already created manually + context.GameWindow ??= CreateWindow(context); // Register on Activated gameWindow.Activated += OnActivated; diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 00be755193..08cd2404b4 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -49,7 +49,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra private readonly object lockDeviceCreation; - private GameBase game; + private readonly GameBase game; private bool deviceSettingsChanged; @@ -100,12 +100,12 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game, GameContext context = null) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) { - throw new ArgumentNullException("game"); + throw new ArgumentNullException(nameof(game)); } lockDeviceCreation = new object(); @@ -119,8 +119,8 @@ public GraphicsDeviceManager(GameBase game, GameContext context = null) preferredBackBufferHeight = DefaultBackBufferHeight; preferredRefreshRate = new Rational(60, 1); PreferredMultisampleCount = MultisampleCount.None; - PreferredGraphicsProfile = new[] - { + PreferredGraphicsProfile = + [ GraphicsProfile.Level_11_1, GraphicsProfile.Level_11_0, GraphicsProfile.Level_10_1, @@ -128,7 +128,7 @@ public GraphicsDeviceManager(GameBase game, GameContext context = null) GraphicsProfile.Level_9_3, GraphicsProfile.Level_9_2, GraphicsProfile.Level_9_1, - }; + ]; graphicsDeviceFactory = game.Services.GetService(); if (graphicsDeviceFactory == null) diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index 8e55414ba2..5788899fcd 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -140,8 +140,10 @@ public interface IGame /// The window. GameWindow Window { get; } - public void SetWindow(GameWindow window); - + /// + /// Sets the game context. + /// + /// public void SetGameContext(GameContext context); } } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 7c91017ac3..7793f87679 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -318,7 +318,7 @@ public void Initialize(GameContext gameContext) { this.gameContext = gameContext ?? throw new ArgumentNullException(nameof(gameContext)); - AddSources(); + //AddSources(); // After adding initial devices, reassign gamepad id's // this creates a beter index assignment in the case where you have both an xbox controller and another controller at startup @@ -626,14 +626,15 @@ public void PoolInputEvent(InputEvent inputEvent) { eventRouters[inputEvent.GetType()].PoolEvent(inputEvent); } - + /// /// Resets the collection back to it's default values /// + [Obsolete] public void ResetSources() { Sources.Clear(); - AddSources(); + //AddSources(); } /// diff --git a/sources/engine/Stride.Input/SDL/InputSourceSDL.cs b/sources/engine/Stride.Input/SDL/InputSourceSDL.cs index 7b33c0afb0..328cb58cad 100644 --- a/sources/engine/Stride.Input/SDL/InputSourceSDL.cs +++ b/sources/engine/Stride.Input/SDL/InputSourceSDL.cs @@ -14,7 +14,7 @@ namespace Stride.Input /// /// Provides support for mouse/touch/keyboard/gamepads using SDL /// - internal unsafe class InputSourceSDL : InputSourceBase + public unsafe class InputSourceSDL : InputSourceBase { private static Sdl SDL = Window.SDL; diff --git a/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs b/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs index b46764d109..cbfca61bfa 100644 --- a/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs +++ b/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs @@ -18,7 +18,7 @@ namespace Stride.Input /// /// Provides support for mouse and keyboard input on windows forms /// - internal class InputSourceWinforms : InputSourceBase + public class InputSourceWinforms : InputSourceBase { private readonly HashSet heldKeys = new HashSet(); private readonly List keysToRelease = new List(); From 7136214315a59f3e151abd8e49b87582f2606565 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 11 May 2025 20:17:18 -0600 Subject: [PATCH 05/92] Separated input --- sources/Directory.Packages.props | 4 +- sources/core/Stride.Core/IServiceRegistry.cs | 9 +++ sources/core/Stride.Core/ServiceRegistry.cs | 16 ++++ .../Engine/Builder/GameBuilder.cs | 76 +++++++++++++++++-- .../Engine/Builder/GameBuilderExtensions.cs | 49 ++++++++---- .../Engine/Builder/IGameBuilder.cs | 15 +++- .../Engine/Builder/MinimalGame.cs | 18 ++++- .../Engine/Hosting/IStrideBuilder.cs | 16 ++++ .../Engine/Hosting/StrideBuilder.cs | 52 +++++++++++++ .../engine/Stride.Engine/Stride.Engine.csproj | 2 + 10 files changed, 233 insertions(+), 24 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 633d58c70b..12076223f2 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -12,6 +12,7 @@ + @@ -45,6 +46,7 @@ + @@ -146,4 +148,4 @@ - \ No newline at end of file + diff --git a/sources/core/Stride.Core/IServiceRegistry.cs b/sources/core/Stride.Core/IServiceRegistry.cs index c2b564561a..9f25c94df1 100644 --- a/sources/core/Stride.Core/IServiceRegistry.cs +++ b/sources/core/Stride.Core/IServiceRegistry.cs @@ -47,6 +47,15 @@ public interface IServiceRegistry /// Thrown when a service of the same type is already registered. void AddService(T service) where T : class; + /// + /// Adds a service to this . + /// + /// The service to add. + /// The type to register as. + /// Thrown when the provided service is null. + /// Thrown when a service of the same type is already registered. + void AddService(object service, Type type); + /// /// Gets the service object of the specified type. /// diff --git a/sources/core/Stride.Core/ServiceRegistry.cs b/sources/core/Stride.Core/ServiceRegistry.cs index 09b7543516..ca5dcede37 100644 --- a/sources/core/Stride.Core/ServiceRegistry.cs +++ b/sources/core/Stride.Core/ServiceRegistry.cs @@ -76,6 +76,22 @@ public void AddService(T service) OnServiceAdded(new ServiceEventArgs(type, service)); } + /// + /// + /// This implementation triggers the event after a service is successfully added. + /// + public void AddService(object service, Type type) + { + ArgumentNullException.ThrowIfNull(service); + + lock (registeredService) + { + if (!registeredService.TryAdd(type, service)) + throw new ArgumentException("Service is already registered with this type", nameof(type)); + } + OnServiceAdded(new ServiceEventArgs(type, service)); + } + /// /// /// This implementation triggers the event after a service is successfully removed. diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 28001c7729..82affae29c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,7 +1,12 @@ +using System; using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; +using Stride.Core.IO; using Stride.Games; +using Stride.Input; namespace Stride.Engine.Builder; @@ -11,19 +16,28 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { - public IServiceRegistry Services { get; protected set; } + public Dictionary Services { get; internal set; } = []; - public GameSystemCollection GameSystems { get; protected set; } + public IServiceCollection DiServices { get; internal set; } = new ServiceCollection(); - public List LogListeners { get; protected set; } = []; + public GameSystemCollection GameSystems { get; internal set; } - public GameBase Game { get; protected set; } + public List LogListeners { get; internal set; } = []; + + public List InputSources { get; internal set; } = []; + + public DatabaseFileProvider DatabaseFileProvider { get; set; } + + public GameBase Game { get; set; } + + public GameContext Context { get; set; } internal GameBuilder() { Game = new MinimalGame(null); - Services = Game.Services; GameSystems = Game.GameSystems; + DiServices.AddSingleton(Game.Services); + Services.Add(typeof(IServiceRegistry), Game.Services); } public static GameBuilder Create() @@ -33,11 +47,63 @@ public static GameBuilder Create() public virtual GameBase Build() { + var provider = DiServices.BuildServiceProvider(); + foreach (var service in Services) + { + if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) + continue; + + try + { + if (service.Value == null) + { + var instance = provider.GetService(service.Key); + Game.Services.AddService(instance, service.Key); + Services[service.Key] = instance; + } + else + { + Game.Services.AddService(service.Value, service.Key); + } + } + catch (Exception ex) + { + // TODO: check if service is already registered first. + } + } + + // Add all game systems to the game. + foreach (var service in Services) + { + var system = provider.GetService(service.Key); + if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) + { + Game.GameSystems.Add(gameSystem); + } + } + foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } + if (Context != null) + { + Game.SetGameContext(Context); + } + + if(InputSources.Count > 0) + { + var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + foreach (var inputSource in InputSources) + { + inputManager.Sources.Add(inputSource); + } + } + + var dataBase = Game.Services.GetService(); + dataBase.FileProvider = DatabaseFileProvider; + return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 0b45d86da8..83b0d1af70 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,12 +1,20 @@ using System; +using Microsoft.Extensions.DependencyInjection; +using Stride.Audio; +using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; +using Stride.Engine.Processors; using Stride.Games; using Stride.Input; +using Stride.Profiling; using Stride.Rendering; +using Stride.Rendering.Fonts; +using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; +using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions @@ -19,7 +27,15 @@ public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gam public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { - gameBuilder.Services.AddService(service); + gameBuilder.Services.Add(typeof(T), service); + gameBuilder.DiServices.AddSingleton(service); + return gameBuilder; + } + + public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class + { + gameBuilder.Services.Add(typeof(T), null); + gameBuilder.DiServices.AddSingleton(); return gameBuilder; } @@ -29,6 +45,20 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + + var inputSystem = new InputSystem(services); + + gameBuilder + .AddGameSystem(inputSystem) + .AddService(inputSystem) + .AddService(inputSystem.Manager); + + return gameBuilder; + } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); @@ -44,8 +74,7 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. - var dataBase = gameBuilder.Services.GetService(); - dataBase.FileProvider = provider; + gameBuilder.DatabaseFileProvider = provider; return gameBuilder; } @@ -73,7 +102,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services; + var services = gameBuilder.Game.Services; var content = new ContentManager(services); services.AddService(content); services.AddService(content); @@ -106,22 +135,12 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); - return gameBuilder; } public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) { - var inputManager = gameBuilder.Services.GetService(); - - if (inputManager == null) - { - throw new InvalidOperationException("InputManager is not registered in the service registry."); - } - - inputManager.Sources.Add(inputSource); - + gameBuilder.InputSources.Add(inputSource); return gameBuilder; } - } diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index f658479a7b..9bb6a0060a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -1,16 +1,27 @@ using System.Collections.Generic; using Stride.Core.Diagnostics; -using Stride.Core; using Stride.Games; +using System; +using Microsoft.Extensions.DependencyInjection; +using Stride.Input; +using Stride.Core.IO; namespace Stride.Engine.Builder; public interface IGameBuilder { - IServiceRegistry Services { get; } + Dictionary Services { get; } + + IServiceCollection DiServices { get; } GameSystemCollection GameSystems { get; } List LogListeners { get; } + List InputSources { get; } + + DatabaseFileProvider DatabaseFileProvider { get; set; } + GameBase Game { get; } + + GameContext Context { get; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 62e77076ea..ec51270191 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,4 +1,7 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; using Stride.Core.Diagnostics; using Stride.Core.Serialization; using Stride.Core.Serialization.Contents; @@ -11,7 +14,7 @@ namespace Stride.Engine.Builder; /// /// A game class with no registered systems by default. /// -public class MinimalGame : GameBase +public class MinimalGame : GameBase, IHostedService { /// @@ -85,4 +88,17 @@ protected override void PrepareContext() Content = contentManager; } + + public Task StartAsync(CancellationToken cancellationToken = default) + { + Run(); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken = default) + { + Exit(); + return Task.CompletedTask; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs new file mode 100644 index 0000000000..9de0f50191 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public interface IStrideBuilder : IHostBuilder +{ + /// + /// Gets the game context. + /// + GameContext Context { get; } + /// + /// Gets the game. + /// + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs new file mode 100644 index 0000000000..f6bffe3367 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public class StrideBuilder : IStrideBuilder +{ + public GameContext Context { get; set; } + + public GameBase Game { get; set; } + + public IDictionary Properties { get; set; } + + public IHost Build() + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureContainer(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureServices(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } +} diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 7bded5b689..234f39796f 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -26,8 +26,10 @@ + + From aa3c9fe1dac7f023215a4262d475b6c1fb7627fa Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Mon, 12 May 2025 15:47:29 -0600 Subject: [PATCH 06/92] clean up and docs --- .../Engine/Builder/GameBuilder.cs | 16 +++- .../Engine/Builder/GameBuilderExtensions.cs | 87 ++++++++++++++----- .../Engine/Builder/IGameBuilder.cs | 4 +- .../Engine/Hosting/IStrideBuilder.cs | 16 ---- .../Engine/Hosting/StrideBuilder.cs | 52 ----------- 5 files changed, 82 insertions(+), 93 deletions(-) delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 82affae29c..af4d652806 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; @@ -58,6 +57,21 @@ public virtual GameBase Build() if (service.Value == null) { var instance = provider.GetService(service.Key); + + if(instance == null) + { + //check if the type is inherited from another instance in the services. + foreach (var kvp in Services) + { + if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) + { + instance = provider.GetService(kvp.Key); + if(instance is not null) + break; + } + } + } + Game.Services.AddService(instance, service.Key); Services[service.Key] = instance; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 83b0d1af70..2a1fe0d064 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,30 +1,39 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Stride.Audio; using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; -using Stride.Engine.Processors; using Stride.Games; using Stride.Input; -using Stride.Profiling; using Stride.Rendering; -using Stride.Rendering.Fonts; -using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; -using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions { + + /// + /// Adds cire systems to the game. Does not register the systems into the + /// + /// + /// + /// + /// public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gameSystem) where T : IGameSystemBase { gameBuilder.GameSystems.Add(gameSystem); return gameBuilder; } + /// + /// Registers a service into the . + /// + /// + /// + /// + /// public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { gameBuilder.Services.Add(typeof(T), service); @@ -32,6 +41,12 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder, T servic return gameBuilder; } + /// + /// Registers a service into the . + /// + /// + /// + /// public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class { gameBuilder.Services.Add(typeof(T), null); @@ -39,13 +54,41 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T return gameBuilder; } + /// + /// Registers a service and its interface into the . + /// + /// + /// + /// + /// + public static IGameBuilder AddService(this IGameBuilder gameBuilder) where TClass : class, TInterface where TInterface : class + { + // This is a work around to allow DI to work the same way as the ServiceRegistry expects. + // Without registering both the interface and the class, the DI will not be able to resolve the interface on build. + gameBuilder.Services.Add(typeof(TInterface), null); + gameBuilder.Services.Add(typeof(TClass), null); + gameBuilder.DiServices.AddSingleton(); + return gameBuilder; + } + + /// + /// Adds a log listener to the game. This is used thoughout Stride systems for logging events. + /// + /// + /// + /// public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogListener logListener) { gameBuilder.LogListeners.Add(logListener); return gameBuilder; } - public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + /// + /// Adds the Stride input system to the game with no sources. + /// + /// + /// + public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; @@ -61,17 +104,17 @@ public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { - gameBuilder.Game.SetGameContext(context); + gameBuilder.Context = context; return gameBuilder; } /// - /// Allows the user to add a custom database file provider to the game. + /// Add a custom database file provider to the game. /// /// /// /// - public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) + public static IGameBuilder SetDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. gameBuilder.DatabaseFileProvider = provider; @@ -94,7 +137,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) var mountPath = VirtualFileSystem.ResolveProviderUnsafe("/asset", true).Provider == null ? "/asset" : null; var result = new DatabaseFileProvider(objDatabase, mountPath); - gameBuilder.AddDbFileProvider(result); + gameBuilder.SetDbFileProvider(result); } return gameBuilder; @@ -112,11 +155,11 @@ public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilde /// /// Adds a default effect compiler to the game. This is used to compile shaders and effects. /// - /// + /// /// /// /// - public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) + public static EffectSystem CreateDefaultEffectCompiler(this EffectSystem effectSystem, IVirtualFileProvider fileProvider) { EffectCompilerBase compiler = new EffectCompiler(fileProvider) { @@ -125,20 +168,20 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp if(fileProvider is DatabaseFileProvider databaseFileProvider) { - effectCompiler.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); - return effectCompiler; + effectSystem.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); + return effectSystem; } throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); } - public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) - { - gameBuilder.Game.SetGameContext(context); - return gameBuilder; - } - - public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) + /// + /// Adds an input source to the game. This requires the Stride input system to be used. + /// + /// + /// + /// + public static IGameBuilder AddStrideInputSource(this IGameBuilder gameBuilder, IInputSource inputSource) { gameBuilder.InputSources.Add(inputSource); return gameBuilder; diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index 9bb6a0060a..7b1d916455 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -21,7 +21,7 @@ public interface IGameBuilder DatabaseFileProvider DatabaseFileProvider { get; set; } - GameBase Game { get; } + GameBase Game { get; set; } - GameContext Context { get; } + GameContext Context { get; set; } } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs deleted file mode 100644 index 9de0f50191..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public interface IStrideBuilder : IHostBuilder -{ - /// - /// Gets the game context. - /// - GameContext Context { get; } - /// - /// Gets the game. - /// - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs deleted file mode 100644 index f6bffe3367..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public class StrideBuilder : IStrideBuilder -{ - public GameContext Context { get; set; } - - public GameBase Game { get; set; } - - public IDictionary Properties { get; set; } - - public IHost Build() - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureContainer(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureServices(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } -} From 257c4589ede6ce30b94355f4f7213e7cd812d511 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 14:53:08 -0600 Subject: [PATCH 07/92] Kryptos feedback --- sources/Directory.Packages.props | 4 +--- sources/editor/Stride.Editor/Preview/PreviewGame.cs | 10 +++++----- sources/engine/Stride.Input/InputManager.cs | 6 ++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 12076223f2..f289648c35 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,9 +11,7 @@ - - - + diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index 143ab1c307..b7a5a8c9f1 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -2,19 +2,19 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Threading.Tasks; -using Stride.Core.BuildEngine; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Core.Mathematics; using Stride.Assets; using Stride.Assets.SpriteFont; using Stride.Assets.SpriteFont.Compiler; +using Stride.Core; +using Stride.Core.BuildEngine; +using Stride.Core.Diagnostics; +using Stride.Core.Mathematics; using Stride.Engine; using Stride.Engine.Design; +using Stride.Games; using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; -using Stride.Games; namespace Stride.Editor.Preview { diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 7793f87679..eb9e1d788c 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -318,8 +318,6 @@ public void Initialize(GameContext gameContext) { this.gameContext = gameContext ?? throw new ArgumentNullException(nameof(gameContext)); - //AddSources(); - // After adding initial devices, reassign gamepad id's // this creates a beter index assignment in the case where you have both an xbox controller and another controller at startup var sortedGamePads = GamePads.OrderBy(x => x.CanChangeIndex); @@ -630,11 +628,11 @@ public void PoolInputEvent(InputEvent inputEvent) /// /// Resets the collection back to it's default values /// - [Obsolete] + [Obsolete("This should be managed manually instead by using the Sources collection")] public void ResetSources() { Sources.Clear(); - //AddSources(); + AddSources(); } /// From e83810a6d1876da56cfe4318e77b01315705b1c6 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 15:10:04 -0600 Subject: [PATCH 08/92] missed some duplicate packages --- sources/Directory.Packages.props | 3 +-- sources/engine/Stride.Engine/Stride.Engine.csproj | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index f289648c35..6368b59dc8 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,7 +11,7 @@ - + @@ -44,7 +44,6 @@ - diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 234f39796f..7836b61cf4 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -29,7 +29,6 @@ - From 18397c542e215dbf2c59ae383b0df5272cf33818 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 18:16:47 -0600 Subject: [PATCH 09/92] add option for DI in GameFontSystem --- .../engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs b/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs index 0db5f3866f..570f6895b3 100644 --- a/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs +++ b/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs @@ -15,11 +15,11 @@ public class GameFontSystem : GameSystemBase { public FontSystem FontSystem { get; private set; } - public GameFontSystem(IServiceRegistry registry) + public GameFontSystem(IServiceRegistry registry, FontSystem fontSystem = null) : base(registry) { Visible = true; - FontSystem = new FontSystem(); + FontSystem = fontSystem ?? new FontSystem(); } public override void Draw(GameTime gameTime) From 2588b5fd969c7a265cd873d48ada25edd9903d92 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 19:37:36 -0600 Subject: [PATCH 10/92] Fix error caused by StreamingManager DI. --- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 14 ++++++++------ sources/engine/Stride.Engine/Engine/Game.cs | 3 +++ .../Stride.Rendering/Streaming/StreamingManager.cs | 5 ++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index af4d652806..c3b6cbc3ec 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -46,6 +46,12 @@ public static GameBuilder Create() public virtual GameBase Build() { + + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + var provider = DiServices.BuildServiceProvider(); foreach (var service in Services) { @@ -82,7 +88,8 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first. + // TODO: check if service is already registered first.' + GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -96,11 +103,6 @@ public virtual GameBase Build() } } - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - if (Context != null) { Game.SetGameContext(Context); diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 0094175372..dbaaab9489 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,10 +11,12 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; +using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; +using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; @@ -220,6 +222,7 @@ public Game(GameContext context = null) : base() Services.AddService(SceneSystem); Streaming = new StreamingManager(Services); + Services.AddService(Streaming); Audio = new AudioSystem(Services); Services.AddService(Audio); diff --git a/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs b/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs index 394c791ec6..21ca774303 100644 --- a/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs +++ b/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs @@ -92,9 +92,8 @@ public class StreamingManager : GameSystemBase, IStreamingManager, ITexturesStre public StreamingManager([NotNull] IServiceRegistry services) : base(services) { - services.AddService(this); - services.AddService(this); - services.AddService(this); + Services.AddService(this); + Services.AddService(this); ContentStreaming = new ContentStreamingService(); From f1f7b49b16185d3ad20319286861cb03838d6ce7 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:01:50 -0600 Subject: [PATCH 11/92] renaming to favour ServiceCollection --- .../Engine/Builder/GameBuilder.cs | 19 +++++++++---------- .../Engine/Builder/GameBuilderExtensions.cs | 16 ++++++++-------- .../Engine/Builder/IGameBuilder.cs | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index c3b6cbc3ec..092440c1bc 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,9 +15,9 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { - public Dictionary Services { get; internal set; } = []; + public Dictionary InternalServices { get; internal set; } = []; - public IServiceCollection DiServices { get; internal set; } = new ServiceCollection(); + public IServiceCollection Services { get; internal set; } = new ServiceCollection(); public GameSystemCollection GameSystems { get; internal set; } @@ -35,8 +35,8 @@ internal GameBuilder() { Game = new MinimalGame(null); GameSystems = Game.GameSystems; - DiServices.AddSingleton(Game.Services); - Services.Add(typeof(IServiceRegistry), Game.Services); + Services.AddSingleton(Game.Services); + InternalServices.Add(typeof(IServiceRegistry), Game.Services); } public static GameBuilder Create() @@ -46,14 +46,13 @@ public static GameBuilder Create() public virtual GameBase Build() { - foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } - var provider = DiServices.BuildServiceProvider(); - foreach (var service in Services) + var provider = Services.BuildServiceProvider(); + foreach (var service in InternalServices) { if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) continue; @@ -67,7 +66,7 @@ public virtual GameBase Build() if(instance == null) { //check if the type is inherited from another instance in the services. - foreach (var kvp in Services) + foreach (var kvp in InternalServices) { if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) { @@ -79,7 +78,7 @@ public virtual GameBase Build() } Game.Services.AddService(instance, service.Key); - Services[service.Key] = instance; + InternalServices[service.Key] = instance; } else { @@ -94,7 +93,7 @@ public virtual GameBase Build() } // Add all game systems to the game. - foreach (var service in Services) + foreach (var service in InternalServices) { var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 2a1fe0d064..702d8f1912 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -36,8 +36,8 @@ public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gam /// public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { - gameBuilder.Services.Add(typeof(T), service); - gameBuilder.DiServices.AddSingleton(service); + gameBuilder.InternalServices.Add(typeof(T), service); + gameBuilder.Services.AddSingleton(service); return gameBuilder; } @@ -49,8 +49,8 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder, T servic /// public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class { - gameBuilder.Services.Add(typeof(T), null); - gameBuilder.DiServices.AddSingleton(); + gameBuilder.InternalServices.Add(typeof(T), null); + gameBuilder.Services.AddSingleton(); return gameBuilder; } @@ -65,9 +65,9 @@ public static IGameBuilder AddService(this IGameBuilder game { // This is a work around to allow DI to work the same way as the ServiceRegistry expects. // Without registering both the interface and the class, the DI will not be able to resolve the interface on build. - gameBuilder.Services.Add(typeof(TInterface), null); - gameBuilder.Services.Add(typeof(TClass), null); - gameBuilder.DiServices.AddSingleton(); + gameBuilder.InternalServices.Add(typeof(TInterface), null); + gameBuilder.InternalServices.Add(typeof(TClass), null); + gameBuilder.Services.AddSingleton(); return gameBuilder; } @@ -90,7 +90,7 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList /// public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + var services = gameBuilder.InternalServices[typeof(IServiceRegistry)] as IServiceRegistry; var inputSystem = new InputSystem(services); diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index 7b1d916455..a56c041060 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -9,9 +9,9 @@ namespace Stride.Engine.Builder; public interface IGameBuilder { - Dictionary Services { get; } + Dictionary InternalServices { get; } - IServiceCollection DiServices { get; } + IServiceCollection Services { get; } GameSystemCollection GameSystems { get; } From 938a50cb2e63b39058032e235d891390ca2338fb Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:06:39 -0600 Subject: [PATCH 12/92] typo --- .../Stride.Engine/Engine/Builder/GameBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 702d8f1912..5e09032a5a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -15,7 +15,7 @@ public static class GameBuilderExtensions { /// - /// Adds cire systems to the game. Does not register the systems into the + /// Adds core systems to the game. Does not register the systems into the /// /// /// From c2de7f489b4fb0963abfa9754520890898533b26 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:43:14 -0600 Subject: [PATCH 13/92] docs --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 092440c1bc..fee0db5890 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,8 +15,14 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { + /// + /// This is used to allow the same instance to be registered multiple times as differenet interfaces or types. This was done due to how works."/> + /// public Dictionary InternalServices { get; internal set; } = []; + /// + /// This allows for Service to be registered through DI. + /// public IServiceCollection Services { get; internal set; } = new ServiceCollection(); public GameSystemCollection GameSystems { get; internal set; } From 3b26a456073a61252efd331daaf12150839a3a6a Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:53:31 -0600 Subject: [PATCH 14/92] docs --- .../Engine/Builder/GameBuilder.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index fee0db5890..ec4a2dd27e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -10,7 +10,7 @@ namespace Stride.Engine.Builder; /// -/// Helps build the game and preps it to be able to run after built. +/// Helps build the game and preps it to be able to run after . /// /// public class GameBuilder : IGameBuilder @@ -25,10 +25,19 @@ public class GameBuilder : IGameBuilder /// public IServiceCollection Services { get; internal set; } = new ServiceCollection(); + /// + /// This is a direct reference to the game systems collection of the game. + /// public GameSystemCollection GameSystems { get; internal set; } + /// + /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur."/> + /// public List LogListeners { get; internal set; } = []; + /// + /// Adds input sources to the game on . + /// public List InputSources { get; internal set; } = []; public DatabaseFileProvider DatabaseFileProvider { get; set; } @@ -37,17 +46,21 @@ public class GameBuilder : IGameBuilder public GameContext Context { get; set; } - internal GameBuilder() + internal GameBuilder(GameBase game) { - Game = new MinimalGame(null); + Game = game ?? new MinimalGame(null); GameSystems = Game.GameSystems; Services.AddSingleton(Game.Services); InternalServices.Add(typeof(IServiceRegistry), Game.Services); } - public static GameBuilder Create() + /// + /// Creates a new instance of the class. + /// + /// + public static GameBuilder Create(GameBase game = null) { - return new GameBuilder(); + return new GameBuilder(game); } public virtual GameBase Build() From 384dd48fae6c4e07394661db662b40f4165dccfb Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 12:42:05 -0600 Subject: [PATCH 15/92] clean up and build logging --- .../Engine/Builder/GameBuilder.cs | 27 ++++++++++++------- .../Engine/Builder/GameBuilderExtensions.cs | 4 ++- .../Engine/Builder/IGameBuilder.cs | 2 -- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index ec4a2dd27e..0e0fd4fa3c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; -using Stride.Core.IO; using Stride.Games; using Stride.Input; @@ -26,7 +25,7 @@ public class GameBuilder : IGameBuilder public IServiceCollection Services { get; internal set; } = new ServiceCollection(); /// - /// This is a direct reference to the game systems collection of the game. + /// This is a direct reference to the game systems collection of the . /// public GameSystemCollection GameSystems { get; internal set; } @@ -40,12 +39,12 @@ public class GameBuilder : IGameBuilder /// public List InputSources { get; internal set; } = []; - public DatabaseFileProvider DatabaseFileProvider { get; set; } - public GameBase Game { get; set; } public GameContext Context { get; set; } + private static Logger _log => GlobalLogger.GetLogger("GameBuilder"); + internal GameBuilder(GameBase game) { Game = game ?? new MinimalGame(null); @@ -96,18 +95,20 @@ public virtual GameBase Build() } } + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(instance, service.Key); InternalServices[service.Key] = instance; } else { + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(service.Value, service.Key); } } catch (Exception ex) { // TODO: check if service is already registered first.' - GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); + _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -117,27 +118,35 @@ public virtual GameBase Build() var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) { + _log.Info($"Adding game system {gameSystem.GetType().Name} to the game systems collection."); Game.GameSystems.Add(gameSystem); } } if (Context != null) { + _log.Info($"Setting game context."); Game.SetGameContext(Context); } if(InputSources.Count > 0) { - var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + var inputManager = Game.Services.GetService(); + + if (inputManager is null) + { + _log.Info("No InputManager found in the game services, creating default."); + inputManager = new InputManager(); + Game.Services.AddService(inputManager); + } + foreach (var inputSource in InputSources) { + _log.Info($"Adding input source {inputSource.GetType().Name} to the input manager."); inputManager.Sources.Add(inputSource); } } - var dataBase = Game.Services.GetService(); - dataBase.FileProvider = DatabaseFileProvider; - return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 5e09032a5a..200289b29c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -117,7 +117,9 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon public static IGameBuilder SetDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. - gameBuilder.DatabaseFileProvider = provider; + var fileProviderService = gameBuilder.Game.Services.GetService(); + + fileProviderService.FileProvider = provider; return gameBuilder; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index a56c041060..eba6f13b5b 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -19,8 +19,6 @@ public interface IGameBuilder List InputSources { get; } - DatabaseFileProvider DatabaseFileProvider { get; set; } - GameBase Game { get; set; } GameContext Context { get; set; } From ceaec0485b18b36b84767ebd28b6d7b345164f21 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 18:49:07 -0600 Subject: [PATCH 16/92] remove some hardcoded Game references --- .../Stride.Debugger/Debugger/LiveAssemblyReloader.cs | 11 ++++++----- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 4 ++-- sources/engine/Stride.Engine/Engine/Game.cs | 2 -- sources/engine/Stride.Engine/Engine/GameSystem.cs | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs b/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs index 67c314e85f..bb4d910626 100644 --- a/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs +++ b/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs @@ -1,29 +1,30 @@ -// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using Stride.Core; using Stride.Core.Reflection; -using Stride.Core.Serialization; using Stride.Core.Yaml; using Stride.Core.Yaml.Events; using Stride.Core.Yaml.Serialization; using Stride.Debugger.Target; using Stride.Engine; +using Stride.Games; namespace Stride.Debugger { public static class LiveAssemblyReloader { - public static void Reload(Game game, AssemblyContainer assemblyContainer, List assembliesToUnregister, List assembliesToRegister) + public static void Reload(GameBase game, AssemblyContainer assemblyContainer, List assembliesToUnregister, List assembliesToRegister) { List entities = new List(); + var sceneSystem = game.Services.GetSafeServiceAs(); + if (game != null) - entities.AddRange(game.SceneSystem.SceneInstance); + entities.AddRange(sceneSystem.SceneInstance); CloneReferenceSerializer.References = new List(); diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 0e0fd4fa3c..0469f99e15 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -107,7 +107,7 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first.' + // TODO: check if service is already registered first. _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -147,6 +147,6 @@ public virtual GameBase Build() } } - return Game; + return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index dbaaab9489..7064d566e6 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,12 +11,10 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; -using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; -using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; diff --git a/sources/engine/Stride.Engine/Engine/GameSystem.cs b/sources/engine/Stride.Engine/Engine/GameSystem.cs index 3ea3a8f9ec..545609b8c9 100644 --- a/sources/engine/Stride.Engine/Engine/GameSystem.cs +++ b/sources/engine/Stride.Engine/Engine/GameSystem.cs @@ -19,6 +19,6 @@ protected GameSystem(IServiceRegistry registry) : base(registry) /// /// The game. /// This value can be null - public new Game Game => (Game)base.Game; + public new GameBase Game => base.Game; } } From 8723abe05256e87e32bed9950ed3cc9ca7c95332 Mon Sep 17 00:00:00 2001 From: Donovan Prezeau Date: Thu, 8 May 2025 15:04:01 -0600 Subject: [PATCH 17/92] initial PoC --- build/Stride.sln | 15 ++++ sources/Directory.Packages.props | 4 +- .../Engine/Builder/GameBuilder.cs | 51 +++++++++++++ .../Engine/Builder/GameBuilderExtensions.cs | 72 +++++++++++++++++++ .../Engine/Builder/IGameBuilder.cs | 16 +++++ .../Engine/Builder/MinimalGame.cs | 43 +++++++++++ .../Engine/Design/GameSettings.cs | 2 - sources/engine/Stride.Games/GameBase.cs | 4 +- .../Stride.Games/GraphicsDeviceManager.cs | 2 +- sources/engine/Stride.Games/IGame.cs | 1 - sources/engine/Stride.Hosting/BasicGame.cs | 42 +++++++++++ .../Stride.Hosting/IStrideGameBuilder.cs | 16 +++++ .../Stride.Hosting/Stride.Hosting.csproj | 28 ++++++++ .../Stride.Hosting/StrideGameBuilder.cs | 39 ++++++++++ 14 files changed, 328 insertions(+), 7 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs create mode 100644 sources/engine/Stride.Hosting/BasicGame.cs create mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs create mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj create mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/build/Stride.sln b/build/Stride.sln index c7060e2b2c..6283779106 100644 --- a/build/Stride.sln +++ b/build/Stride.sln @@ -338,6 +338,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\so EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Tests", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Tests\Stride.BepuPhysics.Tests.csproj", "{7B70C783-4085-4702-B3C6-6570FD85CB8F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stride.Hosting", "..\sources\engine\Stride.Hosting\Stride.Hosting.csproj", "{A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1523,6 +1525,18 @@ Global {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.ActiveCfg = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.Build.0 = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.ActiveCfg = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.Build.0 = Debug|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.Build.0 = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.ActiveCfg = Release|Any CPU + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1651,6 +1665,7 @@ Global {7715D094-DF59-4D91-BC9A-9A5118039ECB} = {DE048114-9AE4-467E-A879-188DC0D88A59} {66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C} {7B70C783-4085-4702-B3C6-6570FD85CB8F} = {DE048114-9AE4-467E-A879-188DC0D88A59} + {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715} = {4C142567-C42B-40F5-B092-798882190209} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2} diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 28607e25a4..633d58c70b 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,6 +11,8 @@ + + @@ -144,4 +146,4 @@ - + \ No newline at end of file diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs new file mode 100644 index 0000000000..dd5a1b202d --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Engine.Builder; + +/// +/// Helps build the game and preps it to be able to run after built. +/// +/// +public class GameBuilder : IGameBuilder where T : IGame +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal GameBuilder() + { + Game = new MinimalGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static GameBuilder Create() + { + return new GameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} + +/// +/// Creates a default GameBuilder for a . +/// +public class GameBuilder : GameBuilder +{ + +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs new file mode 100644 index 0000000000..ead167468a --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -0,0 +1,72 @@ +using System; +using Stride.Core.Diagnostics; +using Stride.Core.IO; +using Stride.Core.Storage; +using Stride.Games; +using Stride.Rendering; +using Stride.Shaders.Compiler; + +namespace Stride.Engine.Builder; +public static class GameBuilderExtensions +{ + public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gameSystem) where T : IGameSystemBase + { + gameBuilder.GameSystems.Add(gameSystem); + return gameBuilder; + } + + public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class + { + gameBuilder.Services.AddService(service); + return gameBuilder; + } + + public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogListener logListener) + { + gameBuilder.LogListeners.Add(logListener); + return gameBuilder; + } + + public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) + { + // Gets initialized by the GameBase constructor. + var dataBase = gameBuilder.Services.GetService(); + // There should probably be a change to the interface to avoid the below casting. + ((DatabaseFileProviderService)dataBase).FileProvider = provider; + return gameBuilder; + } + + public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) + { + using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) + { + // Create and mount database file system + var objDatabase = ObjectDatabase.CreateDefaultDatabase(); + + // Only set a mount path if not mounted already + var mountPath = VirtualFileSystem.ResolveProviderUnsafe("/asset", true).Provider == null ? "/asset" : null; + var result = new DatabaseFileProvider(objDatabase, mountPath); + + gameBuilder.AddDbFileProvider(result); + } + + return gameBuilder; + } + + public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) + { + EffectCompilerBase compiler = new EffectCompiler(fileProvider) + { + SourceDirectories = { EffectCompilerBase.DefaultSourceShaderFolder }, + }; + + if(fileProvider is DatabaseFileProvider databaseFileProvider) + { + effectCompiler.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); + return effectCompiler; + } + + throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); + } + +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs new file mode 100644 index 0000000000..f658479a7b --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Core; +using Stride.Games; + +namespace Stride.Engine.Builder; +public interface IGameBuilder +{ + IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs new file mode 100644 index 0000000000..b13acc624b --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -0,0 +1,43 @@ +using System; +using Stride.Core.Serialization; +using Stride.Core.Streaming; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Engine.Builder; +public class MinimalGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public MinimalGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Context.RequestedWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Context.RequestedHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs b/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs index a012e43d9d..7bfd6fab92 100644 --- a/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs +++ b/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs @@ -1,12 +1,10 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; using Stride.Core; using Stride.Core.Mathematics; using Stride.Core.Serialization.Contents; using Stride.Data; -using Stride.Graphics; namespace Stride.Engine.Design { diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9fd977372d..97df14822d 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -59,7 +59,7 @@ public abstract class GameBase : ComponentBase, IGame private bool isMouseVisible; - internal object TickLock = new object(); + internal object TickLock = new(); #endregion @@ -402,7 +402,7 @@ internal void InitializeBeforeRun() /// /// The window Context for this game. /// Cannot run this instance while it is already running - public void Run(GameContext gameContext = null) + public virtual void Run(GameContext gameContext = null) { if (IsRunning) { diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 86cfab0220..90c47f779f 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - internal GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index c8da0cf304..6456ee6927 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -4,7 +4,6 @@ using Stride.Core; using Stride.Core.Serialization.Contents; -using Stride.Games.Time; using Stride.Graphics; namespace Stride.Games diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs new file mode 100644 index 0000000000..1b599d454c --- /dev/null +++ b/sources/engine/Stride.Hosting/BasicGame.cs @@ -0,0 +1,42 @@ +using System; +using Stride.Core.Serialization; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Hosting; +public class BasicGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public BasicGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs new file mode 100644 index 0000000000..3326ba14fb --- /dev/null +++ b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Hosting; +public interface IStrideGameBuilder +{ + public IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj new file mode 100644 index 0000000000..dbf6858a2e --- /dev/null +++ b/sources/engine/Stride.Hosting/Stride.Hosting.csproj @@ -0,0 +1,28 @@ + + + + true + + + + true + true + * + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs new file mode 100644 index 0000000000..0ba4f91eda --- /dev/null +++ b/sources/engine/Stride.Hosting/StrideGameBuilder.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Games; +using Stride.Core; + +namespace Stride.Hosting; +public class StrideGameBuilder : IStrideGameBuilder +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal StrideGameBuilder() + { + Game = new BasicGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static StrideGameBuilder Create() + { + return new StrideGameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} From 7590a43a41f344aceb54016f60b46139724b73aa Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:02:01 -0600 Subject: [PATCH 18/92] reorganizing code to work with GameStudio --- .../MicrothreadLocalDatabases.cs | 7 +- .../IO/IDatabaseFileProviderService.cs | 4 +- .../Game/EntityHierarchyEditorGame.cs | 3 +- .../EditorGame/Game/EditorServiceGame.cs | 5 + .../Stride.Editor/Engine/EmbeddedGame.cs | 3 +- .../Preview/GameStudioPreviewService.cs | 2 +- .../Stride.Editor/Preview/PreviewGame.cs | 3 +- .../Engine/Builder/GameBuilder.cs | 16 +- .../Engine/Builder/GameBuilderExtensions.cs | 36 +++++ .../Engine/Builder/MinimalGame.cs | 38 ++++- sources/engine/Stride.Engine/Engine/Game.cs | 21 ++- .../Android/GamePlatformAndroid.cs | 2 +- .../Desktop/GamePlatformDesktop.cs | 2 +- sources/engine/Stride.Games/GameBase.cs | 147 ++++++++++++------ sources/engine/Stride.Games/GameContext.cs | 10 +- sources/engine/Stride.Games/GamePlatform.cs | 38 +++-- .../Stride.Games/GraphicsDeviceManager.cs | 3 +- sources/engine/Stride.Games/IGame.cs | 4 + sources/engine/Stride.Games/IGamePlatform.cs | 3 + .../WindowsStore/GamePlatformUWP.cs | 4 +- .../Stride.Games/iOS/GamePlatformiOS.cs | 2 +- sources/engine/Stride.Input/InputManager.cs | 3 +- 22 files changed, 262 insertions(+), 94 deletions(-) diff --git a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs index 8c892bea0e..1a99c7f97f 100644 --- a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs +++ b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs @@ -113,6 +113,11 @@ private static DatabaseFileProvider CreateDatabase(BuildTransaction transaction) private class MicroThreadLocalProviderService : IDatabaseFileProviderService { - public DatabaseFileProvider FileProvider => MicroThreadLocalDatabaseFileProvider.Value; + public DatabaseFileProvider FileProvider + { + get => MicroThreadLocalDatabaseFileProvider.Value; + set => MicroThreadLocalDatabaseFileProvider.Value = value; + //throw new InvalidOperationException($"Can not change the value of a {nameof(MicroThreadLocalProviderService.FileProvider)}"); + } } } diff --git a/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs b/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs index 93c36db2f8..7d251cd2c2 100644 --- a/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs +++ b/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs @@ -5,5 +5,5 @@ namespace Stride.Core.IO; public interface IDatabaseFileProviderService { - DatabaseFileProvider FileProvider { get; } -} \ No newline at end of file + DatabaseFileProvider FileProvider { get; set; } +} diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs index 589ceaeccb..b0059ad35d 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs @@ -48,7 +48,8 @@ public abstract class EntityHierarchyEditorGame : EditorServiceGame private Material fallbackColorMaterial; private Material fallbackTextureMaterial; - protected EntityHierarchyEditorGame(TaskCompletionSource gameContentLoadedTaskSource, IEffectCompiler effectCompiler, string effectLogPath) + protected EntityHierarchyEditorGame(TaskCompletionSource gameContentLoadedTaskSource, IEffectCompiler effectCompiler, string effectLogPath, GameContext context = null) + : base(context) { this.gameContentLoadedTaskSource = gameContentLoadedTaskSource; this.effectCompiler = effectCompiler; diff --git a/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs b/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs index bd04fdc2b0..25a80860c5 100644 --- a/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs +++ b/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs @@ -99,6 +99,11 @@ public bool IsEditorHidden public event EventHandler ExceptionThrown; + public EditorServiceGame(GameContext context) : base(context) + { + + } + /// /// Calculates and returns the position of the mouse in the scene. /// diff --git a/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs b/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs index 5eab6d24fc..66d262c9c3 100644 --- a/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs +++ b/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs @@ -3,6 +3,7 @@ using Stride.Core.Diagnostics; using Stride.Engine; +using Stride.Games; using Stride.Graphics; namespace Stride.Editor.Engine @@ -17,7 +18,7 @@ public class EmbeddedGame : Game /// public static bool DebugMode { get; set; } - public EmbeddedGame() + public EmbeddedGame(GameContext context) : base(context) { GraphicsDeviceManager.PreferredGraphicsProfile = new [] { GraphicsProfile.Level_11_0, GraphicsProfile.Level_10_1, GraphicsProfile.Level_10_0 }; GraphicsDeviceManager.PreferredBackBufferWidth = 64; diff --git a/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs b/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs index 522b71f911..99047e09fa 100644 --- a/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs +++ b/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs @@ -137,8 +137,8 @@ private void StrideUIThread() initializationSignal.Set(); - PreviewGame = new PreviewGame(AssetBuilderService.EffectCompiler); var context = new GameContextWinforms(gameForm) { InitializeDatabase = false }; + PreviewGame = new PreviewGame(AssetBuilderService.EffectCompiler, context); // Wait for shaders to be loaded AssetBuilderService.WaitForShaders(); diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index c88ac25032..143ab1c307 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -14,6 +14,7 @@ using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; +using Stride.Games; namespace Stride.Editor.Preview { @@ -43,7 +44,7 @@ public class PreviewGame : EditorGame.Game.EditorServiceGame private Scene previewScene; - public PreviewGame(IEffectCompiler effectCompiler) + public PreviewGame(IEffectCompiler effectCompiler, GameContext context) : base(context) { this.effectCompiler = effectCompiler; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index dd5a1b202d..28001c7729 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -9,7 +9,7 @@ namespace Stride.Engine.Builder; /// Helps build the game and preps it to be able to run after built. /// /// -public class GameBuilder : IGameBuilder where T : IGame +public class GameBuilder : IGameBuilder { public IServiceRegistry Services { get; protected set; } @@ -21,14 +21,14 @@ public class GameBuilder : IGameBuilder where T : IGame internal GameBuilder() { - Game = new MinimalGame(); + Game = new MinimalGame(null); Services = Game.Services; GameSystems = Game.GameSystems; } - public static GameBuilder Create() + public static GameBuilder Create() { - return new GameBuilder(); + return new GameBuilder(); } public virtual GameBase Build() @@ -41,11 +41,3 @@ public virtual GameBase Build() return Game; } } - -/// -/// Creates a default GameBuilder for a . -/// -public class GameBuilder : GameBuilder -{ - -} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index ead167468a..ba96b7864a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,6 +1,8 @@ using System; +using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; +using Stride.Core.Serialization.Contents; using Stride.Core.Storage; using Stride.Games; using Stride.Rendering; @@ -27,6 +29,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + /// + /// Allows the user to add a custom database file provider to the game. + /// + /// + /// + /// public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. @@ -36,6 +44,11 @@ public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, Data return gameBuilder; } + /// + /// Creates a default database to be used in the game. + /// + /// + /// public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) { using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) @@ -53,6 +66,22 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) return gameBuilder; } + public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services; + var content = new ContentManager(services); + services.AddService(content); + services.AddService(content); + return gameBuilder; + } + + /// + /// Adds a default effect compiler to the game. This is used to compile shaders and effects. + /// + /// + /// + /// + /// public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) { EffectCompilerBase compiler = new EffectCompiler(fileProvider) @@ -69,4 +98,11 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); } + public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + + return gameBuilder; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index b13acc624b..8042319f43 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,6 +1,7 @@ using System; +using Stride.Core.Diagnostics; using Stride.Core.Serialization; -using Stride.Core.Streaming; +using Stride.Core.Serialization.Contents; using Stride.Games; using Stride.Graphics; @@ -14,10 +15,25 @@ public class MinimalGame : GameBase /// The graphics device manager. public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - public MinimalGame() + public MinimalGame(GameContext gameContext) : base() { + Context = gameContext ?? DetectDefaultContext(); + Context.CurrentGame = this; + + // Create Platform + Context.GamePlatform = GamePlatform.Create(Context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + // Setup registry + Services.AddService(this); + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } @@ -40,4 +56,20 @@ protected override void Initialize() Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); } + + protected override void PrepareContext() + { + //Allow the user to add their own ContentManager + var contentManager = Services.GetService(); + + if (contentManager is null) + { + Log.Info("No ContentManager found, creating default ContentManager"); + contentManager = new ContentManager(Services); + Services.AddService(contentManager); + Services.AddService(contentManager); + } + + Content = contentManager; + } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 6c4c162ed5..7e06b1ba2d 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -188,8 +188,23 @@ public LogMessageType ConsoleLogLevel /// /// Initializes a new instance of the class. /// - public Game() + public Game(GameContext context = null) : base() { + Context = context ?? DetectDefaultContext(); + Context.CurrentGame = this; + + // Create Platform + Context.GamePlatform = GamePlatform.Create(Context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + // Setup registry + Services.AddService(this); + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + // Register the logger backend before anything else logListener = GetLogListener(); @@ -227,7 +242,7 @@ public Game() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, context); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); @@ -256,7 +271,7 @@ protected override void PrepareContext() if (Context.InitializeDatabase) { databaseFileProvider = InitializeAssetDatabase(); - ((DatabaseFileProviderService)Services.GetService()).FileProvider = databaseFileProvider; + Services.GetService().FileProvider = databaseFileProvider; var renderingSettings = new RenderingSettings(); if (Content.Exists(GameSettings.AssetUrl)) diff --git a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs index 167afa863d..5db252837c 100644 --- a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs +++ b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs @@ -28,7 +28,7 @@ private void PopulateFullName() FullName = $"{manufacturer} - {model}"; } - public GamePlatformAndroid(GameBase game) : base(game) + public GamePlatformAndroid(GameContext context) : base(context) { PopulateFullName(); } diff --git a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs index 7d48fae49e..c3911ba734 100644 --- a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs +++ b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs @@ -29,7 +29,7 @@ namespace Stride.Games { internal class GamePlatformDesktop : GamePlatform { - public GamePlatformDesktop(GameBase game) : base(game) + public GamePlatformDesktop(GameContext context) : base(context) { IsBlockingRun = true; #if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 97df14822d..05de63e24d 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -41,7 +41,7 @@ public abstract class GameBase : ComponentBase, IGame { #region Fields - private readonly GamePlatform gamePlatform; + private GamePlatform gamePlatform => Context.GamePlatform; private IGraphicsDeviceService graphicsDeviceService; protected IGraphicsDeviceManager graphicsDeviceManager; private ResumeManager resumeManager; @@ -95,21 +95,23 @@ protected GameBase() GameSystems = new GameSystemCollection(Services); Services.AddService(GameSystems); - // Create Platform - gamePlatform = GamePlatform.Create(this); - gamePlatform.Activated += GamePlatform_Activated; - gamePlatform.Deactivated += GamePlatform_Deactivated; - gamePlatform.Exiting += GamePlatform_Exiting; - gamePlatform.WindowCreated += GamePlatformOnWindowCreated; - - // Setup registry - Services.AddService(this); - Services.AddService(gamePlatform); - Services.AddService(gamePlatform); - IsActive = true; } + protected static GameContext DetectDefaultContext() + { +#if STRIDE_PLATFORM_UWP + return GameContextFactory.NewGameContextUWPXaml(); +#elif STRIDE_PLATFORM_ANDROID + return GameContextFactory.NewGameContextAndroid(); +#elif STRIDE_PLATFORM_IOS + return GameContextFactory.NewGameContextiOS(); +#else + // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... + return GameContextFactory.NewGameContextDesktop(); +#endif + } + #endregion #region Public Events @@ -165,7 +167,7 @@ protected GameBase() /// /// Gets the . /// - public ContentManager Content { get; private set; } + public ContentManager Content { get; protected set; } /// /// Gets the game components registered by this game. @@ -177,15 +179,15 @@ protected GameBase() /// Gets the game context. /// /// The game context. - public GameContext Context { get; private set; } + public GameContext Context { get; protected set; } /// /// Gets the graphics device. /// /// The graphics device. - public GraphicsDevice GraphicsDevice { get; private set; } + public GraphicsDevice GraphicsDevice { get; protected set; } - public GraphicsContext GraphicsContext { get; private set; } + public GraphicsContext GraphicsContext { get; protected set; } /// /// Gets or sets the time between each when is false. @@ -197,13 +199,13 @@ protected GameBase() /// Gets a value indicating whether this instance is active. /// /// true if this instance is active; otherwise, false. - public bool IsActive { get; private set; } + public bool IsActive { get; protected set; } /// /// Gets a value indicating whether this instance is exiting. /// /// true if this instance is exiting; otherwise, false. - public bool IsExiting{ get; private set; } + public bool IsExiting{ get; protected set; } /// /// Gets or sets a value indicating whether the elapsed time between each update should be constant, @@ -295,6 +297,7 @@ public bool IsMouseVisible /// Gets the abstract window. /// /// The window. + [Obsolete("Use GameContext.GameWindow instead.")] public GameWindow Window { get @@ -416,22 +419,40 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } + if(gameContext != null) + { + gameContext.GamePlatform = Context.GamePlatform; + Context = gameContext; + Context.CurrentGame = this; + + // Overwrite Platform + if (gamePlatform != null) + { + Context.GamePlatform.Activated -= GamePlatform_Activated; + Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; + Context.GamePlatform.Exiting -= GamePlatform_Exiting; + Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; + + Services.RemoveService(); + Services.RemoveService(); + } + + Context.GamePlatform = GamePlatform.Create(gameContext); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + } + // Gets the GameWindow Context - if (gameContext == null) + EnsureGameContextIsSet(); + if(gameContext is null) { - AppContextType c; - if (OperatingSystem.IsWindows()) - c = AppContextType.Desktop; - else if (OperatingSystem.IsAndroid()) - c = AppContextType.Android; - else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) - c = AppContextType.iOS; - else - c = AppContextType.DesktopSDL; - gameContext = GameContextFactory.NewGameContext(c); + throw new InvalidOperationException("No GameContext found"); } - - Context = gameContext; PrepareContext(); @@ -446,7 +467,7 @@ public virtual void Run(GameContext gameContext = null) Context.RequestedGraphicsProfile = graphicsDeviceManagerImpl.PreferredGraphicsProfile; Context.DeviceCreationFlags = graphicsDeviceManagerImpl.DeviceCreationFlags; - gamePlatform.Run(Context); + gamePlatform.Run(); if (gamePlatform.IsBlockingRun) { @@ -468,6 +489,28 @@ public virtual void Run(GameContext gameContext = null) } } + /// + /// Attempts to get GameContext based on the current platform. + /// + private void EnsureGameContextIsSet() + { + // Gets the GameWindow Context + if (Context == null) + { + AppContextType c; + if (OperatingSystem.IsWindows()) + c = AppContextType.Desktop; + else if (OperatingSystem.IsAndroid()) + c = AppContextType.Android; + else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) + c = AppContextType.iOS; + else + c = AppContextType.DesktopSDL; + + Context = GameContextFactory.NewGameContext(c); + } + } + /// /// Creates or updates before window and device are created. /// @@ -512,6 +555,26 @@ public void Tick() } } + public virtual void SetWindow(GameWindow window) + { + if (IsRunning) + { + throw new InvalidOperationException("Cannot set the game window while the game is running"); + } + + Context.GameWindow = window; + //Window = window; + } + + public virtual void SetGameContext(GameContext context) + { + if(IsRunning) + { + throw new InvalidOperationException("Cannot set the game context while the game is running"); + } + Context = context; + } + /// /// Calls automatically based on this game's setup, override it to implement your own system. /// @@ -586,7 +649,7 @@ protected virtual void RawTickProducer() RawTick(singleFrameElapsedTime, updateCount, drawLag / (float)TargetElapsedTime.Ticks, drawFrame); - var window = gamePlatform.MainWindow; + var window = Window; if (gamePlatform.IsBlockingRun) // throttle fps if Game.Tick() called from internal main loop { if (window.IsMinimized || window.Visible == false || (window.Focused == false && TreatNotFocusedLikeMinimized)) @@ -717,17 +780,13 @@ protected override void Destroy() for (int i = 0; i < array.Length; i++) { var disposable = array[i] as IDisposable; - if (disposable != null) - { - disposable.Dispose(); - } + disposable?.Dispose(); } // Reset graphics context GraphicsContext = null; - var disposableGraphicsManager = graphicsDeviceManager as IDisposable; - if (disposableGraphicsManager != null) + if (graphicsDeviceManager is IDisposable disposableGraphicsManager) { disposableGraphicsManager.Dispose(); } @@ -888,7 +947,7 @@ protected virtual void OnWindowCreated() WindowCreated?.Invoke(this, EventArgs.Empty); } - private void GamePlatformOnWindowCreated(object sender, EventArgs eventArgs) + protected void GamePlatformOnWindowCreated(object sender, EventArgs eventArgs) { Window.IsMouseVisible = isMouseVisible; OnWindowCreated(); @@ -912,7 +971,7 @@ protected virtual void UnloadContent() GameSystems.UnloadContent(); } - private void GamePlatform_Activated(object sender, EventArgs e) + protected void GamePlatform_Activated(object sender, EventArgs e) { if (!IsActive) { @@ -921,7 +980,7 @@ private void GamePlatform_Activated(object sender, EventArgs e) } } - private void GamePlatform_Deactivated(object sender, EventArgs e) + protected void GamePlatform_Deactivated(object sender, EventArgs e) { if (IsActive) { @@ -930,7 +989,7 @@ private void GamePlatform_Deactivated(object sender, EventArgs e) } } - private void GamePlatform_Exiting(object sender, EventArgs e) + protected void GamePlatform_Exiting(object sender, EventArgs e) { OnExiting(this, EventArgs.Empty); } diff --git a/sources/engine/Stride.Games/GameContext.cs b/sources/engine/Stride.Games/GameContext.cs index 8e2338269e..4fd1a2bc8a 100644 --- a/sources/engine/Stride.Games/GameContext.cs +++ b/sources/engine/Stride.Games/GameContext.cs @@ -30,7 +30,7 @@ namespace Stride.Games { /// - /// Contains context used to render the game (Control for WinForm, a DrawingSurface for WP8...etc.). + /// Contains context for the game and its core modules. /// public abstract class GameContext { @@ -56,6 +56,14 @@ public abstract class GameContext /// The run loop. public Action ExitCallback { get; internal set; } + public GameBase CurrentGame { get; set; } + + public GamePlatform GamePlatform { get; set; } + + public GameWindow GameWindow { get; set; } + + public IServiceRegistry Services { get; set; } + // TODO: remove these requested values. /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index 36848ae436..c5eab1e0e9 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -30,35 +30,38 @@ namespace Stride.Games { - internal abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform + public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform { private bool hasExitRan = false; - protected readonly GameBase game; - protected readonly IServiceRegistry Services; - protected GameWindow gameWindow; + protected GameBase game => context.CurrentGame; + + protected GameWindow gameWindow => context.GameWindow; + + protected GameContext context; public string FullName { get; protected set; } = string.Empty; - protected GamePlatform(GameBase game) + protected GamePlatform(GameContext context) { - this.game = game; - Services = game.Services; + Services = context.Services; + this.context = context; + this.context.GamePlatform = this; } - public static GamePlatform Create(GameBase game) + public static GamePlatform Create(GameContext context) { #if STRIDE_PLATFORM_UWP - return new GamePlatformUWP(game); + return new GamePlatformUWP(context); #elif STRIDE_PLATFORM_ANDROID - return new GamePlatformAndroid(game); + return new GamePlatformAndroid(context); #elif STRIDE_PLATFORM_IOS - return new GamePlatformiOS(game); + return new GamePlatformiOS(context); #else // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... - return new GamePlatformDesktop(game); + return new GamePlatformDesktop(context); #endif } @@ -103,6 +106,7 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); + context.GameWindow = window; return window; } @@ -115,11 +119,11 @@ public virtual GameWindow CreateWindow(GameContext gameContext) /// public bool IsBlockingRun { get; protected set; } - public void Run(GameContext gameContext) + public void Run() { - IsBlockingRun = !gameContext.IsUserManagingRun; + IsBlockingRun = !context.IsUserManagingRun; - gameWindow = CreateWindow(gameContext); + context.GameWindow = CreateWindow(context); // Register on Activated gameWindow.Activated += OnActivated; @@ -293,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = MainWindow.NativeWindow, + DeviceWindowHandle = context.GameWindow.NativeWindow, ColorSpace = preferredParameters.ColorSpace, }, }; @@ -380,7 +384,7 @@ protected override void Destroy() if (gameWindow != null) { gameWindow.Dispose(); - gameWindow = null; + context.GameWindow = null; } Activated = null; diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 90c47f779f..00be755193 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game, GameContext context = null) { this.game = game; if (this.game == null) @@ -661,6 +661,7 @@ protected virtual GraphicsDeviceInformation FindBestDevice(bool anySuitableDevic preferredParameters.PreferredBackBufferHeight = resizedBackBufferHeight; } + graphicsDeviceFactory = game.Services.GetService(); var devices = graphicsDeviceFactory.FindBestDevices(preferredParameters); if (devices.Count == 0) { diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index 6456ee6927..8e55414ba2 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -139,5 +139,9 @@ public interface IGame /// /// The window. GameWindow Window { get; } + + public void SetWindow(GameWindow window); + + public void SetGameContext(GameContext context); } } diff --git a/sources/engine/Stride.Games/IGamePlatform.cs b/sources/engine/Stride.Games/IGamePlatform.cs index 9db9b9618f..ea4671c2dc 100644 --- a/sources/engine/Stride.Games/IGamePlatform.cs +++ b/sources/engine/Stride.Games/IGamePlatform.cs @@ -1,5 +1,7 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +using System; + namespace Stride.Games { /// @@ -17,6 +19,7 @@ public interface IGamePlatform /// Gets the main window. /// /// The main window. + [Obsolete("Use GameContext.MainWindow instead. This property will be removed in a future version.")] GameWindow MainWindow { get; } /// diff --git a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs index 466ac7fc17..87cfa1bbc7 100644 --- a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs +++ b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. // // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel @@ -32,7 +32,7 @@ namespace Stride.Games { internal class GamePlatformUWP : GamePlatform { - public GamePlatformUWP(GameBase game) : base(game) + public GamePlatformUWP(GameContext context) : base(context) { // Application lifecycle reference: // https://docs.microsoft.com/en-us/windows/uwp/launch-resume/app-lifecycle diff --git a/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs b/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs index 70f2c9ddbd..5ca80248c4 100644 --- a/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs +++ b/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs @@ -27,7 +27,7 @@ private unsafe void PopulateFullName() Marshal.FreeHGlobal(output); } - public GamePlatformiOS(GameBase game) : base(game) + public GamePlatformiOS(GameContext context) : base(context) { PopulateFullName(); } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 5b16714c14..7c91017ac3 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -704,7 +704,8 @@ private void AddSources() #endif break; default: - throw new InvalidOperationException("GameContext type is not supported by the InputManager"); + Logger.Warning("GameContext type is not supported by the InputManager. Register your own for input to be handled properly."); + break; } } From 6f02a8beefa88c149d471bfd15c25fe6dc920743 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:17:34 -0600 Subject: [PATCH 19/92] clean up --- build/Stride.sln | 15 ------- sources/engine/Stride.Games/GameBase.cs | 4 +- sources/engine/Stride.Hosting/BasicGame.cs | 42 ------------------- .../Stride.Hosting/IStrideGameBuilder.cs | 16 ------- .../Stride.Hosting/Stride.Hosting.csproj | 28 ------------- .../Stride.Hosting/StrideGameBuilder.cs | 39 ----------------- 6 files changed, 2 insertions(+), 142 deletions(-) delete mode 100644 sources/engine/Stride.Hosting/BasicGame.cs delete mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs delete mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj delete mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/build/Stride.sln b/build/Stride.sln index 6283779106..c7060e2b2c 100644 --- a/build/Stride.sln +++ b/build/Stride.sln @@ -338,8 +338,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\so EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Tests", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Tests\Stride.BepuPhysics.Tests.csproj", "{7B70C783-4085-4702-B3C6-6570FD85CB8F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stride.Hosting", "..\sources\engine\Stride.Hosting\Stride.Hosting.csproj", "{A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1525,18 +1523,6 @@ Global {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.ActiveCfg = Release|Any CPU {7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.Build.0 = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.ActiveCfg = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Debug|Win32.Build.0 = Debug|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Any CPU.Build.0 = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.ActiveCfg = Release|Any CPU - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715}.Release|Win32.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1665,7 +1651,6 @@ Global {7715D094-DF59-4D91-BC9A-9A5118039ECB} = {DE048114-9AE4-467E-A879-188DC0D88A59} {66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C} {7B70C783-4085-4702-B3C6-6570FD85CB8F} = {DE048114-9AE4-467E-A879-188DC0D88A59} - {A8C9E40D-B141-4D2E-A3BD-24D5C88DA715} = {4C142567-C42B-40F5-B092-798882190209} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2} diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 05de63e24d..9531bf2332 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -419,7 +419,7 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } - if(gameContext != null) + if(Context is not null && gameContext is not null) { gameContext.GamePlatform = Context.GamePlatform; Context = gameContext; @@ -449,7 +449,7 @@ public virtual void Run(GameContext gameContext = null) // Gets the GameWindow Context EnsureGameContextIsSet(); - if(gameContext is null) + if(Context is null) { throw new InvalidOperationException("No GameContext found"); } diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs deleted file mode 100644 index 1b599d454c..0000000000 --- a/sources/engine/Stride.Hosting/BasicGame.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Stride.Core.Serialization; -using Stride.Games; -using Stride.Graphics; - -namespace Stride.Hosting; -public class BasicGame : GameBase -{ - - /// - /// Gets the graphics device manager. - /// - /// The graphics device manager. - public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - - public BasicGame() - { - // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); - Services.AddService(GraphicsDeviceManager); - Services.AddService(GraphicsDeviceManager); - } - - public override void ConfirmRenderingSettings(bool gameCreation) - { - var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; - - if (gameCreation) - { - //if our device width or height is actually smaller then requested we use the device one - deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); - deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); - } - } - - protected override void Initialize() - { - base.Initialize(); - - Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); - } -} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs deleted file mode 100644 index 3326ba14fb..0000000000 --- a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Games; - -namespace Stride.Hosting; -public interface IStrideGameBuilder -{ - public IServiceRegistry Services { get; } - - GameSystemCollection GameSystems { get; } - - List LogListeners { get; } - - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj deleted file mode 100644 index dbf6858a2e..0000000000 --- a/sources/engine/Stride.Hosting/Stride.Hosting.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - true - - - - true - true - * - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs deleted file mode 100644 index 0ba4f91eda..0000000000 --- a/sources/engine/Stride.Hosting/StrideGameBuilder.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using Stride.Core.Diagnostics; -using Stride.Games; -using Stride.Core; - -namespace Stride.Hosting; -public class StrideGameBuilder : IStrideGameBuilder -{ - public IServiceRegistry Services { get; protected set; } - - public GameSystemCollection GameSystems { get; protected set; } - - public List LogListeners { get; protected set; } = []; - - public GameBase Game { get; protected set; } - - internal StrideGameBuilder() - { - Game = new BasicGame(); - Services = Game.Services; - GameSystems = Game.GameSystems; - } - - public static StrideGameBuilder Create() - { - return new StrideGameBuilder(); - } - - public virtual GameBase Build() - { - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - - return Game; - } -} From 9f7bd5259e364cf0ee615d6985994843e2a7f69d Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sat, 10 May 2025 14:06:08 -0600 Subject: [PATCH 20/92] fixing input issues --- .../Engine/Builder/GameBuilderExtensions.cs | 25 +++++- .../Engine/Builder/MinimalGame.cs | 17 +++- sources/engine/Stride.Engine/Engine/Game.cs | 48 ++++++++++- sources/engine/Stride.Games/GameBase.cs | 80 +++++++++---------- sources/engine/Stride.Games/GamePlatform.cs | 4 +- .../Stride.Games/GraphicsDeviceManager.cs | 12 +-- sources/engine/Stride.Games/IGame.cs | 6 +- sources/engine/Stride.Input/InputManager.cs | 7 +- .../engine/Stride.Input/SDL/InputSourceSDL.cs | 2 +- .../Windows/InputSourceWinforms.cs | 2 +- 10 files changed, 137 insertions(+), 66 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index ba96b7864a..0b45d86da8 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,10 +1,10 @@ using System; -using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; using Stride.Games; +using Stride.Input; using Stride.Rendering; using Stride.Shaders.Compiler; @@ -29,6 +29,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + return gameBuilder; + } + /// /// Allows the user to add a custom database file provider to the game. /// @@ -39,8 +45,7 @@ public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, Data { // Gets initialized by the GameBase constructor. var dataBase = gameBuilder.Services.GetService(); - // There should probably be a change to the interface to avoid the below casting. - ((DatabaseFileProviderService)dataBase).FileProvider = provider; + dataBase.FileProvider = provider; return gameBuilder; } @@ -105,4 +110,18 @@ public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameCon return gameBuilder; } + public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) + { + var inputManager = gameBuilder.Services.GetService(); + + if (inputManager == null) + { + throw new InvalidOperationException("InputManager is not registered in the service registry."); + } + + inputManager.Sources.Add(inputSource); + + return gameBuilder; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 8042319f43..62e77076ea 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -4,8 +4,13 @@ using Stride.Core.Serialization.Contents; using Stride.Games; using Stride.Graphics; +using Stride.Input; namespace Stride.Engine.Builder; + +/// +/// A game class with no registered systems by default. +/// public class MinimalGame : GameBase { @@ -17,7 +22,7 @@ public class MinimalGame : GameBase public MinimalGame(GameContext gameContext) : base() { - Context = gameContext ?? DetectDefaultContext(); + Context = gameContext ?? GetDefaultContext(); Context.CurrentGame = this; // Create Platform @@ -33,7 +38,7 @@ public MinimalGame(GameContext gameContext) : base() Services.AddService(Context.GamePlatform); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } @@ -55,6 +60,14 @@ protected override void Initialize() base.Initialize(); Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + + // Add window specific input source + var inputManager = Services.GetService(); + if (inputManager is not null) + { + var windowInputSource = InputSourceFactory.NewWindowInputSource(Context); + inputManager.Sources.Add(windowInputSource); + } } protected override void PrepareContext() diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7e06b1ba2d..0094175372 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -190,7 +190,7 @@ public LogMessageType ConsoleLogLevel /// public Game(GameContext context = null) : base() { - Context = context ?? DetectDefaultContext(); + Context = context ?? GetDefaultContext(); Context.CurrentGame = this; // Create Platform @@ -242,7 +242,7 @@ public Game(GameContext context = null) : base() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, context); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); @@ -357,6 +357,7 @@ protected override void Initialize() Input = inputSystem.Manager; Services.AddService(Input); GameSystems.Add(inputSystem); + SetInitialInputSources(Input); // Initialize the systems base.Initialize(); @@ -408,6 +409,49 @@ protected override void Initialize() OnGameStarted(this); } + private void SetInitialInputSources(InputManager inputManager) + { + // Add window specific input source + var windowInputSource = InputSourceFactory.NewWindowInputSource(Context); + inputManager.Sources.Add(windowInputSource); + + // Add platform specific input sources + switch (Context.ContextType) + { +#if STRIDE_UI_SDL + case AppContextType.DesktopSDL: + break; +#endif +#if STRIDE_PLATFORM_ANDROID + case AppContextType.Android: + break; +#endif +#if STRIDE_PLATFORM_IOS + case AppContextType.iOS: + break; +#endif +#if STRIDE_PLATFORM_UWP + case AppContextType.UWPXaml: + case AppContextType.UWPCoreWindow: + break; +#endif + case AppContextType.Desktop: +#if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) + inputManager.Sources.Add(new InputSourceWindowsDirectInput()); + if (InputSourceWindowsXInput.IsSupported()) + inputManager.Sources.Add(new InputSourceWindowsXInput()); +#if STRIDE_INPUT_RAWINPUT + if (rawInputEnabled && context is GameContextWinforms gameContextWinforms) + inputManager.Sources.Add(new InputSourceWindowsRawInput(gameContextWinforms.Control)); +#endif +#endif + break; + default: + Log.Warning("GameContext type is not supported by the InputManager. Register your own for input to be handled properly."); + break; + } + } + internal static DatabaseFileProvider InitializeAssetDatabase() { using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9531bf2332..9cb2262684 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -98,7 +98,7 @@ protected GameBase() IsActive = true; } - protected static GameContext DetectDefaultContext() + protected static GameContext GetDefaultContext() { #if STRIDE_PLATFORM_UWP return GameContextFactory.NewGameContextUWPXaml(); @@ -302,9 +302,9 @@ public GameWindow Window { get { - if (gamePlatform != null) + if (Context != null) { - return gamePlatform.MainWindow; + return Context.GameWindow; } return null; } @@ -419,35 +419,7 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } - if(Context is not null && gameContext is not null) - { - gameContext.GamePlatform = Context.GamePlatform; - Context = gameContext; - Context.CurrentGame = this; - - // Overwrite Platform - if (gamePlatform != null) - { - Context.GamePlatform.Activated -= GamePlatform_Activated; - Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; - Context.GamePlatform.Exiting -= GamePlatform_Exiting; - Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; - - Services.RemoveService(); - Services.RemoveService(); - } - - Context.GamePlatform = GamePlatform.Create(gameContext); - Context.GamePlatform.Activated += GamePlatform_Activated; - Context.GamePlatform.Deactivated += GamePlatform_Deactivated; - Context.GamePlatform.Exiting += GamePlatform_Exiting; - Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; - - Services.AddService(Context.GamePlatform); - Services.AddService(Context.GamePlatform); - } - - // Gets the GameWindow Context + SetGameContext(gameContext); EnsureGameContextIsSet(); if(Context is null) { @@ -494,7 +466,7 @@ public virtual void Run(GameContext gameContext = null) /// private void EnsureGameContextIsSet() { - // Gets the GameWindow Context + // Gets the Game Context if (Context == null) { AppContextType c; @@ -555,24 +527,44 @@ public void Tick() } } - public virtual void SetWindow(GameWindow window) + public virtual void SetGameContext(GameContext context) { - if (IsRunning) + if(IsRunning) { - throw new InvalidOperationException("Cannot set the game window while the game is running"); + throw new InvalidOperationException("Cannot set the game context while the game is running"); } - Context.GameWindow = window; - //Window = window; - } + if (Context is not null && context is not null) + { + context.GamePlatform = Context.GamePlatform; + Context = context; + Context.CurrentGame = this; - public virtual void SetGameContext(GameContext context) - { - if(IsRunning) + // Overwrite Platform + if (gamePlatform != null) + { + Context.GamePlatform.Activated -= GamePlatform_Activated; + Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; + Context.GamePlatform.Exiting -= GamePlatform_Exiting; + Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; + + Services.RemoveService(); + Services.RemoveService(); + } + + Context.GamePlatform = GamePlatform.Create(context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + } + else if (context is not null) { - throw new InvalidOperationException("Cannot set the game context while the game is running"); + Context = context; } - Context = context; } /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index c5eab1e0e9..d6fa19874d 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -106,7 +106,6 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); - context.GameWindow = window; return window; } @@ -123,7 +122,8 @@ public void Run() { IsBlockingRun = !context.IsUserManagingRun; - context.GameWindow = CreateWindow(context); + // Create the game window if not already created manually + context.GameWindow ??= CreateWindow(context); // Register on Activated gameWindow.Activated += OnActivated; diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 00be755193..08cd2404b4 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -49,7 +49,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra private readonly object lockDeviceCreation; - private GameBase game; + private readonly GameBase game; private bool deviceSettingsChanged; @@ -100,12 +100,12 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game, GameContext context = null) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) { - throw new ArgumentNullException("game"); + throw new ArgumentNullException(nameof(game)); } lockDeviceCreation = new object(); @@ -119,8 +119,8 @@ public GraphicsDeviceManager(GameBase game, GameContext context = null) preferredBackBufferHeight = DefaultBackBufferHeight; preferredRefreshRate = new Rational(60, 1); PreferredMultisampleCount = MultisampleCount.None; - PreferredGraphicsProfile = new[] - { + PreferredGraphicsProfile = + [ GraphicsProfile.Level_11_1, GraphicsProfile.Level_11_0, GraphicsProfile.Level_10_1, @@ -128,7 +128,7 @@ public GraphicsDeviceManager(GameBase game, GameContext context = null) GraphicsProfile.Level_9_3, GraphicsProfile.Level_9_2, GraphicsProfile.Level_9_1, - }; + ]; graphicsDeviceFactory = game.Services.GetService(); if (graphicsDeviceFactory == null) diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index 8e55414ba2..5788899fcd 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -140,8 +140,10 @@ public interface IGame /// The window. GameWindow Window { get; } - public void SetWindow(GameWindow window); - + /// + /// Sets the game context. + /// + /// public void SetGameContext(GameContext context); } } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 7c91017ac3..7793f87679 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -318,7 +318,7 @@ public void Initialize(GameContext gameContext) { this.gameContext = gameContext ?? throw new ArgumentNullException(nameof(gameContext)); - AddSources(); + //AddSources(); // After adding initial devices, reassign gamepad id's // this creates a beter index assignment in the case where you have both an xbox controller and another controller at startup @@ -626,14 +626,15 @@ public void PoolInputEvent(InputEvent inputEvent) { eventRouters[inputEvent.GetType()].PoolEvent(inputEvent); } - + /// /// Resets the collection back to it's default values /// + [Obsolete] public void ResetSources() { Sources.Clear(); - AddSources(); + //AddSources(); } /// diff --git a/sources/engine/Stride.Input/SDL/InputSourceSDL.cs b/sources/engine/Stride.Input/SDL/InputSourceSDL.cs index 7b33c0afb0..328cb58cad 100644 --- a/sources/engine/Stride.Input/SDL/InputSourceSDL.cs +++ b/sources/engine/Stride.Input/SDL/InputSourceSDL.cs @@ -14,7 +14,7 @@ namespace Stride.Input /// /// Provides support for mouse/touch/keyboard/gamepads using SDL /// - internal unsafe class InputSourceSDL : InputSourceBase + public unsafe class InputSourceSDL : InputSourceBase { private static Sdl SDL = Window.SDL; diff --git a/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs b/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs index b46764d109..cbfca61bfa 100644 --- a/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs +++ b/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs @@ -18,7 +18,7 @@ namespace Stride.Input /// /// Provides support for mouse and keyboard input on windows forms /// - internal class InputSourceWinforms : InputSourceBase + public class InputSourceWinforms : InputSourceBase { private readonly HashSet heldKeys = new HashSet(); private readonly List keysToRelease = new List(); From 848bd105a58e694c464f74f5cd7b9ff21037675f Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 11 May 2025 20:17:18 -0600 Subject: [PATCH 21/92] Separated input --- sources/Directory.Packages.props | 4 +- sources/core/Stride.Core/IServiceRegistry.cs | 9 +++ sources/core/Stride.Core/ServiceRegistry.cs | 16 ++++ .../Engine/Builder/GameBuilder.cs | 76 +++++++++++++++++-- .../Engine/Builder/GameBuilderExtensions.cs | 49 ++++++++---- .../Engine/Builder/IGameBuilder.cs | 15 +++- .../Engine/Builder/MinimalGame.cs | 18 ++++- .../Engine/Hosting/IStrideBuilder.cs | 16 ++++ .../Engine/Hosting/StrideBuilder.cs | 52 +++++++++++++ .../engine/Stride.Engine/Stride.Engine.csproj | 2 + 10 files changed, 233 insertions(+), 24 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 633d58c70b..12076223f2 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -12,6 +12,7 @@ + @@ -45,6 +46,7 @@ + @@ -146,4 +148,4 @@ - \ No newline at end of file + diff --git a/sources/core/Stride.Core/IServiceRegistry.cs b/sources/core/Stride.Core/IServiceRegistry.cs index c2b564561a..9f25c94df1 100644 --- a/sources/core/Stride.Core/IServiceRegistry.cs +++ b/sources/core/Stride.Core/IServiceRegistry.cs @@ -47,6 +47,15 @@ public interface IServiceRegistry /// Thrown when a service of the same type is already registered. void AddService(T service) where T : class; + /// + /// Adds a service to this . + /// + /// The service to add. + /// The type to register as. + /// Thrown when the provided service is null. + /// Thrown when a service of the same type is already registered. + void AddService(object service, Type type); + /// /// Gets the service object of the specified type. /// diff --git a/sources/core/Stride.Core/ServiceRegistry.cs b/sources/core/Stride.Core/ServiceRegistry.cs index 09b7543516..ca5dcede37 100644 --- a/sources/core/Stride.Core/ServiceRegistry.cs +++ b/sources/core/Stride.Core/ServiceRegistry.cs @@ -76,6 +76,22 @@ public void AddService(T service) OnServiceAdded(new ServiceEventArgs(type, service)); } + /// + /// + /// This implementation triggers the event after a service is successfully added. + /// + public void AddService(object service, Type type) + { + ArgumentNullException.ThrowIfNull(service); + + lock (registeredService) + { + if (!registeredService.TryAdd(type, service)) + throw new ArgumentException("Service is already registered with this type", nameof(type)); + } + OnServiceAdded(new ServiceEventArgs(type, service)); + } + /// /// /// This implementation triggers the event after a service is successfully removed. diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 28001c7729..82affae29c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,7 +1,12 @@ +using System; using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; +using Stride.Core.IO; using Stride.Games; +using Stride.Input; namespace Stride.Engine.Builder; @@ -11,19 +16,28 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { - public IServiceRegistry Services { get; protected set; } + public Dictionary Services { get; internal set; } = []; - public GameSystemCollection GameSystems { get; protected set; } + public IServiceCollection DiServices { get; internal set; } = new ServiceCollection(); - public List LogListeners { get; protected set; } = []; + public GameSystemCollection GameSystems { get; internal set; } - public GameBase Game { get; protected set; } + public List LogListeners { get; internal set; } = []; + + public List InputSources { get; internal set; } = []; + + public DatabaseFileProvider DatabaseFileProvider { get; set; } + + public GameBase Game { get; set; } + + public GameContext Context { get; set; } internal GameBuilder() { Game = new MinimalGame(null); - Services = Game.Services; GameSystems = Game.GameSystems; + DiServices.AddSingleton(Game.Services); + Services.Add(typeof(IServiceRegistry), Game.Services); } public static GameBuilder Create() @@ -33,11 +47,63 @@ public static GameBuilder Create() public virtual GameBase Build() { + var provider = DiServices.BuildServiceProvider(); + foreach (var service in Services) + { + if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) + continue; + + try + { + if (service.Value == null) + { + var instance = provider.GetService(service.Key); + Game.Services.AddService(instance, service.Key); + Services[service.Key] = instance; + } + else + { + Game.Services.AddService(service.Value, service.Key); + } + } + catch (Exception ex) + { + // TODO: check if service is already registered first. + } + } + + // Add all game systems to the game. + foreach (var service in Services) + { + var system = provider.GetService(service.Key); + if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) + { + Game.GameSystems.Add(gameSystem); + } + } + foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } + if (Context != null) + { + Game.SetGameContext(Context); + } + + if(InputSources.Count > 0) + { + var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + foreach (var inputSource in InputSources) + { + inputManager.Sources.Add(inputSource); + } + } + + var dataBase = Game.Services.GetService(); + dataBase.FileProvider = DatabaseFileProvider; + return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 0b45d86da8..83b0d1af70 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,12 +1,20 @@ using System; +using Microsoft.Extensions.DependencyInjection; +using Stride.Audio; +using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; +using Stride.Engine.Processors; using Stride.Games; using Stride.Input; +using Stride.Profiling; using Stride.Rendering; +using Stride.Rendering.Fonts; +using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; +using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions @@ -19,7 +27,15 @@ public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gam public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { - gameBuilder.Services.AddService(service); + gameBuilder.Services.Add(typeof(T), service); + gameBuilder.DiServices.AddSingleton(service); + return gameBuilder; + } + + public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class + { + gameBuilder.Services.Add(typeof(T), null); + gameBuilder.DiServices.AddSingleton(); return gameBuilder; } @@ -29,6 +45,20 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + + var inputSystem = new InputSystem(services); + + gameBuilder + .AddGameSystem(inputSystem) + .AddService(inputSystem) + .AddService(inputSystem.Manager); + + return gameBuilder; + } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); @@ -44,8 +74,7 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. - var dataBase = gameBuilder.Services.GetService(); - dataBase.FileProvider = provider; + gameBuilder.DatabaseFileProvider = provider; return gameBuilder; } @@ -73,7 +102,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services; + var services = gameBuilder.Game.Services; var content = new ContentManager(services); services.AddService(content); services.AddService(content); @@ -106,22 +135,12 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); - return gameBuilder; } public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) { - var inputManager = gameBuilder.Services.GetService(); - - if (inputManager == null) - { - throw new InvalidOperationException("InputManager is not registered in the service registry."); - } - - inputManager.Sources.Add(inputSource); - + gameBuilder.InputSources.Add(inputSource); return gameBuilder; } - } diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index f658479a7b..9bb6a0060a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -1,16 +1,27 @@ using System.Collections.Generic; using Stride.Core.Diagnostics; -using Stride.Core; using Stride.Games; +using System; +using Microsoft.Extensions.DependencyInjection; +using Stride.Input; +using Stride.Core.IO; namespace Stride.Engine.Builder; public interface IGameBuilder { - IServiceRegistry Services { get; } + Dictionary Services { get; } + + IServiceCollection DiServices { get; } GameSystemCollection GameSystems { get; } List LogListeners { get; } + List InputSources { get; } + + DatabaseFileProvider DatabaseFileProvider { get; set; } + GameBase Game { get; } + + GameContext Context { get; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 62e77076ea..ec51270191 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,4 +1,7 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; using Stride.Core.Diagnostics; using Stride.Core.Serialization; using Stride.Core.Serialization.Contents; @@ -11,7 +14,7 @@ namespace Stride.Engine.Builder; /// /// A game class with no registered systems by default. /// -public class MinimalGame : GameBase +public class MinimalGame : GameBase, IHostedService { /// @@ -85,4 +88,17 @@ protected override void PrepareContext() Content = contentManager; } + + public Task StartAsync(CancellationToken cancellationToken = default) + { + Run(); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken = default) + { + Exit(); + return Task.CompletedTask; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs new file mode 100644 index 0000000000..9de0f50191 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public interface IStrideBuilder : IHostBuilder +{ + /// + /// Gets the game context. + /// + GameContext Context { get; } + /// + /// Gets the game. + /// + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs new file mode 100644 index 0000000000..f6bffe3367 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public class StrideBuilder : IStrideBuilder +{ + public GameContext Context { get; set; } + + public GameBase Game { get; set; } + + public IDictionary Properties { get; set; } + + public IHost Build() + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureContainer(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureServices(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } +} diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 7bded5b689..234f39796f 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -26,8 +26,10 @@ + + From 731610dcb1d5e1ca42167779ce860c928a44e64e Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Mon, 12 May 2025 15:47:29 -0600 Subject: [PATCH 22/92] clean up and docs --- .../Engine/Builder/GameBuilder.cs | 16 +++- .../Engine/Builder/GameBuilderExtensions.cs | 87 ++++++++++++++----- .../Engine/Builder/IGameBuilder.cs | 4 +- .../Engine/Hosting/IStrideBuilder.cs | 16 ---- .../Engine/Hosting/StrideBuilder.cs | 52 ----------- 5 files changed, 82 insertions(+), 93 deletions(-) delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 82affae29c..af4d652806 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; @@ -58,6 +57,21 @@ public virtual GameBase Build() if (service.Value == null) { var instance = provider.GetService(service.Key); + + if(instance == null) + { + //check if the type is inherited from another instance in the services. + foreach (var kvp in Services) + { + if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) + { + instance = provider.GetService(kvp.Key); + if(instance is not null) + break; + } + } + } + Game.Services.AddService(instance, service.Key); Services[service.Key] = instance; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 83b0d1af70..2a1fe0d064 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,30 +1,39 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Stride.Audio; using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; -using Stride.Engine.Processors; using Stride.Games; using Stride.Input; -using Stride.Profiling; using Stride.Rendering; -using Stride.Rendering.Fonts; -using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; -using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions { + + /// + /// Adds cire systems to the game. Does not register the systems into the + /// + /// + /// + /// + /// public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gameSystem) where T : IGameSystemBase { gameBuilder.GameSystems.Add(gameSystem); return gameBuilder; } + /// + /// Registers a service into the . + /// + /// + /// + /// + /// public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { gameBuilder.Services.Add(typeof(T), service); @@ -32,6 +41,12 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder, T servic return gameBuilder; } + /// + /// Registers a service into the . + /// + /// + /// + /// public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class { gameBuilder.Services.Add(typeof(T), null); @@ -39,13 +54,41 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T return gameBuilder; } + /// + /// Registers a service and its interface into the . + /// + /// + /// + /// + /// + public static IGameBuilder AddService(this IGameBuilder gameBuilder) where TClass : class, TInterface where TInterface : class + { + // This is a work around to allow DI to work the same way as the ServiceRegistry expects. + // Without registering both the interface and the class, the DI will not be able to resolve the interface on build. + gameBuilder.Services.Add(typeof(TInterface), null); + gameBuilder.Services.Add(typeof(TClass), null); + gameBuilder.DiServices.AddSingleton(); + return gameBuilder; + } + + /// + /// Adds a log listener to the game. This is used thoughout Stride systems for logging events. + /// + /// + /// + /// public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogListener logListener) { gameBuilder.LogListeners.Add(logListener); return gameBuilder; } - public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + /// + /// Adds the Stride input system to the game with no sources. + /// + /// + /// + public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; @@ -61,17 +104,17 @@ public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { - gameBuilder.Game.SetGameContext(context); + gameBuilder.Context = context; return gameBuilder; } /// - /// Allows the user to add a custom database file provider to the game. + /// Add a custom database file provider to the game. /// /// /// /// - public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) + public static IGameBuilder SetDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. gameBuilder.DatabaseFileProvider = provider; @@ -94,7 +137,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) var mountPath = VirtualFileSystem.ResolveProviderUnsafe("/asset", true).Provider == null ? "/asset" : null; var result = new DatabaseFileProvider(objDatabase, mountPath); - gameBuilder.AddDbFileProvider(result); + gameBuilder.SetDbFileProvider(result); } return gameBuilder; @@ -112,11 +155,11 @@ public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilde /// /// Adds a default effect compiler to the game. This is used to compile shaders and effects. /// - /// + /// /// /// /// - public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) + public static EffectSystem CreateDefaultEffectCompiler(this EffectSystem effectSystem, IVirtualFileProvider fileProvider) { EffectCompilerBase compiler = new EffectCompiler(fileProvider) { @@ -125,20 +168,20 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp if(fileProvider is DatabaseFileProvider databaseFileProvider) { - effectCompiler.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); - return effectCompiler; + effectSystem.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); + return effectSystem; } throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); } - public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) - { - gameBuilder.Game.SetGameContext(context); - return gameBuilder; - } - - public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) + /// + /// Adds an input source to the game. This requires the Stride input system to be used. + /// + /// + /// + /// + public static IGameBuilder AddStrideInputSource(this IGameBuilder gameBuilder, IInputSource inputSource) { gameBuilder.InputSources.Add(inputSource); return gameBuilder; diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index 9bb6a0060a..7b1d916455 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -21,7 +21,7 @@ public interface IGameBuilder DatabaseFileProvider DatabaseFileProvider { get; set; } - GameBase Game { get; } + GameBase Game { get; set; } - GameContext Context { get; } + GameContext Context { get; set; } } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs deleted file mode 100644 index 9de0f50191..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public interface IStrideBuilder : IHostBuilder -{ - /// - /// Gets the game context. - /// - GameContext Context { get; } - /// - /// Gets the game. - /// - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs deleted file mode 100644 index f6bffe3367..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public class StrideBuilder : IStrideBuilder -{ - public GameContext Context { get; set; } - - public GameBase Game { get; set; } - - public IDictionary Properties { get; set; } - - public IHost Build() - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureContainer(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureServices(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } -} From 8c7eaeafb86bb4efb3785f633185ee2fd9209498 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 14:53:08 -0600 Subject: [PATCH 23/92] Kryptos feedback --- sources/Directory.Packages.props | 4 +--- sources/editor/Stride.Editor/Preview/PreviewGame.cs | 10 +++++----- sources/engine/Stride.Input/InputManager.cs | 6 ++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 12076223f2..f289648c35 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,9 +11,7 @@ - - - + diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index 143ab1c307..b7a5a8c9f1 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -2,19 +2,19 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Threading.Tasks; -using Stride.Core.BuildEngine; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Core.Mathematics; using Stride.Assets; using Stride.Assets.SpriteFont; using Stride.Assets.SpriteFont.Compiler; +using Stride.Core; +using Stride.Core.BuildEngine; +using Stride.Core.Diagnostics; +using Stride.Core.Mathematics; using Stride.Engine; using Stride.Engine.Design; +using Stride.Games; using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; -using Stride.Games; namespace Stride.Editor.Preview { diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 7793f87679..eb9e1d788c 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -318,8 +318,6 @@ public void Initialize(GameContext gameContext) { this.gameContext = gameContext ?? throw new ArgumentNullException(nameof(gameContext)); - //AddSources(); - // After adding initial devices, reassign gamepad id's // this creates a beter index assignment in the case where you have both an xbox controller and another controller at startup var sortedGamePads = GamePads.OrderBy(x => x.CanChangeIndex); @@ -630,11 +628,11 @@ public void PoolInputEvent(InputEvent inputEvent) /// /// Resets the collection back to it's default values /// - [Obsolete] + [Obsolete("This should be managed manually instead by using the Sources collection")] public void ResetSources() { Sources.Clear(); - //AddSources(); + AddSources(); } /// From 415cd6f5b004d14bc9fd87eee12598882f7c0206 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 15:10:04 -0600 Subject: [PATCH 24/92] missed some duplicate packages --- sources/Directory.Packages.props | 3 +-- sources/engine/Stride.Engine/Stride.Engine.csproj | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index f289648c35..6368b59dc8 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,7 +11,7 @@ - + @@ -44,7 +44,6 @@ - diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 234f39796f..7836b61cf4 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -29,7 +29,6 @@ - From 08dc3ce62bcc625f207d0fdc423d30094d562676 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 18:16:47 -0600 Subject: [PATCH 25/92] add option for DI in GameFontSystem --- .../engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs b/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs index 0db5f3866f..570f6895b3 100644 --- a/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs +++ b/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs @@ -15,11 +15,11 @@ public class GameFontSystem : GameSystemBase { public FontSystem FontSystem { get; private set; } - public GameFontSystem(IServiceRegistry registry) + public GameFontSystem(IServiceRegistry registry, FontSystem fontSystem = null) : base(registry) { Visible = true; - FontSystem = new FontSystem(); + FontSystem = fontSystem ?? new FontSystem(); } public override void Draw(GameTime gameTime) From a51d8cfb6a3bad5629b082c545c0489e62942db5 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 19:37:36 -0600 Subject: [PATCH 26/92] Fix error caused by StreamingManager DI. --- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 14 ++++++++------ sources/engine/Stride.Engine/Engine/Game.cs | 3 +++ .../Stride.Rendering/Streaming/StreamingManager.cs | 5 ++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index af4d652806..c3b6cbc3ec 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -46,6 +46,12 @@ public static GameBuilder Create() public virtual GameBase Build() { + + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + var provider = DiServices.BuildServiceProvider(); foreach (var service in Services) { @@ -82,7 +88,8 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first. + // TODO: check if service is already registered first.' + GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -96,11 +103,6 @@ public virtual GameBase Build() } } - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - if (Context != null) { Game.SetGameContext(Context); diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 0094175372..dbaaab9489 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,10 +11,12 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; +using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; +using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; @@ -220,6 +222,7 @@ public Game(GameContext context = null) : base() Services.AddService(SceneSystem); Streaming = new StreamingManager(Services); + Services.AddService(Streaming); Audio = new AudioSystem(Services); Services.AddService(Audio); diff --git a/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs b/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs index 394c791ec6..21ca774303 100644 --- a/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs +++ b/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs @@ -92,9 +92,8 @@ public class StreamingManager : GameSystemBase, IStreamingManager, ITexturesStre public StreamingManager([NotNull] IServiceRegistry services) : base(services) { - services.AddService(this); - services.AddService(this); - services.AddService(this); + Services.AddService(this); + Services.AddService(this); ContentStreaming = new ContentStreamingService(); From 1bcc2e5a53f1e47c98772ff5888e596ddb8a1268 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:01:50 -0600 Subject: [PATCH 27/92] renaming to favour ServiceCollection --- .../Engine/Builder/GameBuilder.cs | 19 +++++++++---------- .../Engine/Builder/GameBuilderExtensions.cs | 16 ++++++++-------- .../Engine/Builder/IGameBuilder.cs | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index c3b6cbc3ec..092440c1bc 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,9 +15,9 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { - public Dictionary Services { get; internal set; } = []; + public Dictionary InternalServices { get; internal set; } = []; - public IServiceCollection DiServices { get; internal set; } = new ServiceCollection(); + public IServiceCollection Services { get; internal set; } = new ServiceCollection(); public GameSystemCollection GameSystems { get; internal set; } @@ -35,8 +35,8 @@ internal GameBuilder() { Game = new MinimalGame(null); GameSystems = Game.GameSystems; - DiServices.AddSingleton(Game.Services); - Services.Add(typeof(IServiceRegistry), Game.Services); + Services.AddSingleton(Game.Services); + InternalServices.Add(typeof(IServiceRegistry), Game.Services); } public static GameBuilder Create() @@ -46,14 +46,13 @@ public static GameBuilder Create() public virtual GameBase Build() { - foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } - var provider = DiServices.BuildServiceProvider(); - foreach (var service in Services) + var provider = Services.BuildServiceProvider(); + foreach (var service in InternalServices) { if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) continue; @@ -67,7 +66,7 @@ public virtual GameBase Build() if(instance == null) { //check if the type is inherited from another instance in the services. - foreach (var kvp in Services) + foreach (var kvp in InternalServices) { if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) { @@ -79,7 +78,7 @@ public virtual GameBase Build() } Game.Services.AddService(instance, service.Key); - Services[service.Key] = instance; + InternalServices[service.Key] = instance; } else { @@ -94,7 +93,7 @@ public virtual GameBase Build() } // Add all game systems to the game. - foreach (var service in Services) + foreach (var service in InternalServices) { var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 2a1fe0d064..702d8f1912 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -36,8 +36,8 @@ public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gam /// public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { - gameBuilder.Services.Add(typeof(T), service); - gameBuilder.DiServices.AddSingleton(service); + gameBuilder.InternalServices.Add(typeof(T), service); + gameBuilder.Services.AddSingleton(service); return gameBuilder; } @@ -49,8 +49,8 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder, T servic /// public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class { - gameBuilder.Services.Add(typeof(T), null); - gameBuilder.DiServices.AddSingleton(); + gameBuilder.InternalServices.Add(typeof(T), null); + gameBuilder.Services.AddSingleton(); return gameBuilder; } @@ -65,9 +65,9 @@ public static IGameBuilder AddService(this IGameBuilder game { // This is a work around to allow DI to work the same way as the ServiceRegistry expects. // Without registering both the interface and the class, the DI will not be able to resolve the interface on build. - gameBuilder.Services.Add(typeof(TInterface), null); - gameBuilder.Services.Add(typeof(TClass), null); - gameBuilder.DiServices.AddSingleton(); + gameBuilder.InternalServices.Add(typeof(TInterface), null); + gameBuilder.InternalServices.Add(typeof(TClass), null); + gameBuilder.Services.AddSingleton(); return gameBuilder; } @@ -90,7 +90,7 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList /// public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + var services = gameBuilder.InternalServices[typeof(IServiceRegistry)] as IServiceRegistry; var inputSystem = new InputSystem(services); diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index 7b1d916455..a56c041060 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -9,9 +9,9 @@ namespace Stride.Engine.Builder; public interface IGameBuilder { - Dictionary Services { get; } + Dictionary InternalServices { get; } - IServiceCollection DiServices { get; } + IServiceCollection Services { get; } GameSystemCollection GameSystems { get; } From c5d1c3dbb5de6227e98bc7deb74ee8ddb9bcd460 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:06:39 -0600 Subject: [PATCH 28/92] typo --- .../Stride.Engine/Engine/Builder/GameBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 702d8f1912..5e09032a5a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -15,7 +15,7 @@ public static class GameBuilderExtensions { /// - /// Adds cire systems to the game. Does not register the systems into the + /// Adds core systems to the game. Does not register the systems into the /// /// /// From 1f8eba64b0ebc79f1743e3766845bd655db4253c Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:43:14 -0600 Subject: [PATCH 29/92] docs --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 092440c1bc..fee0db5890 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,8 +15,14 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { + /// + /// This is used to allow the same instance to be registered multiple times as differenet interfaces or types. This was done due to how works."/> + /// public Dictionary InternalServices { get; internal set; } = []; + /// + /// This allows for Service to be registered through DI. + /// public IServiceCollection Services { get; internal set; } = new ServiceCollection(); public GameSystemCollection GameSystems { get; internal set; } From a315d2bcda47beabb90fc9ca1cf36d902ac42fe3 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:53:31 -0600 Subject: [PATCH 30/92] docs --- .../Engine/Builder/GameBuilder.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index fee0db5890..ec4a2dd27e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -10,7 +10,7 @@ namespace Stride.Engine.Builder; /// -/// Helps build the game and preps it to be able to run after built. +/// Helps build the game and preps it to be able to run after . /// /// public class GameBuilder : IGameBuilder @@ -25,10 +25,19 @@ public class GameBuilder : IGameBuilder /// public IServiceCollection Services { get; internal set; } = new ServiceCollection(); + /// + /// This is a direct reference to the game systems collection of the game. + /// public GameSystemCollection GameSystems { get; internal set; } + /// + /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur."/> + /// public List LogListeners { get; internal set; } = []; + /// + /// Adds input sources to the game on . + /// public List InputSources { get; internal set; } = []; public DatabaseFileProvider DatabaseFileProvider { get; set; } @@ -37,17 +46,21 @@ public class GameBuilder : IGameBuilder public GameContext Context { get; set; } - internal GameBuilder() + internal GameBuilder(GameBase game) { - Game = new MinimalGame(null); + Game = game ?? new MinimalGame(null); GameSystems = Game.GameSystems; Services.AddSingleton(Game.Services); InternalServices.Add(typeof(IServiceRegistry), Game.Services); } - public static GameBuilder Create() + /// + /// Creates a new instance of the class. + /// + /// + public static GameBuilder Create(GameBase game = null) { - return new GameBuilder(); + return new GameBuilder(game); } public virtual GameBase Build() From 0ed0012e4e21a843e3f75242596b9bbec752b0a9 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 12:42:05 -0600 Subject: [PATCH 31/92] clean up and build logging --- .../Engine/Builder/GameBuilder.cs | 27 ++++++++++++------- .../Engine/Builder/GameBuilderExtensions.cs | 4 ++- .../Engine/Builder/IGameBuilder.cs | 2 -- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index ec4a2dd27e..0e0fd4fa3c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; -using Stride.Core.IO; using Stride.Games; using Stride.Input; @@ -26,7 +25,7 @@ public class GameBuilder : IGameBuilder public IServiceCollection Services { get; internal set; } = new ServiceCollection(); /// - /// This is a direct reference to the game systems collection of the game. + /// This is a direct reference to the game systems collection of the . /// public GameSystemCollection GameSystems { get; internal set; } @@ -40,12 +39,12 @@ public class GameBuilder : IGameBuilder /// public List InputSources { get; internal set; } = []; - public DatabaseFileProvider DatabaseFileProvider { get; set; } - public GameBase Game { get; set; } public GameContext Context { get; set; } + private static Logger _log => GlobalLogger.GetLogger("GameBuilder"); + internal GameBuilder(GameBase game) { Game = game ?? new MinimalGame(null); @@ -96,18 +95,20 @@ public virtual GameBase Build() } } + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(instance, service.Key); InternalServices[service.Key] = instance; } else { + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(service.Value, service.Key); } } catch (Exception ex) { // TODO: check if service is already registered first.' - GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); + _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -117,27 +118,35 @@ public virtual GameBase Build() var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) { + _log.Info($"Adding game system {gameSystem.GetType().Name} to the game systems collection."); Game.GameSystems.Add(gameSystem); } } if (Context != null) { + _log.Info($"Setting game context."); Game.SetGameContext(Context); } if(InputSources.Count > 0) { - var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + var inputManager = Game.Services.GetService(); + + if (inputManager is null) + { + _log.Info("No InputManager found in the game services, creating default."); + inputManager = new InputManager(); + Game.Services.AddService(inputManager); + } + foreach (var inputSource in InputSources) { + _log.Info($"Adding input source {inputSource.GetType().Name} to the input manager."); inputManager.Sources.Add(inputSource); } } - var dataBase = Game.Services.GetService(); - dataBase.FileProvider = DatabaseFileProvider; - return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 5e09032a5a..200289b29c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -117,7 +117,9 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon public static IGameBuilder SetDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. - gameBuilder.DatabaseFileProvider = provider; + var fileProviderService = gameBuilder.Game.Services.GetService(); + + fileProviderService.FileProvider = provider; return gameBuilder; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index a56c041060..eba6f13b5b 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -19,8 +19,6 @@ public interface IGameBuilder List InputSources { get; } - DatabaseFileProvider DatabaseFileProvider { get; set; } - GameBase Game { get; set; } GameContext Context { get; set; } From 4718339b396b1f2cc7974d13a6170e071649f53b Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 18:49:07 -0600 Subject: [PATCH 32/92] remove some hardcoded Game references --- .../Stride.Debugger/Debugger/LiveAssemblyReloader.cs | 11 ++++++----- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 4 ++-- sources/engine/Stride.Engine/Engine/Game.cs | 2 -- sources/engine/Stride.Engine/Engine/GameSystem.cs | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs b/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs index 67c314e85f..bb4d910626 100644 --- a/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs +++ b/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs @@ -1,29 +1,30 @@ -// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using Stride.Core; using Stride.Core.Reflection; -using Stride.Core.Serialization; using Stride.Core.Yaml; using Stride.Core.Yaml.Events; using Stride.Core.Yaml.Serialization; using Stride.Debugger.Target; using Stride.Engine; +using Stride.Games; namespace Stride.Debugger { public static class LiveAssemblyReloader { - public static void Reload(Game game, AssemblyContainer assemblyContainer, List assembliesToUnregister, List assembliesToRegister) + public static void Reload(GameBase game, AssemblyContainer assemblyContainer, List assembliesToUnregister, List assembliesToRegister) { List entities = new List(); + var sceneSystem = game.Services.GetSafeServiceAs(); + if (game != null) - entities.AddRange(game.SceneSystem.SceneInstance); + entities.AddRange(sceneSystem.SceneInstance); CloneReferenceSerializer.References = new List(); diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 0e0fd4fa3c..0469f99e15 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -107,7 +107,7 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first.' + // TODO: check if service is already registered first. _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -147,6 +147,6 @@ public virtual GameBase Build() } } - return Game; + return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index dbaaab9489..7064d566e6 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,12 +11,10 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; -using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; -using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; diff --git a/sources/engine/Stride.Engine/Engine/GameSystem.cs b/sources/engine/Stride.Engine/Engine/GameSystem.cs index 3ea3a8f9ec..545609b8c9 100644 --- a/sources/engine/Stride.Engine/Engine/GameSystem.cs +++ b/sources/engine/Stride.Engine/Engine/GameSystem.cs @@ -19,6 +19,6 @@ protected GameSystem(IServiceRegistry registry) : base(registry) /// /// The game. /// This value can be null - public new Game Game => (Game)base.Game; + public new GameBase Game => base.Game; } } From 5d34b28114122bacb8936f8b4071afd3a1fe3102 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sat, 19 Jul 2025 20:45:59 -0600 Subject: [PATCH 33/92] GameWindowTest --- .../Engine/Builder/GameBuilder.cs | 2 +- .../Stride.Games/Windowing/IGameWindow.cs | 23 +++++++++++++++++++ .../Stride.Games/Windowing/IStrideSurface.cs | 8 +++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 sources/engine/Stride.Games/Windowing/IGameWindow.cs create mode 100644 sources/engine/Stride.Games/Windowing/IStrideSurface.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 0469f99e15..5c9f60db0c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -43,7 +43,7 @@ public class GameBuilder : IGameBuilder public GameContext Context { get; set; } - private static Logger _log => GlobalLogger.GetLogger("GameBuilder"); + private static Logger _log => GlobalLogger.GetLogger(nameof(GameBuilder)); internal GameBuilder(GameBase game) { diff --git a/sources/engine/Stride.Games/Windowing/IGameWindow.cs b/sources/engine/Stride.Games/Windowing/IGameWindow.cs new file mode 100644 index 0000000000..643b1d6ac9 --- /dev/null +++ b/sources/engine/Stride.Games/Windowing/IGameWindow.cs @@ -0,0 +1,23 @@ +using System; +using Stride.Core.Mathematics; + +namespace Stride.Games.Windowing; +public interface IGameWindow : IStrideSurface +{ + public IntPtr WindowHandle { get; } + public Int2 Position { get; set; } + public Int2 Size { get; set; } + + public string Title { get; set; } + + public WindowState State { get; set; } +} + +public enum WindowState +{ + Normal, + Minimized, + Maximized, + FullscreenWindowed, + FullscreenExclusive, +} diff --git a/sources/engine/Stride.Games/Windowing/IStrideSurface.cs b/sources/engine/Stride.Games/Windowing/IStrideSurface.cs new file mode 100644 index 0000000000..7e7481ff54 --- /dev/null +++ b/sources/engine/Stride.Games/Windowing/IStrideSurface.cs @@ -0,0 +1,8 @@ +using System; +using Stride.Core.Mathematics; + +namespace Stride.Games.Windowing; +public interface IStrideSurface +{ + public Int2 Size { get; set; } +} From 850659de347b2d2956adf7763de04463d398e5c5 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:27:36 -0600 Subject: [PATCH 34/92] writable ConentManager --- .../Serialization/Contents/IContentManager.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs b/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs index baf4983438..d495e40f7c 100644 --- a/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs +++ b/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs @@ -25,6 +25,19 @@ public interface IContentManager /// A stream to the raw asset. Stream OpenAsStream(string url, StreamFlags streamFlags = StreamFlags.None); + /// + /// Saves an asset at a specific URL. + /// + /// The URL. + /// The asset. + /// The custom storage type to use. Use null as default. + /// + /// url + /// or + /// asset + /// + void Save(string url, object asset, Type? storageType); + /// /// Loads content from the specified URL. /// From 1432594368bcaf2bf637adfd83064b53a91fb085 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:43:11 -0700 Subject: [PATCH 35/92] Update sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 5c9f60db0c..e9891cc82e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,7 +15,7 @@ namespace Stride.Engine.Builder; public class GameBuilder : IGameBuilder { /// - /// This is used to allow the same instance to be registered multiple times as differenet interfaces or types. This was done due to how works."/> + /// This is used to allow the same instance to be registered multiple times as different interfaces or types. This was done due to how works."/> /// public Dictionary InternalServices { get; internal set; } = []; From 4e241b330a4d0e61a2a390af5733f08c4c48090c Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:43:26 -0700 Subject: [PATCH 36/92] Update sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs index 1a99c7f97f..de655f4b79 100644 --- a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs +++ b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs @@ -117,7 +117,6 @@ public DatabaseFileProvider FileProvider { get => MicroThreadLocalDatabaseFileProvider.Value; set => MicroThreadLocalDatabaseFileProvider.Value = value; - //throw new InvalidOperationException($"Can not change the value of a {nameof(MicroThreadLocalProviderService.FileProvider)}"); } } } From bdc76e104471967206c03ed75011441457de5921 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:47:36 -0700 Subject: [PATCH 37/92] Update sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index ec51270191..fb98eea673 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -52,7 +52,7 @@ public override void ConfirmRenderingSettings(bool gameCreation) if (gameCreation) { - //if our device width or height is actually smaller then requested we use the device one + //if our device width or height is actually smaller than requested we use the device one deviceManager.PreferredBackBufferWidth = Context.RequestedWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); deviceManager.PreferredBackBufferHeight = Context.RequestedHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); } From 0742e538869805812ef6dc76c81fc1de088f9829 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:50:56 -0700 Subject: [PATCH 38/92] Update sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index e9891cc82e..5f7f64424e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -11,7 +11,6 @@ namespace Stride.Engine.Builder; /// /// Helps build the game and preps it to be able to run after . /// -/// public class GameBuilder : IGameBuilder { /// From 7bbfceafa64a086b95bc3a2383d0ebabab1166d0 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:09:38 -0700 Subject: [PATCH 39/92] Update sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 5f7f64424e..89354f46f1 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -29,7 +29,7 @@ public class GameBuilder : IGameBuilder public GameSystemCollection GameSystems { get; internal set; } /// - /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur."/> + /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur. /// public List LogListeners { get; internal set; } = []; From 4bbce682dae850ebe06509f46e2cb3aa24388f1e Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:21:24 -0700 Subject: [PATCH 40/92] Update sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index fb98eea673..623af93443 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -27,6 +27,7 @@ public MinimalGame(GameContext gameContext) : base() { Context = gameContext ?? GetDefaultContext(); Context.CurrentGame = this; + Context.Services = Services; // Create Platform Context.GamePlatform = GamePlatform.Create(Context); From 8d64efd0f3a2afb0774a6d67e457c651463c545b Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:22:19 -0700 Subject: [PATCH 41/92] Update sources/engine/Stride.Engine/Engine/Game.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Game.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7064d566e6..f4087357b8 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -192,6 +192,7 @@ public Game(GameContext context = null) : base() { Context = context ?? GetDefaultContext(); Context.CurrentGame = this; + Context.Services = Services; // Create Platform Context.GamePlatform = GamePlatform.Create(Context); From 4491da922c745332ea93be1134ecb49ecda8f68e Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:23:50 -0700 Subject: [PATCH 42/92] Update sources/engine/Stride.Engine/Engine/Game.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Game.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index f4087357b8..c211e0ec6e 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -443,7 +443,7 @@ private void SetInitialInputSources(InputManager inputManager) if (InputSourceWindowsXInput.IsSupported()) inputManager.Sources.Add(new InputSourceWindowsXInput()); #if STRIDE_INPUT_RAWINPUT - if (rawInputEnabled && context is GameContextWinforms gameContextWinforms) + if (rawInputEnabled && Context is GameContextWinforms gameContextWinforms) inputManager.Sources.Add(new InputSourceWindowsRawInput(gameContextWinforms.Control)); #endif #endif From 57a6118bd043d8f87d8ae3dd5230a44a5a1a384b Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:37:40 -0700 Subject: [PATCH 43/92] Update sources/engine/Stride.Games/GamePlatform.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Games/GamePlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index d6fa19874d..08b988cc73 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -297,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = context.GameWindow.NativeWindow, + DeviceWindowHandle = context.GameWindow != null ? context.GameWindow.NativeWindow : IntPtr.Zero, ColorSpace = preferredParameters.ColorSpace, }, }; From 57c0166594188077e325bd25db509f7409a84cd0 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:53:15 -0700 Subject: [PATCH 44/92] minor fixes and clean up --- sources/engine/Stride.Games/GamePlatform.cs | 6 +++--- sources/engine/Stride.Games/GameWindow.cs | 2 +- sources/engine/Stride.Games/Windowing/IGameWindow.cs | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index d6fa19874d..743d2f46ad 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -34,7 +34,7 @@ public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGam { private bool hasExitRan = false; - protected readonly IServiceRegistry Services; + //protected readonly IServiceRegistry Services; protected GameBase game => context.CurrentGame; @@ -46,7 +46,7 @@ public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGam protected GamePlatform(GameContext context) { - Services = context.Services; + //Services = context.Services; this.context = context; this.context.GamePlatform = this; } @@ -98,7 +98,7 @@ public virtual GameWindow CreateWindow(GameContext gameContext) var window = GetSupportedGameWindow(gameContext.ContextType); if (window != null) { - window.Services = Services; + //window.Services = Services; // Pass initial size var requestedSize = new Int2(gameContext.RequestedWidth, gameContext.RequestedHeight); diff --git a/sources/engine/Stride.Games/GameWindow.cs b/sources/engine/Stride.Games/GameWindow.cs index 26a1b83937..02dd1be2d7 100644 --- a/sources/engine/Stride.Games/GameWindow.cs +++ b/sources/engine/Stride.Games/GameWindow.cs @@ -268,7 +268,7 @@ public virtual IMessageLoop CreateUserManagedMessageLoop() throw new PlatformNotSupportedException(); } - internal IServiceRegistry Services { get; set; } + //internal IServiceRegistry Services { get; set; } protected internal abstract void SetSupportedOrientations(DisplayOrientation orientations); diff --git a/sources/engine/Stride.Games/Windowing/IGameWindow.cs b/sources/engine/Stride.Games/Windowing/IGameWindow.cs index 643b1d6ac9..5f23573032 100644 --- a/sources/engine/Stride.Games/Windowing/IGameWindow.cs +++ b/sources/engine/Stride.Games/Windowing/IGameWindow.cs @@ -6,7 +6,6 @@ public interface IGameWindow : IStrideSurface { public IntPtr WindowHandle { get; } public Int2 Position { get; set; } - public Int2 Size { get; set; } public string Title { get; set; } From a4da3df48f38972776aea736a5807e56561474ad Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:59:42 -0700 Subject: [PATCH 45/92] Undo Copilot change --- sources/engine/Stride.Games/GamePlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index b097157341..743d2f46ad 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -297,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = context.GameWindow != null ? context.GameWindow.NativeWindow : IntPtr.Zero, + DeviceWindowHandle = context.GameWindow.NativeWindow, ColorSpace = preferredParameters.ColorSpace, }, }; From 9ea93a6f8390c84e3bdb755430676d8e808c9625 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:42:18 -0700 Subject: [PATCH 46/92] added license --- THIRD PARTY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/THIRD PARTY.md b/THIRD PARTY.md index 0240b0b096..99513c7a2a 100644 --- a/THIRD PARTY.md +++ b/THIRD PARTY.md @@ -62,6 +62,7 @@ Stride uses the following open-source products. * [SLNTools](https://slntools.codeplex.com) (MIT License) * [WPFToolKit](http://wpftoolkit.codeplex.com/) (Ms-PL) * [XamlMarkdown](https://github.com/Kryptos-FR/XamlMarkdown/) (MIT License) +* [DotRecast](https://github.com/ikpil/DotRecast) (Zlib license) ### Fugue Icons From e6ac1c5adf0e384b506b2db2b94c2e2419088f0d Mon Sep 17 00:00:00 2001 From: Donovan Prezeau Date: Thu, 8 May 2025 15:04:01 -0600 Subject: [PATCH 47/92] initial PoC --- sources/Directory.Packages.props | 2 + .../Engine/Builder/GameBuilder.cs | 51 +++++++++++++ .../Engine/Builder/GameBuilderExtensions.cs | 72 +++++++++++++++++++ .../Engine/Builder/IGameBuilder.cs | 16 +++++ .../Engine/Builder/MinimalGame.cs | 43 +++++++++++ .../Engine/Design/GameSettings.cs | 2 - sources/engine/Stride.Games/GameBase.cs | 4 +- .../Stride.Games/GraphicsDeviceManager.cs | 2 +- sources/engine/Stride.Games/IGame.cs | 1 - sources/engine/Stride.Hosting/BasicGame.cs | 42 +++++++++++ .../Stride.Hosting/IStrideGameBuilder.cs | 16 +++++ .../Stride.Hosting/Stride.Hosting.csproj | 28 ++++++++ .../Stride.Hosting/StrideGameBuilder.cs | 39 ++++++++++ 13 files changed, 312 insertions(+), 6 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs create mode 100644 sources/engine/Stride.Hosting/BasicGame.cs create mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs create mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj create mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index d80c39307b..a3f81c9c5a 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,6 +11,8 @@ + + diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs new file mode 100644 index 0000000000..dd5a1b202d --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Engine.Builder; + +/// +/// Helps build the game and preps it to be able to run after built. +/// +/// +public class GameBuilder : IGameBuilder where T : IGame +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal GameBuilder() + { + Game = new MinimalGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static GameBuilder Create() + { + return new GameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} + +/// +/// Creates a default GameBuilder for a . +/// +public class GameBuilder : GameBuilder +{ + +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs new file mode 100644 index 0000000000..ead167468a --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -0,0 +1,72 @@ +using System; +using Stride.Core.Diagnostics; +using Stride.Core.IO; +using Stride.Core.Storage; +using Stride.Games; +using Stride.Rendering; +using Stride.Shaders.Compiler; + +namespace Stride.Engine.Builder; +public static class GameBuilderExtensions +{ + public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gameSystem) where T : IGameSystemBase + { + gameBuilder.GameSystems.Add(gameSystem); + return gameBuilder; + } + + public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class + { + gameBuilder.Services.AddService(service); + return gameBuilder; + } + + public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogListener logListener) + { + gameBuilder.LogListeners.Add(logListener); + return gameBuilder; + } + + public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) + { + // Gets initialized by the GameBase constructor. + var dataBase = gameBuilder.Services.GetService(); + // There should probably be a change to the interface to avoid the below casting. + ((DatabaseFileProviderService)dataBase).FileProvider = provider; + return gameBuilder; + } + + public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) + { + using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) + { + // Create and mount database file system + var objDatabase = ObjectDatabase.CreateDefaultDatabase(); + + // Only set a mount path if not mounted already + var mountPath = VirtualFileSystem.ResolveProviderUnsafe("/asset", true).Provider == null ? "/asset" : null; + var result = new DatabaseFileProvider(objDatabase, mountPath); + + gameBuilder.AddDbFileProvider(result); + } + + return gameBuilder; + } + + public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) + { + EffectCompilerBase compiler = new EffectCompiler(fileProvider) + { + SourceDirectories = { EffectCompilerBase.DefaultSourceShaderFolder }, + }; + + if(fileProvider is DatabaseFileProvider databaseFileProvider) + { + effectCompiler.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); + return effectCompiler; + } + + throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); + } + +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs new file mode 100644 index 0000000000..f658479a7b --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Core; +using Stride.Games; + +namespace Stride.Engine.Builder; +public interface IGameBuilder +{ + IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs new file mode 100644 index 0000000000..b13acc624b --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -0,0 +1,43 @@ +using System; +using Stride.Core.Serialization; +using Stride.Core.Streaming; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Engine.Builder; +public class MinimalGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public MinimalGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Context.RequestedWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Context.RequestedHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs b/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs index a012e43d9d..7bfd6fab92 100644 --- a/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs +++ b/sources/engine/Stride.Engine/Engine/Design/GameSettings.cs @@ -1,12 +1,10 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -using System; using Stride.Core; using Stride.Core.Mathematics; using Stride.Core.Serialization.Contents; using Stride.Data; -using Stride.Graphics; namespace Stride.Engine.Design { diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9fd977372d..97df14822d 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -59,7 +59,7 @@ public abstract class GameBase : ComponentBase, IGame private bool isMouseVisible; - internal object TickLock = new object(); + internal object TickLock = new(); #endregion @@ -402,7 +402,7 @@ internal void InitializeBeforeRun() /// /// The window Context for this game. /// Cannot run this instance while it is already running - public void Run(GameContext gameContext = null) + public virtual void Run(GameContext gameContext = null) { if (IsRunning) { diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 86cfab0220..90c47f779f 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - internal GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index c8da0cf304..6456ee6927 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -4,7 +4,6 @@ using Stride.Core; using Stride.Core.Serialization.Contents; -using Stride.Games.Time; using Stride.Graphics; namespace Stride.Games diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs new file mode 100644 index 0000000000..1b599d454c --- /dev/null +++ b/sources/engine/Stride.Hosting/BasicGame.cs @@ -0,0 +1,42 @@ +using System; +using Stride.Core.Serialization; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Hosting; +public class BasicGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public BasicGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs new file mode 100644 index 0000000000..3326ba14fb --- /dev/null +++ b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Hosting; +public interface IStrideGameBuilder +{ + public IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj new file mode 100644 index 0000000000..dbf6858a2e --- /dev/null +++ b/sources/engine/Stride.Hosting/Stride.Hosting.csproj @@ -0,0 +1,28 @@ + + + + true + + + + true + true + * + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs new file mode 100644 index 0000000000..0ba4f91eda --- /dev/null +++ b/sources/engine/Stride.Hosting/StrideGameBuilder.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Games; +using Stride.Core; + +namespace Stride.Hosting; +public class StrideGameBuilder : IStrideGameBuilder +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal StrideGameBuilder() + { + Game = new BasicGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static StrideGameBuilder Create() + { + return new StrideGameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} From 1628b238c65ec3afa4b7d378708d298789b19d6a Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:02:01 -0600 Subject: [PATCH 48/92] reorganizing code to work with GameStudio --- .../MicrothreadLocalDatabases.cs | 7 +- .../IO/IDatabaseFileProviderService.cs | 4 +- .../Game/EntityHierarchyEditorGame.cs | 3 +- .../EditorGame/Game/EditorServiceGame.cs | 5 + .../Stride.Editor/Engine/EmbeddedGame.cs | 3 +- .../Preview/GameStudioPreviewService.cs | 2 +- .../Stride.Editor/Preview/PreviewGame.cs | 3 +- .../Engine/Builder/GameBuilder.cs | 16 +- .../Engine/Builder/GameBuilderExtensions.cs | 36 +++++ .../Engine/Builder/MinimalGame.cs | 38 ++++- sources/engine/Stride.Engine/Engine/Game.cs | 21 ++- .../Android/GamePlatformAndroid.cs | 2 +- .../Desktop/GamePlatformDesktop.cs | 2 +- sources/engine/Stride.Games/GameBase.cs | 147 ++++++++++++------ sources/engine/Stride.Games/GameContext.cs | 10 +- sources/engine/Stride.Games/GamePlatform.cs | 38 +++-- .../Stride.Games/GraphicsDeviceManager.cs | 3 +- sources/engine/Stride.Games/IGame.cs | 4 + sources/engine/Stride.Games/IGamePlatform.cs | 3 + .../WindowsStore/GamePlatformUWP.cs | 4 +- .../Stride.Games/iOS/GamePlatformiOS.cs | 2 +- sources/engine/Stride.Input/InputManager.cs | 3 +- 22 files changed, 262 insertions(+), 94 deletions(-) diff --git a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs index 8c892bea0e..1a99c7f97f 100644 --- a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs +++ b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs @@ -113,6 +113,11 @@ private static DatabaseFileProvider CreateDatabase(BuildTransaction transaction) private class MicroThreadLocalProviderService : IDatabaseFileProviderService { - public DatabaseFileProvider FileProvider => MicroThreadLocalDatabaseFileProvider.Value; + public DatabaseFileProvider FileProvider + { + get => MicroThreadLocalDatabaseFileProvider.Value; + set => MicroThreadLocalDatabaseFileProvider.Value = value; + //throw new InvalidOperationException($"Can not change the value of a {nameof(MicroThreadLocalProviderService.FileProvider)}"); + } } } diff --git a/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs b/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs index 93c36db2f8..7d251cd2c2 100644 --- a/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs +++ b/sources/core/Stride.Core.Serialization/IO/IDatabaseFileProviderService.cs @@ -5,5 +5,5 @@ namespace Stride.Core.IO; public interface IDatabaseFileProviderService { - DatabaseFileProvider FileProvider { get; } -} \ No newline at end of file + DatabaseFileProvider FileProvider { get; set; } +} diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs index 589ceaeccb..b0059ad35d 100644 --- a/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs +++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/EntityHierarchyEditor/Game/EntityHierarchyEditorGame.cs @@ -48,7 +48,8 @@ public abstract class EntityHierarchyEditorGame : EditorServiceGame private Material fallbackColorMaterial; private Material fallbackTextureMaterial; - protected EntityHierarchyEditorGame(TaskCompletionSource gameContentLoadedTaskSource, IEffectCompiler effectCompiler, string effectLogPath) + protected EntityHierarchyEditorGame(TaskCompletionSource gameContentLoadedTaskSource, IEffectCompiler effectCompiler, string effectLogPath, GameContext context = null) + : base(context) { this.gameContentLoadedTaskSource = gameContentLoadedTaskSource; this.effectCompiler = effectCompiler; diff --git a/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs b/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs index bd04fdc2b0..25a80860c5 100644 --- a/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs +++ b/sources/editor/Stride.Editor/EditorGame/Game/EditorServiceGame.cs @@ -99,6 +99,11 @@ public bool IsEditorHidden public event EventHandler ExceptionThrown; + public EditorServiceGame(GameContext context) : base(context) + { + + } + /// /// Calculates and returns the position of the mouse in the scene. /// diff --git a/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs b/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs index 5eab6d24fc..66d262c9c3 100644 --- a/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs +++ b/sources/editor/Stride.Editor/Engine/EmbeddedGame.cs @@ -3,6 +3,7 @@ using Stride.Core.Diagnostics; using Stride.Engine; +using Stride.Games; using Stride.Graphics; namespace Stride.Editor.Engine @@ -17,7 +18,7 @@ public class EmbeddedGame : Game /// public static bool DebugMode { get; set; } - public EmbeddedGame() + public EmbeddedGame(GameContext context) : base(context) { GraphicsDeviceManager.PreferredGraphicsProfile = new [] { GraphicsProfile.Level_11_0, GraphicsProfile.Level_10_1, GraphicsProfile.Level_10_0 }; GraphicsDeviceManager.PreferredBackBufferWidth = 64; diff --git a/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs b/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs index 522b71f911..99047e09fa 100644 --- a/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs +++ b/sources/editor/Stride.Editor/Preview/GameStudioPreviewService.cs @@ -137,8 +137,8 @@ private void StrideUIThread() initializationSignal.Set(); - PreviewGame = new PreviewGame(AssetBuilderService.EffectCompiler); var context = new GameContextWinforms(gameForm) { InitializeDatabase = false }; + PreviewGame = new PreviewGame(AssetBuilderService.EffectCompiler, context); // Wait for shaders to be loaded AssetBuilderService.WaitForShaders(); diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index c88ac25032..143ab1c307 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -14,6 +14,7 @@ using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; +using Stride.Games; namespace Stride.Editor.Preview { @@ -43,7 +44,7 @@ public class PreviewGame : EditorGame.Game.EditorServiceGame private Scene previewScene; - public PreviewGame(IEffectCompiler effectCompiler) + public PreviewGame(IEffectCompiler effectCompiler, GameContext context) : base(context) { this.effectCompiler = effectCompiler; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index dd5a1b202d..28001c7729 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -9,7 +9,7 @@ namespace Stride.Engine.Builder; /// Helps build the game and preps it to be able to run after built. /// /// -public class GameBuilder : IGameBuilder where T : IGame +public class GameBuilder : IGameBuilder { public IServiceRegistry Services { get; protected set; } @@ -21,14 +21,14 @@ public class GameBuilder : IGameBuilder where T : IGame internal GameBuilder() { - Game = new MinimalGame(); + Game = new MinimalGame(null); Services = Game.Services; GameSystems = Game.GameSystems; } - public static GameBuilder Create() + public static GameBuilder Create() { - return new GameBuilder(); + return new GameBuilder(); } public virtual GameBase Build() @@ -41,11 +41,3 @@ public virtual GameBase Build() return Game; } } - -/// -/// Creates a default GameBuilder for a . -/// -public class GameBuilder : GameBuilder -{ - -} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index ead167468a..ba96b7864a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,6 +1,8 @@ using System; +using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; +using Stride.Core.Serialization.Contents; using Stride.Core.Storage; using Stride.Games; using Stride.Rendering; @@ -27,6 +29,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + /// + /// Allows the user to add a custom database file provider to the game. + /// + /// + /// + /// public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. @@ -36,6 +44,11 @@ public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, Data return gameBuilder; } + /// + /// Creates a default database to be used in the game. + /// + /// + /// public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) { using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) @@ -53,6 +66,22 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) return gameBuilder; } + public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services; + var content = new ContentManager(services); + services.AddService(content); + services.AddService(content); + return gameBuilder; + } + + /// + /// Adds a default effect compiler to the game. This is used to compile shaders and effects. + /// + /// + /// + /// + /// public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) { EffectCompilerBase compiler = new EffectCompiler(fileProvider) @@ -69,4 +98,11 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); } + public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + + return gameBuilder; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index b13acc624b..8042319f43 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,6 +1,7 @@ using System; +using Stride.Core.Diagnostics; using Stride.Core.Serialization; -using Stride.Core.Streaming; +using Stride.Core.Serialization.Contents; using Stride.Games; using Stride.Graphics; @@ -14,10 +15,25 @@ public class MinimalGame : GameBase /// The graphics device manager. public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - public MinimalGame() + public MinimalGame(GameContext gameContext) : base() { + Context = gameContext ?? DetectDefaultContext(); + Context.CurrentGame = this; + + // Create Platform + Context.GamePlatform = GamePlatform.Create(Context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + // Setup registry + Services.AddService(this); + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } @@ -40,4 +56,20 @@ protected override void Initialize() Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); } + + protected override void PrepareContext() + { + //Allow the user to add their own ContentManager + var contentManager = Services.GetService(); + + if (contentManager is null) + { + Log.Info("No ContentManager found, creating default ContentManager"); + contentManager = new ContentManager(Services); + Services.AddService(contentManager); + Services.AddService(contentManager); + } + + Content = contentManager; + } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 6c4c162ed5..7e06b1ba2d 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -188,8 +188,23 @@ public LogMessageType ConsoleLogLevel /// /// Initializes a new instance of the class. /// - public Game() + public Game(GameContext context = null) : base() { + Context = context ?? DetectDefaultContext(); + Context.CurrentGame = this; + + // Create Platform + Context.GamePlatform = GamePlatform.Create(Context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + // Setup registry + Services.AddService(this); + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + // Register the logger backend before anything else logListener = GetLogListener(); @@ -227,7 +242,7 @@ public Game() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, context); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); @@ -256,7 +271,7 @@ protected override void PrepareContext() if (Context.InitializeDatabase) { databaseFileProvider = InitializeAssetDatabase(); - ((DatabaseFileProviderService)Services.GetService()).FileProvider = databaseFileProvider; + Services.GetService().FileProvider = databaseFileProvider; var renderingSettings = new RenderingSettings(); if (Content.Exists(GameSettings.AssetUrl)) diff --git a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs index 167afa863d..5db252837c 100644 --- a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs +++ b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs @@ -28,7 +28,7 @@ private void PopulateFullName() FullName = $"{manufacturer} - {model}"; } - public GamePlatformAndroid(GameBase game) : base(game) + public GamePlatformAndroid(GameContext context) : base(context) { PopulateFullName(); } diff --git a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs index 7d48fae49e..c3911ba734 100644 --- a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs +++ b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs @@ -29,7 +29,7 @@ namespace Stride.Games { internal class GamePlatformDesktop : GamePlatform { - public GamePlatformDesktop(GameBase game) : base(game) + public GamePlatformDesktop(GameContext context) : base(context) { IsBlockingRun = true; #if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 97df14822d..05de63e24d 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -41,7 +41,7 @@ public abstract class GameBase : ComponentBase, IGame { #region Fields - private readonly GamePlatform gamePlatform; + private GamePlatform gamePlatform => Context.GamePlatform; private IGraphicsDeviceService graphicsDeviceService; protected IGraphicsDeviceManager graphicsDeviceManager; private ResumeManager resumeManager; @@ -95,21 +95,23 @@ protected GameBase() GameSystems = new GameSystemCollection(Services); Services.AddService(GameSystems); - // Create Platform - gamePlatform = GamePlatform.Create(this); - gamePlatform.Activated += GamePlatform_Activated; - gamePlatform.Deactivated += GamePlatform_Deactivated; - gamePlatform.Exiting += GamePlatform_Exiting; - gamePlatform.WindowCreated += GamePlatformOnWindowCreated; - - // Setup registry - Services.AddService(this); - Services.AddService(gamePlatform); - Services.AddService(gamePlatform); - IsActive = true; } + protected static GameContext DetectDefaultContext() + { +#if STRIDE_PLATFORM_UWP + return GameContextFactory.NewGameContextUWPXaml(); +#elif STRIDE_PLATFORM_ANDROID + return GameContextFactory.NewGameContextAndroid(); +#elif STRIDE_PLATFORM_IOS + return GameContextFactory.NewGameContextiOS(); +#else + // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... + return GameContextFactory.NewGameContextDesktop(); +#endif + } + #endregion #region Public Events @@ -165,7 +167,7 @@ protected GameBase() /// /// Gets the . /// - public ContentManager Content { get; private set; } + public ContentManager Content { get; protected set; } /// /// Gets the game components registered by this game. @@ -177,15 +179,15 @@ protected GameBase() /// Gets the game context. /// /// The game context. - public GameContext Context { get; private set; } + public GameContext Context { get; protected set; } /// /// Gets the graphics device. /// /// The graphics device. - public GraphicsDevice GraphicsDevice { get; private set; } + public GraphicsDevice GraphicsDevice { get; protected set; } - public GraphicsContext GraphicsContext { get; private set; } + public GraphicsContext GraphicsContext { get; protected set; } /// /// Gets or sets the time between each when is false. @@ -197,13 +199,13 @@ protected GameBase() /// Gets a value indicating whether this instance is active. /// /// true if this instance is active; otherwise, false. - public bool IsActive { get; private set; } + public bool IsActive { get; protected set; } /// /// Gets a value indicating whether this instance is exiting. /// /// true if this instance is exiting; otherwise, false. - public bool IsExiting{ get; private set; } + public bool IsExiting{ get; protected set; } /// /// Gets or sets a value indicating whether the elapsed time between each update should be constant, @@ -295,6 +297,7 @@ public bool IsMouseVisible /// Gets the abstract window. /// /// The window. + [Obsolete("Use GameContext.GameWindow instead.")] public GameWindow Window { get @@ -416,22 +419,40 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } + if(gameContext != null) + { + gameContext.GamePlatform = Context.GamePlatform; + Context = gameContext; + Context.CurrentGame = this; + + // Overwrite Platform + if (gamePlatform != null) + { + Context.GamePlatform.Activated -= GamePlatform_Activated; + Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; + Context.GamePlatform.Exiting -= GamePlatform_Exiting; + Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; + + Services.RemoveService(); + Services.RemoveService(); + } + + Context.GamePlatform = GamePlatform.Create(gameContext); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + } + // Gets the GameWindow Context - if (gameContext == null) + EnsureGameContextIsSet(); + if(gameContext is null) { - AppContextType c; - if (OperatingSystem.IsWindows()) - c = AppContextType.Desktop; - else if (OperatingSystem.IsAndroid()) - c = AppContextType.Android; - else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) - c = AppContextType.iOS; - else - c = AppContextType.DesktopSDL; - gameContext = GameContextFactory.NewGameContext(c); + throw new InvalidOperationException("No GameContext found"); } - - Context = gameContext; PrepareContext(); @@ -446,7 +467,7 @@ public virtual void Run(GameContext gameContext = null) Context.RequestedGraphicsProfile = graphicsDeviceManagerImpl.PreferredGraphicsProfile; Context.DeviceCreationFlags = graphicsDeviceManagerImpl.DeviceCreationFlags; - gamePlatform.Run(Context); + gamePlatform.Run(); if (gamePlatform.IsBlockingRun) { @@ -468,6 +489,28 @@ public virtual void Run(GameContext gameContext = null) } } + /// + /// Attempts to get GameContext based on the current platform. + /// + private void EnsureGameContextIsSet() + { + // Gets the GameWindow Context + if (Context == null) + { + AppContextType c; + if (OperatingSystem.IsWindows()) + c = AppContextType.Desktop; + else if (OperatingSystem.IsAndroid()) + c = AppContextType.Android; + else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) + c = AppContextType.iOS; + else + c = AppContextType.DesktopSDL; + + Context = GameContextFactory.NewGameContext(c); + } + } + /// /// Creates or updates before window and device are created. /// @@ -512,6 +555,26 @@ public void Tick() } } + public virtual void SetWindow(GameWindow window) + { + if (IsRunning) + { + throw new InvalidOperationException("Cannot set the game window while the game is running"); + } + + Context.GameWindow = window; + //Window = window; + } + + public virtual void SetGameContext(GameContext context) + { + if(IsRunning) + { + throw new InvalidOperationException("Cannot set the game context while the game is running"); + } + Context = context; + } + /// /// Calls automatically based on this game's setup, override it to implement your own system. /// @@ -586,7 +649,7 @@ protected virtual void RawTickProducer() RawTick(singleFrameElapsedTime, updateCount, drawLag / (float)TargetElapsedTime.Ticks, drawFrame); - var window = gamePlatform.MainWindow; + var window = Window; if (gamePlatform.IsBlockingRun) // throttle fps if Game.Tick() called from internal main loop { if (window.IsMinimized || window.Visible == false || (window.Focused == false && TreatNotFocusedLikeMinimized)) @@ -717,17 +780,13 @@ protected override void Destroy() for (int i = 0; i < array.Length; i++) { var disposable = array[i] as IDisposable; - if (disposable != null) - { - disposable.Dispose(); - } + disposable?.Dispose(); } // Reset graphics context GraphicsContext = null; - var disposableGraphicsManager = graphicsDeviceManager as IDisposable; - if (disposableGraphicsManager != null) + if (graphicsDeviceManager is IDisposable disposableGraphicsManager) { disposableGraphicsManager.Dispose(); } @@ -888,7 +947,7 @@ protected virtual void OnWindowCreated() WindowCreated?.Invoke(this, EventArgs.Empty); } - private void GamePlatformOnWindowCreated(object sender, EventArgs eventArgs) + protected void GamePlatformOnWindowCreated(object sender, EventArgs eventArgs) { Window.IsMouseVisible = isMouseVisible; OnWindowCreated(); @@ -912,7 +971,7 @@ protected virtual void UnloadContent() GameSystems.UnloadContent(); } - private void GamePlatform_Activated(object sender, EventArgs e) + protected void GamePlatform_Activated(object sender, EventArgs e) { if (!IsActive) { @@ -921,7 +980,7 @@ private void GamePlatform_Activated(object sender, EventArgs e) } } - private void GamePlatform_Deactivated(object sender, EventArgs e) + protected void GamePlatform_Deactivated(object sender, EventArgs e) { if (IsActive) { @@ -930,7 +989,7 @@ private void GamePlatform_Deactivated(object sender, EventArgs e) } } - private void GamePlatform_Exiting(object sender, EventArgs e) + protected void GamePlatform_Exiting(object sender, EventArgs e) { OnExiting(this, EventArgs.Empty); } diff --git a/sources/engine/Stride.Games/GameContext.cs b/sources/engine/Stride.Games/GameContext.cs index 8e2338269e..4fd1a2bc8a 100644 --- a/sources/engine/Stride.Games/GameContext.cs +++ b/sources/engine/Stride.Games/GameContext.cs @@ -30,7 +30,7 @@ namespace Stride.Games { /// - /// Contains context used to render the game (Control for WinForm, a DrawingSurface for WP8...etc.). + /// Contains context for the game and its core modules. /// public abstract class GameContext { @@ -56,6 +56,14 @@ public abstract class GameContext /// The run loop. public Action ExitCallback { get; internal set; } + public GameBase CurrentGame { get; set; } + + public GamePlatform GamePlatform { get; set; } + + public GameWindow GameWindow { get; set; } + + public IServiceRegistry Services { get; set; } + // TODO: remove these requested values. /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index 36848ae436..c5eab1e0e9 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -30,35 +30,38 @@ namespace Stride.Games { - internal abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform + public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform { private bool hasExitRan = false; - protected readonly GameBase game; - protected readonly IServiceRegistry Services; - protected GameWindow gameWindow; + protected GameBase game => context.CurrentGame; + + protected GameWindow gameWindow => context.GameWindow; + + protected GameContext context; public string FullName { get; protected set; } = string.Empty; - protected GamePlatform(GameBase game) + protected GamePlatform(GameContext context) { - this.game = game; - Services = game.Services; + Services = context.Services; + this.context = context; + this.context.GamePlatform = this; } - public static GamePlatform Create(GameBase game) + public static GamePlatform Create(GameContext context) { #if STRIDE_PLATFORM_UWP - return new GamePlatformUWP(game); + return new GamePlatformUWP(context); #elif STRIDE_PLATFORM_ANDROID - return new GamePlatformAndroid(game); + return new GamePlatformAndroid(context); #elif STRIDE_PLATFORM_IOS - return new GamePlatformiOS(game); + return new GamePlatformiOS(context); #else // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... - return new GamePlatformDesktop(game); + return new GamePlatformDesktop(context); #endif } @@ -103,6 +106,7 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); + context.GameWindow = window; return window; } @@ -115,11 +119,11 @@ public virtual GameWindow CreateWindow(GameContext gameContext) /// public bool IsBlockingRun { get; protected set; } - public void Run(GameContext gameContext) + public void Run() { - IsBlockingRun = !gameContext.IsUserManagingRun; + IsBlockingRun = !context.IsUserManagingRun; - gameWindow = CreateWindow(gameContext); + context.GameWindow = CreateWindow(context); // Register on Activated gameWindow.Activated += OnActivated; @@ -293,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = MainWindow.NativeWindow, + DeviceWindowHandle = context.GameWindow.NativeWindow, ColorSpace = preferredParameters.ColorSpace, }, }; @@ -380,7 +384,7 @@ protected override void Destroy() if (gameWindow != null) { gameWindow.Dispose(); - gameWindow = null; + context.GameWindow = null; } Activated = null; diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 90c47f779f..00be755193 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game, GameContext context = null) { this.game = game; if (this.game == null) @@ -661,6 +661,7 @@ protected virtual GraphicsDeviceInformation FindBestDevice(bool anySuitableDevic preferredParameters.PreferredBackBufferHeight = resizedBackBufferHeight; } + graphicsDeviceFactory = game.Services.GetService(); var devices = graphicsDeviceFactory.FindBestDevices(preferredParameters); if (devices.Count == 0) { diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index 6456ee6927..8e55414ba2 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -139,5 +139,9 @@ public interface IGame /// /// The window. GameWindow Window { get; } + + public void SetWindow(GameWindow window); + + public void SetGameContext(GameContext context); } } diff --git a/sources/engine/Stride.Games/IGamePlatform.cs b/sources/engine/Stride.Games/IGamePlatform.cs index 9db9b9618f..ea4671c2dc 100644 --- a/sources/engine/Stride.Games/IGamePlatform.cs +++ b/sources/engine/Stride.Games/IGamePlatform.cs @@ -1,5 +1,7 @@ // Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +using System; + namespace Stride.Games { /// @@ -17,6 +19,7 @@ public interface IGamePlatform /// Gets the main window. /// /// The main window. + [Obsolete("Use GameContext.MainWindow instead. This property will be removed in a future version.")] GameWindow MainWindow { get; } /// diff --git a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs index 466ac7fc17..87cfa1bbc7 100644 --- a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs +++ b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. // // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel @@ -32,7 +32,7 @@ namespace Stride.Games { internal class GamePlatformUWP : GamePlatform { - public GamePlatformUWP(GameBase game) : base(game) + public GamePlatformUWP(GameContext context) : base(context) { // Application lifecycle reference: // https://docs.microsoft.com/en-us/windows/uwp/launch-resume/app-lifecycle diff --git a/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs b/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs index 70f2c9ddbd..5ca80248c4 100644 --- a/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs +++ b/sources/engine/Stride.Games/iOS/GamePlatformiOS.cs @@ -27,7 +27,7 @@ private unsafe void PopulateFullName() Marshal.FreeHGlobal(output); } - public GamePlatformiOS(GameBase game) : base(game) + public GamePlatformiOS(GameContext context) : base(context) { PopulateFullName(); } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 5b16714c14..7c91017ac3 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -704,7 +704,8 @@ private void AddSources() #endif break; default: - throw new InvalidOperationException("GameContext type is not supported by the InputManager"); + Logger.Warning("GameContext type is not supported by the InputManager. Register your own for input to be handled properly."); + break; } } From 467350003d3e80f99b09debde38504a311af0e34 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:17:34 -0600 Subject: [PATCH 49/92] clean up --- sources/engine/Stride.Games/GameBase.cs | 4 +- sources/engine/Stride.Hosting/BasicGame.cs | 42 ------------------- .../Stride.Hosting/IStrideGameBuilder.cs | 16 ------- .../Stride.Hosting/Stride.Hosting.csproj | 28 ------------- .../Stride.Hosting/StrideGameBuilder.cs | 39 ----------------- 5 files changed, 2 insertions(+), 127 deletions(-) delete mode 100644 sources/engine/Stride.Hosting/BasicGame.cs delete mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs delete mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj delete mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 05de63e24d..9531bf2332 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -419,7 +419,7 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } - if(gameContext != null) + if(Context is not null && gameContext is not null) { gameContext.GamePlatform = Context.GamePlatform; Context = gameContext; @@ -449,7 +449,7 @@ public virtual void Run(GameContext gameContext = null) // Gets the GameWindow Context EnsureGameContextIsSet(); - if(gameContext is null) + if(Context is null) { throw new InvalidOperationException("No GameContext found"); } diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs deleted file mode 100644 index 1b599d454c..0000000000 --- a/sources/engine/Stride.Hosting/BasicGame.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Stride.Core.Serialization; -using Stride.Games; -using Stride.Graphics; - -namespace Stride.Hosting; -public class BasicGame : GameBase -{ - - /// - /// Gets the graphics device manager. - /// - /// The graphics device manager. - public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - - public BasicGame() - { - // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); - Services.AddService(GraphicsDeviceManager); - Services.AddService(GraphicsDeviceManager); - } - - public override void ConfirmRenderingSettings(bool gameCreation) - { - var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; - - if (gameCreation) - { - //if our device width or height is actually smaller then requested we use the device one - deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); - deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); - } - } - - protected override void Initialize() - { - base.Initialize(); - - Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); - } -} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs deleted file mode 100644 index 3326ba14fb..0000000000 --- a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Games; - -namespace Stride.Hosting; -public interface IStrideGameBuilder -{ - public IServiceRegistry Services { get; } - - GameSystemCollection GameSystems { get; } - - List LogListeners { get; } - - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj deleted file mode 100644 index dbf6858a2e..0000000000 --- a/sources/engine/Stride.Hosting/Stride.Hosting.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - true - - - - true - true - * - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs deleted file mode 100644 index 0ba4f91eda..0000000000 --- a/sources/engine/Stride.Hosting/StrideGameBuilder.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using Stride.Core.Diagnostics; -using Stride.Games; -using Stride.Core; - -namespace Stride.Hosting; -public class StrideGameBuilder : IStrideGameBuilder -{ - public IServiceRegistry Services { get; protected set; } - - public GameSystemCollection GameSystems { get; protected set; } - - public List LogListeners { get; protected set; } = []; - - public GameBase Game { get; protected set; } - - internal StrideGameBuilder() - { - Game = new BasicGame(); - Services = Game.Services; - GameSystems = Game.GameSystems; - } - - public static StrideGameBuilder Create() - { - return new StrideGameBuilder(); - } - - public virtual GameBase Build() - { - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - - return Game; - } -} From f5b7d3cec7c98af4e2fec45a4eb0738ab49b5c2b Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sat, 10 May 2025 14:06:08 -0600 Subject: [PATCH 50/92] fixing input issues --- .../Engine/Builder/GameBuilderExtensions.cs | 25 +++++- .../Engine/Builder/MinimalGame.cs | 17 +++- sources/engine/Stride.Engine/Engine/Game.cs | 48 ++++++++++- sources/engine/Stride.Games/GameBase.cs | 80 +++++++++---------- sources/engine/Stride.Games/GamePlatform.cs | 4 +- .../Stride.Games/GraphicsDeviceManager.cs | 12 +-- sources/engine/Stride.Games/IGame.cs | 6 +- sources/engine/Stride.Input/InputManager.cs | 7 +- .../engine/Stride.Input/SDL/InputSourceSDL.cs | 2 +- .../Windows/InputSourceWinforms.cs | 2 +- 10 files changed, 137 insertions(+), 66 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index ba96b7864a..0b45d86da8 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,10 +1,10 @@ using System; -using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; using Stride.Games; +using Stride.Input; using Stride.Rendering; using Stride.Shaders.Compiler; @@ -29,6 +29,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + return gameBuilder; + } + /// /// Allows the user to add a custom database file provider to the game. /// @@ -39,8 +45,7 @@ public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, Data { // Gets initialized by the GameBase constructor. var dataBase = gameBuilder.Services.GetService(); - // There should probably be a change to the interface to avoid the below casting. - ((DatabaseFileProviderService)dataBase).FileProvider = provider; + dataBase.FileProvider = provider; return gameBuilder; } @@ -105,4 +110,18 @@ public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameCon return gameBuilder; } + public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) + { + var inputManager = gameBuilder.Services.GetService(); + + if (inputManager == null) + { + throw new InvalidOperationException("InputManager is not registered in the service registry."); + } + + inputManager.Sources.Add(inputSource); + + return gameBuilder; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 8042319f43..62e77076ea 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -4,8 +4,13 @@ using Stride.Core.Serialization.Contents; using Stride.Games; using Stride.Graphics; +using Stride.Input; namespace Stride.Engine.Builder; + +/// +/// A game class with no registered systems by default. +/// public class MinimalGame : GameBase { @@ -17,7 +22,7 @@ public class MinimalGame : GameBase public MinimalGame(GameContext gameContext) : base() { - Context = gameContext ?? DetectDefaultContext(); + Context = gameContext ?? GetDefaultContext(); Context.CurrentGame = this; // Create Platform @@ -33,7 +38,7 @@ public MinimalGame(GameContext gameContext) : base() Services.AddService(Context.GamePlatform); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } @@ -55,6 +60,14 @@ protected override void Initialize() base.Initialize(); Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + + // Add window specific input source + var inputManager = Services.GetService(); + if (inputManager is not null) + { + var windowInputSource = InputSourceFactory.NewWindowInputSource(Context); + inputManager.Sources.Add(windowInputSource); + } } protected override void PrepareContext() diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7e06b1ba2d..0094175372 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -190,7 +190,7 @@ public LogMessageType ConsoleLogLevel /// public Game(GameContext context = null) : base() { - Context = context ?? DetectDefaultContext(); + Context = context ?? GetDefaultContext(); Context.CurrentGame = this; // Create Platform @@ -242,7 +242,7 @@ public Game(GameContext context = null) : base() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, context); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); @@ -357,6 +357,7 @@ protected override void Initialize() Input = inputSystem.Manager; Services.AddService(Input); GameSystems.Add(inputSystem); + SetInitialInputSources(Input); // Initialize the systems base.Initialize(); @@ -408,6 +409,49 @@ protected override void Initialize() OnGameStarted(this); } + private void SetInitialInputSources(InputManager inputManager) + { + // Add window specific input source + var windowInputSource = InputSourceFactory.NewWindowInputSource(Context); + inputManager.Sources.Add(windowInputSource); + + // Add platform specific input sources + switch (Context.ContextType) + { +#if STRIDE_UI_SDL + case AppContextType.DesktopSDL: + break; +#endif +#if STRIDE_PLATFORM_ANDROID + case AppContextType.Android: + break; +#endif +#if STRIDE_PLATFORM_IOS + case AppContextType.iOS: + break; +#endif +#if STRIDE_PLATFORM_UWP + case AppContextType.UWPXaml: + case AppContextType.UWPCoreWindow: + break; +#endif + case AppContextType.Desktop: +#if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) + inputManager.Sources.Add(new InputSourceWindowsDirectInput()); + if (InputSourceWindowsXInput.IsSupported()) + inputManager.Sources.Add(new InputSourceWindowsXInput()); +#if STRIDE_INPUT_RAWINPUT + if (rawInputEnabled && context is GameContextWinforms gameContextWinforms) + inputManager.Sources.Add(new InputSourceWindowsRawInput(gameContextWinforms.Control)); +#endif +#endif + break; + default: + Log.Warning("GameContext type is not supported by the InputManager. Register your own for input to be handled properly."); + break; + } + } + internal static DatabaseFileProvider InitializeAssetDatabase() { using (Profiler.Begin(GameProfilingKeys.ObjectDatabaseInitialize)) diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9531bf2332..9cb2262684 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -98,7 +98,7 @@ protected GameBase() IsActive = true; } - protected static GameContext DetectDefaultContext() + protected static GameContext GetDefaultContext() { #if STRIDE_PLATFORM_UWP return GameContextFactory.NewGameContextUWPXaml(); @@ -302,9 +302,9 @@ public GameWindow Window { get { - if (gamePlatform != null) + if (Context != null) { - return gamePlatform.MainWindow; + return Context.GameWindow; } return null; } @@ -419,35 +419,7 @@ public virtual void Run(GameContext gameContext = null) throw new InvalidOperationException("No GraphicsDeviceManager found"); } - if(Context is not null && gameContext is not null) - { - gameContext.GamePlatform = Context.GamePlatform; - Context = gameContext; - Context.CurrentGame = this; - - // Overwrite Platform - if (gamePlatform != null) - { - Context.GamePlatform.Activated -= GamePlatform_Activated; - Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; - Context.GamePlatform.Exiting -= GamePlatform_Exiting; - Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; - - Services.RemoveService(); - Services.RemoveService(); - } - - Context.GamePlatform = GamePlatform.Create(gameContext); - Context.GamePlatform.Activated += GamePlatform_Activated; - Context.GamePlatform.Deactivated += GamePlatform_Deactivated; - Context.GamePlatform.Exiting += GamePlatform_Exiting; - Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; - - Services.AddService(Context.GamePlatform); - Services.AddService(Context.GamePlatform); - } - - // Gets the GameWindow Context + SetGameContext(gameContext); EnsureGameContextIsSet(); if(Context is null) { @@ -494,7 +466,7 @@ public virtual void Run(GameContext gameContext = null) /// private void EnsureGameContextIsSet() { - // Gets the GameWindow Context + // Gets the Game Context if (Context == null) { AppContextType c; @@ -555,24 +527,44 @@ public void Tick() } } - public virtual void SetWindow(GameWindow window) + public virtual void SetGameContext(GameContext context) { - if (IsRunning) + if(IsRunning) { - throw new InvalidOperationException("Cannot set the game window while the game is running"); + throw new InvalidOperationException("Cannot set the game context while the game is running"); } - Context.GameWindow = window; - //Window = window; - } + if (Context is not null && context is not null) + { + context.GamePlatform = Context.GamePlatform; + Context = context; + Context.CurrentGame = this; - public virtual void SetGameContext(GameContext context) - { - if(IsRunning) + // Overwrite Platform + if (gamePlatform != null) + { + Context.GamePlatform.Activated -= GamePlatform_Activated; + Context.GamePlatform.Deactivated -= GamePlatform_Deactivated; + Context.GamePlatform.Exiting -= GamePlatform_Exiting; + Context.GamePlatform.WindowCreated -= GamePlatformOnWindowCreated; + + Services.RemoveService(); + Services.RemoveService(); + } + + Context.GamePlatform = GamePlatform.Create(context); + Context.GamePlatform.Activated += GamePlatform_Activated; + Context.GamePlatform.Deactivated += GamePlatform_Deactivated; + Context.GamePlatform.Exiting += GamePlatform_Exiting; + Context.GamePlatform.WindowCreated += GamePlatformOnWindowCreated; + + Services.AddService(Context.GamePlatform); + Services.AddService(Context.GamePlatform); + } + else if (context is not null) { - throw new InvalidOperationException("Cannot set the game context while the game is running"); + Context = context; } - Context = context; } /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index c5eab1e0e9..d6fa19874d 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -106,7 +106,6 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); - context.GameWindow = window; return window; } @@ -123,7 +122,8 @@ public void Run() { IsBlockingRun = !context.IsUserManagingRun; - context.GameWindow = CreateWindow(context); + // Create the game window if not already created manually + context.GameWindow ??= CreateWindow(context); // Register on Activated gameWindow.Activated += OnActivated; diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 00be755193..08cd2404b4 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -49,7 +49,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra private readonly object lockDeviceCreation; - private GameBase game; + private readonly GameBase game; private bool deviceSettingsChanged; @@ -100,12 +100,12 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game, GameContext context = null) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) { - throw new ArgumentNullException("game"); + throw new ArgumentNullException(nameof(game)); } lockDeviceCreation = new object(); @@ -119,8 +119,8 @@ public GraphicsDeviceManager(GameBase game, GameContext context = null) preferredBackBufferHeight = DefaultBackBufferHeight; preferredRefreshRate = new Rational(60, 1); PreferredMultisampleCount = MultisampleCount.None; - PreferredGraphicsProfile = new[] - { + PreferredGraphicsProfile = + [ GraphicsProfile.Level_11_1, GraphicsProfile.Level_11_0, GraphicsProfile.Level_10_1, @@ -128,7 +128,7 @@ public GraphicsDeviceManager(GameBase game, GameContext context = null) GraphicsProfile.Level_9_3, GraphicsProfile.Level_9_2, GraphicsProfile.Level_9_1, - }; + ]; graphicsDeviceFactory = game.Services.GetService(); if (graphicsDeviceFactory == null) diff --git a/sources/engine/Stride.Games/IGame.cs b/sources/engine/Stride.Games/IGame.cs index 8e55414ba2..5788899fcd 100644 --- a/sources/engine/Stride.Games/IGame.cs +++ b/sources/engine/Stride.Games/IGame.cs @@ -140,8 +140,10 @@ public interface IGame /// The window. GameWindow Window { get; } - public void SetWindow(GameWindow window); - + /// + /// Sets the game context. + /// + /// public void SetGameContext(GameContext context); } } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 7c91017ac3..7793f87679 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -318,7 +318,7 @@ public void Initialize(GameContext gameContext) { this.gameContext = gameContext ?? throw new ArgumentNullException(nameof(gameContext)); - AddSources(); + //AddSources(); // After adding initial devices, reassign gamepad id's // this creates a beter index assignment in the case where you have both an xbox controller and another controller at startup @@ -626,14 +626,15 @@ public void PoolInputEvent(InputEvent inputEvent) { eventRouters[inputEvent.GetType()].PoolEvent(inputEvent); } - + /// /// Resets the collection back to it's default values /// + [Obsolete] public void ResetSources() { Sources.Clear(); - AddSources(); + //AddSources(); } /// diff --git a/sources/engine/Stride.Input/SDL/InputSourceSDL.cs b/sources/engine/Stride.Input/SDL/InputSourceSDL.cs index 7b33c0afb0..328cb58cad 100644 --- a/sources/engine/Stride.Input/SDL/InputSourceSDL.cs +++ b/sources/engine/Stride.Input/SDL/InputSourceSDL.cs @@ -14,7 +14,7 @@ namespace Stride.Input /// /// Provides support for mouse/touch/keyboard/gamepads using SDL /// - internal unsafe class InputSourceSDL : InputSourceBase + public unsafe class InputSourceSDL : InputSourceBase { private static Sdl SDL = Window.SDL; diff --git a/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs b/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs index 41179232e5..8023f0459f 100644 --- a/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs +++ b/sources/engine/Stride.Input/Windows/InputSourceWinforms.cs @@ -18,7 +18,7 @@ namespace Stride.Input /// /// Provides support for mouse and keyboard input on windows forms /// - internal class InputSourceWinforms : InputSourceBase + public class InputSourceWinforms : InputSourceBase { private readonly HashSet heldKeys = new HashSet(); private readonly List keysToRelease = new List(); From 52e78bf3432508551f9a6210728839cd50ee105d Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 11 May 2025 20:17:18 -0600 Subject: [PATCH 51/92] Separated input --- sources/Directory.Packages.props | 3 +- sources/core/Stride.Core/IServiceRegistry.cs | 9 +++ sources/core/Stride.Core/ServiceRegistry.cs | 16 ++++ .../Engine/Builder/GameBuilder.cs | 76 +++++++++++++++++-- .../Engine/Builder/GameBuilderExtensions.cs | 49 ++++++++---- .../Engine/Builder/IGameBuilder.cs | 15 +++- .../Engine/Builder/MinimalGame.cs | 18 ++++- .../Engine/Hosting/IStrideBuilder.cs | 16 ++++ .../Engine/Hosting/StrideBuilder.cs | 52 +++++++++++++ .../engine/Stride.Engine/Stride.Engine.csproj | 2 + 10 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index a3f81c9c5a..649fd2d1cc 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -12,6 +12,7 @@ + @@ -150,4 +151,4 @@ - \ No newline at end of file + diff --git a/sources/core/Stride.Core/IServiceRegistry.cs b/sources/core/Stride.Core/IServiceRegistry.cs index c2b564561a..9f25c94df1 100644 --- a/sources/core/Stride.Core/IServiceRegistry.cs +++ b/sources/core/Stride.Core/IServiceRegistry.cs @@ -47,6 +47,15 @@ public interface IServiceRegistry /// Thrown when a service of the same type is already registered. void AddService(T service) where T : class; + /// + /// Adds a service to this . + /// + /// The service to add. + /// The type to register as. + /// Thrown when the provided service is null. + /// Thrown when a service of the same type is already registered. + void AddService(object service, Type type); + /// /// Gets the service object of the specified type. /// diff --git a/sources/core/Stride.Core/ServiceRegistry.cs b/sources/core/Stride.Core/ServiceRegistry.cs index 09b7543516..ca5dcede37 100644 --- a/sources/core/Stride.Core/ServiceRegistry.cs +++ b/sources/core/Stride.Core/ServiceRegistry.cs @@ -76,6 +76,22 @@ public void AddService(T service) OnServiceAdded(new ServiceEventArgs(type, service)); } + /// + /// + /// This implementation triggers the event after a service is successfully added. + /// + public void AddService(object service, Type type) + { + ArgumentNullException.ThrowIfNull(service); + + lock (registeredService) + { + if (!registeredService.TryAdd(type, service)) + throw new ArgumentException("Service is already registered with this type", nameof(type)); + } + OnServiceAdded(new ServiceEventArgs(type, service)); + } + /// /// /// This implementation triggers the event after a service is successfully removed. diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 28001c7729..82affae29c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,7 +1,12 @@ +using System; using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; +using Stride.Core.IO; using Stride.Games; +using Stride.Input; namespace Stride.Engine.Builder; @@ -11,19 +16,28 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { - public IServiceRegistry Services { get; protected set; } + public Dictionary Services { get; internal set; } = []; - public GameSystemCollection GameSystems { get; protected set; } + public IServiceCollection DiServices { get; internal set; } = new ServiceCollection(); - public List LogListeners { get; protected set; } = []; + public GameSystemCollection GameSystems { get; internal set; } - public GameBase Game { get; protected set; } + public List LogListeners { get; internal set; } = []; + + public List InputSources { get; internal set; } = []; + + public DatabaseFileProvider DatabaseFileProvider { get; set; } + + public GameBase Game { get; set; } + + public GameContext Context { get; set; } internal GameBuilder() { Game = new MinimalGame(null); - Services = Game.Services; GameSystems = Game.GameSystems; + DiServices.AddSingleton(Game.Services); + Services.Add(typeof(IServiceRegistry), Game.Services); } public static GameBuilder Create() @@ -33,11 +47,63 @@ public static GameBuilder Create() public virtual GameBase Build() { + var provider = DiServices.BuildServiceProvider(); + foreach (var service in Services) + { + if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) + continue; + + try + { + if (service.Value == null) + { + var instance = provider.GetService(service.Key); + Game.Services.AddService(instance, service.Key); + Services[service.Key] = instance; + } + else + { + Game.Services.AddService(service.Value, service.Key); + } + } + catch (Exception ex) + { + // TODO: check if service is already registered first. + } + } + + // Add all game systems to the game. + foreach (var service in Services) + { + var system = provider.GetService(service.Key); + if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) + { + Game.GameSystems.Add(gameSystem); + } + } + foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } + if (Context != null) + { + Game.SetGameContext(Context); + } + + if(InputSources.Count > 0) + { + var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + foreach (var inputSource in InputSources) + { + inputManager.Sources.Add(inputSource); + } + } + + var dataBase = Game.Services.GetService(); + dataBase.FileProvider = DatabaseFileProvider; + return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 0b45d86da8..83b0d1af70 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,12 +1,20 @@ using System; +using Microsoft.Extensions.DependencyInjection; +using Stride.Audio; +using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; +using Stride.Engine.Processors; using Stride.Games; using Stride.Input; +using Stride.Profiling; using Stride.Rendering; +using Stride.Rendering.Fonts; +using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; +using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions @@ -19,7 +27,15 @@ public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gam public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { - gameBuilder.Services.AddService(service); + gameBuilder.Services.Add(typeof(T), service); + gameBuilder.DiServices.AddSingleton(service); + return gameBuilder; + } + + public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class + { + gameBuilder.Services.Add(typeof(T), null); + gameBuilder.DiServices.AddSingleton(); return gameBuilder; } @@ -29,6 +45,20 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + + var inputSystem = new InputSystem(services); + + gameBuilder + .AddGameSystem(inputSystem) + .AddService(inputSystem) + .AddService(inputSystem.Manager); + + return gameBuilder; + } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); @@ -44,8 +74,7 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. - var dataBase = gameBuilder.Services.GetService(); - dataBase.FileProvider = provider; + gameBuilder.DatabaseFileProvider = provider; return gameBuilder; } @@ -73,7 +102,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services; + var services = gameBuilder.Game.Services; var content = new ContentManager(services); services.AddService(content); services.AddService(content); @@ -106,22 +135,12 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); - return gameBuilder; } public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) { - var inputManager = gameBuilder.Services.GetService(); - - if (inputManager == null) - { - throw new InvalidOperationException("InputManager is not registered in the service registry."); - } - - inputManager.Sources.Add(inputSource); - + gameBuilder.InputSources.Add(inputSource); return gameBuilder; } - } diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index f658479a7b..9bb6a0060a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -1,16 +1,27 @@ using System.Collections.Generic; using Stride.Core.Diagnostics; -using Stride.Core; using Stride.Games; +using System; +using Microsoft.Extensions.DependencyInjection; +using Stride.Input; +using Stride.Core.IO; namespace Stride.Engine.Builder; public interface IGameBuilder { - IServiceRegistry Services { get; } + Dictionary Services { get; } + + IServiceCollection DiServices { get; } GameSystemCollection GameSystems { get; } List LogListeners { get; } + List InputSources { get; } + + DatabaseFileProvider DatabaseFileProvider { get; set; } + GameBase Game { get; } + + GameContext Context { get; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 62e77076ea..ec51270191 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,4 +1,7 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; using Stride.Core.Diagnostics; using Stride.Core.Serialization; using Stride.Core.Serialization.Contents; @@ -11,7 +14,7 @@ namespace Stride.Engine.Builder; /// /// A game class with no registered systems by default. /// -public class MinimalGame : GameBase +public class MinimalGame : GameBase, IHostedService { /// @@ -85,4 +88,17 @@ protected override void PrepareContext() Content = contentManager; } + + public Task StartAsync(CancellationToken cancellationToken = default) + { + Run(); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken = default) + { + Exit(); + return Task.CompletedTask; + } + } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs new file mode 100644 index 0000000000..9de0f50191 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public interface IStrideBuilder : IHostBuilder +{ + /// + /// Gets the game context. + /// + GameContext Context { get; } + /// + /// Gets the game. + /// + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs new file mode 100644 index 0000000000..f6bffe3367 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public class StrideBuilder : IStrideBuilder +{ + public GameContext Context { get; set; } + + public GameBase Game { get; set; } + + public IDictionary Properties { get; set; } + + public IHost Build() + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureContainer(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureServices(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } +} diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 7bded5b689..234f39796f 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -26,8 +26,10 @@ + + From cc1234aeb02d9d67f16959805e4789623109d5a4 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Mon, 12 May 2025 15:47:29 -0600 Subject: [PATCH 52/92] clean up and docs --- .../Engine/Builder/GameBuilder.cs | 16 +++- .../Engine/Builder/GameBuilderExtensions.cs | 87 ++++++++++++++----- .../Engine/Builder/IGameBuilder.cs | 4 +- .../Engine/Hosting/IStrideBuilder.cs | 16 ---- .../Engine/Hosting/StrideBuilder.cs | 52 ----------- 5 files changed, 82 insertions(+), 93 deletions(-) delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 82affae29c..af4d652806 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; @@ -58,6 +57,21 @@ public virtual GameBase Build() if (service.Value == null) { var instance = provider.GetService(service.Key); + + if(instance == null) + { + //check if the type is inherited from another instance in the services. + foreach (var kvp in Services) + { + if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) + { + instance = provider.GetService(kvp.Key); + if(instance is not null) + break; + } + } + } + Game.Services.AddService(instance, service.Key); Services[service.Key] = instance; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 83b0d1af70..2a1fe0d064 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,30 +1,39 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Stride.Audio; using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; -using Stride.Engine.Processors; using Stride.Games; using Stride.Input; -using Stride.Profiling; using Stride.Rendering; -using Stride.Rendering.Fonts; -using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; -using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions { + + /// + /// Adds cire systems to the game. Does not register the systems into the + /// + /// + /// + /// + /// public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gameSystem) where T : IGameSystemBase { gameBuilder.GameSystems.Add(gameSystem); return gameBuilder; } + /// + /// Registers a service into the . + /// + /// + /// + /// + /// public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { gameBuilder.Services.Add(typeof(T), service); @@ -32,6 +41,12 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder, T servic return gameBuilder; } + /// + /// Registers a service into the . + /// + /// + /// + /// public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class { gameBuilder.Services.Add(typeof(T), null); @@ -39,13 +54,41 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T return gameBuilder; } + /// + /// Registers a service and its interface into the . + /// + /// + /// + /// + /// + public static IGameBuilder AddService(this IGameBuilder gameBuilder) where TClass : class, TInterface where TInterface : class + { + // This is a work around to allow DI to work the same way as the ServiceRegistry expects. + // Without registering both the interface and the class, the DI will not be able to resolve the interface on build. + gameBuilder.Services.Add(typeof(TInterface), null); + gameBuilder.Services.Add(typeof(TClass), null); + gameBuilder.DiServices.AddSingleton(); + return gameBuilder; + } + + /// + /// Adds a log listener to the game. This is used thoughout Stride systems for logging events. + /// + /// + /// + /// public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogListener logListener) { gameBuilder.LogListeners.Add(logListener); return gameBuilder; } - public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + /// + /// Adds the Stride input system to the game with no sources. + /// + /// + /// + public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; @@ -61,17 +104,17 @@ public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { - gameBuilder.Game.SetGameContext(context); + gameBuilder.Context = context; return gameBuilder; } /// - /// Allows the user to add a custom database file provider to the game. + /// Add a custom database file provider to the game. /// /// /// /// - public static IGameBuilder AddDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) + public static IGameBuilder SetDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. gameBuilder.DatabaseFileProvider = provider; @@ -94,7 +137,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) var mountPath = VirtualFileSystem.ResolveProviderUnsafe("/asset", true).Provider == null ? "/asset" : null; var result = new DatabaseFileProvider(objDatabase, mountPath); - gameBuilder.AddDbFileProvider(result); + gameBuilder.SetDbFileProvider(result); } return gameBuilder; @@ -112,11 +155,11 @@ public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilde /// /// Adds a default effect compiler to the game. This is used to compile shaders and effects. /// - /// + /// /// /// /// - public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectCompiler, IVirtualFileProvider fileProvider) + public static EffectSystem CreateDefaultEffectCompiler(this EffectSystem effectSystem, IVirtualFileProvider fileProvider) { EffectCompilerBase compiler = new EffectCompiler(fileProvider) { @@ -125,20 +168,20 @@ public static EffectSystem AddDefaultEffectCompiler(this EffectSystem effectComp if(fileProvider is DatabaseFileProvider databaseFileProvider) { - effectCompiler.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); - return effectCompiler; + effectSystem.Compiler = new EffectCompilerCache(compiler, databaseFileProvider); + return effectSystem; } throw new ArgumentException("The file provider must be a DatabaseFileProvider", nameof(fileProvider)); } - public static IGameBuilder UseGameContext(this IGameBuilder gameBuilder, GameContext context) - { - gameBuilder.Game.SetGameContext(context); - return gameBuilder; - } - - public static IGameBuilder AddInput(this IGameBuilder gameBuilder, IInputSource inputSource) + /// + /// Adds an input source to the game. This requires the Stride input system to be used. + /// + /// + /// + /// + public static IGameBuilder AddStrideInputSource(this IGameBuilder gameBuilder, IInputSource inputSource) { gameBuilder.InputSources.Add(inputSource); return gameBuilder; diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index 9bb6a0060a..7b1d916455 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -21,7 +21,7 @@ public interface IGameBuilder DatabaseFileProvider DatabaseFileProvider { get; set; } - GameBase Game { get; } + GameBase Game { get; set; } - GameContext Context { get; } + GameContext Context { get; set; } } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs deleted file mode 100644 index 9de0f50191..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public interface IStrideBuilder : IHostBuilder -{ - /// - /// Gets the game context. - /// - GameContext Context { get; } - /// - /// Gets the game. - /// - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs deleted file mode 100644 index f6bffe3367..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public class StrideBuilder : IStrideBuilder -{ - public GameContext Context { get; set; } - - public GameBase Game { get; set; } - - public IDictionary Properties { get; set; } - - public IHost Build() - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureContainer(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureServices(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } -} From a08ccec687e35341b9038d7d53335a9c6539347d Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 14:53:08 -0600 Subject: [PATCH 53/92] Kryptos feedback --- sources/Directory.Packages.props | 4 +--- sources/editor/Stride.Editor/Preview/PreviewGame.cs | 10 +++++----- sources/engine/Stride.Input/InputManager.cs | 6 ++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 649fd2d1cc..c55910cdfd 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,9 +11,7 @@ - - - + diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index 143ab1c307..b7a5a8c9f1 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -2,19 +2,19 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Threading.Tasks; -using Stride.Core.BuildEngine; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Core.Mathematics; using Stride.Assets; using Stride.Assets.SpriteFont; using Stride.Assets.SpriteFont.Compiler; +using Stride.Core; +using Stride.Core.BuildEngine; +using Stride.Core.Diagnostics; +using Stride.Core.Mathematics; using Stride.Engine; using Stride.Engine.Design; +using Stride.Games; using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; -using Stride.Games; namespace Stride.Editor.Preview { diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 7793f87679..eb9e1d788c 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -318,8 +318,6 @@ public void Initialize(GameContext gameContext) { this.gameContext = gameContext ?? throw new ArgumentNullException(nameof(gameContext)); - //AddSources(); - // After adding initial devices, reassign gamepad id's // this creates a beter index assignment in the case where you have both an xbox controller and another controller at startup var sortedGamePads = GamePads.OrderBy(x => x.CanChangeIndex); @@ -630,11 +628,11 @@ public void PoolInputEvent(InputEvent inputEvent) /// /// Resets the collection back to it's default values /// - [Obsolete] + [Obsolete("This should be managed manually instead by using the Sources collection")] public void ResetSources() { Sources.Clear(); - //AddSources(); + AddSources(); } /// From f2ab0be34cc4feb748650120719f348d015a088e Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 15:10:04 -0600 Subject: [PATCH 54/92] missed some duplicate packages --- sources/Directory.Packages.props | 2 +- sources/engine/Stride.Engine/Stride.Engine.csproj | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index c55910cdfd..9937848ac4 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -11,7 +11,7 @@ - + diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 234f39796f..7836b61cf4 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -29,7 +29,6 @@ - From cf1ede161e96b15a9966d3579c73153ea57e930d Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 18:16:47 -0600 Subject: [PATCH 55/92] add option for DI in GameFontSystem --- .../engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs b/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs index 0db5f3866f..570f6895b3 100644 --- a/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs +++ b/sources/engine/Stride.Rendering/Rendering/Fonts/GameFontSystem.cs @@ -15,11 +15,11 @@ public class GameFontSystem : GameSystemBase { public FontSystem FontSystem { get; private set; } - public GameFontSystem(IServiceRegistry registry) + public GameFontSystem(IServiceRegistry registry, FontSystem fontSystem = null) : base(registry) { Visible = true; - FontSystem = new FontSystem(); + FontSystem = fontSystem ?? new FontSystem(); } public override void Draw(GameTime gameTime) From 1fc428e678822685996c65e6a57c6325a8ccb969 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 19:37:36 -0600 Subject: [PATCH 56/92] Fix error caused by StreamingManager DI. --- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 14 ++++++++------ sources/engine/Stride.Engine/Engine/Game.cs | 3 +++ .../Stride.Rendering/Streaming/StreamingManager.cs | 5 ++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index af4d652806..c3b6cbc3ec 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -46,6 +46,12 @@ public static GameBuilder Create() public virtual GameBase Build() { + + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + var provider = DiServices.BuildServiceProvider(); foreach (var service in Services) { @@ -82,7 +88,8 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first. + // TODO: check if service is already registered first.' + GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -96,11 +103,6 @@ public virtual GameBase Build() } } - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - if (Context != null) { Game.SetGameContext(Context); diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 0094175372..dbaaab9489 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,10 +11,12 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; +using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; +using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; @@ -220,6 +222,7 @@ public Game(GameContext context = null) : base() Services.AddService(SceneSystem); Streaming = new StreamingManager(Services); + Services.AddService(Streaming); Audio = new AudioSystem(Services); Services.AddService(Audio); diff --git a/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs b/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs index 394c791ec6..21ca774303 100644 --- a/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs +++ b/sources/engine/Stride.Rendering/Streaming/StreamingManager.cs @@ -92,9 +92,8 @@ public class StreamingManager : GameSystemBase, IStreamingManager, ITexturesStre public StreamingManager([NotNull] IServiceRegistry services) : base(services) { - services.AddService(this); - services.AddService(this); - services.AddService(this); + Services.AddService(this); + Services.AddService(this); ContentStreaming = new ContentStreamingService(); From b98d3864739046bb10d9cade33ec1cd64c5c3bf8 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:01:50 -0600 Subject: [PATCH 57/92] renaming to favour ServiceCollection --- .../Engine/Builder/GameBuilder.cs | 19 +++++++++---------- .../Engine/Builder/GameBuilderExtensions.cs | 16 ++++++++-------- .../Engine/Builder/IGameBuilder.cs | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index c3b6cbc3ec..092440c1bc 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,9 +15,9 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { - public Dictionary Services { get; internal set; } = []; + public Dictionary InternalServices { get; internal set; } = []; - public IServiceCollection DiServices { get; internal set; } = new ServiceCollection(); + public IServiceCollection Services { get; internal set; } = new ServiceCollection(); public GameSystemCollection GameSystems { get; internal set; } @@ -35,8 +35,8 @@ internal GameBuilder() { Game = new MinimalGame(null); GameSystems = Game.GameSystems; - DiServices.AddSingleton(Game.Services); - Services.Add(typeof(IServiceRegistry), Game.Services); + Services.AddSingleton(Game.Services); + InternalServices.Add(typeof(IServiceRegistry), Game.Services); } public static GameBuilder Create() @@ -46,14 +46,13 @@ public static GameBuilder Create() public virtual GameBase Build() { - foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } - var provider = DiServices.BuildServiceProvider(); - foreach (var service in Services) + var provider = Services.BuildServiceProvider(); + foreach (var service in InternalServices) { if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) continue; @@ -67,7 +66,7 @@ public virtual GameBase Build() if(instance == null) { //check if the type is inherited from another instance in the services. - foreach (var kvp in Services) + foreach (var kvp in InternalServices) { if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) { @@ -79,7 +78,7 @@ public virtual GameBase Build() } Game.Services.AddService(instance, service.Key); - Services[service.Key] = instance; + InternalServices[service.Key] = instance; } else { @@ -94,7 +93,7 @@ public virtual GameBase Build() } // Add all game systems to the game. - foreach (var service in Services) + foreach (var service in InternalServices) { var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 2a1fe0d064..702d8f1912 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -36,8 +36,8 @@ public static IGameBuilder AddGameSystem(this IGameBuilder gameBuilder, T gam /// public static IGameBuilder AddService(this IGameBuilder gameBuilder, T service) where T : class { - gameBuilder.Services.Add(typeof(T), service); - gameBuilder.DiServices.AddSingleton(service); + gameBuilder.InternalServices.Add(typeof(T), service); + gameBuilder.Services.AddSingleton(service); return gameBuilder; } @@ -49,8 +49,8 @@ public static IGameBuilder AddService(this IGameBuilder gameBuilder, T servic /// public static IGameBuilder AddService(this IGameBuilder gameBuilder) where T : class { - gameBuilder.Services.Add(typeof(T), null); - gameBuilder.DiServices.AddSingleton(); + gameBuilder.InternalServices.Add(typeof(T), null); + gameBuilder.Services.AddSingleton(); return gameBuilder; } @@ -65,9 +65,9 @@ public static IGameBuilder AddService(this IGameBuilder game { // This is a work around to allow DI to work the same way as the ServiceRegistry expects. // Without registering both the interface and the class, the DI will not be able to resolve the interface on build. - gameBuilder.Services.Add(typeof(TInterface), null); - gameBuilder.Services.Add(typeof(TClass), null); - gameBuilder.DiServices.AddSingleton(); + gameBuilder.InternalServices.Add(typeof(TInterface), null); + gameBuilder.InternalServices.Add(typeof(TClass), null); + gameBuilder.Services.AddSingleton(); return gameBuilder; } @@ -90,7 +90,7 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList /// public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + var services = gameBuilder.InternalServices[typeof(IServiceRegistry)] as IServiceRegistry; var inputSystem = new InputSystem(services); diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index 7b1d916455..a56c041060 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -9,9 +9,9 @@ namespace Stride.Engine.Builder; public interface IGameBuilder { - Dictionary Services { get; } + Dictionary InternalServices { get; } - IServiceCollection DiServices { get; } + IServiceCollection Services { get; } GameSystemCollection GameSystems { get; } From c9b912f39ad2a1785bffc16607a2cfb3e0f6d6fb Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:06:39 -0600 Subject: [PATCH 58/92] typo --- .../Stride.Engine/Engine/Builder/GameBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 702d8f1912..5e09032a5a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -15,7 +15,7 @@ public static class GameBuilderExtensions { /// - /// Adds cire systems to the game. Does not register the systems into the + /// Adds core systems to the game. Does not register the systems into the /// /// /// From 701d708e61c438ab44b50179b4a013b633ebd98a Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:43:14 -0600 Subject: [PATCH 59/92] docs --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 092440c1bc..fee0db5890 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,8 +15,14 @@ namespace Stride.Engine.Builder; /// public class GameBuilder : IGameBuilder { + /// + /// This is used to allow the same instance to be registered multiple times as differenet interfaces or types. This was done due to how works."/> + /// public Dictionary InternalServices { get; internal set; } = []; + /// + /// This allows for Service to be registered through DI. + /// public IServiceCollection Services { get; internal set; } = new ServiceCollection(); public GameSystemCollection GameSystems { get; internal set; } From 02c81e361e439800d765c00ec620a8b627d7341d Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:53:31 -0600 Subject: [PATCH 60/92] docs --- .../Engine/Builder/GameBuilder.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index fee0db5890..ec4a2dd27e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -10,7 +10,7 @@ namespace Stride.Engine.Builder; /// -/// Helps build the game and preps it to be able to run after built. +/// Helps build the game and preps it to be able to run after . /// /// public class GameBuilder : IGameBuilder @@ -25,10 +25,19 @@ public class GameBuilder : IGameBuilder /// public IServiceCollection Services { get; internal set; } = new ServiceCollection(); + /// + /// This is a direct reference to the game systems collection of the game. + /// public GameSystemCollection GameSystems { get; internal set; } + /// + /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur."/> + /// public List LogListeners { get; internal set; } = []; + /// + /// Adds input sources to the game on . + /// public List InputSources { get; internal set; } = []; public DatabaseFileProvider DatabaseFileProvider { get; set; } @@ -37,17 +46,21 @@ public class GameBuilder : IGameBuilder public GameContext Context { get; set; } - internal GameBuilder() + internal GameBuilder(GameBase game) { - Game = new MinimalGame(null); + Game = game ?? new MinimalGame(null); GameSystems = Game.GameSystems; Services.AddSingleton(Game.Services); InternalServices.Add(typeof(IServiceRegistry), Game.Services); } - public static GameBuilder Create() + /// + /// Creates a new instance of the class. + /// + /// + public static GameBuilder Create(GameBase game = null) { - return new GameBuilder(); + return new GameBuilder(game); } public virtual GameBase Build() From 0fcec851c1ccda2c24f4c049151d00dce05a8c70 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 12:42:05 -0600 Subject: [PATCH 61/92] clean up and build logging --- .../Engine/Builder/GameBuilder.cs | 27 ++++++++++++------- .../Engine/Builder/GameBuilderExtensions.cs | 4 ++- .../Engine/Builder/IGameBuilder.cs | 2 -- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index ec4a2dd27e..0e0fd4fa3c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; -using Stride.Core.IO; using Stride.Games; using Stride.Input; @@ -26,7 +25,7 @@ public class GameBuilder : IGameBuilder public IServiceCollection Services { get; internal set; } = new ServiceCollection(); /// - /// This is a direct reference to the game systems collection of the game. + /// This is a direct reference to the game systems collection of the . /// public GameSystemCollection GameSystems { get; internal set; } @@ -40,12 +39,12 @@ public class GameBuilder : IGameBuilder /// public List InputSources { get; internal set; } = []; - public DatabaseFileProvider DatabaseFileProvider { get; set; } - public GameBase Game { get; set; } public GameContext Context { get; set; } + private static Logger _log => GlobalLogger.GetLogger("GameBuilder"); + internal GameBuilder(GameBase game) { Game = game ?? new MinimalGame(null); @@ -96,18 +95,20 @@ public virtual GameBase Build() } } + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(instance, service.Key); InternalServices[service.Key] = instance; } else { + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(service.Value, service.Key); } } catch (Exception ex) { // TODO: check if service is already registered first.' - GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); + _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -117,27 +118,35 @@ public virtual GameBase Build() var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) { + _log.Info($"Adding game system {gameSystem.GetType().Name} to the game systems collection."); Game.GameSystems.Add(gameSystem); } } if (Context != null) { + _log.Info($"Setting game context."); Game.SetGameContext(Context); } if(InputSources.Count > 0) { - var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + var inputManager = Game.Services.GetService(); + + if (inputManager is null) + { + _log.Info("No InputManager found in the game services, creating default."); + inputManager = new InputManager(); + Game.Services.AddService(inputManager); + } + foreach (var inputSource in InputSources) { + _log.Info($"Adding input source {inputSource.GetType().Name} to the input manager."); inputManager.Sources.Add(inputSource); } } - var dataBase = Game.Services.GetService(); - dataBase.FileProvider = DatabaseFileProvider; - return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 5e09032a5a..200289b29c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -117,7 +117,9 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon public static IGameBuilder SetDbFileProvider(this IGameBuilder gameBuilder, DatabaseFileProvider provider) { // Gets initialized by the GameBase constructor. - gameBuilder.DatabaseFileProvider = provider; + var fileProviderService = gameBuilder.Game.Services.GetService(); + + fileProviderService.FileProvider = provider; return gameBuilder; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index a56c041060..eba6f13b5b 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -19,8 +19,6 @@ public interface IGameBuilder List InputSources { get; } - DatabaseFileProvider DatabaseFileProvider { get; set; } - GameBase Game { get; set; } GameContext Context { get; set; } From cfe5845f65111b7fa788d87a1783e8133d82f5a4 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 18:49:07 -0600 Subject: [PATCH 62/92] remove some hardcoded Game references --- .../Stride.Debugger/Debugger/LiveAssemblyReloader.cs | 11 ++++++----- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 4 ++-- sources/engine/Stride.Engine/Engine/Game.cs | 2 -- sources/engine/Stride.Engine/Engine/GameSystem.cs | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs b/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs index 67c314e85f..bb4d910626 100644 --- a/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs +++ b/sources/engine/Stride.Debugger/Debugger/LiveAssemblyReloader.cs @@ -1,29 +1,30 @@ -// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using Stride.Core; using Stride.Core.Reflection; -using Stride.Core.Serialization; using Stride.Core.Yaml; using Stride.Core.Yaml.Events; using Stride.Core.Yaml.Serialization; using Stride.Debugger.Target; using Stride.Engine; +using Stride.Games; namespace Stride.Debugger { public static class LiveAssemblyReloader { - public static void Reload(Game game, AssemblyContainer assemblyContainer, List assembliesToUnregister, List assembliesToRegister) + public static void Reload(GameBase game, AssemblyContainer assemblyContainer, List assembliesToUnregister, List assembliesToRegister) { List entities = new List(); + var sceneSystem = game.Services.GetSafeServiceAs(); + if (game != null) - entities.AddRange(game.SceneSystem.SceneInstance); + entities.AddRange(sceneSystem.SceneInstance); CloneReferenceSerializer.References = new List(); diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 0e0fd4fa3c..0469f99e15 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -107,7 +107,7 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first.' + // TODO: check if service is already registered first. _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -147,6 +147,6 @@ public virtual GameBase Build() } } - return Game; + return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index dbaaab9489..7064d566e6 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,12 +11,10 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; -using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; -using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; diff --git a/sources/engine/Stride.Engine/Engine/GameSystem.cs b/sources/engine/Stride.Engine/Engine/GameSystem.cs index 3ea3a8f9ec..545609b8c9 100644 --- a/sources/engine/Stride.Engine/Engine/GameSystem.cs +++ b/sources/engine/Stride.Engine/Engine/GameSystem.cs @@ -19,6 +19,6 @@ protected GameSystem(IServiceRegistry registry) : base(registry) /// /// The game. /// This value can be null - public new Game Game => (Game)base.Game; + public new GameBase Game => base.Game; } } From 16e199614006a92ac45da169a800fdf3459ba0a6 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sat, 19 Jul 2025 20:45:59 -0600 Subject: [PATCH 63/92] GameWindowTest --- .../Engine/Builder/GameBuilder.cs | 2 +- .../Stride.Games/Windowing/IGameWindow.cs | 23 +++++++++++++++++++ .../Stride.Games/Windowing/IStrideSurface.cs | 8 +++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 sources/engine/Stride.Games/Windowing/IGameWindow.cs create mode 100644 sources/engine/Stride.Games/Windowing/IStrideSurface.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 0469f99e15..5c9f60db0c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -43,7 +43,7 @@ public class GameBuilder : IGameBuilder public GameContext Context { get; set; } - private static Logger _log => GlobalLogger.GetLogger("GameBuilder"); + private static Logger _log => GlobalLogger.GetLogger(nameof(GameBuilder)); internal GameBuilder(GameBase game) { diff --git a/sources/engine/Stride.Games/Windowing/IGameWindow.cs b/sources/engine/Stride.Games/Windowing/IGameWindow.cs new file mode 100644 index 0000000000..643b1d6ac9 --- /dev/null +++ b/sources/engine/Stride.Games/Windowing/IGameWindow.cs @@ -0,0 +1,23 @@ +using System; +using Stride.Core.Mathematics; + +namespace Stride.Games.Windowing; +public interface IGameWindow : IStrideSurface +{ + public IntPtr WindowHandle { get; } + public Int2 Position { get; set; } + public Int2 Size { get; set; } + + public string Title { get; set; } + + public WindowState State { get; set; } +} + +public enum WindowState +{ + Normal, + Minimized, + Maximized, + FullscreenWindowed, + FullscreenExclusive, +} diff --git a/sources/engine/Stride.Games/Windowing/IStrideSurface.cs b/sources/engine/Stride.Games/Windowing/IStrideSurface.cs new file mode 100644 index 0000000000..7e7481ff54 --- /dev/null +++ b/sources/engine/Stride.Games/Windowing/IStrideSurface.cs @@ -0,0 +1,8 @@ +using System; +using Stride.Core.Mathematics; + +namespace Stride.Games.Windowing; +public interface IStrideSurface +{ + public Int2 Size { get; set; } +} From e2a2774ecd2f1a48c2260fdcbad75703cfdbeb7b Mon Sep 17 00:00:00 2001 From: Donovan Prezeau Date: Thu, 8 May 2025 15:04:01 -0600 Subject: [PATCH 64/92] initial PoC --- sources/Directory.Packages.props | 2 +- .../Engine/Builder/GameBuilder.cs | 6 +-- .../Engine/Builder/GameBuilderExtensions.cs | 2 +- .../Engine/Builder/IGameBuilder.cs | 1 + sources/engine/Stride.Hosting/BasicGame.cs | 42 +++++++++++++++++++ .../Stride.Hosting/IStrideGameBuilder.cs | 16 +++++++ .../Stride.Hosting/Stride.Hosting.csproj | 28 +++++++++++++ .../Stride.Hosting/StrideGameBuilder.cs | 39 +++++++++++++++++ 8 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 sources/engine/Stride.Hosting/BasicGame.cs create mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs create mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj create mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index 9937848ac4..eba00a873d 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -149,4 +149,4 @@ - + \ No newline at end of file diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 5c9f60db0c..16d46b196e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -127,7 +127,7 @@ public virtual GameBase Build() { _log.Info($"Setting game context."); Game.SetGameContext(Context); - } + } if(InputSources.Count > 0) { @@ -138,10 +138,10 @@ public virtual GameBase Build() _log.Info("No InputManager found in the game services, creating default."); inputManager = new InputManager(); Game.Services.AddService(inputManager); - } +} foreach (var inputSource in InputSources) - { +{ _log.Info($"Adding input source {inputSource.GetType().Name} to the input manager."); inputManager.Sources.Add(inputSource); } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 200289b29c..749487e572 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -143,7 +143,7 @@ public static IGameBuilder UseDefaultDb(this IGameBuilder gameBuilder) } return gameBuilder; - } + } public static IGameBuilder UseDefaultContentManager(this IGameBuilder gameBuilder) { diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index eba6f13b5b..e14553734a 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Stride.Core.Diagnostics; +using Stride.Core; using Stride.Games; using System; using Microsoft.Extensions.DependencyInjection; diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs new file mode 100644 index 0000000000..1b599d454c --- /dev/null +++ b/sources/engine/Stride.Hosting/BasicGame.cs @@ -0,0 +1,42 @@ +using System; +using Stride.Core.Serialization; +using Stride.Games; +using Stride.Graphics; + +namespace Stride.Hosting; +public class BasicGame : GameBase +{ + + /// + /// Gets the graphics device manager. + /// + /// The graphics device manager. + public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } + + public BasicGame() + { + // Creates the graphics device manager + GraphicsDeviceManager = new GraphicsDeviceManager(this); + Services.AddService(GraphicsDeviceManager); + Services.AddService(GraphicsDeviceManager); + } + + public override void ConfirmRenderingSettings(bool gameCreation) + { + var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; + + if (gameCreation) + { + //if our device width or height is actually smaller then requested we use the device one + deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); + deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); + } + } + + protected override void Initialize() + { + base.Initialize(); + + Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); + } +} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs new file mode 100644 index 0000000000..3326ba14fb --- /dev/null +++ b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Stride.Core; +using Stride.Core.Diagnostics; +using Stride.Games; + +namespace Stride.Hosting; +public interface IStrideGameBuilder +{ + public IServiceRegistry Services { get; } + + GameSystemCollection GameSystems { get; } + + List LogListeners { get; } + + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj new file mode 100644 index 0000000000..dbf6858a2e --- /dev/null +++ b/sources/engine/Stride.Hosting/Stride.Hosting.csproj @@ -0,0 +1,28 @@ + + + + true + + + + true + true + * + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs new file mode 100644 index 0000000000..0ba4f91eda --- /dev/null +++ b/sources/engine/Stride.Hosting/StrideGameBuilder.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Stride.Core.Diagnostics; +using Stride.Games; +using Stride.Core; + +namespace Stride.Hosting; +public class StrideGameBuilder : IStrideGameBuilder +{ + public IServiceRegistry Services { get; protected set; } + + public GameSystemCollection GameSystems { get; protected set; } + + public List LogListeners { get; protected set; } = []; + + public GameBase Game { get; protected set; } + + internal StrideGameBuilder() + { + Game = new BasicGame(); + Services = Game.Services; + GameSystems = Game.GameSystems; + } + + public static StrideGameBuilder Create() + { + return new StrideGameBuilder(); + } + + public virtual GameBase Build() + { + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + + return Game; + } +} From 9d39888ac88e7386bd4dfe1f7db4b2251ede3244 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:02:01 -0600 Subject: [PATCH 65/92] reorganizing code to work with GameStudio --- .../Stride.Editor/Preview/PreviewGame.cs | 1 + .../Engine/Builder/MinimalGame.cs | 2 +- sources/engine/Stride.Engine/Engine/Game.cs | 2 +- sources/engine/Stride.Games/GameBase.cs | 22 +++++++++++++++++++ sources/engine/Stride.Games/GamePlatform.cs | 1 + .../Stride.Games/GraphicsDeviceManager.cs | 2 +- 6 files changed, 27 insertions(+), 3 deletions(-) diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index b7a5a8c9f1..0dde48a299 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -15,6 +15,7 @@ using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; +using Stride.Games; namespace Stride.Editor.Preview { diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index ec51270191..80b3698ada 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -41,7 +41,7 @@ public MinimalGame(GameContext gameContext) : base() Services.AddService(Context.GamePlatform); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7064d566e6..8e88a8d385 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -243,7 +243,7 @@ public Game(GameContext context = null) : base() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); + GraphicsDeviceManager = new GraphicsDeviceManager(this, context); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9cb2262684..85604d972e 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -461,6 +461,28 @@ public virtual void Run(GameContext gameContext = null) } } + /// + /// Attempts to get GameContext based on the current platform. + /// + private void EnsureGameContextIsSet() + { + // Gets the GameWindow Context + if (Context == null) + { + AppContextType c; + if (OperatingSystem.IsWindows()) + c = AppContextType.Desktop; + else if (OperatingSystem.IsAndroid()) + c = AppContextType.Android; + else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) + c = AppContextType.iOS; + else + c = AppContextType.DesktopSDL; + + Context = GameContextFactory.NewGameContext(c); + } + } + /// /// Attempts to get GameContext based on the current platform. /// diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index d6fa19874d..f956f9fc0e 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -106,6 +106,7 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); + context.GameWindow = window; return window; } diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 08cd2404b4..0cbdc74691 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game) + public GraphicsDeviceManager(GameBase game, GameContext context = null) { this.game = game; if (this.game == null) From 2cd09f2133882e811eddb7aedcb933a960515214 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 9 May 2025 15:17:34 -0600 Subject: [PATCH 66/92] clean up --- sources/engine/Stride.Hosting/BasicGame.cs | 42 ------------------- .../Stride.Hosting/IStrideGameBuilder.cs | 16 ------- .../Stride.Hosting/Stride.Hosting.csproj | 28 ------------- .../Stride.Hosting/StrideGameBuilder.cs | 39 ----------------- 4 files changed, 125 deletions(-) delete mode 100644 sources/engine/Stride.Hosting/BasicGame.cs delete mode 100644 sources/engine/Stride.Hosting/IStrideGameBuilder.cs delete mode 100644 sources/engine/Stride.Hosting/Stride.Hosting.csproj delete mode 100644 sources/engine/Stride.Hosting/StrideGameBuilder.cs diff --git a/sources/engine/Stride.Hosting/BasicGame.cs b/sources/engine/Stride.Hosting/BasicGame.cs deleted file mode 100644 index 1b599d454c..0000000000 --- a/sources/engine/Stride.Hosting/BasicGame.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Stride.Core.Serialization; -using Stride.Games; -using Stride.Graphics; - -namespace Stride.Hosting; -public class BasicGame : GameBase -{ - - /// - /// Gets the graphics device manager. - /// - /// The graphics device manager. - public GraphicsDeviceManager GraphicsDeviceManager { get; internal set; } - - public BasicGame() - { - // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this); - Services.AddService(GraphicsDeviceManager); - Services.AddService(GraphicsDeviceManager); - } - - public override void ConfirmRenderingSettings(bool gameCreation) - { - var deviceManager = (GraphicsDeviceManager)graphicsDeviceManager; - - if (gameCreation) - { - //if our device width or height is actually smaller then requested we use the device one - deviceManager.PreferredBackBufferWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); - deviceManager.PreferredBackBufferHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); - } - } - - protected override void Initialize() - { - base.Initialize(); - - Content.Serializer.LowLevelSerializerSelector = new SerializerSelector("Default", "Content"); - } -} diff --git a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs b/sources/engine/Stride.Hosting/IStrideGameBuilder.cs deleted file mode 100644 index 3326ba14fb..0000000000 --- a/sources/engine/Stride.Hosting/IStrideGameBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Stride.Core; -using Stride.Core.Diagnostics; -using Stride.Games; - -namespace Stride.Hosting; -public interface IStrideGameBuilder -{ - public IServiceRegistry Services { get; } - - GameSystemCollection GameSystems { get; } - - List LogListeners { get; } - - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Hosting/Stride.Hosting.csproj b/sources/engine/Stride.Hosting/Stride.Hosting.csproj deleted file mode 100644 index dbf6858a2e..0000000000 --- a/sources/engine/Stride.Hosting/Stride.Hosting.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - true - - - - true - true - * - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - diff --git a/sources/engine/Stride.Hosting/StrideGameBuilder.cs b/sources/engine/Stride.Hosting/StrideGameBuilder.cs deleted file mode 100644 index 0ba4f91eda..0000000000 --- a/sources/engine/Stride.Hosting/StrideGameBuilder.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using Stride.Core.Diagnostics; -using Stride.Games; -using Stride.Core; - -namespace Stride.Hosting; -public class StrideGameBuilder : IStrideGameBuilder -{ - public IServiceRegistry Services { get; protected set; } - - public GameSystemCollection GameSystems { get; protected set; } - - public List LogListeners { get; protected set; } = []; - - public GameBase Game { get; protected set; } - - internal StrideGameBuilder() - { - Game = new BasicGame(); - Services = Game.Services; - GameSystems = Game.GameSystems; - } - - public static StrideGameBuilder Create() - { - return new StrideGameBuilder(); - } - - public virtual GameBase Build() - { - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - - return Game; - } -} From 4640016fd8bd2f3aacf423484deb871a37193761 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sat, 10 May 2025 14:06:08 -0600 Subject: [PATCH 67/92] fixing input issues --- .../Stride.Engine/Engine/Builder/GameBuilderExtensions.cs | 6 ++++++ sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs | 2 +- sources/engine/Stride.Engine/Engine/Game.cs | 2 +- sources/engine/Stride.Games/GameBase.cs | 2 +- sources/engine/Stride.Games/GamePlatform.cs | 1 - sources/engine/Stride.Games/GraphicsDeviceManager.cs | 2 +- sources/engine/Stride.Input/InputManager.cs | 2 +- 7 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 749487e572..a928fe5b84 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -83,6 +83,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) + { + gameBuilder.Game.SetGameContext(context); + return gameBuilder; + } + /// /// Adds the Stride input system to the game with no sources. /// diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 80b3698ada..ec51270191 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -41,7 +41,7 @@ public MinimalGame(GameContext gameContext) : base() Services.AddService(Context.GamePlatform); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, gameContext); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 8e88a8d385..7064d566e6 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -243,7 +243,7 @@ public Game(GameContext context = null) : base() Services.AddService(VRDeviceSystem); // Creates the graphics device manager - GraphicsDeviceManager = new GraphicsDeviceManager(this, context); + GraphicsDeviceManager = new GraphicsDeviceManager(this); Services.AddService(GraphicsDeviceManager); Services.AddService(GraphicsDeviceManager); diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 85604d972e..5d33c41b45 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -466,7 +466,7 @@ public virtual void Run(GameContext gameContext = null) /// private void EnsureGameContextIsSet() { - // Gets the GameWindow Context + // Gets the Game Context if (Context == null) { AppContextType c; diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index f956f9fc0e..d6fa19874d 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -106,7 +106,6 @@ public virtual GameWindow CreateWindow(GameContext gameContext) window.PreferredFullscreenSize = requestedSize; window.Initialize(gameContext); - context.GameWindow = window; return window; } diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index 0cbdc74691..08cd2404b4 100644 --- a/sources/engine/Stride.Games/GraphicsDeviceManager.cs +++ b/sources/engine/Stride.Games/GraphicsDeviceManager.cs @@ -100,7 +100,7 @@ public class GraphicsDeviceManager : ComponentBase, IGraphicsDeviceManager, IGra /// /// The game. /// The game instance cannot be null. - public GraphicsDeviceManager(GameBase game, GameContext context = null) + public GraphicsDeviceManager(GameBase game) { this.game = game; if (this.game == null) diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index eb9e1d788c..a37d496f39 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -632,7 +632,7 @@ public void PoolInputEvent(InputEvent inputEvent) public void ResetSources() { Sources.Clear(); - AddSources(); + //AddSources(); } /// From f0756be1029ff19c4a4ed51d13741121664571fd Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 11 May 2025 20:17:18 -0600 Subject: [PATCH 68/92] Separated input --- sources/Directory.Packages.props | 2 +- .../Engine/Builder/GameBuilder.cs | 50 ++++++++++++++++++ .../Engine/Builder/GameBuilderExtensions.cs | 19 +++++++ .../Engine/Builder/IGameBuilder.cs | 1 - .../Engine/Hosting/IStrideBuilder.cs | 16 ++++++ .../Engine/Hosting/StrideBuilder.cs | 52 +++++++++++++++++++ .../engine/Stride.Engine/Stride.Engine.csproj | 1 + 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs create mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/Directory.Packages.props b/sources/Directory.Packages.props index eba00a873d..9937848ac4 100644 --- a/sources/Directory.Packages.props +++ b/sources/Directory.Packages.props @@ -149,4 +149,4 @@ - \ No newline at end of file + diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 16d46b196e..dfadec07a1 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; +using Stride.Core.IO; using Stride.Games; using Stride.Input; @@ -64,11 +65,60 @@ public static GameBuilder Create(GameBase game = null) public virtual GameBase Build() { + var provider = DiServices.BuildServiceProvider(); + foreach (var service in Services) + { + if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) + continue; + + try + { + if (service.Value == null) + { + var instance = provider.GetService(service.Key); + Game.Services.AddService(instance, service.Key); + Services[service.Key] = instance; + } + else + { + Game.Services.AddService(service.Value, service.Key); + } + } + catch (Exception ex) + { + // TODO: check if service is already registered first. + } + } + + // Add all game systems to the game. + foreach (var service in Services) + { + var system = provider.GetService(service.Key); + if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) + { + Game.GameSystems.Add(gameSystem); + } + } + foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } + if (Context != null) + { + Game.SetGameContext(Context); + } + + if(InputSources.Count > 0) + { + var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + foreach (var inputSource in InputSources) + { + inputManager.Sources.Add(inputSource); + } + } + var provider = Services.BuildServiceProvider(); foreach (var service in InternalServices) { diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index a928fe5b84..e07ff08c29 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -5,10 +5,15 @@ using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; +using Stride.Engine.Processors; using Stride.Games; using Stride.Input; +using Stride.Profiling; using Stride.Rendering; +using Stride.Rendering.Fonts; +using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; +using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions @@ -83,6 +88,20 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } + public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + { + var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + + var inputSystem = new InputSystem(services); + + gameBuilder + .AddGameSystem(inputSystem) + .AddService(inputSystem) + .AddService(inputSystem.Manager); + + return gameBuilder; + } + public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { gameBuilder.Game.SetGameContext(context); diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index e14553734a..eba6f13b5b 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using Stride.Core.Diagnostics; -using Stride.Core; using Stride.Games; using System; using Microsoft.Extensions.DependencyInjection; diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs new file mode 100644 index 0000000000..9de0f50191 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public interface IStrideBuilder : IHostBuilder +{ + /// + /// Gets the game context. + /// + GameContext Context { get; } + /// + /// Gets the game. + /// + GameBase Game { get; } +} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs new file mode 100644 index 0000000000..f6bffe3367 --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Stride.Games; + +namespace Stride.Engine.Hosting; + +public class StrideBuilder : IStrideBuilder +{ + public GameContext Context { get; set; } + + public GameBase Game { get; set; } + + public IDictionary Properties { get; set; } + + public IHost Build() + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureContainer(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder ConfigureServices(Action configureDelegate) + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } + + public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + throw new NotImplementedException(); + } +} diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 7836b61cf4..234f39796f 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -29,6 +29,7 @@ + From b30a7a06a2abe90dcdda704e1a0b4179ae3c4498 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Mon, 12 May 2025 15:47:29 -0600 Subject: [PATCH 69/92] clean up and docs --- .../Engine/Builder/GameBuilder.cs | 15 ++++++ .../Engine/Builder/GameBuilderExtensions.cs | 14 ++--- .../Engine/Hosting/IStrideBuilder.cs | 16 ------ .../Engine/Hosting/StrideBuilder.cs | 52 ------------------- 4 files changed, 22 insertions(+), 75 deletions(-) delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs delete mode 100644 sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index dfadec07a1..21667ba0aa 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -76,6 +76,21 @@ public virtual GameBase Build() if (service.Value == null) { var instance = provider.GetService(service.Key); + + if(instance == null) + { + //check if the type is inherited from another instance in the services. + foreach (var kvp in Services) + { + if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) + { + instance = provider.GetService(kvp.Key); + if(instance is not null) + break; + } + } + } + Game.Services.AddService(instance, service.Key); Services[service.Key] = instance; } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index e07ff08c29..eeb2ca0e69 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -5,15 +5,10 @@ using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; -using Stride.Engine.Processors; using Stride.Games; using Stride.Input; -using Stride.Profiling; using Stride.Rendering; -using Stride.Rendering.Fonts; -using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; -using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions @@ -88,7 +83,12 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList return gameBuilder; } - public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) + /// + /// Adds the Stride input system to the game with no sources. + /// + /// + /// + public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; @@ -104,7 +104,7 @@ public static IGameBuilder AddStrideInput(this IGameBuilder gameBuilder) public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) { - gameBuilder.Game.SetGameContext(context); + gameBuilder.Context = context; return gameBuilder; } diff --git a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs deleted file mode 100644 index 9de0f50191..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/IStrideBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public interface IStrideBuilder : IHostBuilder -{ - /// - /// Gets the game context. - /// - GameContext Context { get; } - /// - /// Gets the game. - /// - GameBase Game { get; } -} diff --git a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs b/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs deleted file mode 100644 index f6bffe3367..0000000000 --- a/sources/engine/Stride.Engine/Engine/Hosting/StrideBuilder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Stride.Games; - -namespace Stride.Engine.Hosting; - -public class StrideBuilder : IStrideBuilder -{ - public GameContext Context { get; set; } - - public GameBase Game { get; set; } - - public IDictionary Properties { get; set; } - - public IHost Build() - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureContainer(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder ConfigureServices(Action configureDelegate) - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } - - public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull - { - throw new NotImplementedException(); - } -} From da993ade9516ffd77aca43e2937920ee0513c19e Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 14:53:08 -0600 Subject: [PATCH 70/92] Kryptos feedback --- sources/editor/Stride.Editor/Preview/PreviewGame.cs | 1 - sources/engine/Stride.Input/InputManager.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sources/editor/Stride.Editor/Preview/PreviewGame.cs b/sources/editor/Stride.Editor/Preview/PreviewGame.cs index 0dde48a299..b7a5a8c9f1 100644 --- a/sources/editor/Stride.Editor/Preview/PreviewGame.cs +++ b/sources/editor/Stride.Editor/Preview/PreviewGame.cs @@ -15,7 +15,6 @@ using Stride.Graphics; using Stride.Rendering.Compositing; using Stride.Shaders.Compiler; -using Stride.Games; namespace Stride.Editor.Preview { diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index a37d496f39..eb9e1d788c 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -632,7 +632,7 @@ public void PoolInputEvent(InputEvent inputEvent) public void ResetSources() { Sources.Clear(); - //AddSources(); + AddSources(); } /// From 85c4fce86a78f944f60e4542e5dd41218e55836b Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 15:10:04 -0600 Subject: [PATCH 71/92] missed some duplicate packages --- sources/engine/Stride.Engine/Stride.Engine.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Stride.Engine.csproj b/sources/engine/Stride.Engine/Stride.Engine.csproj index 234f39796f..7836b61cf4 100644 --- a/sources/engine/Stride.Engine/Stride.Engine.csproj +++ b/sources/engine/Stride.Engine/Stride.Engine.csproj @@ -29,7 +29,6 @@ - From 9315c0abacf4554d4f9cdc527e5ab4ee3523620f Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Wed, 28 May 2025 19:37:36 -0600 Subject: [PATCH 72/92] Fix error caused by StreamingManager DI. --- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 14 ++++++++------ sources/engine/Stride.Engine/Engine/Game.cs | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 21667ba0aa..e094812ff9 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -65,6 +65,12 @@ public static GameBuilder Create(GameBase game = null) public virtual GameBase Build() { + + foreach (var logListener in LogListeners) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + var provider = DiServices.BuildServiceProvider(); foreach (var service in Services) { @@ -101,7 +107,8 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first. + // TODO: check if service is already registered first.' + GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -115,11 +122,6 @@ public virtual GameBase Build() } } - foreach (var logListener in LogListeners) - { - GlobalLogger.GlobalMessageLogged += logListener; - } - if (Context != null) { Game.SetGameContext(Context); diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7064d566e6..dbaaab9489 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,10 +11,12 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; +using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; +using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; From 91869d4df07e198da802de54df7dd772642ac78f Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 08:01:50 -0600 Subject: [PATCH 73/92] renaming to favour ServiceCollection --- .../Stride.Engine/Engine/Builder/GameBuilder.cs | 11 +++++------ .../Engine/Builder/GameBuilderExtensions.cs | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index e094812ff9..cdc27bb2fc 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -65,14 +65,13 @@ public static GameBuilder Create(GameBase game = null) public virtual GameBase Build() { - foreach (var logListener in LogListeners) { GlobalLogger.GlobalMessageLogged += logListener; } - var provider = DiServices.BuildServiceProvider(); - foreach (var service in Services) + var provider = Services.BuildServiceProvider(); + foreach (var service in InternalServices) { if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) continue; @@ -86,7 +85,7 @@ public virtual GameBase Build() if(instance == null) { //check if the type is inherited from another instance in the services. - foreach (var kvp in Services) + foreach (var kvp in InternalServices) { if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) { @@ -98,7 +97,7 @@ public virtual GameBase Build() } Game.Services.AddService(instance, service.Key); - Services[service.Key] = instance; + InternalServices[service.Key] = instance; } else { @@ -113,7 +112,7 @@ public virtual GameBase Build() } // Add all game systems to the game. - foreach (var service in Services) + foreach (var service in InternalServices) { var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index eeb2ca0e69..414da14d3d 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -90,7 +90,7 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList /// public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) { - var services = gameBuilder.Services[typeof(IServiceRegistry)] as IServiceRegistry; + var services = gameBuilder.InternalServices[typeof(IServiceRegistry)] as IServiceRegistry; var inputSystem = new InputSystem(services); From 33ab4ff3e44dddcd3cc7e538ca068da643fdf953 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 12:42:05 -0600 Subject: [PATCH 74/92] clean up and build logging --- .../Engine/Builder/GameBuilder.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index cdc27bb2fc..c919559b7e 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Stride.Core; using Stride.Core.Diagnostics; -using Stride.Core.IO; using Stride.Games; using Stride.Input; @@ -96,18 +95,20 @@ public virtual GameBase Build() } } + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(instance, service.Key); InternalServices[service.Key] = instance; } else { + _log.Info($"Registering service {service.Key.Name}."); Game.Services.AddService(service.Value, service.Key); } } catch (Exception ex) { // TODO: check if service is already registered first.' - GlobalLogger.GetLogger("GameBuilder").Error($"Failed to register service {service.Key.Name}.\n\n", ex); + _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } @@ -117,20 +118,31 @@ public virtual GameBase Build() var system = provider.GetService(service.Key); if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) { + _log.Info($"Adding game system {gameSystem.GetType().Name} to the game systems collection."); Game.GameSystems.Add(gameSystem); } } if (Context != null) { + _log.Info($"Setting game context."); Game.SetGameContext(Context); } if(InputSources.Count > 0) { - var inputManager = Game.Services.GetService() ?? throw new InvalidOperationException("InputManager is not registered in the service registry."); + var inputManager = Game.Services.GetService(); + + if (inputManager is null) + { + _log.Info("No InputManager found in the game services, creating default."); + inputManager = new InputManager(); + Game.Services.AddService(inputManager); + } + foreach (var inputSource in InputSources) { + _log.Info($"Adding input source {inputSource.GetType().Name} to the input manager."); inputManager.Sources.Add(inputSource); } } From d8b3a70f99716997acdd4506d0f6f5a22a03d4a3 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 29 May 2025 18:49:07 -0600 Subject: [PATCH 75/92] remove some hardcoded Game references --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 2 +- sources/engine/Stride.Engine/Engine/Game.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index c919559b7e..866e594123 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -107,7 +107,7 @@ public virtual GameBase Build() } catch (Exception ex) { - // TODO: check if service is already registered first.' + // TODO: check if service is already registered first. _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); } } diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index dbaaab9489..7064d566e6 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -11,12 +11,10 @@ using Stride.Core.IO; using Stride.Core.Mathematics; using Stride.Core.Storage; -using Stride.Core.Streaming; using Stride.Engine.Design; using Stride.Engine.Processors; using Stride.Games; using Stride.Graphics; -using Stride.Graphics.Data; using Stride.Graphics.Font; using Stride.Input; using Stride.Profiling; From 6e04b895541df3014bdfb130e6db7542632d2643 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:27:36 -0600 Subject: [PATCH 76/92] writable ConentManager --- .../Serialization/Contents/IContentManager.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs b/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs index baf4983438..d495e40f7c 100644 --- a/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs +++ b/sources/core/Stride.Core.Serialization/Serialization/Contents/IContentManager.cs @@ -25,6 +25,19 @@ public interface IContentManager /// A stream to the raw asset. Stream OpenAsStream(string url, StreamFlags streamFlags = StreamFlags.None); + /// + /// Saves an asset at a specific URL. + /// + /// The URL. + /// The asset. + /// The custom storage type to use. Use null as default. + /// + /// url + /// or + /// asset + /// + void Save(string url, object asset, Type? storageType); + /// /// Loads content from the specified URL. /// From a7c63257cc3aa341c59539945dd4b1639f46c986 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:43:11 -0700 Subject: [PATCH 77/92] Update sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 866e594123..f9158a9e86 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -15,7 +15,7 @@ namespace Stride.Engine.Builder; public class GameBuilder : IGameBuilder { /// - /// This is used to allow the same instance to be registered multiple times as differenet interfaces or types. This was done due to how works."/> + /// This is used to allow the same instance to be registered multiple times as different interfaces or types. This was done due to how works."/> /// public Dictionary InternalServices { get; internal set; } = []; From 9f356ff93ea6d051449cb5a6c60b604946b4c176 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:43:26 -0700 Subject: [PATCH 78/92] Update sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs index 1a99c7f97f..de655f4b79 100644 --- a/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs +++ b/sources/buildengine/Stride.Core.BuildEngine.Common/MicrothreadLocalDatabases.cs @@ -117,7 +117,6 @@ public DatabaseFileProvider FileProvider { get => MicroThreadLocalDatabaseFileProvider.Value; set => MicroThreadLocalDatabaseFileProvider.Value = value; - //throw new InvalidOperationException($"Can not change the value of a {nameof(MicroThreadLocalProviderService.FileProvider)}"); } } } From fc3be413a3653e14ccbd00396d58665436c72149 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:47:36 -0700 Subject: [PATCH 79/92] Update sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index ec51270191..fb98eea673 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -52,7 +52,7 @@ public override void ConfirmRenderingSettings(bool gameCreation) if (gameCreation) { - //if our device width or height is actually smaller then requested we use the device one + //if our device width or height is actually smaller than requested we use the device one deviceManager.PreferredBackBufferWidth = Context.RequestedWidth = Math.Min(deviceManager.PreferredBackBufferWidth, Window.ClientBounds.Width); deviceManager.PreferredBackBufferHeight = Context.RequestedHeight = Math.Min(deviceManager.PreferredBackBufferHeight, Window.ClientBounds.Height); } From 402568156b2e4711a7374f33945e4a4fdeb02ed1 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:50:56 -0700 Subject: [PATCH 80/92] Update sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index f9158a9e86..70a1e4c428 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -11,7 +11,6 @@ namespace Stride.Engine.Builder; /// /// Helps build the game and preps it to be able to run after . /// -/// public class GameBuilder : IGameBuilder { /// From 51bb759c43774762de8e64506ee760538a004abf Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:53:15 -0700 Subject: [PATCH 81/92] minor fixes and clean up --- sources/engine/Stride.Games/GamePlatform.cs | 6 +++--- sources/engine/Stride.Games/GameWindow.cs | 2 +- sources/engine/Stride.Games/Windowing/IGameWindow.cs | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index d6fa19874d..743d2f46ad 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -34,7 +34,7 @@ public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGam { private bool hasExitRan = false; - protected readonly IServiceRegistry Services; + //protected readonly IServiceRegistry Services; protected GameBase game => context.CurrentGame; @@ -46,7 +46,7 @@ public abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGam protected GamePlatform(GameContext context) { - Services = context.Services; + //Services = context.Services; this.context = context; this.context.GamePlatform = this; } @@ -98,7 +98,7 @@ public virtual GameWindow CreateWindow(GameContext gameContext) var window = GetSupportedGameWindow(gameContext.ContextType); if (window != null) { - window.Services = Services; + //window.Services = Services; // Pass initial size var requestedSize = new Int2(gameContext.RequestedWidth, gameContext.RequestedHeight); diff --git a/sources/engine/Stride.Games/GameWindow.cs b/sources/engine/Stride.Games/GameWindow.cs index 26a1b83937..02dd1be2d7 100644 --- a/sources/engine/Stride.Games/GameWindow.cs +++ b/sources/engine/Stride.Games/GameWindow.cs @@ -268,7 +268,7 @@ public virtual IMessageLoop CreateUserManagedMessageLoop() throw new PlatformNotSupportedException(); } - internal IServiceRegistry Services { get; set; } + //internal IServiceRegistry Services { get; set; } protected internal abstract void SetSupportedOrientations(DisplayOrientation orientations); diff --git a/sources/engine/Stride.Games/Windowing/IGameWindow.cs b/sources/engine/Stride.Games/Windowing/IGameWindow.cs index 643b1d6ac9..5f23573032 100644 --- a/sources/engine/Stride.Games/Windowing/IGameWindow.cs +++ b/sources/engine/Stride.Games/Windowing/IGameWindow.cs @@ -6,7 +6,6 @@ public interface IGameWindow : IStrideSurface { public IntPtr WindowHandle { get; } public Int2 Position { get; set; } - public Int2 Size { get; set; } public string Title { get; set; } From 8c3385379169f8656597fa807bf39d05ae1081d4 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:09:38 -0700 Subject: [PATCH 82/92] Update sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 70a1e4c428..2ba407d604 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -29,7 +29,7 @@ public class GameBuilder : IGameBuilder public GameSystemCollection GameSystems { get; internal set; } /// - /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur."/> + /// Adds log listeners to the game on . This is registered first so it will log build errors if they occur. /// public List LogListeners { get; internal set; } = []; From c0e37e91e30aacb07e3bce2e29f771821265456b Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:21:24 -0700 Subject: [PATCH 83/92] Update sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index fb98eea673..623af93443 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -27,6 +27,7 @@ public MinimalGame(GameContext gameContext) : base() { Context = gameContext ?? GetDefaultContext(); Context.CurrentGame = this; + Context.Services = Services; // Create Platform Context.GamePlatform = GamePlatform.Create(Context); From 7509aa60d8159465f4af977ac839ad7368b4df76 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:22:19 -0700 Subject: [PATCH 84/92] Update sources/engine/Stride.Engine/Engine/Game.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Game.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 7064d566e6..f4087357b8 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -192,6 +192,7 @@ public Game(GameContext context = null) : base() { Context = context ?? GetDefaultContext(); Context.CurrentGame = this; + Context.Services = Services; // Create Platform Context.GamePlatform = GamePlatform.Create(Context); From b09b949f8a72ca7adb021a9544e5b07d15fc7e50 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:23:50 -0700 Subject: [PATCH 85/92] Update sources/engine/Stride.Engine/Engine/Game.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Engine/Engine/Game.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index f4087357b8..c211e0ec6e 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -443,7 +443,7 @@ private void SetInitialInputSources(InputManager inputManager) if (InputSourceWindowsXInput.IsSupported()) inputManager.Sources.Add(new InputSourceWindowsXInput()); #if STRIDE_INPUT_RAWINPUT - if (rawInputEnabled && context is GameContextWinforms gameContextWinforms) + if (rawInputEnabled && Context is GameContextWinforms gameContextWinforms) inputManager.Sources.Add(new InputSourceWindowsRawInput(gameContextWinforms.Control)); #endif #endif From 2db7d4c8d9e093a5a2e6ea4854e7a3100e335f6e Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:37:40 -0700 Subject: [PATCH 86/92] Update sources/engine/Stride.Games/GamePlatform.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sources/engine/Stride.Games/GamePlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index 743d2f46ad..b097157341 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -297,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = context.GameWindow.NativeWindow, + DeviceWindowHandle = context.GameWindow != null ? context.GameWindow.NativeWindow : IntPtr.Zero, ColorSpace = preferredParameters.ColorSpace, }, }; From 8088212d4b9ba0ceffe9c66fea57269f084ff1b7 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:59:42 -0700 Subject: [PATCH 87/92] Undo Copilot change --- sources/engine/Stride.Games/GamePlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index b097157341..743d2f46ad 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -297,7 +297,7 @@ public virtual List FindBestDevices(GameGraphicsParam IsFullScreen = preferredParameters.IsFullScreen, PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex, PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate, - DeviceWindowHandle = context.GameWindow != null ? context.GameWindow.NativeWindow : IntPtr.Zero, + DeviceWindowHandle = context.GameWindow.NativeWindow, ColorSpace = preferredParameters.ColorSpace, }, }; From eec7b3a51eb9a74c9f3d9b6ade7c4a2859b351fa Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 25 Dec 2025 17:42:42 -0700 Subject: [PATCH 88/92] rebase issues --- .../Engine/Builder/GameBuilder.cs | 78 ------------------- .../Engine/Builder/GameBuilderExtensions.cs | 25 ------ sources/engine/Stride.Games/GameBase.cs | 22 ------ 3 files changed, 125 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 2ba407d604..89354f46f1 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -146,84 +146,6 @@ public virtual GameBase Build() } } - var provider = Services.BuildServiceProvider(); - foreach (var service in InternalServices) - { - if (service.Key == typeof(IServiceRegistry) || service.Key == typeof(IServiceProvider)) - continue; - - try - { - if (service.Value == null) - { - var instance = provider.GetService(service.Key); - - if(instance == null) - { - //check if the type is inherited from another instance in the services. - foreach (var kvp in InternalServices) - { - if (kvp.Key.IsAssignableFrom(service.Key) && kvp.Value != null) - { - instance = provider.GetService(kvp.Key); - if(instance is not null) - break; - } - } - } - - _log.Info($"Registering service {service.Key.Name}."); - Game.Services.AddService(instance, service.Key); - InternalServices[service.Key] = instance; - } - else - { - _log.Info($"Registering service {service.Key.Name}."); - Game.Services.AddService(service.Value, service.Key); - } - } - catch (Exception ex) - { - // TODO: check if service is already registered first. - _log.Error($"Failed to register service {service.Key.Name}.\n\n", ex); - } - } - - // Add all game systems to the game. - foreach (var service in InternalServices) - { - var system = provider.GetService(service.Key); - if (system is IGameSystemBase gameSystem && !Game.GameSystems.Contains(gameSystem)) - { - _log.Info($"Adding game system {gameSystem.GetType().Name} to the game systems collection."); - Game.GameSystems.Add(gameSystem); - } - } - - if (Context != null) - { - _log.Info($"Setting game context."); - Game.SetGameContext(Context); - } - - if(InputSources.Count > 0) - { - var inputManager = Game.Services.GetService(); - - if (inputManager is null) - { - _log.Info("No InputManager found in the game services, creating default."); - inputManager = new InputManager(); - Game.Services.AddService(inputManager); -} - - foreach (var inputSource in InputSources) -{ - _log.Info($"Adding input source {inputSource.GetType().Name} to the input manager."); - inputManager.Sources.Add(inputSource); - } - } - return Game; } } diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 414da14d3d..749487e572 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -108,31 +108,6 @@ public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameCon return gameBuilder; } - /// - /// Adds the Stride input system to the game with no sources. - /// - /// - /// - public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) - { - var services = gameBuilder.InternalServices[typeof(IServiceRegistry)] as IServiceRegistry; - - var inputSystem = new InputSystem(services); - - gameBuilder - .AddGameSystem(inputSystem) - .AddService(inputSystem) - .AddService(inputSystem.Manager); - - return gameBuilder; - } - - public static IGameBuilder SetGameContext(this IGameBuilder gameBuilder, GameContext context) - { - gameBuilder.Context = context; - return gameBuilder; - } - /// /// Add a custom database file provider to the game. /// diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 5d33c41b45..9cb2262684 100644 --- a/sources/engine/Stride.Games/GameBase.cs +++ b/sources/engine/Stride.Games/GameBase.cs @@ -483,28 +483,6 @@ private void EnsureGameContextIsSet() } } - /// - /// Attempts to get GameContext based on the current platform. - /// - private void EnsureGameContextIsSet() - { - // Gets the Game Context - if (Context == null) - { - AppContextType c; - if (OperatingSystem.IsWindows()) - c = AppContextType.Desktop; - else if (OperatingSystem.IsAndroid()) - c = AppContextType.Android; - else if (OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS()) - c = AppContextType.iOS; - else - c = AppContextType.DesktopSDL; - - Context = GameContextFactory.NewGameContext(c); - } - } - /// /// Creates or updates before window and device are created. /// From 53d2433cf6ed3bb6148e528cc41047eac932bf0c Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Thu, 25 Dec 2025 18:37:41 -0700 Subject: [PATCH 89/92] added basic game extensions --- .../Engine/Builder/GameBaseExtensions.cs | 41 +++++++++++++++++++ .../Engine/Builder/GameBuilderExtensions.cs | 4 +- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs new file mode 100644 index 0000000000..3b104fc79a --- /dev/null +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; +using Stride.Core.IO; +using Stride.Core.Serialization.Contents; +using Stride.Engine.Design; +using Stride.Games; +using Stride.Rendering; + +namespace Stride.Engine.Builder; + +public static class GameBaseExtensions +{ + public static GameBase UseInitialSceneFromSettings(this GameBase game) + { + var content = game.Services.GetService(); + var settings = content.Load("GameSettings"); + return game; + } + + public static GameBase UseInitialGraphicsCompositorFromSettings(this GameBase game) + { + var content = game.Services.GetService(); + var settings = content.Load("GameSettings"); + var sceneSystem = game.Services.GetService(); + sceneSystem.InitialSceneUrl = settings.DefaultSceneUrl; + sceneSystem.InitialGraphicsCompositorUrl = settings.DefaultGraphicsCompositorUrl; + + return game; + } + + public static GameBase UseDefaultEffectCompiler(this GameBase game) + { + var fileProviderService = game.Services.GetService().FileProvider; + game.Services.GetService() + .CreateDefaultEffectCompiler(fileProviderService); + + return game; + } +} diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 749487e572..42912c3f41 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -88,7 +88,7 @@ public static IGameBuilder AddLogListener(this IGameBuilder gameBuilder, LogList /// /// /// - public static IGameBuilder UseStrideInput(this IGameBuilder gameBuilder) + public static IGameBuilder UseDefaultInput(this IGameBuilder gameBuilder) { var services = gameBuilder.InternalServices[typeof(IServiceRegistry)] as IServiceRegistry; @@ -183,7 +183,7 @@ public static EffectSystem CreateDefaultEffectCompiler(this EffectSystem effectS /// /// /// - public static IGameBuilder AddStrideInputSource(this IGameBuilder gameBuilder, IInputSource inputSource) + public static IGameBuilder AddInputSource(this IGameBuilder gameBuilder, IInputSource inputSource) { gameBuilder.InputSources.Add(inputSource); return gameBuilder; From 5c709306d1960929e13b77b3f6e86b975a97dec2 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 26 Dec 2025 04:51:11 -0700 Subject: [PATCH 90/92] added default game systems extension --- .../Engine/Builder/GameBuilderExtensions.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 42912c3f41..847c92e5fb 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,14 +1,21 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Stride.Audio; using Stride.Core; using Stride.Core.Diagnostics; using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Core.Storage; +using Stride.Engine.Processors; using Stride.Games; +using Stride.Graphics.Font; using Stride.Input; +using Stride.Profiling; using Stride.Rendering; +using Stride.Rendering.Fonts; +using Stride.Rendering.Sprites; using Stride.Shaders.Compiler; +using Stride.Streaming; namespace Stride.Engine.Builder; public static class GameBuilderExtensions @@ -188,4 +195,26 @@ public static IGameBuilder AddInputSource(this IGameBuilder gameBuilder, IInputS gameBuilder.InputSources.Add(inputSource); return gameBuilder; } + + /// + /// Default s for a Stride game. + /// + /// + /// + public static IGameBuilder UseDefaultGameSystems(this IGameBuilder gameBuilder) + { + gameBuilder + .AddService() + .AddService() + .AddService() + .AddService() + .AddService() + .AddService() + .AddService() + .AddService() + .AddService() + .AddService(); + + return gameBuilder; + } } From bf03434f65136f39111d6c4dd239a978f78eb2a6 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 26 Dec 2025 05:03:37 -0700 Subject: [PATCH 91/92] fix broken extension --- .../engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs index 3b104fc79a..b0d58d05d4 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs @@ -16,6 +16,8 @@ public static GameBase UseInitialSceneFromSettings(this GameBase game) { var content = game.Services.GetService(); var settings = content.Load("GameSettings"); + var sceneSystem = game.Services.GetService(); + sceneSystem.InitialSceneUrl = settings.DefaultSceneUrl; return game; } @@ -24,7 +26,6 @@ public static GameBase UseInitialGraphicsCompositorFromSettings(this GameBase ga var content = game.Services.GetService(); var settings = content.Load("GameSettings"); var sceneSystem = game.Services.GetService(); - sceneSystem.InitialSceneUrl = settings.DefaultSceneUrl; sceneSystem.InitialGraphicsCompositorUrl = settings.DefaultGraphicsCompositorUrl; return game; From 36a6c2ac310046f1374098aa727c4a0df1a3bda0 Mon Sep 17 00:00:00 2001 From: Doprez <73259914+Doprez@users.noreply.github.com> Date: Fri, 26 Dec 2025 06:51:14 -0700 Subject: [PATCH 92/92] clean up --- .../Stride.Engine/Engine/Builder/GameBaseExtensions.cs | 7 +++---- sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs | 3 +++ .../Stride.Engine/Engine/Builder/GameBuilderExtensions.cs | 3 +++ .../engine/Stride.Engine/Engine/Builder/IGameBuilder.cs | 4 +++- sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs | 3 +++ 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs index b0d58d05d4..143e5d0c82 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBaseExtensions.cs @@ -1,7 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using Stride.Core.IO; using Stride.Core.Serialization.Contents; using Stride.Engine.Design; diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs index 89354f46f1..ab78eb29f5 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilder.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; diff --git a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs index 847c92e5fb..75a80446c9 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/GameBuilderExtensions.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System; using Microsoft.Extensions.DependencyInjection; using Stride.Audio; diff --git a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs index eba6f13b5b..bfba8b2b95 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/IGameBuilder.cs @@ -1,10 +1,12 @@ +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System.Collections.Generic; using Stride.Core.Diagnostics; using Stride.Games; using System; using Microsoft.Extensions.DependencyInjection; using Stride.Input; -using Stride.Core.IO; namespace Stride.Engine.Builder; public interface IGameBuilder diff --git a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs index 623af93443..ec96b4272c 100644 --- a/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs +++ b/sources/engine/Stride.Engine/Engine/Builder/MinimalGame.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System; using System.Threading; using System.Threading.Tasks;