diff --git a/src/bflib_datetm.cpp b/src/bflib_datetm.cpp index 853b785b04..d90049fe56 100644 --- a/src/bflib_datetm.cpp +++ b/src/bflib_datetm.cpp @@ -58,7 +58,7 @@ void initial_time_point() game.process_turn_time = 1.0; // Begin initial turn as soon as possible (like original game) } -long double get_time_tick_ns() +int64_t get_time_tick_ns() { return TimeTickNs; } @@ -95,22 +95,6 @@ int get_trigger_time_measurement_fps(struct TriggerTimeMeasurement *trigger) return cnt; } - -float get_delta_time() -{ - // Allow frame skip to work correctly when delta time is enabled - if ( (game.frame_skip != 0) && ((get_gameturn() % game.frame_skip) != 0)) { - return 1.0; - } - long double frame_time_in_nanoseconds = std::chrono::duration_cast(TimeNow - delta_time_previous_timepoint).count(); - delta_time_previous_timepoint = TimeNow; - float calculated_delta_time = (frame_time_in_nanoseconds/1000000000.0) * turns_per_second; - if (calculated_delta_time > 1.0) { // Fix for when initially loading the map, frametime takes too long. Possibly other circumstances too. - calculated_delta_time = 1.0; - } - return calculated_delta_time; -} - void frametime_set_all_measurements_to_be_displayed() { // Display the frametime of the previous frame only, not the current frametime. Drawing "frametime_current" is a bad idea because frametimes are displayed on screen half-way through the rest of the measurements. diff --git a/src/bflib_datetm.h b/src/bflib_datetm.h index 41169ebeed..ce6e0d067e 100644 --- a/src/bflib_datetm.h +++ b/src/bflib_datetm.h @@ -95,11 +95,10 @@ struct FrametimeMeasurements { extern int debug_display_frametime; extern void initial_time_point(); -extern long double get_time_tick_ns(); +extern int64_t get_time_tick_ns(); extern void frametime_start_measurement(int frametime_kind); extern void frametime_end_measurement(int frametime_kind); extern void framerate_measurement_capture(int framerate_kind); -extern float get_delta_time(); extern struct FrametimeMeasurements frametime_measurements; diff --git a/src/engine_render.c b/src/engine_render.c index ba09572224..ef18318636 100644 --- a/src/engine_render.c +++ b/src/engine_render.c @@ -534,17 +534,17 @@ extern float interpolate_time; // main.cpp float interpolate(float previous, float current) { - if (is_feature_on(Ft_DeltaTime) == false || game.frame_skip > 0) { + if (! is_feature_on(Ft_DeltaTime)) return current; - } + return LbLerp(previous, current, interpolate_time); } float interpolate_angle(float previous, float current) { - if (is_feature_on(Ft_DeltaTime) == false || game.frame_skip > 0) { + if (! is_feature_on(Ft_DeltaTime)) return current; - } + return lerp_angle(previous, current, interpolate_time); } diff --git a/src/front_input.c b/src/front_input.c index a39d88a234..5bfd7055cc 100644 --- a/src/front_input.c +++ b/src/front_input.c @@ -98,6 +98,8 @@ struct GuiLayer gui_layer = {GuiLayer_Default}; TbBool first_person_see_item_desc = false; +static TbBool move_camera_this_turn; + long old_mx; long old_my; @@ -2143,10 +2145,6 @@ static short get_map_action_inputs(void) } } -// TODO: Might want to initiate this in main() and pass a reference to it -// rather than using this global variable. But this works. -int global_frameskipTurn = 0; - static void get_isometric_or_front_view_mouse_inputs(struct Packet *pckt,int rotate_pressed,TbBool mods_used) { // Reserve the scroll wheel for the resurrect and transfer creature specials @@ -2185,13 +2183,8 @@ static void get_isometric_or_front_view_mouse_inputs(struct Packet *pckt,int rot } } // Only pan the camera as often as normal despite frameskip - if (game.frame_skip > 0) - { - TbBool moveTheCamera = (global_frameskipTurn == 0); - global_frameskipTurn++; - if (global_frameskipTurn > game.frame_skip) global_frameskipTurn = 0; - if (!moveTheCamera) return; - } + if (! move_camera_this_turn) + return; // Camera Panning : mouse at window edge scrolling feature if (!LbIsMouseActive()) { @@ -2255,15 +2248,7 @@ static void get_isometric_view_nonaction_inputs(void) get_isometric_or_front_view_mouse_inputs(packet, rotate_pressed, no_mods); // Only update the camera as often as normal despite frameskip - TbBool moveTheCamera = true; - if (game.frame_skip > 0) - { - moveTheCamera = (global_frameskipTurn == 0); - global_frameskipTurn++; - if (global_frameskipTurn > game.frame_skip) - global_frameskipTurn = 0; - } - if (moveTheCamera) + if (move_camera_this_turn) { if (rotate_pressed) { @@ -2346,15 +2331,7 @@ static void get_front_view_nonaction_inputs(void) get_isometric_or_front_view_mouse_inputs(pckt,rotate_pressed,no_mods); // Only update the camera as often as normal despite frameskip - TbBool moveTheCamera = true; - if (game.frame_skip > 0) - { - moveTheCamera = (global_frameskipTurn == 0); - global_frameskipTurn++; - if (global_frameskipTurn > game.frame_skip) - global_frameskipTurn = 0; - } - if (moveTheCamera) + if (move_camera_this_turn) { if (rotate_pressed) { @@ -2870,6 +2847,8 @@ static TbBool active_menu_functions_while_paused(void) */ static short get_inputs(void) { + move_camera_this_turn = game.frame_skip == 0 || game.play_gameturn % game.frame_skip == 0; + if ((game.mode_flags & MFlg_IsDemoMode) != 0) { SYNCDBG(5,"Starting for demo mode"); diff --git a/src/frontend.cpp b/src/frontend.cpp index 68fe8c200c..5f82020d94 100644 --- a/src/frontend.cpp +++ b/src/frontend.cpp @@ -97,7 +97,6 @@ extern "C" { #endif extern long double last_draw_completed_time; -long double get_time_tick_ns(); /******************************************************************************/ TbClockMSec gui_message_timeout = 0; char gui_message_text[TEXT_BUFFER_LENGTH]; diff --git a/src/main.cpp b/src/main.cpp index ba554b83a3..9b0da041f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3261,7 +3261,7 @@ short display_should_be_updated_this_turn(void) if ( (game.turns_fastforward == 0) && (!game.packet_loading_in_progress) ) { find_frame_rate(); - if ( (game.frame_skip == 0) || ((get_gameturn() % game.frame_skip) == 0)) + if ( is_feature_on(Ft_DeltaTime) || (game.frame_skip == 0) || ((get_gameturn() % game.frame_skip) == 0)) return true; } else if ( ((get_gameturn() & 0x3F)==0) || @@ -3421,12 +3421,32 @@ static bool use_delta_time() return is_feature_on(Ft_DeltaTime) || network_is_active(); } +static void update_frontend_delta_time() +{ + static int64_t prev = 0; + const int64_t now = get_time_tick_ns(); + const int64_t ns = now - prev; + prev = now; + const long double dt = ns / 1e9L * turns_per_second; + game.delta_time = min(max(dt, 0.L), 1.L); +} + static void update_gameplay_delta_time() { if (use_delta_time()) { - long double process_delta_time = get_delta_time() * multiplayer_clock_adjust; - time_since_last_draw += process_delta_time; - game.process_turn_time += process_delta_time; + static int64_t prev = 0; + const int64_t now = get_time_tick_ns(); + const int64_t ns = now - prev; + prev = now; + + const long double dt = min(max(ns / 1e9L * turns_per_second, 0.L), 1.L); + + game.process_turn_time += dt * multiplayer_clock_adjust * max(game.frame_skip, 1); + + // This sets game.delta_time, which is used to pace locally-displayed + // things (eg. tooltip scroll speed). It should not be affected by + // multiplayer clock adjustment or frameskip. + time_since_last_draw += dt; } else { // Set to 1 so that these variables don't affect anything. (if something is multiplied by 1 it doesn't change) time_since_last_draw = 1; @@ -3437,6 +3457,11 @@ static void update_gameplay_delta_time() static void gameplay_loop_draw() { + update_gameplay_delta_time(); + + if (game.process_turn_time > 1.0 && time_since_last_draw < 1.0) + do_draw = false; + if (is_feature_on(Ft_DeltaTime) && ! network_is_active()) { frametime_start_measurement(Frametime_Sleep); @@ -3546,8 +3571,8 @@ static void gameplay_loop_logic() exchange_packets(); update_gameplay_delta_time(); - if (game.process_turn_time > 2.0) - game.process_turn_time = 2.0; + if (game.process_turn_time > turns_per_second + 1) + game.process_turn_time = turns_per_second + 1; // Adjust client time scaling if (netstate.my_id != SERVER_ID && network_is_active()) @@ -3619,9 +3644,11 @@ extern "C" void network_yield_waiting_gameplay_packets() { do_draw = true; poll_inputs(); + gameplay_loop_draw(); update_gameplay_delta_time(); - if (game.process_turn_time <= 1.0 || time_since_last_draw > 1.0) - gameplay_loop_draw(); + // Reduce game speed during lag spikes. + if (game.process_turn_time > 2.0) + game.process_turn_time = 2.0; } extern "C" void update_velocity(void); @@ -3630,7 +3657,7 @@ extern "C" void fronttorture_update(void); extern "C" void network_yield_draw_frontend() { - game.delta_time = get_delta_time(); + update_frontend_delta_time(); if (frontend_menu_state == FeSt_NETLAND_VIEW) { check_mouse_scroll(); update_velocity(); @@ -3943,7 +3970,7 @@ static TbBool wait_at_frontend(void) fade_palette_in = 0; } else { if (is_feature_on(Ft_DeltaTime) == true && should_use_delta_time_on_menu()) { - game.delta_time = get_delta_time(); + update_frontend_delta_time(); } else { int32_t frame_time; frame_time = max(1, 1000 / turns_per_second);