diff --git a/library/Core.cpp b/library/Core.cpp index 761122939..010017edb 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -50,6 +50,36 @@ using namespace std; #include using namespace DFHack; + struct Core::Cond + { + Cond() + { + predicate = false; + wakeup = SDL_CreateCond(); + } + ~Cond() + { + SDL_DestroyCond(wakeup); + } + bool Lock(SDL::Mutex * m) + { + while(!predicate) + { + SDL_CondWait(wakeup,m); + } + predicate = false; + return true; + } + bool Unlock() + { + predicate = true; + SDL_CondSignal(wakeup); + return true; + } + SDL::Cond * wakeup; + bool predicate; + }; + void cheap_tokenise(string const& input, vector &output) { istringstream str(input); @@ -181,6 +211,7 @@ Core::Core() // create mutex for syncing with interactive tasks AccessMutex = 0; + core_cond = 0; // set up hotkey capture memset(hotkey_states,0,sizeof(hotkey_states)); hotkey_set = false; @@ -219,9 +250,7 @@ bool Core::Init() errorstate = true; return false; } - // lock mutex - SDL_mutexP(AccessMutex); - + core_cond = new Core::Cond(); // create plugin manager plug_mgr = new PluginManager(this); if(!plug_mgr) @@ -275,17 +304,21 @@ std::string Core::getHotkeyCmd( void ) void Core::Suspend() { + Core::Cond * nc = new Core::Cond(); + // put the condition on a stack + SDL_mutexP(StackMutex); + suspended_tools.push(nc); + SDL_mutexV(StackMutex); + // wait until Core::Update() wakes up the tool SDL_mutexP(AccessMutex); + nc->Lock(AccessMutex); + SDL_mutexV(AccessMutex); } void Core::Resume() { - /* - for(unsigned int i = 0 ; i < allModules.size(); i++) - { - allModules[i]->OnResume(); - } - */ + SDL_mutexP(AccessMutex); + core_cond->Unlock(); SDL_mutexV(AccessMutex); } @@ -301,12 +334,26 @@ int Core::Update() std::cerr << "Update from Thread " << SDL_ThreadID() << std::endl; flip2 = true; } + // notify all the plugins that a game tick is finished plug_mgr->OnUpdate(); - SDL_mutexV(AccessMutex); - // other threads can claim the mutex here and use DFHack. - // NO CODE SHOULD EVER BE PLACED HERE - SDL_mutexP(AccessMutex); + // wake waiting tools + // do not allow more tools to join in while we process stuff here + SDL_mutexP(StackMutex); + while (!suspended_tools.empty()) + { + Core::Cond * nc = suspended_tools.top(); + suspended_tools.pop(); + SDL_mutexP(AccessMutex); + // wake tool + nc->Unlock(); + // wait for tool to wake us + core_cond->Lock(AccessMutex); + SDL_mutexV(AccessMutex); + // destroy condition + delete nc; + } + SDL_mutexV(StackMutex); return 0; }; diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h index 1d5368664..1f9615d9e 100644 --- a/library/include/dfhack/Core.h +++ b/library/include/dfhack/Core.h @@ -28,6 +28,7 @@ distribution. #include "dfhack/Export.h" #include "dfhack/FakeSDL.h" #include +#include #include #include @@ -121,8 +122,12 @@ namespace DFHack Core(Core const&); // Don't Implement void operator=(Core const&); // Don't implement bool errorstate; - // mutex for access to DF + // regulate access to DF + struct Cond; SDL::Mutex * AccessMutex; + SDL::Mutex * StackMutex; + std::stack < Core::Cond * > suspended_tools; + Core::Cond * core_cond; // FIXME: shouldn't be kept around like this DFHack::VersionInfoFactory * vif; // Module storage diff --git a/plugins/kittens.cpp b/plugins/kittens.cpp index 8e9da7d09..676559cdd 100644 --- a/plugins/kittens.cpp +++ b/plugins/kittens.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "dfhack/extra/stopwatch.h" using std::vector; using std::string; @@ -11,8 +12,11 @@ using namespace DFHack; //FIXME: possible race conditions with calling kittens from the IO thread and shutdown from Core. bool shutdown_flag = false; bool final_flag = true; +bool timering = false; +uint64_t timeLast = 0; DFhackCExport command_result kittens (Core * c, vector & parameters); +DFhackCExport command_result ktimer (Core * c, vector & parameters); DFhackCExport const char * plugin_name ( void ) { @@ -23,7 +27,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector { commands.clear(); commands.push_back(PluginCommand("kittens","Rainbow kittens. What else?",kittens)); - commands.push_back(PluginCommand("kittanz","Guess what. More rainbow kittenz.",kittens)); + commands.push_back(PluginCommand("ktimer","Time events...",ktimer)); return CR_OK; } @@ -37,6 +41,37 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) return CR_OK; } + + +DFhackCExport command_result plugin_onupdate ( Core * c ) +{ + if(timering == true) + { + uint64_t time2 = GetTimeMs64(); + uint64_t delta = time2-timeLast; + timeLast = time2; + dfout << "Time delta = " << delta << " ms" << std::endl; + } + return CR_OK; +} + +DFhackCExport command_result ktimer (Core * c, vector & parameters) +{ + if(timering) + { + timering = false; + return CR_OK; + } + uint64_t timestart = GetTimeMs64(); + c->Suspend(); + c->Resume(); + uint64_t timeend = GetTimeMs64(); + dfout << "Time to suspend = " << timeend - timestart << " ms" << std::endl; + timeLast = timeend; + timering = true; + return CR_OK; +} + DFhackCExport command_result kittens (Core * c, vector & parameters) { final_flag = false; diff --git a/plugins/vdig.cpp b/plugins/vdig.cpp index fadb8408b..4720c38bb 100644 --- a/plugins/vdig.cpp +++ b/plugins/vdig.cpp @@ -2,14 +2,21 @@ #include #include #include +#include +#include +#include #include +#include +#include #include using std::vector; using std::string; +using std::stack; using namespace DFHack; DFhackCExport command_result vdig (Core * c, vector & parameters); +DFhackCExport command_result autodig (Core * c, vector & parameters); DFhackCExport const char * plugin_name ( void ) { @@ -19,7 +26,8 @@ DFhackCExport const char * plugin_name ( void ) DFhackCExport command_result plugin_init ( Core * c, std::vector &commands) { commands.clear(); - commands.push_back(PluginCommand("vdig","Dig a whole vein.",vdig)); + commands.push_back(PluginCommand("vdig","Dig a whole vein. With 'x' option, dig stairs between z-levels.",vdig)); + commands.push_back(PluginCommand("autodig","Mark a tile for continuous digging.",autodig)); return CR_OK; } @@ -30,5 +38,163 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) DFhackCExport command_result vdig (Core * c, vector & parameters) { + uint32_t x_max,y_max,z_max; + bool updown = false; + if(parameters.size() && parameters[0]=="x") + updown = true; + + c->Suspend(); + DFHack::Maps * Maps = c->getMaps(); + DFHack::Gui * Gui = c->getGui(); + // init the map + if(!Maps->Start()) + { + dfout << "Can't init map. Make sure you have a map loaded in DF." << std::endl; + c->Resume(); + return CR_FAILURE; + } + + int32_t cx, cy, cz; + Maps->getSize(x_max,y_max,z_max); + uint32_t tx_max = x_max * 16; + uint32_t ty_max = y_max * 16; + Gui->getCursorCoords(cx,cy,cz); + while(cx == -30000) + { + dfout << "Cursor is not active. Point the cursor at a vein." << std::endl; + c->Resume(); + return CR_FAILURE; + } + DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); + if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) + { + dfout << "I won't dig the borders. That would be cheating!" << std::endl; + c->Resume(); + return CR_FAILURE; + } + MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); + DFHack::t_designation des = MCache->designationAt(xy); + int16_t tt = MCache->tiletypeAt(xy); + int16_t veinmat = MCache->veinMaterialAt(xy); + if( veinmat == -1 ) + { + dfout << "This tile is not a vein." << std::endl; + delete MCache; + c->Resume(); + return CR_FAILURE; + } + fprintf(dfout_C,"%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); + stack flood; + flood.push(xy); + + while( !flood.empty() ) + { + DFHack::DFCoord current = flood.top(); + flood.pop(); + int16_t vmat2 = MCache->veinMaterialAt(current); + tt = MCache->tiletypeAt(current); + if(!DFHack::isWallTerrain(tt)) + continue; + if(vmat2!=veinmat) + continue; + + // found a good tile, dig+unset material + DFHack::t_designation des = MCache->designationAt(current); + DFHack::t_designation des_minus; + DFHack::t_designation des_plus; + des_plus.whole = des_minus.whole = 0; + int16_t vmat_minus = -1; + int16_t vmat_plus = -1; + bool below = 0; + bool above = 0; + if(updown) + { + if(MCache->testCoord(current-1)) + { + below = 1; + des_minus = MCache->designationAt(current-1); + vmat_minus = MCache->veinMaterialAt(current-1); + } + + if(MCache->testCoord(current+1)) + { + above = 1; + des_plus = MCache->designationAt(current+1); + vmat_plus = MCache->veinMaterialAt(current+1); + } + } + if(MCache->testCoord(current)) + { + MCache->clearMaterialAt(current); + if(current.x < tx_max - 2) + { + flood.push(DFHack::DFCoord(current.x + 1, current.y, current.z)); + if(current.y < ty_max - 2) + { + flood.push(DFHack::DFCoord(current.x + 1, current.y + 1,current.z)); + flood.push(DFHack::DFCoord(current.x, current.y + 1,current.z)); + } + if(current.y > 1) + { + flood.push(DFHack::DFCoord(current.x + 1, current.y - 1,current.z)); + flood.push(DFHack::DFCoord(current.x, current.y - 1,current.z)); + } + } + if(current.x > 1) + { + flood.push(DFHack::DFCoord(current.x - 1, current.y,current.z)); + if(current.y < ty_max - 2) + { + flood.push(DFHack::DFCoord(current.x - 1, current.y + 1,current.z)); + flood.push(DFHack::DFCoord(current.x, current.y + 1,current.z)); + } + if(current.y > 1) + { + flood.push(DFHack::DFCoord(current.x - 1, current.y - 1,current.z)); + flood.push(DFHack::DFCoord(current.x, current.y - 1,current.z)); + } + } + if(updown) + { + if(current.z > 0 && below && vmat_minus == vmat2) + { + flood.push(current-1); + + if(des_minus.bits.dig == DFHack::designation_d_stair) + des_minus.bits.dig = DFHack::designation_ud_stair; + else + des_minus.bits.dig = DFHack::designation_u_stair; + MCache->setDesignationAt(current-1,des_minus); + + des.bits.dig = DFHack::designation_d_stair; + } + if(current.z < z_max - 1 && above && vmat_plus == vmat2) + { + flood.push(current+ 1); + + if(des_plus.bits.dig == DFHack::designation_u_stair) + des_plus.bits.dig = DFHack::designation_ud_stair; + else + des_plus.bits.dig = DFHack::designation_d_stair; + MCache->setDesignationAt(current+1,des_plus); + + if(des.bits.dig == DFHack::designation_d_stair) + des.bits.dig = DFHack::designation_ud_stair; + else + des.bits.dig = DFHack::designation_u_stair; + } + } + if(des.bits.dig == DFHack::designation_no) + des.bits.dig = DFHack::designation_default; + MCache->setDesignationAt(current,des); + } + } + MCache->WriteAll(); + c->Resume(); return CR_OK; } + +DFhackCExport command_result autodig (Core * c, vector & parameters) +{ + return CR_OK; +} \ No newline at end of file