#include "Museum.h" using namespace std; Museum::Museum() : people(*this), canvas(*this), collision(*this), pathfinding(*this) { this->worker = new std::thread(&Museum::work, this); } Museum::~Museum() { this->working = false; this->worker->join(); if (this->worker != nullptr) { delete this->worker; this->worker = nullptr; } } void Museum::update() { unsigned long long next_snapshot = this->snapshot_ticks; if (!this->history.empty()) next_snapshot += this->history.top().tick; if (this->tick >= next_snapshot || this->history.empty()) { this->history.push(this->save_snapshot()); } this->people.update(); this->canvas.update(); this->collision.update(); this->tick++; } void Museum::skip_forward() { this->jump++; } void Museum::skip_backward() { this->paused = true; this->jump--; } void Museum::work() { while (this->working) { // immediately process jumps, even if paused if (this->jump > 0) { // forward jump for (; this->jump != 0; this->jump--) { for (size_t i = 0; i < this->snapshot_ticks; i++) this->update(); } } else if (this->jump < 0) { // backward jump for (; this->jump != 0; this->jump++) { if (this->history.empty()) continue; this->restore_snapshot(this->history.top()); if (this->tick > 0) this->history.pop(); } } // wait with regular update if paused if (this->paused) continue; // regular update auto next = chrono::steady_clock::now() + this->tick_interval; this->update(); this_thread::sleep_until(next); } } static void memories_concat(Memories & a, Memories b) { a.insert(a.end(), make_move_iterator(b.begin()), make_move_iterator(b.end())); } Museum::Snapshot Museum::save_snapshot() { Snapshot snapshot = { .tick = this->tick, .memories = {}, }; memories_concat(snapshot.memories, this->canvas.save()); memories_concat(snapshot.memories, this->people.save()); return snapshot; } void Museum::restore_snapshot(const Snapshot & snapshot) { this->tick = snapshot.tick; this->canvas.restore(snapshot.memories); this->people.restore(snapshot.memories); }