Merge branch 'eventManager' into diggingInvaders

develop
expwnent 2012-12-16 16:43:58 -05:00
commit 131d19e4cf
10 changed files with 448 additions and 15 deletions

@ -111,6 +111,7 @@ include/modules/Burrows.h
include/modules/Constructions.h include/modules/Constructions.h
include/modules/Units.h include/modules/Units.h
include/modules/Engravings.h include/modules/Engravings.h
include/modules/EventManager.h
include/modules/Gui.h include/modules/Gui.h
include/modules/Items.h include/modules/Items.h
include/modules/Job.h include/modules/Job.h
@ -133,6 +134,7 @@ modules/Burrows.cpp
modules/Constructions.cpp modules/Constructions.cpp
modules/Units.cpp modules/Units.cpp
modules/Engravings.cpp modules/Engravings.cpp
modules/EventManager.cpp
modules/Gui.cpp modules/Gui.cpp
modules/Items.cpp modules/Items.cpp
modules/Job.cpp modules/Job.cpp

@ -44,6 +44,7 @@ using namespace std;
#include "VersionInfo.h" #include "VersionInfo.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "ModuleFactory.h" #include "ModuleFactory.h"
#include "modules/EventManager.h"
#include "modules/Gui.h" #include "modules/Gui.h"
#include "modules/World.h" #include "modules/World.h"
#include "modules/Graphic.h" #include "modules/Graphic.h"
@ -904,6 +905,7 @@ bool Core::Init()
cerr << "Initializing Plugins.\n"; cerr << "Initializing Plugins.\n";
// create plugin manager // create plugin manager
plug_mgr = new PluginManager(this); plug_mgr = new PluginManager(this);
plug_mgr->init(this);
IODATA *temp = new IODATA; IODATA *temp = new IODATA;
temp->core = this; temp->core = this;
temp->plug_mgr = plug_mgr; temp->plug_mgr = plug_mgr;
@ -1238,6 +1240,8 @@ static int buildings_timer = 0;
void Core::onUpdate(color_ostream &out) void Core::onUpdate(color_ostream &out)
{ {
EventManager::manageEvents(out);
// convert building reagents // convert building reagents
if (buildings_do_onupdate && (++buildings_timer & 1)) if (buildings_do_onupdate && (++buildings_timer & 1))
buildings_onUpdate(out); buildings_onUpdate(out);
@ -1251,6 +1255,8 @@ void Core::onUpdate(color_ostream &out)
void Core::onStateChange(color_ostream &out, state_change_event event) void Core::onStateChange(color_ostream &out, state_change_event event)
{ {
EventManager::onStateChange(out, event);
buildings_onStateChange(out, event); buildings_onStateChange(out, event);
plug_mgr->OnStateChange(out, event); plug_mgr->OnStateChange(out, event);

@ -22,6 +22,7 @@ must not be misrepresented as being the original software.
distribution. distribution.
*/ */
#include "modules/EventManager.h"
#include "Internal.h" #include "Internal.h"
#include "Core.h" #include "Core.h"
#include "MemAccess.h" #include "MemAccess.h"
@ -270,6 +271,7 @@ bool Plugin::unload(color_ostream &con)
// if we are actually loaded // if we are actually loaded
if(state == PS_LOADED) if(state == PS_LOADED)
{ {
EventManager::unregisterAll(this);
// notify the plugin about an attempt to shutdown // notify the plugin about an attempt to shutdown
if (plugin_onstatechange && if (plugin_onstatechange &&
plugin_onstatechange(con, SC_BEGIN_UNLOAD) == CR_NOT_FOUND) plugin_onstatechange(con, SC_BEGIN_UNLOAD) == CR_NOT_FOUND)
@ -598,6 +600,22 @@ void Plugin::push_function(lua_State *state, LuaFunction *fn)
} }
PluginManager::PluginManager(Core * core) PluginManager::PluginManager(Core * core)
{
cmdlist_mutex = new mutex();
eval_ruby = NULL;
}
PluginManager::~PluginManager()
{
for(size_t i = 0; i < all_plugins.size();i++)
{
delete all_plugins[i];
}
all_plugins.clear();
delete cmdlist_mutex;
}
void PluginManager::init(Core * core)
{ {
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
string path = core->getHackPath() + "plugins/"; string path = core->getHackPath() + "plugins/";
@ -606,8 +624,6 @@ PluginManager::PluginManager(Core * core)
string path = core->getHackPath() + "plugins\\"; string path = core->getHackPath() + "plugins\\";
const string searchstr = ".plug.dll"; const string searchstr = ".plug.dll";
#endif #endif
cmdlist_mutex = new mutex();
eval_ruby = NULL;
vector <string> filez; vector <string> filez;
getdir(path, filez); getdir(path, filez);
for(size_t i = 0; i < filez.size();i++) for(size_t i = 0; i < filez.size();i++)
@ -622,16 +638,6 @@ PluginManager::PluginManager(Core * core)
} }
} }
PluginManager::~PluginManager()
{
for(size_t i = 0; i < all_plugins.size();i++)
{
delete all_plugins[i];
}
all_plugins.clear();
delete cmdlist_mutex;
}
Plugin *PluginManager::getPluginByName (const std::string & name) Plugin *PluginManager::getPluginByName (const std::string & name)
{ {
for(size_t i = 0; i < all_plugins.size(); i++) for(size_t i = 0; i < all_plugins.size(); i++)

@ -205,6 +205,7 @@ namespace DFHack
friend class Plugin; friend class Plugin;
PluginManager(Core * core); PluginManager(Core * core);
~PluginManager(); ~PluginManager();
void init(Core* core);
void OnUpdate(color_ostream &out); void OnUpdate(color_ostream &out);
void OnStateChange(color_ostream &out, state_change_event event); void OnStateChange(color_ostream &out, state_change_event event);
void registerCommands( Plugin * p ); void registerCommands( Plugin * p );

@ -0,0 +1,47 @@
#pragma once
#ifndef EVENT_MANAGER_H_INCLUDED
#define EVENT_MANAGER_H_INCLUDED
#include "Core.h"
#include "Export.h"
#include "ColorText.h"
#include "PluginManager.h"
#include "Console.h"
namespace DFHack {
namespace EventManager {
namespace EventType {
enum EventType {
TICK,
JOB_INITIATED,
JOB_COMPLETED,
UNIT_DEATH,
ITEM_CREATED,
EVENT_MAX
};
}
struct EventHandler {
void (*eventHandler)(color_ostream&, void*); //called when the event happens
EventHandler(void (*eventHandlerIn)(color_ostream&, void*)): eventHandler(eventHandlerIn) {
}
bool operator==(EventHandler& handle) const {
return eventHandler == handle.eventHandler;
}
bool operator!=(EventHandler& handle) const {
return !( *this == handle);
}
};
DFHACK_EXPORT void registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin);
DFHACK_EXPORT void registerTick(EventHandler handler, int32_t when, Plugin* plugin, bool absolute=false);
DFHACK_EXPORT void unregister(EventType::EventType e, EventHandler handler, Plugin* plugin);
DFHACK_EXPORT void unregisterAll(Plugin* plugin);
void manageEvents(color_ostream& out);
void onStateChange(color_ostream& out, state_change_event event);
}
}
#endif

@ -47,7 +47,7 @@ namespace DFHack
{ {
namespace Job { namespace Job {
// Duplicate the job structure. It is not linked into any DF lists. // Duplicate the job structure. It is not linked into any DF lists.
DFHACK_EXPORT df::job *cloneJobStruct(df::job *job); DFHACK_EXPORT df::job *cloneJobStruct(df::job *job, bool keepWorkerData=false);
// Delete a cloned structure. // Delete a cloned structure.
DFHACK_EXPORT void deleteJobStruct(df::job *job); DFHACK_EXPORT void deleteJobStruct(df::job *job);

@ -0,0 +1,291 @@
#include "Core.h"
#include "Console.h"
#include "modules/EventManager.h"
#include "modules/Job.h"
#include "modules/World.h"
#include "df/global_objects.h"
#include "df/item.h"
#include "df/job.h"
#include "df/job_list_link.h"
#include "df/unit.h"
#include "df/world.h"
//#include <list>
#include <map>
//#include <vector>
using namespace std;
using namespace DFHack;
using namespace EventManager;
/*
* TODO:
* error checking
**/
//map<uint32_t, vector<DFHack::EventManager::EventHandler> > tickQueue;
multimap<uint32_t, EventHandler> tickQueue;
multimap<Plugin*, EventHandler> handlers[EventType::EVENT_MAX];
const uint32_t ticksPerYear = 403200;
void DFHack::EventManager::registerListener(EventType::EventType e, EventHandler handler, Plugin* plugin) {
handlers[e].insert(pair<Plugin*, EventHandler>(plugin, handler));
}
void DFHack::EventManager::registerTick(EventHandler handler, int32_t when, Plugin* plugin, bool absolute) {
uint32_t tick = DFHack::World::ReadCurrentYear()*ticksPerYear
+ DFHack::World::ReadCurrentTick();
if ( !Core::getInstance().isWorldLoaded() ) {
tick = 0;
if ( absolute ) {
Core::getInstance().getConsole().print("Warning: absolute flag will not be honored.\n");
}
}
if ( absolute ) {
tick = 0;
}
tickQueue.insert(pair<uint32_t, EventHandler>(tick+(uint32_t)when, handler));
handlers[EventType::TICK].insert(pair<Plugin*,EventHandler>(plugin,handler));
return;
}
void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handler, Plugin* plugin) {
for ( multimap<Plugin*, EventHandler>::iterator i = handlers[e].find(plugin); i != handlers[e].end(); i++ ) {
if ( (*i).first != plugin )
break;
EventHandler handle = (*i).second;
if ( handle == handler ) {
handlers[e].erase(i);
break;
}
}
return;
}
void DFHack::EventManager::unregisterAll(Plugin* plugin) {
for ( auto i = handlers[EventType::TICK].find(plugin); i != handlers[EventType::TICK].end(); i++ ) {
if ( (*i).first != plugin )
break;
//shenanigans to avoid concurrent modification
EventHandler getRidOf = (*i).second;
bool didSomething;
do {
didSomething = false;
for ( auto j = tickQueue.begin(); j != tickQueue.end(); j++ ) {
EventHandler candidate = (*j).second;
if ( getRidOf != candidate )
continue;
tickQueue.erase(j);
didSomething = true;
break;
}
} while(didSomething);
}
for ( size_t a = 0; a < (size_t)EventType::EVENT_MAX; a++ ) {
handlers[a].erase(plugin);
}
return;
}
static void manageTickEvent(color_ostream& out);
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 uint32_t lastTick = 0;
static int32_t lastJobId = -1;
static map<int32_t, df::job*> prevJobs;
static set<int32_t> livingUnits;
static int32_t nextItem;
void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event event) {
if ( event == DFHack::SC_MAP_UNLOADED ) {
lastTick = 0;
lastJobId = -1;
for ( auto i = prevJobs.begin(); i != prevJobs.end(); i++ ) {
Job::deleteJobStruct((*i).second);
}
prevJobs.clear();
tickQueue.clear();
livingUnits.clear();
nextItem = -1;
} else if ( event == DFHack::SC_MAP_LOADED ) {
uint32_t tick = DFHack::World::ReadCurrentYear()*ticksPerYear
+ DFHack::World::ReadCurrentTick();
multimap<uint32_t,EventHandler> newTickQueue;
for ( auto i = tickQueue.begin(); i != tickQueue.end(); i++ ) {
newTickQueue.insert(pair<uint32_t,EventHandler>(tick + (*i).first, (*i).second));
}
tickQueue.clear();
tickQueue.insert(newTickQueue.begin(), newTickQueue.end());
nextItem = *df::global::item_next_id;
}
}
void DFHack::EventManager::manageEvents(color_ostream& out) {
if ( !Core::getInstance().isWorldLoaded() ) {
return;
}
uint32_t tick = DFHack::World::ReadCurrentYear()*ticksPerYear
+ DFHack::World::ReadCurrentTick();
if ( tick <= lastTick )
return;
lastTick = tick;
manageTickEvent(out);
manageJobInitiatedEvent(out);
manageJobCompletedEvent(out);
manageUnitDeathEvent(out);
manageItemCreationEvent(out);
return;
}
static void manageTickEvent(color_ostream& out) {
uint32_t tick = DFHack::World::ReadCurrentYear()*ticksPerYear
+ DFHack::World::ReadCurrentTick();
while ( !tickQueue.empty() ) {
if ( tick < (*tickQueue.begin()).first )
break;
EventHandler handle = (*tickQueue.begin()).second;
tickQueue.erase(tickQueue.begin());
handle.eventHandler(out, (void*)tick);
}
}
static void manageJobInitiatedEvent(color_ostream& out) {
if ( handlers[EventType::JOB_INITIATED].empty() )
return;
if ( lastJobId == -1 ) {
lastJobId = *df::global::job_next_id - 1;
return;
}
if ( lastJobId+1 == *df::global::job_next_id ) {
return; //no new jobs
}
multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_INITIATED].begin(), handlers[EventType::JOB_INITIATED].end());
for ( df::job_list_link* link = &df::global::world->job_list; link != NULL; link = link->next ) {
if ( link->item == NULL )
continue;
if ( link->item->id <= lastJobId )
continue;
for ( auto i = copy.begin(); i != copy.end(); i++ ) {
(*i).second.eventHandler(out, (void*)link->item);
}
}
lastJobId = *df::global::job_next_id - 1;
}
static void manageJobCompletedEvent(color_ostream& out) {
if ( handlers[EventType::JOB_COMPLETED].empty() ) {
return;
}
multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_COMPLETED].begin(), handlers[EventType::JOB_COMPLETED].end());
map<int32_t, df::job*> nowJobs;
for ( df::job_list_link* link = &df::global::world->job_list; link != NULL; link = link->next ) {
if ( link->item == NULL )
continue;
nowJobs[link->item->id] = link->item;
}
for ( map<int32_t, df::job*>::iterator i = prevJobs.begin(); i != prevJobs.end(); i++ ) {
if ( nowJobs.find((*i).first) != nowJobs.end() )
continue;
//recently finished or cancelled job!
for ( auto j = copy.begin(); j != copy.end(); j++ ) {
(*j).second.eventHandler(out, (void*)(*i).second);
}
}
//erase old jobs, copy over possibly altered jobs
for ( map<int32_t, df::job*>::iterator i = prevJobs.begin(); i != prevJobs.end(); i++ ) {
Job::deleteJobStruct((*i).second);
}
prevJobs.clear();
//create new jobs
for ( map<int32_t, df::job*>::iterator j = nowJobs.begin(); j != nowJobs.end(); j++ ) {
/*map<int32_t, df::job*>::iterator i = prevJobs.find((*j).first);
if ( i != prevJobs.end() ) {
continue;
}*/
df::job* newJob = Job::cloneJobStruct((*j).second, true);
prevJobs[newJob->id] = newJob;
}
/*//get rid of old pointers to deallocated jobs
for ( size_t a = 0; a < toDelete.size(); a++ ) {
prevJobs.erase(a);
}*/
}
static void manageUnitDeathEvent(color_ostream& out) {
if ( handlers[EventType::UNIT_DEATH].empty() ) {
return;
}
multimap<Plugin*,EventHandler> copy(handlers[EventType::UNIT_DEATH].begin(), handlers[EventType::UNIT_DEATH].end());
for ( size_t a = 0; a < df::global::world->units.active.size(); a++ ) {
df::unit* unit = df::global::world->units.active[a];
if ( unit->counters.death_id == -1 ) {
livingUnits.insert(unit->id);
continue;
}
//dead: if dead since last check, trigger events
if ( livingUnits.find(unit->id) == livingUnits.end() )
continue;
for ( auto i = copy.begin(); i != copy.end(); i++ ) {
(*i).second.eventHandler(out, (void*)unit->id);
}
livingUnits.erase(unit->id);
}
}
static void manageItemCreationEvent(color_ostream& out) {
if ( handlers[EventType::ITEM_CREATED].empty() ) {
return;
}
if ( nextItem >= *df::global::item_next_id ) {
return;
}
multimap<Plugin*,EventHandler> copy(handlers[EventType::ITEM_CREATED].begin(), handlers[EventType::ITEM_CREATED].end());
size_t index = df::item::binsearch_index(df::global::world->items.all, nextItem, false);
for ( size_t a = index; a < df::global::world->items.all.size(); a++ ) {
df::item* item = df::global::world->items.all[a];
//invaders
if ( item->flags.bits.foreign )
continue;
//traders who bring back your items?
if ( item->flags.bits.trader )
continue;
//migrants
if ( item->flags.bits.owned )
continue;
//spider webs don't count
if ( item->flags.bits.spider_web )
continue;
for ( auto i = copy.begin(); i != copy.end(); i++ ) {
(*i).second.eventHandler(out, (void*)item->id);
}
}
nextItem = *df::global::item_next_id;
}

@ -54,7 +54,7 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
df::job *DFHack::Job::cloneJobStruct(df::job *job) df::job *DFHack::Job::cloneJobStruct(df::job *job, bool keepWorkerData)
{ {
CHECK_NULL_POINTER(job); CHECK_NULL_POINTER(job);
@ -75,7 +75,7 @@ df::job *DFHack::Job::cloneJobStruct(df::job *job)
{ {
df::general_ref *ref = pnew->references[i]; df::general_ref *ref = pnew->references[i];
if (virtual_cast<df::general_ref_unit_workerst>(ref)) if (!keepWorkerData && virtual_cast<df::general_ref_unit_workerst>(ref))
vector_erase_at(pnew->references, i); vector_erase_at(pnew->references, i);
else else
pnew->references[i] = ref->clone(); pnew->references[i] = ref->clone();

@ -18,6 +18,7 @@ DFHACK_PLUGIN(stripcaged stripcaged.cpp)
DFHACK_PLUGIN(rprobe rprobe.cpp) DFHACK_PLUGIN(rprobe rprobe.cpp)
DFHACK_PLUGIN(nestboxes nestboxes.cpp) DFHACK_PLUGIN(nestboxes nestboxes.cpp)
DFHACK_PLUGIN(vshook vshook.cpp) DFHACK_PLUGIN(vshook vshook.cpp)
DFHACK_PLUGIN(eventExample eventExample.cpp)
IF(UNIX) IF(UNIX)
DFHACK_PLUGIN(ref-index ref-index.cpp) DFHACK_PLUGIN(ref-index ref-index.cpp)
ENDIF() ENDIF()

@ -0,0 +1,79 @@
#include "Console.h"
#include "Core.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/EventManager.h"
#include "DataDefs.h"
#include "df/item.h"
#include "df/world.h"
#include <vector>
using namespace DFHack;
using namespace std;
DFHACK_PLUGIN("eventExample");
void jobInitiated(color_ostream& out, void* job);
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);
command_result eventExample(color_ostream& out, vector<string>& parameters);
DFhackCExport command_result plugin_init(color_ostream &out, std::vector<PluginCommand> &commands) {
commands.push_back(PluginCommand("eventExample", "Sets up a few event triggers.",eventExample));
return CR_OK;
}
command_result eventExample(color_ostream& out, vector<string>& parameters) {
EventManager::EventHandler initiateHandler(jobInitiated);
EventManager::EventHandler completeHandler(jobCompleted);
EventManager::EventHandler timeHandler(timePassed);
EventManager::EventHandler deathHandler(unitDeath);
EventManager::EventHandler itemHandler(itemCreate);
Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("eventExample");
EventManager::registerListener(EventManager::EventType::JOB_INITIATED, initiateHandler, me);
EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, completeHandler, me);
EventManager::registerTick(timeHandler, 1, me);
EventManager::registerTick(timeHandler, 2, me);
EventManager::registerTick(timeHandler, 4, me);
EventManager::registerTick(timeHandler, 8, me);
EventManager::registerListener(EventManager::EventType::UNIT_DEATH, deathHandler, me);
EventManager::registerListener(EventManager::EventType::ITEM_CREATED, itemHandler, me);
out.print("Events registered.\n");
return CR_OK;
}
void jobInitiated(color_ostream& out, void* job) {
out.print("Job initiated! 0x%X\n", job);
}
void jobCompleted(color_ostream& out, void* job) {
out.print("Job completed! 0x%X\n", job);
}
void timePassed(color_ostream& out, void* ptr) {
out.print("Time: %d\n", (int32_t)(ptr));
}
void unitDeath(color_ostream& out, void* ptr) {
out.print("Death: %d\n", (int32_t)(ptr));
}
void itemCreate(color_ostream& out, void* ptr) {
int32_t item_index = df::item::binsearch_index(df::global::world->items.all, (int32_t)ptr);
if ( item_index == -1 ) {
out.print("%s, %d: Error.\n", __FILE__, __LINE__);
}
df::item* item = df::global::world->items.all[item_index];
df::item_type type = item->getType();
df::coord pos = item->pos;
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);
}