diff --git a/library/include/modules/EventManager.h b/library/include/modules/EventManager.h index c1c09da7d..1c610564e 100644 --- a/library/include/modules/EventManager.h +++ b/library/include/modules/EventManager.h @@ -17,6 +17,8 @@ namespace DFHack { JOB_COMPLETED, UNIT_DEATH, ITEM_CREATED, + BUILDING, + CONSTRUCTION, EVENT_MAX }; } diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 187a95819..f2d7e0261 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -4,6 +4,8 @@ #include "modules/Job.h" #include "modules/World.h" +#include "df/building.h" +#include "df/construction.h" #include "df/global_objects.h" #include "df/item.h" #include "df/job.h" @@ -11,9 +13,10 @@ #include "df/unit.h" #include "df/world.h" -//#include #include -//#include +#include +#include + using namespace std; using namespace DFHack; using namespace EventManager; @@ -21,11 +24,13 @@ using namespace EventManager; /* * TODO: * error checking + * consider a typedef instead of a struct for EventHandler **/ //map > tickQueue; multimap tickQueue; +//TODO: consider unordered_map of pairs, or unordered_map of unordered_set, or whatever multimap handlers[EventType::EVENT_MAX]; const uint32_t ticksPerYear = 403200; @@ -96,13 +101,31 @@ static void manageJobInitiatedEvent(color_ostream& out); static void manageJobCompletedEvent(color_ostream& out); static void manageUnitDeathEvent(color_ostream& out); static void manageItemCreationEvent(color_ostream& out); +static void manageBuildingEvent(color_ostream& out); +static void manageConstructionEvent(color_ostream& out); +//tick event static uint32_t lastTick = 0; + +//job initiated static int32_t lastJobId = -1; -static map prevJobs; -static set livingUnits; + +//job completed +static unordered_map prevJobs; + +//unit death +static unordered_set livingUnits; + +//item creation static int32_t nextItem; +//building +static int32_t nextBuilding; +static unordered_set buildings; + +//construction +static unordered_set constructions; + void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event event) { if ( event == DFHack::SC_MAP_UNLOADED ) { lastTick = 0; @@ -114,6 +137,9 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event tickQueue.clear(); livingUnits.clear(); nextItem = -1; + nextBuilding = -1; + buildings.clear(); + constructions.clear(); } else if ( event == DFHack::SC_MAP_LOADED ) { uint32_t tick = DFHack::World::ReadCurrentYear()*ticksPerYear + DFHack::World::ReadCurrentTick(); @@ -126,6 +152,8 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event tickQueue.insert(newTickQueue.begin(), newTickQueue.end()); nextItem = *df::global::item_next_id; + nextBuilding = *df::global::building_next_id; + constructions.insert(df::global::world->constructions.begin(), df::global::world->constructions.end()); } } @@ -144,6 +172,8 @@ void DFHack::EventManager::manageEvents(color_ostream& out) { manageJobCompletedEvent(out); manageUnitDeathEvent(out); manageItemCreationEvent(out); + manageBuildingEvent(out); + manageConstructionEvent(out); return; } @@ -201,7 +231,7 @@ static void manageJobCompletedEvent(color_ostream& out) { nowJobs[link->item->id] = link->item; } - for ( map::iterator i = prevJobs.begin(); i != prevJobs.end(); i++ ) { + for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) { if ( nowJobs.find((*i).first) != nowJobs.end() ) continue; @@ -212,13 +242,13 @@ static void manageJobCompletedEvent(color_ostream& out) { } //erase old jobs, copy over possibly altered jobs - for ( map::iterator i = prevJobs.begin(); i != prevJobs.end(); i++ ) { + for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) { Job::deleteJobStruct((*i).second); } prevJobs.clear(); //create new jobs - for ( map::iterator j = nowJobs.begin(); j != nowJobs.end(); j++ ) { + for ( auto j = nowJobs.begin(); j != nowJobs.end(); j++ ) { /*map::iterator i = prevJobs.find((*j).first); if ( i != prevJobs.end() ) { continue; @@ -289,3 +319,77 @@ static void manageItemCreationEvent(color_ostream& out) { nextItem = *df::global::item_next_id; } +static void manageBuildingEvent(color_ostream& out) { + /* + * TODO: could be faster + * consider looking at jobs: building creation / destruction + **/ + if ( handlers[EventType::ITEM_CREATED].empty() ) + return; + + multimap copy(handlers[EventType::BUILDING].begin(), handlers[EventType::BUILDING].end()); + //first alert people about new buildings + 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); + if ( index == -1 ) { + out.print("%s, line %d: Couldn't find new building with id %d.\n", __FILE__, __LINE__, a); + } + buildings.insert(a); + for ( auto b = copy.begin(); b != copy.end(); b++ ) { + EventHandler bob = (*b).second; + bob.eventHandler(out, (void*)a); + } + } + nextBuilding = *df::global::building_next_id; + + //now alert people about destroyed buildings + unordered_set toDelete; + for ( auto a = buildings.begin(); a != buildings.end(); a++ ) { + int32_t id = *a; + int32_t index = df::building::binsearch_index(df::global::world->buildings.all,id); + if ( index != -1 ) + continue; + toDelete.insert(id); + + for ( auto b = copy.begin(); b != copy.end(); b++ ) { + EventHandler bob = (*b).second; + bob.eventHandler(out, (void*)id); + } + } + + for ( auto a = toDelete.begin(); a != toDelete.end(); a++ ) { + int32_t id = *a; + buildings.erase(id); + } +} + +static void manageConstructionEvent(color_ostream& out) { + if ( handlers[EventType::CONSTRUCTION].empty() ) + return; + + unordered_set constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end()); + + multimap copy(handlers[EventType::CONSTRUCTION].begin(), handlers[EventType::CONSTRUCTION].end()); + for ( auto a = constructions.begin(); a != constructions.end(); a++ ) { + df::construction* construction = *a; + if ( constructionsNow.find(construction) != constructionsNow.end() ) + continue; + for ( auto b = copy.begin(); b != copy.end(); b++ ) { + EventHandler handle = (*b).second; + handle.eventHandler(out, (void*)construction); + } + } + + for ( auto a = constructionsNow.begin(); a != constructionsNow.end(); a++ ) { + df::construction* construction = *a; + if ( constructions.find(construction) != constructions.end() ) + continue; + for ( auto b = copy.begin(); b != copy.end(); b++ ) { + EventHandler handle = (*b).second; + handle.eventHandler(out, (void*)construction); + } + } + + constructions.clear(); + constructions.insert(constructionsNow.begin(), constructionsNow.end()); +} diff --git a/plugins/devel/eventExample.cpp b/plugins/devel/eventExample.cpp index 2099be110..d93396d29 100644 --- a/plugins/devel/eventExample.cpp +++ b/plugins/devel/eventExample.cpp @@ -21,6 +21,8 @@ void jobCompleted(color_ostream& out, void* job); void timePassed(color_ostream& out, void* ptr); void unitDeath(color_ostream& out, void* ptr); void itemCreate(color_ostream& out, void* ptr); +void building(color_ostream& out, void* ptr); +void construction(color_ostream& out, void* ptr); command_result eventExample(color_ostream& out, vector& parameters); @@ -36,7 +38,10 @@ command_result eventExample(color_ostream& out, vector& parameters) { EventManager::EventHandler timeHandler(timePassed); EventManager::EventHandler deathHandler(unitDeath); EventManager::EventHandler itemHandler(itemCreate); + EventManager::EventHandler buildingHandler(building); + EventManager::EventHandler constructionHandler(construction); Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("eventExample"); + EventManager::unregisterAll(me); EventManager::registerListener(EventManager::EventType::JOB_INITIATED, initiateHandler, me); EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, completeHandler, me); @@ -46,6 +51,8 @@ command_result eventExample(color_ostream& out, vector& parameters) { EventManager::registerTick(timeHandler, 8, me); EventManager::registerListener(EventManager::EventType::UNIT_DEATH, deathHandler, me); EventManager::registerListener(EventManager::EventType::ITEM_CREATED, itemHandler, me); + EventManager::registerListener(EventManager::EventType::BUILDING, buildingHandler, me); + EventManager::registerListener(EventManager::EventType::CONSTRUCTION, constructionHandler, me); out.print("Events registered.\n"); return CR_OK; } @@ -77,3 +84,10 @@ void itemCreate(color_ostream& out, void* ptr) { out.print("Item created: %d, %s, at (%d,%d,%d)\n", (int32_t)(ptr), ENUM_KEY_STR(item_type, type).c_str(), pos.x, pos.y, pos.z); } +void building(color_ostream& out, void* ptr) { + out.print("Building created/destroyed: %d\n", (int32_t)ptr); +} + +void construction(color_ostream& out, void* ptr) { + out.print("Construction created/destroyed: 0x%X\n", ptr); +}