Compare commits

...

7 Commits

@ -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^

@ -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"

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

Binary file not shown.

@ -409,7 +409,7 @@ LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
void destroy_constraints(cpBody *body, cpConstraint *constraint, void *data)
{
((Entity*)cpConstraintGetUserData(constraint))->landed_constraint = NULL;
((Entity *)cpConstraintGetUserData(constraint))->landed_constraint = NULL;
cpSpaceRemoveConstraint(cpBodyGetSpace(body), constraint);
cpConstraintFree(constraint);
}
@ -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,25 +464,20 @@ 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)
{
// need to do this here because body which constraint is attached to can be destroyed
// NOT TRUE: can't do this here because the handle to the constraint cannot be set to NULL. Constraints are freed by the entities that own them
cpBodyEachConstraint(e->body, destroy_constraints, NULL);
// NOT TRUE: can't do this here because the handle to the constraint cannot be set to NULL. Constraints are freed by the entities that own them
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);
@ -534,7 +542,7 @@ void create_body(GameState *gs, Entity *e)
}
// must always call this after creating a constraint
void on_create_constraint(Entity *e, cpConstraint* c)
void on_create_constraint(Entity *e, cpConstraint *c)
{
cpConstraintSetUserData(c, (cpDataPointer)e);
}
@ -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)
{
@ -815,24 +835,22 @@ bool could_learn_from_scanner(Player *for_player, Entity *box)
return (for_player->box_unlocks | box->blueprints_learned) != for_player->box_unlocks;
}
bool box_enterable(Entity *box)
{
return box->box_type == BoxMedbay || box->box_type == BoxCockpit;
}
bool box_interactible(GameState *gs, Player *for_player, Entity *box)
{
flight_assert(box->is_box);
if (box->box_type == BoxCockpit || box->box_type == BoxMedbay)
if (box->box_type == BoxMerge)
{
return true;
return merge_box_is_merged(gs, box);
}
else
{
if (box->box_type == BoxMerge)
{
return merge_box_is_merged(gs, box);
}
else
{
return false;
}
return false;
}
}
@ -1018,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)
@ -1030,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)
@ -1399,6 +1414,7 @@ SerMaybeFailure ser_inputframe(SerState *ser, InputFrame *i)
SER_MAYBE_RETURN(ser_entityid(ser, &i->invite_this_player));
SER_VAR(&i->seat_action);
SER_VAR(&i->interact_action);
SER_MAYBE_RETURN(ser_fV2(ser, &i->hand_pos));
SER_VAR(&i->dobuild);
@ -1436,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);
cpVect shape_pos;
if (ser->serializing)
shape_pos = entity_shape_pos(e);
SER_MAYBE_RETURN(ser_fV2(ser, &shape_pos));
SER_VAR(&e->no_save_to_disk);
SER_VAR(&e->always_visible);
SER_VAR(&e->generation);
SER_MAYBE_RETURN(ser_f(ser, &e->damage));
double shape_mass;
if (ser->serializing)
shape_mass = entity_shape_mass(e);
SER_VAR(&shape_mass);
SER_ASSERT(!isnan(shape_mass));
bool has_body = ser->serializing && e->body != NULL;
SER_VAR(&has_body);
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;
}
@ -2571,6 +2559,7 @@ void create_initial_world(GameState *gs)
#endif // debug world
}
// does not actually set seat in variables so can be used on respawn
void exit_seat(GameState *gs, Entity *seat_in, Entity *p)
{
cpVect pilot_seat_exit_spot = cpvadd(entity_pos(seat_in), cpvmult(box_facing_vector(seat_in), BOX_SIZE));
@ -2727,7 +2716,31 @@ void process(struct GameState *gs, double dt)
p->damage = 0.0;
#endif
#if 1
cpVect world_hand_pos = get_world_hand_pos(gs, &player->input, p);
if (player->input.interact_action)
{
player->input.interact_action = false;
cpPointQueryInfo query_info = {0};
cpShape *result = cpSpacePointQueryNearest(gs->space, (world_hand_pos), 0.1, FILTER_ONLY_BOXES, &query_info);
if (result != NULL)
{
Entity *potential_seat = cp_shape_entity(result);
flight_assert(potential_seat->is_box);
// IMPORTANT: if you update these, make sure you update box_interactible so
// the button prompt still works
if (potential_seat->box_type == BoxMerge) // disconnect!
{
potential_seat->wants_disconnect = true;
grid_correct_for_holes(gs, box_grid(potential_seat));
flight_assert(potential_seat->exists);
flight_assert(potential_seat->is_box);
flight_assert(potential_seat->box_type == BoxMerge);
}
}
}
if (player->input.seat_action)
{
player->input.seat_action = false; // "handle" the input
@ -2740,21 +2753,8 @@ void process(struct GameState *gs, double dt)
{
Entity *potential_seat = cp_shape_entity(result);
flight_assert(potential_seat->is_box);
// IMPORTANT: if you update these, make sure you update box_interactible so
// IMPORTANT: if you update these, make sure you update box_enterable so
// the button prompt still works
if (potential_seat->box_type == BoxScanner) // learn everything from the scanner
{
player->box_unlocks |= potential_seat->blueprints_learned;
}
if (potential_seat->box_type == BoxMerge) // disconnect!
{
potential_seat->wants_disconnect = true;
grid_correct_for_holes(gs, box_grid(potential_seat));
flight_assert(potential_seat->exists);
flight_assert(potential_seat->is_box);
flight_assert(potential_seat->box_type == BoxMerge);
}
if (potential_seat->box_type == BoxCockpit || potential_seat->box_type == BoxMedbay)
{
// don't let players get inside of cockpits that somebody else is already inside of
@ -2934,6 +2934,7 @@ void process(struct GameState *gs, double dt)
PROFILE_SCOPE("process entities")
{
ENTITIES_ITER(gs, e)
if (!e->flag_for_destruction)
{
if (e->body != NULL && cpvlengthsq((entity_pos(e))) > (INSTANT_DEATH_DISTANCE_FROM_CENTER * INSTANT_DEATH_DISTANCE_FROM_CENTER))
{
@ -3198,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)
@ -3239,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);
@ -3494,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));
@ -3504,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));
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

@ -76,7 +76,6 @@ static double dilating_time_factor = 1.0;
static bool build_pressed = false;
static double time_to_process = 0.0;
static bool interact_pressed = false;
#define MAX_MOUSEBUTTON (SAPP_MOUSEBUTTON_MIDDLE + 1)
static bool mousedown[MAX_MOUSEBUTTON] = {0};
typedef struct MousePressed
@ -141,6 +140,7 @@ static sg_image image_orb_frozen;
static sg_image image_radardot;
static sg_image image_landing_gear;
static sg_image image_pip;
static sg_image image_enter_exit;
static sg_image fire_rendertarget;
static sg_pass fire_pass;
@ -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()};
@ -859,6 +859,7 @@ static void init(void)
image_radardot = load_image("loaded/radardot.png");
image_landing_gear = load_image("loaded/landing_gear.png");
image_pip = load_image("loaded/pip.png");
image_enter_exit = load_image("loaded/enter_exit.png");
}
// socket initialization
@ -1063,9 +1064,12 @@ static void ui(bool draw, double dt, double width, double height)
// draw pick new box type menu
static double pick_opacity = 0.0;
static bool choosing_flags = false; // modifies choosing flags in pick box type modal
{
if (keypressed[SAPP_KEYCODE_ESCAPE].pressed)
picking_new_boxtype = false;
if(picking_new_boxtype)
choosing_flags = false;
AABB pick_modal = (AABB){
.x = width * 0.25,
.y = height * 0.25,
@ -1073,19 +1077,10 @@ static void ui(bool draw, double dt, double width, double height)
.height = height * 0.5,
};
pick_opacity = lerp(pick_opacity, picking_new_boxtype ? 1.0 : 0.0, dt * 7.0);
if (picking_new_boxtype)
if (picking_new_boxtype && build_pressed && !has_point(pick_modal, mouse_pos))
{
if (build_pressed)
{
if (has_point(pick_modal, mouse_pos))
{
}
else
{
build_pressed = false;
picking_new_boxtype = false;
}
}
build_pressed = false;
picking_new_boxtype = false;
}
static double item_scaling[ARRLEN(boxes)] = {1.0};
{
@ -1157,6 +1152,10 @@ static void ui(bool draw, double dt, double width, double height)
cur_column++;
}
}
if (picking_new_boxtype && build_pressed && has_point(pick_modal, mouse_pos))
{
build_pressed = false; // modal handles the input
}
}
// draw squad invite
@ -1165,8 +1164,7 @@ static void ui(bool draw, double dt, double width, double height)
static double yes_size = 50.0;
static double no_size = 50.0;
{
bool invited =
myentity() != NULL && myentity()->squad_invited_to != SquadNone;
bool invited = myentity() != NULL && myentity()->squad_invited_to != SquadNone;
double size = 200.0;
double x_center = 0.75 * width;
double x = x_center - size / 2.0;
@ -1293,7 +1291,6 @@ static void ui(bool draw, double dt, double width, double height)
static cpVect flag_pos[SquadLast] = {0};
static double flag_rot[SquadLast] = {0};
static double flag_scaling_increase[SquadLast] = {0};
static bool choosing_flags = false;
const double flag_padding = 70.0;
const double center_panel_height = 200.0;
static double center_panel_width = 0.0;
@ -1693,7 +1690,8 @@ static void frame(void)
}
build_pressed = mousepressed[SAPP_MOUSEBUTTON_LEFT].pressed;
interact_pressed = mousepressed[SAPP_MOUSEBUTTON_RIGHT].pressed;
bool interact_pressed = mousepressed[SAPP_MOUSEBUTTON_RIGHT].pressed;
bool seat_pressed = keypressed[SAPP_KEYCODE_F].pressed;
// networking
PROFILE_SCOPE("networking")
@ -1922,7 +1920,10 @@ static void frame(void)
}
if (interact_pressed)
cur_input_frame.seat_action = interact_pressed;
cur_input_frame.interact_action = interact_pressed;
if (seat_pressed)
cur_input_frame.seat_action = seat_pressed;
cur_input_frame.hand_pos = local_hand_pos;
if (take_over_squad >= 0)
@ -2409,7 +2410,9 @@ static void frame(void)
set_color_values(1.0, 1.0, 1.0, 1.0 - b->sun_amount);
}
if (myplayer() != NULL && box_interactible(&gs, myplayer(), b))
bool interactible = box_interactible(&gs, myplayer(), b);
bool enterable = box_enterable(b);
if (myplayer() != NULL && interactible || enterable)
{
if (box_has_point((BoxCentered){
.pos = entity_pos(b),
@ -2424,7 +2427,15 @@ static void frame(void)
{
pipeline_scope(goodpixel_pipeline)
{
sgp_set_image(0, image_rightclick);
if (interactible)
{
sgp_set_image(0, image_rightclick);
}
else
{
flight_assert(enterable);
sgp_set_image(0, image_enter_exit);
}
cpVect draw_at = cpvadd(entity_pos(b), cpv(BOX_SIZE, 0));
rotate_at(-entity_rotation(b) - rotangle(b->compass_rotation), draw_at.x, draw_at.y);
draw_texture_centered(draw_at, BOX_SIZE + sin(exec_time * 5.0) * BOX_SIZE * 0.1);
@ -2457,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);
@ -2792,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();
@ -2804,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();
@ -2945,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
};
}

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

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

@ -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
@ -250,13 +250,14 @@ typedef struct InputFrame
bool reject_cur_squad_invite;
EntityID invite_this_player; // null means inviting nobody! @Robust make it so just sends interact pos input, and server processes who to invite. This depends on client side prediction + proper input processing at the right tick.
bool interact_action;
bool seat_action;
cpVect hand_pos; // local to player transationally but not rotationally
bool dobuild;
enum BoxType build_type;
enum CompassRotation build_rotation;
} InputFrame;
} InputFrame; // the length of this is assumed to be constant
typedef struct PlatonicDetection
{
@ -378,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
@ -550,6 +553,7 @@ Entity *get_entity(struct GameState *gs, EntityID id);
Entity *new_entity(struct GameState *gs);
EntityID get_id(struct GameState *gs, Entity *e);
cpVect entity_pos(Entity *e);
bool box_enterable(Entity *box);
bool box_interactible(GameState *gs, Player *for_player, Entity *box);
void entity_set_rotation(Entity *e, double rot);
bool could_learn_from_scanner(Player *for_player, Entity *box);
@ -588,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
{

Loading…
Cancel
Save