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 Dec 8, 2022
1 parent fed9f76 commit f273dd1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 19 deletions.
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,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 auto-matically requeu 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
45 changes: 28 additions & 17 deletions library/modules/EventManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,24 @@ 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) {
if(e == EventType::TICK){
enqueueTickEvent(handler);
}
handlers[e].insert(pair<Plugin*, EventHandler>(plugin, handler));
}

Expand All @@ -76,12 +93,13 @@ 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));
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;
}

static void removeFromTickQueue(EventHandler getRidOf) {
for ( auto j = tickQueue.find(getRidOf.freq); j != tickQueue.end(); ) {
if ( (*j).first > getRidOf.freq )
Expand Down Expand Up @@ -382,28 +400,21 @@ 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 )
break;
EventHandler &handle = (*tickQueue.begin()).second;
tickQueue.erase(tickQueue.begin());
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 f273dd1

Please sign in to comment.