diff --git a/plugins/channel-safely/channel-groups.cpp b/plugins/channel-safely/channel-groups.cpp index 7ee779df8..41928c556 100644 --- a/plugins/channel-safely/channel-groups.cpp +++ b/plugins/channel-safely/channel-groups.cpp @@ -5,67 +5,6 @@ #include -// scans the map for channel designations -void ChannelGroups::scan_map() { - static std::default_random_engine RNG(0); - static std::bernoulli_distribution optimizing(0.3333); - DEBUG(groups).print(" scan_map()\n"); - // foreach block - for (int32_t z = mapz - 1; z >= 0; --z) { - for (int32_t by = 0; by < mapy; ++by) { - for (int32_t bx = 0; bx < mapx; ++bx) { - // the block - if (df::map_block* block = Maps::getBlock(bx, by, z)) { - // skip this block? - if (!block->flags.bits.designated && optimizing(RNG)) { - // todo: add remainder of block width onto bx - TRACE(groups).print(" skipping this block, it has no designations\n"); - continue; - } - // foreach tile - for (int16_t lx = 0; lx < 16; ++lx) { - for (int16_t ly = 0; ly < 16; ++ly) { - // the tile, check if it has a channel designation - 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 - TRACE(groups).print(" tile designation priority: %d\n", evT->priority[lx][ly]); - if (evT->priority[lx][ly] < 1000 * config.ignore_threshold) { - df::coord map_pos((bx * 16) + lx, (by * 16) + ly, z); - TRACE(groups).print(" adding (" COORD ")\n", COORDARGS(map_pos)); - add(map_pos); - } - } - } - } - } - } - } - } - } - } - INFO(groups).print("scan_map() exits\n"); -} - -// scans a single tile for channel designations -void ChannelGroups::scan_one(const df::coord &map_pos) { - df::map_block* block = Maps::getTileBlock(map_pos); - int16_t lx = map_pos.x % 16; - int16_t ly = map_pos.y % 16; - 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 - if (evT->priority[lx][ly] < 1000 * config.ignore_threshold) { - TRACE(groups).print(" adding (" COORD ")\n", COORDARGS(map_pos)); - add(map_pos); - } - } - } - } -} - // 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 @@ -150,16 +89,79 @@ void ChannelGroups::add(const df::coord &map_pos) { // DEBUG(groups).flush(); } +// scans a single tile for channel designations +void ChannelGroups::scan_one(const df::coord &map_pos) { + df::map_block* block = Maps::getTileBlock(map_pos); + int16_t lx = map_pos.x % 16; + int16_t ly = map_pos.y % 16; + 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 + if (evT->priority[lx][ly] < 1000 * config.ignore_threshold) { + TRACE(groups).print(" adding (" COORD ")\n", COORDARGS(map_pos)); + add(map_pos); + } + } + } + } else if (isOpenTerrain(block->tiletype[lx][ly])) { + remove(map_pos); + } +} + // builds groupings of adjacent channel designations -void ChannelGroups::build() { - clear(); +void ChannelGroups::scan() { // iterate over each job, finding channel jobs jobs.load_channel_jobs(); // transpose channel jobs to for (auto &pos : jobs) { add(pos); } - scan_map(); + DEBUG(groups).print(" scan()\n"); + // foreach block + for (int32_t z = mapz - 1; z >= 0; --z) { + for (int32_t by = 0; by < mapy; ++by) { + for (int32_t bx = 0; bx < mapx; ++bx) { + // the block + if (df::map_block* block = Maps::getBlock(bx, by, z)) { + // skip this block? + if (!block->flags.bits.designated && !group_blocks.count(block)) { + continue; + } + // foreach tile + bool empty_group = true; + for (int16_t lx = 0; lx < 16; ++lx) { + 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])) { + 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 + TRACE(groups).print(" tile designation priority: %d\n", evT->priority[lx][ly]); + if (evT->priority[lx][ly] < 1000 * config.ignore_threshold) { + if (empty_group) { + group_blocks.emplace(block); + } + 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); + } + } + } + if (empty_group) { + group_blocks.erase(block); + } + } + } + } + } + INFO(groups).print("scan() exits\n"); } // clears out the containers for unloading maps or disabling the plugin @@ -231,23 +233,23 @@ size_t ChannelGroups::count(const df::coord &map_pos) const { // prints debug info about the groups stored, and their members void ChannelGroups::debug_groups() { -// int idx = 0; -// TRACE(groups).print(" debugging group data\n"); -// for (auto &group : groups) { -// TRACE(groups).print(" group %d (size: %zu)\n", idx, group.size()); -// for (auto &pos : group) { -// TRACE(groups).print(" (%d,%d,%d)\n", pos.x, pos.y, pos.z); -// } -// idx++; -// } + int idx = 0; + TRACE(groups).print(" debugging group data\n"); + for (auto &group : groups) { + TRACE(groups).print(" group %d (size: %zu)\n", idx, group.size()); + for (auto &pos : group) { + TRACE(groups).print(" (%d,%d,%d)\n", pos.x, pos.y, pos.z); + } + idx++; + } } // prints debug info group mappings void ChannelGroups::debug_map() { -// INFO(groups).print("Group Mappings: %zu\n", groups_map.size()); -// for (auto &pair : groups_map) { -// DEBUG(groups).print(" map[" COORD "] = %d\n",COORDARGS(pair.first), pair.second); -// } + INFO(groups).print("Group Mappings: %zu\n", groups_map.size()); + for (auto &pair : groups_map) { + DEBUG(groups).print(" map[" COORD "] = %d\n",COORDARGS(pair.first), pair.second); + } } diff --git a/plugins/channel-safely/channel-manager.cpp b/plugins/channel-safely/channel-manager.cpp index 79bc6a7aa..28d757772 100644 --- a/plugins/channel-safely/channel-manager.cpp +++ b/plugins/channel-safely/channel-manager.cpp @@ -10,8 +10,8 @@ blocks[48][96][135].designation[10][0].hidden: false * */ // sets mark flags as necessary, for all designations -void ChannelManager::manage_all() { - INFO(manager).print("manage_all()\n"); +void ChannelManager::manage_groups() { + INFO(manager).print("manage_groups()\n"); // make sure we've got a fort map to analyze if (World::isFortressMode() && Maps::IsValid()) { // iterate the groups we built/updated @@ -95,5 +95,5 @@ 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); + 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 e6cdf231b..b473598ae 100644 --- a/plugins/channel-safely/channel-safely-plugin.cpp +++ b/plugins/channel-safely/channel-safely-plugin.cpp @@ -140,11 +140,9 @@ namespace CSP { void UnpauseEvent(){ INFO(monitor).print("UnpauseEvent()\n"); ChannelManager::Get().build_groups(); - INFO(monitor).print("after building groups\n"); + ChannelManager::Get().manage_groups(); ChannelManager::Get().debug(); - ChannelManager::Get().manage_all(); INFO(monitor).print("UnpauseEvent() exits\n"); - ChannelManager::Get().debug(); } void JobStartedEvent(color_ostream &out, void* p) { @@ -387,10 +385,22 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan // manage all designations on unpause CSP::UnpauseEvent(); default: - break; + return DFHack::CR_OK; } } - return CR_OK; + switch (event) { + case SC_WORLD_LOADED: + case SC_WORLD_UNLOADED: + case SC_MAP_UNLOADED: + // destroy any old group data + out.print("channel-safely: unloading data!\n"); + ChannelManager::Get().destroy_groups(); + case SC_MAP_LOADED: + // cache the map size + Maps::getSize(mapx, mapy, mapz); + default: + return DFHack::CR_OK; + } } DFhackCExport command_result plugin_onupdate(color_ostream &out, state_change_event event) { diff --git a/plugins/channel-safely/include/channel-groups.h b/plugins/channel-safely/include/channel-groups.h index d39780df3..abdbc56fc 100644 --- a/plugins/channel-safely/include/channel-groups.h +++ b/plugins/channel-safely/include/channel-groups.h @@ -26,18 +26,19 @@ using Groups = std::vector; */ class ChannelGroups { private: + using GroupBlocks = std::set; using GroupsMap = std::map; + GroupBlocks group_blocks; GroupsMap groups_map; Groups groups; ChannelJobs &jobs; std::set free_spots; protected: - void scan_map(); void add(const df::coord &map_pos); public: explicit ChannelGroups(ChannelJobs &jobs) : jobs(jobs) { groups.reserve(200); } void scan_one(const df::coord &map_pos); - void build(); + void scan(); void clear(); void remove(const df::coord &map_pos); Groups::const_iterator find(const df::coord &map_pos) const; diff --git a/plugins/channel-safely/include/channel-manager.h b/plugins/channel-safely/include/channel-manager.h index 2e33c5c46..79c1e3770 100644 --- a/plugins/channel-safely/include/channel-manager.h +++ b/plugins/channel-safely/include/channel-manager.h @@ -23,17 +23,18 @@ public: return instance; } - void build_groups() { groups.build(); debug(); } - void manage_all(); + void build_groups() { groups.scan(); debug(); } + void destroy_groups() { groups.clear(); debug(); } + void manage_groups(); void manage_group(const df::coord &map_pos, bool set_marker_mode = false, bool marker_mode = false); void manage_group(const Group &group, bool set_marker_mode = false, bool marker_mode = false); bool manage_one(const Group &group, const df::coord &map_pos, bool set_marker_mode = false, bool marker_mode = false); void mark_done(const df::coord &map_pos); void debug() { + DEBUG(groups).print(" DEBUGGING GROUPS:\n"); if (config.debug) { groups.debug_groups(); groups.debug_map(); - //std::terminate(); } } };