Skip to content

Instantly share code, notes, and snippets.

@hcarty
Created March 31, 2024 05:51
Show Gist options
  • Save hcarty/5a3cb48efed7c6ff058fb33afb4343c9 to your computer and use it in GitHub Desktop.
Save hcarty/5a3cb48efed7c6ff058fb33afb4343c9 to your computer and use it in GitHub Desktop.
Very basic, data driven game events in ore - based on triggers proposal
[Object]
; All the actual object definition
; ...
OnCreate = > @, Input.EnableSet < true
OnDelete = > @, Input.EnableSet < false
; Game event handlers
EventHandlerList= DropperEvents
; Inputs
KEY_SPACE = Drop
KEY_LEFT = Left
KEY_RIGHT = Right
[Events]
GameOver = Object.AddFX ^ DesaturateFX true true, > Object.GetName ^, Input.EnableSet < false, Object.SetLifeTime ^ fx
namespace game::event
{
// Key holding names of sections with event handler definitions for an object
auto CONFIG_KEY = "EventHandlerList";
auto COMMAND = "Event.Send";
// Map from event name to registered handlers listening for that event
static std::map<orxSTRINGID, std::map<const orxOBJECT *, orxSTRINGID>> eventRecipientObjects{};
void Command(orxU32 _u32ArgNumber, const orxCOMMAND_VAR *_astArgList, orxCOMMAND_VAR *_pstResult)
{
switch (_u32ArgNumber)
{
case 1ul:
{
// Event name
Send(_astArgList[0].zValue);
break;
}
case 2ul:
{
// Event name and a recipient object
auto object = orxOBJECT(orxStructure_Get(_astArgList[1].u64Value));
if (object)
{
Send(_astArgList[0].zValue, object);
}
break;
}
default:
{
// This should not be possible if the command is registered properly
orxASSERT(orxFALSE);
break;
}
}
}
// Record events handled by newly created objects and removes objects when they're deleted
orxSTATUS ObjectEventHandler(const orxEVENT *event)
{
// This handler should only be called for object events
orxASSERT(event->eType == orxEVENT_TYPE_OBJECT);
switch (event->eID)
{
case orxOBJECT_EVENT_CREATE:
{
// The object being created
orxOBJECT *obj = static_cast<orxOBJECT *>(event->hSender);
orxASSERT(obj);
// Get the object's name and therefore config section
auto name = orxObject_GetName(obj);
if (!orxConfig_HasSection(name))
{
// No config section matching this object
break;
}
// Get supported events from config
orxConfig_PushSection(name);
{
auto sections = orxConfig_GetListCount(CONFIG_KEY);
for (int i = 0; i < sections; i++)
{
// Process event handlers from given section
auto section = orxConfig_GetListString(CONFIG_KEY, i);
if (!orxConfig_HasSection(section))
{
orxLOG("No section %s referenced in %s from section %s", section, CONFIG_KEY, name);
continue;
}
// Register all handlers according to their keys
orxConfig_PushSection(section);
{
auto keys = orxConfig_GetKeyCount();
for (int j = 0; j < keys; j++)
{
auto key = orxConfig_GetKey(j);
auto id = orxString_GetID(key);
// Add the current object to the set of recipients with handlers for this event
eventRecipientObjects[id][obj] = orxString_GetID(section);
}
}
orxConfig_PopSection();
}
}
orxConfig_PopSection();
break;
}
case orxOBJECT_EVENT_DELETE:
{
orxOBJECT *obj = static_cast<orxOBJECT *>(event->hSender);
orxASSERT(obj);
// Get the object's name and therefore config section
auto name = orxObject_GetName(obj);
if (!orxConfig_HasSection(name))
{
// No config section matching this object
break;
}
// Get supported events from config
orxConfig_PushSection(name);
{
auto sections = orxConfig_GetListCount(CONFIG_KEY);
for (int i = 0; i < sections; i++)
{
// Process event handlers from given section
auto section = orxConfig_GetListString(CONFIG_KEY, i);
if (!orxConfig_HasSection(section))
{
orxLOG("No section %s referenced in %s from section %s", section, CONFIG_KEY, name);
continue;
}
// Register all handlers according to their keys
orxConfig_PushSection(section);
{
auto keys = orxConfig_GetKeyCount();
for (int j = 0; j < keys; j++)
{
auto key = orxConfig_GetKey(j);
auto id = orxString_GetID(key);
// Remove the current object from the set of recipients with handlers for this event
eventRecipientObjects[id].erase(obj);
}
}
orxConfig_PopSection();
}
}
orxConfig_PopSection();
break;
}
default:
{
// This should not happen as long as we register the event handler correctly
orxLOG("Unhandled object event ID");
orxASSERT(orxFALSE);
}
};
return orxSTATUS_SUCCESS;
}
void Init()
{
// Object event handling
orxEvent_AddHandler(orxEVENT_TYPE_OBJECT, ObjectEventHandler);
orxEvent_SetHandlerIDFlags(ObjectEventHandler, orxEVENT_TYPE_OBJECT, orxNULL,
orxEVENT_GET_FLAG(orxOBJECT_EVENT_CREATE) | orxEVENT_GET_FLAG(orxOBJECT_EVENT_DELETE),
orxEVENT_KU32_MASK_ID_ALL);
// Register commands
orxCOMMAND_REGISTER(COMMAND, Command, "none", orxCOMMAND_VAR_TYPE_NONE, 1, 1, {"Event", orxCOMMAND_VAR_TYPE_STRING}, {"Object = <void>", orxCOMMAND_VAR_TYPE_U64});
}
void Exit()
{
// Event handling
orxEvent_RemoveHandler(orxEVENT_TYPE_OBJECT, ObjectEventHandler);
// Commands
orxCOMMAND_UNREGISTER(COMMAND);
}
void EvaluateCommandFromConfig(const orxSTRING section, const orxSTRING key, const orxU64 guid)
{
orxConfig_PushSection(section);
orxCOMMAND_VAR _result;
orxCommand_EvaluateWithGUID(orxConfig_GetString(key), guid, &_result);
orxConfig_PopSection();
}
// Send an event to all listeners for an event
void Send(const orxSTRING event)
{
auto id = orxString_GetID(event);
auto recipients = eventRecipientObjects[id];
for (const auto [object, sectionID] : recipients)
{
auto section = orxString_GetFromID(sectionID);
EvaluateCommandFromConfig(section, event, orxStructure_GetGUID(orxSTRUCTURE(object)));
}
}
// Send an event to a specific object
void Send(const orxSTRING event, const orxOBJECT *object)
{
auto eventID = orxString_GetID(event);
if (!eventRecipientObjects.contains(eventID) || !eventRecipientObjects[eventID].contains(object))
{
orxLOG("Event %s is not registered to any objects", event);
return;
}
auto sectionID = eventRecipientObjects[eventID][object];
EvaluateCommandFromConfig(orxString_GetFromID(sectionID), event, orxStructure_GetGUID(orxSTRUCTURE(object)));
}
}
namespace game::event
{
// Call at init time to setup event handling and commands
void Init();
// Call at exit time to remove event handlers and commands
void Exit();
// Send an event to all listeners for an event
void Send(const orxSTRING event);
// Send an event to a specific object
void Send(const orxSTRING event, const orxOBJECT *object);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment