Skip to content

Commit

Permalink
Allows tick events to auto-requeue when registered as listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
cppcooper committed Mar 16, 2023
1 parent f191334 commit 75d019f
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 21 deletions.
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 5 additions & 2 deletions library/include/modules/EventManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
51 changes: 32 additions & 19 deletions library/modules/EventManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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*, EventHandler>(plugin, handler));
}

Expand All @@ -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<int32_t, EventHandler>(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*,EventHandler>(plugin,handler));
handler.when = when;
tickQueue.insert(pair<int32_t, EventHandler>(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*,EventHandler>(plugin,handler));
// since the event isn't added to the handlers, we don't need to unregister these events
return when;
}

Expand Down Expand Up @@ -393,29 +412,23 @@ void DFHack::EventManager::manageEvents(color_ostream& out) {
static void manageTickEvent(color_ostream& out) {
if (!df::global::world)
return;
unordered_set<EventHandler> toRemove;
unordered_set<EventHandler> 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);
}
}

Expand Down

0 comments on commit 75d019f

Please sign in to comment.