Skip to content

Commit 457d660

Browse files
committed
Simplifies channel-safely-plugin.cpp
1 parent f7109e9 commit 457d660

File tree

1 file changed

+22
-275
lines changed

1 file changed

+22
-275
lines changed

plugins/channel-safely/channel-safely-plugin.cpp

Lines changed: 22 additions & 275 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ This skeletal logic has not been kept up-to-date since ~v0.5
5656
#include "plugin.h"
5757
#include "inlines.h"
5858
#include "channel-manager.h"
59+
#include "active-job-manager.h"
5960
#include "tile-cache.h"
6061

6162
#include <Debug.h>
@@ -68,7 +69,9 @@ This skeletal logic has not been kept up-to-date since ~v0.5
6869
#include <df/report.h>
6970
#include <df/tile_traffic.h>
7071
#include <df/world.h>
72+
#include <df/unit.h>
7173

74+
#include <ranges>
7275
#include <cinttypes>
7376
#include <unordered_map>
7477
#include <unordered_set>
@@ -114,44 +117,9 @@ enum SettingConfigData {
114117
};
115118

116119
// dig-now.cpp
117-
df::coord simulate_fall(const df::coord &pos) {
118-
if unlikely(!Maps::isValidTilePos(pos)) {
119-
ERR(plugin).print("Error: simulate_fall(" COORD ") - invalid coordinate\n", COORDARGS(pos));
120-
return {};
121-
}
122-
df::coord resting_pos(pos);
123-
124-
while (Maps::ensureTileBlock(resting_pos)) {
125-
df::tiletype tt = *Maps::getTileType(resting_pos);
126-
if (isWalkable(tt))
127-
break;
128-
--resting_pos.z;
129-
}
130-
131-
return resting_pos;
132-
}
133-
134-
df::coord simulate_area_fall(const df::coord &pos) {
135-
df::coord neighbours[8]{};
136-
get_neighbours(pos, neighbours);
137-
df::coord lowest = simulate_fall(pos);
138-
for (auto p : neighbours) {
139-
if unlikely(!Maps::isValidTilePos(p)) continue;
140-
auto nlow = simulate_fall(p);
141-
if (nlow.z < lowest.z) {
142-
lowest = nlow;
143-
}
144-
}
145-
return lowest;
146-
}
147120

