diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index e6b9c5259..c7401b469 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -41,6 +41,7 @@ #include #include #include +#include using namespace std; using namespace DFHack; @@ -140,24 +141,58 @@ static void manageInteractionEvent(color_ostream& out); typedef void (*eventManager_t)(color_ostream&); -static const eventManager_t eventManager[] = { - manageTickEvent, - manageJobInitiatedEvent, - manageJobStartedEvent, - manageJobCompletedEvent, - manageNewUnitActiveEvent, - manageUnitDeathEvent, - manageItemCreationEvent, - manageBuildingEvent, - manageConstructionEvent, - manageSyndromeEvent, - manageInvasionEvent, - manageEquipmentEvent, - manageReportEvent, - manageUnitAttackEvent, - manageUnloadEvent, - manageInteractionEvent, -}; +// integrate new events into this function, and no longer worry about syncing the enum list with the `eventManager` array +eventManager_t getManager(EventType::EventType t) { + switch (t) { + case EventType::TICK: + return manageTickEvent; + case EventType::JOB_INITIATED: + return manageJobInitiatedEvent; + case EventType::JOB_STARTED: + return manageJobStartedEvent; + case EventType::JOB_COMPLETED: + return manageJobCompletedEvent; + case EventType::UNIT_NEW_ACTIVE: + return manageNewUnitActiveEvent; + case EventType::UNIT_DEATH: + return manageUnitDeathEvent; + case EventType::ITEM_CREATED: + return manageItemCreationEvent; + case EventType::BUILDING: + return manageBuildingEvent; + case EventType::CONSTRUCTION: + return manageConstructionEvent; + case EventType::SYNDROME: + return manageSyndromeEvent; + case EventType::INVASION: + return manageInvasionEvent; + case EventType::INVENTORY_CHANGE: + return manageEquipmentEvent; + case EventType::REPORT: + return manageReportEvent; + case EventType::UNIT_ATTACK: + return manageUnitAttackEvent; + case EventType::UNLOAD: + return manageUnloadEvent; + case EventType::INTERACTION: + return manageInteractionEvent; + case EventType::EVENT_MAX: + return nullptr; + //default: + //we don't do this... because then the compiler wouldn't error for missing cases in the enum + } + return nullptr; +} + +std::array compileManagerArray() { + std::array managers{}; + auto t = (EventType::EventType) 0; + while (t < EventType::EVENT_MAX) { + managers[t] = getManager(t); + t = (EventType::EventType) int(t + 1); + } + return managers; +} //job initiated static int32_t lastJobId = -1; @@ -312,6 +347,7 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event } void DFHack::EventManager::manageEvents(color_ostream& out) { + static const std::array eventManager = compileManagerArray(); if ( !gameLoaded ) { return; } diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 094b25198..980b2db9c 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -28,6 +28,7 @@ #include #include +#include using std::vector; using std::string; @@ -223,26 +224,61 @@ static void ev_mng_interaction(color_ostream& out, void* ptr) { std::vector enabledEventManagerEvents(EventManager::EventType::EVENT_MAX,-1); typedef void (*handler_t) (color_ostream&,void*); -// NOTICE: keep this list synchronized with the EventManager::EventType enum or -// else the wrong event handlers will get called. -static const handler_t eventHandlers[] = { - NULL, - ev_mng_jobInitiated, - ev_mng_jobStarted, - ev_mng_jobCompleted, - ev_mng_unitNewActive, - ev_mng_unitDeath, - ev_mng_itemCreate, - ev_mng_building, - ev_mng_construction, - ev_mng_syndrome, - ev_mng_invasion, - ev_mng_inventory, - ev_mng_report, - ev_mng_unitAttack, - ev_mng_unload, - ev_mng_interaction, -}; +using namespace EventManager::EventType; +// integrate new events into this function, and no longer worry about syncing with the enum list +handler_t getManager(EventType t) { + switch (t) { + case TICK: + return nullptr; + case JOB_INITIATED: + return ev_mng_jobInitiated; + case JOB_STARTED: + return ev_mng_jobStarted; + case JOB_COMPLETED: + return ev_mng_jobCompleted; + case UNIT_NEW_ACTIVE: + return ev_mng_unitNewActive; + case UNIT_DEATH: + return ev_mng_unitDeath; + case ITEM_CREATED: + return ev_mng_itemCreate; + case BUILDING: + return ev_mng_building; + case CONSTRUCTION: + return ev_mng_construction; + case SYNDROME: + return ev_mng_syndrome; + case INVASION: + return ev_mng_invasion; + case INVENTORY_CHANGE: + return ev_mng_inventory; + case REPORT: + return ev_mng_report; + case UNIT_ATTACK: + return ev_mng_unitAttack; + case UNLOAD: + return ev_mng_unload; + case INTERACTION: + return ev_mng_interaction; + case EVENT_MAX: + return nullptr; + //default: + //we don't do this... because then the compiler wouldn't error for missing cases in the enum + } + return nullptr; +} + +std::array compileEventHandlerArray() { + std::array managers{}; + auto t = (EventManager::EventType::EventType) 0; + while (t < EventManager::EventType::EVENT_MAX) { + managers[t] = getManager(t); + t = (EventManager::EventType::EventType) int(t + 1); + } + return managers; +} +static std::array eventHandlers; + static void enableEvent(int evType,int freq) { if (freq < 0) @@ -483,6 +519,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { + eventHandlers = compileEventHandlerArray(); if (Core::getInstance().isWorldLoaded()) plugin_onstatechange(out, SC_WORLD_LOADED); enable_hooks(true);