@@ -71,13 +71,16 @@ using namespace df::enums;
7171command_result diggingInvadersCommand (color_ostream &out, std::vector <std::string> & parameters);
7272void watchForJobComplete (color_ostream& out, void * ptr);
7373void newInvasionHandler (color_ostream& out, void * ptr);
74+ void clearDijkstra ();
75+ void findAndAssignInvasionJob (color_ostream& out, void *);
7476// int32_t manageInvasion(color_ostream& out);
7577
7678DFHACK_PLUGIN (" diggingInvaders" );
7779
7880// TODO: when world unloads
7981static int32_t lastInvasionJob=-1 ;
8082static int32_t lastInvasionDigger = -1 ;
83+ static int32_t edgesPerTick = 100 ;
8184// static EventManager::EventHandler jobCompleteHandler(watchForJobComplete, 5);
8285static bool enabled=false ;
8386static bool activeDigging=false ;
@@ -87,17 +90,24 @@ static df::coord lastDebugEdgeCostPoint;
8790
8891DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
8992{
90- EventManager::EventHandler handler (newInvasionHandler, 1000 );
91- EventManager::registerListener (EventManager::EventType::INVASION , handler, plugin_self);
92-
9393 commands.push_back (PluginCommand (
9494 " diggingInvaders" , " Makes invaders dig to your dwarves." ,
9595 diggingInvadersCommand, false , /* true means that the command can't be used from non-interactive user interface */
96+ " example usage:\n "
97+ " diggingInvaders 0\n disables the plugin\n "
98+ " diggingInvaders 1\n enables the plugin\n "
9699 " diggingInvaders enable\n enables the plugin\n "
97100 " diggingInvaders disable\n disables the plugin\n "
98- " diggingInvaders add GOBLIN\n registers the race GOBLIN as a digging invader\n "
99- " diggingInvaders remove GOBLIN\n unregisters the race GOBLIN as a digging invader\n "
100- " diggingInvaders\n Makes invaders try to dig now.\n "
101+ " diggingInvaders add GOBLIN\n registers the race GOBLIN as a digging invader. Case-sensitive.\n "
102+ " diggingInvaders remove GOBLIN\n unregisters the race GOBLIN as a digging invader. Case-sensitive.\n "
103+ " diggingInvaders setCost walk n\n sets the walk cost in the path algorithm\n "
104+ " diggingInvaders setCost destroyBuilding n\n "
105+ " diggingInvaders setCost dig n\n "
106+ " diggingInvaders setCost destroyConstruction n\n "
107+ " diggingInvaders now\n makes invaders try to dig now, if plugin is enabled\n "
108+ " diggingInvaders clear\n clears all digging invader races\n "
109+ " diggingInvaders edgesPerTick n\n makes the pathfinding algorithm work on at most n edges per tick. Set to 0 or lower to make it unlimited."
110+ // " diggingInvaders\n Makes invaders try to dig now.\n"
101111 ));
102112
103113 *df::global::debug_showambush = true ;
@@ -111,16 +121,20 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
111121
112122DFhackCExport command_result plugin_onstatechange (color_ostream &out, state_change_event event)
113123{
114- EventManager::EventHandler invasionHandler (newInvasionHandler, 1000 );
115124 switch (event) {
116125 case DFHack::SC_WORLD_LOADED :
117126 // TODO: check game mode
118- lastInvasionJob = -1 ;
119- // in case there are invaders when the game is loaded, we should check
120- EventManager::registerTick (invasionHandler, 10 , plugin_self);
127+ // in case there are invaders when the game is loaded, we check if there's work to be done
128+ activeDigging = enabled;
129+ clearDijkstra ();
130+ findAndAssignInvasionJob (out, (void *)0 );
121131 break ;
122132 case DFHack::SC_WORLD_UNLOADED :
123133 // cleanup
134+ lastInvasionJob = lastInvasionDigger = -1 ;
135+ activeDigging = false ;
136+ clearDijkstra ();
137+ invaderJobs.clear ();
124138 break ;
125139 default :
126140 break ;
@@ -156,105 +170,19 @@ class PointComp {
156170};
157171
158172// bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev, set<df::coord>& importantPoints, set<Edge>& importantEdges);
159- void findAndAssignInvasionJob (color_ostream& out, void *);
160173
161174void newInvasionHandler (color_ostream& out, void * ptr) {
162175 if ( activeDigging )
163176 return ;
164177 activeDigging = true ;
165- EventManager::EventHandler handler (findAndAssignInvasionJob, 1 );
166- EventManager::registerTick (handler, 1 , plugin_self);
167- #if 0
168- //called when there's a new invasion
169- //TODO: check if invaders can dig
170- if ( manageInvasion(out) == -2 )
171- return;
172-
173- //schedule the next thing
174- uint32_t tick = World::ReadCurrentTick();
175- tick = tick % 1000;
176- tick = 1000 - tick;
177-
178- EventManager::EventHandler handle(newInvasionHandler, 1000);
179- EventManager::registerTick(handle, tick, plugin_self);
180- #endif
181- }
182-
183- #if 0
184- void watchForJobComplete(color_ostream& out, void* ptr) {
185- /*
186- df::job* job = (df::job*)ptr;
187-
188- if ( job->id != lastInvasionJob )
189- return;
190-
191- EventManager::unregister(EventManager::EventType::JOB_COMPLETED, jobCompleteHandler, plugin_self);
192- */
193-
194- manageInvasion(out);
195- }
196- #endif
197-
198- #if 0
199- int32_t manageInvasion(color_ostream& out) {
200- //EventManager::unregisterAll(plugin_self);
201- if ( !enabled ) {
202- return -1;
203- }
204- int32_t lastInvasion = df::global::ui->invasions.next_id-1;
205- if ( lastInvasion < 0 || df::global::ui->invasions.list[lastInvasion]->flags.bits.active == 0 ) {
206- //if the invasion is over, we're done
207- //out.print("Invasion is over. Stopping diggingInvaders.\n");
208- return -2;
209- }
210- EventManager::registerTick(jobCompleteHandler, 1, plugin_self);
211- if ( lastInvasionJob != -1 ) {
212- //check if he's still doing it
213- df::unit* worker = df::unit::find(lastInvasionDigger);
214- //int32_t index = df::unit::binsearch_index(df::global::world->units.all, lastInvasionDigger);
215- if ( !worker ) {
216- out.print("Error %s line %d.\n", __FILE__, __LINE__);
217- return -1;
218- }
219- df::job* job = worker->job.current_job;
220- //out.print("job id: old = %d, new = %d\n", lastInvasionJob, job == NULL ? -1 : job->id);
221- if ( job != NULL && lastInvasionJob == job->id ) {
222- //out.print("Still working on the previous job.\n");
223- return -1;
224- }
225-
226- //return 1; //still invading, but nothing new done
227- }
228-
229- int32_t unitId = findAndAssignInvasionJob(out);
230- if ( unitId == -1 ) {
231- //might need to do more digging later, after we've killed off a few locals
232- //out.print("DiggingInvaders is waiting.\n");
233- return -1;
234- }
235-
236- lastInvasionDigger = unitId;
237- {
238- df::unit* unit = df::unit::find(unitId);
239- if ( !unit ) {
240- //out.print("Error %s line %d: unitId = %d, index = %d.\n", __FILE__, __LINE__, unitId, index);
241- return -1;
242- }
243- lastInvasionJob = unit->job.current_job->id;
244- }
245-
246- //EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, jobCompleteHandler, plugin_self);
247- //out.print("DiggingInvaders: job assigned.\n");
248- *df::global::pause_state = true;
249- return 0; //did something
178+ findAndAssignInvasionJob (out, (void *)0 );
250179}
251- #endif
252180
253181command_result diggingInvadersCommand (color_ostream& out, std::vector<std::string>& parameters) {
254182 for ( size_t a = 0 ; a < parameters.size (); a++ ) {
255- if ( parameters[a] == " enable" ) {
183+ if ( parameters[a] == " 1 " || parameters[a] == " enable" ) {
256184 enabled = true ;
257- } else if ( parameters[a] == " disable" ) {
185+ } else if ( parameters[a] == " 0 " || parameters[a] == " disable" ) {
258186 enabled = false ;
259187 } else if ( parameters[a] == " add" || parameters[a] == " remove" ) {
260188 if ( a+1 >= parameters.size () )
@@ -265,24 +193,6 @@ command_result diggingInvadersCommand(color_ostream& out, std::vector<std::strin
265193 } else {
266194 diggingRaces.erase (race);
267195 }
268- /* bool foundIt = false;
269- for ( size_t b = 0; b < df::global::world->raws.creatures.all.size(); b++ ) {
270- df::creature_raw* raw = df::global::world->raws.creatures.all[b];
271- if ( race == raw->creature_id ) {
272- //out.print("%s = %s\n", race.c_str(), raw->creature_id.c_str());
273- if ( parameters[a] == "add" ) {
274- diggingRaces.insert(b);
275- } else {
276- diggingRaces.erase(b);
277- }
278- foundIt = true;
279- break;
280- }
281- }
282- if ( !foundIt ) {
283- out.print("Couldn't find \"%s\"\n", race.c_str());
284- return CR_WRONG_USAGE;
285- }*/
286196 a++;
287197 } else if ( parameters[a] == " setCost" ) {
288198 if ( a+2 >= parameters.size () )
@@ -311,16 +221,35 @@ command_result diggingInvadersCommand(color_ostream& out, std::vector<std::strin
311221 df::coord bob = Gui::getCursorPos ();
312222 out.print (" (%d,%d,%d), (%d,%d,%d): cost = %lld\n " , lastDebugEdgeCostPoint.x , lastDebugEdgeCostPoint.y , lastDebugEdgeCostPoint.z , bob.x , bob.y , bob.z , getEdgeCost (out, lastDebugEdgeCostPoint, bob));
313223 lastDebugEdgeCostPoint = bob;
224+ } else if ( parameters[a] == " now" ) {
225+ activeDigging = true ;
226+ findAndAssignInvasionJob (out, (void *)0 );
227+ } else if ( parameters[a] == " clear" ) {
228+ diggingRaces.clear ();
229+ } else if ( parameters[a] == " edgesPerTick" ) {
230+ if ( a+1 >= parameters.size () )
231+ return CR_WRONG_USAGE ;
232+ stringstream asdf (parameters[a+1 ]);
233+ int32_t edgeCount = 100 ;
234+ asdf >> edgeCount;
235+ edgesPerTick = edgeCount;
236+ a++;
314237 }
315238 else {
316239 return CR_WRONG_USAGE ;
317240 }
318241 }
242+ activeDigging = enabled;
243+ out.print (" diggingInvaders: enabled = %d, activeDigging = %d, edgesPerTick = %d\n " , enabled, activeDigging, edgesPerTick);
319244
320- if ( parameters.size () == 0 ) {
321- // manageInvasion(out);
322- newInvasionHandler (out, (void *)0 );
245+ EventManager::unregisterAll (plugin_self);
246+ if ( enabled ) {
247+ EventManager::EventHandler handler (newInvasionHandler, 1000 );
248+ EventManager::registerListener (EventManager::EventType::INVASION , handler, plugin_self);
249+ clearDijkstra ();
250+ findAndAssignInvasionJob (out, (void *)0 );
323251 }
252+
324253 return CR_OK ;
325254}
326255
@@ -335,7 +264,6 @@ unordered_map<df::coord,cost_t,PointHash> costMap;
335264PointComp comp (&costMap);
336265set<df::coord, PointComp> fringe (comp);
337266EventManager::EventHandler findJobTickHandler (findAndAssignInvasionJob, 1 );
338- const int32_t edgesPerFrame = 10000000 ;
339267
340268int32_t localPtsFound = 0 ;
341269unordered_set<df::coord,PointHash> closedSet;
@@ -363,7 +291,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
363291 // returns the worker id of the job created //used to
364292 // out.print("%s, %d: %d\n", __FILE__, __LINE__, (int32_t)tickTime);
365293
366- if ( !activeDigging ) {
294+ if ( !enabled || ! activeDigging ) {
367295 clearDijkstra ();
368296 return ;
369297 }
@@ -454,12 +382,12 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
454382 xMax *= 16 ;
455383 yMax *= 16 ;
456384 MapExtras::MapCache cache;
457-
385+
458386 clock_t t0 = clock ();
459387 clock_t totalEdgeTime = 0 ;
460388 int32_t edgesExpanded = 0 ;
461389 while (!fringe.empty ()) {
462- if ( edgesExpanded++ >= edgesPerFrame ) {
390+ if ( edgesPerTick > 0 && edgesExpanded++ >= edgesPerTick ) {
463391 return ;
464392 }
465393 df::coord pt = *(fringe.begin ());
@@ -513,7 +441,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
513441 delete myEdges;
514442 }
515443 clock_t time = clock () - t0;
516- out.print (" tickTime = %d, time = %d, totalEdgeTime = %d, total points = %d, total edges = %d, time per point = %.3f, time per edge = %.3f, clocks/sec = %d\n " , (int32_t )tickTime, time, totalEdgeTime, closedSet.size (), edgeCount, (float )time / closedSet.size (), (float )time / edgeCount, CLOCKS_PER_SEC );
444+ // out.print("tickTime = %d, time = %d, totalEdgeTime = %d, total points = %d, total edges = %d, time per point = %.3f, time per edge = %.3f, clocks/sec = %d\n", (int32_t)tickTime, time, totalEdgeTime, closedSet.size(), edgeCount, (float)time / closedSet.size(), (float)time / edgeCount, CLOCKS_PER_SEC);
517445 fringe.clear ();
518446
519447 if ( !foundTarget )
@@ -570,29 +498,6 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
570498 out.print (" %s,%d: closest = (%d,%d,%d), estimate = %lld != actual = %lld\n " , __FILE__, __LINE__, closest.x ,closest.y ,closest.z , closestCostEstimate, closestCostActual);
571499 return ;
572500 }
573- #if 0
574- unordered_set<df::coord,PointHash> toDelete;
575- for ( auto a = requiresZNeg.begin(); a != requiresZNeg.end(); a++ ) {
576- df::coord pos = *a;
577- df::tiletype* type = Maps::getTileType(pos);
578- df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *type);
579- if ( ENUM_ATTR(tiletype_shape, passable_low, shape) ) {
580- toDelete.insert(pos);
581- }
582- }
583- requiresZNeg.erase(toDelete.begin(), toDelete.end());
584- toDelete.clear();
585- for ( auto a = requiresZPos.begin(); a != requiresZPos.end(); a++ ) {
586- df::coord pos = *a;
587- df::tiletype* type = Maps::getTileType(pos);
588- df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *type);
589- if ( ENUM_ATTR(tiletype_shape, passable_high, shape) ) {
590- toDelete.insert(pos);
591- }
592- }
593- requiresZPos.erase(toDelete.begin(), toDelete.end());
594- toDelete.clear();
595- #endif
596501
597502 assignJob (out, firstImportantEdge, parentMap, costMap, invaders, requiresZNeg, requiresZPos, cache);
598503 lastInvasionDigger = firstInvader->id ;
0 commit comments