Skip to content

Messages

Matt Styles edited this page Apr 25, 2019 · 10 revisions

Entities, components, states, UI controls and any other classes which have access to the message bus can emit messages which are broadcast system-wide. Messages are designed to broadcast any important events which occur, along with any pertinent data such as position or entity ID, rather than target any one specific object or system. Raising a message requires a data struct for message specific data, and a unique identifier to allow correct parsing of message data once a message is received. xygine contains a few built message types which it uses internally, and a few preset IDs which can be found in xy::Message::Type. Because of this, when extending message types with new IDs, it is recommended that a new enum be created where the
first member has the value of xy::Message::Count. For example:

enum MyMessageId
{
    SomeEvent = xy::Message::Count,
    AnotherEvent,
    ExampleEvent
};

This ensures that not only are any new event IDs unique and won't clash with xygine's built in IDs, it will also guarantee that you code will not break should any more default IDs be added to xygine's built in message enum.

To send a message over the message bus use the MessageBus::post() function, providing the data type of your message data as a template parameter, and the unique ID for that event. This function returns a pointer to the message data which can then be filled in.

auto msg = messageBus.post<MyEventData>(MyMessageId::SomeEvent);
msg->myProperty = myValue;

Systems and Directors have a postMessage<T>() function precisely for this purpose.

IMPORTANT. MyEventData should be a trivial struct, with no more than a few POD type members. Trying to send a complicated object attached to a message is a sure fire way to induce trouble. If you want to broadcast more complicated data, then attach a pointer to that object to the message, not the object itself.

Receiving messages

All messages are despatched from xy::App via handleMessages() where they can be passed down through the game systems hierarchy. Systems can optionally implement System::handleMessage() and directors are required to implement Director::handleMessage(). To act on a message first check the message ID, then retrieve the data if necessary:

if(msg.id == MyMessageId::SomeEvent)
{
    auto& msgData = msg.getData<MyEventData>();
    if(msg.property == myValue) doStuff();
}

getData() will return a const reference to the data stored in the message, note the & after auto. It is important that you supply the correct type to the template argument else behaviour will be undefined. The message data will be an instance of the struct used to define the data when it was first sent. Messages cannot be consumed by any means, and all objects / systems which have message handlers will receive all messages sent in the last frame. Simply ignore any messages which are not of interest to a particular class, if you have no need to handle it.

Clone this wiki locally