diff --git a/plugins/spectate/pause.cpp b/plugins/spectate/pause.cpp index 0c8462580..fadf8d5e9 100644 --- a/plugins/spectate/pause.cpp +++ b/plugins/spectate/pause.cpp @@ -71,11 +71,13 @@ inline bool only_or_none_locked(Locks locks, LockT* this_lock) { template inline bool reportLockedLocks(color_ostream &out, Locks locks) { + out.color(DFHack::COLOR_YELLOW); for (auto &L: locks) { if (L->isLocked()) { - out.print("Lock '%s' is locked\n", L->name.c_str()); + out.print("Lock: '%s'\n", L->name.c_str()); } } + out.reset_color(); return true; } @@ -118,7 +120,7 @@ void PlayerLock::reportLocks(color_ostream &out) { reportLockedLocks(out, locks); } -bool World::DisableAnnouncementPausing(color_ostream &out) { +bool World::DisableAnnouncementPausing() { if (!announcementLock.isAnyLocked()) { for (auto& flag : df::global::d_init->announcements.flags) { flag.bits.PAUSE = false; diff --git a/plugins/spectate/pause.h b/plugins/spectate/pause.h index 90e884b90..ff4f8992d 100644 --- a/plugins/spectate/pause.h +++ b/plugins/spectate/pause.h @@ -51,9 +51,9 @@ namespace DFHack { }; } namespace World { - bool DisableAnnouncementPausing(color_ostream &out); // disable announcement pausing if all locks are open + bool DisableAnnouncementPausing(); // disable announcement pausing if all locks are open bool SaveAnnouncementSettings(); // save current announcement pause settings if all locks are open - bool RestoreAnnouncementSettings(); // restore saved announcement pause settings if all locks are open + bool RestoreAnnouncementSettings(); // restore saved announcement pause settings if all locks are open and there is state information to restore (returns true if a restore took place) bool EnablePlayerPausing(); // enable player pausing if all locks are open bool DisablePlayerPausing(); // disable player pausing if all locks are open diff --git a/plugins/spectate/spectate.cpp b/plugins/spectate/spectate.cpp index 96500820a..ae577c1b2 100644 --- a/plugins/spectate/spectate.cpp +++ b/plugins/spectate/spectate.cpp @@ -46,6 +46,7 @@ bool disengage_enabled = false; bool unpause_enabled = false; Pausing::AnnouncementLock* pause_lock = nullptr; bool lock_collision = false; +bool announcements_disabled = false; bool following_dwarf = false; df::unit* our_dorf = nullptr; @@ -79,6 +80,18 @@ inline void saveConfig() { } } +//struct player_pause_hook : df::viewscreen_dwarfmodest { +// typedef df::viewscreen_dwarfmodest interpose_base; +// DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set* input)) { +// if ((ui->main.mode == ui_sidebar_mode::Default) && !allow_player_pause) { +// input->erase(interface_key::D_PAUSE); +// } +// INTERPOSE_NEXT(feed)(input); +// } +//}; +// +//IMPLEMENT_VMETHOD_INTERPOSE(player_pause_hook, feed); + command_result spectate (color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { @@ -106,6 +119,8 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { disengage_enabled = config.ival(DISENGAGE); focus_jobs_enabled = config.ival(JOB_FOCUS); tick_threshold = config.ival(TICK_THRESHOLD); + pause_lock->unlock(); + enable_auto_unpause(out, unpause_enabled); } return DFHack::CR_OK; } @@ -121,11 +136,17 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { EM::registerListener(EventType::TICK, ticking, plugin_self); EM::registerListener(EventType::JOB_STARTED, start, plugin_self); EM::registerListener(EventType::JOB_COMPLETED, complete, plugin_self); + out.print("running: spectate auto-unpause %d\n", unpause_enabled); + enabled = true; // enable_auto_unpause won't do anything without this set now enable_auto_unpause(out, unpause_enabled); } else if (!enable && enabled) { // warp 8, engage! out.print("Spectate mode disabled!\n"); EM::unregisterAll(plugin_self); + // we need to retain whether auto-unpause is enabled, but we also need to disable its effect + bool temp = unpause_enabled; + enable_auto_unpause(out, false); + unpause_enabled = temp; job_tracker.clear(); freq.clear(); } @@ -134,7 +155,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { } DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { - if (enabled && world) { + if (enabled) { switch (event) { case SC_MAP_UNLOADED: case SC_BEGIN_UNLOAD: @@ -142,12 +163,6 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan our_dorf = nullptr; job_watched = nullptr; following_dwarf = false; - //pause_lock->unlock(); - break; - case SC_MAP_LOADED: - // todo: RE UNDEAD_ATTACK event still pausing regardless of announcement settings - //enable_auto_unpause(out, unpause_enabled); - break; default: break; } @@ -157,24 +172,27 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan DFhackCExport command_result plugin_onupdate(color_ostream &out) { // keeps announcement pause settings locked -// World::Update(); // from pause.h -// if (lock_collision) { -// if (unpause_enabled) { -// // player asked for auto-unpause enabled -// World::SaveAnnouncementSettings(); -// if (World::DisableAnnouncementPausing(out)) { -// // now that we've got what we want, we can lock it down -// lock_collision = false; -// } -// } else { -// if (World::RestoreAnnouncementSettings()) { -// lock_collision = false; -// } -// } -// } + World::Update(); // from pause.h + if (lock_collision) { + if (unpause_enabled) { + // player asked for auto-unpause enabled + World::SaveAnnouncementSettings(); + if (World::DisableAnnouncementPausing()) { + // now that we've got what we want, we can lock it down + lock_collision = false; + } + } else { + if (World::RestoreAnnouncementSettings()) { + lock_collision = false; + } + } + } while (unpause_enabled && !world->status.popups.empty()) { // dismiss announcement popup(s) Gui::getCurViewscreen(true)->feed_key(interface_key::CLOSE_MEGA_ANNOUNCEMENT); + if (World::ReadPauseState()) { + World::SetPauseState(false); + } } if (disengage_enabled && !World::ReadPauseState()) { if (our_dorf && our_dorf->id != df::global::ui->follow_unit) { @@ -187,47 +205,54 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) { void enable_auto_unpause(color_ostream &out, bool state) { // we don't need to do any of this yet if the plugin isn't enabled if (enabled) { -// Announcement manipulation doesn't prevent siege pauses -// if(pause_lock) { -// // lock_collision == true means: enable_auto_unpause() was already invoked and didn't complete -// // The onupdate function above ensure the procedure properly completes, thus we only care about -// // state reversal here ergo `enabled != state` -// if (lock_collision && unpause_enabled != state) { -// out.print("handling collision\n"); -// // if unpaused_enabled is true, then a lock collision means: we couldn't save/disable the pause settings, -// // therefore nothing to revert and the lock won't even be engaged (nothing to unlock) -// lock_collision = false; -// unpause_enabled = state; -// if (unpause_enabled) { -// // a collision means we couldn't restore the pause settings, therefore we only need re-engage the lock -// pause_lock->lock(); -// } -// return; -// } -// // update the announcement settings if we can -// if (state) { -// if (World::SaveAnnouncementSettings()) { -// World::DisableAnnouncementPausing(out); -// pause_lock->lock(); -// } else { -// lock_collision = true; -// } -// } else { -// pause_lock->unlock(); -// if (!World::RestoreAnnouncementSettings()) { -// // this in theory shouldn't happen, if others use the lock like we do in spectate -// lock_collision = true; -// } -// } -// if (lock_collision) { -// out.printerr( -// "auto-unpause: must wait for another Pausing::AnnouncementLock to be lifted." -// " This setting will complete when the lock lifts.\n"); -// pause_lock->reportLocks(out); -// } -// } - unpause_enabled = state; + // todo: R.E. UNDEAD_ATTACK event [still pausing regardless of announcement settings] + if(pause_lock) { + // lock_collision == true means: enable_auto_unpause() was already invoked and didn't complete + // The onupdate function above ensure the procedure properly completes, thus we only care about + // state reversal here ergo `enabled != state` + if (lock_collision && unpause_enabled != state) { + out.print("handling collision\n"); + // if unpaused_enabled is true, then a lock collision means: we couldn't save/disable the pause settings, + // therefore nothing to revert and the lock won't even be engaged (nothing to unlock) + lock_collision = false; + unpause_enabled = state; + if (unpause_enabled) { + // a collision means we couldn't restore the pause settings, therefore we only need re-engage the lock + pause_lock->lock(); + } + return; + } + // update the announcement settings if we can + if (state) { + if (World::SaveAnnouncementSettings()) { + World::DisableAnnouncementPausing(); + announcements_disabled = true; + pause_lock->lock(); + } else { + out.printerr("lock collision enabling auto-unpause\n"); + lock_collision = true; + } + } else { + pause_lock->unlock(); + if (announcements_disabled) { + if (!World::RestoreAnnouncementSettings()) { + // this in theory shouldn't happen, if others use the lock like we do in spectate + out.printerr("lock collision disabling auto-unpause\n"); + lock_collision = true; + } else { + announcements_disabled = false; + } + } + } + if (lock_collision) { + out.printerr( + "auto-unpause: must wait for another Pausing::AnnouncementLock to be lifted.\n" + "The action you were attempting will complete when the following lock or locks lift.\n"); + pause_lock->reportLocks(out); + } + } } + unpause_enabled = state; } command_result spectate (color_ostream &out, std::vector & parameters) {