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>
// 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
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<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
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<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
@ -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);
}
}

@ -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)
}

@ -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) {

@ -26,18 +26,19 @@ using Groups = std::vector<Group>;
*/
class ChannelGroups {
private:
using GroupBlocks = std::set<df::map_block*>;
using GroupsMap = std::map<df::coord, int>;
GroupBlocks group_blocks;
GroupsMap groups_map;
Groups groups;
ChannelJobs &jobs;
std::set<int> 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;

@ -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();
}
}
};