Open ParadiseFallen opened 2 years ago
So after some research issue is exatly how events actually handled by stride.
By default game will Tick()
ONLY when reach next frame.
What we actually need is to run 2 threads for app.
Thread thread1 = new Thread(RunCallback);
thread1.Start();
But then we facing new issue: Sync
.
For communication between UI and Logic we could use System.IO.Pipelines or Rx.Net(Can scheldule work on diff threads. Works perfectly well and looks like prefered variant).
Current issue is: How to render on background and then display it to window.
I thought about IEnumerable<IDrawCommand> RenderCommands
that Window
can Replay(command)
when next frame ready on background thread. But there is issue if game uses that render result ingame (i.e. ingame cameras. some postrendering processing. etc.).
So this means we need to fully compose image on background thred and then just on Window
side do var frame = await Game.Frames.FirstAsync()
and just display it.
Main issue is right there:
Also with this aproach its easy to impliment Headless
GamePlatform
, which just start game logic as main thread and do nothing with window.
AND we need to add kinda EnableRendering : bool
property to game. If game run as headles and dosen't require frames to render than we can disable it and optimize for hosting (most cases). Or still perform rendering and pushing new frames to IObservable<Frame> Frames {get;}
property if we want to display it somewhere.
Seems like this changes that we need to do (step by step):
[ ] Expose all communication as System.Reactive
extension points. This will provide easy changes outer frameworks (easy use UWP, WPF, SDL2, Avalonia, and even Stride
itself to make game in game LOL). Game
should expose extension points like PushEvent()
or directly Game.WindowEvents.OnNext(@event)
. It means each platform will transform platform specific event to generic stride events and push em in game.
[ ] Make GamePlatform
: IDisposable
. Need this for background thread stopping.
[ ] On SDL2
runtime need to modify code.
using (var renderLoop = new SDLMessageLoop(form))
{
while (renderLoop.NextFrame())
{
var lastFrame = Game.Frames.Last();
renderToWindow(lastFrame); // <== dunno how to impliment this part.
}
}
It means we display last ready frame and ONLY when window is ready for it. But still keep rendering on background.
So if we start dragging window we stop this displaying
. Window image will freeze. Not logic. And when we stop dragging we dislay last fresh frame (I don't think we'll get any significant delay here. we’ll even speed it up while the finished scene is displayed, we are already preparing the next one in parallel).
// in loop
Game.WindowEvents.OnNext(transformToStrideEvevnt(e));
This means we always pushing there each event that we get. But When game perform Tick()
there will be Buffer
of all unhandled events and game logic can handle that buffer. While game proceesing given slice of event next bucket of event is filled by main Window
thread. There is no racce conditions and all perfectly synced.
// UnhandledWindowEvents is IObservable<StrideGameEvent>. that created in ctor by rx expression that will chunk events
handleWindowEvents(this.UnhandledWindowEvents);
[ ] Change GamePlatform to make em decide main
or background
thread execution of logic
Game platform is run ALWAYS by main thread.
this.Frames.OnNext(renderResult)
any ideas about this?
script for testing is
public class TestScript : AsyncScript
{
// Declared public member fields and properties will show in the game studio
public UIComponent Ui { get; init; }
private TextBlock TextBlock { get; set; }
private int Counter { get; set; } = 0;
private Task Start()
{
TextBlock = Ui.Page.RootElement.FindVisualChildOfType<TextBlock>();
return Task.CompletedTask;
}
private async Task Tick()
{
TextBlock.Text = Counter.ToString();
Counter++;
await Task.Delay(TimeSpan.FromSeconds(1));
}
public override async Task Execute()
{
Game.Window.AllowUserResizing = true;
await Start();
while (Game.IsRunning)
{
await Tick();
}
}
}
Bump, would like to mess with networking in stride but this is a major issue
Stride is a community project, people contribute to this engine out of their own free time. If you want to see this feature in the engine, your best bet is to do it yourself or find someone else who will do so in your stead
Is your feature request related to a problem? Please describe. Game core must be independet with window. If it will be independent its easy to beals windowless game. I.e. game server. So you can
write once use as you want
. You dont need to write same logic again. Also with this feature will help in #1485. If core will be separated it's easy to made concurency collections / pipes in places where window send events in core and core renders to window.Describe the solution you'd like Made
core
independent. AddRunCoreAsync()
which will configure and run core without renderers / window. AddRunAsync()
which will configurewindow / rendering
and create em after start.In fact, it would be cool to create a
HostBuilder
for Stride. #1487Here are some questions that can aid in the description of the feature request: