Skip to content

Commit

Permalink
make it trim and AOT compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
LeNitrous committed Jun 24, 2023
1 parent 24f6a2e commit 4f4c642
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 40 deletions.
2 changes: 1 addition & 1 deletion samples/SampleGame/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static class Program
{
private static void Main()
{
Host.Run<Sample>();
Host.Run<Sample>(new HostOptions { Title = "Sample" });
}
}

Expand Down
4 changes: 4 additions & 0 deletions samples/SampleGame/SampleGame.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../../source/Sekai.Desktop/Sekai.Desktop.csproj" />
<ProjectReference Include="../../source/Sekai.OpenAL/Sekai.OpenAL.csproj" />
Expand Down
5 changes: 5 additions & 0 deletions samples/SampleGame/TrimmerRoots.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<linker>
<assembly fullname="Sekai.OpenGL" preserve="all"/>
<assembly fullname="Sekai.OpenAL" preserve="all"/>
<assembly fullname="Sekai.Desktop" preserve="all"/>
</linker>
6 changes: 3 additions & 3 deletions source/Sekai.Desktop/DesktopPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Sekai.Desktop;
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("osx")]
internal sealed unsafe class DesktopPlatform : Platform, IInputContext
internal sealed unsafe class DesktopPlatform : Platform, IInputSource
{
public override IMonitor PrimaryMonitor => monitors.Values.FirstOrDefault(m => m.Handle == glfw.GetPrimaryMonitor());
public override IEnumerable<IMonitor> Monitors => monitors.Values.Cast<IMonitor>();
Expand Down Expand Up @@ -136,9 +136,9 @@ private Monitor createMonitorFromHandle(int index, Silk.NET.GLFW.Monitor* monito
return new(index, name, monitor, new(x, y), new(new(mc->Width, mc->Height), mc->RefreshRate), ms);
}

IEnumerable<IInputDevice> IInputContext.Devices => devices.Values;
IEnumerable<IInputDevice> IInputSource.Devices => devices.Values;

event Action<IInputDevice, bool>? IInputContext.ConnectionChanged
event Action<IInputDevice, bool>? IInputSource.ConnectionChanged
{
add => connectionChanged += value;
remove => connectionChanged -= value;
Expand Down
4 changes: 2 additions & 2 deletions source/Sekai.Desktop/Windowing/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Sekai.Desktop.Windowing;
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("osx")]
internal sealed unsafe partial class Window : IWindow, IHasIcon, IHasDragDrop, IGLContextSource, IInputContext
internal sealed unsafe partial class Window : IWindow, IHasIcon, IHasDragDrop, IGLContextSource, IInputSource
{
public bool Exists { get; private set; }

Expand Down Expand Up @@ -294,7 +294,7 @@ public string Title
glfw.SwapInterval
);

public string Class { get; init; } = "Sekai";
public string Class { get; } = "Sekai";

public IEnumerable<IInputDevice> Devices => devices;

Expand Down
2 changes: 1 addition & 1 deletion source/Sekai.Headless/Windowing/DummyWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal sealed class DummyWindow : IWindow, IHasSuspend, IHasRestart
public bool HasFocus { get; private set; }
public bool Visible { get; set; }
public string Title { get; set; } = string.Empty;
public string Class { get; init; } = string.Empty;
public string Class { get; } = string.Empty;

public Size Size
{
Expand Down
5 changes: 5 additions & 0 deletions source/Sekai/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public Host Host
/// </summary>
public Logger Logger => Host.Logger;

/// <summary>
/// The options passed during initialization.
/// </summary>
public HostOptions Options => Host.Options;

private Host? host;

/// <summary>
Expand Down
34 changes: 20 additions & 14 deletions source/Sekai/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ public sealed class Host
/// Gets or sets the ticking mode.
/// </summary>
/// <remarks>
/// When set to <see cref="TickMode.Fixed"/>, the target time between frames is provided by <see cref="UpdatePerSecond"/>.
/// When set to <see cref="TickMode.Fixed"/>, the target time between frames is provided by <see cref="UpdateRate"/>.
/// Otherwise, it is the duration of each elapsed frame.
/// </remarks>
public TickMode TickMode { get; set; } = TickMode.Fixed;

/// <summary>
/// Gets or sets the update rate of the game when <see cref="TickMode"/> is <see cref="TickMode.Fixed"/>.
/// Gets or sets the update rate (in seconds) of the game when <see cref="TickMode"/> is <see cref="TickMode.Fixed"/>.
/// </summary>
/// <remarks>
/// The returned value may be an approximation of the originally set value.
/// </remarks>
public double UpdatePerSecond
public double UpdateRate
{
get => 1000 / msPerUpdate.Milliseconds;
set
Expand Down Expand Up @@ -85,6 +85,7 @@ public HostState State
public IEnumerable<IMonitor> Monitors => platform?.Monitors ?? throw hostNotLoadedException;

internal Logger Logger { get; private set; } = new();
internal HostOptions Options { get; private set; }
internal IWindow Window => window ?? throw hostNotLoadedException;
internal InputState Input => input ?? throw hostNotLoadedException;
internal AudioDevice Audio => audio ?? throw hostNotLoadedException;
Expand All @@ -106,23 +107,26 @@ public HostState State
private TimeSpan previousTime;
private readonly object sync = new();
private readonly Stopwatch stopwatch = new();
private readonly MergedInputContext inputContext = new();
private readonly MergedInputSource inputContext = new();
private static readonly TimeSpan wait_threshold = TimeSpan.FromMilliseconds(2);

private Host()
private Host(HostOptions? options = null)
{
Options = options ?? new();
TickMode = Options.TickMode;
UpdateRate = Options.UpdateRate;
}

/// <summary>
/// Runs the game.
/// </summary>
/// <typeparam name="T">The game to run.</typeparam>
public static void Run<T>()
public static void Run<T>(HostOptions? options = null)
where T : Game, new()
{
try
{
RunAsync<T>().Wait();
RunAsync<T>(options).Wait();
}
catch (AggregateException e)
{
Expand All @@ -136,11 +140,11 @@ public static void Run<T>()
/// <typeparam name="T">The game to run.</typeparam>
/// <param name="token">The cancellation token when canceled closes the game.</param>
/// <returns>A task that represents the game's main execution loop.</returns>
public static async Task RunAsync<T>(CancellationToken token = default)
public static async Task RunAsync<T>(HostOptions? options = null, CancellationToken token = default)
where T : Game, new()
{
var game = new T();
var host = new Host();
var host = new Host(options);
await host.run(game, token);
}

Expand Down Expand Up @@ -181,8 +185,10 @@ private async Task run(Game game, CancellationToken token = default)
Logger.Log("--------------------------------------------------------");

window = platform.CreateWindow();
window.Title = $"Sekai{(asm?.Name is not null ? $" (running {asm.Name})" : string.Empty)}";
window.Size = Options.WindowSize;
window.Title = Options.Title;
window.State = WindowState.Minimized;
window.Border = Options.WindowBorder;
window.Closed += Exit;

if (window is IHasSuspend suspendable)
Expand Down Expand Up @@ -291,12 +297,12 @@ private bool runTick()
{
case HostState.Loading:
{
if (window is IInputContext windowInput)
if (window is IInputSource windowInput)
{
inputContext.Add(windowInput);
}

if (platform is IInputContext platformInput)
if (platform is IInputSource platformInput)
{
inputContext.Add(platformInput);
}
Expand Down Expand Up @@ -515,7 +521,7 @@ private static U getProvider<T, U>(string[] assemblyNames)
throw new InvalidOperationException("Failed to load provider.");
}

private static bool tryLoad<T, U>(string assemblyName, [NotNullWhen(true)] out U? provider)
private static bool tryLoad<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T, U>(string assemblyName, [NotNullWhen(true)] out U? provider)
where T : Attribute, IProviderAttribute
where U : class
{
Expand All @@ -536,7 +542,7 @@ private static bool tryLoad<T, U>(string assemblyName, [NotNullWhen(true)] out U
return false;
}

provider = (U)Activator.CreateInstance(att.Type, true)!;
provider = (U)Activator.CreateInstance(att.Type)!;

return true;
}
Expand Down
52 changes: 52 additions & 0 deletions source/Sekai/HostOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) Cosyne
// Licensed under MIT. See LICENSE for details.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Sekai.Mathematics;
using Sekai.Windowing;

namespace Sekai;

/// <summary>
/// Options passed to <see cref="Host"/> during initialization.
/// </summary>
public sealed class HostOptions
{
/// <summary>
/// The window's title.
/// </summary>
public string Title { get; init; } = Assembly.GetEntryAssembly()?.GetName()?.Name ?? "Sekai";

/// <summary>
/// The host's tick mode.
/// </summary>
public TickMode TickMode { get; init; } = TickMode.Variable;

/// <summary>
/// The host's update rate.
/// </summary>
public double UpdateRate { get; init; } = 120.0;

/// <summary>
/// The window's size.
/// </summary>
public Size WindowSize { get; init; } = new Size(1280, 720);

/// <summary>
/// The window's border presentation.
/// </summary>
public WindowBorder WindowBorder { get; init; } = WindowBorder.Resizable;

/// <summary>
/// The arguments passed when the program was launched.
/// </summary>
public IReadOnlyList<string> Arguments { get; } = Environment.GetCommandLineArgs();

/// <summary>
/// The environment variables passed when the program was launched.
/// </summary>
public IDictionary Variables { get; } = Environment.GetEnvironmentVariables();
}
4 changes: 3 additions & 1 deletion source/Sekai/Hosting/AudioProviderAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace Sekai.Hosting;

Expand All @@ -13,9 +14,10 @@ namespace Sekai.Hosting;
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class AudioProviderAttribute : Attribute, IProviderAttribute
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public Type Type { get; }

public AudioProviderAttribute(Type type)
public AudioProviderAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)
{
Type = type;
}
Expand Down
4 changes: 3 additions & 1 deletion source/Sekai/Hosting/GraphicsProviderAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@

using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace Sekai.Hosting;

[AttributeUsage(AttributeTargets.Assembly)]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class GraphicsProviderAttribute : Attribute, IProviderAttribute
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public Type Type { get; }

public GraphicsProviderAttribute(Type type)
public GraphicsProviderAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)
{
Type = type;
}
Expand Down
2 changes: 2 additions & 0 deletions source/Sekai/Hosting/IProviderAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
// Licensed under MIT. See LICENSE for details.

using System;
using System.Diagnostics.CodeAnalysis;

namespace Sekai.Hosting;

internal interface IProviderAttribute
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
Type Type { get; }
}
4 changes: 3 additions & 1 deletion source/Sekai/Hosting/PlatformProviderAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@

using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace Sekai.Hosting;

[AttributeUsage(AttributeTargets.Assembly)]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class PlatformProviderAttribute : Attribute, IProviderAttribute
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public Type Type { get; }

public PlatformProviderAttribute(Type type)
public PlatformProviderAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)
{
Type = type;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Sekai.Input;
/// <summary>
/// The input source hosting all available devices.
/// </summary>
public interface IInputContext
public interface IInputSource
{
/// <summary>
/// An enumeration of all available devices.
Expand Down
Loading

0 comments on commit 4f4c642

Please sign in to comment.