From c2d346fc841dfa8b6affdb4c683ed15241b410cc Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Sun, 6 Nov 2022 13:16:27 -0800 Subject: [PATCH] Implements plugin: channel-safely v0.4 --- docs/plugins/channel-safely.rst | 5 +- plugins/channel-safely/channel-groups.cpp | 32 ++++++++- plugins/channel-safely/channel-manager.cpp | 18 +++-- .../channel-safely/channel-safely-plugin.cpp | 33 ++++----- plugins/channel-safely/include/inlines.h | 67 ++++++++++++------- plugins/channel-safely/include/plugin.h | 4 +- 6 files changed, 105 insertions(+), 54 deletions(-) diff --git a/docs/plugins/channel-safely.rst b/docs/plugins/channel-safely.rst index 6010f4925..842d57353 100644 --- a/docs/plugins/channel-safely.rst +++ b/docs/plugins/channel-safely.rst @@ -55,8 +55,7 @@ Settings -------- :refresh-freq: The rate at which full refreshes are performed. This can be expensive if you're undertaking many mega projects. (default:600, twice a day) -:monitor-freq: The rate at which active jobs are monitored. - todo: this can have a massive impact? (default:10) +:monitor-freq: The rate at which active jobs are monitored. (default:1) :ignore-threshold: Sets the priority threshold below which designations are processed. You can set to 1 or 0 to - effectively disable the scanning. (default: 7) + effectively disable the scanning. (default: 5) :fall-threshold: Sets the fall threshold beyond which is considered unsafe. (default: 1) diff --git a/plugins/channel-safely/channel-groups.cpp b/plugins/channel-safely/channel-groups.cpp index 638ba395b..7e5cccf20 100644 --- a/plugins/channel-safely/channel-groups.cpp +++ b/plugins/channel-safely/channel-groups.cpp @@ -5,6 +5,22 @@ #include +template +void set_difference(const Ctr1 &c1, const Ctr2 &c2, Ctr3 &c3) { + for (const auto &a : c1) { + bool matched = false; + for (const auto &b : c2) { + if (a == b) { + matched = true; + break; + } + } + if (!matched) { + c3.emplace(a); + } + } +} + // adds map_pos to a group if an adjacent one exists, or creates one if none exist... if multiple exist they're merged into the first found void ChannelGroups::add(const df::coord &map_pos) { // if we've already added this, we don't need to do it again @@ -111,12 +127,24 @@ void ChannelGroups::scan_one(const df::coord &map_pos) { // builds groupings of adjacent channel designations void ChannelGroups::scan() { - // iterate over each job, finding channel jobs + // save current jobs, then clear and load the current jobs + std::set last_jobs; + for (auto &pos : jobs) { + last_jobs.emplace(pos); + } jobs.load_channel_jobs(); // transpose channel jobs to - for (auto &pos : jobs) { + std::set new_jobs; + std::set gone_jobs; + set_difference(last_jobs, jobs, gone_jobs); + set_difference(jobs, last_jobs, new_jobs); + for (auto &pos : new_jobs) { add(pos); } + for (auto &pos : gone_jobs){ + remove(pos); + } + DEBUG(groups).print(" scan()\n"); // foreach block for (int32_t z = mapz - 1; z >= 0; --z) { diff --git a/plugins/channel-safely/channel-manager.cpp b/plugins/channel-safely/channel-manager.cpp index 28d757772..86ce5a726 100644 --- a/plugins/channel-safely/channel-manager.cpp +++ b/plugins/channel-safely/channel-manager.cpp @@ -62,9 +62,18 @@ bool ChannelManager::manage_one(const Group &group, const df::coord &map_pos, bo // do we already know whether to set marker mode? if (set_marker_mode) { DEBUG(manager).print(" -> marker_mode\n"); - tile_occupancy.bits.dig_marked = marker_mode; - jobs.erase(map_pos); - return true; + // if enabling marker mode, just do it + if (marker_mode) { + tile_occupancy.bits.dig_marked = marker_mode; + return true; + } + // if activating designation, check if it is safe to dig or not a channel designation + if (!is_channel_designation(block->designation[Coord(local)]) || is_safe_to_dig_down(map_pos)) { + tile_occupancy.bits.dig_marked = marker_mode; + return marker_mode; + } + return false; + } else { // next search for the designation priority for (df::block_square_event* event: block->block_events) { @@ -73,7 +82,7 @@ bool ChannelManager::manage_one(const Group &group, const df::coord &map_pos, bo if (evT->priority[Coord(local)] < 1000 * config.ignore_threshold) { DEBUG(manager).print(" if(has_groups_above())\n"); // check that the group has no incomplete groups directly above it - if (has_group_above(groups, map_pos)) { + if (has_group_above(groups, map_pos) || !is_safe_to_dig_down(map_pos)) { DEBUG(manager).print(" has_groups_above: setting marker mode\n"); tile_occupancy.bits.dig_marked = true; jobs.erase(map_pos); @@ -95,5 +104,4 @@ bool ChannelManager::manage_one(const Group &group, const df::coord &map_pos, bo void ChannelManager::mark_done(const df::coord &map_pos) { groups.remove(map_pos); - jobs.erase(map_pos); //redundant (repopulated on each build) } diff --git a/plugins/channel-safely/channel-safely-plugin.cpp b/plugins/channel-safely/channel-safely-plugin.cpp index 333d4452a..a63228e27 100644 --- a/plugins/channel-safely/channel-safely-plugin.cpp +++ b/plugins/channel-safely/channel-safely-plugin.cpp @@ -1,7 +1,7 @@ /* Prevent channeling down into known open space. Author: Josh Cooper Created: Aug. 4 2020 -Updated: Nov. 1 2022 +Updated: Nov. 6 2022 Enable plugin: -> build groups @@ -13,9 +13,9 @@ Updated: Nov. 1 2022 Manage Designation(s): -> for each group in groups: - -> for each designation in this group: - -> - + -> does any tile in group have a group above + -> Yes: set entire group to marker mode + -> No: activate entire group (still checks is_safe_to_dig_down before activating each designation) Job started event: -> validate job type (channel) @@ -150,7 +150,7 @@ namespace CSP { INFO(monitor).print("JobStartedEvent()\n"); auto job = (df::job*) p; // validate job type - if (is_dig_job(job)) { + if (is_channel_job(job)) { DEBUG(monitor).print(" valid channel job:\n"); df::unit* worker = Job::getWorker(job); // there is a valid worker (living citizen) on the job? right.. @@ -160,7 +160,7 @@ namespace CSP { local.x = local.x % 16; local.y = local.y % 16; // check pathing exists to job - if (Maps::canWalkBetween(worker->pos, job->pos)) { + if (can_reach_designation(worker->pos, job->pos)) { DEBUG(monitor).print(" can path from (" COORD ") to (" COORD ")\n", COORDARGS(worker->pos), COORDARGS(job->pos)); // track workers on jobs @@ -246,6 +246,17 @@ namespace CSP { last_refresh_tick = tick; TRACE(monitor).print("OnUpdate()\n"); UnpauseEvent(); + + TRACE(monitor).print(" -> evaluate dignow queue\n"); + for (const df::coord &pos: dignow_queue) { + if (!has_unit(Maps::getTileOccupancy(pos))) { + dig_now(out, pos); + } else { + // todo: teleport? + //Units::teleport() + } + } + TRACE(monitor).print("OnUpdate() exits\n"); } if (config.monitor_active && tick - last_monitor_tick >= config.monitor_freq) { last_monitor_tick = tick; @@ -299,16 +310,6 @@ namespace CSP { } } } - TRACE(monitor).print(" -> evaluate dignow queue\n"); - for (const df::coord &pos: dignow_queue) { - if (!has_unit(Maps::getTileOccupancy(pos))) { - dig_now(out, pos); - } else { - // todo: teleport? - //Units::teleport() - } - } - TRACE(monitor).print("OnUpdate() exits\n"); } } } diff --git a/plugins/channel-safely/include/inlines.h b/plugins/channel-safely/include/inlines.h index 72042327a..e8689d245 100644 --- a/plugins/channel-safely/include/inlines.h +++ b/plugins/channel-safely/include/inlines.h @@ -17,16 +17,39 @@ namespace CSP { extern std::unordered_set dignow_queue; } +inline void get_neighbours(const df::coord &map_pos, df::coord(&neighbours)[8]) { + neighbours[0] = map_pos; + neighbours[1] = map_pos; + neighbours[2] = map_pos; + neighbours[3] = map_pos; + neighbours[4] = map_pos; + neighbours[5] = map_pos; + neighbours[6] = map_pos; + neighbours[7] = map_pos; + neighbours[0].x--; neighbours[0].y--; + neighbours[1].y--; + neighbours[2].x++; neighbours[2].y--; + neighbours[3].x--; + neighbours[4].x++; + neighbours[5].x--; neighbours[5].y++; + neighbours[6].y++; + neighbours[7].x++; neighbours[7].y++; +} + inline bool is_dig_job(const df::job* job) { return job->job_type == df::job_type::Dig || job->job_type == df::job_type::DigChannel; } +inline bool is_channel_job(const df::job* job) { + return job->job_type == df::job_type::DigChannel; +} + inline bool is_dig_designation(const df::tile_designation &designation) { return designation.bits.dig != df::tile_dig_designation::No; } -inline bool has_unit(const df::tile_occupancy* occupancy) { - return occupancy->bits.unit || occupancy->bits.unit_grounded; +inline bool is_channel_designation(const df::tile_designation &designation) { + return designation.bits.dig != df::tile_dig_designation::Channel; } inline bool is_safe_fall(const df::coord &map_pos) { @@ -65,11 +88,22 @@ inline bool is_safe_to_dig_down(const df::coord &map_pos) { return false; } -inline bool is_group_occupied(const ChannelGroups &groups, const Group &group) { - // return true if any tile in the group is occupied by a unit - return std::any_of(group.begin(), group.end(), [](const Group::key_type &pos){ - return has_unit(Maps::getTileOccupancy(pos)); - }); +inline bool can_reach_designation(const df::coord &start, const df::coord &end) { + if (!Maps::canWalkBetween(start,end)) { + df::coord neighbours[8]; + get_neighbours(end, neighbours); + for (auto &pos : neighbours) { + if (Maps::canWalkBetween(start, pos)) { + return true; + } + } + return false; + } + return true; +} + +inline bool has_unit(const df::tile_occupancy* occupancy) { + return occupancy->bits.unit || occupancy->bits.unit_grounded; } inline bool has_group_above(const ChannelGroups &groups, const df::coord &map_pos) { @@ -128,22 +162,3 @@ inline void cancel_job(df::job* job) { Job::removeJob(job); } } - -inline void get_neighbours(const df::coord &map_pos, df::coord(&neighbours)[8]) { - neighbours[0] = map_pos; - neighbours[1] = map_pos; - neighbours[2] = map_pos; - neighbours[3] = map_pos; - neighbours[4] = map_pos; - neighbours[5] = map_pos; - neighbours[6] = map_pos; - neighbours[7] = map_pos; - neighbours[0].x--; neighbours[0].y--; - neighbours[1].y--; - neighbours[2].x++; neighbours[2].y--; - neighbours[3].x--; - neighbours[4].x++; - neighbours[5].x--; neighbours[5].y++; - neighbours[6].y++; - neighbours[7].x++; neighbours[7].y++; -} diff --git a/plugins/channel-safely/include/plugin.h b/plugins/channel-safely/include/plugin.h index 71e4665c7..d165d3f18 100644 --- a/plugins/channel-safely/include/plugin.h +++ b/plugins/channel-safely/include/plugin.h @@ -14,8 +14,8 @@ struct Configuration { bool require_vision = true; bool insta_dig = false; int32_t refresh_freq = 600; - int32_t monitor_freq = 10; - uint8_t ignore_threshold = 7; + int32_t monitor_freq = 1; + uint8_t ignore_threshold = 5; uint8_t fall_threshold = 1; };