diff --git a/sources/engine/Stride.Engine/Engine/Game.cs b/sources/engine/Stride.Engine/Engine/Game.cs index 6c4c162ed5..162a9d5d3c 100644 --- a/sources/engine/Stride.Engine/Engine/Game.cs +++ b/sources/engine/Stride.Engine/Engine/Game.cs @@ -453,9 +453,9 @@ protected virtual Task LoadContent() return Task.FromResult(true); } - internal override void LoadContentInternal() + public override void LoadContentDefault() { - base.LoadContentInternal(); + base.LoadContentDefault(); Script.AddTask(LoadContent); } protected virtual LogListener GetLogListener() diff --git a/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs b/sources/engine/Stride.Games/Android/GamePlatformAndroid.cs index 167afa863d..d84a9e8761 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() : base() { PopulateFullName(); } diff --git a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs index 7d48fae49e..7b74f0e3ff 100644 --- a/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs +++ b/sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs @@ -27,9 +27,9 @@ namespace Stride.Games { - internal class GamePlatformDesktop : GamePlatform + public class GamePlatformDesktop : GamePlatform { - public GamePlatformDesktop(GameBase game) : base(game) + public GamePlatformDesktop() : base() { IsBlockingRun = true; #if (STRIDE_UI_WINFORMS || STRIDE_UI_WPF) @@ -51,7 +51,7 @@ public override string DefaultAppDirectory } } - internal override GameWindow GetSupportedGameWindow(AppContextType type) + public override GameWindow GetSupportedGameWindow(AppContextType type) { switch (type) { diff --git a/sources/engine/Stride.Games/Desktop/GameWindowWinforms.cs b/sources/engine/Stride.Games/Desktop/GameWindowWinforms.cs index 5cd805665d..092f7b779a 100644 --- a/sources/engine/Stride.Games/Desktop/GameWindowWinforms.cs +++ b/sources/engine/Stride.Games/Desktop/GameWindowWinforms.cs @@ -120,7 +120,7 @@ public override void EndScreenDeviceChange(int clientWidth, int clientHeight) deviceChangeWillBeFullScreen = null; } - protected internal override void SetSupportedOrientations(DisplayOrientation orientations) + public override void SetSupportedOrientations(DisplayOrientation orientations) { // Desktop doesn't have orientation (unless on Windows 8?) } @@ -166,7 +166,7 @@ protected override void Initialize(GameContext gameContext) } } - internal override void Run() + public override void Run() { Debug.Assert(InitCallback != null, $"{nameof(InitCallback)} is null"); Debug.Assert(RunCallback != null, $"{nameof(RunCallback)} is null"); @@ -298,7 +298,7 @@ protected override void SetTitle(string title) } } - internal override void Resize(int width, int height) + public override void Resize(int width, int height) { Control.ClientSize = new Size(width, height); } diff --git a/sources/engine/Stride.Games/GameBase.cs b/sources/engine/Stride.Games/GameBase.cs index 9fd977372d..cf4203bc68 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; + protected GamePlatform gamePlatform; private IGraphicsDeviceService graphicsDeviceService; protected IGraphicsDeviceManager graphicsDeviceManager; private ResumeManager resumeManager; @@ -59,7 +59,7 @@ public abstract class GameBase : ComponentBase, IGame private bool isMouseVisible; - internal object TickLock = new object(); + public object TickLock = new object(); #endregion @@ -68,7 +68,43 @@ public abstract class GameBase : ComponentBase, IGame /// /// Initializes a new instance of the class. /// - protected GameBase() + public GameBase(bool test) + { + // Internals + Log = GlobalLogger.GetLogger(GetType().GetTypeInfo().Name); + UpdateTime = new GameTime(); + DrawTime = new GameTime(); + autoTickTimer = new TimerTick(); + IsFixedTimeStep = false; + maximumElapsedTime = TimeSpan.FromMilliseconds(500.0); + TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60); // target elapsed time is by default 60Hz + + TreatNotFocusedLikeMinimized = true; + WindowMinimumUpdateRate = new ThreadThrottler(TimeSpan.FromSeconds(0d)); + MinimizedMinimumUpdateRate = new ThreadThrottler(15); // by default 15 updates per second while minimized + + isMouseVisible = true; + + // Externals + Services = new ServiceRegistry(); + + // Database file provider + Services.AddService(new DatabaseFileProviderService(null)); + + LaunchParameters = new LaunchParameters(); + GameSystems = new GameSystemCollection(Services); + Services.AddService(GameSystems); + + // Setup registry + Services.AddService(this); + + IsActive = true; + } + + /// + /// Initializes a new instance of the class. + /// + protected GameBase(GamePlatform platform = null) { // Internals Log = GlobalLogger.GetLogger(GetType().GetTypeInfo().Name); @@ -96,7 +132,10 @@ protected GameBase() Services.AddService(GameSystems); // Create Platform - gamePlatform = GamePlatform.Create(this); + gamePlatform = platform ?? GamePlatform.Create(); + + // Configure platform to contain the game reference as needed. + gamePlatform.ConfigurePlatform(this); gamePlatform.Activated += GamePlatform_Activated; gamePlatform.Deactivated += GamePlatform_Deactivated; gamePlatform.Exiting += GamePlatform_Exiting; @@ -197,7 +236,7 @@ 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. @@ -216,7 +255,7 @@ protected GameBase() /// Gets or sets a value indicating whether this instance should force exactly one update step per one draw step /// /// true if this instance forces one update step per one draw step; otherwise, false. - protected internal bool ForceOneUpdatePerDraw { get; set; } + protected bool ForceOneUpdatePerDraw { get; set; } /// /// When is set, is it allowed to render frames between two steps when we have time to do so. @@ -340,7 +379,7 @@ public void ResetElapsedTime() forceElapsedTimeToZero = true; } - internal void InitializeBeforeRun() + public void InitializeBeforeRun() { try { @@ -371,7 +410,7 @@ internal void InitializeBeforeRun() // Bind Graphics Context enabling initialize to use GL API eg. SetData to texture ...etc BeginDraw(); - LoadContentInternal(); + LoadContentDefault(); IsRunning = true; @@ -848,7 +887,7 @@ protected virtual void Initialize() GameSystems.Initialize(); } - internal virtual void LoadContentInternal() + public virtual void LoadContentDefault() { GameSystems.LoadContent(); } @@ -978,7 +1017,7 @@ private void GraphicsDeviceService_DeviceCreated(object sender, EventArgs e) if (GameSystems.State != GameSystemState.ContentLoaded) { - LoadContentInternal(); + LoadContentDefault(); } } diff --git a/sources/engine/Stride.Games/GameContext.cs b/sources/engine/Stride.Games/GameContext.cs index 8e2338269e..74c0c68ef8 100644 --- a/sources/engine/Stride.Games/GameContext.cs +++ b/sources/engine/Stride.Games/GameContext.cs @@ -48,40 +48,40 @@ public abstract class GameContext /// Gets the main loop callback to be called when is true. /// /// The run loop. - public Action RunCallback { get; internal set; } + public Action RunCallback { get; set; } /// /// Gets the exit callback to be called when is true when exiting the game. /// /// The run loop. - public Action ExitCallback { get; internal set; } + public Action ExitCallback { get; set; } // TODO: remove these requested values. /// /// The requested width. /// - internal int RequestedWidth; + public int RequestedWidth; /// /// The requested height. /// - internal int RequestedHeight; + public int RequestedHeight; /// /// The requested back buffer format. /// - internal PixelFormat RequestedBackBufferFormat; + public PixelFormat RequestedBackBufferFormat; /// /// The requested depth stencil format. /// - internal PixelFormat RequestedDepthStencilFormat; + public PixelFormat RequestedDepthStencilFormat; /// /// The requested graphics profiles. /// - internal GraphicsProfile[] RequestedGraphicsProfile; + public GraphicsProfile[] RequestedGraphicsProfile; /// /// The device creation flags that will be used to create the . @@ -98,7 +98,7 @@ public abstract class GameContext /// Product name of game. /// TODO: Provide proper access title through code and game studio /// - internal static string ProductName + public static string ProductName { get { diff --git a/sources/engine/Stride.Games/GameContextFactory.cs b/sources/engine/Stride.Games/GameContextFactory.cs index 95b0a2f8fc..2fd169e985 100644 --- a/sources/engine/Stride.Games/GameContextFactory.cs +++ b/sources/engine/Stride.Games/GameContextFactory.cs @@ -41,6 +41,8 @@ public static GameContext NewGameContext(AppContextType type, int requestedWidth case AppContextType.iOS: res = NewGameContextiOS(); break; + case AppContextType.Custom: + throw new InvalidOperationException("Custom Contexts can not be created by the factory. Consider using a built in context if you are unsure."); } if (res == null) diff --git a/sources/engine/Stride.Games/GamePlatform.cs b/sources/engine/Stride.Games/GamePlatform.cs index 36848ae436..5eef3a1ba4 100644 --- a/sources/engine/Stride.Games/GamePlatform.cs +++ b/sources/engine/Stride.Games/GamePlatform.cs @@ -30,35 +30,46 @@ 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 GameBase game; - protected readonly IServiceRegistry Services; + protected IServiceRegistry Services; protected GameWindow gameWindow; public string FullName { get; protected set; } = string.Empty; - protected GamePlatform(GameBase game) + /// + /// should be configured by calling before being used. + /// + protected GamePlatform() + { + } + + /// + /// This is called by the game to configure the platform within the constructor. + /// + /// + public virtual void ConfigurePlatform(GameBase gameBase) { - this.game = game; + game = gameBase; Services = game.Services; } - public static GamePlatform Create(GameBase game) + public static GamePlatform Create() { #if STRIDE_PLATFORM_UWP - return new GamePlatformUWP(game); + return new GamePlatformUWP(); #elif STRIDE_PLATFORM_ANDROID - return new GamePlatformAndroid(game); + return new GamePlatformAndroid(); #elif STRIDE_PLATFORM_IOS - return new GamePlatformiOS(game); + return new GamePlatformiOS(); #else // Here we cover all Desktop variants: OpenTK, SDL, Winforms,... - return new GamePlatformDesktop(game); + return new GamePlatformDesktop(); #endif } @@ -88,7 +99,7 @@ public GameWindow MainWindow } } - internal abstract GameWindow GetSupportedGameWindow(AppContextType type); + public abstract GameWindow GetSupportedGameWindow(AppContextType type); public virtual GameWindow CreateWindow(GameContext gameContext) { diff --git a/sources/engine/Stride.Games/GameTime.cs b/sources/engine/Stride.Games/GameTime.cs index 1defdd97e5..644c71321c 100644 --- a/sources/engine/Stride.Games/GameTime.cs +++ b/sources/engine/Stride.Games/GameTime.cs @@ -118,8 +118,10 @@ public double Factor set => factor = value > 0 ? value : 0; } - - internal void Update(TimeSpan totalGameTime, TimeSpan elapsedGameTime, bool incrementFrameCount) + /// + /// Set and to the properties provided, also increments frame count if is true + /// + public void Update(TimeSpan totalGameTime, TimeSpan elapsedGameTime, bool incrementFrameCount) { Total = totalGameTime; Elapsed = elapsedGameTime; @@ -145,7 +147,10 @@ internal void Update(TimeSpan totalGameTime, TimeSpan elapsedGameTime, bool incr } } - internal void Reset(TimeSpan totalGameTime) + /// + /// Set to and reset every other properties to their initial value. + /// + public void Reset(TimeSpan totalGameTime) { Update(totalGameTime, TimeSpan.Zero, false); accumulatedElapsedTime = TimeSpan.Zero; diff --git a/sources/engine/Stride.Games/GameWindow.cs b/sources/engine/Stride.Games/GameWindow.cs index e1e149ccd9..98f8f6af47 100644 --- a/sources/engine/Stride.Games/GameWindow.cs +++ b/sources/engine/Stride.Games/GameWindow.cs @@ -212,6 +212,15 @@ internal void SetIsReallyFullscreen(bool isReallyFullscreen) #region Public Methods and Operators + /// + /// Logic to set the window to fullscreen or windowed mode without the border. + /// + /// + public virtual void SetBorderlessWindowFullScreen(bool borderlessFullScreen) + { + FullscreenIsBorderlessWindow = borderlessFullScreen; + } + public abstract void BeginScreenDeviceChange(bool willBeFullScreen); public void EndScreenDeviceChange() @@ -225,19 +234,19 @@ public void EndScreenDeviceChange() #region Methods - protected internal abstract void Initialize(GameContext gameContext); + public abstract void Initialize(GameContext gameContext); - internal bool Exiting; + public bool Exiting; - internal Action InitCallback; + public Action InitCallback; - internal Action RunCallback; + public Action RunCallback; - internal Action ExitCallback; + public Action ExitCallback; private bool isFullscreen; - internal abstract void Run(); + public abstract void Run(); /// /// Sets the size of the client area and triggers the event. @@ -253,7 +262,7 @@ public void SetSize(Int2 size) /// Only used internally by the device managers when they adapt the window size to the backbuffer size. /// Resizes the window, without sending the resized event. /// - internal abstract void Resize(int width, int height); + public abstract void Resize(int width, int height); public virtual IMessageLoop CreateUserManagedMessageLoop() { @@ -261,9 +270,9 @@ public virtual IMessageLoop CreateUserManagedMessageLoop() throw new PlatformNotSupportedException(); } - internal IServiceRegistry Services { get; set; } + public IServiceRegistry Services { get; set; } - protected internal abstract void SetSupportedOrientations(DisplayOrientation orientations); + public abstract void SetSupportedOrientations(DisplayOrientation orientations); protected void OnActivated(object source, EventArgs e) { @@ -319,12 +328,12 @@ protected void OnClosing(object source, EventArgs e) #endregion - internal void OnPause() + public void OnPause() { OnDeactivated(this, EventArgs.Empty); } - internal void OnResume() + public void OnResume() { OnActivated(this, EventArgs.Empty); } @@ -332,7 +341,7 @@ internal void OnResume() public abstract class GameWindow : GameWindow { - protected internal sealed override void Initialize(GameContext gameContext) + public sealed override void Initialize(GameContext gameContext) { var context = gameContext as GameContext; if (context != null) @@ -346,7 +355,7 @@ protected internal sealed override void Initialize(GameContext gameContext) } } - internal GameContext GameContext; + public GameContext GameContext; protected abstract void Initialize(GameContext context); } diff --git a/sources/engine/Stride.Games/GraphicsDeviceManager.cs b/sources/engine/Stride.Games/GraphicsDeviceManager.cs index bdf0fcc685..ccb49e0ee5 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/SDL/GameWindowSDL.cs b/sources/engine/Stride.Games/SDL/GameWindowSDL.cs index 4baa81c48e..140cfeefab 100644 --- a/sources/engine/Stride.Games/SDL/GameWindowSDL.cs +++ b/sources/engine/Stride.Games/SDL/GameWindowSDL.cs @@ -83,7 +83,7 @@ public override void EndScreenDeviceChange(int clientWidth, int clientHeight) deviceChangeWillBeFullScreen = null; } - protected internal override void SetSupportedOrientations(DisplayOrientation orientations) + public override void SetSupportedOrientations(DisplayOrientation orientations) { // Desktop doesn't have orientation (unless on Windows 8?) } @@ -133,7 +133,7 @@ private void GameForm_CloseActions() OnClosing(this, new EventArgs()); } - internal override void Run() + public override void Run() { Debug.Assert(InitCallback != null, $"{nameof(InitCallback)} is null"); Debug.Assert(RunCallback != null, $"{nameof(RunCallback)} is null"); @@ -269,7 +269,7 @@ protected override void SetTitle(string title) } } - internal override void Resize(int width, int height) + public override void Resize(int width, int height) { window.ClientSize = new Size2(width, height); } diff --git a/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs b/sources/engine/Stride.Games/WindowsStore/GamePlatformUWP.cs index 466ac7fc17..d8f131eab5 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() : base() { // 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..2e58999829 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() : base() { PopulateFullName(); } diff --git a/sources/engine/Stride.Graphics/AppContextType.cs b/sources/engine/Stride.Graphics/AppContextType.cs index a767ba508b..32371dcb8d 100644 --- a/sources/engine/Stride.Graphics/AppContextType.cs +++ b/sources/engine/Stride.Graphics/AppContextType.cs @@ -58,11 +58,14 @@ public enum AppContextType /// UWPCoreWindow, -#pragma warning disable SA1300 // Element must begin with upper-case letter /// /// Game running on iOS in a iPhoneOSGameView. /// iOS, -#pragma warning restore SA1300 // Element must begin with upper-case letter + + /// + /// Game running on a custom context. + /// + Custom, } } diff --git a/sources/engine/Stride.Input/InputManager.cs b/sources/engine/Stride.Input/InputManager.cs index 5b16714c14..44a6bacfd7 100644 --- a/sources/engine/Stride.Input/InputManager.cs +++ b/sources/engine/Stride.Input/InputManager.cs @@ -670,7 +670,10 @@ private void AddSources() // Add window specific input source var windowInputSource = InputSourceFactory.NewWindowInputSource(context); - Sources.Add(windowInputSource); + if (windowInputSource != null) + { + Sources.Add(windowInputSource); + } // Add platform specific input sources switch (context.ContextType) @@ -703,6 +706,8 @@ private void AddSources() #endif #endif break; + case AppContextType.Custom: // if the context is custom, we can't create an input source and assume the user will provide one. + break; default: throw new InvalidOperationException("GameContext type is not supported by the InputManager"); } diff --git a/sources/engine/Stride.Input/InputSourceFactory.cs b/sources/engine/Stride.Input/InputSourceFactory.cs index cd923917cf..a1e0e006e7 100644 --- a/sources/engine/Stride.Input/InputSourceFactory.cs +++ b/sources/engine/Stride.Input/InputSourceFactory.cs @@ -48,6 +48,8 @@ public static IInputSource NewWindowInputSource(GameContext context) var winformsContext = (GameContextWinforms)context; return new InputSourceWinforms(winformsContext.Control); #endif + case AppContextType.Custom: // if the context is custom, we can't create an input source and assume the user will provide one. + return null; default: throw new InvalidOperationException("GameContext type is not supported by the InputManager"); } diff --git a/sources/engine/Stride/Graphics/ImageSerializer.cs b/sources/engine/Stride/Graphics/ImageSerializer.cs index 1fa5cc4083..7eb1c8dfdc 100644 --- a/sources/engine/Stride/Graphics/ImageSerializer.cs +++ b/sources/engine/Stride/Graphics/ImageSerializer.cs @@ -7,7 +7,7 @@ namespace Stride.Graphics { - internal class ImageSerializer : ContentSerializerBase + public class ImageSerializer : ContentSerializerBase { public override void Serialize(ContentSerializerContext context, SerializationStream stream, Image textureData) {