Extended Timers

Started by ., Sep 14, 2015, 07:45 PM

Previous topic - Next topic

.

NOTE: For a faster, safer and more efficient implementation, please use this instead.



Well, I got curious and you know what happens when I get curious ;D Here's the code:

[noae]// ------------------------------------------------------------------------------------------------
srand((GetTickCount() % time()) / 3);

// ------------------------------------------------------------------------------------------------
_Timer <- {
    // --------------------------------------------------------------------------------------------
    m__Timers = { /* ... */ }

    // --------------------------------------------------------------------------------------------
    function Create(environment, listener, interval, repeat, ...)
    {
        // ----------------------------------------------------------------------------------------
        // Prepare the arguments pack
        vargv.insert(0, environment);
        // ----------------------------------------------------------------------------------------
        // Store timer information into a table
        local data = {
            Environment = environment,
            Listener = listener,
            Interval = interval,
            Repeat = repeat,
            Timer = null,
            Args = vargv
        };
        // ----------------------------------------------------------------------------------------
        local hash = split(data+"", ":")[1].slice(3, -1).tointeger(16);
        // ----------------------------------------------------------------------------------------
        // Create the timer instance
        data.Timer = NewTimer("tm_TimerProcess", interval, repeat, hash);
        // ----------------------------------------------------------------------------------------
        // Store the timer information
        m__Timers.rawset(hash, data);
        // ----------------------------------------------------------------------------------------
        // Return the hash that identifies this timer
        return hash;
    }

    // --------------------------------------------------------------------------------------------
    function Destroy(hash)
    {
        // See if the specified timer exists
        if (m__Timers.rawin(hash))
        {
            // Destroy the timer instance
            m__Timers.rawget(hash).Timer.Delete();
            // Remove the timer information
            m__Timers.rawdelete(hash);
        }
    }

    // --------------------------------------------------------------------------------------------
    function Exists(hash)
    {
        // See if the specified timer exists
        return m__Timers.rawin(hash);
    }

    // --------------------------------------------------------------------------------------------
    function Fetch(hash)
    {
        // Return the timer information
        return m__Timers.rawget(hash);
    }

    // --------------------------------------------------------------------------------------------
    function Clear()
    {
        // Process all existing timers
        foreach (tm in m__Timers)
        {
            // Destroy the timer instance
            tm.Timer.Delete();
        }
        // Clear existing timers
        m__Timers.clear();
    }
}

// ------------------------------------------------------------------------------------------------
tm_TimerProcess <- function(hash)
{
    // See if the specified timer exists
    if (_Timer.m__Timers.rawin(hash))
    {
        // Get the timer associated with the specified hash
        local tm = _Timer.m__Timers.rawget(hash);
        // Call the specified listener
        tm.Listener.pacall(tm.Args);
        // Calculate the remaining cycles
        if (tm.Repeat && (--tm.Repeat <= 0))
        {
            // Release the timer
            _Timer.Destroy(hash);
        }
    }
}
[/noae]

Here's example code:
[noae]function FreeFunc(table, array)
{
    print(" -------- BEGIN FREE FUNCTION -------- ");
    foreach(k, v in table) print(k + " -> " + v);
    foreach(v in array) print(">> " + v);
    print(" -------- END FREE FUNCTION -------- ");
}

_Timer.Create(this, FreeFunc, 1000, 3, {a = "x", b = "y", c = "z"}, [22, true, "foo"]);

class Dummy
{
    FnType = "METHOD"

    constructor()
    {
        _Timer.Create(this, MethodFunc, 1000, 3, {a = "x", b = "y", c = "z"}, [22, true, "foo"]);
    }

    function MethodFunc(table, array)
    {
        print(" -------- BEGIN " + FnType + " FUNCTION -------- ");
        foreach(k, v in table) print(k + " -> " + v);
        foreach(v in array) print(">> " + v);
        print(" -------- END " + FnType + " FUNCTION -------- ");
    }
}

local dm = Dummy();
[/noae]

Supports calling both global functions or instance methods and allows any kind of argument to be passed. Of course this adds a bit more stress to the script than the usual timer but I've seen you waste more resources on way more stupid things. Therefore, this timer implementation should be the least of your worries when it comes to performance.

Use carefully and the reason I haven't documented any code and pretty much left this as self explanatory is because I don't want nabs to start using it and mess sh!t up. If you're a decent programmer then you should know how to use this.
.

.

#1
Updated to a simplified approach. The implementation supports global functions/local functions/anonymous functions/lambdas/class methods/instance methods.

Functions:
function KickPlayer(player)
{
    player.Kick();
}

function onPlayerJoin(player)
{
    _Timer.Create(this, KickPlayer, 5000, 1, player);
}

Anonymous functions:
function onPlayerJoin(player)
{
    _Timer.Create(this, function(player) {
        player.Kick();
    }, 5000, 1, player);
}

Lambdas:
function onPlayerJoin(player)
{
    _Timer.Create(this, @(player) player.Kick(), 5000, 1, player);
}

Class/instance methods:
function onPlayerJoin(player)
{
    _Timer.Create(player, CPlayer.Kick, 5000, 1);
}
.

.

#2
Fixed a leak because I forgot to destroy the timer instance. Also implemented the Clear function to terminate all timers. Useful when shutting down the server.

Now this should work as expected:
// ------------------------------------------------------------------------------------------------
_Timer.Create(this, @() print("a"), 1000, 0);
_Timer.Create(this, @() print("b"), 2000, 0);
_Timer.Create(this, @() _Timer.Clear(), 5000, 1);
.

Murdock

Really useful! Thanks!