From 9519189cd867d4def5f4a41b9a2466a5f88a5bc2 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Thu, 17 Nov 2022 14:50:22 -0800 Subject: [PATCH] Box bitfield unlocks and helix fix warnings --- gamestate.c | 137 +++++++++++++++++++++++++++++----------------------- main.c | 42 ++++++++-------- server.c | 13 ++--- types.h | 16 +++--- 4 files changed, 114 insertions(+), 94 deletions(-) diff --git a/gamestate.c b/gamestate.c index 0d7fe0a..61ad1ce 100644 --- a/gamestate.c +++ b/gamestate.c @@ -73,6 +73,22 @@ Entity *get_entity(GameState *gs, EntityID id) return to_return; } +static uint64_t box_unlock_number(enum BoxType box) +{ + assert((uint64_t)box < 64); + return (uint64_t)((uint64_t)1 << ((uint64_t)box)); +} + +void unlock_box(Player *player, enum BoxType box) +{ + player->box_unlocks |= box_unlock_number(box); +} + +bool box_unlocked(Player *player, enum BoxType box) +{ + return (player->box_unlocks & box_unlock_number(box)) > 0; +} + EntityID get_id(GameState *gs, Entity *e) { if (e == NULL) @@ -287,7 +303,19 @@ void create_rectangle_shape(GameState *gs, Entity *e, Entity *parent, V2 pos, V2 #define PLAYER_SHAPE_FILTER cpShapeFilterNew(CP_NO_GROUP, PLAYERS, CP_ALL_CATEGORIES) -void create_player(GameState *gs, Entity *e) +void create_player(Player *player) +{ + // default box unlocks, required for survival and growth + unlock_box(player, BoxHullpiece); + unlock_box(player, BoxThruster); + unlock_box(player, BoxBattery); + unlock_box(player, BoxCockpit); + unlock_box(player, BoxMedbay); + unlock_box(player, BoxSolarPanel); + unlock_box(player, BoxScanner); +} + +void create_player_entity(GameState *gs, Entity *e) { e->is_player = true; e->no_save_to_disk = true; @@ -478,7 +506,7 @@ static void grid_remove_box(GameState *gs, struct Entity *grid, struct Entity *b grid_correct_for_holes(gs, grid); } -static cpBool on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData) +static void on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData) { cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b); @@ -504,10 +532,7 @@ static cpBool on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData) // b must be the key passed into the post step removed, the key is cast into its shape // cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL); // cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, a, NULL); - - return true; // keep colliding } - void initialize(GameState *gs, void *entity_arena, size_t entity_arena_size) { *gs = (GameState){0}; @@ -639,7 +664,7 @@ void update_from(cpBody *body, struct BodyData *data) typedef struct SerState { - char *bytes; + 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; @@ -705,45 +730,36 @@ SerMaybeFailure ser_data(SerState *ser, char *data, size_t data_len, const char { if (ser->write_varnames) { - char read_name[512] = {0}; + // deserialize and check the var name - size_t just_field_name = strlen(name); - int i = 0; - int nondigit_i = 0; - while (true) + // skip past the digits + size_t num_digits = 0; + while (ser->bytes[ser->cursor] >= '0' && ser->bytes[ser->cursor] <= '9') { - read_name[i] = ser->bytes[ser->cursor]; - if (nondigit_i == 0 && read_name[i] >= '0' && read_name[i] <= '9') - { - // still a digit - if (i >= 10) - { // 10 is way too many digits for a line number... - return (SerMaybeFailure){ - .expression = "Way too many digits as a line number before a field name", - .failed = true, - .line = __LINE__, - }; - } - } - else + ser->cursor += 1; + SER_ASSERT(ser->cursor <= ser->max_size); + num_digits += 1; + if (num_digits >= 10) { - nondigit_i += 1; + return (SerMaybeFailure){ + .expression = "Way too many digits as a line number before a field name", + .failed = true, + .line = __LINE__, + }; } - i++; + } + // cursor is now on a non digit, the start of the name + char read_name[512] = {0}; + size_t just_field_name_length = strlen(name); + for (size_t i = 0; i < just_field_name_length; i++) + { + read_name[i] = ser->bytes[ser->cursor]; ser->cursor += 1; SER_ASSERT(ser->cursor <= ser->max_size); - if (nondigit_i >= just_field_name) - break; } - read_name[i + 1] = '\0'; - // advance past digits - char *read = read_name; - char *var = var_name; - while (*read >= '0' && *read <= '9') - read++; - while (*var >= '0' && *var <= '9') - var++; - SER_ASSERT(strcmp(read, var) == 0); + + // now compare! + SER_ASSERT(strcmp(read_name, name) == 0); } for (int b = 0; b < data_len; b++) { @@ -775,6 +791,7 @@ enum GameVersion VRemovedTimeFromDiskSave, // did this to avoid wayy too big a time causing precision problems VReallyRemovedTimeFromDiskSave, // apparently last one didn't work VRemovedInsideOfMe, + VSwitchedToUnlocks, VMax, // this minus one will be the version used }; @@ -839,7 +856,15 @@ SerMaybeFailure ser_player(SerState *ser, Player *p) SER_VAR(&p->connected); if (p->connected) { - SER_VAR(&p->unlocked_bombs); + if (ser->version >= VSwitchedToUnlocks) + { + SER_VAR(&p->box_unlocks); + } + else + { + bool throwaway; + SER_VAR_NAME(&throwaway, "&p->unlocked_bombs"); + } if (ser->version >= VAddedSquads) SER_VAR(&p->squad); SER_MAYBE_RETURN(ser_entityid(ser, &p->entity)); @@ -953,7 +978,12 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e) { SER_VAR(&e->box_type); SER_VAR(&e->always_visible); - SER_VAR(&e->is_explosion_unlock); + + if (ser->version <= VSwitchedToUnlocks) + { + bool throwaway; + SER_VAR_NAME(&throwaway, "&e->is_explosion_unlock"); + } SER_MAYBE_RETURN(ser_entityid(ser, &e->next_box)); SER_MAYBE_RETURN(ser_entityid(ser, &e->prev_box)); SER_VAR(&e->compass_rotation); @@ -990,7 +1020,7 @@ SerMaybeFailure ser_opus_packets(SerState *ser, Queue *mic_or_speaker_data) if (!isnull && cur != NULL) // cur != NULL is to suppress VS warning { SER_VAR(&cur->length); - SER_DATA(cur->data, cur->length); + SER_DATA((char *)cur->data, cur->length); } } no_more_packets = true; @@ -1014,7 +1044,7 @@ SerMaybeFailure ser_opus_packets(SerState *ser, Queue *mic_or_speaker_data) SER_VAR(&cur->length); SER_ASSERT(cur->length < VOIP_PACKET_MAX_SIZE); SER_ASSERT(cur->length >= 0); - SER_DATA(cur->data, cur->length); + SER_DATA((char *)cur->data, cur->length); } } } @@ -1171,7 +1201,7 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s) } // for_this_player can be null then the entire world will be sent -bool server_to_client_serialize(struct ServerToClient *msg, char *bytes, size_t *out_len, size_t max_len, Entity *for_this_player, bool to_disk) +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) { assert(msg->cur_gs != NULL); assert(msg != NULL); @@ -1209,7 +1239,7 @@ bool server_to_client_serialize(struct ServerToClient *msg, char *bytes, size_t } } -bool server_to_client_deserialize(struct ServerToClient *msg, char *bytes, size_t max_len, bool from_disk) +bool server_to_client_deserialize(struct ServerToClient *msg, unsigned char *bytes, size_t max_len, bool from_disk) { assert(msg->cur_gs != NULL); assert(msg != NULL); @@ -1288,7 +1318,7 @@ SerMaybeFailure ser_client_to_server(SerState *ser, ClientToServer *msg) return ser_ok; } -bool client_to_server_serialize(GameState *gs, struct ClientToServer *msg, char *bytes, size_t *out_len, 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) { SerState ser = (SerState){ .bytes = bytes, @@ -1316,7 +1346,7 @@ bool client_to_server_serialize(GameState *gs, struct ClientToServer *msg, char } } -bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, char *bytes, size_t max_len) +bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, unsigned char *bytes, size_t max_len) { SerState servar = (SerState){ .bytes = bytes, @@ -1525,7 +1555,6 @@ EntityID create_spacestation(GameState *gs) entity_ensure_in_orbit(grid); Entity *explosion_box = new_entity(gs); box_create(gs, explosion_box, grid, (V2){0}); - explosion_box->is_explosion_unlock = true; explosion_box->no_save_to_disk = true; explosion_box->always_visible = true; BOX_AT_TYPE(grid, ((V2){BOX_SIZE, 0}), BoxExplosive); @@ -1612,7 +1641,7 @@ void process(GameState *gs, float dt) if (p == NULL) { p = new_entity(gs); - create_player(gs, p); + create_player_entity(gs, p); player->entity = get_id(gs, p); Entity *medbay = get_entity(gs, player->last_used_medbay); entity_ensure_in_orbit(p); @@ -1809,18 +1838,6 @@ void process(GameState *gs, float dt) if (!e->exists) continue; - if (e->is_explosion_unlock) - { - PLAYERS_ITER(gs->players, player) - { - Entity *player_entity = get_entity(gs, player->entity); - if (player_entity != NULL && V2length(V2sub(entity_pos(player_entity), entity_pos(e))) < GOLD_UNLOCK_RADIUS) - { - player->unlocked_bombs = true; - } - } - } - if (e->body != NULL) { cpVect p = cpvsub(cpBodyGetPosition(e->body), v2_to_cp(SUN_POS)); diff --git a/main.c b/main.c index 87da037..620605a 100644 --- a/main.c +++ b/main.c @@ -177,7 +177,8 @@ static struct BoxInfo cur++) \ if (cur->exists) #define ARRLEN(arr) (sizeof(arr) / sizeof(*arr)) - +// suppress compiler warning about ^^ above used in floating point context +#define ARRLENF(arr) ((float)sizeof(arr) / sizeof(*arr)) static struct SquadMeta { enum Squad squad; @@ -604,12 +605,11 @@ static void draw_circle(V2 point, float radius) bool can_build(int i) { bool allow_building = true; - if (boxinfo((enum BoxType)i).needs_tobe_unlocked) - { - allow_building = false; - if (myplayer() != NULL) - allow_building = myplayer()->unlocked_bombs; - } + enum BoxType box_type = (enum BoxType)i; + + allow_building = false; + if (myplayer() != NULL) + allow_building = box_unlocked(myplayer(), box_type); return allow_building; } @@ -978,7 +978,7 @@ static void ui(bool draw, float dt, float width, float height) (float)sg_query_image_info(image_itemframe).width * 2.0f; float itemframe_height = (float)sg_query_image_info(image_itemframe).height * 2.0f; - float total_width = itemframe_width * ARRLEN(boxes); + float total_width = itemframe_width * (float) ARRLENF(boxes); float item_width = itemframe_width * 0.75f; float item_height = itemframe_height * 0.75f; float item_offset_x = (itemframe_width - item_width) / 2.0f; @@ -1122,6 +1122,11 @@ static void frame(void) { switch (event.type) { + case ENET_EVENT_TYPE_NONE: + { + Log("Wtf none event type?\n"); + break; + } case ENET_EVENT_TYPE_CONNECT: { Log("New client from host %x\n", event.peer->address.host); @@ -1130,7 +1135,7 @@ static void frame(void) case ENET_EVENT_TYPE_RECEIVE: { - char *decompressed = malloc( + unsigned char *decompressed = malloc( sizeof *decompressed * MAX_SERVER_TO_CLIENT); // @Robust no malloc size_t decompressed_max_len = MAX_SERVER_TO_CLIENT; assert(LZO1X_MEM_DECOMPRESS == 0); @@ -1368,12 +1373,12 @@ static void frame(void) .mic_data = &packets_to_send, .input_data = &input_queue, }; - char serialized[MAX_CLIENT_TO_SERVER] = {0}; + 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)) { - char compressed[MAX_CLIENT_TO_SERVER] = {0}; + unsigned char compressed[MAX_CLIENT_TO_SERVER] = {0}; char lzo_working_mem[LZO1X_1_MEM_COMPRESS] = {0}; size_t compressed_len = 0; @@ -1554,11 +1559,6 @@ static void frame(void) Entity *g = e; BOXES_ITER(&gs, b, g) { - if (b->is_explosion_unlock) - { - set_color(colhexcode(0xfcba03)); - draw_circle(entity_pos(b), GOLD_UNLOCK_RADIUS); - } sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); if (b->box_type == BoxBattery) { @@ -1623,15 +1623,15 @@ static void frame(void) sgp_set_color(0.2f, 0.2f, 0.2f, 1.0f); } pipeline_scope(goodpixel_pipeline) - draw_texture_centered(entity_pos(b), BOX_SIZE); + draw_texture_centered(entity_pos(b), BOX_SIZE); sgp_reset_image(0); - - if(b->box_type == BoxScanner) + + if (b->box_type == BoxScanner) { sgp_set_image(0, image_scanner_head); - sgp_rotate_at((float)gs.time*3.0f, entity_pos(b).x, entity_pos(b).y); + sgp_rotate_at((float)gs.time * 3.0f, entity_pos(b).x, entity_pos(b).y); pipeline_scope(goodpixel_pipeline) - draw_texture_centered(entity_pos(b), BOX_SIZE); + draw_texture_centered(entity_pos(b), BOX_SIZE); } sgp_set_color(0.5f, 0.1f, 0.1f, b->damage); diff --git a/server.c b/server.c index 933798a..221223a 100644 --- a/server.c +++ b/server.c @@ -104,7 +104,7 @@ void server(void *info_raw) if (world_save_name != NULL) { size_t read_game_data_buffer_size = entities_size; - char *read_game_data = malloc(read_game_data_buffer_size); + unsigned char *read_game_data = malloc(read_game_data_buffer_size); FILE *file = NULL; fopen_s(&file, (const char *)world_save_name, "rb"); @@ -201,7 +201,7 @@ void server(void *info_raw) uint64_t last_sent_gamestate_time = stm_now(); float audio_time_to_send = 0.0f; float total_time = 0.0f; - char *world_save_buffer = malloc(entities_size); + unsigned char *world_save_buffer = malloc(entities_size); while (true) { ma_mutex_lock(&info->info_mutex); @@ -251,7 +251,8 @@ void server(void *info_raw) event.peer->data = (void *)player_slot; gs.players[player_slot] = (struct Player){0}; gs.players[player_slot].connected = true; - + create_player(&gs.players[player_slot]); + int error; player_encoders[player_slot] = opus_encoder_create(VOIP_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &error); if (error != OPUS_OK) @@ -292,7 +293,7 @@ void server(void *info_raw) queue_clear(&player_input_queues[player_slot]); struct ClientToServer received = {.mic_data = buffer_to_fill, .input_data = &player_input_queues[player_slot]}; - char decompressed[MAX_CLIENT_TO_SERVER] = {0}; + unsigned char decompressed[MAX_CLIENT_TO_SERVER] = {0}; size_t decompressed_max_len = MAX_CLIENT_TO_SERVER; assert(LZO1X_MEM_DECOMPRESS == 0); @@ -457,8 +458,8 @@ void server(void *info_raw) if (this_player_entity == NULL) continue; // @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again - char *bytes_buffer = malloc(sizeof *bytes_buffer * MAX_SERVER_TO_CLIENT); - char *compressed_buffer = malloc(sizeof *compressed_buffer * MAX_SERVER_TO_CLIENT); + unsigned char *bytes_buffer = malloc(sizeof *bytes_buffer * MAX_SERVER_TO_CLIENT); + unsigned char *compressed_buffer = malloc(sizeof *compressed_buffer * MAX_SERVER_TO_CLIENT); // mix audio to be sent VOIP_QUEUE_DECL(buffer_to_play, buffer_to_play_data); diff --git a/types.h b/types.h index 87e72b5..86b5491 100644 --- a/types.h +++ b/types.h @@ -44,7 +44,8 @@ #define VOIP_PACKET_BUFFER_SIZE 15 // audio. Must be bigger than 2 #define VOIP_EXPECTED_FRAME_COUNT 480 #define VOIP_SAMPLE_RATE 48000 -#define VOIP_TIME_PER_PACKET (1.0f / ((float)(VOIP_SAMPLE_RATE / VOIP_EXPECTED_FRAME_COUNT))) // in seconds +// in seconds +#define VOIP_TIME_PER_PACKET (1.0f / ((float)((float)VOIP_SAMPLE_RATE / VOIP_EXPECTED_FRAME_COUNT))) #define VOIP_PACKET_MAX_SIZE 4000 #define VOIP_DISTANCE_WHEN_CANT_HEAR (VISION_RADIUS * 0.8f) @@ -230,7 +231,6 @@ typedef struct Entity bool is_box; bool always_visible; // always serialized to the player enum BoxType box_type; - bool is_explosion_unlock; EntityID next_box; EntityID prev_box; // doubly linked so can remove in middle of chain enum CompassRotation compass_rotation; @@ -245,7 +245,7 @@ typedef struct Entity typedef struct Player { bool connected; - bool unlocked_bombs; + uint64_t box_unlocks; // each bit is that box's unlock enum Squad squad; EntityID entity; EntityID last_used_medbay; @@ -329,6 +329,8 @@ typedef struct ClientToServer // server void server(void *info); // data parameter required from thread api... +void create_player(Player *player); +bool box_unlocked(Player *player, enum BoxType box); // gamestate EntityID create_spacestation(GameState *gs); @@ -340,10 +342,10 @@ Entity *closest_to_point_in_radius(struct GameState *gs, V2 point, float radius) uint64_t tick(struct GameState *gs); // all of these return if successful or not -bool server_to_client_serialize(struct ServerToClient *msg, 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, char *bytes, size_t max_len, bool from_disk); -bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, char *bytes, size_t max_len); -bool client_to_server_serialize(GameState *gs, struct ClientToServer *msg, char *bytes, size_t *out_len, size_t max_len); +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); // entities Entity *get_entity(struct GameState *gs, EntityID id);