Skip to content

Instantly share code, notes, and snippets.

@Sar777
Forked from Naios/TaskSchedulerExamples.md
Last active August 29, 2015 14:22
Show Gist options
  • Save Sar777/079eb233ecccd8eac7cd to your computer and use it in GitHub Desktop.
Save Sar777/079eb233ecccd8eac7cd to your computer and use it in GitHub Desktop.

TaskScheduler guide for TrinityCore Scripting

Basic Usage

The Basis usage is like EventMap

#include "TaskScheduler"

TaskScheduler scheduler;

void UpdateAI(uint32 diff) override
{
    // Update the scheduler with the given difftime in ms.
    scheduler.Update(diff);
}

Scheduling Tasks

Scheduling tasks is very easy with lamdas, if you are not familar with c++ lamdas check it out, you can also use static methods, member methods or std::bind (everything which convertible into std::function<void(TaskContext)>).

void EnterCombat(Unit* /*who*/) override
{
    scheduler.Schedule(Seconds(3), [this](TaskContext context)
    {
        me->Yell("Hey, this is a simple task scheduler test", LANG_UNIVERSAL);
    });
    
    // Schedule with a random time between 5 and 8 seconds.
    scheduler.Schedule(Seconds(5), Seconds(8), [this](TaskContext context)
    {
        // ... Do something
    });

    // Schedule an async task std::function<void()>
    scheduler.Async([this]
    {
        // ... Do something
    });
}

Modify Tasks

Its also possible to assign group id's to tasks

enum Groups
{
    GROUP_ONE,
    GROUP_TWO,
    GROUP_THREE
}

// Schedule with a random time between 5 and 8 seconds.
scheduler.Schedule(Seconds(5), GROUP_ONE, [this](TaskContext context)
{
    // ... Do something
});

scheduler.CancelGroup(GROUP_ONE);

scheduler.CancelAll();

// More methods are available, just check it out, the TaskScheduler is well documented.
scheduler.DelayGroup(GROUP_ONE, Seconds(3), Seconds(5));

scheduler.DelayAll(Seconds(3));

scheduler.RescheduleGroup(GROUP_ONE, Seconds(3), Seconds(5));

Every method which requires a time duration is overloaded several times and to accept a static time or a random time between min and max (equal to EventMap usage with urand()).

Nearly every method call returns this as reference which makes it possible to concat multiple calls together:

scheduler
    .Schedule(Milliseconds(1000), 20, [](TaskContext context)
    {
        std::cout << "Delay: Second" << std::endl;
    })
    .Schedule(Milliseconds(1500), 21, [](TaskContext context)
    {
        std::cout << "Delay: First" << std::endl;
    })
    .Schedule(Milliseconds(500), 22, [](TaskContext context)
    {
        std::cout << "Delay: Third" << std::endl;
    });

Working with the current executed Task (TaskContext)

The TaskContext provides the ability the modify or to repeat the current event. You can also store the TaskContext in the script for further usage.

Also the TaskContext provides the ability to modify the TaskScheduler safe (never access the TaskScheduler directly from a scheduled task).

scheduler.Schedule(Seconds(5), [this](TaskContext context)
{
    // Modify the TaskScheduler from the called task.
    context->CancelAll();

    // Schedule a new task from within the task.
    context->Schedule(Seconds(7), GROUP_ONE, [this](TaskContext context)
    {
        // ... Do something
    });

    // Repeat with the same duration
    context->Repeat();

    // Repeat with 4s
    context->Repeat(Seconds(4));

    // Repeat with a random duration between 6s and 10s.
    context->Repeat(Seconds(6), Seconds(10));
});

Using times repeated counter

A task counts how often it was repeated, you can access this counter by using TaskContext::GetRepeatCounter().

The following example shows how to write a simple spoken event using the repeat counter:

void EnterCombat(Unit* /*who*/) override
{
    scheduler.Schedule(Seconds(5), [this](TaskContext context)
    {
        // The repeat counter increases every time the event was repeated.
        switch (context->GetRepeatCounter())
        {
            case 0:
                me->Yell("O shit!", LANG_UNIVERSAL);
                break;
            case 1:
                me->Yell("I see it was a mistake to fight you.", LANG_UNIVERSAL);
                break;
            case 2:
                me->Yell("There is no loot you can get today, sorry!", LANG_UNIVERSAL);
                break;
            case 3:
                me->Yell("See YA!", LANG_UNIVERSAL);
                break;
            default:
                me->DisappearAndDie();
                // Return here without repeating the event.
                return;
        }
        
        // Repeat the event for the next step.
        context->Repeat(Seconds(4), Seconds(6));
    });
}

I need more usage examples

For more usage examples check out my development repositoy or my TrinityCore fork which contains a sample script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment