Many random fixes and landing gear

main
parent 982d01e09a
commit c04155ea26

@ -17,14 +17,17 @@ popd
@REM /DENET_DEBUG=1^ @REM /DENET_DEBUG=1^
clang -target x86_64-pc-windows-elf -c^ 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"^ -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 rmdir /S /Q elf_objects
mkdir elf_objects mkdir elf_objects
move *.o elf_objects move *.o elf_objects
@REM main.c gamestate.c server.c debugdraw.c^ @REM main.c gamestate.c server.c debugdraw.c^
@REM thirdparty\minilzo\minilzo.c^ @REM thirdparty\minilzo\minilzo.c^
@REM %OPUSLIB% @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 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^

@ -14,7 +14,8 @@
#define ASSERT_DO_POPUP_AND_CRASH #define ASSERT_DO_POPUP_AND_CRASH
// #define SERVER_ADDRESS "207.246.80.160" // #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 // 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_RENDERING
@ -22,11 +23,11 @@
#define UNLOCK_ALL #define UNLOCK_ALL
#define TIME_BETWEEN_WORLD_SAVE 1000000.0f #define TIME_BETWEEN_WORLD_SAVE 1000000.0f
// #define TIME_BETWEEN_WORLD_SAVE 1.0f // #define TIME_BETWEEN_WORLD_SAVE 1.0f
#define INFINITE_RESOURCES // #define INFINITE_RESOURCES
#define DEBUG_TOOLS #define DEBUG_TOOLS
#define CHIPMUNK_INTEGRITY_CHECK #define CHIPMUNK_INTEGRITY_CHECK
// #define FAT_THRUSTERS // #define FAT_THRUSTERS
//#define NO_GRAVITY #define NO_GRAVITY
// #define NO_SUNS // #define NO_SUNS
#else #else
@ -35,6 +36,7 @@
// DANGER modifying these, make sure to change them back before releasing // DANGER modifying these, make sure to change them back before releasing
#define CONSOLE_ATTACH
// #define PROFILING // #define PROFILING
// #define SERVER_ADDRESS "127.0.0.1" // #define SERVER_ADDRESS "127.0.0.1"
#define SERVER_ADDRESS "207.246.80.160" #define SERVER_ADDRESS "207.246.80.160"

@ -0,0 +1,4 @@
int myfunc()
{
return 5;
}

Binary file not shown.

