|
|
@ -578,6 +578,9 @@ V2 entity_pos(Entity* e)
|
|
|
|
if (e->is_box) {
|
|
|
|
if (e->is_box) {
|
|
|
|
return V2add(entity_pos(box_grid(e)), V2rotate(entity_shape_pos(e), entity_rotation(box_grid(e))));
|
|
|
|
return V2add(entity_pos(box_grid(e)), V2rotate(entity_shape_pos(e), entity_rotation(box_grid(e))));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (e->is_explosion) {
|
|
|
|
|
|
|
|
return e->explosion_pos;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
assert(e->body != NULL);
|
|
|
|
assert(e->body != NULL);
|
|
|
|
return cp_to_v2(cpBodyGetPosition(e->body));
|
|
|
|
return cp_to_v2(cpBodyGetPosition(e->body));
|
|
|
@ -608,13 +611,13 @@ void update_from(cpBody* body, struct BodyData* data)
|
|
|
|
cpBodySetAngularVelocity(body, data->angular_velocity);
|
|
|
|
cpBodySetAngularVelocity(body, data->angular_velocity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//#define WRITE_VARNAMES // debugging feature horrible for network
|
|
|
|
|
|
|
|
typedef struct SerState
|
|
|
|
typedef struct SerState
|
|
|
|
{
|
|
|
|
{
|
|
|
|
char* bytes;
|
|
|
|
char* bytes;
|
|
|
|
bool serializing;
|
|
|
|
bool serializing;
|
|
|
|
size_t cursor; // points to next available byte, is the size of current message after serializing something
|
|
|
|
size_t cursor; // points to next available byte, is the size of current message after serializing something
|
|
|
|
size_t max_size;
|
|
|
|
size_t max_size;
|
|
|
|
|
|
|
|
Entity* for_player;
|
|
|
|
} SerState;
|
|
|
|
} SerState;
|
|
|
|
void ser_var(SerState* ser, char* var_pointer, size_t var_size, const char* name, const char* file, int line)
|
|
|
|
void ser_var(SerState* ser, char* var_pointer, size_t var_size, const char* name, const char* file, int line)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -805,6 +808,7 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
|
|
|
|
if (e->is_box)
|
|
|
|
if (e->is_box)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SER_VAR(&e->box_type);
|
|
|
|
SER_VAR(&e->box_type);
|
|
|
|
|
|
|
|
SER_VAR(&e->always_visible);
|
|
|
|
SER_VAR(&e->is_explosion_unlock);
|
|
|
|
SER_VAR(&e->is_explosion_unlock);
|
|
|
|
ser_entityid(ser, &e->next_box);
|
|
|
|
ser_entityid(ser, &e->next_box);
|
|
|
|
ser_entityid(ser, &e->prev_box);
|
|
|
|
ser_entityid(ser, &e->prev_box);
|
|
|
@ -851,15 +855,31 @@ void ser_server_to_client(SerState* ser, ServerToClient* s)
|
|
|
|
for (size_t i = 0; i < gs->cur_next_entity; i++)
|
|
|
|
for (size_t i = 0; i < gs->cur_next_entity; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Entity* e = &gs->entities[i];
|
|
|
|
Entity* e = &gs->entities[i];
|
|
|
|
if (e->exists && !e->is_box) // boxes are serialized after their parent entities, their grid.
|
|
|
|
#define SER_ENTITY() SER_VAR(&entities_done); SER_VAR(&i); ser_entity(ser, gs, e)
|
|
|
|
|
|
|
|
if (e->exists)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SER_VAR(&entities_done);
|
|
|
|
if (!e->is_box && !e->is_grid)
|
|
|
|
SER_VAR(&i);
|
|
|
|
{
|
|
|
|
ser_entity(ser, gs, e);
|
|
|
|
SER_ENTITY();
|
|
|
|
|
|
|
|
}
|
|
|
|
if (e->is_grid)
|
|
|
|
if (e->is_grid)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
bool this_grid_is_visible = false;
|
|
|
|
// serialize boxes always after bodies, so that by the time the boxes
|
|
|
|
// serialize boxes always after bodies, so that by the time the boxes
|
|
|
|
// are loaded in the parent body is loaded in and can be referenced.
|
|
|
|
// are loaded in the parent body is loaded in and can be referenced.
|
|
|
|
|
|
|
|
BOXES_ITER(gs, cur, e)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bool this_box_in_range = (ser->for_player == NULL || (ser->for_player != NULL && V2distsqr(entity_pos(ser->for_player), entity_pos(cur)) < VISION_RADIUS*VISION_RADIUS));
|
|
|
|
|
|
|
|
if (cur->always_visible) this_box_in_range = true;
|
|
|
|
|
|
|
|
if (!this_grid_is_visible && this_box_in_range)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
SER_ENTITY(); // serializes the grid the box is visible in
|
|
|
|
|
|
|
|
this_grid_is_visible = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this_grid_is_visible)
|
|
|
|
|
|
|
|
{
|
|
|
|
BOXES_ITER(gs, cur, e)
|
|
|
|
BOXES_ITER(gs, cur, e)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
EntityID cur_id = get_id(gs, cur);
|
|
|
|
EntityID cur_id = get_id(gs, cur);
|
|
|
@ -870,7 +890,10 @@ void ser_server_to_client(SerState* ser, ServerToClient* s)
|
|
|
|
ser_entity(ser, gs, cur);
|
|
|
|
ser_entity(ser, gs, cur);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef SER_ENTITY
|
|
|
|
}
|
|
|
|
}
|
|
|
|
entities_done = true;
|
|
|
|
entities_done = true;
|
|
|
|
SER_VAR(&entities_done);
|
|
|
|
SER_VAR(&entities_done);
|
|
|
@ -904,7 +927,8 @@ void ser_server_to_client(SerState* ser, ServerToClient* s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void into_bytes(struct ServerToClient* msg, char* bytes, size_t* out_len, size_t max_len)
|
|
|
|
// for_this_player can be null then the entire world will be sent
|
|
|
|
|
|
|
|
void into_bytes(struct ServerToClient* msg, char* bytes, size_t* out_len, size_t max_len, Entity* for_this_player)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(msg->cur_gs != NULL);
|
|
|
|
assert(msg->cur_gs != NULL);
|
|
|
|
assert(msg != NULL);
|
|
|
|
assert(msg != NULL);
|
|
|
@ -914,6 +938,7 @@ void into_bytes(struct ServerToClient* msg, char* bytes, size_t* out_len, size_t
|
|
|
|
.serializing = true,
|
|
|
|
.serializing = true,
|
|
|
|
.cursor = 0,
|
|
|
|
.cursor = 0,
|
|
|
|
.max_size = max_len,
|
|
|
|
.max_size = max_len,
|
|
|
|
|
|
|
|
.for_player = for_this_player,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ser_server_to_client(&ser, msg);
|
|
|
|
ser_server_to_client(&ser, msg);
|
|
|
@ -1058,7 +1083,7 @@ void entity_ensure_in_orbit(Entity* e)
|
|
|
|
|
|
|
|
|
|
|
|
EntityID create_spacestation(GameState* gs)
|
|
|
|
EntityID create_spacestation(GameState* gs)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#define BOX_AT_TYPE(grid, pos, type) { Entity* box = new_entity(gs); box_create(gs, box, grid, pos); box->box_type = type; box->indestructible = indestructible; }
|
|
|
|
#define BOX_AT_TYPE(grid, pos, type) { Entity* box = new_entity(gs); box_create(gs, box, grid, pos); box->box_type = type; box->indestructible = indestructible; box->always_visible = true; }
|
|
|
|
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
|
|
|
|
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
|
|
|
|
|
|
|
|
|
|
|
|
bool indestructible = false;
|
|
|
|
bool indestructible = false;
|
|
|
@ -1125,7 +1150,6 @@ void process(GameState* gs, float dt)
|
|
|
|
p->damage = 0.0f;
|
|
|
|
p->damage = 0.0f;
|
|
|
|
gs->goldpos = (V2){ .x = hash11((float)gs->time) * 20.0f, .y = hash11((float)gs->time - 13.6f) * 20.0f };
|
|
|
|
gs->goldpos = (V2){ .x = hash11((float)gs->time) * 20.0f, .y = hash11((float)gs->time - 13.6f) * 20.0f };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
#if 1
|
|
|
|
V2 world_hand_pos = get_world_hand_pos(gs, &player->input, p);
|
|
|
|
V2 world_hand_pos = get_world_hand_pos(gs, &player->input, p);
|
|
|
|
if (player->input.seat_action)
|
|
|
|
if (player->input.seat_action)
|
|
|
|