148121
namespace CSP {
149-
std::unordered_map<df::unit*, int32_t> endangered_units;
150-
std::unordered_map<df::job*, int32_t> job_id_map;
151-
std::unordered_map<int32_t, df::job*> active_jobs;
152-
std::unordered_map<int32_t, df::unit*> active_workers;
153-
154-
std::unordered_map<int32_t, df::coord> last_safe;
122+
ActiveJobManager active_job_manager;
155123
std::unordered_set<df::coord> dignow_queue;
156124

157125
static int32_t last_tick = 0;
@@ -162,11 +130,7 @@ namespace CSP {
162130
void ClearData() {
163131
ChannelManager::Get().destroy_groups();
164132
dignow_queue.clear();
165-
last_safe.clear();
166-
endangered_units.clear();
167-
active_workers.clear();
168-
active_jobs.clear();
169-
job_id_map.clear();
133+
active_job_manager.clear();
170134
}
171135

172136
void SaveSettings() {
@@ -214,7 +178,6 @@ namespace CSP {
214178
ERR(plugin).print("%s\n", e.what());
215179
}
216180
}
217-
active_workers.clear();
218181
}
219182

220183
void UnpauseEvent(bool full_scan = false){
@@ -225,85 +188,23 @@ namespace CSP {
225188
}
226189

227190
void JobStartedEvent(color_ostream &out, void* j) {
228-
if (enabled && World::isFortressMode() && Maps::IsValid()) {
229-
TRACE(jobs).print("JobStartedEvent()\n");
230-
auto job = (df::job*) j;
231-
// validate job type
232-
if (ChannelManager::Get().exists(job->pos)) {
233-
DEBUG(jobs).print(" valid channel job:\n");
234-
df::unit* worker = Job::getWorker(job);
235-
// there is a valid worker (living citizen) on the job? right..
236-
if (worker && Units::isAlive(worker) && Units::isCitizen(worker)) {
237-
ChannelManager::Get().jobs.mark_active(job->pos);
238-
if (config.riskaverse) {
239-
if (ChannelManager::Get().jobs.possible_cavein(job->pos)) {
240-
cancel_job(job);
241-
ChannelManager::Get().manage_one(job->pos, true, true);
242-
} else {
243-
ChannelManager::Get().manage_group(job->pos, true, false);
244-
}
245-
}
246-
DEBUG(jobs).print(" valid worker:\n");
247-
// track workers on jobs
248-
df::coord &pos = job->pos;
249-
TRACE(jobs).print(" -> Starting job at (" COORD ")\n", COORDARGS(pos));
250-
if (config.monitoring || config.resurrect) {
251-
job_id_map.emplace(job, job->id);
252-
active_jobs.emplace(job->id, job);
253-
active_workers[job->id] = worker;
254-
if (config.resurrect) {
255-
// this is the only place we can be 100% sure of "safety"
256-
// (excluding deadly enemies that will have arrived)
257-
last_safe[worker->id] = worker->pos;
258-
}
259-
}
260-
// set tile to restricted
261-
TRACE(jobs).print(" setting job tile to restricted\n");
262-
Maps::getTileDesignation(job->pos)->bits.traffic = df::tile_traffic::Restricted;
263-
}
264-
}
265-
TRACE(jobs).print(" <- JobStartedEvent() exits normally\n");
191+
if (!enabled || World::isFortressMode() || Maps::IsValid()) {
192+
return;
193+
}
194+
auto job = static_cast<df::job*>(j);
195+
if likely(is_channel_job(job)) {
196+
active_job_manager.on_job_start(job);
266197
}
267198
}
268199

269200
void JobCompletedEvent(color_ostream &out, void* j) {
270-
if (enabled && World::isFortressMode() && Maps::IsValid()) {
271-
TRACE(jobs).print("JobCompletedEvent()\n");
272-
auto job = (df::job*) j;
273-
// we only care if the job is a channeling one
274-
if (ChannelManager::Get().exists(job->pos)) {
275-
ChannelManager::Get().manage_group(job->pos, true, false);
276-
// check job outcome
277-
auto block = Maps::getTileBlock(job->pos);
278-
df::coord local(job->pos);
279-
local.x = local.x % 16;
280-
local.y = local.y % 16;
281-
// verify completion
282-
if (TileCache::Get().hasChanged(job->pos, block->tiletype[Coord(local)])) {
283-
// the job can be considered done
284-
df::coord below(job->pos);
285-
below.z--;
286-
DEBUG(jobs).print(" -> (" COORD ") is marked done, managing group below.\n", COORDARGS(job->pos));
287-
// mark done and manage below (and the rest of the group, if there were cavein candidates)
288-
block->designation[Coord(local)].bits.traffic = df::tile_traffic::Normal;
289-
ChannelManager::Get().mark_done(job->pos);
290-
ChannelManager::Get().manage_group(below);
291-
if (config.resurrect) {
292-
// this is the only place we can be 100% sure of "safety"
293-
// (excluding deadly enemies that may have arrived, and future digging)
294-
if (active_workers.count(job->id)) {
295-
df::unit* worker = active_workers[job->id];
296-
last_safe[worker->id] = worker->pos;
297-
}
298-
}
299-
}
300-
// clean up
301-
auto jp = active_jobs[job->id];
302-
job_id_map.erase(jp);
303-
active_workers.erase(job->id);
304-
active_jobs.erase(job->id);
305-
}
306-
TRACE(jobs).print("JobCompletedEvent() exits\n");
201+
if (!enabled || World::isFortressMode() || Maps::IsValid()) {
202+
return;
203+
}
204+
auto job = static_cast<df::job*>(j);
205+
// we only care if the job is a channeling one
206+
if likely(is_channel_job(job)) {
207+
active_job_manager.on_job_completed(out, job);
307208
}
308209
}
309210

@@ -315,59 +216,15 @@ namespace CSP {
315216
WARN(plugin).print("Error: NewReportEvent() received an invalid report_id - a report* cannot be found\n");
316217
return;
317218
}
318-
switch (report->type) {
319-
case announcement_type::CANCEL_JOB:
320-
if (config.insta_dig) {
321-
if (report->text.find("cancels Dig") != std::string::npos ||
322-
report->text.find("path") != std::string::npos) {
323-
324-
dignow_queue.emplace(report->pos);
325-
}
326-
DEBUG(plugin).print("%d, pos: " COORD ", pos2: " COORD "\n%s\n", report_id, COORDARGS(report->pos),
327-
COORDARGS(report->pos2), report->text.c_str());
328-
}
329-
break;
330-
case announcement_type::CAVE_COLLAPSE:
331-
if (config.resurrect) {
332-
DEBUG(plugin).print("CAVE IN\n%d, pos: " COORD ", pos2: " COORD "\n%s\n", report_id, COORDARGS(report->pos),
333-
COORDARGS(report->pos2), report->text.c_str());
334-
335-
df::coord below = report->pos;
336-
below.z -= 1;
337-
below = simulate_area_fall(below);
338-
df::coord areaMin{report->pos};
339-
df::coord areaMax{areaMin};
340-
areaMin.x -= 15;
341-
areaMin.y -= 15;
342-
areaMax.x += 15;
343-
areaMax.y += 15;
344-
areaMin.z = below.z;
345-
areaMax.z += 1;
346-
std::vector<df::unit*> units;
347-
Units::getUnitsInBox(units, COORDARGS(areaMin), COORDARGS(areaMax));
348-
for (auto unit: units) {
349-
endangered_units[unit] = tick;
350-
DEBUG(plugin).print(" [id %d] was near a cave in.\n", unit->id);
351-
}
352-
for (auto unit : world->units.all) {
353-
if (last_safe.count(unit->id)) {
354-
endangered_units[unit] = tick;
355-
DEBUG(plugin).print(" [id %d] is/was a worker, we'll track them too.\n", unit->id);
356-
}
357-
}
358-
}
359-
break;
360-
default:
361-
break;
362-
}
219+
active_job_manager.on_report_event(report);
363220
}
364221

365222
void OnUpdate(color_ostream &out) {
366223
if (World::ReadPauseState())
367224
return;
368225

226+
active_job_manager.on_update(out);
369227
int32_t tick = world->frame_counter;
370-
371228
// Refreshing the group data with full scanning
372229
if (tick - last_refresh_tick >= config.refresh_freq) {
373230
last_refresh_tick = tick;
@@ -384,116 +241,6 @@ namespace CSP {
384241
UnpauseEvent(false);
385242
TRACE(monitor).print("OnUpdate() refresh done\n");
386243
}
387-
388-
// Clean up stale df::job*
389-
if ((config.monitoring || config.resurrect) && tick - last_tick >= 1) {
390-
last_tick = tick;
391-
// make note of valid jobs
392-
std::unordered_map<int32_t, df::job*> valid_jobs;
393-
for (df::job_list_link* link = &world->jobs.list; link != nullptr; link = link->next) {
394-
df::job* job = link->item;
395-
if (job && active_jobs.count(job->id)) {
396-
valid_jobs.emplace(job->id, job);
397-
}
398-
}
399-
400-
// erase the active jobs that aren't valid
401-
std::unordered_set<df::job*> erase;
402-
map_value_difference(active_jobs, valid_jobs, erase);
403-
for (auto j : erase) {
404-
auto id = job_id_map[j];
405-
job_id_map.erase(j);
406-
active_jobs.erase(id);
407-
active_workers.erase(id);
408-
}
409-
}
410-
411-
// Monitoring Active and Resurrecting Dead
412-
if (config.monitoring && tick - last_monitor_tick >= config.monitor_freq) {
413-
last_monitor_tick = tick;
414-
TRACE(monitor).print("OnUpdate() monitoring now\n");
415-
416-
// iterate active jobs
417-
for (auto pair: active_jobs) {
418-
df::job* job = pair.second;
419-
df::unit* unit = active_workers[job->id];
420-
if (!unit) continue;
421-
if (!Maps::isValidTilePos(job->pos)) continue;
422-
TRACE(monitor).print(" -> check for job in tracking\n");
423-
if (Units::isAlive(unit)) {
424-
if (!config.monitoring) continue;
425-
TRACE(monitor).print(" -> compare positions of worker and job\n");
426-
427-
// check for fall safety
428-
if (unit->pos == job->pos && !is_safe_fall(job->pos)) {
429-
// unsafe
430-
WARN(monitor).print(" -> unsafe job\n");
431-
Job::removeWorker(job);
432-
433-
// decide to insta-dig or marker mode
434-
if (config.insta_dig) {
435-
// delete the job
436-
Job::removeJob(job);
437-
// queue digging the job instantly
438-
dignow_queue.emplace(job->pos);
439-
DEBUG(monitor).print(" -> insta-dig\n");
440-
} else if (config.resurrect) {
441-
endangered_units.emplace(unit, tick);
442-
} else {
443-
// set marker mode
444-
Maps::getTileOccupancy(job->pos)->bits.dig_marked = true;
445-
446-
// prevent algorithm from re-enabling designation
447-
for (auto &be: Maps::getBlock(job->pos)->block_events) {
448-
if (auto bsedp = virtual_cast<df::block_square_event_designation_priorityst>(
449-
be)) {
450-
df::coord local(job->pos);
451-
local.x = local.x % 16;
452-
local.y = local.y % 16;
453-
bsedp->priority[Coord(local)] = config.ignore_threshold * 1000 + 1;
454-
break;
455-
}
456-
}
457-
DEBUG(monitor).print(" -> set marker mode\n");
458-
}
459-
}
460-
} else if (config.resurrect) {
461-
resurrect(out, unit->id);
462-
if (last_safe.count(unit->id)) {
463-
df::coord lowest = simulate_fall(last_safe[unit->id]);
464-
Units::teleport(unit, lowest);
465-
}
466-
}
467-
}
468-
TRACE(monitor).print("OnUpdate() monitoring done\n");
469-
}
470-
471-
// Resurrect Dead Workers
472-
if (config.resurrect && tick - last_resurrect_tick >= 1) {
473-
last_resurrect_tick = tick;
474-
475-
// clean up any "endangered" workers that have been tracked 100 ticks or more
476-
for (auto iter = endangered_units.begin(); iter != endangered_units.end();) {
477-
if (tick - iter->second >= 1200) { //keep watch 1 day
478-
DEBUG(plugin).print("It has been one day since [id %d]'s last incident.\n", iter->first->id);
479-
iter = endangered_units.erase(iter);
480-
continue;
481-
}
482-
++iter;
483-
}
484-
485-
// resurrect any dead units
486-
for (auto pair : endangered_units) {
487-
auto unit = pair.first;
488-
if (!Units::isAlive(unit)) {
489-
resurrect(out, unit->id);
490-
if (last_safe.count(unit->id)) {
491-
df::coord lowest = simulate_fall(last_safe[unit->id]);
492-
Units::teleport(unit, lowest);
493-
}
494-
}
495-
}
496-
}
497244
}
498245
}
499246

@@ -616,7 +363,7 @@ command_result channel_safely(color_ostream &out, std::vector<std::string> &para
616363
// if this is a fresh start
617364
if (state && !config.resurrect) {
618365
// we need a fresh start
619-
CSP::active_workers.clear();
366+
CSP::ClearData();
620367
}
621368
}
622369
} else if (parameters[1] == "risk-averse") {
@@ -632,7 +379,7 @@ command_result channel_safely(color_ostream &out, std::vector<std::string> &para
632379
// if this is a fresh start
633380
if (state && !config.monitoring) {
634381
// we need a fresh start
635-
CSP::active_workers.clear();
382+
CSP::ClearData();
636383
}
637384
}
638385
} else if (parameters[1] == "refresh-freq" && set && parameters.size() == 3) {

0 commit comments

Comments
 (0)