diff --git a/docs/changelog.txt b/docs/changelog.txt index c98d727f60..6df83f27d2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -53,6 +53,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Documentation ## API +- ``EventManager``: revises tick events to work as listeners. Tick events registered with ``registerListener`` will now automatically requeue at their designated frequency. ## Lua diff --git a/library/include/modules/EventManager.h b/library/include/modules/EventManager.h index 7808f6d8c6..f73977ab4f 100644 --- a/library/include/modules/EventManager.h +++ b/library/include/modules/EventManager.h @@ -46,9 +46,11 @@ namespace DFHack { typedef void (*callback_t)(color_ostream&, void*); //called when the event happens callback_t eventHandler; int32_t freq; //how often event is allowed to fire (in ticks) use 0 to always fire when possible + int32_t when = -1; //when to fire event (global tick count) - EventHandler(callback_t eventHandlerIn, int32_t freqIn): eventHandler(eventHandlerIn), freq(freqIn) { - } + EventHandler(callback_t eventHandlerIn, int32_t freqIn) : + eventHandler(eventHandlerIn), + freq(freqIn) {} bool operator==(const EventHandler& handle) const { return eventHandler == handle.eventHandler && freq == handle.freq; @@ -144,6 +146,7 @@ namespace std { size_t r = 17; const size_t m = 65537; r = m*(r+(intptr_t)h.eventHandler); + r = m*(r+h.when); r = m*(r+h.freq); return r; } diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 02b1892e95..b6790130e0 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -67,8 +67,25 @@ static int32_t eventLastTick[EventType::EVENT_MAX]; static const int32_t ticksPerYear = 403200; +// this function is only used within the file in registerListener and manageTickEvent +void enqueueTickEvent(EventHandler &handler){ + int32_t when = 0; + df::world* world = df::global::world; + if ( world ) { + when = world->frame_counter + handler.freq; + } else { + if ( Once::doOnce("EventManager registerListener unhonored absolute=false") ) + Core::getInstance().getConsole().print("EventManager::registerTick: warning! absolute flag=false not honored.\n"); + } + handler.when = when; + tickQueue.emplace(handler.when, handler); +} + void DFHack::EventManager::registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin) { DEBUG(log).print("registering handler %p from plugin %s for event %d\n", handler.eventHandler, plugin->getName().c_str(), e); + if(e == EventType::TICK){ + enqueueTickEvent(handler); + } handlers[e].insert(pair(plugin, handler)); } @@ -82,10 +99,12 @@ int32_t DFHack::EventManager::registerTick(EventHandler handler, int32_t when, P Core::getInstance().getConsole().print("EventManager::registerTick: warning! absolute flag=false not honored.\n"); } } - handler.freq = when; - tickQueue.insert(pair(handler.freq, handler)); DEBUG(log).print("registering handler %p from plugin %s for event TICK\n", handler.eventHandler, plugin->getName().c_str()); - handlers[EventType::TICK].insert(pair(plugin,handler)); + handler.when = when; + tickQueue.insert(pair(handler.when, handler)); + // we don't track this handler, this allows registerTick to retain the old behaviour of needing to re-register the tick event + //handlers[EventType::TICK].insert(pair(plugin,handler)); + // since the event isn't added to the handlers, we don't need to unregister these events return when; } @@ -393,29 +412,23 @@ void DFHack::EventManager::manageEvents(color_ostream& out) { static void manageTickEvent(color_ostream& out) { if (!df::global::world) return; - unordered_set toRemove; + unordered_set toRequeue; int32_t tick = df::global::world->frame_counter; while ( !tickQueue.empty() ) { - if ( tick < (*tickQueue.begin()).first ) + auto iter = tickQueue.begin(); + if ( tick < iter->first ) break; - EventHandler &handle = (*tickQueue.begin()).second; - tickQueue.erase(tickQueue.begin()); + EventHandler &handle = iter->second; + tickQueue.erase(iter); DEBUG(log,out).print("calling handler for tick event\n"); handle.eventHandler(out, (void*)intptr_t(tick)); - toRemove.insert(handle); + toRequeue.emplace(handle); } - if ( toRemove.empty() ) + if ( toRequeue.empty() ) return; - for ( auto a = handlers[EventType::TICK].begin(); a != handlers[EventType::TICK].end(); ) { - EventHandler &handle = (*a).second; - if ( toRemove.find(handle) == toRemove.end() ) { - a++; - continue; - } - a = handlers[EventType::TICK].erase(a); - toRemove.erase(handle); - if ( toRemove.empty() ) - break; + for (auto pair : handlers[EventType::TICK]) { + EventHandler &handler = pair.second; + enqueueTickEvent(handler); } }