Implements plugin: channel-safely v0.2

develop
Josh Cooper 2022-11-06 11:53:46 -08:00
parent 22414f26fa
commit bd6c748d00
5 changed files with 104 additions and 90 deletions

@ -5,67 +5,6 @@
#include <random> #include <random>
// 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<df::block_square_event_designation_priorityst>(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<df::block_square_event_designation_priorityst>(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 // 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) { void ChannelGroups::add(const df::coord &map_pos) {
// if we've already added this, we don't need to do it again // 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(); // 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<df::block_square_event_designation_priorityst>(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 // builds groupings of adjacent channel designations
void ChannelGroups::build() { void ChannelGroups::scan() {
clear();
// iterate over each job, finding channel jobs // iterate over each job, finding channel jobs
jobs.load_channel_jobs(); jobs.load_channel_jobs();
// transpose channel jobs to // transpose channel jobs to
for (auto &pos : jobs) { for (auto &pos : jobs) {
add(pos); 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<df::block_square_event_designation_priorityst>(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 // 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 // prints debug info about the groups stored, and their members
void ChannelGroups::debug_groups() { void ChannelGroups::debug_groups() {
// int idx = 0; int idx = 0;
// TRACE(groups).print(" debugging group data\n"); TRACE(groups).print(" debugging group data\n");
// for (auto &group : groups) { for (auto &group : groups) {
// TRACE(groups).print(" group %d (size: %zu)\n", idx, group.size()); TRACE(groups).print(" group %d (size: %zu)\n", idx, group.size());
// for (auto &pos : group) { for (auto &pos : group) {
// TRACE(groups).print(" (%d,%d,%d)\n", pos.x, pos.y, pos.z); TRACE(groups).print(" (%d,%d,%d)\n", pos.x, pos.y, pos.z);
// } }
// idx++; idx++;
// } }
} }
// prints debug info group mappings // prints debug info group mappings
void ChannelGroups::debug_map() { void ChannelGroups::debug_map() {
// INFO(groups).print("Group Mappings: %zu\n", groups_map.size()); INFO(groups).print("Group Mappings: %zu\n", groups_map.size());
// for (auto &pair : groups_map) { for (auto &pair : groups_map) {
// DEBUG(groups).print(" map[" COORD "] = %d\n",COORDARGS(pair.first), pair.second); DEBUG(groups).print(" map[" COORD "] = %d\n",COORDARGS(pair.first), pair.second);
// } }
} }

@ -10,8 +10,8 @@ blocks[48][96][135].designation[10][0].hidden: false
* */ * */
// sets mark flags as necessary, for all designations // sets mark flags as necessary, for all designations
void ChannelManager::manage_all() { void ChannelManager::manage_groups() {
INFO(manager).print("manage_all()\n"); INFO(manager).print("manage_groups()\n");
// make sure we've got a fort map to analyze // make sure we've got a fort map to analyze
if (World::isFortressMode() && Maps::IsValid()) { if (World::isFortressMode() && Maps::IsValid()) {
// iterate the groups we built/updated // 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) { void ChannelManager::mark_done(const df::coord &map_pos) {
groups.remove(map_pos); groups.remove(map_pos);
jobs.erase(map_pos); jobs.erase(map_pos); //redundant (repopulated on each build)
} }

@ -140,11 +140,9 @@ namespace CSP {
void UnpauseEvent(){ void UnpauseEvent(){
INFO(monitor).print("UnpauseEvent()\n"); INFO(monitor).print("UnpauseEvent()\n");
ChannelManager::Get().build_groups(); ChannelManager::Get().build_groups();
INFO(monitor).print("after building groups\n"); ChannelManager::Get().manage_groups();
ChannelManager::Get().debug(); ChannelManager::Get().debug();
ChannelManager::Get().manage_all();
INFO(monitor).print("UnpauseEvent() exits\n"); INFO(monitor).print("UnpauseEvent() exits\n");
ChannelManager::Get().debug();
} }
void JobStartedEvent(color_ostream &out, void* p) { 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 // manage all designations on unpause
CSP::UnpauseEvent(); CSP::UnpauseEvent();
default: 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) { DFhackCExport command_result plugin_onupdate(color_ostream &out, state_change_event event) {

@ -26,18 +26,19 @@ using Groups = std::vector<Group>;
*/ */
class ChannelGroups { class ChannelGroups {
private: private:
using GroupBlocks = std::set<df::map_block*>;
using GroupsMap = std::map<df::coord, int>; using GroupsMap = std::map<df::coord, int>;
GroupBlocks group_blocks;
GroupsMap groups_map; GroupsMap groups_map;
Groups groups; Groups groups;
ChannelJobs &jobs; ChannelJobs &jobs;
std::set<int> free_spots; std::set<int> free_spots;
protected: protected:
void scan_map();
void add(const df::coord &map_pos); void add(const df::coord &map_pos);
public: public:
explicit ChannelGroups(ChannelJobs &jobs) : jobs(jobs) { groups.reserve(200); } explicit ChannelGroups(ChannelJobs &jobs) : jobs(jobs) { groups.reserve(200); }
void scan_one(const df::coord &map_pos); void scan_one(const df::coord &map_pos);
void build(); void scan();
void clear(); void clear();
void remove(const df::coord &map_pos); void remove(const df::coord &map_pos);
Groups::const_iterator find(const df::coord &map_pos) const; Groups::const_iterator find(const df::coord &map_pos) const;

@ -23,17 +23,18 @@ public:
return instance; return instance;
} }
void build_groups() { groups.build(); debug(); } void build_groups() { groups.scan(); debug(); }
void manage_all(); 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 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); 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); 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 mark_done(const df::coord &map_pos);
void debug() { void debug() {
DEBUG(groups).print(" DEBUGGING GROUPS:\n");
if (config.debug) { if (config.debug) {
groups.debug_groups(); groups.debug_groups();
groups.debug_map(); groups.debug_map();
//std::terminate();
} }
} }
}; };