stride3d / stride

Stride (formerly Xenko), a free and open-source cross-platform C# game engine.
https://stride3d.net
MIT License
6.65k stars 957 forks source link

[RFC] Stride multithreading | Separate logic and windowing #1488

Open ParadiseFallen opened 2 years ago

ParadiseFallen commented 2 years ago

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. Add RunCoreAsync() which will configure and run core without renderers / window. Add RunAsync() which will configure window / rendering and create em after start.

In fact, it would be cool to create a HostBuilder for Stride. #1487

Here are some questions that can aid in the description of the feature request:

What are the usecases?

  • Run raw game login without any rendering. Calculate physics process or game server What kind of options/settings are expected/wanted?
  • separate loginc and rendering with input system. suggested methods What would the (pseudo) code look like?
  • idk. there can be large work. First need to define all places where logic and window acting. separate em. Is the feature affecting behaviour in the editor?
  • No. But game with this can be run in editor directly. Just bind editor scene and run game logic. Editor view will be renderer for us (game window) Is there a component or datastructure?
  • architecture what kind of documentation is needed or needs to be updated?
  • write new docs about how to build windowles and run just core Should there be an example project?
  • one project will be enough. But when networking comes to Stride
ParadiseFallen commented 1 year 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.

ParadiseFallen commented 1 year ago

Seems like this changes that we need to do (step by step):

ParadiseFallen commented 1 year ago
ParadiseFallen commented 11 months ago

any ideas about this?

ParadiseFallen commented 11 months ago

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();
        }
    }
}
Consumedgrub2 commented 4 months ago

Bump, would like to mess with networking in stride but this is a major issue

Eideren commented 4 months ago

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