dfkeenan / StrideToolkit

Stride Toolkit is a .NET Standard library for use with the Stride Game Engine.
MIT License
30 stars 5 forks source link

AddOnEventAction MicroThread List Question #2

Closed stefnotch closed 4 years ago

stefnotch commented 6 years ago

What's the point of the List of MicroThreads? Doesn't AddOnEventAction take care of that stuff?

tasks = new List<MicroThread>()
        {
            //Directly using EventKey so you don't have to declare EventReciever:
            Script.AddOnEventAction(SenderScript.SomeEvent, HandleSomeEvent),

        };
tasks.CancelAll();

I wonder if it's possible to make the syntax more elegant. (And as powerful as Rx?)

dfkeenan commented 6 years ago

The problem is the MicroThread being created when you call AddOnEventAction will listen for the SenderScript.SomeEvent indefinitely (until the game is closed). Even if you change scenes, the Entity that HandleSomeEvent is declared in is removed from the scene or the ScriptComponent is removed from the Entity.

So if your game logic requires you to stop handling that event i.e. player is dead or you change to the next level you need a way to stop handling the event. The list was just a convenience so if you started multiple MicroThreads you could stop them all with one method call. You could also just store them in variables. i.e.

someEventMicroThread = Script.AddOnEventAction(SenderScript.SomeEvent, HandleSomeEvent);
//.......
someEventMicroThread.Cancel();

This is the same as if you used the out of the box Script.AddTask.

It might be possible to make it so it automatically handles the Scene, Entity or ScriptComponent being removed. (Possibly requiring an extra parameter.) Which is probably the common scenario when you would want to stop handling the event.

As for Rx it's, probably not a massive amount of work to create methods like:

public static IObservable<T> AsObservable<T>(
            this ScriptSystem scriptSystem,
            EventKey<T> eventKey,
            long priority = 0L)
{ 
    //...
}

I personally have never used Rx so wasn't high on my priority. But if there is demand for it we can look into it.

stefnotch commented 6 years ago

I tried to create a ScriptComponent.AddTask(), that adds a task which gets cancelled when the script gets cancelled. That sort of approach could also be used for event handlers.

What do you think about it?

public static class ScriptComponentExtensions
{
    public static void AddTask(this ScriptComponent script, Func<Task> task, long priority = 0L)
    {
        MicroThread t = script.Script.AddTask(task, priority);
        script.Entity.GetOrCreate<TaskDisposer>().Tasks.Add(t);
    }

    private class TaskDisposer : ScriptComponent
    {
        public List<MicroThread> Tasks { get; } = new List<MicroThread>();
        public override void Cancel()
        {
            Tasks.ForEach(task => task.Cancel());
        }
    }
}
dfkeenan commented 6 years ago

That is an option. I was going to try something a bit fancier/trickier.

stefnotch commented 6 years ago

Regarding Rx, this seems to be fairly similar to your Script.AddTask(DelayedTask, TimeSpan.FromSeconds(2));.

dfkeenan commented 4 years ago

Closing this issue for now.