Page MenuHomeFeedback Tracker

[Featue Request] Persistent ScriptInvoker for events
New, NormalPublic

Description

Problem

ScriptInvoker is used for event callbacks, but it has two problems:

  1. It doesn't call inserted callback if invoke called before insertion:
MyInvokerClass myInvoker;
myInvoker.GetOnData().Insert(fn1); // fn1 is called
myInvoker.OnData(new MyData());
myInvoker.GetOnData().Insert(fn2); // but fn2 is not called

// to call fn2 you need to add extra code everywehere
if (/* some condition */)
    fn2();
  1. Manually calling inserted callback can be difficult due to mandatory function parameters that you don't have access to and/or can be difficult to get:
MyData data = myInvoker.GetData(); // GetData may be missing or non-public
if (data) // GetData 
    fn2(data);

// or

array<MyData> dataArr = new array<MyData>();
myInvoker.GetDataArray(dataArr); // GetDataArray can be very expensive due to creating a copy of the array, while myInvoker has direct access to it and calls the inserted callback by passing it directly.
foreach (MyData data : dataArr)
{
    fn2(data);
};

Solution

To solve these problems I suggest to add PersistentScriptInvokerBase class with definition like this:

class PersistentScriptInvokerBase<Class T> : ScriptInvokerBase<T>
{
    protected func m_PersistentCallback;

    void PersistentScriptInvokerBase(func fn)
    {
        SetPersistentCallback(fn);
    };

    void SetPersistentCallback(func fn)
    {
        m_PersistentCallback = fn;
    };

    func GetPersistentCallback()
    {
        return m_PersistentCallback;
    };
    
    override void Insert(T fn, bool persistent = true)
    {
        super.Insert(fn);

        if (!persistent || !m_PersistentCallback)
            return;

        m_PersistentCallback(fn);
    };
};

Usage example

So, usage will be:

class MyInvokerClass
{
    protected MyData m_Data;

    protected PersistentScriptInvoker m_OnDataEvent;

    void MyInvokerClass()
    {
        m_Data = null;
        m_OnDataEvent = PersistentScriptInvoker(OnPersistentStateChanged);
    };

    void OnData(MyData data)
    {
        m_Data = data;

        if (!data)
            return;

        m_OnDataEvent.Invoke(this, data);
    };

    void OnPersistentData(func fn)
    {
        if (!m_Data)
            return;

        fn(this, m_Data)
    };

    PersistentScriptInvoker GetOnData()
    {
        return m_OnDataEvent;
    };
};
MyInvokerClass myInvoker;

myInvoker.GetOnData().Insert(fn1); // fn1 is not called

myInvoker.OnData(new MyData()); // fn1 is called

myInvoker.GetOnData().Insert(fn2); // fn2 is called
myInvoker.GetOnData().Insert(fn3, false); // fn3 is not called
myInvoker.GetOnData().Insert(fn4, persistent); // fn4 is called if persistent is true

myInvoker.OnData(new MyData()); // fn1, fn2, fn3 and fn4 are called

Details

Severity
Feature
Resolution
Open
Reproducibility
N/A
Operating System
Windows 11 x64
Category
General

Event Timeline

vlad333000 updated the task description. (Show Details)