From 2ecc4c4a07ca99cc301d0815e31f86ce1f307452 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Mon, 9 Jan 2017 19:09:34 +0800 Subject: [PATCH] Remove call to window_close(Game_wind) when stopping demo playback Replace call to window_close(Game_wind) with returning window_event_result::close to game_handler. Applies to whenever newdemo_stop_playback() is called. Closing a window within its handler is problematic - it can result in an unstable state. --- common/main/newdemo.h | 7 ++-- similar/main/game.cpp | 9 +++-- similar/main/gamecntl.cpp | 16 ++++---- similar/main/newdemo.cpp | 83 +++++++++++++++++++++++++-------------- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/common/main/newdemo.h b/common/main/newdemo.h index 1aa5f5552..4db162fd3 100644 --- a/common/main/newdemo.h +++ b/common/main/newdemo.h @@ -28,6 +28,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #ifdef __cplusplus #include "physfsx.h" #include "fwd-object.h" +#include "fwd-window.h" class object_signature_t; @@ -140,13 +141,13 @@ extern void newdemo_record_secret_exit_blown(int truth); // Functions called during playback process... extern void newdemo_object_move_all(); -extern void newdemo_playback_one_frame(); +extern window_event_result newdemo_playback_one_frame(); #ifdef dsx namespace dsx { -extern void newdemo_goto_end(int to_rewrite); +extern window_event_result newdemo_goto_end(int to_rewrite); } #endif -extern void newdemo_goto_beginning(); +extern window_event_result newdemo_goto_beginning(); // Interactive functions to control playback/record; #ifdef dsx diff --git a/similar/main/game.cpp b/similar/main/game.cpp index f0a09a780..a8c38f897 100644 --- a/similar/main/game.cpp +++ b/similar/main/game.cpp @@ -1485,9 +1485,12 @@ window_event_result GameProcessFrame() flash_frame(); - if ( Newdemo_state == ND_STATE_PLAYBACK ) { - newdemo_playback_one_frame(); - if ( Newdemo_state != ND_STATE_PLAYBACK ) { + if ( Newdemo_state == ND_STATE_PLAYBACK ) + { + result = std::max(newdemo_playback_one_frame(), result); + if ( Newdemo_state != ND_STATE_PLAYBACK ) + { + Assert(result == window_event_result::close); return window_event_result::close; // Go back to menu } } diff --git a/similar/main/gamecntl.cpp b/similar/main/gamecntl.cpp index 622e65901..70aafbb86 100644 --- a/similar/main/gamecntl.cpp +++ b/similar/main/gamecntl.cpp @@ -458,7 +458,7 @@ static int HandleDeathInput(const d_event &event) return 0; } -static int HandleDemoKey(int key) +static window_event_result HandleDemoKey(int key) { switch (key) { KEY_MAC(case KEY_COMMAND+KEY_1:) @@ -487,6 +487,7 @@ static int HandleDemoKey(int key) break; } newdemo_stop_playback(); + return window_event_result::close; break; case KEY_UP: Newdemo_vcr_state = ND_STATE_PLAYBACK; @@ -503,10 +504,10 @@ static int HandleDemoKey(int key) Newdemo_vcr_state = ND_STATE_ONEFRAMEFORWARD; break; case KEY_CTRLED + KEY_RIGHT: - newdemo_goto_end(0); + return newdemo_goto_end(0); break; case KEY_CTRLED + KEY_LEFT: - newdemo_goto_beginning(); + return newdemo_goto_beginning(); break; KEY_MAC(case KEY_COMMAND+KEY_P:) @@ -574,10 +575,10 @@ static int HandleDemoKey(int key) #endif default: - return 0; + return window_event_result::ignored; } - return 1; + return window_event_result::handled; } #if defined(DXX_BUILD_DESCENT_II) @@ -1893,8 +1894,9 @@ window_event_result ReadControls(const d_event &event) } else if (Newdemo_state == ND_STATE_PLAYBACK ) { - if (HandleDemoKey(key)) - return window_event_result::handled; + auto r = HandleDemoKey(key); + if (r != window_event_result::ignored) + return r; } else { diff --git a/similar/main/newdemo.cpp b/similar/main/newdemo.cpp index f287d1061..3aa2c98a1 100644 --- a/similar/main/newdemo.cpp +++ b/similar/main/newdemo.cpp @@ -3269,7 +3269,7 @@ static int newdemo_read_frame_information(int rewrite) } } -void newdemo_goto_beginning() +window_event_result newdemo_goto_beginning() { //if (nd_playback_v_framecount == 0) // return; @@ -3283,10 +3283,13 @@ void newdemo_goto_beginning() newdemo_stop_playback(); Newdemo_vcr_state = ND_STATE_PAUSED; nd_playback_v_at_eof = 0; + + // check if we stopped playback + return Newdemo_state == ND_STATE_NORMAL ? window_event_result::close : window_event_result::handled; } namespace dsx { -void newdemo_goto_end(int to_rewrite) +window_event_result newdemo_goto_end(int to_rewrite) { short frame_length=0, byte_count=0, bshort=0; sbyte level=0, bbyte=0, c=0, cloaked=0; @@ -3302,7 +3305,7 @@ void newdemo_goto_end(int to_rewrite) nm_messagebox( NULL, 1, TXT_OK, "%s\n%s\n%s", TXT_CANT_PLAYBACK, TXT_LEVEL_CANT_LOAD, TXT_DEMO_OLD_CORRUPT ); Current_mission.reset(); newdemo_stop_playback(); - return; + return window_event_result::close; } if (level != Current_level_num) LoadLevel(level,1); @@ -3336,7 +3339,7 @@ void newdemo_goto_end(int to_rewrite) } if (to_rewrite) - return; + return window_event_result::handled; PHYSFSX_fseek(infile, -12, SEEK_END); nd_read_short(&frame_length); @@ -3435,7 +3438,7 @@ void newdemo_goto_end(int to_rewrite) } if (to_rewrite) - return; + return window_event_result::handled; PHYSFSX_fseek(infile, loc, SEEK_SET); } @@ -3446,11 +3449,11 @@ void newdemo_goto_end(int to_rewrite) Newdemo_vcr_state = ND_STATE_PLAYBACK; newdemo_read_frame_information(0); // then the frame information Newdemo_vcr_state = ND_STATE_PAUSED; - return; + return window_event_result::handled; } } -static void newdemo_back_frames(int frames) +static window_event_result newdemo_back_frames(int frames) { short last_frame_length; for (int i = 0; i < frames; i++) @@ -3461,7 +3464,7 @@ static void newdemo_back_frames(int frames) if (!nd_playback_v_at_eof && newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); - return; + return window_event_result::close; } if (nd_playback_v_at_eof) nd_playback_v_at_eof = 0; @@ -3471,6 +3474,7 @@ static void newdemo_back_frames(int frames) PHYSFS_seek(infile, PHYSFS_tell(infile) + 8 - last_frame_length); } + return window_event_result::handled; } /* @@ -3483,13 +3487,13 @@ static void newdemo_back_frames(int frames) * at. */ -static void interpolate_frame(fix d_play, fix d_recorded) +static window_event_result interpolate_frame(fix d_play, fix d_recorded) { fix factor; static fix InterpolStep = fl2f(.01); if (nd_playback_v_framecount < 1) - return; + return window_event_result::ignored; factor = fixdiv(d_play, d_recorded); if (factor > F1_0) @@ -3501,7 +3505,7 @@ static void interpolate_frame(fix d_play, fix d_recorded) Newdemo_vcr_state = ND_STATE_PAUSED; if (newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); - return; + return window_event_result::close; } InterpolStep -= FrameTime; @@ -3566,21 +3570,27 @@ static void interpolate_frame(fix d_play, fix d_recorded) // with Highest_object_index and the object array (previously rendered // objects, etc....) - newdemo_back_frames(1); - newdemo_back_frames(1); + auto result = newdemo_back_frames(1); + result = std::max(newdemo_back_frames(1), result); if (newdemo_read_frame_information(0) == -1) + { newdemo_stop_playback(); + result = window_event_result::close; + } Newdemo_vcr_state = ND_STATE_PLAYBACK; std::copy(cur_objs.begin(), cur_objs.begin() + num_cur_objs, Objects.begin()); Objects.set_count(num_cur_objs); + + return result; } -void newdemo_playback_one_frame() +window_event_result newdemo_playback_one_frame() { int frames_back; static fix base_interpol_time = 0; static fix d_recorded = 0; + auto result = window_event_result::handled; range_for (auto &i, Players) { @@ -3593,7 +3603,7 @@ void newdemo_playback_one_frame() } if (Newdemo_vcr_state == ND_STATE_PAUSED) // render a frame or not - return; + return window_event_result::ignored; Control_center_destroyed = 0; Countdown_seconds_left = -1; @@ -3603,10 +3613,9 @@ void newdemo_playback_one_frame() { const int level = Current_level_num; if (nd_playback_v_framecount == 0) - return; + return window_event_result::ignored; else if ((Newdemo_vcr_state == ND_STATE_REWINDING) && (nd_playback_v_framecount < 10)) { - newdemo_goto_beginning(); - return; + return newdemo_goto_beginning(); } if (Newdemo_vcr_state == ND_STATE_REWINDING) frames_back = 10; @@ -3615,14 +3624,14 @@ void newdemo_playback_one_frame() if (nd_playback_v_at_eof) { PHYSFS_seek(infile, PHYSFS_tell(infile) + (shareware ? -2 : +11)); } - newdemo_back_frames(frames_back); + result = newdemo_back_frames(frames_back); if (level != Current_level_num) newdemo_pop_ctrlcen_triggers(); if (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) { if (level != Current_level_num) - newdemo_back_frames(1); + result = std::max(newdemo_back_frames(1), result); Newdemo_vcr_state = ND_STATE_PAUSED; } } @@ -3636,7 +3645,10 @@ void newdemo_playback_one_frame() if (nd_playback_v_at_eof) Newdemo_vcr_state = ND_STATE_PAUSED; else + { newdemo_stop_playback(); + result = window_event_result::close; + } break; } } @@ -3649,12 +3661,18 @@ void newdemo_playback_one_frame() const int level = Current_level_num; if (newdemo_read_frame_information(0) == -1) { if (!nd_playback_v_at_eof) + { newdemo_stop_playback(); + result = window_event_result::close; + } } if (level != Current_level_num) { if (newdemo_read_frame_information(0) == -1) { if (!nd_playback_v_at_eof) + { newdemo_stop_playback(); + result = window_event_result::close; + } } } Newdemo_vcr_state = ND_STATE_PAUSED; @@ -3703,11 +3721,14 @@ void newdemo_playback_one_frame() const int level = Current_level_num; if (newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); - return; + return window_event_result::close; } if (level != Current_level_num) { if (newdemo_read_frame_information(0) == -1) + { newdemo_stop_playback(); + result = window_event_result::close; + } break; } @@ -3732,24 +3753,25 @@ void newdemo_playback_one_frame() } d_play = nd_playback_total - base_interpol_time; - interpolate_frame(d_play, d_recorded); - return; + return std::max(interpolate_frame(d_play, d_recorded), result); } else { if (newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); - return; + return window_event_result::close; } if (nd_playback_v_style == SKIP_PLAYBACK) { while (nd_playback_total > nd_recorded_total) { if (newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); - return; + return window_event_result::close; } } } } } + + return result; } void newdemo_start_recording() @@ -4083,8 +4105,12 @@ void newdemo_start_playback(const char * filename) HUD_clear_messages(); if (!Game_wind) hide_menus(); - newdemo_playback_one_frame(); // this one loads new level - newdemo_playback_one_frame(); // get all of the objects to renderb game + auto result = newdemo_playback_one_frame(); // this one loads new level + result = std::max(newdemo_playback_one_frame(), result); // get all of the objects to renderb game + + if (result == window_event_result::close) + return; // whoops, there was an error reading the first two frames! Abort! + if (!Game_wind) Game_wind = game_setup(); // create game environment } @@ -4107,9 +4133,6 @@ void newdemo_stop_playback() // Required for the editor obj_relink_all(); - - if (Game_wind) - window_close(Game_wind); // Exit game loop } }