diff --git a/build_elf_objects.bat b/build_elf_objects.bat index 7aad252..cad9088 100644 --- a/build_elf_objects.bat +++ b/build_elf_objects.bat @@ -17,14 +17,17 @@ popd @REM /DENET_DEBUG=1^ clang -target x86_64-pc-windows-elf -c^ + -DDEBUG^ -I"thirdparty" -I"thirdparty\minilzo" -I"thirdparty\enet\include" -I"thirdparty\Chipmunk2D\include\chipmunk" -I"thirdparty\Chipmunk2D\include" -I"thirdparty\opus\include" -I"thirdparty\opus\src"^ - %MUNKSRC% + %MUNKSRC%^ + gamestate.c + rmdir /S /Q elf_objects mkdir elf_objects move *.o elf_objects - @REM main.c gamestate.c server.c debugdraw.c^ - @REM thirdparty\minilzo\minilzo.c^ - @REM %OPUSLIB% - @REM thirdparty\enet\callbacks.c thirdparty\enet\compress.c thirdparty\enet\host.c thirdparty\enet\list.c thirdparty\enet\packet.c thirdparty\enet\peer.c thirdparty\enet\protocol.c thirdparty\enet\win32.c Ws2_32.lib winmm.lib^ +@REM main.c gamestate.c server.c debugdraw.c^ +@REM thirdparty\minilzo\minilzo.c^ +@REM %OPUSLIB% +@REM thirdparty\enet\callbacks.c thirdparty\enet\compress.c thirdparty\enet\host.c thirdparty\enet\list.c thirdparty\enet\packet.c thirdparty\enet\peer.c thirdparty\enet\protocol.c thirdparty\enet\win32.c Ws2_32.lib winmm.lib^ diff --git a/buildsettings.h b/buildsettings.h index 455f21e..0c44b31 100644 --- a/buildsettings.h +++ b/buildsettings.h @@ -14,7 +14,8 @@ #define ASSERT_DO_POPUP_AND_CRASH // #define SERVER_ADDRESS "207.246.80.160" -// #define PROFILING +#define CONSOLE_CREATE +#define PROFILING // Intensive profiling means profiling a lot of little tiny stuff. Not always enabled because tanks performance // #define INTENSIVE_PROFILING // #define DEBUG_RENDERING @@ -22,11 +23,11 @@ #define UNLOCK_ALL #define TIME_BETWEEN_WORLD_SAVE 1000000.0f // #define TIME_BETWEEN_WORLD_SAVE 1.0f -#define INFINITE_RESOURCES +// #define INFINITE_RESOURCES #define DEBUG_TOOLS #define CHIPMUNK_INTEGRITY_CHECK // #define FAT_THRUSTERS -//#define NO_GRAVITY +#define NO_GRAVITY // #define NO_SUNS #else @@ -35,6 +36,7 @@ // DANGER modifying these, make sure to change them back before releasing +#define CONSOLE_ATTACH // #define PROFILING // #define SERVER_ADDRESS "127.0.0.1" #define SERVER_ADDRESS "207.246.80.160" diff --git a/delete_this.c b/delete_this.c new file mode 100644 index 0000000..5acd8d0 --- /dev/null +++ b/delete_this.c @@ -0,0 +1,4 @@ +int myfunc() +{ + return 5; +} \ No newline at end of file diff --git a/flight.rdbg b/flight.rdbg index 88fac28..ba90e93 100644 Binary files a/flight.rdbg and b/flight.rdbg differ diff --git a/gamestate.c b/gamestate.c index 3e378cc..76bb717 100644 --- a/gamestate.c +++ b/gamestate.c @@ -430,6 +430,19 @@ void destroy_child_shape(cpBody *body, cpShape *shape, void *data) } } +void entity_free_allocated(Entity *e) +{ +#define MAYBE_FREE(variable, free_call) \ + if (variable != NULL) \ + { \ + free_call(variable); \ + variable = NULL; \ + } + MAYBE_FREE(e->shape, cpShapeFree); + MAYBE_FREE(e->body, cpBodyFree); + MAYBE_FREE(e->landed_constraint, cpConstraintFree); +} + // Destroys the entity and puts its slot back into the free list. Doesn't obey game rules // like making sure grids don't have holes in them, for that you want entity_destroy. // *Does* free all owned memory/entities though, e.g grids free the boxes they own. @@ -451,14 +464,10 @@ void entity_memory_free(GameState *gs, Entity *e) if (e->shape != NULL) { cpSpaceRemoveShape(gs->space, e->shape); - cpShapeFree(e->shape); - e->shape = NULL; } if (e->landed_constraint != NULL) { cpSpaceRemoveConstraint(gs->space, e->landed_constraint); - cpConstraintFree(e->landed_constraint); - e->landed_constraint = NULL; } if (e->body != NULL) { @@ -467,9 +476,8 @@ void entity_memory_free(GameState *gs, Entity *e) cpBodyEachConstraint(e->body, destroy_constraints, NULL); cpBodyEachShape(e->body, destroy_child_shape, (void *)gs); cpSpaceRemoveBody(gs->space, e->body); - cpBodyFree(e->body); - e->body = NULL; } + entity_free_allocated(e); Entity *front_of_free_list = get_entity(gs, gs->free_list); if (front_of_free_list != NULL) flight_assert(!front_of_free_list->exists); @@ -595,29 +603,41 @@ static const cpShapeFilter FILTER_DEFAULT = {CP_NO_GROUP, DEFAULT, CP_ALL_CATEGO // size is (1/2 the width, 1/2 the height) void create_rectangle_shape(GameState *gs, Entity *e, Entity *parent, cpVect pos, cpVect size, double mass) { - // @Robust remove this garbage - if (e->shape != NULL) + PROFILE_SCOPE("Create rectangle shape") { - cpSpaceRemoveShape(gs->space, e->shape); - cpShapeFree(e->shape); - e->shape = NULL; - } - - cpBB box = cpBBNew(-size.x + pos.x, -size.y + pos.y, size.x + pos.x, size.y + pos.y); - cpVect verts[4] = { - cpv(box.r, box.b), - cpv(box.r, box.t), - cpv(box.l, box.t), - cpv(box.l, box.b), - }; + // @Robust remove this garbage + if (e->shape != NULL) + { + PROFILE_SCOPE("Freeing shape") + { + cpSpaceRemoveShape(gs->space, e->shape); + cpShapeFree(e->shape); + e->shape = NULL; + } + } - e->shape_size = size; - e->shape_parent_entity = get_id(gs, parent); - e->shape = (cpShape *)cpPolyShapeInitRaw(cpPolyShapeAlloc(), parent->body, 4, verts, 0.0); // this cast is done in chipmunk, not sure why it works - cpShapeSetUserData(e->shape, (void *)e); - cpShapeSetMass(e->shape, mass); - cpSpaceAddShape(gs->space, e->shape); - cpShapeSetFilter(e->shape, FILTER_DEFAULT); + cpBB box = cpBBNew(-size.x + pos.x, -size.y + pos.y, size.x + pos.x, size.y + pos.y); + cpVect verts[4] = { + cpv(box.r, box.b), + cpv(box.r, box.t), + cpv(box.l, box.t), + cpv(box.l, box.b), + }; + + e->shape_size = size; + e->shape_parent_entity = get_id(gs, parent); + e->shape = (cpShape *)cpPolyShapeInitRaw(cpPolyShapeAlloc(), parent->body, 4, verts, 0.0); // this cast is done in chipmunk, not sure why it works + cpShapeSetUserData(e->shape, (void *)e); + PROFILE_SCOPE("Setting mass") + { + cpShapeSetMass(e->shape, mass); + } + PROFILE_SCOPE("Adding shape") + { + cpSpaceAddShape(gs->space, e->shape); + } + cpShapeSetFilter(e->shape, FILTER_DEFAULT); + } } void create_circle_shape(GameState *gs, Entity *e, double radius) { @@ -1016,9 +1036,6 @@ static void on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData) } } - // if(entity_a->is_missile) {getPointFunc = cpArbiterGetPointA; - // if(entity_b->is_missile) getPointFunc = cpArbiterGetPointB; - double damage = cpvlength((cpArbiterTotalImpulse(arb))) * COLLISION_DAMAGE_SCALING; if (entity_a->is_box && entity_a->box_type == BoxExplosive) @@ -1028,45 +1045,45 @@ static void on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData) if (damage > 0.05) { - // Log("Collision with damage %f\n", damage); entity_a->damage += damage; entity_b->damage += damage; } - - // 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); } // must be called with zero initialized game state, because copies the server side computing! void initialize(GameState *gs, void *entity_arena, size_t entity_arena_size) { - bool is_server_side = gs->server_side_computing; - *gs = (GameState){0}; - memset(entity_arena, 0, entity_arena_size); // SUPER critical. Random vals in the entity data causes big problem - gs->entities = (Entity *)entity_arena; - gs->max_entities = (unsigned int)(entity_arena_size / sizeof(Entity)); - gs->space = cpSpaceNew(); - cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler - cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0); - handler->postSolveFunc = on_damage; - gs->server_side_computing = is_server_side; + PROFILE_SCOPE("Initialize") + { + bool is_server_side = gs->server_side_computing; + *gs = (GameState){0}; + gs->entities = (Entity *)entity_arena; + gs->max_entities = (unsigned int)(entity_arena_size / sizeof(Entity)); + gs->space = cpSpaceNew(); + cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler + cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0); + handler->postSolveFunc = on_damage; + gs->server_side_computing = is_server_side; + } } void destroy(GameState *gs) { - // can't zero out gs data because the entity memory arena is reused - // on deserialization - for (size_t i = 0; i < gs->cur_next_entity; i++) + PROFILE_SCOPE("Destroy") { - if (gs->entities[i].exists) + // can't zero out gs data because the entity memory arena is reused + // on deserialization + for (size_t i = 0; i < gs->cur_next_entity; i++) { - entity_memory_free(gs, &gs->entities[i]); - gs->entities[i] = (Entity){0}; + if (gs->entities[i].exists) + { + entity_free_allocated(&gs->entities[i]); + gs->entities[i] = (Entity){0}; // IMPORTANT expects zeroed for initialize + } } + cpSpaceFree(gs->space); + gs->space = NULL; + gs->cur_next_entity = 0; } - cpSpaceFree(gs->space); - gs->space = NULL; - gs->cur_next_entity = 0; } // center of mass, not the literal position cpVect grid_com(Entity *grid) @@ -1435,235 +1452,207 @@ 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)); - - bool has_body = ser->serializing && e->body != NULL; - SER_VAR(&has_body); - - if (has_body) - { - struct BodyData body_data; - if (ser->serializing) - populate(e->body, &body_data); - SER_MAYBE_RETURN(ser_bodydata(ser, &body_data)); - if (!ser->serializing) - { - create_body(gs, e); - update_from(e->body, &body_data); - } - } - - bool has_shape = ser->serializing && e->shape != NULL; - SER_VAR(&has_shape); - if (has_shape) + PROFILE_SCOPE("Ser entity") { - SER_VAR(&e->is_circle_shape); - if (e->is_circle_shape) - { - SER_MAYBE_RETURN(ser_f(ser, &e->shape_radius)); - } - else - { - SER_MAYBE_RETURN(ser_fV2(ser, &e->shape_size)); - } - - SER_MAYBE_RETURN(ser_entityid(ser, &e->shape_parent_entity)); - Entity *parent = get_entity(gs, e->shape_parent_entity); - SER_ASSERT(parent != NULL); + SER_VAR(&e->no_save_to_disk); + SER_VAR(&e->always_visible); + SER_VAR(&e->generation); + SER_MAYBE_RETURN(ser_f(ser, &e->damage)); - cpVect shape_pos; - if (ser->serializing) - shape_pos = entity_shape_pos(e); - SER_MAYBE_RETURN(ser_fV2(ser, &shape_pos)); + bool has_body = ser->serializing && e->body != NULL; + SER_VAR(&has_body); - double shape_mass; - if (ser->serializing) - shape_mass = entity_shape_mass(e); - SER_VAR(&shape_mass); - SER_ASSERT(!isnan(shape_mass)); - - cpShapeFilter filter; - if (ser->serializing) + if (has_body) { - filter = cpShapeGetFilter(e->shape); + struct BodyData body_data; + if (ser->serializing) + populate(e->body, &body_data); + SER_MAYBE_RETURN(ser_bodydata(ser, &body_data)); + if (!ser->serializing) + { + create_body(gs, e); + update_from(e->body, &body_data); + } } - SER_VAR(&filter.categories); - SER_VAR(&filter.group); - SER_VAR(&filter.mask); - if (!ser->serializing) + + bool has_shape = ser->serializing && e->shape != NULL; + SER_VAR(&has_shape); + if (has_shape) { + SER_VAR(&e->is_circle_shape); if (e->is_circle_shape) { - create_circle_shape(gs, e, e->shape_radius); + SER_MAYBE_RETURN(ser_f(ser, &e->shape_radius)); } else { - create_rectangle_shape(gs, e, parent, shape_pos, e->shape_size, shape_mass); + SER_MAYBE_RETURN(ser_fV2(ser, &e->shape_size)); } - cpShapeSetFilter(e->shape, filter); - } - } - if (!ser->save_or_load_from_disk) - { - SER_MAYBE_RETURN(ser_f(ser, &e->time_was_last_cloaked)); - } + SER_MAYBE_RETURN(ser_entityid(ser, &e->shape_parent_entity)); + Entity *parent = get_entity(gs, e->shape_parent_entity); + SER_ASSERT(parent != NULL); - SER_VAR(&e->owning_squad); + cpVect shape_pos; + if (ser->serializing) + shape_pos = entity_shape_pos(e); + SER_MAYBE_RETURN(ser_fV2(ser, &shape_pos)); - SER_VAR(&e->is_player); - if (e->is_player) - { - SER_ASSERT(e->no_save_to_disk); + double shape_mass; + if (ser->serializing) + shape_mass = entity_shape_mass(e); + SER_VAR(&shape_mass); + SER_ASSERT(!isnan(shape_mass)); - SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box)); - SER_VAR(&e->squad_invited_to); + cpShapeFilter filter; + if (ser->serializing) + { + filter = cpShapeGetFilter(e->shape); + } + SER_VAR(&filter.categories); + SER_VAR(&filter.group); + SER_VAR(&filter.mask); + if (!ser->serializing) + { + if (e->is_circle_shape) + { + create_circle_shape(gs, e, e->shape_radius); + } + else + { + create_rectangle_shape(gs, e, parent, shape_pos, e->shape_size, shape_mass); + } + cpShapeSetFilter(e->shape, filter); + } + } - if (ser->version < VNoGold) + if (!ser->save_or_load_from_disk) { - double goldness; - SER_VAR_NAME(&goldness, "&e->goldness"); + SER_MAYBE_RETURN(ser_f(ser, &e->time_was_last_cloaked)); } - } - SER_VAR(&e->is_explosion); - if (e->is_explosion) - { - SER_MAYBE_RETURN(ser_V2(ser, &e->explosion_pos)); - SER_MAYBE_RETURN(ser_V2(ser, &e->explosion_vel)); - SER_MAYBE_RETURN(ser_f(ser, &e->explosion_progress)); - SER_MAYBE_RETURN(ser_f(ser, &e->explosion_push_strength)); - SER_MAYBE_RETURN(ser_f(ser, &e->explosion_radius)); - } + SER_VAR(&e->owning_squad); - SER_VAR(&e->is_sun); - if (e->is_sun) - { - SER_MAYBE_RETURN(ser_V2(ser, &e->sun_vel)); - SER_MAYBE_RETURN(ser_V2(ser, &e->sun_pos)); - SER_MAYBE_RETURN(ser_f(ser, &e->sun_mass)); - SER_MAYBE_RETURN(ser_f(ser, &e->sun_radius)); - if (ser->version >= VSafeSun) - SER_VAR(&e->sun_is_safe); - } + SER_VAR(&e->is_player); + if (e->is_player) + { + SER_ASSERT(e->no_save_to_disk); - SER_VAR(&e->is_grid); - if (e->is_grid) - { - SER_MAYBE_RETURN(ser_f(ser, &e->total_energy_capacity)); - SER_MAYBE_RETURN(ser_entityid(ser, &e->boxes)); - } + SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box)); + SER_VAR(&e->squad_invited_to); - SER_VAR(&e->is_missile); - if (e->is_missile) - { - SER_MAYBE_RETURN(ser_f(ser, &e->time_burned_for)); - } + if (ser->version < VNoGold) + { + double goldness; + SER_VAR_NAME(&goldness, "&e->goldness"); + } + } - SER_VAR(&e->is_orb); - if (e->is_orb) - { - } + SER_VAR(&e->is_explosion); + if (e->is_explosion) + { + SER_MAYBE_RETURN(ser_V2(ser, &e->explosion_pos)); + SER_MAYBE_RETURN(ser_V2(ser, &e->explosion_vel)); + SER_MAYBE_RETURN(ser_f(ser, &e->explosion_progress)); + SER_MAYBE_RETURN(ser_f(ser, &e->explosion_push_strength)); + SER_MAYBE_RETURN(ser_f(ser, &e->explosion_radius)); + } - SER_VAR(&e->is_box); - if (e->is_box) - { - SER_VAR(&e->box_type); - SER_VAR(&e->is_platonic); + SER_VAR(&e->is_sun); + if (e->is_sun) + { + SER_MAYBE_RETURN(ser_V2(ser, &e->sun_vel)); + SER_MAYBE_RETURN(ser_V2(ser, &e->sun_pos)); + SER_MAYBE_RETURN(ser_f(ser, &e->sun_mass)); + SER_MAYBE_RETURN(ser_f(ser, &e->sun_radius)); + if (ser->version >= VSafeSun) + SER_VAR(&e->sun_is_safe); + } - SER_VAR(&e->owning_squad); + SER_VAR(&e->is_grid); + if (e->is_grid) + { + SER_MAYBE_RETURN(ser_f(ser, &e->total_energy_capacity)); + SER_MAYBE_RETURN(ser_entityid(ser, &e->boxes)); + } - SER_MAYBE_RETURN(ser_entityid(ser, &e->next_box)); - SER_MAYBE_RETURN(ser_entityid(ser, &e->prev_box)); - SER_VAR(&e->compass_rotation); - SER_VAR(&e->indestructible); - switch (e->box_type) + SER_VAR(&e->is_missile); + if (e->is_missile) { - case BoxMedbay: - case BoxCockpit: - if (!ser->save_or_load_from_disk) - SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me)); - break; - case BoxThruster: - SER_MAYBE_RETURN(ser_f(ser, &e->thrust)); - SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust)); - break; - case BoxGyroscope: - SER_MAYBE_RETURN(ser_f(ser, &e->thrust)); - SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust)); - SER_MAYBE_RETURN(ser_f(ser, &e->gyrospin_angle)); - SER_MAYBE_RETURN(ser_f(ser, &e->gyrospin_velocity)); - break; - case BoxBattery: - SER_MAYBE_RETURN(ser_f(ser, &e->energy_used)); - break; - case BoxSolarPanel: - SER_MAYBE_RETURN(ser_f(ser, &e->sun_amount)); - break; - case BoxScanner: - SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_scanning)); - SER_MAYBE_RETURN(ser_f(ser, &e->currently_scanning_progress)); - SER_VAR(&e->blueprints_learned); - SER_MAYBE_RETURN(ser_f(ser, &e->scanner_head_rotate)); - for (int i = 0; i < SCANNER_MAX_PLATONICS; i++) - { - SER_MAYBE_RETURN(ser_V2(ser, &e->detected_platonics[i].direction)); - SER_MAYBE_RETURN(ser_f(ser, &e->detected_platonics[i].intensity)); - } - for (int i = 0; i < SCANNER_MAX_POINTS; i++) - { - SER_VAR(&e->scanner_points[i]); - } - break; - case BoxCloaking: - SER_MAYBE_RETURN(ser_f(ser, &e->cloaking_power)); - break; - case BoxMissileLauncher: - SER_MAYBE_RETURN(ser_f(ser, &e->missile_construction_charge)); - break; - case BoxLandingGear: + SER_MAYBE_RETURN(ser_f(ser, &e->time_burned_for)); + } + + SER_VAR(&e->is_orb); + if (e->is_orb) { - bool is_null = e->landed_constraint == NULL; - SER_VAR(&is_null); - if (!is_null) + } + + SER_VAR(&e->is_box); + if (e->is_box) + { + SER_VAR(&e->box_type); + SER_VAR(&e->is_platonic); + + SER_VAR(&e->owning_squad); + + SER_MAYBE_RETURN(ser_entityid(ser, &e->next_box)); + SER_MAYBE_RETURN(ser_entityid(ser, &e->prev_box)); + SER_VAR(&e->compass_rotation); + SER_VAR(&e->indestructible); + switch (e->box_type) { - EntityID from = {0}; - EntityID to = {0}; - cpVect pin = {0}; - if (ser->serializing) + case BoxMedbay: + case BoxCockpit: + if (!ser->save_or_load_from_disk) + SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me)); + break; + case BoxThruster: + SER_MAYBE_RETURN(ser_f(ser, &e->thrust)); + SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust)); + break; + case BoxGyroscope: + SER_MAYBE_RETURN(ser_f(ser, &e->thrust)); + SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust)); + SER_MAYBE_RETURN(ser_f(ser, &e->gyrospin_angle)); + SER_MAYBE_RETURN(ser_f(ser, &e->gyrospin_velocity)); + break; + case BoxBattery: + SER_MAYBE_RETURN(ser_f(ser, &e->energy_used)); + break; + case BoxSolarPanel: + SER_MAYBE_RETURN(ser_f(ser, &e->sun_amount)); + break; + case BoxScanner: + SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_scanning)); + SER_MAYBE_RETURN(ser_f(ser, &e->currently_scanning_progress)); + SER_VAR(&e->blueprints_learned); + SER_MAYBE_RETURN(ser_f(ser, &e->scanner_head_rotate)); + for (int i = 0; i < SCANNER_MAX_PLATONICS; i++) { - from = get_id(gs, cp_body_entity(cpConstraintGetBodyA(e->landed_constraint))); - to = get_id(gs, cp_body_entity(cpConstraintGetBodyB(e->landed_constraint))); - pin = cpPivotJointGetAnchorA(e->landed_constraint); + SER_MAYBE_RETURN(ser_V2(ser, &e->detected_platonics[i].direction)); + SER_MAYBE_RETURN(ser_f(ser, &e->detected_platonics[i].intensity)); } - SER_MAYBE_RETURN(ser_entityid(ser, &from)); - SER_MAYBE_RETURN(ser_entityid(ser, &to)); - SER_MAYBE_RETURN(ser_V2(ser, &pin)); - if (!ser->serializing) + for (int i = 0; i < SCANNER_MAX_POINTS; i++) { - Entity *from_entity = get_entity(gs, from); - Entity *to_entity = get_entity(gs, to); - if (from_entity == NULL || to_entity == NULL) - { - } - else - { - e->landed_constraint = cpPivotJointNew(from_entity->body, to_entity->body, pin); - cpSpaceAddConstraint(gs->space, e->landed_constraint); - on_create_constraint(e, e->landed_constraint); - } + SER_VAR(&e->scanner_points[i]); } + break; + case BoxCloaking: + SER_MAYBE_RETURN(ser_f(ser, &e->cloaking_power)); + break; + case BoxMissileLauncher: + SER_MAYBE_RETURN(ser_f(ser, &e->missile_construction_charge)); + break; + case BoxLandingGear: + { + SER_MAYBE_RETURN(ser_entityid(ser, &e->shape_to_land_on)); + break; + } + default: + break; } - break; - } - default: - break; } } - return ser_ok; } @@ -3210,6 +3199,8 @@ void process(struct GameState *gs, double dt) // PROFILE_SCOPE("Grid processing") { Entity *grid = e; + float e; // turn all references to e into errors + (void)e; // calculate how much energy solar panels provide double energy_to_add = 0.0; BOXES_ITER(gs, cur_box, grid) @@ -3251,6 +3242,7 @@ void process(struct GameState *gs, double dt) // use the energy, stored in the batteries, in various boxes BOXES_ITER(gs, cur_box, grid) { + if (cur_box->box_type == BoxThruster) { cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, cur_box->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt); @@ -3506,8 +3498,49 @@ void process(struct GameState *gs, double dt) } if (cur_box->box_type == BoxLandingGear) { - if (cur_box->landed_constraint == NULL) + cpVect landing_point = cpvadd(entity_pos(cur_box), cpvmult(box_facing_vector(cur_box), BOX_SIZE / 2.0)); + Entity *must_have_shape = get_entity(gs, cur_box->shape_to_land_on); + bool want_have_constraint = true; + if (want_have_constraint) + want_have_constraint &= must_have_shape != NULL; + if (want_have_constraint) + want_have_constraint &= must_have_shape->shape != NULL; + if (want_have_constraint) + want_have_constraint &= cpShapeGetBody(must_have_shape->shape) != NULL; + if (want_have_constraint) + want_have_constraint &= cpvdist(entity_pos(must_have_shape), landing_point) < BOX_SIZE + LANDING_GEAR_MAX_DIST; + +#define DELETE_CONSTRAINT(constraint) \ + { \ + cpSpaceRemoveConstraint(gs->space, constraint); \ + cpConstraintFree(constraint); \ + constraint = NULL; \ + } + if (want_have_constraint) { + flight_assert(must_have_shape != NULL); + cpBody *body_a = box_grid(cur_box)->body; + cpBody *body_b = cpShapeGetBody(must_have_shape->shape); + if (cur_box->landed_constraint != NULL && (cpConstraintGetBodyA(cur_box->landed_constraint) != body_a || cpConstraintGetBodyB(cur_box->landed_constraint) != body_b)) + { + DELETE_CONSTRAINT(cur_box->landed_constraint); + } + if (cur_box->landed_constraint == NULL) + { + cur_box->landed_constraint = cpPivotJointNew(body_a, body_b, landing_point); + cpSpaceAddConstraint(gs->space, cur_box->landed_constraint); + on_create_constraint(cur_box, cur_box->landed_constraint); + } + } + else + { + if (cur_box->landed_constraint != NULL) + { + DELETE_CONSTRAINT(cur_box->landed_constraint); + } + cur_box->shape_to_land_on = (EntityID){0}; + + // maybe see something to land on cpVect along = box_facing_vector(cur_box); cpVect from = cpvadd(entity_pos(cur_box), cpvmult(along, BOX_SIZE / 2.0 + 0.03)); cpVect to = cpvadd(from, cpvmult(along, LANDING_GEAR_MAX_DIST)); @@ -3516,12 +3549,7 @@ void process(struct GameState *gs, double dt) cpShape *found = cpSpaceSegmentQueryFirst(gs->space, from, to, 0.0, FILTER_DEFAULT, &query_result); if (found != NULL && cpShapeGetBody(found) != box_grid(cur_box)->body) { - cpVect anchor = cpvadd(entity_pos(cur_box), cpvmult(along, BOX_SIZE / 2.0)); - cpBody *a = box_grid(cur_box)->body; - cpBody *b = cpShapeGetBody(found); - cur_box->landed_constraint = cpPivotJointNew(a, b, anchor); - cpSpaceAddConstraint(gs->space, cur_box->landed_constraint); - on_create_constraint(cur_box, cur_box->landed_constraint); + cur_box->shape_to_land_on = get_id(gs, cp_shape_entity(found)); } } } diff --git a/main.c b/main.c index d065fc7..e46d981 100644 --- a/main.c +++ b/main.c @@ -693,7 +693,7 @@ static void init(void) Log("Initialized audio\n"); } - Entity *entity_data = malloc(sizeof *entity_data * MAX_ENTITIES); + Entity *entity_data = calloc(1, sizeof *entity_data * MAX_ENTITIES); initialize(&gs, entity_data, sizeof *entity_data * MAX_ENTITIES); sg_desc sgdesc = {.context = sapp_sgcontext()}; @@ -2468,7 +2468,7 @@ static void frame(void) else { pipeline_scope(goodpixel_pipeline) - draw_texture_centered(entity_pos(b), BOX_SIZE); + draw_texture_centered(entity_pos(b), BOX_SIZE); } sgp_reset_image(0); @@ -2803,7 +2803,10 @@ void cleanup(void) server_info.should_quit = true; ma_mutex_unlock(&server_info.info_mutex); WaitForSingleObject(server_thread_handle, INFINITE); - + + destroy(&gs); + free(gs.entities); + end_profiling_mythread(); end_profiling(); @@ -2815,9 +2818,7 @@ void cleanup(void) opus_encoder_destroy(enc); opus_decoder_destroy(dec); - - destroy(&gs); - free(gs.entities); + sgp_shutdown(); sg_shutdown(); enet_deinitialize(); @@ -2956,7 +2957,12 @@ sapp_desc sokol_main(int argc, char *argv[]) .window_title = "Flight Not Hosting", .icon.sokol_default = true, .event_cb = event, + #ifdef CONSOLE_CREATE + .win32_console_create = true, + #endif + #ifdef CONSOLE_ATTACH .win32_console_attach = true, + #endif .sample_count = 4, // anti aliasing }; } diff --git a/profiling.h b/profiling.h index 4364ee2..f3bfd64 100644 --- a/profiling.h +++ b/profiling.h @@ -47,7 +47,7 @@ void init_profiling_mythread(uint32_t id) my_thread_id = id; if (buffer_data != NULL) { - *(int *)0 = 0; + __debugbreak(); } buffer_data = malloc(PROFILING_BUFFER_SIZE); spall_buffer = (SpallBuffer){ diff --git a/server.c b/server.c index 2ed3d87..ee6e50d 100644 --- a/server.c +++ b/server.c @@ -40,7 +40,7 @@ void server(void *info_raw) struct GameState gs = {0}; size_t entities_size = (sizeof(Entity) * MAX_ENTITIES); - Entity *entity_data = malloc(entities_size); + Entity *entity_data = calloc(1, entities_size); initialize(&gs, entity_data, entities_size); gs.server_side_computing = true; Log("Allocated %zu bytes for entities\n", entities_size); @@ -64,7 +64,7 @@ void server(void *info_raw) if (world_save_name != NULL) { size_t read_game_data_buffer_size = entities_size; - unsigned char *read_game_data = malloc(read_game_data_buffer_size); + unsigned char *read_game_data = calloc(1, read_game_data_buffer_size); FILE *file = NULL; fopen_s(&file, (const char *)world_save_name, "rb"); @@ -139,7 +139,7 @@ void server(void *info_raw) uint64_t last_sent_gamestate_time = stm_now(); double audio_time_to_send = 0.0; double total_time = 0.0; - unsigned char *world_save_buffer = malloc(entities_size); + unsigned char *world_save_buffer = calloc(1, entities_size); PROFILE_SCOPE("Serving") { while (true) @@ -422,8 +422,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 - unsigned char *bytes_buffer = malloc(sizeof *bytes_buffer * MAX_SERVER_TO_CLIENT); - unsigned char *compressed_buffer = malloc(sizeof *compressed_buffer * MAX_SERVER_TO_CLIENT); + unsigned char *bytes_buffer = calloc(1, sizeof *bytes_buffer * MAX_SERVER_TO_CLIENT); + unsigned char *compressed_buffer = calloc(1, 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 c34fcbd..ac2baf2 100644 --- a/types.h +++ b/types.h @@ -8,7 +8,7 @@ #define MAX_PLAYERS 16 #define MAX_SUNS 8 #define MAX_ENTITIES 1024 * 25 -#define BOX_SIZE 0.25f +#define BOX_SIZE 0.25f // whole size, not half size #define MERGE_MAX_DIST (BOX_SIZE / 2.0f + 0.01f) #define MISSILE_RANGE 4.0f @@ -58,7 +58,7 @@ #define THRUSTER_ENERGY_USED_PER_SECOND 0.005 #define THRUSTER_DAMAGE_PER_SEC 2.0 -#define LANDING_GEAR_MAX_DIST (BOX_SIZE * 0.25) +#define LANDING_GEAR_MAX_DIST (BOX_SIZE * 0.05) #define GYROSCOPE_ENERGY_USED_PER_SECOND 0.005f #define GYROSCOPE_TORQUE 1.5f @@ -379,7 +379,9 @@ typedef struct Entity double scanner_head_rotate; // landing gear only - cpConstraint *landed_constraint; // when null is landed + cpConstraint *landed_constraint; // when not null, landing gear landed on something. Only valid while shape_to_land_on is a valid reference + // to land, set this to the shape to land on. A constraint will be created if it is valid. If it's not, it will be zerod + EntityID shape_to_land_on; // checked for surface distance to make sure is valid PlatonicDetection detected_platonics[SCANNER_MAX_PLATONICS]; // intensity of 0.0 means undetected @@ -590,6 +592,7 @@ cpVect thruster_force(Entity *box); void dbg_drawall(); void dbg_line(cpVect from, cpVect to); void dbg_rect(cpVect center); +typedef struct { int __do_not_reference__; } MakeUnreferencable; // used to remove variables from scope typedef struct ServerThreadInfo {