@ -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 // 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. // 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. // *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) if (e->shape != NULL)
{ {
cpSpaceRemoveShape(gs->space, e->shape); cpSpaceRemoveShape(gs->space, e->shape);
cpShapeFree(e->shape);
e->shape = NULL;
} }
if (e->landed_constraint != NULL) if (e->landed_constraint != NULL)
{ {
cpSpaceRemoveConstraint(gs->space, e->landed_constraint); cpSpaceRemoveConstraint(gs->space, e->landed_constraint);
cpConstraintFree(e->landed_constraint);
e->landed_constraint = NULL;
} }
if (e->body != NULL) if (e->body != NULL)
{ {
@ -467,9 +476,8 @@ void entity_memory_free(GameState *gs, Entity *e)
cpBodyEachConstraint(e->body, destroy_constraints, NULL); cpBodyEachConstraint(e->body, destroy_constraints, NULL);
cpBodyEachShape(e->body, destroy_child_shape, (void *)gs); cpBodyEachShape(e->body, destroy_child_shape, (void *)gs);
cpSpaceRemoveBody(gs->space, e->body); 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); Entity *front_of_free_list = get_entity(gs, gs->free_list);
if (front_of_free_list != NULL) if (front_of_free_list != NULL)
flight_assert(!front_of_free_list->exists); 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) // 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) void create_rectangle_shape(GameState *gs, Entity *e, Entity *parent, cpVect pos, cpVect size, double mass)
{ {
// @Robust remove this garbage PROFILE_SCOPE("Create rectangle shape")
if (e->shape != NULL)
{ {
cpSpaceRemoveShape(gs->space, e->shape); // @Robust remove this garbage
cpShapeFree(e->shape); if (e->shape != NULL)
e->shape = NULL; {
} PROFILE_SCOPE("Freeing shape")
{
cpBB box = cpBBNew(-size.x + pos.x, -size.y + pos.y, size.x + pos.x, size.y + pos.y); cpSpaceRemoveShape(gs->space, e->shape);
cpVect verts[4] = { cpShapeFree(e->shape);
cpv(box.r, box.b), e->shape = NULL;
cpv(box.r, box.t), }
cpv(box.l, box.t), }
cpv(box.l, box.b),
};
e->shape_size = size; cpBB box = cpBBNew(-size.x + pos.x, -size.y + pos.y, size.x + pos.x, size.y + pos.y);
e->shape_parent_entity = get_id(gs, parent); cpVect verts[4] = {
e->shape = (cpShape *)cpPolyShapeInitRaw(cpPolyShapeAlloc(), parent->body, 4, verts, 0.0); // this cast is done in chipmunk, not sure why it works cpv(box.r, box.b),
cpShapeSetUserData(e->shape, (void *)e); cpv(box.r, box.t),
cpShapeSetMass(e->shape, mass); cpv(box.l, box.t),
cpSpaceAddShape(gs->space, e->shape); cpv(box.l, box.b),
cpShapeSetFilter(e->shape, FILTER_DEFAULT); };
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) 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; double damage = cpvlength((cpArbiterTotalImpulse(arb))) * COLLISION_DAMAGE_SCALING;
if (entity_a->is_box && entity_a->box_type == BoxExplosive) 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) if (damage > 0.05)
{ {
// Log("Collision with damage %f\n", damage);
entity_a->damage += damage; entity_a->damage += damage;
entity_b->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! // 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) void initialize(GameState *gs, void *entity_arena, size_t entity_arena_size)
{ {
bool is_server_side = gs->server_side_computing; PROFILE_SCOPE("Initialize")
*gs = (GameState){0}; {
memset(entity_arena, 0, entity_arena_size); // SUPER critical. Random vals in the entity data causes big problem bool is_server_side = gs->server_side_computing;
gs->entities = (Entity *)entity_arena; *gs = (GameState){0};
gs->max_entities = (unsigned int)(entity_arena_size / sizeof(Entity)); gs->entities = (Entity *)entity_arena;
gs->space = cpSpaceNew(); gs->max_entities = (unsigned int)(entity_arena_size / sizeof(Entity));
cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler gs->space = cpSpaceNew();
cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0); cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler
handler->postSolveFunc = on_damage; cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0);
gs->server_side_computing = is_server_side; handler->postSolveFunc = on_damage;
gs->server_side_computing = is_server_side;
}
} }
void destroy(GameState *gs) void destroy(GameState *gs)
{ {
// can't zero out gs data because the entity memory arena is reused PROFILE_SCOPE("Destroy")
// on deserialization
for (size_t i = 0; i < gs->cur_next_entity; i++)
{ {
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]); if (gs->entities[i].exists)
gs->entities[i] = (Entity){0}; {
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 // center of mass, not the literal position
cpVect grid_com(Entity *grid) 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) SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
{ {
SER_VAR(&e->no_save_to_disk); PROFILE_SCOPE("Ser entity")
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)
{ {
SER_VAR(&e->is_circle_shape); SER_VAR(&e->no_save_to_disk);
if (e->is_circle_shape) SER_VAR(&e->always_visible);
{ SER_VAR(&e->generation);
SER_MAYBE_RETURN(ser_f(ser, &e->shape_radius)); SER_MAYBE_RETURN(ser_f(ser, &e->damage));
}
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);
cpVect shape_pos; bool has_body = ser->serializing && e->body != NULL;
if (ser->serializing) SER_VAR(&has_body);
shape_pos = entity_shape_pos(e);
SER_MAYBE_RETURN(ser_fV2(ser, &shape_pos));
double shape_mass; if (has_body)
if (ser->serializing)
shape_mass = entity_shape_mass(e);
SER_VAR(&shape_mass);
SER_ASSERT(!isnan(shape_mass));
cpShapeFilter filter;
if (ser->serializing)
{ {
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); bool has_shape = ser->serializing && e->shape != NULL;
SER_VAR(&filter.mask); SER_VAR(&has_shape);
if (!ser->serializing) if (has_shape)
{ {
SER_VAR(&e->is_circle_shape);
if (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 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_entityid(ser, &e->shape_parent_entity));
{ Entity *parent = get_entity(gs, e->shape_parent_entity);
SER_MAYBE_RETURN(ser_f(ser, &e->time_was_last_cloaked)); 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); double shape_mass;
if (e->is_player) if (ser->serializing)
{ shape_mass = entity_shape_mass(e);
SER_ASSERT(e->no_save_to_disk); SER_VAR(&shape_mass);
SER_ASSERT(!isnan(shape_mass));
SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box)); cpShapeFilter filter;
SER_VAR(&e->squad_invited_to); 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_MAYBE_RETURN(ser_f(ser, &e->time_was_last_cloaked));
SER_VAR_NAME(&goldness, "&e->goldness");
} }
}
SER_VAR(&e->is_explosion); SER_VAR(&e->owning_squad);
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_sun); SER_VAR(&e->is_player);
if (e->is_sun) if (e->is_player)
{ {
SER_MAYBE_RETURN(ser_V2(ser, &e->sun_vel)); SER_ASSERT(e->no_save_to_disk);
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_grid); SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box));
if (e->is_grid) SER_VAR(&e->squad_invited_to);
{
SER_MAYBE_RETURN(ser_f(ser, &e->total_energy_capacity));
SER_MAYBE_RETURN(ser_entityid(ser, &e->boxes));
}
SER_VAR(&e->is_missile); if (ser->version < VNoGold)
if (e->is_missile) {
{ double goldness;
SER_MAYBE_RETURN(ser_f(ser, &e->time_burned_for)); SER_VAR_NAME(&goldness, "&e->goldness");
} }
}
SER_VAR(&e->is_orb); SER_VAR(&e->is_explosion);
if (e->is_orb) 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); SER_VAR(&e->is_sun);
if (e->is_box) if (e->is_sun)
{ {
SER_VAR(&e->box_type); SER_MAYBE_RETURN(ser_V2(ser, &e->sun_vel));
SER_VAR(&e->is_platonic); 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_VAR(&e->is_missile);
SER_MAYBE_RETURN(ser_entityid(ser, &e->prev_box)); if (e->is_missile)
SER_VAR(&e->compass_rotation);
SER_VAR(&e->indestructible);
switch (e->box_type)
{ {
case BoxMedbay: SER_MAYBE_RETURN(ser_f(ser, &e->time_burned_for));
case BoxCockpit: }
if (!ser->save_or_load_from_disk)
SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me)); SER_VAR(&e->is_orb);
break; if (e->is_orb)
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:
{ {
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}; case BoxMedbay:
EntityID to = {0}; case BoxCockpit:
cpVect pin = {0}; if (!ser->save_or_load_from_disk)
if (ser->serializing) 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))); SER_MAYBE_RETURN(ser_V2(ser, &e->detected_platonics[i].direction));
to = get_id(gs, cp_body_entity(cpConstraintGetBodyB(e->landed_constraint))); SER_MAYBE_RETURN(ser_f(ser, &e->detected_platonics[i].intensity));
pin = cpPivotJointGetAnchorA(e->landed_constraint);
} }
SER_MAYBE_RETURN(ser_entityid(ser, &from)); for (int i = 0; i < SCANNER_MAX_POINTS; i++)
SER_MAYBE_RETURN(ser_entityid(ser, &to));
SER_MAYBE_RETURN(ser_V2(ser, &pin));
if (!ser->serializing)
{ {
Entity *from_entity = get_entity(gs, from); SER_VAR(&e->scanner_points[i]);
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);
}
} }
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; return ser_ok;
} }
@ -3210,6 +3199,8 @@ void process(struct GameState *gs, double dt)
// PROFILE_SCOPE("Grid processing") // PROFILE_SCOPE("Grid processing")
{ {
Entity *grid = e; Entity *grid = e;
float e; // turn all references to e into errors
(void)e;
// calculate how much energy solar panels provide // calculate how much energy solar panels provide
double energy_to_add = 0.0; double energy_to_add = 0.0;
BOXES_ITER(gs, cur_box, grid) 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 // use the energy, stored in the batteries, in various boxes
BOXES_ITER(gs, cur_box, grid) BOXES_ITER(gs, cur_box, grid)
{ {
if (cur_box->box_type == BoxThruster) 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); 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->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 along = box_facing_vector(cur_box);
cpVect from = cpvadd(entity_pos(cur_box), cpvmult(along, BOX_SIZE / 2.0 + 0.03)); 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)); 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); cpShape *found = cpSpaceSegmentQueryFirst(gs->space, from, to, 0.0, FILTER_DEFAULT, &query_result);
if (found != NULL && cpShapeGetBody(found) != box_grid(cur_box)->body) if (found != NULL && cpShapeGetBody(found) != box_grid(cur_box)->body)
{ {
cpVect anchor = cpvadd(entity_pos(cur_box), cpvmult(along, BOX_SIZE / 2.0)); cur_box->shape_to_land_on = get_id(gs, cp_shape_entity(found));
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);
} }
} }
} }

