Box bitfield unlocks and helix fix warnings

main
Cameron Murphy Reikes 2 years ago
parent f48a609ac8
commit 9519189cd8

@ -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));

@ -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);

@ -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);

@ -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);

Loading…
Cancel
Save