From e5dbaac85d83bad166948fb0446cf59a6e6a7a20 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Sun, 6 Nov 2022 15:59:30 -0800 Subject: [PATCH] Implements plugin: channel-safely v0.5 --- plugins/channel-safely/channel-groups.cpp | 29 ++++++++------- plugins/channel-safely/channel-manager.cpp | 14 ++++++-- .../channel-safely/channel-safely-plugin.cpp | 30 +++++++++------- plugins/channel-safely/include/channel-jobs.h | 1 + plugins/channel-safely/include/inlines.h | 4 +++ plugins/channel-safely/include/tile-cache.h | 35 +++++++++++++++++++ 6 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 plugins/channel-safely/include/tile-cache.h diff --git a/plugins/channel-safely/channel-groups.cpp b/plugins/channel-safely/channel-groups.cpp index 7e5cccf20..48f4a9ee5 100644 --- a/plugins/channel-safely/channel-groups.cpp +++ b/plugins/channel-safely/channel-groups.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -91,18 +92,12 @@ void ChannelGroups::add(const df::coord &map_pos) { // puts the "add" in "ChannelGroups::add" group->emplace(map_pos); DEBUG(groups).print(" = group[%d] of (" COORD ") is size: %zu\n", group_index, COORDARGS(map_pos), group->size()); -// ERR(groups).print("\n\n\nDEBUG MAPPINGS:\n"); -// debug_map(); -// DEBUG(groups).flush(); // we may have performed a merge, so we update all the `coord -> group index` mappings for (auto &wpos: *group) { groups_map[wpos] = group_index; } DEBUG(groups).print(" <- add() exits, there are %zu mappings\n", groups_map.size()); -// ERR(groups).print("\n\n\nDEBUG MAPPINGS:\n"); -// debug_map(); -// DEBUG(groups).flush(); } // scans a single tile for channel designations @@ -120,7 +115,8 @@ void ChannelGroups::scan_one(const df::coord &map_pos) { } } } - } else if (isOpenTerrain(block->tiletype[lx][ly])) { + } else if (TileCache::Get().hasChanged(map_pos, block->tiletype[lx][ly])) { + TileCache::Get().uncache(map_pos); remove(map_pos); } } @@ -145,6 +141,9 @@ void ChannelGroups::scan() { remove(pos); } + static std::default_random_engine RNG(0); + static std::bernoulli_distribution optimizing(0.75); // fixing OpenSpace as designated + DEBUG(groups).print(" scan()\n"); // foreach block for (int32_t z = mapz - 1; z >= 0; --z) { @@ -153,7 +152,7 @@ void ChannelGroups::scan() { // the block if (df::map_block* block = Maps::getBlock(bx, by, z)) { // skip this block? - if (!block->flags.bits.designated && !group_blocks.count(block)) { + if (!block->flags.bits.designated && !group_blocks.count(block) && optimizing(RNG)) { continue; } // foreach tile @@ -162,7 +161,13 @@ void ChannelGroups::scan() { for (int16_t ly = 0; ly < 16; ++ly) { // the tile, check if it has a channel designation df::coord map_pos((bx * 16) + lx, (by * 16) + ly, z); - if (is_dig_designation(block->designation[lx][ly])) { + if (TileCache::Get().hasChanged(map_pos, block->tiletype[lx][ly])) { + remove(map_pos); + if (jobs.count(map_pos)) { + jobs.erase(map_pos); + } + block->designation[lx][ly].bits.dig = df::tile_dig_designation::No; + } else if (is_dig_designation(block->designation[lx][ly])) { for (df::block_square_event* event: block->block_events) { if (auto evT = virtual_cast(event)) { // we want to let the user keep some designations free of being managed @@ -170,18 +175,17 @@ void ChannelGroups::scan() { if (evT->priority[lx][ly] < 1000 * config.ignore_threshold) { if (empty_group) { group_blocks.emplace(block); + empty_group = false; } TRACE(groups).print(" adding (" COORD ")\n", COORDARGS(map_pos)); add(map_pos); - empty_group = false; } } } - } else if (isOpenTerrain(block->tiletype[lx][ly])) { - remove(map_pos); } } } + // erase the block if we didn't find anything iterating through it if (empty_group) { group_blocks.erase(block); } @@ -196,6 +200,7 @@ void ChannelGroups::scan() { void ChannelGroups::clear() { debug_map(); WARN(groups).print(" <- clearing groups\n"); + group_blocks.clear(); free_spots.clear(); groups_map.clear(); for(size_t i = 0; i < groups.size(); ++i) { diff --git a/plugins/channel-safely/channel-manager.cpp b/plugins/channel-safely/channel-manager.cpp index 86ce5a726..7d923e9b2 100644 --- a/plugins/channel-safely/channel-manager.cpp +++ b/plugins/channel-safely/channel-manager.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -69,8 +70,11 @@ bool ChannelManager::manage_one(const Group &group, const df::coord &map_pos, bo } // 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; + if (!block->flags.bits.designated) { + block->flags.bits.designated = true; + } + tile_occupancy.bits.dig_marked = false; + TileCache::Get().cache(map_pos, block->tiletype[Coord(local)]); } return false; @@ -85,7 +89,9 @@ bool ChannelManager::manage_one(const Group &group, const df::coord &map_pos, bo 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); + if (jobs.count(map_pos)) { + jobs.erase(map_pos); + } WARN(manager).print(" <- manage_one() exits normally\n"); return true; } @@ -104,4 +110,6 @@ 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); + TileCache::Get().uncache(map_pos); } diff --git a/plugins/channel-safely/channel-safely-plugin.cpp b/plugins/channel-safely/channel-safely-plugin.cpp index a63228e27..8c22ede44 100644 --- a/plugins/channel-safely/channel-safely-plugin.cpp +++ b/plugins/channel-safely/channel-safely-plugin.cpp @@ -53,6 +53,7 @@ Updated: Nov. 6 2022 #include #include #include +#include #include #include @@ -211,23 +212,23 @@ namespace CSP { INFO(monitor).print("JobCompletedEvent()\n"); auto job = (df::job*) job_ptr; // we only care if the job is a channeling one - if (is_dig_job(job)) { + if (ChannelManager::Get().groups.count(job->pos)) { // untrack job/worker active_workers.erase(job->id); // check job outcome + auto block = Maps::getTileBlock(job->pos); df::coord local(job->pos); - auto block = Maps::getTileBlock(local); local.x = local.x % 16; local.y = local.y % 16; + const auto &type = block->tiletype[Coord(local)]; // verify completion - if (isOpenTerrain(block->tiletype[local.x][local.y]) - || block->designation[local.x][local.y].bits.dig != df::enums::tile_dig_designation::Channel) { + if (TileCache::Get().hasChanged(job->pos, type)) { // the job can be considered done df::coord below(job->pos); below.z--; WARN(monitor).print(" -> Marking tile done and managing the group below.\n"); // mark done and manage below - Maps::getTileDesignation(job->pos)->bits.traffic = df::tile_traffic::Normal; + block->designation[Coord(local)].bits.traffic = df::tile_traffic::Normal; ChannelManager::Get().mark_done(job->pos); ChannelManager::Get().manage_group(below); ChannelManager::Get().debug(); @@ -247,16 +248,18 @@ namespace CSP { 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() + if (config.insta_dig) { + TRACE(monitor).print(" -> evaluate dignow queue\n"); + for (const df::coord &pos: dignow_queue) { + if (!has_unit(Maps::getTileOccupancy(pos))) { + out.print("channel-safely: insta-dig: Digging now!\n"); + 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; @@ -311,6 +314,7 @@ namespace CSP { } } } + TRACE(monitor).print("OnUpdate() exits\n"); } } } diff --git a/plugins/channel-safely/include/channel-jobs.h b/plugins/channel-safely/include/channel-jobs.h index d0aaead7c..0290baa19 100644 --- a/plugins/channel-safely/include/channel-jobs.h +++ b/plugins/channel-safely/include/channel-jobs.h @@ -22,6 +22,7 @@ private: public: void load_channel_jobs(); void clear(); + int count(const df::coord &map_pos) const { return jobs.count(map_pos); } Jobs::iterator erase(const df::coord &map_pos); Jobs::const_iterator find(const df::coord &map_pos) const; Jobs::const_iterator begin() const; diff --git a/plugins/channel-safely/include/inlines.h b/plugins/channel-safely/include/inlines.h index e8689d245..dca17460e 100644 --- a/plugins/channel-safely/include/inlines.h +++ b/plugins/channel-safely/include/inlines.h @@ -44,6 +44,10 @@ inline bool is_channel_job(const df::job* job) { return job->job_type == df::job_type::DigChannel; } +inline bool is_group_job(const ChannelGroups &groups, const df::job* job) { + return groups.count(job->pos); +} + inline bool is_dig_designation(const df::tile_designation &designation) { return designation.bits.dig != df::tile_dig_designation::No; } diff --git a/plugins/channel-safely/include/tile-cache.h b/plugins/channel-safely/include/tile-cache.h new file mode 100644 index 000000000..ddd37c34a --- /dev/null +++ b/plugins/channel-safely/include/tile-cache.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +#include + +class TileCache { +private: + TileCache() = default; + std::map locations; +public: + static TileCache& Get() { + static TileCache instance; + return instance; + } + + void cache(const df::coord &pos, df::tiletype type) { + locations.emplace(pos, type); + } + + void uncache(const df::coord &pos) { + locations.erase(pos); + } + + bool hasChanged(const df::coord &pos, const df::tiletype &type) { + if (locations.count(pos)) { + if (type != locations.find(pos)->second){ + return true; + } + } + return false; + } +};