{"action":"created","issue":{"url":"https://api.github.com/repos/CorsixTH/CorsixTH/issues/589","labels_url":"https://api.github.com/repos/CorsixTH/CorsixTH/issues/589/labels{/name}","comments_url":"https://api.github.com/repos/CorsixTH/CorsixTH/issues/589/comments","events_url":"https://api.github.com/repos/CorsixTH/CorsixTH/issues/589/events","html_url":"https://github.com/CorsixTH/CorsixTH/issues/589","id":53116940,"number":589,"title":"Game Replays","user":{"login":"J-Shep","id":6353342,"avatar_url":"https://avatars.githubusercontent.com/u/6353342?v=3","gravatar_id":"","url":"https://api.github.com/users/J-Shep","html_url":"https://github.com/J-Shep","followers_url":"https://api.github.com/users/J-Shep/followers","following_url":"https://api.github.com/users/J-Shep/following{/other_user}","gists_url":"https://api.github.com/users/J-Shep/gists{/gist_id}","starred_url":"https://api.github.com/users/J-Shep/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/J-Shep/subscriptions","organizations_url":"https://api.github.com/users/J-Shep/orgs","repos_url":"https://api.github.com/users/J-Shep/repos","events_url":"https://api.github.com/users/J-Shep/events{/privacy}","received_events_url":"https://api.github.com/users/J-Shep/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/CorsixTH/CorsixTH/labels/Type-Enhancement","name":"Type-Enhancement","color":"8593ab"}],"state":"open","locked":false,"assignee":{"login":"J-Shep","id":6353342,"avatar_url":"https://avatars.githubusercontent.com/u/6353342?v=3","gravatar_id":"","url":"https://api.github.com/users/J-Shep","html_url":"https://github.com/J-Shep","followers_url":"https://api.github.com/users/J-Shep/followers","following_url":"https://api.github.com/users/J-Shep/following{/other_user}","gists_url":"https://api.github.com/users/J-Shep/gists{/gist_id}","starred_url":"https://api.github.com/users/J-Shep/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/J-Shep/subscriptions","organizations_url":"https://api.github.com/users/J-Shep/orgs","repos_url":"https://api.github.com/users/J-Shep/repos","events_url":"https://api.github.com/users/J-Shep/events{/privacy}","received_events_url":"https://api.github.com/users/J-Shep/received_events","type":"User","site_admin":false},"milestone":null,"comments":13,"created_at":"2014-12-30T13:55:03Z","updated_at":"2015-07-28T18:20:02Z","closed_at":null,"body":"I'm working on this now and I may include this enhancement's commit in my pull request for automated Lua error reports (#445).\r\n\r\nI guess no player would be entertained by watching a replay of another player's game but this enhancement would be useful for developers because it could be used to repeat reported Lua errors and it could be used to test CorsixTH by making it play through levels at a fast speed.\r\n\r\nReplay data will be stored in a App.lua table: if a player chooses to attach a replay to a saved game then its data will be persisted in this table. To play a replay a player/developer would just load a saved game which has an attached replay and then they would be asked if they wanted to play the attached replay.\r\n\r\nCorsixTH could also be launched from the command line in a no input & optionally no graphics, replay test mode. So a level replay test could be added to the travis build script."},"comment":{"url":"https://api.github.com/repos/CorsixTH/CorsixTH/issues/comments/125702004","html_url":"https://github.com/CorsixTH/CorsixTH/issues/589#issuecomment-125702004","issue_url":"https://api.github.com/repos/CorsixTH/CorsixTH/issues/589","id":125702004,"user":{"login":"J-Shep","id":6353342,"avatar_url":"https://avatars.githubusercontent.com/u/6353342?v=3","gravatar_id":"","url":"https://api.github.com/users/J-Shep","html_url":"https://github.com/J-Shep","followers_url":"https://api.github.com/users/J-Shep/followers","following_url":"https://api.github.com/users/J-Shep/following{/other_user}","gists_url":"https://api.github.com/users/J-Shep/gists{/gist_id}","starred_url":"https://api.github.com/users/J-Shep/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/J-Shep/subscriptions","organizations_url":"https://api.github.com/users/J-Shep/orgs","repos_url":"https://api.github.com/users/J-Shep/repos","events_url":"https://api.github.com/users/J-Shep/events{/privacy}","received_events_url":"https://api.github.com/users/J-Shep/received_events","type":"User","site_admin":false},"created_at":"2015-07-28T18:20:02Z","updated_at":"2015-07-28T18:20:02Z","body":"When you've loaded saved game X:\r\n1) CorsixTH will begin recording a new black box replay, marking for deletion any previously referenced black box replay: by making TheApp.black_box_replay reference a new Replay object, giving this Replay object the current game state for its prior_game_state field and then telling it to start recording input events.\r\n2) Lets say an autosave occurs before you create saved game Y: so CorsixTH will repeat step 1 this time creating a fresh black box replay for the this new autosave and discarding the blackbox replay for savegame X.\r\n3) Then you create saved game Y, so CorsixTH will repeat step 1 again.\r\n4) Now you continue playing and as you play TheApp will record each SDL input event in:\r\n>> TheApp.black_box_replay.events{1:{time, playback_callback}, 2: time, playback_callback} etc}\r\n\r\nEach event is recorded before its executed and could potentially cause a Lua error. An event's playback_callback will simply be its App:on...() handling callback with its occurrence parameters.\r\n5) Then before any new saved games are created an event handled by a call to one of TheApp's SDL event handling callback functions causes a Lua error to occur.\r\n6) TheApp.run() will now begin responding to this Lua error in its CorsixTH executing coroutine, by creating a new saved game for the black box replay: creating this new saved game from the game state table referenced by **TheApp.black_box_replay.prior_game_state** and then persisting this replay by including a reference to its Replay object's table written to the saved game file.\r\n\r\n7) Now a developer wants to reproduce your error so you give them your **black_box.rsav** file to load from their \"load saved game\" menu.\r\n8) When CorsixTH loads this saved game it notices that this saved game's state table doesn't have a nil replay field so after initialising the game state CorsixTH will pause it and the prompt developer user to confirm if they want it to run the replay.\r\n9) The developer clicks yes: so a reference to this Replay object's loaded table is assigned to TheApp.replay, the variable for referencing a replay being recorded/played which isn't the black_box replay.\r\n10) Then CorsixTH begins the replay by calling: **TheApp.replay:play()** making this object create  a SDL countdown timer for the first \"playback\" event's execution delay.\r\n11) This countdown timer expires making SDL call sdl_core.cpp which passes a new replay_timer_expired event to the App class which has a onReplayTimerExpired() handler which in turn calls: TheApp.replay.countdown_timer:onExpired().\r\n12) CountDownTimer:onExpired() replays the event by simply executing TheApp.replay.events[TheApp.replay.pointer].callback. Then incrementing the pointer. Its response finishes by calling TheApp.replay.play() which will be called recursively to reset the countdown timer for triggering the execution of the next playback event until there's no more events when it finish the replay's execution by calling TheApp:onReplayFinished().\r\n13) But because the last replay playback event will be the one which caused the error to occur, the final TheApp.replay:play() call would never be reached for this replay. With this being a black_box.rsav replay the developer and CorsixTH will know that the last replay event will cause an error to occur so CorsixTH can avoid executing this instruction until the developer tells it to allow this this event's Lua error to occur.\r\n\r\nI've created the essential code for recording, playing and persisting replays. Now I need to debug this code.\r\n\r\nI want to make a Busted Lua script to include in my pull request which will make use of replay execution calls to perform a useful runtime test. This way I can find out what the functional requirements will be for making my implementation of game replays support effective integration with Busted Lua script tests.\r\n\r\nI have in mind a Busted script which would use one or more game replays to construct & thoroughly test any room (provided as a parameter) with all its objects  and patients, to see if any Lua error occur."}}