Serialization refactor, FIX BAD RADAR BUG

main
Cameron Murphy Reikes 2 years ago
parent 1fa9e497d1
commit cb661bd98f

Binary file not shown.

@ -1152,28 +1152,6 @@ void update_from(cpBody *body, struct BodyData *data)
cpBodySetAngularVelocity(body, data->angular_velocity);
}
typedef struct SerState
{
unsigned char *bytes;
bool serializing;
size_t cursor; // points to next available byte, is the size of current message after serializing something
size_t max_size;
Entity *for_player;
size_t max_entity_index; // for error checking
bool write_varnames;
bool save_or_load_from_disk;
// output
uint32_t version;
uint32_t git_release_tag;
} SerState;
typedef struct SerMaybeFailure
{
bool failed;
int line;
const char *expression;
} SerMaybeFailure;
const static SerMaybeFailure ser_ok = {0};
#define SER_ASSERT(cond) \
if (!(cond)) \
@ -1424,6 +1402,7 @@ SerMaybeFailure ser_player(SerState *ser, Player *p)
SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
{
SER_VAR(&e->no_save_to_disk);
SER_VAR(&e->always_visible);
SER_VAR(&e->generation);
SER_MAYBE_RETURN(ser_f(ser, &e->damage));
@ -1561,7 +1540,6 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
SER_VAR(&e->owning_squad);
SER_VAR(&e->always_visible);
SER_MAYBE_RETURN(ser_entityid(ser, &e->next_box));
SER_MAYBE_RETURN(ser_entityid(ser, &e->prev_box));
SER_VAR(&e->compass_rotation);
@ -1853,6 +1831,14 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
return ser_ok;
}
// On serialize:
// 1. put struct's data into bytes, for a specific player or not, and to disk or not
// 2. output the number of bytes it took to put the struct's data into bytes
// On deserialize:
// 1. put bytes into a struct for a specific player, from disk or not
// 2. perform operations on those bytes to initialize the struct
// for_this_player can be null then the entire world will be sent
bool server_to_client_serialize(struct ServerToClient *msg, unsigned char *bytes, size_t *out_len, size_t max_len, Entity *for_this_player, bool to_disk)
{
@ -1965,60 +1951,47 @@ SerMaybeFailure ser_client_to_server(SerState *ser, ClientToServer *msg)
}
return ser_ok;
}
size_t ser_size(SerState *ser)
{
flight_assert(ser->cursor > 0); // if this fails, haven't serialized anything yet!
return ser->cursor + 1;
}
bool client_to_server_serialize(GameState *gs, struct ClientToServer *msg, unsigned char *bytes, size_t *out_len, size_t max_len)
SerState init_serializing(GameState *gs, unsigned char *bytes, size_t max_size, Entity *for_player, bool to_disk)
{
SerState ser = (SerState){
bool write_varnames = to_disk;
#ifdef WRITE_VARNAMES
write_varnames = true;
#endif
return (SerState){
.bytes = bytes,
.serializing = true,
.cursor = 0,
.max_size = max_len,
.for_player = NULL,
.max_entity_index = gs->cur_next_entity,
.max_size = max_size,
.for_player = for_player,
.version = VMax - 1,
.save_or_load_from_disk = to_disk,
.write_varnames = write_varnames,
};
#ifdef WRITE_VARNAMES
ser.write_varnames = true;
#endif
SerMaybeFailure result = ser_client_to_server(&ser, msg);
*out_len = ser.cursor + 1; // see other comment for server to client
if (result.failed)
{
Log("Failed to serialize client to server because %s was false, line %d\n", result.expression, result.line);
return false;
}
else
{
return true;
}
}
bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, unsigned char *bytes, size_t max_len)
SerState init_deserializing(GameState *gs, unsigned char *bytes, size_t max_size, bool from_disk)
{
SerState servar = (SerState){
bool has_varnames = from_disk;
#ifdef WRITE_VARNAMES
has_varnames = true;
#endif
return (SerState){
.bytes = bytes,
.serializing = false,
.cursor = 0,
.max_size = max_len,
.max_entity_index = gs->cur_next_entity,
.save_or_load_from_disk = false,
.max_size = max_size,
.max_entity_index = gs->max_entities,
.for_player = NULL,
.save_or_load_from_disk = from_disk,
.write_varnames = has_varnames,
};
#ifdef WRITE_VARNAMES
servar.write_varnames = true;
#endif
SerState *ser = &servar;
SerMaybeFailure result = ser_client_to_server(ser, msg);
if (result.failed)
{
Log("Failed to deserialize client to server on line %d because of %s\n", result.line, result.expression);
return false;
}
else
{
return true;
}
}
// filter func null means everything is ok, if it's not null and returns false, that means
@ -2434,10 +2407,19 @@ void create_initial_world(GameState *gs)
entity_set_pos(grid, cpv(1.5, 0.0));
BOX_AT_TYPE(grid, cpv(0.0, 0.0), BoxExplosive);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE, 0.0), BoxScanner);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE, BOX_SIZE), BoxSolarPanel);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE, BOX_SIZE * 2.0), BoxSolarPanel);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE*2.0, 0.0), BoxSolarPanel);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE*3.0, 0.0), BoxSolarPanel);
entity_ensure_in_orbit(gs, grid);
}
{
Entity *grid = new_entity(gs);
grid_create(gs, grid);
entity_set_pos(grid, cpv(0.0, 10.0));
BOX_AT_TYPE(grid, cpv(0.0, 0.0), BoxHullpiece);
entity_ensure_in_orbit(gs, grid);
}
#endif
#if 0 // merge box

