|
|
@ -60,17 +60,19 @@ Updated: Nov. 6 2022
|
|
|
|
#include <LuaWrapper.h>
|
|
|
|
#include <LuaWrapper.h>
|
|
|
|
#include <PluginManager.h>
|
|
|
|
#include <PluginManager.h>
|
|
|
|
#include <modules/EventManager.h>
|
|
|
|
#include <modules/EventManager.h>
|
|
|
|
|
|
|
|
#include <modules/Units.h>
|
|
|
|
|
|
|
|
#include <df/world.h>
|
|
|
|
|
|
|
|
#include <df/report.h>
|
|
|
|
|
|
|
|
#include <df/tile_traffic.h>
|
|
|
|
|
|
|
|
#include <df/block_square_event_designation_priorityst.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <cinttypes>
|
|
|
|
#include <cinttypes>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <unordered_set>
|
|
|
|
#include <unordered_set>
|
|
|
|
#include <modules/Units.h>
|
|
|
|
|
|
|
|
#include <df/report.h>
|
|
|
|
|
|
|
|
#include <df/tile_traffic.h>
|
|
|
|
|
|
|
|
#include <df/world.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Debugging
|
|
|
|
// Debugging
|
|
|
|
namespace DFHack {
|
|
|
|
namespace DFHack {
|
|
|
|
|
|
|
|
DBG_DECLARE(channelsafely, plugin, DebugCategory::LINFO);
|
|
|
|
DBG_DECLARE(channelsafely, monitor, DebugCategory::LERROR);
|
|
|
|
DBG_DECLARE(channelsafely, monitor, DebugCategory::LERROR);
|
|
|
|
DBG_DECLARE(channelsafely, manager, DebugCategory::LERROR);
|
|
|
|
DBG_DECLARE(channelsafely, manager, DebugCategory::LERROR);
|
|
|
|
DBG_DECLARE(channelsafely, groups, DebugCategory::LERROR);
|
|
|
|
DBG_DECLARE(channelsafely, groups, DebugCategory::LERROR);
|
|
|
@ -87,33 +89,25 @@ using namespace EM::EventType;
|
|
|
|
|
|
|
|
|
|
|
|
int32_t mapx, mapy, mapz;
|
|
|
|
int32_t mapx, mapy, mapz;
|
|
|
|
Configuration config;
|
|
|
|
Configuration config;
|
|
|
|
PersistentDataItem pconfig;
|
|
|
|
PersistentDataItem psetting;
|
|
|
|
const std::string CONFIG_KEY = std::string(plugin_name) + "/config";
|
|
|
|
PersistentDataItem pfeature;
|
|
|
|
|
|
|
|
const std::string FCONFIG_KEY = std::string(plugin_name) + "/feature";
|
|
|
|
|
|
|
|
const std::string SCONFIG_KEY = std::string(plugin_name) + "/setting";
|
|
|
|
//std::unordered_set<int32_t> active_jobs;
|
|
|
|
//std::unordered_set<int32_t> active_jobs;
|
|
|
|
|
|
|
|
|
|
|
|
#include <df/block_square_event_designation_priorityst.h>
|
|
|
|
enum FeatureConfigData {
|
|
|
|
|
|
|
|
|
|
|
|
enum ConfigurationData {
|
|
|
|
|
|
|
|
MONITOR,
|
|
|
|
|
|
|
|
VISION,
|
|
|
|
VISION,
|
|
|
|
INSTADIG,
|
|
|
|
MONITOR,
|
|
|
|
IGNORE_THRESH,
|
|
|
|
RESURRECT,
|
|
|
|
FALL_THRESH,
|
|
|
|
INSTADIG
|
|
|
|
REFRESH_RATE,
|
|
|
|
|
|
|
|
MONITOR_RATE
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
inline void saveConfig() {
|
|
|
|
enum SettingConfigData {
|
|
|
|
if (pconfig.isValid()) {
|
|
|
|
REFRESH_RATE,
|
|
|
|
pconfig.ival(MONITOR) = config.monitor_active;
|
|
|
|
MONITOR_RATE,
|
|
|
|
pconfig.ival(VISION) = config.require_vision;
|
|
|
|
IGNORE_THRESH,
|
|
|
|
pconfig.ival(INSTADIG) = config.insta_dig;
|
|
|
|
FALL_THRESH
|
|
|
|
pconfig.ival(REFRESH_RATE) = config.refresh_freq;
|
|
|
|
};
|
|
|
|
pconfig.ival(MONITOR_RATE) = config.monitor_freq;
|
|
|
|
|
|
|
|
pconfig.ival(IGNORE_THRESH) = config.ignore_threshold;
|
|
|
|
|
|
|
|
pconfig.ival(FALL_THRESH) = config.fall_threshold;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// executes dig designations for the specified tile coordinates
|
|
|
|
// executes dig designations for the specified tile coordinates
|
|
|
|
inline bool dig_now(color_ostream &out, const df::coord &map_pos) {
|
|
|
|
inline bool dig_now(color_ostream &out, const df::coord &map_pos) {
|
|
|
@ -133,11 +127,65 @@ inline bool dig_now(color_ostream &out, const df::coord &map_pos) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fully heals the unit specified, resurrecting if need be
|
|
|
|
|
|
|
|
inline void resurrect(color_ostream &out, const int32_t &unit) {
|
|
|
|
|
|
|
|
std::vector<std::string> params{"-r", "--unit", std::to_string(unit)};
|
|
|
|
|
|
|
|
Core::getInstance().runCommand(out,"full-heal", params);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace CSP {
|
|
|
|
namespace CSP {
|
|
|
|
std::unordered_map<int32_t, int32_t> active_workers;
|
|
|
|
std::unordered_set<df::unit*> endangered_workers;
|
|
|
|
|
|
|
|
std::unordered_map<df::job*, int32_t> job_ids;
|
|
|
|
|
|
|
|
std::unordered_map<int32_t, df::job*> active_jobs;
|
|
|
|
|
|
|
|
std::unordered_map<int32_t, df::unit*> active_workers;
|
|
|
|
|
|
|
|
|
|
|
|
std::unordered_map<int32_t, df::coord> last_safe;
|
|
|
|
std::unordered_map<int32_t, df::coord> last_safe;
|
|
|
|
std::unordered_set<df::coord> dignow_queue;
|
|
|
|
std::unordered_set<df::coord> dignow_queue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SaveSettings() {
|
|
|
|
|
|
|
|
if (pfeature.isValid() && psetting.isValid()) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
pfeature.ival(MONITOR) = config.monitor_active;
|
|
|
|
|
|
|
|
pfeature.ival(VISION) = config.require_vision;
|
|
|
|
|
|
|
|
pfeature.ival(INSTADIG) = config.insta_dig;
|
|
|
|
|
|
|
|
pfeature.ival(RESURRECT) = config.resurrect;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
psetting.ival(REFRESH_RATE) = config.refresh_freq;
|
|
|
|
|
|
|
|
psetting.ival(MONITOR_RATE) = config.monitor_freq;
|
|
|
|
|
|
|
|
psetting.ival(IGNORE_THRESH) = config.ignore_threshold;
|
|
|
|
|
|
|
|
psetting.ival(FALL_THRESH) = config.fall_threshold;
|
|
|
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
|
|
|
ERR(plugin).print("%s\n", e.what());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LoadSettings() {
|
|
|
|
|
|
|
|
pfeature = World::GetPersistentData(FCONFIG_KEY);
|
|
|
|
|
|
|
|
psetting = World::GetPersistentData(SCONFIG_KEY);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pfeature.isValid() || !psetting.isValid()) {
|
|
|
|
|
|
|
|
pfeature = World::AddPersistentData(FCONFIG_KEY);
|
|
|
|
|
|
|
|
psetting = World::AddPersistentData(SCONFIG_KEY);
|
|
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
config.monitor_active = pfeature.ival(MONITOR);
|
|
|
|
|
|
|
|
config.require_vision = pfeature.ival(VISION);
|
|
|
|
|
|
|
|
config.insta_dig = pfeature.ival(INSTADIG);
|
|
|
|
|
|
|
|
config.resurrect = pfeature.ival(RESURRECT);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
config.ignore_threshold = psetting.ival(IGNORE_THRESH);
|
|
|
|
|
|
|
|
config.fall_threshold = psetting.ival(FALL_THRESH);
|
|
|
|
|
|
|
|
config.refresh_freq = psetting.ival(REFRESH_RATE);
|
|
|
|
|
|
|
|
config.monitor_freq = psetting.ival(MONITOR_RATE);
|
|
|
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
|
|
|
ERR(plugin).print("%s\n", e.what());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
active_workers.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnpauseEvent(){
|
|
|
|
void UnpauseEvent(){
|
|
|
|
INFO(monitor).print("UnpauseEvent()\n");
|
|
|
|
INFO(monitor).print("UnpauseEvent()\n");
|
|
|
|
ChannelManager::Get().build_groups();
|
|
|
|
ChannelManager::Get().build_groups();
|
|
|
@ -158,8 +206,10 @@ namespace CSP {
|
|
|
|
if (worker && Units::isAlive(worker) && Units::isCitizen(worker)) {
|
|
|
|
if (worker && Units::isAlive(worker) && Units::isCitizen(worker)) {
|
|
|
|
DEBUG(jobs).print(" valid worker:\n");
|
|
|
|
DEBUG(jobs).print(" valid worker:\n");
|
|
|
|
// track workers on jobs
|
|
|
|
// track workers on jobs
|
|
|
|
if (config.monitor_active) {
|
|
|
|
if (config.monitor_active || config.resurrect) {
|
|
|
|
active_workers.emplace(job->id, Units::findIndexById(worker->id));
|
|
|
|
job_ids.emplace(job, job->id);
|
|
|
|
|
|
|
|
active_jobs.emplace(job->id, job);
|
|
|
|
|
|
|
|
active_workers[job->id] = worker;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// set tile to restricted
|
|
|
|
// set tile to restricted
|
|
|
|
TRACE(jobs).print(" setting job tile to restricted\n");
|
|
|
|
TRACE(jobs).print(" setting job tile to restricted\n");
|
|
|
@ -176,8 +226,6 @@ namespace CSP {
|
|
|
|
auto job = (df::job*) j;
|
|
|
|
auto job = (df::job*) j;
|
|
|
|
// we only care if the job is a channeling one
|
|
|
|
// we only care if the job is a channeling one
|
|
|
|
if (ChannelManager::Get().groups.count(job->pos)) {
|
|
|
|
if (ChannelManager::Get().groups.count(job->pos)) {
|
|
|
|
// untrack job/worker
|
|
|
|
|
|
|
|
active_workers.erase(job->id);
|
|
|
|
|
|
|
|
// check job outcome
|
|
|
|
// check job outcome
|
|
|
|
auto block = Maps::getTileBlock(job->pos);
|
|
|
|
auto block = Maps::getTileBlock(job->pos);
|
|
|
|
df::coord local(job->pos);
|
|
|
|
df::coord local(job->pos);
|
|
|
@ -188,12 +236,22 @@ namespace CSP {
|
|
|
|
// the job can be considered done
|
|
|
|
// the job can be considered done
|
|
|
|
df::coord below(job->pos);
|
|
|
|
df::coord below(job->pos);
|
|
|
|
below.z--;
|
|
|
|
below.z--;
|
|
|
|
WARN(jobs).print(" -> Marking tile done and managing the group below.\n");
|
|
|
|
WARN(jobs).print(" -> (" COORD ") is marked done, managing group below.\n", COORDARGS(job->pos));
|
|
|
|
// mark done and manage below
|
|
|
|
// mark done and manage below
|
|
|
|
block->designation[Coord(local)].bits.traffic = df::tile_traffic::Normal;
|
|
|
|
block->designation[Coord(local)].bits.traffic = df::tile_traffic::Normal;
|
|
|
|
ChannelManager::Get().mark_done(job->pos);
|
|
|
|
ChannelManager::Get().mark_done(job->pos);
|
|
|
|
ChannelManager::Get().manage_group(below);
|
|
|
|
ChannelManager::Get().manage_group(below);
|
|
|
|
ChannelManager::Get().debug();
|
|
|
|
ChannelManager::Get().debug();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ERR(jobs).print(" -> (" COORD ") is not done but the job \"completed\".\n", COORDARGS(job->pos));
|
|
|
|
|
|
|
|
endangered_workers.emplace(active_workers[job->id]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
|
|
|
|
if (!config.resurrect) {
|
|
|
|
|
|
|
|
auto jp = active_jobs[job->id];
|
|
|
|
|
|
|
|
job_ids.erase(jp);
|
|
|
|
|
|
|
|
active_workers.erase(job->id);
|
|
|
|
|
|
|
|
active_jobs.erase(job->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
INFO(jobs).print("JobCompletedEvent() exits\n");
|
|
|
|
INFO(jobs).print("JobCompletedEvent() exits\n");
|
|
|
@ -201,22 +259,34 @@ namespace CSP {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void NewReportEvent(color_ostream &out, void* r) {
|
|
|
|
void NewReportEvent(color_ostream &out, void* r) {
|
|
|
|
int32_t report_id = (int32_t)(intptr_t(r));
|
|
|
|
auto report_id = (int32_t)(intptr_t(r));
|
|
|
|
if (df::global::world) {
|
|
|
|
if (df::global::world) {
|
|
|
|
auto &reports = df::global::world->status.reports;
|
|
|
|
std::vector<df::report*> &reports = df::global::world->status.reports;
|
|
|
|
size_t idx = df::report::binsearch_index(reports, report_id);
|
|
|
|
size_t idx = -1;
|
|
|
|
if (idx >= 0 && idx < reports.size()){
|
|
|
|
idx = df::report::binsearch_index(reports, report_id);
|
|
|
|
auto report = reports[report_id];
|
|
|
|
df::report* report = reports.at(idx);
|
|
|
|
out.print("%d\n%s\n", report_id, report->text.c_str());
|
|
|
|
switch (report->type) {
|
|
|
|
|
|
|
|
case announcement_type::CAVE_COLLAPSE:
|
|
|
|
|
|
|
|
for (auto p : active_workers) {
|
|
|
|
|
|
|
|
endangered_workers.emplace(p.second);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case announcement_type::CANCEL_JOB:
|
|
|
|
|
|
|
|
out.print("%d, pos: " COORD "\n%s\n", report_id, COORDARGS(report->pos), report->text.c_str());
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OnUpdate(color_ostream &out) {
|
|
|
|
void OnUpdate(color_ostream &out) {
|
|
|
|
if (enabled && World::isFortressMode() && Maps::IsValid() && !World::ReadPauseState()) {
|
|
|
|
if (enabled && World::isFortressMode() && Maps::IsValid() && !World::ReadPauseState()) {
|
|
|
|
|
|
|
|
static int32_t last_tick = df::global::world->frame_counter;
|
|
|
|
static int32_t last_monitor_tick = df::global::world->frame_counter;
|
|
|
|
static int32_t last_monitor_tick = df::global::world->frame_counter;
|
|
|
|
static int32_t last_refresh_tick = df::global::world->frame_counter;
|
|
|
|
static int32_t last_refresh_tick = df::global::world->frame_counter;
|
|
|
|
|
|
|
|
static int32_t last_resurrect_tick = df::global::world->frame_counter;
|
|
|
|
int32_t tick = df::global::world->frame_counter;
|
|
|
|
int32_t tick = df::global::world->frame_counter;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Refreshing the group data with full scanning
|
|
|
|
if (tick - last_refresh_tick >= config.refresh_freq) {
|
|
|
|
if (tick - last_refresh_tick >= config.refresh_freq) {
|
|
|
|
last_refresh_tick = tick;
|
|
|
|
last_refresh_tick = tick;
|
|
|
|
TRACE(monitor).print("OnUpdate() refreshing now\n");
|
|
|
|
TRACE(monitor).print("OnUpdate() refreshing now\n");
|
|
|
@ -236,60 +306,112 @@ namespace CSP {
|
|
|
|
TRACE(monitor).print("OnUpdate() refresh done\n");
|
|
|
|
TRACE(monitor).print("OnUpdate() refresh done\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clean up stale df::job*
|
|
|
|
|
|
|
|
if ((config.monitor_active || config.resurrect) && tick - last_tick >= 1) {
|
|
|
|
|
|
|
|
last_tick = tick;
|
|
|
|
|
|
|
|
// make note of valid jobs
|
|
|
|
|
|
|
|
std::unordered_map<int32_t, df::job*> valid_jobs;
|
|
|
|
|
|
|
|
for (df::job_list_link* link = &df::global::world->jobs.list; link != nullptr; link = link->next) {
|
|
|
|
|
|
|
|
df::job* job = link->item;
|
|
|
|
|
|
|
|
if (job && active_jobs.count(job->id)) {
|
|
|
|
|
|
|
|
valid_jobs.emplace(job->id, job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// erase the active jobs that aren't valid
|
|
|
|
|
|
|
|
std::unordered_set<df::job*> erase;
|
|
|
|
|
|
|
|
map_value_difference(active_jobs, valid_jobs, erase);
|
|
|
|
|
|
|
|
for (auto j : erase) {
|
|
|
|
|
|
|
|
auto id = job_ids[j];
|
|
|
|
|
|
|
|
job_ids.erase(j);
|
|
|
|
|
|
|
|
active_jobs.erase(id);
|
|
|
|
|
|
|
|
active_workers.erase(id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Monitoring Active and Resurrecting Dead
|
|
|
|
if (config.monitor_active && tick - last_monitor_tick >= config.monitor_freq) {
|
|
|
|
if (config.monitor_active && tick - last_monitor_tick >= config.monitor_freq) {
|
|
|
|
last_monitor_tick = tick;
|
|
|
|
last_monitor_tick = tick;
|
|
|
|
TRACE(monitor).print("OnUpdate() monitoring now\n");
|
|
|
|
TRACE(monitor).print("OnUpdate() monitoring now\n");
|
|
|
|
for (df::job_list_link* link = &df::global::world->jobs.list; link != nullptr; link = link->next) {
|
|
|
|
|
|
|
|
df::job* job = link->item;
|
|
|
|
// iterate active jobs
|
|
|
|
if (job) {
|
|
|
|
for (auto pair: active_jobs) {
|
|
|
|
auto iter = active_workers.find(job->id);
|
|
|
|
df::job* job = pair.second;
|
|
|
|
TRACE(monitor).print(" -> check for job in tracking\n");
|
|
|
|
df::unit* unit = active_workers[job->id];
|
|
|
|
if (iter != active_workers.end()) {
|
|
|
|
if (!unit) continue;
|
|
|
|
df::unit* unit = df::global::world->units.active[iter->second];
|
|
|
|
TRACE(monitor).print(" -> check for job in tracking\n");
|
|
|
|
TRACE(monitor).print(" -> compare positions of worker and job\n");
|
|
|
|
if (Units::isAlive(unit)) {
|
|
|
|
// check if fall is possible
|
|
|
|
if (!config.monitor_active) continue;
|
|
|
|
if (unit->pos == job->pos) {
|
|
|
|
TRACE(monitor).print(" -> compare positions of worker and job\n");
|
|
|
|
// can fall, is safe?
|
|
|
|
|
|
|
|
TRACE(monitor).print(" equal -> check if safe fall\n");
|
|
|
|
// save position
|
|
|
|
if (!is_safe_fall(job->pos)) {
|
|
|
|
if (unit->pos != job->pos && isFloorTerrain(*Maps::getTileType(unit->pos))) {
|
|
|
|
// unsafe
|
|
|
|
// worker is perfectly safe right now
|
|
|
|
Job::removeWorker(job);
|
|
|
|
last_safe[unit->id] = unit->pos;
|
|
|
|
if (config.insta_dig) {
|
|
|
|
TRACE(monitor).print(" -> save safe position\n");
|
|
|
|
TRACE(monitor).print(" -> insta-dig\n");
|
|
|
|
continue;
|
|
|
|
// delete the job
|
|
|
|
}
|
|
|
|
Job::removeJob(job);
|
|
|
|
|
|
|
|
// queue digging the job instantly
|
|
|
|
// check for fall safety
|
|
|
|
dignow_queue.emplace(job->pos);
|
|
|
|
if (unit->pos == job->pos && !is_safe_fall(job->pos)) {
|
|
|
|
// worker is currently in the air
|
|
|
|
// unsafe
|
|
|
|
Units::teleport(unit, last_safe[unit->id]);
|
|
|
|
WARN(monitor).print(" -> unsafe job\n");
|
|
|
|
last_safe.erase(unit->id);
|
|
|
|
Job::removeWorker(job);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
TRACE(monitor).print(" -> set marker mode\n");
|
|
|
|
// decide to insta-dig or marker mode
|
|
|
|
// set to marker mode
|
|
|
|
if (config.insta_dig) {
|
|
|
|
Maps::getTileOccupancy(job->pos)->bits.dig_marked = true;
|
|
|
|
// delete the job
|
|
|
|
// prevent algorithm from re-enabling designation
|
|
|
|
Job::removeJob(job);
|
|
|
|
for (auto &be: Maps::getBlock(job->pos)->block_events) { ;
|
|
|
|
// queue digging the job instantly
|
|
|
|
if (auto bsedp = virtual_cast<df::block_square_event_designation_priorityst>(
|
|
|
|
dignow_queue.emplace(job->pos);
|
|
|
|
be)) {
|
|
|
|
DEBUG(monitor).print(" -> insta-dig\n");
|
|
|
|
df::coord local(job->pos);
|
|
|
|
} else if (Maps::isValidTilePos(job->pos)) {
|
|
|
|
local.x = local.x % 16;
|
|
|
|
// set marker mode
|
|
|
|
local.y = local.y % 16;
|
|
|
|
Maps::getTileOccupancy(job->pos)->bits.dig_marked = true;
|
|
|
|
bsedp->priority[Coord(local)] = config.ignore_threshold * 1000 + 1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
// prevent algorithm from re-enabling designation
|
|
|
|
}
|
|
|
|
for (auto &be: Maps::getBlock(job->pos)->block_events) { ;
|
|
|
|
}
|
|
|
|
if (auto bsedp = virtual_cast<df::block_square_event_designation_priorityst>(
|
|
|
|
|
|
|
|
be)) {
|
|
|
|
|
|
|
|
df::coord local(job->pos);
|
|
|
|
|
|
|
|
local.x = local.x % 16;
|
|
|
|
|
|
|
|
local.y = local.y % 16;
|
|
|
|
|
|
|
|
bsedp->priority[Coord(local)] = config.ignore_threshold * 1000 + 1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUG(monitor).print(" -> set marker mode\n");
|
|
|
|
TRACE(monitor).print(" -> save safe position\n");
|
|
|
|
|
|
|
|
// worker is perfectly safe right now
|
|
|
|
|
|
|
|
last_safe[unit->id] = unit->pos;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TRACE(monitor).print("OnUpdate() monitoring done\n");
|
|
|
|
TRACE(monitor).print("OnUpdate() monitoring done\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (config.resurrect && tick - last_resurrect_tick >= 1) {
|
|
|
|
|
|
|
|
last_resurrect_tick = tick;
|
|
|
|
|
|
|
|
static std::unordered_map<df::unit*, int32_t> age;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// clean up any "endangered" workers that have been tracked 100 ticks or more
|
|
|
|
|
|
|
|
for (auto iter = age.begin(); iter != age.end();) {
|
|
|
|
|
|
|
|
if (tick - iter->second >= 1200) { //keep watch 1 day
|
|
|
|
|
|
|
|
iter = age.erase(iter);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
++iter;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// resurrect any dead units
|
|
|
|
|
|
|
|
for (auto unit : endangered_workers) {
|
|
|
|
|
|
|
|
age.emplace(unit, tick);
|
|
|
|
|
|
|
|
if (!Units::isAlive(unit)) {
|
|
|
|
|
|
|
|
resurrect(out, unit->id);
|
|
|
|
|
|
|
|
Units::teleport(unit, last_safe[unit->id]);
|
|
|
|
|
|
|
|
WARN(plugin).print(">RESURRECTING<\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -310,19 +432,10 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DFhackCExport command_result plugin_load_data (color_ostream &out) {
|
|
|
|
DFhackCExport command_result plugin_load_data (color_ostream &out) {
|
|
|
|
pconfig = World::GetPersistentData(CONFIG_KEY);
|
|
|
|
CSP::LoadSettings();
|
|
|
|
|
|
|
|
if (enabled) {
|
|
|
|
if (!pconfig.isValid()) {
|
|
|
|
std::vector<std::string> params;
|
|
|
|
pconfig = World::AddPersistentData(CONFIG_KEY);
|
|
|
|
channel_safely(out, params);
|
|
|
|
saveConfig();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
config.monitor_active = pconfig.ival(MONITOR);
|
|
|
|
|
|
|
|
config.require_vision = pconfig.ival(VISION);
|
|
|
|
|
|
|
|
config.insta_dig = pconfig.ival(INSTADIG);
|
|
|
|
|
|
|
|
config.refresh_freq = pconfig.ival(REFRESH_RATE);
|
|
|
|
|
|
|
|
config.monitor_freq = pconfig.ival(MONITOR_RATE);
|
|
|
|
|
|
|
|
config.ignore_threshold = pconfig.ival(IGNORE_THRESH);
|
|
|
|
|
|
|
|
config.fall_threshold = pconfig.ival(FALL_THRESH);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DFHack::CR_OK;
|
|
|
|
return DFHack::CR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -352,6 +465,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
|
|
|
|
if (enabled && World::isFortressMode() && Maps::IsValid()) {
|
|
|
|
if (enabled && World::isFortressMode() && Maps::IsValid()) {
|
|
|
|
switch (event) {
|
|
|
|
switch (event) {
|
|
|
|
case SC_MAP_LOADED:
|
|
|
|
case SC_MAP_LOADED:
|
|
|
|
|
|
|
|
CSP::active_workers.clear();
|
|
|
|
// cache the map size
|
|
|
|
// cache the map size
|
|
|
|
Maps::getSize(mapx, mapy, mapz);
|
|
|
|
Maps::getSize(mapx, mapy, mapz);
|
|
|
|
case SC_UNPAUSED:
|
|
|
|
case SC_UNPAUSED:
|
|
|
@ -447,12 +561,28 @@ command_result channel_safely(color_ostream &out, std::vector<std::string> ¶
|
|
|
|
DBG_NAME(groups).allowed(DFHack::DebugCategory::LERROR);
|
|
|
|
DBG_NAME(groups).allowed(DFHack::DebugCategory::LERROR);
|
|
|
|
DBG_NAME(jobs).allowed(DFHack::DebugCategory::LERROR);
|
|
|
|
DBG_NAME(jobs).allowed(DFHack::DebugCategory::LERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if(parameters[1] == "monitor-active"){
|
|
|
|
} else if(parameters[1] == "monitor"){
|
|
|
|
config.monitor_active = state;
|
|
|
|
if (state != config.monitor_active) {
|
|
|
|
|
|
|
|
config.monitor_active = state;
|
|
|
|
|
|
|
|
// if this is a fresh start
|
|
|
|
|
|
|
|
if (state && !config.resurrect) {
|
|
|
|
|
|
|
|
// we need a fresh start
|
|
|
|
|
|
|
|
CSP::active_workers.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
} else if (parameters[1] == "require-vision") {
|
|
|
|
} else if (parameters[1] == "require-vision") {
|
|
|
|
config.require_vision = state;
|
|
|
|
config.require_vision = state;
|
|
|
|
} else if (parameters[1] == "insta-dig") {
|
|
|
|
} else if (parameters[1] == "insta-dig") {
|
|
|
|
config.insta_dig = state;
|
|
|
|
config.insta_dig = state;
|
|
|
|
|
|
|
|
} else if (parameters[1] == "resurrect") {
|
|
|
|
|
|
|
|
if (state != config.resurrect) {
|
|
|
|
|
|
|
|
config.resurrect = state;
|
|
|
|
|
|
|
|
// if this is a fresh start
|
|
|
|
|
|
|
|
if (state && !config.monitor_active) {
|
|
|
|
|
|
|
|
// we need a fresh start
|
|
|
|
|
|
|
|
CSP::active_workers.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
} else if (parameters[1] == "refresh-freq" && set && parameters.size() == 3) {
|
|
|
|
} else if (parameters[1] == "refresh-freq" && set && parameters.size() == 3) {
|
|
|
|
config.refresh_freq = std::abs(std::stol(parameters[2]));
|
|
|
|
config.refresh_freq = std::abs(std::stol(parameters[2]));
|
|
|
|
} else if (parameters[1] == "monitor-freq" && set && parameters.size() == 3) {
|
|
|
|
} else if (parameters[1] == "monitor-freq" && set && parameters.size() == 3) {
|
|
|
@ -477,14 +607,17 @@ command_result channel_safely(color_ostream &out, std::vector<std::string> ¶
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
out.print("Channel-Safely is %s\n", enabled ? "ENABLED." : "DISABLED.");
|
|
|
|
out.print("Channel-Safely is %s\n", enabled ? "ENABLED." : "DISABLED.");
|
|
|
|
out.print("monitor-active: %s\n", config.monitor_active ? "on." : "off.");
|
|
|
|
out.print(" FEATURES:\n");
|
|
|
|
out.print("require-vision: %s\n", config.require_vision ? "on." : "off.");
|
|
|
|
out.print(" %-20s\t%s\n", "monitor-active: ", config.monitor_active ? "on." : "off.");
|
|
|
|
out.print("insta-dig: %s\n", config.insta_dig ? "on." : "off.");
|
|
|
|
out.print(" %-20s\t%s\n", "require-vision: ", config.require_vision ? "on." : "off.");
|
|
|
|
out.print("refresh-freq: %" PRIi32 "\n", config.refresh_freq);
|
|
|
|
out.print(" %-20s\t%s\n", "insta-dig: ", config.insta_dig ? "on." : "off.");
|
|
|
|
out.print("monitor-freq: %" PRIi32 "\n", config.monitor_freq);
|
|
|
|
out.print(" %-20s\t%s\n", "resurrect: ", config.resurrect ? "on." : "off.");
|
|
|
|
out.print("ignore-threshold: %" PRIu8 "\n", config.ignore_threshold);
|
|
|
|
out.print(" SETTINGS:\n");
|
|
|
|
out.print("fall-threshold: %" PRIu8 "\n", config.fall_threshold);
|
|
|
|
out.print(" %-20s\t%" PRIi32 "\n", "refresh-freq: ", config.refresh_freq);
|
|
|
|
|
|
|
|
out.print(" %-20s\t%" PRIi32 "\n", "monitor-freq: ", config.monitor_freq);
|
|
|
|
|
|
|
|
out.print(" %-20s\t%" PRIu8 "\n", "ignore-threshold: ", config.ignore_threshold);
|
|
|
|
|
|
|
|
out.print(" %-20s\t%" PRIu8 "\n", "fall-threshold: ", config.fall_threshold);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
saveConfig();
|
|
|
|
CSP::SaveSettings();
|
|
|
|
return DFHack::CR_OK;
|
|
|
|
return DFHack::CR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|