11#include " Core.h"
22#include " Debug.h"
3+ #include " LuaTools.h"
34#include " PluginManager.h"
45#include " TileTypes.h"
56
1819#include " df/world.h"
1920
2021#include < bitset>
22+ #include < format>
2123#include < functional>
2224#include < ranges>
2325#include < string>
@@ -76,6 +78,21 @@ inline bool isExternalReason(Reason reason) {
7678 return reason == Reason::BUILDINGPLAN || reason == Reason::UNDER_WATER ;
7779}
7880
81+ static string reasonToString (Reason reason) {
82+ switch (reason) {
83+ case Reason::DEADEND :
84+ return " Blocks another build job" ;
85+ case Reason::RISK_BLOCKING :
86+ return " May block another build job" ;
87+ case Reason::UNSUPPORTED :
88+ return " Would collapse immediately" ;
89+ case Reason::ERASE_DESIGNATION :
90+ return " Waiting for carve/smooth/engrave" ;
91+ default :
92+ return " External reason" ;
93+ }
94+ }
95+
7996using df::coord;
8097
8198// set() is constexpr starting with C++23
@@ -497,10 +514,30 @@ class SuspendManager {
497514
498515 std::map<int ,Reason> suspensions;
499516 std::set<int > leadsToDeadend;
517+ size_t num_suspend = 0 , num_unsuspend = 0 ;
500518
501519public:
502520 bool prevent_blocking = true ;
503521
522+ // gather some statistics about the last call to do_cycle()
523+ string getStatus (color_ostream &out) {
524+ std::map<Reason,int > stats;
525+
526+ for (auto [_ , reason] : suspensions) {
527+ stats[reason == Reason::DEADEND ? Reason::RISK_BLOCKING : reason]++;
528+ }
529+
530+ string res;
531+ res += std::format (" suspended {} and unsuspend {} jobs\n " , num_suspend, num_unsuspend);
532+ res += std::format (" maintaining {} suspension reasons\n " , suspensions.size ());
533+ for (auto stat : stats) {
534+ res += std::format (" {:5} {}\n " , stat.second , reasonToString (stat.first ));
535+ }
536+
537+ DEBUG (control,out).print (" res: %s" , res.c_str ());
538+ return res;
539+ }
540+
504541 void refresh (color_ostream &out)
505542 {
506543 DEBUG (cycle,out).print (" starting refresh, prevent blocking is %s\n " ,
@@ -551,7 +588,7 @@ class SuspendManager {
551588
552589 void do_cycle (color_ostream &out) {
553590 refresh (out);
554- size_t num_suspend = 0 , num_unsuspend = 0 ;
591+ num_suspend = 0 , num_unsuspend = 0 ;
555592
556593 Reason reason;
557594
@@ -588,18 +625,7 @@ class SuspendManager {
588625 std::string suspensionDescription (df::job *job) {
589626 Reason reason;
590627 if (tryGetReason (job,reason)) {
591- switch (reason) {
592- case Reason::DEADEND :
593- return " Blocks another build job" ;
594- case Reason::RISK_BLOCKING :
595- return " May block another build job" ;
596- case Reason::UNSUPPORTED :
597- return " Would collapse immediately" ;
598- case Reason::ERASE_DESIGNATION :
599- return " Waiting for carve/smooth/engrave" ;
600- default :
601- return " External reason" ;
602- }
628+ return reasonToString (reason);
603629 }
604630 return " not suspended by suspendmanager" ;
605631 }
@@ -699,7 +725,6 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) {
699725 return CR_OK ;
700726}
701727
702-
703728static command_result do_command (color_ostream &out, vector<string> ¶meters) {
704729 // be sure to suspend the core if any DF state is read or modified
705730 CoreSuspender suspend;
@@ -711,11 +736,26 @@ static command_result do_command(color_ostream &out, vector<string> ¶meters)
711736
712737 if (parameters[0 ] == " now" ) {
713738 do_cycle (out);
739+ return CR_OK ;
740+ } else if (parameters[0 ] == " enable" ) {
741+ return plugin_enable (out,true );
742+ } else if (parameters[0 ] == " disable" ) {
743+ return plugin_enable (out,false );
744+ } else if (parameters[0 ] == " set" && parameters[1 ] == " preventblocking" ) {
745+ if (parameters[3 ] == " true" ) {
746+ suspendmanager_instance->prevent_blocking = true ;
747+ if (is_enabled) do_cycle (out);
748+ return CR_OK ;
749+ } else if (parameters[3 ] == " false" ) {
750+ suspendmanager_instance->prevent_blocking = false ;
751+ if (is_enabled) do_cycle (out);
752+ return CR_OK ;
753+ } else
754+ return CR_WRONG_USAGE ;
714755 } else {
715756 return CR_WRONG_USAGE ;
716757 }
717758
718- return CR_OK ;
719759}
720760
721761static void jobCompletedHandler (color_ostream& out, void * ptr) {
@@ -738,6 +778,7 @@ static void do_cycle(color_ostream &out) {
738778 suspendmanager_instance->do_cycle (out);
739779}
740780
781+
741782// ///////////////////////////////////////////////////
742783// Lua exports
743784//
@@ -763,15 +804,21 @@ static bool suspendmanager_isKeptSuspended(df::job *job) {
763804}
764805
765806static void suspendmanager_runOnce (color_ostream &out, bool blocking) {
807+ auto save = suspendmanager_instance->prevent_blocking ;
766808 suspendmanager_instance->prevent_blocking = blocking;
767809 do_cycle (out);
768- suspendmanager_instance->prevent_blocking = true ;
810+ suspendmanager_instance->prevent_blocking = save;
811+ }
812+
813+ static string suspendmanager_getStatus (color_ostream &out) {
814+ return suspendmanager_instance->getStatus (out);
769815}
770816
771817
772818DFHACK_PLUGIN_LUA_FUNCTIONS {
773819 DFHACK_LUA_FUNCTION (suspendmanager_suspensionDescription),
774820 DFHACK_LUA_FUNCTION (suspendmanager_isKeptSuspended),
775821 DFHACK_LUA_FUNCTION (suspendmanager_runOnce),
822+ DFHACK_LUA_FUNCTION (suspendmanager_getStatus),
776823 DFHACK_LUA_END
777824};
0 commit comments