@ -693,7 +693,7 @@ static void init(void)
Log("Initialized audio\n"); 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); initialize(&gs, entity_data, sizeof *entity_data * MAX_ENTITIES);
sg_desc sgdesc = {.context = sapp_sgcontext()}; sg_desc sgdesc = {.context = sapp_sgcontext()};
@ -2468,7 +2468,7 @@ static void frame(void)
else else
{ {
pipeline_scope(goodpixel_pipeline) pipeline_scope(goodpixel_pipeline)
draw_texture_centered(entity_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
} }
sgp_reset_image(0); sgp_reset_image(0);
@ -2803,7 +2803,10 @@ void cleanup(void)
server_info.should_quit = true; server_info.should_quit = true;
ma_mutex_unlock(&server_info.info_mutex); ma_mutex_unlock(&server_info.info_mutex);
WaitForSingleObject(server_thread_handle, INFINITE); WaitForSingleObject(server_thread_handle, INFINITE);
destroy(&gs);
free(gs.entities);
end_profiling_mythread(); end_profiling_mythread();
end_profiling(); end_profiling();
@ -2815,9 +2818,7 @@ void cleanup(void)
opus_encoder_destroy(enc); opus_encoder_destroy(enc);
opus_decoder_destroy(dec); opus_decoder_destroy(dec);
destroy(&gs);
free(gs.entities);
sgp_shutdown(); sgp_shutdown();
sg_shutdown(); sg_shutdown();
enet_deinitialize(); enet_deinitialize();
@ -2956,7 +2957,12 @@ sapp_desc sokol_main(int argc, char *argv[])
.window_title = "Flight Not Hosting", .window_title = "Flight Not Hosting",
.icon.sokol_default = true, .icon.sokol_default = true,
.event_cb = event, .event_cb = event,
#ifdef CONSOLE_CREATE
.win32_console_create = true,
#endif
#ifdef CONSOLE_ATTACH
.win32_console_attach = true, .win32_console_attach = true,
#endif
.sample_count = 4, // anti aliasing .sample_count = 4, // anti aliasing
}; };
} }

