Skip to content

Commit

Permalink
Create MessageDispatchService
Browse files Browse the repository at this point in the history
Give entities a way to communicate with each other via the
MessageDispatchService. The `MessageInbox` component is used to receive
messages. Currently the MessageDispatchService is for entity-to-entity
communication. Global events will be handled by another service,
although will probably use the same `Message` object with `EventArg`
parameters.
  • Loading branch information
meisekimiu committed Aug 25, 2024
1 parent 62af3fa commit 9c05d98
Show file tree
Hide file tree
Showing 18 changed files with 893 additions and 2 deletions.
11 changes: 9 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ project(gl-adagio)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
file(GLOB_RECURSE SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp" "${CMAKE_SOURCE_DIR}/src/math/*.cpp" "${CMAKE_SOURCE_DIR}/src/audio/*.cpp" "${CMAKE_SOURCE_DIR}/src/graphics/*.cpp" "${CMAKE_SOURCE_DIR}/src/state/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/systems/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/states/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/*.cpp")
file(GLOB_RECURSE TESTS "${CMAKE_SOURCE_DIR}/src/math/*.cpp" "${CMAKE_SOURCE_DIR}/test/math/*.cpp" "${CMAKE_SOURCE_DIR}/src/audio/*.cpp" "${CMAKE_SOURCE_DIR}/test/audio/**/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/factories/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/systems/*.cpp" "${CMAKE_SOURCE_DIR}/test/game/**/*.cpp"
file(GLOB_RECURSE SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp" "${CMAKE_SOURCE_DIR}/src/literals/*.cpp" "${CMAKE_SOURCE_DIR}/src/math/*.cpp" "${CMAKE_SOURCE_DIR}/src/event/*.cpp" "${CMAKE_SOURCE_DIR}/src/audio/*.cpp" "${CMAKE_SOURCE_DIR}/src/graphics/*.cpp" "${CMAKE_SOURCE_DIR}/src/state/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/systems/*.cpp"
"${CMAKE_SOURCE_DIR}/src/game/components/**/*.cpp"
"${CMAKE_SOURCE_DIR}/src/game/states/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/*.cpp")
file(GLOB_RECURSE TESTS
"${CMAKE_SOURCE_DIR}/src/literals/*.cpp" "${CMAKE_SOURCE_DIR}/test/literals/*.cpp"
"${CMAKE_SOURCE_DIR}/src/math/*.cpp" "${CMAKE_SOURCE_DIR}/test/math/*.cpp" "${CMAKE_SOURCE_DIR}/src/audio/*.cpp" "${CMAKE_SOURCE_DIR}/test/audio/**/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/factories/*.cpp" "${CMAKE_SOURCE_DIR}/src/game/systems/*.cpp"
"${CMAKE_SOURCE_DIR}/src/game/components/**/*.cpp"
"${CMAKE_SOURCE_DIR}/test/game/**/*.cpp"
"${CMAKE_SOURCE_DIR}/src/graphics/*.cpp" "${CMAKE_SOURCE_DIR}/test/graphics/*.cpp"
"${CMAKE_SOURCE_DIR}/src/state/*.cpp" "${CMAKE_SOURCE_DIR}/test/state/**/*.cpp"
"${CMAKE_SOURCE_DIR}/src/event/*.cpp" "${CMAKE_SOURCE_DIR}/test/event/*.cpp"
"${CMAKE_SOURCE_DIR}/test/*.cpp")
file(COPY "${CMAKE_SOURCE_DIR}/assets" DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")

Expand Down
25 changes: 25 additions & 0 deletions src/event/EventArg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef GL_ADAGIO_EVENTVARIANTTYPE_H
#define GL_ADAGIO_EVENTVARIANTTYPE_H

#include "../literals/HashString.h"
#include <cstdint>

namespace Adagio {
enum Type {
TYPE_NULL, TYPE_UINT, TYPE_INT, TYPE_FLOAT, TYPE_BOOL, TYPE_HASH
};

struct EventArg {
std::uint32_t eventName{0};

Type type{TYPE_NULL};

union {
std::uint32_t m_Uint{0};
std::int32_t m_Int;
float m_Float;
bool m_Bool;
};
};
} // namespace Adagio
#endif // GL_ADAGIO_EVENTVARIANTTYPE_H
72 changes: 72 additions & 0 deletions src/event/Message.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "Message.h"
#include <stdexcept>
#include <algorithm>

const Adagio::EventArg *Adagio::Message::getArg(unsigned char index) const { return &argument[index]; }

Adagio::Message &Adagio::Message::addBoolArg(std::uint32_t eventName, bool value) {
EventArg &arg = getFirstFreeArgument();
arg.eventName = eventName;
arg.type = Adagio::TYPE_BOOL;
arg.m_Bool = value;
return *this;
}

Adagio::Message &Adagio::Message::addUintArg(std::uint32_t eventName, std::uint32_t value) {
EventArg &arg = getFirstFreeArgument();
arg.eventName = eventName;
arg.type = Adagio::TYPE_UINT;
arg.m_Uint = value;
return *this;
}

Adagio::Message &Adagio::Message::addIntArg(std::uint32_t eventName, std::int32_t value) {
EventArg &arg = getFirstFreeArgument();
arg.eventName = eventName;
arg.type = Adagio::TYPE_INT;
arg.m_Int = value;
return *this;
}

Adagio::Message &Adagio::Message::addFloatArg(std::uint32_t eventName, float value) {
EventArg &arg = getFirstFreeArgument();
arg.eventName = eventName;
arg.type = Adagio::TYPE_FLOAT;
arg.m_Float = value;
return *this;
}

unsigned char Adagio::Message::getArgumentCount() const {
for (unsigned char i = 0; i < MAX_EVENT_ARGS; i++) {
if (argument[i].type == Adagio::TYPE_NULL) {
return i;
}
}
return MAX_EVENT_ARGS;
}

void Adagio::Message::nullifyArguments() {
for (auto &a: argument) {
a.eventName = 0;
a.type = Adagio::TYPE_NULL;
a.m_Uint = 0;
}
}

Adagio::EventArg &Adagio::Message::getFirstFreeArgument() {
unsigned char count = getArgumentCount();
if (count >= MAX_EVENT_ARGS) {
throw std::range_error("Too many arguments on event");
}
return argument[count];
}

const Adagio::EventArg *Adagio::Message::getArgByName(std::uint32_t argName) const {
auto i = std::find_if(argument, argument + MAX_EVENT_ARGS, [argName](const Adagio::EventArg &arg) {
return arg.eventName == argName;
});
if (i != argument + MAX_EVENT_ARGS) {
return i;
}
return nullptr;
}
43 changes: 43 additions & 0 deletions src/event/Message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef GL_ADAGIO_MESSAGE_H
#define GL_ADAGIO_MESSAGE_H

#include "EventArg.h"

#define MAX_EVENT_ARGS 4

namespace Adagio {
struct Message {
struct MessageLinks {
Message *next{nullptr};
Message *prev{nullptr};
};
std::uint32_t name{0};
std::uint32_t from{0};
std::uint32_t to{0};
bool active{false};
MessageLinks links;

EventArg argument[MAX_EVENT_ARGS];

[[nodiscard]] const EventArg *getArg(unsigned char index) const;

[[nodiscard]] const EventArg *getArgByName(std::uint32_t name) const;

Message &addBoolArg(std::uint32_t eventName, bool value);

Message &addUintArg(std::uint32_t eventName, std::uint32_t value);

Message &addIntArg(std::uint32_t eventName, std::int32_t value);

Message &addFloatArg(std::uint32_t eventName, float value);

[[nodiscard]] unsigned char getArgumentCount() const;

void nullifyArguments();

private:
EventArg &getFirstFreeArgument();
};
} // namespace Adagio

#endif // GL_ADAGIO_MESSAGE_H
66 changes: 66 additions & 0 deletions src/event/MessageCollection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "MessageCollection.h"

namespace Adagio {
size_t MessageCollection::size() const {
return length;
}

void MessageCollection::append(Message *e) {
e->links.next = nullptr;
if (first == nullptr) {
e->links.prev = nullptr;
first = e;
} else {
e->links.prev = last;
last->links.next = e;
}
last = e;
length++;
}

Message *MessageCollection::operator[](size_t i) const {
return at(i);
}

void MessageCollection::remove(size_t index) {
Message *event = at(index);
Message *prev = event->links.prev;
Message *next = event->links.next;
if (index == 0) {
first = next;
}
if (index == length - 1) {
last = prev;
}
if (prev && next) {
prev->links.next = next;
next->links.prev = prev;
}
event->nullifyArguments();
event->active = false;
event->name = 0;
event->from = 0;
event->to = 0;
length--;
}

Message *MessageCollection::at(size_t i) const {
Message *event = first;
for (size_t j = 0; j < i; j++) {
event = event->links.next;
}
return event;
}

Message *MessageCollection::shift() {
Message *e = first;
if (first) {
remove(0);
}
return e;
}

bool MessageCollection::empty() const {
return size() == 0;
}
} // Adagio
32 changes: 32 additions & 0 deletions src/event/MessageCollection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef GL_ADAGIO_MESSAGECOLLECTION_H
#define GL_ADAGIO_MESSAGECOLLECTION_H

#include "Message.h"

namespace Adagio {
class MessageCollection {
public:
Message *first{nullptr};
Message *last{nullptr};

void append(Message *e);

void remove(size_t index);

Message *shift();

[[nodiscard]] bool empty() const;

[[nodiscard]] size_t size() const;

[[nodiscard]] Message *at(size_t i) const;

Message *operator[](size_t i) const;

private:
size_t length{0};
};

} // Adagio

#endif //GL_ADAGIO_MESSAGECOLLECTION_H
30 changes: 30 additions & 0 deletions src/event/MessageDispatchService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "MessageDispatchService.h"
#include <algorithm>

namespace Adagio {
Message &MessageDispatchService::dispatch(InboxId to, InboxId from, std::uint32_t eventName) {
auto inbox = inboxMap.find(to);
auto it = std::find_if(eventPool, eventPool + MSGPOOL_MAX, [](Message &e) {
return !e.active;
});
if (it == eventPool + MSGPOOL_MAX || inbox == inboxMap.end()) {
invalidMessage.name = 0xdeadbeef;
invalidMessage.active = false;
return invalidMessage;
}
it->active = true;
it->from = from;
it->to = to;
it->name = eventName;
inbox->second->append(it);
return *it;
}

void MessageDispatchService::registerInbox(InboxId id, MessageCollection *inboxDestination) {
inboxMap[id] = inboxDestination;
}

void MessageDispatchService::unregisterInbox(InboxId id) {
inboxMap.erase(id);
}
} // namespace Adagio
51 changes: 51 additions & 0 deletions src/event/MessageDispatchService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef GL_ADAGIO_MESSAGEDISPATCHSERVICE_H
#define GL_ADAGIO_MESSAGEDISPATCHSERVICE_H

#include <cstdint>
#include <unordered_map>
#include "Message.h"
#include "MessageCollection.h"

#define MSGPOOL_MAX 32

namespace Adagio {

typedef std::uint32_t InboxId;

class MessageDispatchService {
public:
void registerInbox(InboxId id, MessageCollection *inboxDestination);

template<typename T, typename U>
void registerInbox(T id, U &inboxObject) {
registerInbox(static_cast<InboxId>(id), &inboxObject.messages);
}

template<typename T>
void registerInbox(T id, MessageCollection *inboxDestination) {
registerInbox(static_cast<InboxId>(id), inboxDestination);
}

void unregisterInbox(InboxId id);

template<typename T>
void unregisterInbox(T id) {
unregisterInbox(static_cast<InboxId>(id));
}

Message &dispatch(InboxId to, InboxId from, std::uint32_t eventName);

template<typename T, typename U>
Message &dispatch(T to, U from, std::uint32_t eventName) {
return dispatch(static_cast<InboxId>(to), static_cast<InboxId>(from), eventName);
}

private:
Message eventPool[MSGPOOL_MAX];
Message invalidMessage;
std::unordered_map<InboxId, MessageCollection *> inboxMap;
};

} // namespace Adagio

#endif // GL_ADAGIO_MESSAGEDISPATCHSERVICE_H
10 changes: 10 additions & 0 deletions src/game/components/events/MessageInbox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef GL_ADAGIO_MESSAGEINBOX_H
#define GL_ADAGIO_MESSAGEINBOX_H

#include "../../../event/MessageCollection.h"

struct MessageInbox {
Adagio::MessageCollection messages;
};

#endif //GL_ADAGIO_MESSAGEINBOX_H
18 changes: 18 additions & 0 deletions src/game/components/events/hooks/MessageInboxHooks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "../../../../event/MessageDispatchService.h"
#include "../MessageInbox.h"
#include "MessageInboxHooks.h"

void RegisterInboxWithMessageService(entt::registry &registry, entt::entity id) {
Adagio::MessageDispatchService *eventService = registry.ctx().get<Adagio::MessageDispatchService *>();
if (eventService) {
MessageInbox &component = registry.get<MessageInbox>(id);
eventService->registerInbox(id, component);
}
}

void UnregisterInboxWithMessageService(entt::registry &registry, entt::entity id) {
Adagio::MessageDispatchService *eventService = registry.ctx().get<Adagio::MessageDispatchService *>();
if (eventService) {
eventService->unregisterInbox(id);
}
}
10 changes: 10 additions & 0 deletions src/game/components/events/hooks/MessageInboxHooks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef GL_ADAGIO_MESSAGEINBOXHOOKS_H
#define GL_ADAGIO_MESSAGEINBOXHOOKS_H

#include <entt/entt.hpp>

void RegisterInboxWithMessageService(entt::registry &registry, entt::entity id);

void UnregisterInboxWithMessageService(entt::registry &registry, entt::entity id);

#endif //GL_ADAGIO_MESSAGEINBOXHOOKS_H
Loading

0 comments on commit 9c05d98

Please sign in to comment.