ICT290 / src / scene / AIController / Messaging / MessageDispatcher.cpp
MessageDispatcher.cpp
Raw
#include "MessageDispatcher.h"
#include "EntityManager.h"

MessageDispatcher* MessageDispatcher::Instance() {
    static MessageDispatcher instance;

    return &instance;
}

//----------------------------- Dispatch ---------------------------------
//
//  see description in header
//------------------------------------------------------------------------
void MessageDispatcher::Discharge(BasicEntity* receiver,
                                  const Telegram& telegram) {
    if (!receiver->HandleMessage(telegram)) {
// telegram could not be handled
#ifdef SHOW_MESSAGING_INFO
        debug_con << "Message not handled"
                  << "";
#endif
    }
}

//---------------------------- DispatchMsg ---------------------------
//
//  given a message, a receiver, a sender and any time delay, this function
//  routes the message to the correct agent (if no delay) or stores
//  in the message queue to be dispatched at the correct time
//------------------------------------------------------------------------
void MessageDispatcher::DispatchMsg(Uint32 delay,
                                    int sender,
                                    int receiverID,
                                    int msg,
                                    void* additionalInfo = nullptr) {
    // get a pointer to the receiver
    BasicEntity* receiver = EntityMgr->getEntityFromID(receiverID);

    // make sure the receiver is valid
    if (receiver == nullptr) {
#ifdef SHOW_MESSAGING_INFO
        debug_con << "\nWarning! No Receiver with ID of " << receiver
                  << " found"
                  << "";
#endif

        return;
    }

    // create the telegram
    Telegram telegram(0, sender, receiverID, msg, additionalInfo);

    // if there is no delay, route telegram immediately
    if (delay <= 0.0) {
#ifdef SHOW_MESSAGING_INFO
        debug_con << "\nTelegram dispatched at time: "
                  << TickCounter->GetCurrentFrame() << " by " << sender
                  << " for " << receiver << ". Msg is " << msg << "";
#endif

        // send the telegram to the recipient
        Discharge(receiver, telegram);
    }

    // else calculate the time when the telegram should be dispatched
    else {
        Uint32 currentTime = SDL_GetTicks();
        // double CurrentTime = TickCounter->GetCurrentFrame();

        telegram.DispatchTime = currentTime + delay;

        // and put it in the queue
        PriorityQ.insert(telegram);

#ifdef SHOW_MESSAGING_INFO
        debug_con << "\nDelayed telegram from " << sender
                  << " recorded at time " << TickCounter->GetCurrentFrame()
                  << " for " << receiver << ". Msg is " << msg << "";
#endif
    }
}

//---------------------- DispatchDelayedMessages -------------------------
//
//  This function dispatches any telegrams with a timestamp that has
//  expired. Any dispatched telegrams are removed from the queue
//------------------------------------------------------------------------
void MessageDispatcher::DispatchDelayedMessages() {
    // first get current time
    Uint32 currentTime = SDL_GetTicks();
    // double CurrentTime = TickCounter->GetCurrentFrame();

    // now peek at the queue to see if any telegrams need dispatching.
    // remove all telegrams from the front of the queue that have gone
    // past their sell by date
    while (!PriorityQ.empty() && (PriorityQ.begin()->DispatchTime < currentTime)
           && (PriorityQ.begin()->DispatchTime > 0)) {
        // read the telegram from the front of the queue
        const Telegram& telegram = *PriorityQ.begin();

        // find the recipient
        BasicEntity* receiver = EntityMgr->getEntityFromID(telegram.Receiver);

#ifdef SHOW_MESSAGING_INFO
        debug_con << "\nQueued telegram ready for dispatch: Sent to "
                  << pReceiver->ID() << ". Msg is " << telegram.Msg << "";
#endif

        // send the telegram to the recipient
        Discharge(receiver, telegram);

        // remove it from the queue
        PriorityQ.erase(PriorityQ.begin());
    }
}