From a70c6d390ed6cd1600cd974475079fc585d472bd Mon Sep 17 00:00:00 2001 From: bmayeur Date: Sat, 12 Sep 2020 17:42:22 +0200 Subject: [PATCH 1/3] Replay mode : adapting replay speed to reality --- src/Input.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Input.hpp b/src/Input.hpp index e4919bd..a15af7f 100644 --- a/src/Input.hpp +++ b/src/Input.hpp @@ -298,8 +298,10 @@ struct GameState pendingEvents.erase(pendingEvents.begin()); std::visit(overloaded{ - [](const TimeElapsed &te) { - std::this_thread::sleep_for(te.elapsed); + [&](const TimeElapsed &te) { + const auto timeElapsed = clock::now() - lastTick; + std::this_thread::sleep_for(te.elapsed - timeElapsed); + lastTick += te.elapsed; }, [&](const Moved &me) { sf::Mouse::setPosition({me.source.x, me.source.y}, window); From cc9e673ecb352542a8f78d0035ae660541feb598 Mon Sep 17 00:00:00 2001 From: bmayeur Date: Sat, 12 Sep 2020 17:51:54 +0200 Subject: [PATCH 2/3] Concatenation of two TimeElapsed event is forbidden, 3 is needed: In the case: - Button pushed - TimeElapsed - Button released - TimeElapsed <--- now the game state knows the button is release - TimeElapsed - TimeElapsed - Something else happened Otherwise, after compression in replay it would become - Button pushed - TimeElapsed - Button released - TimeElapsed (compressed, so x3) <--- now the game state knows the button is release - Something else happened Such that the timings are incorrects --- src/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0b3344b..2cf386d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -103,17 +103,18 @@ int main(int argc, const char **argv) std::uint64_t eventsProcessed{ 0 }; - std::vector events{ Game::GameState::TimeElapsed{} }; + std::vector events{ Game::GameState::TimeElapsed{}, Game::GameState::TimeElapsed{} }; while (window.isOpen()) { const auto event = gs.nextEvent(window); - std::visit(Game::overloaded{ [](Game::GameState::TimeElapsed &prev, const Game::GameState::TimeElapsed &next) { + std::visit(Game::overloaded{ [](Game::GameState::TimeElapsed &/*prevPrev*/, Game::GameState::TimeElapsed &prev, const Game::GameState::TimeElapsed &next) { prev.elapsed += next.elapsed; }, - [&](const auto & /*prev*/, const std::monostate &) {}, - [&](const auto & /*prev*/, const auto &next) { events.push_back(next); } }, + [&](const auto & /*prev*/, const auto & /*prev*/, const std::monostate &) {}, + [&](const auto & /*prev*/, const auto & /*prev*/, const auto &next) { events.push_back(next); } }, + *std::prev(events.end(),2), events.back(), event); From e2fd7d24861d7b72bf163c0a0f8e2218751f198d Mon Sep 17 00:00:00 2001 From: bmayeur Date: Sat, 12 Sep 2020 18:44:25 +0200 Subject: [PATCH 3/3] Reset the configuration to the one of the replayed scenario Arguments of the display may have changed between save/replay Here is some way to do it. Maybe not the best way to, my idea was to expose the problem here. Another problem that is still not fixed here: - Windows are not resized / Moved by replay --- src/Input.hpp | 13 ++++++++++++- src/main.cpp | 33 ++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/Input.hpp b/src/Input.hpp index a15af7f..cb3b2f0 100644 --- a/src/Input.hpp +++ b/src/Input.hpp @@ -131,6 +131,15 @@ struct GameState } }; + struct InitialConfiguration + { + constexpr static std::string_view name{ "InitialConfiguration" }; + constexpr static auto elements = std::to_array({ "width", "height", "scale", "imgui" }); + long width; + long height; + long scale; + std::string imgui; + }; struct Joystick { @@ -206,7 +215,8 @@ struct GameState Pressed, Released, CloseWindow, - TimeElapsed>; + TimeElapsed, + InitialConfiguration>; static sf::Event::KeyEvent toSFMLEventInternal(const Key &key) @@ -280,6 +290,7 @@ struct GameState { return std::visit( overloaded{ [&](const auto &value) -> std::optional { return toSFMLEventInternal(value); }, + [&](const InitialConfiguration &) -> std::optional { return {}; }, [&](const TimeElapsed &) -> std::optional { return {}; }, [&](const std::monostate &) -> std::optional { return {}; } }, event); diff --git a/src/main.cpp b/src/main.cpp index 2cf386d..211a4d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,9 +39,9 @@ int main(int argc, const char **argv) true,// show help if requested "Game 0.0");// version string - const auto width = args["--width"].asLong(); - const auto height = args["--height"].asLong(); - const auto scale = args["--scale"].asLong(); + auto width = args["--width"].asLong(); + auto height = args["--height"].asLong(); + auto scale = args["--scale"].asLong(); std::vector initialEvents; if (args["--replay"]) { @@ -49,6 +49,23 @@ int main(int argc, const char **argv) std::ifstream ifs(eventFile); const auto j = nlohmann::json::parse(ifs); initialEvents = j.get>(); + + auto event = initialEvents.front(); + + std::visit(Game::overloaded{ + [&](const Game::GameState::InitialConfiguration &ic) { + width = ic.width; + height = ic.height; + scale = ic.scale; + + std::ofstream ofs{ "imgui.ini" }; + ofs << ic.imgui; + + initialEvents.erase(initialEvents.begin()); + }, + [](const auto &) { } + }, + event); } @@ -103,8 +120,14 @@ int main(int argc, const char **argv) std::uint64_t eventsProcessed{ 0 }; - std::vector events{ Game::GameState::TimeElapsed{}, Game::GameState::TimeElapsed{} }; - + std::string imgui; + { + std::ifstream f("imgui.ini", std::ios::binary); + std::vector v(std::istreambuf_iterator{f}, {}); + imgui= std::string(v.begin(), v.end()); + } + std::vector events{ Game::GameState::InitialConfiguration{width, height, scale, imgui}, Game::GameState::TimeElapsed{} }; + while (window.isOpen()) { const auto event = gs.nextEvent(window);