Refactors EventManager

- handler freq now works on an individual handler basis (set to 0 to fire as frequently as possible)
- tick events no longer need to be re-registered after every eventful tick
develop
Josh Cooper 2021-06-18 15:06:14 -07:00 committed by Myk
parent 12df6d14e9
commit f5ced46608
2 changed files with 417 additions and 366 deletions

@ -40,6 +40,7 @@ namespace DFHack {
typedef void (*callback_t)(color_ostream&, void*); //called when the event happens typedef void (*callback_t)(color_ostream&, void*); //called when the event happens
callback_t eventHandler; callback_t eventHandler;
int32_t freq; int32_t freq;
int32_t when;
EventHandler(callback_t eventHandlerIn, int32_t freqIn): eventHandler(eventHandlerIn), freq(freqIn) { EventHandler(callback_t eventHandlerIn, int32_t freqIn): eventHandler(eventHandlerIn), freq(freqIn) {
} }

@ -57,11 +57,24 @@ static multimap<int32_t, EventHandler> tickQueue;
//TODO: consider unordered_map of pairs, or unordered_map of unordered_set, or whatever //TODO: consider unordered_map of pairs, or unordered_map of unordered_set, or whatever
static multimap<Plugin*, EventHandler> handlers[EventType::EVENT_MAX]; static multimap<Plugin*, EventHandler> handlers[EventType::EVENT_MAX];
static int32_t eventLastTick[EventType::EVENT_MAX]; static map<EventHandler::callback_t,int32_t> eventLastTick;
static const int32_t ticksPerYear = 403200; static const int32_t ticksPerYear = 403200;
void DFHack::EventManager::registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin) { void DFHack::EventManager::registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin) {
if(e == EventType::TICK){
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.insert(pair<int32_t, EventHandler>(handler.when, handler));
}
eventLastTick[handler.eventHandler] = -1;
handlers[e].insert(pair<Plugin*, EventHandler>(plugin, handler)); handlers[e].insert(pair<Plugin*, EventHandler>(plugin, handler));
} }
@ -75,8 +88,9 @@ int32_t DFHack::EventManager::registerTick(EventHandler handler, int32_t when, P
Core::getInstance().getConsole().print("EventManager::registerTick: warning! absolute flag=false not honored.\n"); Core::getInstance().getConsole().print("EventManager::registerTick: warning! absolute flag=false not honored.\n");
} }
} }
handler.freq = when; handler.when = when;
tickQueue.insert(pair<int32_t, EventHandler>(handler.freq, handler)); tickQueue.insert(pair<int32_t, EventHandler>(handler.when, handler));
eventLastTick[handler.eventHandler] = -1;
handlers[EventType::TICK].insert(pair<Plugin*,EventHandler>(plugin,handler)); handlers[EventType::TICK].insert(pair<Plugin*,EventHandler>(plugin,handler));
return when; return when;
} }
@ -103,22 +117,29 @@ void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handl
continue; continue;
} }
i = handlers[e].erase(i); i = handlers[e].erase(i);
eventLastTick.erase(handler.eventHandler);
if ( e == EventType::TICK ) if ( e == EventType::TICK )
removeFromTickQueue(handler); removeFromTickQueue(handler);
} }
} }
void DFHack::EventManager::unregisterAll(Plugin* plugin) { void DFHack::EventManager::unregisterAll(Plugin* plugin) {
for ( auto i = handlers[EventType::TICK].find(plugin); i != handlers[EventType::TICK].end(); i++ ) { for ( auto i = handlers[EventType::TICK].find(plugin); i != handlers[EventType::TICK].end(); ++i ) {
if ( (*i).first != plugin ) if ( (*i).first != plugin )
break; break;
eventLastTick.erase(i->second.eventHandler);
removeFromTickQueue((*i).second); removeFromTickQueue((*i).second);
} }
for ( size_t a = 0; a < (size_t)EventType::EVENT_MAX; a++ ) { for (auto &event_type : handlers) {
handlers[a].erase(plugin); for (auto i = event_type.find(plugin); i != event_type.end(); ++i ) {
if ( (*i).first != plugin )
break;
eventLastTick.erase(i->second.eventHandler);
}
event_type.erase(plugin);
} }
return;
} }
static void manageTickEvent(color_ostream& out); static void manageTickEvent(color_ostream& out);
@ -294,9 +315,9 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event
lastReportInteraction = -1; lastReportInteraction = -1;
reportToRelevantUnitsTime = -1; reportToRelevantUnitsTime = -1;
reportToRelevantUnits.clear(); reportToRelevantUnits.clear();
for ( size_t a = 0; a < EventType::EVENT_MAX; a++ ) { // for ( size_t a = 0; a < EventType::EVENT_MAX; a++ ) {
eventLastTick[a] = -1;//-1000000; // eventLastTick[a] = -1;//-1000000;
} // }
for ( size_t a = 0; a < df::global::world->history.figures.size(); a++ ) { for ( size_t a = 0; a < df::global::world->history.figures.size(); a++ ) {
df::historical_figure* unit = df::global::world->history.figures[a]; df::historical_figure* unit = df::global::world->history.figures[a];
if ( unit->id < 0 && unit->name.language < 0 ) if ( unit->id < 0 && unit->name.language < 0 )
@ -318,23 +339,21 @@ void DFHack::EventManager::manageEvents(color_ostream& out) {
int32_t tick = df::global::world->frame_counter; int32_t tick = df::global::world->frame_counter;
for ( size_t a = 0; a < EventType::EVENT_MAX; a++ ) { for (size_t type = 0; type < EventType::EVENT_MAX; type++ ) {
if ( handlers[a].empty() ) if (handlers[type].empty())
continue; continue;
int32_t eventFrequency = -100; bool call_events = false;
if ( a != EventType::TICK ) for (auto &iter : handlers[type]) {
for ( auto b = handlers[a].begin(); b != handlers[a].end(); b++ ) { EventHandler handler = iter.second;
EventHandler bob = (*b).second; int32_t last_tick = eventLastTick[handler.eventHandler];
if ( bob.freq < eventFrequency || eventFrequency == -100 ) if (tick - last_tick >= handler.freq){
eventFrequency = bob.freq; //todo: integrate into every sub-function
//eventLastTick[handler.eventHandler] = tick;
call_events = true;
} }
else eventFrequency = 1; }
if(call_events)
if ( tick >= eventLastTick[a] && tick - eventLastTick[a] < eventFrequency ) eventManager[type](out);
continue;
eventManager[a](out);
eventLastTick[a] = tick;
} }
} }
@ -353,14 +372,15 @@ static void manageTickEvent(color_ostream& out) {
} }
if ( toRemove.empty() ) if ( toRemove.empty() )
return; return;
for ( auto a = handlers[EventType::TICK].begin(); a != handlers[EventType::TICK].end(); ) { for (auto iter = handlers[EventType::TICK].begin(); iter != handlers[EventType::TICK].end(); ) {
EventHandler handle = (*a).second; EventHandler &handle = iter->second;
if ( toRemove.find(handle) == toRemove.end() ) { if ( toRemove.find(handle) == toRemove.end() ) {
a++; ++iter;
continue; continue;
} }
a = handlers[EventType::TICK].erase(a); iter = handlers[EventType::TICK].erase(iter);
toRemove.erase(handle); toRemove.erase(handle);
registerTick(handle, handle.freq, iter->first);
if ( toRemove.empty() ) if ( toRemove.empty() )
break; break;
} }
@ -380,14 +400,20 @@ static void manageJobInitiatedEvent(color_ostream& out) {
return; //no new jobs return; //no new jobs
} }
multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_INITIATED].begin(), handlers[EventType::JOB_INITIATED].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_INITIATED].begin(), handlers[EventType::JOB_INITIATED].end());
int32_t tick = df::global::world->frame_counter;
for(auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( df::job_list_link* link = &df::global::world->jobs.list; link != NULL; link = link->next ) { for ( df::job_list_link* link = &df::global::world->jobs.list; link != NULL; link = link->next ) {
if ( link->item == NULL ) if ( link->item == NULL )
continue; continue;
if ( link->item->id <= lastJobId ) if ( link->item->id <= lastJobId )
continue; continue;
for ( auto i = copy.begin(); i != copy.end(); i++ ) {
(*i).second.eventHandler(out, (void*)link->item); handler.eventHandler(out, (void*)link->item);
}
} }
} }
@ -406,8 +432,11 @@ TODO: consider checking item creation / experience gain just in case
static void manageJobCompletedEvent(color_ostream& out) { static void manageJobCompletedEvent(color_ostream& out) {
if (!df::global::world) if (!df::global::world)
return; return;
int32_t tick0 = eventLastTick[EventType::JOB_COMPLETED]; static int32_t last_tick = -1;
int32_t tick1 = df::global::world->frame_counter; int32_t tick = df::global::world->frame_counter;
if(tick < last_tick){
last_tick = tick;
}
multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_COMPLETED].begin(), handlers[EventType::JOB_COMPLETED].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_COMPLETED].begin(), handlers[EventType::JOB_COMPLETED].end());
map<int32_t, df::job*> nowJobs; map<int32_t, df::job*> nowJobs;
@ -433,7 +462,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
" completion_timer : %d\n" " completion_timer : %d\n"
" workerID : %d\n" " workerID : %d\n"
" time : %d -> %d\n" " time : %d -> %d\n"
"\n", job1.list_link->item, job1.id, job1.job_type, ENUM_ATTR(job_type, caption, job1.job_type), job1.flags.bits.working, job1.completion_timer, getWorkerID(&job1), tick0, tick1); "\n", job1.list_link->item, job1.id, job1.job_type, ENUM_ATTR(job_type, caption, job1.job_type), job1.flags.bits.working, job1.completion_timer, getWorkerID(&job1), last_tick, tick);
} }
for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) { for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) {
df::job& job0 = *(*i).second; df::job& job0 = *(*i).second;
@ -447,7 +476,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
" completion_timer : %d\n" " completion_timer : %d\n"
" workerID : %d\n" " workerID : %d\n"
" time : %d -> %d\n" " time : %d -> %d\n"
,job0.list_link == NULL ? 0 : job0.list_link->item, job0.id, job0.job_type, ENUM_ATTR(job_type, caption, job0.job_type), job0.flags.bits.working, job0.completion_timer, getWorkerID(&job0), tick0, tick1); ,job0.list_link == NULL ? 0 : job0.list_link->item, job0.id, job0.job_type, ENUM_ATTR(job_type, caption, job0.job_type), job0.flags.bits.working, job0.completion_timer, getWorkerID(&job0), last_tick, tick);
continue; continue;
} }
df::job& job1 = *(*j).second; df::job& job1 = *(*j).second;
@ -474,14 +503,18 @@ static void manageJobCompletedEvent(color_ostream& out) {
job0.flags.bits.working, job1.flags.bits.working, job0.flags.bits.working, job1.flags.bits.working,
job0.completion_timer, job1.completion_timer, job0.completion_timer, job1.completion_timer,
getWorkerID(&job0), getWorkerID(&job1), getWorkerID(&job0), getWorkerID(&job1),
tick0, tick1 last_tick, tick
); );
} }
#endif #endif
for(auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) { for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) {
//if it happened within a tick, must have been cancelled by the user or a plugin: not completed //if it happened within a tick, must have been cancelled by the user or a plugin: not completed
if ( tick1 <= tick0 ) if (tick <= last_tick )
continue; continue;
if ( nowJobs.find((*i).first) != nowJobs.end() ) { if ( nowJobs.find((*i).first) != nowJobs.end() ) {
@ -496,9 +529,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
continue; continue;
//still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen //still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen
for ( auto j = copy.begin(); j != copy.end(); j++ ) { handler.eventHandler(out, (void*) &job0);
(*j).second.eventHandler(out, (void*)&job0);
}
continue; continue;
} }
@ -507,8 +538,8 @@ static void manageJobCompletedEvent(color_ostream& out) {
if ( job0.flags.bits.repeat || job0.completion_timer != 0 ) if ( job0.flags.bits.repeat || job0.completion_timer != 0 )
continue; continue;
for ( auto j = copy.begin(); j != copy.end(); j++ ) { handler.eventHandler(out, (void*) &job0);
(*j).second.eventHandler(out, (void*)&job0); }
} }
} }
@ -528,12 +559,18 @@ static void manageJobCompletedEvent(color_ostream& out) {
df::job* newJob = Job::cloneJobStruct((*j).second, true); df::job* newJob = Job::cloneJobStruct((*j).second, true);
prevJobs[newJob->id] = newJob; prevJobs[newJob->id] = newJob;
} }
last_tick = tick;
} }
static void manageUnitDeathEvent(color_ostream& out) { static void manageUnitDeathEvent(color_ostream& out) {
if (!df::global::world) if (!df::global::world)
return; return;
multimap<Plugin*,EventHandler> copy(handlers[EventType::UNIT_DEATH].begin(), handlers[EventType::UNIT_DEATH].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::UNIT_DEATH].begin(), handlers[EventType::UNIT_DEATH].end());
int32_t tick = df::global::world->frame_counter;
for (auto &iter : copy) {
auto &handler = iter.second;
if(tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( size_t a = 0; a < df::global::world->units.all.size(); a++ ) { for ( size_t a = 0; a < df::global::world->units.all.size(); a++ ) {
df::unit* unit = df::global::world->units.all[a]; df::unit* unit = df::global::world->units.all[a];
//if ( unit->counters.death_id == -1 ) { //if ( unit->counters.death_id == -1 ) {
@ -545,11 +582,11 @@ static void manageUnitDeathEvent(color_ostream& out) {
if ( livingUnits.find(unit->id) == livingUnits.end() ) if ( livingUnits.find(unit->id) == livingUnits.end() )
continue; continue;
for ( auto i = copy.begin(); i != copy.end(); i++ ) { handler.eventHandler(out, (void*) intptr_t(unit->id));
(*i).second.eventHandler(out, (void*)intptr_t(unit->id));
}
livingUnits.erase(unit->id); livingUnits.erase(unit->id);
} }
}
}
} }
static void manageItemCreationEvent(color_ostream& out) { static void manageItemCreationEvent(color_ostream& out) {
@ -562,27 +599,32 @@ static void manageItemCreationEvent(color_ostream& out) {
} }
multimap<Plugin*,EventHandler> copy(handlers[EventType::ITEM_CREATED].begin(), handlers[EventType::ITEM_CREATED].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::ITEM_CREATED].begin(), handlers[EventType::ITEM_CREATED].end());
int32_t tick = df::global::world->frame_counter;
size_t index = df::item::binsearch_index(df::global::world->items.all, nextItem, false); size_t index = df::item::binsearch_index(df::global::world->items.all, nextItem, false);
if ( index != 0 ) index--; if ( index != 0 ) index--;
for ( size_t a = index; a < df::global::world->items.all.size(); a++ ) { for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for (size_t a = index; a < df::global::world->items.all.size(); a++) {
df::item* item = df::global::world->items.all[a]; df::item* item = df::global::world->items.all[a];
//already processed //already processed
if ( item->id < nextItem ) if (item->id < nextItem)
continue; continue;
//invaders //invaders
if ( item->flags.bits.foreign ) if (item->flags.bits.foreign)
continue; continue;
//traders who bring back your items? //traders who bring back your items?
if ( item->flags.bits.trader ) if (item->flags.bits.trader)
continue; continue;
//migrants //migrants
if ( item->flags.bits.owned ) if (item->flags.bits.owned)
continue; continue;
//spider webs don't count //spider webs don't count
if ( item->flags.bits.spider_web ) if (item->flags.bits.spider_web)
continue; continue;
for ( auto i = copy.begin(); i != copy.end(); i++ ) { handler.eventHandler(out, (void*) intptr_t(item->id));
(*i).second.eventHandler(out, (void*)intptr_t(item->id)); }
} }
} }
nextItem = *df::global::item_next_id; nextItem = *df::global::item_next_id;
@ -598,7 +640,12 @@ static void manageBuildingEvent(color_ostream& out) {
* consider looking at jobs: building creation / destruction * consider looking at jobs: building creation / destruction
**/ **/
multimap<Plugin*,EventHandler> copy(handlers[EventType::BUILDING].begin(), handlers[EventType::BUILDING].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::BUILDING].begin(), handlers[EventType::BUILDING].end());
//first alert people about new buildings int32_t tick = df::global::world->frame_counter;
//no more separation between new and destroyed events
for (auto &iter : copy) {
auto &handler = iter.second;
if(tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( int32_t a = nextBuilding; a < *df::global::building_next_id; a++ ) { for ( int32_t a = nextBuilding; a < *df::global::building_next_id; a++ ) {
int32_t index = df::building::binsearch_index(df::global::world->buildings.all, a); int32_t index = df::building::binsearch_index(df::global::world->buildings.all, a);
if ( index == -1 ) { if ( index == -1 ) {
@ -607,10 +654,8 @@ static void manageBuildingEvent(color_ostream& out) {
continue; continue;
} }
buildings.insert(a); buildings.insert(a);
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)intptr_t(a));
EventHandler bob = (*b).second;
bob.eventHandler(out, (void*)intptr_t(a));
}
} }
nextBuilding = *df::global::building_next_id; nextBuilding = *df::global::building_next_id;
@ -622,13 +667,11 @@ static void manageBuildingEvent(color_ostream& out) {
a++; a++;
continue; continue;
} }
handler.eventHandler(out, (void*)intptr_t(id));
for ( auto b = copy.begin(); b != copy.end(); b++ ) {
EventHandler bob = (*b).second;
bob.eventHandler(out, (void*)intptr_t(id));
}
a = buildings.erase(a); a = buildings.erase(a);
} }
}
}
} }
static void manageConstructionEvent(color_ostream& out) { static void manageConstructionEvent(color_ostream& out) {
@ -637,6 +680,11 @@ static void manageConstructionEvent(color_ostream& out) {
//unordered_set<df::construction*> constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end()); //unordered_set<df::construction*> constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end());
multimap<Plugin*,EventHandler> copy(handlers[EventType::CONSTRUCTION].begin(), handlers[EventType::CONSTRUCTION].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::CONSTRUCTION].begin(), handlers[EventType::CONSTRUCTION].end());
int32_t tick = df::global::world->frame_counter;
for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( auto a = constructions.begin(); a != constructions.end(); ) { for ( auto a = constructions.begin(); a != constructions.end(); ) {
df::construction& construction = (*a).second; df::construction& construction = (*a).second;
if ( df::construction::find(construction.pos) != NULL ) { if ( df::construction::find(construction.pos) != NULL ) {
@ -645,13 +693,9 @@ static void manageConstructionEvent(color_ostream& out) {
} }
//construction removed //construction removed
//out.print("Removed construction (%d,%d,%d)\n", construction.pos.x,construction.pos.y,construction.pos.z); //out.print("Removed construction (%d,%d,%d)\n", construction.pos.x,construction.pos.y,construction.pos.z);
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)&construction);
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&construction);
}
a = constructions.erase(a); a = constructions.erase(a);
} }
//for ( auto a = constructionsNow.begin(); a != constructionsNow.end(); a++ ) { //for ( auto a = constructionsNow.begin(); a != constructionsNow.end(); a++ ) {
for ( auto a = df::global::world->constructions.begin(); a != df::global::world->constructions.end(); a++ ) { for ( auto a = df::global::world->constructions.begin(); a != df::global::world->constructions.end(); a++ ) {
df::construction* construction = *a; df::construction* construction = *a;
@ -661,9 +705,8 @@ static void manageConstructionEvent(color_ostream& out) {
continue; continue;
//construction created //construction created
//out.print("Created construction (%d,%d,%d)\n", construction->pos.x,construction->pos.y,construction->pos.z); //out.print("Created construction (%d,%d,%d)\n", construction->pos.x,construction->pos.y,construction->pos.z);
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)construction);
EventHandler handle = (*b).second; }
handle.eventHandler(out, (void*)construction);
} }
} }
} }
@ -673,6 +716,11 @@ static void manageSyndromeEvent(color_ostream& out) {
return; return;
multimap<Plugin*,EventHandler> copy(handlers[EventType::SYNDROME].begin(), handlers[EventType::SYNDROME].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::SYNDROME].begin(), handlers[EventType::SYNDROME].end());
int32_t highestTime = -1; int32_t highestTime = -1;
int32_t tick = df::global::world->frame_counter;
for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( auto a = df::global::world->units.all.begin(); a != df::global::world->units.all.end(); a++ ) { for ( auto a = df::global::world->units.all.begin(); a != df::global::world->units.all.end(); a++ ) {
df::unit* unit = *a; df::unit* unit = *a;
/* /*
@ -688,9 +736,8 @@ static void manageSyndromeEvent(color_ostream& out) {
continue; continue;
SyndromeData data(unit->id, b); SyndromeData data(unit->id, b);
for ( auto c = copy.begin(); c != copy.end(); c++ ) { handler.eventHandler(out, (void*)&data);
EventHandler handle = (*c).second; }
handle.eventHandler(out, (void*)&data);
} }
} }
} }
@ -706,9 +753,13 @@ static void manageInvasionEvent(color_ostream& out) {
return; return;
nextInvasion = df::global::ui->invasions.next_id; nextInvasion = df::global::ui->invasions.next_id;
for ( auto a = copy.begin(); a != copy.end(); a++ ) { int32_t tick = df::global::world->frame_counter;
EventHandler handle = (*a).second; for (auto &iter : copy) {
handle.eventHandler(out, (void*)intptr_t(nextInvasion-1)); auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
handler.eventHandler(out, (void*) intptr_t(nextInvasion - 1));
}
} }
} }
@ -719,10 +770,14 @@ static void manageEquipmentEvent(color_ostream& out) {
unordered_map<int32_t, InventoryItem> itemIdToInventoryItem; unordered_map<int32_t, InventoryItem> itemIdToInventoryItem;
unordered_set<int32_t> currentlyEquipped; unordered_set<int32_t> currentlyEquipped;
for ( auto a = df::global::world->units.all.begin(); a != df::global::world->units.all.end(); a++ ) { int32_t tick = df::global::world->frame_counter;
for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for (auto unit : df::global::world->units.all) {
itemIdToInventoryItem.clear(); itemIdToInventoryItem.clear();
currentlyEquipped.clear(); currentlyEquipped.clear();
df::unit* unit = *a;
/*if ( unit->flags1.bits.inactive ) /*if ( unit->flags1.bits.inactive )
continue; continue;
*/ */
@ -730,69 +785,62 @@ static void manageEquipmentEvent(color_ostream& out) {
auto oldEquipment = equipmentLog.find(unit->id); auto oldEquipment = equipmentLog.find(unit->id);
bool hadEquipment = oldEquipment != equipmentLog.end(); bool hadEquipment = oldEquipment != equipmentLog.end();
vector<InventoryItem>* temp; vector<InventoryItem>* temp;
if ( hadEquipment ) { if (hadEquipment) {
temp = &((*oldEquipment).second); temp = &((*oldEquipment).second);
} else { } else {
temp = new vector<InventoryItem>; temp = new vector<InventoryItem>;
} }
//vector<InventoryItem>& v = (*oldEquipment).second; //vector<InventoryItem>& v = (*oldEquipment).second;
vector<InventoryItem>& v = *temp; vector<InventoryItem> &v = *temp;
for ( auto b = v.begin(); b != v.end(); b++ ) { for (auto &item : v) {
InventoryItem& i = *b; itemIdToInventoryItem[item.itemId] = item;
itemIdToInventoryItem[i.itemId] = i;
} }
for ( size_t b = 0; b < unit->inventory.size(); b++ ) { for (size_t b = 0; b < unit->inventory.size(); b++) {
df::unit_inventory_item* dfitem_new = unit->inventory[b]; df::unit_inventory_item* dfitem_new = unit->inventory[b];
currentlyEquipped.insert(dfitem_new->item->id); currentlyEquipped.insert(dfitem_new->item->id);
InventoryItem item_new(dfitem_new->item->id, *dfitem_new); InventoryItem item_new(dfitem_new->item->id, *dfitem_new);
auto c = itemIdToInventoryItem.find(dfitem_new->item->id); auto c = itemIdToInventoryItem.find(dfitem_new->item->id);
if ( c == itemIdToInventoryItem.end() ) { if (c == itemIdToInventoryItem.end()) {
//new item equipped (probably just picked up) //new item equipped (probably just picked up)
InventoryChangeData data(unit->id, NULL, &item_new); InventoryChangeData data(unit->id, NULL, &item_new);
for ( auto h = copy.begin(); h != copy.end(); h++ ) { handler.eventHandler(out, (void*) &data);
EventHandler handle = (*h).second;
handle.eventHandler(out, (void*)&data);
}
continue; continue;
} }
InventoryItem item_old = (*c).second; InventoryItem item_old = (*c).second;
df::unit_inventory_item& item0 = item_old.item; df::unit_inventory_item &item0 = item_old.item;
df::unit_inventory_item& item1 = item_new.item; df::unit_inventory_item &item1 = item_new.item;
if ( item0.mode == item1.mode && item0.body_part_id == item1.body_part_id && item0.wound_id == item1.wound_id ) if (item0.mode == item1.mode && item0.body_part_id == item1.body_part_id &&
item0.wound_id == item1.wound_id)
continue; continue;
//some sort of change in how it's equipped //some sort of change in how it's equipped
InventoryChangeData data(unit->id, &item_old, &item_new); InventoryChangeData data(unit->id, &item_old, &item_new);
for ( auto h = copy.begin(); h != copy.end(); h++ ) { handler.eventHandler(out, (void*) &data);
EventHandler handle = (*h).second;
handle.eventHandler(out, (void*)&data);
}
} }
//check for dropped items //check for dropped items
for ( auto b = v.begin(); b != v.end(); b++ ) { for (auto b = v.begin(); b != v.end(); b++) {
InventoryItem i = *b; InventoryItem i = *b;
if ( currentlyEquipped.find(i.itemId) != currentlyEquipped.end() ) if (currentlyEquipped.find(i.itemId) != currentlyEquipped.end())
continue; continue;
//TODO: delete ptr if invalid //TODO: delete ptr if invalid
InventoryChangeData data(unit->id, &i, NULL); InventoryChangeData data(unit->id, &i, NULL);
for ( auto h = copy.begin(); h != copy.end(); h++ ) { handler.eventHandler(out, (void*) &data);
EventHandler handle = (*h).second;
handle.eventHandler(out, (void*)&data);
} }
} if (!hadEquipment)
if ( !hadEquipment )
delete temp; delete temp;
//update equipment //update equipment
vector<InventoryItem>& equipment = equipmentLog[unit->id]; vector<InventoryItem> &equipment = equipmentLog[unit->id];
equipment.clear(); equipment.clear();
for ( size_t b = 0; b < unit->inventory.size(); b++ ) { for (size_t b = 0; b < unit->inventory.size(); b++) {
df::unit_inventory_item* dfitem = unit->inventory[b]; df::unit_inventory_item* dfitem = unit->inventory[b];
InventoryItem item(dfitem->item->id, *dfitem); InventoryItem item(dfitem->item->id, *dfitem);
equipment.push_back(item); equipment.push_back(item);
} }
} }
}
}
} }
static void updateReportToRelevantUnits() { static void updateReportToRelevantUnits() {
@ -827,14 +875,18 @@ static void manageReportEvent(color_ostream& out) {
while (a < reports.size() && reports[a]->id <= lastReport) { while (a < reports.size() && reports[a]->id <= lastReport) {
a++; a++;
} }
for ( ; a < reports.size(); a++ ) { int32_t tick = df::global::world->frame_counter;
for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for (; a < reports.size(); a++) {
df::report* report = reports[a]; df::report* report = reports[a];
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*) intptr_t(report->id));
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)intptr_t(report->id));
}
lastReport = report->id; lastReport = report->id;
} }
}
}
} }
static df::unit_wound* getWound(df::unit* attacker, df::unit* defender) { static df::unit_wound* getWound(df::unit* attacker, df::unit* defender) {
@ -873,8 +925,12 @@ static void manageUnitAttackEvent(color_ostream& out) {
return; return;
updateReportToRelevantUnits(); updateReportToRelevantUnits();
map<int32_t, map<int32_t, int32_t> > alreadyDone; map<int32_t, map<int32_t, int32_t> > alreadyDone;
for ( auto a = strikeReports.begin(); a != strikeReports.end(); a++ ) { int32_t tick = df::global::world->frame_counter;
int32_t reportId = *a; for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for (int reportId : strikeReports) {
df::report* report = df::report::find(reportId); df::report* report = df::report::find(reportId);
if ( !report ) if ( !report )
continue; //TODO: error continue; //TODO: error
@ -908,10 +964,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
data.wound = wound1->id; data.wound = wound1->id;
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)&data);
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&data);
}
} }
if ( wound2 && !alreadyDone[unit1->id][unit2->id] ) { if ( wound2 && !alreadyDone[unit1->id][unit2->id] ) {
@ -921,10 +974,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
data.wound = wound2->id; data.wound = wound2->id;
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)&data);
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&data);
}
} }
if ( Units::isKilled(unit1) ) { if ( Units::isKilled(unit1) ) {
@ -933,10 +983,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
data.defender = unit1->id; data.defender = unit1->id;
data.wound = -1; data.wound = -1;
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)&data);
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&data);
}
} }
if ( Units::isKilled(unit2) ) { if ( Units::isKilled(unit2) ) {
@ -945,10 +992,7 @@ static void manageUnitAttackEvent(color_ostream& out) {
data.defender = unit2->id; data.defender = unit2->id;
data.wound = -1; data.wound = -1;
alreadyDone[data.attacker][data.defender] = 1; alreadyDone[data.attacker][data.defender] = 1;
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)&data);
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&data);
}
} }
if ( !wound1 && !wound2 ) { if ( !wound1 && !wound2 ) {
@ -961,6 +1005,8 @@ static void manageUnitAttackEvent(color_ostream& out) {
} }
} }
} }
}
}
} }
static std::string getVerb(df::unit* unit, std::string reportStr) { static std::string getVerb(df::unit* unit, std::string reportStr) {
@ -1152,6 +1198,11 @@ static void manageInteractionEvent(color_ostream& out) {
df::unit* lastAttacker = NULL; df::unit* lastAttacker = NULL;
//df::unit* lastDefender = NULL; //df::unit* lastDefender = NULL;
unordered_map<int32_t,unordered_set<int32_t> > history; unordered_map<int32_t,unordered_set<int32_t> > history;
int32_t tick = df::global::world->frame_counter;
for (auto &iter : copy) {
auto &handler = iter.second;
if (tick - eventLastTick[handler.eventHandler] >= handler.freq) {
eventLastTick[handler.eventHandler] = tick;
for ( ; a < reports.size(); a++ ) { for ( ; a < reports.size(); a++ ) {
df::report* report = reports[a]; df::report* report = reports[a];
lastReportInteraction = report->id; lastReportInteraction = report->id;
@ -1203,11 +1254,10 @@ static void manageInteractionEvent(color_ostream& out) {
lastAttacker = df::unit::find(data.attacker); lastAttacker = df::unit::find(data.attacker);
//lastDefender = df::unit::find(data.defender); //lastDefender = df::unit::find(data.defender);
//fire event //fire event
for ( auto b = copy.begin(); b != copy.end(); b++ ) { handler.eventHandler(out, (void*)&data);
EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&data);
}
//TODO: deduce attacker from latest defend event first //TODO: deduce attacker from latest defend event first
} }
}
}
} }