@ -47,7 +47,7 @@ void init_profiling_mythread(uint32_t id)
my_thread_id = id; my_thread_id = id;
if (buffer_data != NULL) if (buffer_data != NULL)
{ {
*(int *)0 = 0; __debugbreak();
} }
buffer_data = malloc(PROFILING_BUFFER_SIZE); buffer_data = malloc(PROFILING_BUFFER_SIZE);
spall_buffer = (SpallBuffer){ spall_buffer = (SpallBuffer){

@ -40,7 +40,7 @@ void server(void *info_raw)
struct GameState gs = {0}; struct GameState gs = {0};
size_t entities_size = (sizeof(Entity) * MAX_ENTITIES); 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); initialize(&gs, entity_data, entities_size);
gs.server_side_computing = true; gs.server_side_computing = true;
Log("Allocated %zu bytes for entities\n", entities_size); Log("Allocated %zu bytes for entities\n", entities_size);
@ -64,7 +64,7 @@ void server(void *info_raw)
if (world_save_name != NULL) if (world_save_name != NULL)
{ {
size_t read_game_data_buffer_size = entities_size; 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; FILE *file = NULL;
fopen_s(&file, (const char *)world_save_name, "rb"); 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(); uint64_t last_sent_gamestate_time = stm_now();
double audio_time_to_send = 0.0; double audio_time_to_send = 0.0;
double total_time = 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") PROFILE_SCOPE("Serving")
{ {
while (true) while (true)
@ -422,8 +422,8 @@ void server(void *info_raw)
if (this_player_entity == NULL) if (this_player_entity == NULL)
continue; continue;
// @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again // @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 *bytes_buffer = calloc(1, sizeof *bytes_buffer * MAX_SERVER_TO_CLIENT);
unsigned char *compressed_buffer = malloc(sizeof *compressed_buffer * MAX_SERVER_TO_CLIENT); unsigned char *compressed_buffer = calloc(1, sizeof *compressed_buffer * MAX_SERVER_TO_CLIENT);
// mix audio to be sent // mix audio to be sent
VOIP_QUEUE_DECL(buffer_to_play, buffer_to_play_data); VOIP_QUEUE_DECL(buffer_to_play, buffer_to_play_data);

@ -8,7 +8,7 @@
#define MAX_PLAYERS 16 #define MAX_PLAYERS 16
#define MAX_SUNS 8 #define MAX_SUNS 8
#define MAX_ENTITIES 1024 * 25 #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 MERGE_MAX_DIST (BOX_SIZE / 2.0f + 0.01f)
#define MISSILE_RANGE 4.0f #define MISSILE_RANGE 4.0f
@ -58,7 +58,7 @@
#define THRUSTER_ENERGY_USED_PER_SECOND 0.005 #define THRUSTER_ENERGY_USED_PER_SECOND 0.005
#define THRUSTER_DAMAGE_PER_SEC 2.0 #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_ENERGY_USED_PER_SECOND 0.005f
#define GYROSCOPE_TORQUE 1.5f #define GYROSCOPE_TORQUE 1.5f
@ -379,7 +379,9 @@ typedef struct Entity
double scanner_head_rotate; double scanner_head_rotate;
// landing gear only // 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 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_drawall();
void dbg_line(cpVect from, cpVect to); void dbg_line(cpVect from, cpVect to);
void dbg_rect(cpVect center); void dbg_rect(cpVect center);
typedef struct { int __do_not_reference__; } MakeUnreferencable; // used to remove variables from scope
typedef struct ServerThreadInfo typedef struct ServerThreadInfo
{ {

Loading…
Cancel
Save