From 9b87edd09d875261a0d6cf07e321adfd73db5710 Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Fri, 10 Jun 2022 10:14:34 +0200 Subject: [PATCH 1/6] chore(backend): remove unnecessary debug output --- .gitignore | 2 +- lib/Network/ShipSink/ShipSink.cpp | 4 +--- lib/helper.h | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 006b849..e4e30ac 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /.idea # Exclude temporary / build / auto-generated directories -/*Remote* +/*Release* /*Debug* /*build* /*tmp* diff --git a/lib/Network/ShipSink/ShipSink.cpp b/lib/Network/ShipSink/ShipSink.cpp index 3266579..dd53191 100644 --- a/lib/Network/ShipSink/ShipSink.cpp +++ b/lib/Network/ShipSink/ShipSink.cpp @@ -14,9 +14,7 @@ namespace cg { log ("Ship closed stream"); try { - auto promise = onDone(); - log ("Done, returning"); - return kj::mv (promise); + return onDone(); } catch (std::bad_function_call & e) { KJ_DLOG (WARNING, "ShipSink::done called without valid callback registered"); } diff --git a/lib/helper.h b/lib/helper.h index a838158..f8289ce 100644 --- a/lib/helper.h +++ b/lib/helper.h @@ -4,7 +4,7 @@ #include /// If this is defined, backend debug output will be more fine-grained -#define DEBUG_MINOR +//#define DEBUG_MINOR /// Output function printing to stdout if debug mode is enabled inline void debug_stdout (std::string const & message) { From c652dbaa5c3dd9857f8c68b67399182067378e78 Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Fri, 10 Jun 2022 11:02:13 +0200 Subject: [PATCH 2/6] fix(backend): remove clients even if sending done requests fails --- .gitignore | 1 + lib/Data/Client.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e4e30ac..2a6d237 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ /*tmp* *generated* /docs +/vgcore* diff --git a/lib/Data/Client.cpp b/lib/Data/Client.cpp index 09f3ab2..2766a55 100644 --- a/lib/Data/Client.cpp +++ b/lib/Data/Client.cpp @@ -11,6 +11,8 @@ namespace cg { // Close the sink and then remove it from the map return sinks.at (username).doneRequest().send().ignoreResult().then ([this, username] () { sinks.erase (username); + }, [this, username] (kj::Exception && e) { + sinks.erase (username); }); } From 818bda069f89731fbbad9f145a4596f7998cf542 Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Fri, 10 Jun 2022 11:36:09 +0200 Subject: [PATCH 3/6] fix(scene): use pointer wrapper to ensure deletion of Scenes --- CMakeLists.txt | 2 +- src/Game.cpp | 4 +++- src/Scene/GameScene.cpp | 7 +++---- src/Scene/MenuScene.cpp | 4 ++-- src/Scene/Scene.cpp | 6 +++++- src/Scene/Scene.h | 2 ++ 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c754ee..325d264 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ find_package(box2d REQUIRED) include_directories(box2d/include/box2d) target_link_libraries(Capstone box2d) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OXYGINE_CXX_FLAGS} -fconcepts -w") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OXYGINE_CXX_FLAGS} -fconcepts -w -fsanitize=address") if (EMSCRIPTEN) SET(CMAKE_EXECUTABLE_SUFFIX ".html") diff --git a/src/Game.cpp b/src/Game.cpp index a26f876..a47e04d 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -54,7 +54,7 @@ namespace kt { #endif // Create main menu scene - new MenuScene (); + Scene::instance = kj::heap (); logs::messageln ("Scene initialisation complete"); // Main game loop. Returns true if done @@ -63,6 +63,8 @@ namespace kt { done = loop (); } while (!done); + Scene::instance = nullptr; + // Release all internal components and the stage core::release(); diff --git a/src/Scene/GameScene.cpp b/src/Scene/GameScene.cpp index b2a75fa..ed7d80c 100644 --- a/src/Scene/GameScene.cpp +++ b/src/Scene/GameScene.cpp @@ -176,22 +176,21 @@ namespace kt { // Remove this scene including all its listeners removeChildren(); detach(); - getStage()->removeAllEventListeners(); } void GameScene::onRestart (Event * event) { GameScene::~GameScene(); - new GameScene (rng.seed); + instance = kj::heap (rng.seed); } void GameScene::onNewGame (Event * event) { GameScene::~GameScene(); - new GameScene (RANDOM_SEED); + instance = kj::heap (RANDOM_SEED); } void GameScene::onDisconnect (Event * event) { GameScene::~GameScene(); - new MenuScene(); + instance = kj::heap (); } void GameScene::onQuit (Event * event) { diff --git a/src/Scene/MenuScene.cpp b/src/Scene/MenuScene.cpp index 801dfd0..2b21ef9 100644 --- a/src/Scene/MenuScene.cpp +++ b/src/Scene/MenuScene.cpp @@ -33,7 +33,7 @@ namespace kt { void MenuScene::onNewGame (Event * event) { MenuScene::~MenuScene(); - new GameScene (RANDOM_SEED); + instance = kj::heap (RANDOM_SEED); } void MenuScene::onJoinGame (Event * event) { // Request entering an address to connect to @@ -44,7 +44,7 @@ namespace kt { // Ping the address; if it resolves start a new game and connect to it if (Backend::ping (address, SERVER_PORT)) { MenuScene::~MenuScene(); - new GameScene (address, SERVER_PORT); + instance = kj::heap (address, SERVER_PORT); } } void MenuScene::onRequestExit (Event * event) { diff --git a/src/Scene/Scene.cpp b/src/Scene/Scene.cpp index 035506c..9ff6264 100644 --- a/src/Scene/Scene.cpp +++ b/src/Scene/Scene.cpp @@ -1,14 +1,18 @@ #include "Scene.h" namespace kt { + kj::Own Scene::instance; + Scene::Scene () { // Inject us into the stage and adjust position and size to it (-> fill the entire window with this scene) attachTo (getStage()); setPosition (getStage()->getPosition()); setSize (getStage()->getSize()); } - Scene::~Scene () noexcept = default; + + + } /* Copyright © 2022 Aaron Alef */ diff --git a/src/Scene/Scene.h b/src/Scene/Scene.h index e2e9e6d..2be90ef 100644 --- a/src/Scene/Scene.h +++ b/src/Scene/Scene.h @@ -14,6 +14,8 @@ namespace kt { /// Construct a new Scene. Injects itself into the stage. Should be the only scene there Scene (); ~Scene() override = 0; + + static kj::Own instance; }; DECLARE_SMART (Scene, spScene); From 68a7d1ea35382daa172ab50f4a0ee5b6a573bdc2 Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Fri, 10 Jun 2022 12:03:45 +0200 Subject: [PATCH 4/6] fix(game): ensure objects do not leak by retaining ownership --- src/Planet/Planet.cpp | 4 ++++ src/Planet/Planet.h | 1 + src/Scene/GameScene.cpp | 33 +++++++++++++++++---------------- src/Scene/GameScene.h | 12 ++++++------ src/Spaceship/Spaceship.cpp | 24 +++++++++++------------- src/World/World.cpp | 4 ++++ src/World/World.h | 1 + 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/Planet/Planet.cpp b/src/Planet/Planet.cpp index 7781b04..4b9c915 100644 --- a/src/Planet/Planet.cpp +++ b/src/Planet/Planet.cpp @@ -74,6 +74,10 @@ namespace kt { Actor::update (updateState); } + + Planet::~Planet () noexcept { + detach(); + } } /* Copyright © 2022 Aaron Alef */ diff --git a/src/Planet/Planet.h b/src/Planet/Planet.h index 6073cb1..5771d77 100644 --- a/src/Planet/Planet.h +++ b/src/Planet/Planet.h @@ -32,6 +32,7 @@ namespace kt { public: /// Create a new planet with given sprite in the given world at the given position with the given size. Planet (World & world, ResAnim * animation, Vector2 const & pos, float scale = 1); + ~Planet () noexcept override; /// Exert gravitational force on non-planet objects based on mass and distance void update (UpdateState const & updateState) override; diff --git a/src/Scene/GameScene.cpp b/src/Scene/GameScene.cpp index ed7d80c..fd31cd7 100644 --- a/src/Scene/GameScene.cpp +++ b/src/Scene/GameScene.cpp @@ -27,7 +27,7 @@ namespace kt { logs::messageln ("Seed: %lu", rng.seed); initWorld(); - clock = new Text (gameResources.getResFont ("kt-liberation")); + clock = kj::heap (gameResources.getResFont ("kt-liberation")); clock->setPosition (0.78 * getSize().x, 0.95 * getSize().y); addChild (clock); @@ -53,7 +53,7 @@ namespace kt { // Configure dialog to open on pressing Escape auto size = getSize(); - onMenuDialog = new Dialog ({size.x / 4, size.y / 5}, {size.x / 2, size.y / 2}, "Exit the game?"); + onMenuDialog = kj::heap (Vector2 (size.x / 4, size.y / 5), Vector2 (size.x / 2, size.y / 2), "Exit the game?"); onMenuDialog->addButton ("Restart", CLOSURE (this, & GameScene::onRestart)); onMenuDialog->addButton ("New game", CLOSURE (this, & GameScene::onNewGame)); onMenuDialog->addButton ("Disconnect", CLOSURE (this, & GameScene::onDisconnect)); @@ -77,22 +77,22 @@ namespace kt { gameResources.loadXML (GAME_RESOURCES); // Create the world - auto & world = actors.world = new World (gameResources.getResAnim ("sky"), WORLD_SIZE); + auto & world = actors.world = kj::heap (gameResources.getResAnim ("sky"), WORLD_SIZE); addChild (world); // Generate a couple of planets, number based on world size auto planetAnimation = gameResources.getResAnim ("venus"); int const number_of_planets = PLANETS_PER_PIXEL * getSize().x * getSize().y; for (std::size_t i = 0; i < number_of_planets; i++) { - actors.planets.push_back (new Planet (* world, planetAnimation, { + actors.planets.push_back (kj::heap (* world, planetAnimation, Vector2 ( float (rng.random ({100, world->getSize().x - 100})), float (rng.random ({100, world->getSize().y - 100})) - }, float (rng.random ({0.3, 0.7})))); + ), float (rng.random ({0.3, 0.7})))); } // Create the keyboard-controlled spaceship with ID = 0 Spaceship::resetCounter(); - actors.localShip = new KeyboardSpaceship (* world, & gameResources, MenuScene::getUsername(), waitscope); + actors.localShip = kj::heap (* world, & gameResources, MenuScene::getUsername(), waitscope); } kj::Own GameScene::getRegistrarImpl () { @@ -115,12 +115,13 @@ namespace kt { actors.remoteShips.erase (username); // Case 2b: Create a new remote ship connected to the given handle - spRemoteSpaceship ship = new RemoteSpaceship (* actors.world, & gameResources, username); - actors.remoteShips.emplace (username, ship); - ship->setOnDone ([](){ return kj::READY_NOW; }); - ship->setData (data); - ship->setHandle (std::move (handle)); - return ship->getSink (); + auto owned_ship = kj::heap (* actors.world, & gameResources, username); + actors.remoteShips.emplace (username, kj::mv (owned_ship)); + auto & ship = * actors.remoteShips.at (username); + ship.setOnDone ([](){ return kj::READY_NOW; }); + ship.setData (data); + ship.setHandle (std::move (handle)); + return ship.getSink (); } catch (std::exception & e) { logs::warning ("Error on registering new spaceship"); return {}; @@ -158,16 +159,16 @@ namespace kt { void GameScene::onMenu (Event * event) { // Open a dialog with options to join a remote game or restart or quit the current one - if (getLastChild() == onMenuDialog) removeChild (onMenuDialog); - else addChild (onMenuDialog); + if (getLastChild().get() == onMenuDialog.get()) removeChild (onMenuDialog.get()); + else addChild (onMenuDialog.get()); } GameScene::~GameScene() noexcept { // Destroy KeyboardSpaceship - if (auto ship = actors.localShip) ship->destroy().wait (waitscope); + if (auto & ship = actors.localShip) ship->destroy().wait (waitscope); // Destroy RemoteSpaceships - for (auto ship : actors.remoteShips) ship.second->destroy().wait (waitscope); + for (auto & ship : actors.remoteShips) ship.second->destroy().wait (waitscope); actors.remoteShips.clear(); // Free all game assets diff --git a/src/Scene/GameScene.h b/src/Scene/GameScene.h index f53968c..c2783e4 100644 --- a/src/Scene/GameScene.h +++ b/src/Scene/GameScene.h @@ -66,20 +66,20 @@ namespace kt { std::mutex mx; /// The world holding all things and updating physics - spWorld world; + kj::Own world; /// The ship controlled by WASD / arrow keys - spKeyboardSpaceship localShip; + kj::Own localShip; /// The list of all remote ships registered by the backend - std::unordered_map remoteShips; + std::unordered_map > remoteShips; /// All planets in the game - std::vector planets; + std::vector > planets; } actors; /// Menu opened on pressing Escape in-game - spDialog onMenuDialog; + kj::Own onMenuDialog; /// clock window - spText clock; + kj::Own clock; /// Update the clock void updateTime (); diff --git a/src/Spaceship/Spaceship.cpp b/src/Spaceship/Spaceship.cpp index ff2d975..3843182 100644 --- a/src/Spaceship/Spaceship.cpp +++ b/src/Spaceship/Spaceship.cpp @@ -101,9 +101,19 @@ namespace kt { } Spaceship::~Spaceship() noexcept { - if (isDestroyed) return; + detach (); + } + + kj::Promise Spaceship::destroy () { + if (isDestroyed) return kj::READY_NOW; isDestroyed = true; + try { + return onDone(); + } catch (std::bad_function_call & e) { + logs::warning ("Spaceship destroyed without done callback registered"); + } + // Stop listening to anything for (auto listener: listeners) getStage ()->removeEventListener (listener); listeners.clear(); @@ -117,18 +127,6 @@ namespace kt { // Remove the physical body and detach the ship from the game if (body) body->GetUserData().pointer = 0; body = nullptr; - detach (); - } - - kj::Promise Spaceship::destroy () { - if (isDestroyed) return kj::READY_NOW; - - Spaceship::~Spaceship(); - try { - return onDone(); - } catch (std::bad_function_call & e) { - logs::warning ("Spaceship destroyed without done callback registered"); - } } void Spaceship::updateScoreboard (std::string const & msg, long ping) { diff --git a/src/World/World.cpp b/src/World/World.cpp index 4002854..c59eb2c 100644 --- a/src/World/World.cpp +++ b/src/World/World.cpp @@ -125,6 +125,10 @@ namespace kt { // Forward call to parent class Actor::addChild (child); } + + World::~World () noexcept { + detach(); + } } /* Copyright © 2022 Aaron Alef */ diff --git a/src/World/World.h b/src/World/World.h index 84ac5c5..503d6f5 100644 --- a/src/World/World.h +++ b/src/World/World.h @@ -37,6 +37,7 @@ namespace kt { /// Construct a new world with the given background and size World (ResAnim * background, b2Vec2 size); + ~World() noexcept override; /// Update all physical bodies and their corresponding sprites void update (UpdateState const & updateState) override; From b1943b4c67a2769a582dfcefde9f246c901b9e9b Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Fri, 10 Jun 2022 12:26:52 +0200 Subject: [PATCH 5/6] chore(cmake): turn address sanitisation back on --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 325d264..135f85c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,8 @@ find_package(box2d REQUIRED) include_directories(box2d/include/box2d) target_link_libraries(Capstone box2d) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OXYGINE_CXX_FLAGS} -fconcepts -w -fsanitize=address") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OXYGINE_CXX_FLAGS} -fconcepts -w") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") if (EMSCRIPTEN) SET(CMAKE_EXECUTABLE_SUFFIX ".html") From 29d54de2efedf9809fe61e2cd79a24c95f9fbc46 Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Sat, 11 Jun 2022 15:37:49 +0200 Subject: [PATCH 6/6] docs: adjust the diagrams and add another screenshot --- data/architecture.mdj | 13395 +++++++++++++++++++++++----------------- data/screenshot2.png | Bin 49406 -> 49136 bytes data/screenshot3.png | Bin 0 -> 29482 bytes 3 files changed, 7776 insertions(+), 5619 deletions(-) create mode 100644 data/screenshot3.png diff --git a/data/architecture.mdj b/data/architecture.mdj index eb3b53f..40cc3c1 100644 --- a/data/architecture.mdj +++ b/data/architecture.mdj @@ -48,8 +48,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": -144, - "top": 192, + "left": 672, + "top": -128, "height": 13 }, { @@ -59,9 +59,9 @@ "$ref": "AAAAAAGAdKNUSMAwEXM=" }, "font": "Arial;13;3", - "left": 61, - "top": 199, - "width": 135, + "left": 469, + "top": 39, + "width": 87, "height": 13, "text": "Game" }, @@ -73,8 +73,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": -144, - "top": 192, + "left": 672, + "top": -128, "width": 73.67724609375, "height": 13, "text": "(from Model)" @@ -87,16 +87,16 @@ }, "visible": false, "font": "Arial;13;0", - "left": -144, - "top": 192, + "left": 672, + "top": -128, "height": 13, "horizontalAlignment": 1 } ], "font": "Arial;13;0", - "left": 56, - "top": 192, - "width": 145, + "left": 464, + "top": 32, + "width": 97, "height": 25, "stereotypeLabel": { "$ref": "AAAAAAGAdKNUSMAx8H8=" @@ -132,8 +132,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 61, - "top": 334, + "left": 877, + "top": 14, "width": 89.603515625, "height": 13, "underline": true, @@ -142,9 +142,9 @@ } ], "font": "Arial;13;0", - "left": 56, - "top": 217, - "width": 145, + "left": 464, + "top": 57, + "width": 97, "height": 10 }, { @@ -168,8 +168,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 61, - "top": 344, + "left": 877, + "top": 24, "width": 89.603515625, "height": 13, "underline": true, @@ -187,8 +187,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 61, - "top": 346, + "left": 877, + "top": 26, "width": 89.603515625, "height": 13, "underline": true, @@ -206,8 +206,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 61, - "top": 346, + "left": 877, + "top": 26, "width": 89.603515625, "height": 13, "underline": true, @@ -216,9 +216,9 @@ } ], "font": "Arial;13;0", - "left": 56, - "top": 227, - "width": 145, + "left": 464, + "top": 67, + "width": 97, "height": 10 }, { @@ -232,8 +232,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": -56, - "top": 240, + "left": 352, + "top": 80, "width": 10, "height": 10 }, @@ -248,17 +248,17 @@ }, "visible": false, "font": "Arial;13;0", - "left": -56, - "top": 240, + "left": 352, + "top": 80, "width": 10, "height": 10 } ], "font": "Arial;13;0", "containerChangeable": true, - "left": 56, - "top": 192, - "width": 145, + "left": 464, + "top": 32, + "width": 97, "height": 45, "nameCompartment": { "$ref": "AAAAAAGAdKNUSMAwEXM=" @@ -304,8 +304,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 112, - "top": -304, + "left": 512, + "top": -272, "height": 13 }, { @@ -315,9 +315,9 @@ "$ref": "AAAAAAGAdKqjCcCqZS4=" }, "font": "Arial;13;3", - "left": 237, - "top": 199, - "width": 135, + "left": 469, + "top": 215, + "width": 87, "height": 13, "text": "Scene" }, @@ -329,8 +329,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 112, - "top": -304, + "left": 512, + "top": -272, "width": 73.67724609375, "height": 13, "text": "(from Model)" @@ -343,16 +343,16 @@ }, "visible": false, "font": "Arial;13;0", - "left": 112, - "top": -304, + "left": 512, + "top": -272, "height": 13, "horizontalAlignment": 1 } ], "font": "Arial;13;0", - "left": 232, - "top": 192, - "width": 145, + "left": 464, + "top": 208, + "width": 97, "height": 25, "stereotypeLabel": { "$ref": "AAAAAAGAdKqjCcCrp0Q=" @@ -377,9 +377,9 @@ "$ref": "AAAAAAGAdKqjCcCnSMU=" }, "font": "Arial;13;0", - "left": 232, - "top": 217, - "width": 145, + "left": 464, + "top": 233, + "width": 97, "height": 10 }, { @@ -403,8 +403,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 269, - "top": 320, + "left": 669, + "top": 352, "width": 95, "height": 13, "text": "+Scene()", @@ -412,9 +412,9 @@ } ], "font": "Arial;13;0", - "left": 232, - "top": 227, - "width": 145, + "left": 464, + "top": 243, + "width": 97, "height": 10 }, { @@ -428,8 +428,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 72, - "top": -8, + "left": 272, + "top": 8, "width": 10, "height": 10 }, @@ -444,17 +444,17 @@ }, "visible": false, "font": "Arial;13;0", - "left": 72, - "top": -8, + "left": 272, + "top": 8, "width": 10, "height": 10 } ], "font": "Arial;13;0", "containerChangeable": true, - "left": 232, - "top": 192, - "width": 145, + "left": 464, + "top": 208, + "width": 97, "height": 45, "nameCompartment": { "$ref": "AAAAAAGAdKqjCcCqZS4=" @@ -501,8 +501,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 368, - "top": -748, + "left": 320, + "top": -652, "height": 13 }, { @@ -513,9 +513,9 @@ }, "fillColor": "#ffeeee", "font": "Arial;13;1", - "left": 429, - "top": 87, - "width": 135, + "left": 405, + "top": 135, + "width": 87, "height": 13, "text": "MenuScene" }, @@ -528,8 +528,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 368, - "top": -748, + "left": 320, + "top": -652, "width": 73.67724609375, "height": 13, "text": "(from Model)" @@ -543,17 +543,17 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 368, - "top": -748, + "left": 320, + "top": -652, "height": 13, "horizontalAlignment": 1 } ], "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 424, - "top": 80, - "width": 145, + "left": 400, + "top": 128, + "width": 97, "height": 25, "stereotypeLabel": { "$ref": "AAAAAAGAdKulX8DYZzw=" @@ -579,9 +579,9 @@ }, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 424, - "top": 105, - "width": 145, + "left": 400, + "top": 153, + "width": 97, "height": 10 }, { @@ -606,8 +606,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 477, - "top": 160, + "left": 429, + "top": 256, "width": 178.1279296875, "height": 13, "text": "+MenuScene()", @@ -625,8 +625,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 477, - "top": 162, + "left": 429, + "top": 258, "width": 178.1279296875, "height": 13, "text": "+onNewGame(Event * event)", @@ -644,8 +644,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 477, - "top": 162, + "left": 429, + "top": 258, "width": 178.1279296875, "height": 13, "text": "+onRequestExit(Event * event)", @@ -654,9 +654,9 @@ ], "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 424, - "top": 115, - "width": 145, + "left": 400, + "top": 163, + "width": 97, "height": 10 }, { @@ -671,8 +671,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 200, - "top": -230, + "left": 176, + "top": -182, "width": 10, "height": 10 }, @@ -688,8 +688,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 200, - "top": -230, + "left": 176, + "top": -182, "width": 10, "height": 10 } @@ -697,9 +697,9 @@ "fillColor": "#ffeeee", "font": "Arial;13;0", "containerChangeable": true, - "left": 424, - "top": 80, - "width": 145, + "left": 400, + "top": 128, + "width": 97, "height": 45, "nameCompartment": { "$ref": "AAAAAAGAdKulX8DXllk=" @@ -738,8 +738,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 407, - "top": 164, + "left": 491, + "top": 174, "height": 13, "alpha": 1.5707963267948966, "distance": 15, @@ -759,8 +759,8 @@ }, "visible": null, "font": "Arial;13;0", - "left": 415, - "top": 177, + "left": 503, + "top": 164, "height": 13, "alpha": 1.5707963267948966, "distance": 30, @@ -780,8 +780,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 392, - "top": 139, + "left": 468, + "top": 193, "height": 13, "alpha": -1.5707963267948966, "distance": 15, @@ -799,7 +799,7 @@ "$ref": "AAAAAAGAdKulX8DWFtU=" }, "lineStyle": 1, - "points": "457:125;343:191", + "points": "466:173;494:207", "showVisibility": true, "nameLabel": { "$ref": "AAAAAAGAdKule8EAmoE=" @@ -840,8 +840,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 245.744140625, - "top": -208, + "left": 373.744140625, + "top": -624, "height": 13 }, { @@ -852,9 +852,9 @@ }, "fillColor": "#eeeeff", "font": "Arial;13;1", - "left": 421, - "top": 343, - "width": 135, + "left": 533, + "top": 135, + "width": 87, "height": 13, "text": "GameScene" }, @@ -867,8 +867,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 245.744140625, - "top": -208, + "left": 373.744140625, + "top": -624, "width": 73.67724609375, "height": 13, "text": "(from Model)" @@ -882,17 +882,17 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 245.744140625, - "top": -208, + "left": 373.744140625, + "top": -624, "height": 13, "horizontalAlignment": 1 } ], "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 416, - "top": 336, - "width": 145, + "left": 528, + "top": 128, + "width": 97, "height": 25, "stereotypeLabel": { "$ref": "AAAAAAGAdK3F8sE2F5k=" @@ -929,8 +929,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 478, + "left": 589, + "top": 62, "width": 196.2060546875, "height": 13, "text": "-gameResources Resources", @@ -948,8 +948,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 480, + "left": 589, + "top": 64, "width": 196.2060546875, "height": 13, "text": "-rng HashedRNG", @@ -967,8 +967,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 480, + "left": 589, + "top": 64, "width": 196.2060546875, "height": 13, "text": "-softPause: bool", @@ -977,9 +977,9 @@ ], "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 416, - "top": 361, - "width": 145, + "left": 528, + "top": 153, + "width": 97, "height": 10 }, { @@ -1004,8 +1004,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 488, + "left": 589, + "top": 72, "width": 196.2060546875, "height": 13, "text": "+GameScene(int seed?)", @@ -1023,8 +1023,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 490, + "left": 589, + "top": 74, "width": 196.2060546875, "height": 13, "text": "+update(UpdateState const & us)", @@ -1042,8 +1042,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 490, + "left": 589, + "top": 74, "width": 196.2060546875, "height": 13, "text": "+onRestart(Event * event)", @@ -1061,8 +1061,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 490, + "left": 589, + "top": 74, "width": 196.2060546875, "height": 13, "text": "+onNewGame(Evente * event)", @@ -1080,8 +1080,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 490, + "left": 589, + "top": 74, "width": 196.2060546875, "height": 13, "text": "+onAbandon(Event * event)", @@ -1099,8 +1099,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 461, - "top": 535, + "left": 589, + "top": 119, "width": 196.2060546875, "height": 13, "text": "+onQuit(Event * event)", @@ -1109,9 +1109,9 @@ ], "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 416, - "top": 371, - "width": 145, + "left": 528, + "top": 163, + "width": 97, "height": 10 }, { @@ -1126,8 +1126,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 138.8720703125, - "top": 40, + "left": 202.8720703125, + "top": -168, "width": 10, "height": 10 }, @@ -1143,8 +1143,8 @@ "visible": false, "fillColor": "#eeeeff", "font": "Arial;13;0", - "left": 138.8720703125, - "top": 40, + "left": 202.8720703125, + "top": -168, "width": 10, "height": 10 } @@ -1152,9 +1152,9 @@ "fillColor": "#eeeeff", "font": "Arial;13;0", "containerChangeable": true, - "left": 416, - "top": 336, - "width": 145, + "left": 528, + "top": 128, + "width": 97, "height": 45, "nameCompartment": { "$ref": "AAAAAAGAdK3F8sE1mEs=" @@ -1193,8 +1193,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 386, - "top": 291, + "left": 555, + "top": 193, "height": 13, "alpha": 1.5707963267948966, "distance": 15, @@ -1214,8 +1214,8 @@ }, "visible": null, "font": "Arial;13;0", - "left": 377, - "top": 303, + "left": 567, + "top": 203, "height": 13, "alpha": 1.5707963267948966, "distance": 30, @@ -1235,8 +1235,8 @@ }, "visible": false, "font": "Arial;13;0", - "left": 405, - "top": 268, + "left": 532, + "top": 174, "height": 13, "alpha": -1.5707963267948966, "distance": 15, @@ -1254,7 +1254,7 @@ "$ref": "AAAAAAGAdK3F8sE0vfs=" }, "lineStyle": 1, - "points": "459:335;333:237", + "points": "558:173;530:207", "showVisibility": true, "nameLabel": { "$ref": "AAAAAAGAdK3GBMFekU8=" @@ -1295,7 +1295,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "top": -448, + "left": -688, + "top": -192, "height": 13 }, { @@ -1306,9 +1307,9 @@ }, "fillColor": "#ffeeee", "font": "Arial;13;1", - "left": 653, - "top": 87, - "width": 135, + "left": 309, + "top": 215, + "width": 87, "height": 13, "text": "Dialog" }, @@ -1321,7 +1322,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "top": -448, + "left": -688, + "top": -192, "width": 73.67724609375, "height": 13, "text": "(from Model)" @@ -1335,16 +1337,17 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "top": -448, + "left": -688, + "top": -192, "height": 13, "horizontalAlignment": 1 } ], "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 648, - "top": 80, - "width": 145, + "left": 304, + "top": 208, + "width": 97, "height": 25, "stereotypeLabel": { "$ref": "AAAAAAGAdLJvIMHanwk=" @@ -1381,8 +1384,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 629, - "top": 78, + "left": -59, + "top": 334, "width": 297.34326171875, "height": 13, "underline": true, @@ -1401,8 +1404,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 629, - "top": 80, + "left": -59, + "top": 336, "width": 297.34326171875, "height": 13, "text": "-text: Text *", @@ -1420,8 +1423,8 @@ "visible": false, "fillColor": "#ffeeee", "font": "Arial;13;0", - "left": 629, - "top": 80, + "left": -59, + "top": 336, "width": 297.34326171875, "height": 13, "text": "-buttons: List