Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requirements for fully custom Game runtime management #2404

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions sources/engine/Stride.Engine/Engine/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion sources/engine/Stride.Games/Android/GamePlatformAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private void PopulateFullName()
FullName = $"{manufacturer} - {model}";
}

public GamePlatformAndroid(GameBase game) : base(game)
public GamePlatformAndroid() : base()
{
PopulateFullName();
}
Expand Down
6 changes: 3 additions & 3 deletions sources/engine/Stride.Games/Desktop/GamePlatformDesktop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -51,7 +51,7 @@ public override string DefaultAppDirectory
}
}

internal override GameWindow GetSupportedGameWindow(AppContextType type)
public override GameWindow GetSupportedGameWindow(AppContextType type)
{
switch (type)
{
Expand Down
6 changes: 3 additions & 3 deletions sources/engine/Stride.Games/Desktop/GameWindowWinforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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?)
}
Expand Down Expand Up @@ -166,7 +166,7 @@ protected override void Initialize(GameContext<Control> 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");
Expand Down Expand Up @@ -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);
}
Expand Down
59 changes: 49 additions & 10 deletions sources/engine/Stride.Games/GameBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -59,7 +59,7 @@ public abstract class GameBase : ComponentBase, IGame

private bool isMouseVisible;

internal object TickLock = new object();
public object TickLock = new object();

#endregion

Expand All @@ -68,7 +68,43 @@ public abstract class GameBase : ComponentBase, IGame
/// <summary>
/// Initializes a new instance of the <see cref="GameBase" /> class.
/// </summary>
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<IDatabaseFileProviderService>(new DatabaseFileProviderService(null));

LaunchParameters = new LaunchParameters();
GameSystems = new GameSystemCollection(Services);
Services.AddService<IGameSystemCollection>(GameSystems);

// Setup registry
Services.AddService<IGame>(this);

IsActive = true;
}

/// <summary>
/// Initializes a new instance of the <see cref="GameBase" /> class.
/// </summary>
protected GameBase(GamePlatform platform = null)
{
// Internals
Log = GlobalLogger.GetLogger(GetType().GetTypeInfo().Name);
Expand Down Expand Up @@ -96,7 +132,10 @@ protected GameBase()
Services.AddService<IGameSystemCollection>(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;
Expand Down Expand Up @@ -197,7 +236,7 @@ protected GameBase()
/// Gets a value indicating whether this instance is active.
/// </summary>
/// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
public bool IsActive { get; private set; }
public bool IsActive { get; protected set; }

/// <summary>
/// Gets a value indicating whether this instance is exiting.
Expand All @@ -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
/// </summary>
/// <value><c>true</c> if this instance forces one update step per one draw step; otherwise, <c>false</c>.</value>
protected internal bool ForceOneUpdatePerDraw { get; set; }
protected bool ForceOneUpdatePerDraw { get; set; }

/// <summary>
/// When <see cref="IsFixedTimeStep"/> is set, is it allowed to render frames between two steps when we have time to do so.
Expand Down Expand Up @@ -340,7 +379,7 @@ public void ResetElapsedTime()
forceElapsedTimeToZero = true;
}

internal void InitializeBeforeRun()
public void InitializeBeforeRun()
{
try
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -848,7 +887,7 @@ protected virtual void Initialize()
GameSystems.Initialize();
}

internal virtual void LoadContentInternal()
public virtual void LoadContentDefault()
{
GameSystems.LoadContent();
}
Expand Down Expand Up @@ -978,7 +1017,7 @@ private void GraphicsDeviceService_DeviceCreated(object sender, EventArgs e)

if (GameSystems.State != GameSystemState.ContentLoaded)
{
LoadContentInternal();
LoadContentDefault();
}
}

Expand Down
16 changes: 8 additions & 8 deletions sources/engine/Stride.Games/GameContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,40 @@ public abstract class GameContext
/// Gets the main loop callback to be called when <see cref="IsUserManagingRun"/> is true.
/// </summary>
/// <value>The run loop.</value>
public Action RunCallback { get; internal set; }
public Action RunCallback { get; set; }

/// <summary>
/// Gets the exit callback to be called when <see cref="IsUserManagingRun"/> is true when exiting the game.
/// </summary>
/// <value>The run loop.</value>
public Action ExitCallback { get; internal set; }
public Action ExitCallback { get; set; }

// TODO: remove these requested values.

/// <summary>
/// The requested width.
/// </summary>
internal int RequestedWidth;
public int RequestedWidth;

/// <summary>
/// The requested height.
/// </summary>
internal int RequestedHeight;
public int RequestedHeight;

/// <summary>
/// The requested back buffer format.
/// </summary>
internal PixelFormat RequestedBackBufferFormat;
public PixelFormat RequestedBackBufferFormat;

/// <summary>
/// The requested depth stencil format.
/// </summary>
internal PixelFormat RequestedDepthStencilFormat;
public PixelFormat RequestedDepthStencilFormat;

/// <summary>
/// The requested graphics profiles.
/// </summary>
internal GraphicsProfile[] RequestedGraphicsProfile;
public GraphicsProfile[] RequestedGraphicsProfile;

/// <summary>
/// The device creation flags that will be used to create the <see cref="GraphicsDevice"/>.
Expand All @@ -98,7 +98,7 @@ public abstract class GameContext
/// Product name of game.
/// TODO: Provide proper access title through code and game studio
/// </summary>
internal static string ProductName
public static string ProductName
{
get
{
Expand Down
2 changes: 2 additions & 0 deletions sources/engine/Stride.Games/GameContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
33 changes: 22 additions & 11 deletions sources/engine/Stride.Games/GamePlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
/// <summary>
/// <see cref="GamePlatform"/> should be configured by calling <see cref="ConfigurePlatform"/> before being used.
/// </summary>
protected GamePlatform()
{
}

/// <summary>
/// This is called by the game to configure the platform within the <see cref="GameBase"/> constructor.
/// </summary>
/// <param name="gameBase"></param>
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
}

Expand Down Expand Up @@ -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)
{
Expand Down
11 changes: 8 additions & 3 deletions sources/engine/Stride.Games/GameTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ public double Factor
set => factor = value > 0 ? value : 0;
}


internal void Update(TimeSpan totalGameTime, TimeSpan elapsedGameTime, bool incrementFrameCount)
/// <summary>
/// Set <see cref="Total" /> and <see cref="Elapsed" /> to the properties provided, also increments frame count if <paramref name="incrementFrameCount" /> is true
/// </summary>
public void Update(TimeSpan totalGameTime, TimeSpan elapsedGameTime, bool incrementFrameCount)
{
Total = totalGameTime;
Elapsed = elapsedGameTime;
Expand All @@ -145,7 +147,10 @@ internal void Update(TimeSpan totalGameTime, TimeSpan elapsedGameTime, bool incr
}
}

internal void Reset(TimeSpan totalGameTime)
/// <summary>
/// Set <see cref="Total" /> to <paramref name="totalGameTime" /> and reset every other properties to their initial value.
/// </summary>
public void Reset(TimeSpan totalGameTime)
{
Update(totalGameTime, TimeSpan.Zero, false);
accumulatedElapsedTime = TimeSpan.Zero;
Expand Down
Loading