From 9275927cc77efc10b1d5ded4bb04689e7d6b0668 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Thu, 22 Dec 2022 11:41:43 -0800 Subject: [PATCH] Add recorded inputs integration testt --- build_debug_dll.bat | 4 ++ buildsettings.h | 2 +- flight.rdbg | Bin 1482 -> 1847 bytes input_go_down.bin | Bin 0 -> 45144 bytes input_go_up.bin | Bin 0 -> 38874 bytes inputtest.bat | 4 ++ main.c | 108 ++++++++++++++++++++++++++++++++++++++++---- server.c | 36 +++++++++++++-- types.h | 4 ++ 9 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 build_debug_dll.bat create mode 100644 input_go_down.bin create mode 100644 input_go_up.bin create mode 100644 inputtest.bat diff --git a/build_debug_dll.bat b/build_debug_dll.bat new file mode 100644 index 0000000..3503889 --- /dev/null +++ b/build_debug_dll.bat @@ -0,0 +1,4 @@ +@REM for whitebox +call shadergen.bat +set compileopts=/Zi /DDEBUG /DLL /OUT:flight_dll /LD +call build_msvc.bat \ No newline at end of file diff --git a/buildsettings.h b/buildsettings.h index dbaa2fb..1473356 100644 --- a/buildsettings.h +++ b/buildsettings.h @@ -16,7 +16,7 @@ // #define PROFILING // Intensive profiling means profiling a lot of little tiny stuff. Not always enabled because tanks performance -#define INTENSIVE_PROFILING +// #define INTENSIVE_PROFILING // #define DEBUG_RENDERING #define DEBUG_WORLD // #define UNLOCK_ALL diff --git a/flight.rdbg b/flight.rdbg index d36c7a0fe71c984e578f372a0a25c5ac3e79bf16..8a56a64e08ec1e9f7aaa53ade52d05ba34d7030e 100644 GIT binary patch delta 453 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 literal 0 HcmV?d00001 diff --git a/inputtest.bat b/inputtest.bat new file mode 100644 index 0000000..1a718ef --- /dev/null +++ b/inputtest.bat @@ -0,0 +1,4 @@ +set EXECUTABLE=x64\Debug\Flight.exe + +START /b %EXECUTABLE% host=true replay_inputs_from=input_go_up.bin +%EXECUTABLE% replay_inputs_from=input_go_down.bin \ No newline at end of file diff --git a/main.c b/main.c index 7ff8a9d..808d4ff 100644 --- a/main.c +++ b/main.c @@ -60,6 +60,7 @@ typedef struct KeyPressed static KeyPressed keypressed[MAX_KEYDOWN] = {0}; static cpVect mouse_pos = {0}; static FILE *record_inputs_to = NULL; +static FILE *replay_inputs_from = NULL; static bool fullscreened = false; static bool picking_new_boxtype = false; static double exec_time = 0.0; // cosmetic bouncing, network stats @@ -269,6 +270,16 @@ struct SquadMeta squad_meta(enum Squad squad) return (struct SquadMeta){0}; } +static size_t serialized_inputframe_length() +{ + InputFrame frame = {0}; + unsigned char serialized[1024 * 5] = {0}; + SerState ser = init_serializing(&gs, serialized, ARRLEN(serialized), NULL, false); + ser_inputframe(&ser, &frame); + flight_assert(ser_size(&ser) > 1); + return ser_size(&ser); +} + static enum BoxType currently_building() { flight_assert(cur_toolbar_slot >= 0); @@ -514,7 +525,8 @@ static void init(void) printf( "Usage: astris.exe [option]=data , the =stuff is required\n" "host - hosts a server locally if exists in commandline, like `astris.exe host=yes`\n" - "record_inputs_to - records inputs to the file specified"); + "record_inputs_to - records inputs to the file specified\n" + "replay_inputs_from - replays inputs from the file specified\n"); if (sargs_exists("host")) { server_thread_handle = (void *)_beginthread(server, 0, (void *)&server_info); @@ -523,16 +535,32 @@ static void init(void) if (sargs_exists("record_inputs_to")) { const char *filename = sargs_value("record_inputs_to"); + Log("Recording inputs to %s\n", filename); if (filename == NULL) { quit_with_popup("Failed to record inputs, filename not specified", "Failed to record inputs"); } - fopen_s(&record_inputs_to, filename, "wb"); + errno_t error = fopen_s(&record_inputs_to, filename, "wb"); + Log("%d\n", error); if (record_inputs_to == NULL) { quit_with_popup("Failed to open file to record inputs into", "Failed to record inputs"); } } + if (sargs_exists("replay_inputs_from")) + { + const char *filename = sargs_value("replay_inputs_from"); + Log("Replaying inputs from %s\n", filename); + if (filename == NULL) + { + quit_with_popup("Failed to replay inputs, filename not specified", "Failed to replay inputs"); + } + fopen_s(&replay_inputs_from, filename, "rb"); + if (replay_inputs_from == NULL) + { + quit_with_popup("Failed to open file to replay inputs from", "Failed to replay inputs"); + } + } } // audio @@ -1634,11 +1662,8 @@ static void frame(void) if (applied_gamestate_packet) { uint64_t server_current_tick = tick(&gs); - int ticks_should_repredict = (int)predicted_to_tick - (int)server_current_tick; - int healthy_num_ticks_ahead = (int)ceil((((double)peer->roundTripTime + (double)peer->roundTripTimeVariance * CAUTIOUS_MULTIPLIER) / 1000.0) / TIMESTEP) + 6; - int ticks_to_repredict = ticks_should_repredict; if (ticks_should_repredict < healthy_num_ticks_ahead - 1) @@ -1746,8 +1771,7 @@ static void frame(void) } // Create and send input packet, and predict a frame of gamestate - static InputFrame cur_input_frame = { - 0}; // keep across frames for high refresh rate screens + static InputFrame cur_input_frame = {0}; // keep across frames for high refresh rate screens static size_t last_input_committed_tick = 0; { // prepare the current input frame, such that when processed next, @@ -1814,10 +1838,36 @@ static void frame(void) do { // "commit" the input. each input must be on a successive tick. - if (tick(&gs) > last_input_committed_tick) + // if (tick(&gs) > last_input_committed_tick) + while(tick(&gs) > last_input_committed_tick) { - cur_input_frame.tick = tick(&gs); - last_input_committed_tick = tick(&gs); + if (replay_inputs_from != NULL) + { + unsigned char deserialized[2048] = {0}; + flight_assert(ARRLEN(deserialized) >= serialized_inputframe_length()); + + size_t bytes_read = fread(deserialized, 1, serialized_inputframe_length(), replay_inputs_from); + if (bytes_read != serialized_inputframe_length()) + { + // no more inputs in the saved file + flight_assert(myentity() != NULL); + Entity *should_be_medbay = get_entity(&gs, myentity()->currently_inside_of_box); + flight_assert(should_be_medbay != NULL); + flight_assert(should_be_medbay->is_box && should_be_medbay->box_type == BoxMedbay); + exit(0); + } + SerState ser = init_deserializing(&gs, deserialized, serialized_inputframe_length(), false); + SerMaybeFailure maybe_fail = ser_inputframe(&ser, &cur_input_frame); + flight_assert(!maybe_fail.failed); + flight_assert(serialized_inputframe_length() == ser_size(&ser)); + } + else + { + cur_input_frame.tick = last_input_committed_tick + 1; + // cur_input_frame.tick = tick(&gs); + } + + last_input_committed_tick = cur_input_frame.tick; InputFrame *to_push_to = queue_push_element(&input_queue); if (to_push_to == NULL) @@ -1830,8 +1880,40 @@ static void frame(void) *to_push_to = cur_input_frame; + /* + optionally save the current input frame for debugging purposes + ░░░░░▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄░░░░░░░ + ░░░░░█░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄░░░░ + ░░░░█░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█░░░ + ░░░█░░░░░░▄██▀▄▄░░░░░▄▄▄░░░░█░░ + ░▄▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░░█░ + █░▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒░█ + █░▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█ + ░█░▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█░ + ░░█░░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█░░ + ░░░█░░░░██░░▀█▄▄▄█▄▄█▄████░█░░░ + ░░░░█░░░░▀▀▄░█░░░█░█▀██████░█░░ + ░░░░░▀▄░░░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█░░ + ░░░░░░░▀▄▄░▒▒▒▒░░░░░░░░░░▒░░░█░ + ░░░░░░░░░░▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░░░░█░ + ░░░░░░░░░░░░░░▀▄▄▄▄▄░░░░░░░░█░░ + le informative comment + */ + if (record_inputs_to != NULL) + { + unsigned char serialized[2048] = {0}; + SerState ser = init_serializing(&gs, serialized, ARRLEN(serialized), NULL, false); + SerMaybeFailure maybe_fail = ser_inputframe(&ser, &cur_input_frame); + flight_assert(!maybe_fail.failed); + flight_assert(serialized_inputframe_length() == ser_size(&ser)); + size_t written = fwrite(serialized, 1, ser_size(&ser), record_inputs_to); + flight_assert(written == ser_size(&ser)); + } + if (myplayer() != NULL) + { myplayer()->input = cur_input_frame; // for the client side prediction! + } cur_input_frame = (InputFrame){0}; cur_input_frame.take_over_squad = -1; // @Robust make this zero initialized @@ -2456,7 +2538,13 @@ static void frame(void) void cleanup(void) { sargs_shutdown(); + fclose(log_file); + if (record_inputs_to != NULL) + fclose(record_inputs_to); + if (replay_inputs_from != NULL) + fclose(replay_inputs_from); + sg_destroy_pipeline(hueshift_pipeline); ma_mutex_lock(&server_info.info_mutex); diff --git a/server.c b/server.c index 6cddb16..e25e22a 100644 --- a/server.c +++ b/server.c @@ -225,8 +225,11 @@ void server(void *info_raw) if (get_entity(&gs, gs.players[player_slot].entity) == NULL) buffer_to_fill = &throwaway_buffer; - queue_clear(&player_input_queues[player_slot]); - struct ClientToServer received = {.mic_data = buffer_to_fill, .input_data = &player_input_queues[player_slot]}; + Queue new_inputs = {0}; + char new_inputs_data[QUEUE_SIZE_FOR_ELEMENTS(sizeof(InputFrame), INPUT_QUEUE_MAX)] = {0}; + queue_init(&new_inputs, sizeof(InputFrame), new_inputs_data, ARRLEN(new_inputs_data)); + + struct ClientToServer received = {.mic_data = buffer_to_fill, .input_data = &new_inputs}; unsigned char decompressed[MAX_CLIENT_TO_SERVER] = {0}; size_t decompressed_max_len = MAX_CLIENT_TO_SERVER; flight_assert(LZO1X_MEM_DECOMPRESS == 0); @@ -241,6 +244,26 @@ void server(void *info_raw) { Log("Bad packet from client %d | %d %s\n", (int)player_slot, maybe_fail.line, maybe_fail.expression); } + else + { + QUEUE_ITER(&new_inputs, InputFrame, new_input) + { + QUEUE_ITER(&player_input_queues[player_slot], InputFrame, existing_input) + { + if (existing_input->tick == new_input->tick && existing_input->been_processed) + { + new_input->been_processed = true; + } + } + } + queue_clear(&player_input_queues[player_slot]); + QUEUE_ITER(&new_inputs, InputFrame, cur) + { + InputFrame *new_elem = queue_push_element(&player_input_queues[player_slot]); + flight_assert(new_elem != NULL); + *new_elem = *cur; + } + } } else { @@ -291,16 +314,21 @@ void server(void *info_raw) { PROFILE_SCOPE("World Processing") { - CONNECTED_PEERS(enet_host, cur) + CONNECTED_PEERS(enet_host, cur_peer) { - int this_player_index = (int)(int64_t)cur->data; + int this_player_index = (int)(int64_t)cur_peer->data; QUEUE_ITER(&player_input_queues[this_player_index], InputFrame, cur) { if (cur->tick == tick(&gs)) { gs.players[this_player_index].input = *cur; + cur->been_processed = true; break; } + if (cur->tick < tick(&gs) && !cur->been_processed) + { + Log("Did not process input from client %d %llu ticks ago!\n", this_player_index,tick(&gs) - cur->tick); + } } } diff --git a/types.h b/types.h index e63df02..9754655 100644 --- a/types.h +++ b/types.h @@ -232,6 +232,9 @@ enum ScannerPointKind typedef struct InputFrame { uint64_t tick; + + bool been_processed; // not serialized, used by server just to keep track of what inputs have been processed + cpVect movement; double rotation; @@ -511,6 +514,7 @@ SerState init_serializing(GameState *gs, unsigned char *bytes, size_t max_size, SerState init_deserializing(GameState *gs, unsigned char *bytes, size_t max_size, bool from_disk); SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s); SerMaybeFailure ser_client_to_server(SerState *ser, ClientToServer *msg); +SerMaybeFailure ser_inputframe(SerState *ser, InputFrame *i); // entities bool is_burning(Entity *missile);