@ -14,11 +14,11 @@
#define SOKOL_IMPL
#define SOKOL_D3D11
#include "sokol_app.h"
#include "sokol_args.h"
#include "sokol_gfx.h"
#include "sokol_glue.h"
#include "sokol_gp.h"
#include "sokol_time.h"
#include "sokol_args.h"
#pragma warning(default : 33010)
#pragma warning(disable : 6262) // warning about using a lot of stack, lol that's how stb image is
#define STB_IMAGE_IMPLEMENTATION
@ -59,17 +59,17 @@ typedef struct KeyPressed
} KeyPressed;
static KeyPressed keypressed[MAX_KEYDOWN] = {0};
static cpVect mouse_pos = {0};
static FILE * record_inputs_to = NULL;
static FILE *record_inputs_to = NULL;
static bool fullscreened = false;
static bool picking_new_boxtype = false;
static double exec_time = 0.0; // cosmetic bouncing, network stats
static float iTime = 0.0; // fmodded to 1000, shader trick http://the-witness.net/news/2022/02/a-shader-trick/
static float iTime = 0.0; // fmodded to 1000, shader trick http://the-witness.net/news/2022/02/a-shader-trick/
// for network statistics, printed to logs with F3
static uint64_t total_bytes_sent = 0;
static uint64_t total_bytes_received = 0;
static double dilating_time_factor = 1.0;
static bool build_pressed = false;
static double dilating_time_factor = 1.0;
static double time_to_process = 0.0;
static bool interact_pressed = false;
#define MAX_MOUSEBUTTON (SAPP_MOUSEBUTTON_MIDDLE + 1)
@ -80,6 +80,7 @@ typedef struct MousePressed
uint64_t frame;
} MousePressed;
static MousePressed mousepressed[MAX_MOUSEBUTTON] = {0};
static EntityID maybe_inviting_this_player = {0};
static EntityID hovering_this_player = {0};
bool confirm_invite_this_player = false;
@ -511,23 +512,23 @@ static void init(void)
// commandline
{
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"
);
if(sargs_exists("host"))
"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");
if (sargs_exists("host"))
{
server_thread_handle = (void *)_beginthread(server, 0, (void *)&server_info);
sapp_set_window_title("Flight Hosting");
}
if(sargs_exists("record_inputs_to"))
if (sargs_exists("record_inputs_to"))
{
const char *filename = sargs_value("record_inputs_to");
if(filename == NULL){
if (filename == NULL)
{
quit_with_popup("Failed to record inputs, filename not specified", "Failed to record inputs");
}
fopen_s(&record_inputs_to, filename, "wb");
if(record_inputs_to == NULL)
if (record_inputs_to == NULL)
{
quit_with_popup("Failed to open file to record inputs into", "Failed to record inputs");
}
@ -1585,8 +1586,12 @@ static void frame(void)
{
PROFILE_SCOPE("Deserializing data")
{
server_to_client_deserialize(&msg, decompressed,
decompressed_max_len, false);
SerState ser = init_deserializing(&gs, decompressed, decompressed_max_len, false);
SerMaybeFailure maybe_fail = ser_server_to_client(&ser, &msg);
if (maybe_fail.failed)
{
Log("Failed to deserialize game state packet line %d %s\n", maybe_fail.line, maybe_fail.expression);
}
applied_gamestate_packet = true;
}
my_player_index = msg.your_player;
@ -1857,9 +1862,10 @@ static void frame(void)
.input_data = &input_queue,
};
unsigned char serialized[MAX_CLIENT_TO_SERVER] = {0};
size_t out_len = 0;
if (client_to_server_serialize(&gs, &to_send, serialized, &out_len,
MAX_CLIENT_TO_SERVER))
SerState ser = init_serializing(&gs, serialized, MAX_CLIENT_TO_SERVER, NULL, false);
SerMaybeFailure maybe_fail = ser_client_to_server(&ser, &to_send);
size_t out_len = ser_size(&ser);
if (!maybe_fail.failed)
{
unsigned char compressed[MAX_CLIENT_TO_SERVER] = {0};
char lzo_working_mem[LZO1X_1_MEM_COMPRESS] = {0};
@ -1885,7 +1891,7 @@ static void frame(void)
}
else
{
Log("Failed to serialize client to server!\n");
Log("Failed to serialize client to server: %d %s\n", maybe_fail.line, maybe_fail.expression);
}
ma_mutex_unlock(&send_packets_mutex);
}
@ -2166,10 +2172,10 @@ static void frame(void)
{
sgp_set_image(0, (sg_image){0});
lightning_uniforms_t uniform = {
.iTime = iTime,
.iTime = iTime,
};
sgp_set_uniform(&uniform, sizeof(uniform));
draw_color_rect_centered(entity_pos(b), BOX_SIZE*2.0);
draw_color_rect_centered(entity_pos(b), BOX_SIZE * 2.0);
sgp_reset_image(0);
}
}
@ -2254,7 +2260,7 @@ static void frame(void)
sgp_set_image(0, image_radardot);
for (int i = 0; i < SCANNER_MAX_POINTS; i++)
{
if (b->scanner_points[i].x != 0 && b->scanner_points[i].y != 0)
if (b->scanner_points[i].x != 0 || b->scanner_points[i].y != 0)
{
struct ScannerPoint point = b->scanner_points[i];
switch (point.kind)
@ -2593,8 +2599,7 @@ sapp_desc sokol_main(int argc, char *argv[])
{
sargs_setup(&(sargs_desc){
.argc = argc,
.argv = argv
});
.argv = argv});
stm_setup();
ma_mutex_init(&server_info.info_mutex);

@ -22,6 +22,12 @@
#include "profiling.h"
static void panicquit()
{
flight_assert(false);
exit(-1);
}
// started in a thread from host
void server(void *info_raw)
{
@ -39,7 +45,6 @@ void server(void *info_raw)
gs.server_side_computing = true;
Log("Allocated %zu bytes for entities\n", entities_size);
create_initial_world(&gs);
// inputs
@ -56,9 +61,6 @@ void server(void *info_raw)
OpusEncoder *player_encoders[MAX_PLAYERS] = {0};
OpusDecoder *player_decoders[MAX_PLAYERS] = {0};
#ifdef DEBUG_WORLD
world_save_name = NULL;
#endif
if (world_save_name != NULL)
{
size_t read_game_data_buffer_size = entities_size;
@ -76,13 +78,18 @@ void server(void *info_raw)
if (actual_length <= 1)
{
Log("Could only read %zu bytes, error: errno %d\n", actual_length, errno);
exit(-1);
panicquit();
}
Log("Read %zu bytes from save file\n", actual_length);
ServerToClient msg = (ServerToClient){
.cur_gs = &gs,
};
server_to_client_deserialize(&msg, read_game_data, actual_length, true);
SerState ser = init_deserializing(&gs, read_game_data, actual_length, true);
SerMaybeFailure maybe_fail = ser_server_to_client(&ser, &msg);
if (maybe_fail.failed)
{
Log("Failed to deserialize game world from save file: %d %s\n", maybe_fail.line, maybe_fail.expression);
}
fclose(file);
}
@ -97,11 +104,10 @@ void server(void *info_raw)
}
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
if (enet_initialize() != 0)
{
fprintf(stderr, "An error occurred while initializing ENet.\n");
exit(-1);
panicquit();
}
ENetAddress address;
@ -122,7 +128,7 @@ void server(void *info_raw)
{
fprintf(stderr,
"An error occurred while trying to create an ENet server host.\n");
exit(-1);
panicquit();
}
Log("Serving on port %d...\n", SERVER_PORT);
@ -229,9 +235,11 @@ void server(void *info_raw)
if (return_value == LZO_E_OK)
{
if (!client_to_server_deserialize(&gs, &received, decompressed, decompressed_max_len))
SerState ser = init_deserializing(&gs, decompressed, decompressed_max_len, false);
SerMaybeFailure maybe_fail = ser_client_to_server(&ser, &received);
if (maybe_fail.failed)
{
Log("Bad packet from client %d\n", (int)player_slot);
Log("Bad packet from client %d | %d %s\n", (int)player_slot, maybe_fail.line, maybe_fail.expression);
}
}
else
@ -309,8 +317,10 @@ void server(void *info_raw)
ServerToClient msg = (ServerToClient){
.cur_gs = &gs,
};
size_t out_len = 0;
if (server_to_client_serialize(&msg, world_save_buffer, &out_len, entities_size, NULL, true))
SerState ser = init_serializing(&gs, world_save_buffer, entities_size, NULL, true);
SerMaybeFailure maybe_fail = ser_server_to_client(&ser, &msg);
size_t out_len = ser_size(&ser);
if (!maybe_fail.failed)
{
FILE *save_file = NULL;
fopen_s(&save_file, (const char *)world_save_name, "wb");
@ -334,7 +344,7 @@ void server(void *info_raw)
}
else
{
Log("URGENT: FAILED TO SAVE WORLD FILE!\n");
Log("URGENT: FAILED TO SAVE WORLD FILE! Failed at line %d expression %s\n", maybe_fail.line, maybe_fail.expression);
}
}
}
@ -431,13 +441,15 @@ void server(void *info_raw)
.audio_playback_buffer = &buffer_to_play,
};
size_t len = 0;
if (server_to_client_serialize(&to_send, bytes_buffer, &len, MAX_SERVER_TO_CLIENT, this_player_entity, false))
SerState ser = init_serializing(&gs, bytes_buffer, MAX_SERVER_TO_CLIENT, this_player_entity, false);
SerMaybeFailure maybe_fail = ser_server_to_client(&ser, &to_send);
size_t len = ser_size(&ser);
if (!maybe_fail.failed)
{
if (len > MAX_SERVER_TO_CLIENT - 8)
{
Log("Too much data quitting!\n");
exit(-1);
panicquit();
}
size_t compressed_len = 0;

@ -253,6 +253,7 @@ typedef struct Entity
bool exists;
EntityID next_free_entity;
unsigned int generation;
bool always_visible; // always serialized to the player.
bool no_save_to_disk; // stuff generated later on, like player's bodies or space stations that respawn.
@ -310,7 +311,6 @@ typedef struct Entity
bool is_box;
enum BoxType box_type;
bool is_platonic; // can't be destroyed, unaffected by physical forces
bool always_visible; // always serialized to the player. @Robust check if not used
EntityID next_box; // for the grid!
EntityID prev_box; // doubly linked so can remove in middle of chain
enum CompassRotation compass_rotation;
@ -481,11 +481,36 @@ double sun_dist_no_gravity(Entity *sun);
void quit_with_popup(const char *message_utf8, const char *title_utf8);
// serialization stuff
typedef struct SerState
{
unsigned char *bytes;
bool serializing;
size_t cursor; // points to next available byte, is the size of current message after serializing something
size_t max_size;
Entity *for_player;
size_t max_entity_index; // for error checking
bool write_varnames;
bool save_or_load_from_disk;
// output
uint32_t version;
uint32_t git_release_tag; // release tag, unlike version, is about the game version not the serialization verson
} SerState;
typedef struct SerMaybeFailure
{
bool failed;
int line;
const char *expression;
} SerMaybeFailure;
// all of these return if successful or not
bool server_to_client_serialize(struct ServerToClient *msg, unsigned char *bytes, size_t *out_len, size_t max_len, Entity *for_this_player, bool to_disk);
bool server_to_client_deserialize(struct ServerToClient *msg, unsigned char *bytes, size_t max_len, bool from_disk);
bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, unsigned char *bytes, size_t max_len);
bool client_to_server_serialize(GameState *gs, struct ClientToServer *msg, unsigned char *bytes, size_t *out_len, size_t max_len);
size_t ser_size(SerState *ser);
SerState init_serializing(GameState *gs, unsigned char *bytes, size_t max_size, Entity *for_player, bool to_disk);
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);
// entities
bool is_burning(Entity *missile);

Loading…
Cancel
Save