Only send player what's near them, other fixes

- When zoom out players get big
main
Cameron Murphy Reikes 2 years ago
parent 0efd1fca91
commit dd5731eb45

@ -578,6 +578,9 @@ V2 entity_pos(Entity* e)
if (e->is_box) {
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 {
assert(e->body != NULL);
return cp_to_v2(cpBodyGetPosition(e->body));
@ -608,13 +611,13 @@ void update_from(cpBody* body, struct BodyData* data)
cpBodySetAngularVelocity(body, data->angular_velocity);
}
//#define WRITE_VARNAMES // debugging feature horrible for network
typedef struct SerState
{
char* bytes;
bool serializing;
size_t cursor; // points to next available byte, is the size of current message after serializing something
size_t max_size;
Entity* for_player;
} SerState;
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)
{
SER_VAR(&e->box_type);
SER_VAR(&e->always_visible);
SER_VAR(&e->is_explosion_unlock);
ser_entityid(ser, &e->next_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++)
{
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);
SER_VAR(&i);
ser_entity(ser, gs, e);
if (!e->is_box && !e->is_grid)
{
SER_ENTITY();
}
if (e->is_grid)
{
bool this_grid_is_visible = false;
// 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.
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)
{
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);
}
}
}
}
#undef SER_ENTITY
}
entities_done = true;
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 != NULL);
@ -914,6 +938,7 @@ void into_bytes(struct ServerToClient* msg, char* bytes, size_t* out_len, size_t
.serializing = true,
.cursor = 0,
.max_size = max_len,
.for_player = for_this_player,
};
ser_server_to_client(&ser, msg);
@ -1058,7 +1083,7 @@ void entity_ensure_in_orbit(Entity* e)
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)
bool indestructible = false;
@ -1125,7 +1150,6 @@ void process(GameState* gs, float dt)
p->damage = 0.0f;
gs->goldpos = (V2){ .x = hash11((float)gs->time) * 20.0f, .y = hash11((float)gs->time - 13.6f) * 20.0f };
}
#if 1
V2 world_hand_pos = get_world_hand_pos(gs, &player->input, p);
if (player->input.seat_action)

@ -398,9 +398,7 @@ static void draw_dots(V2 camera_pos, float gap)
for (int x = -num; x < num; x++) {
for (int y = -num; y < num; y++) {
V2 star = (V2){ (float)x * gap, (float)y * gap };
if (fabsf(star.x - camera_pos.x) > VISION_RADIUS)
continue;
if (fabsf(star.y - camera_pos.y) > VISION_RADIUS)
if(V2lengthsqr(V2sub(star, camera_pos)) > VISION_RADIUS*VISION_RADIUS)
continue;
star.x += hash11(star.x * 100.0f + star.y * 67.0f) * gap;
@ -692,6 +690,7 @@ frame(void)
sgp_translate(-camera_pos.x, -camera_pos.y);
draw_dots(camera_pos, 1.5f); // in plane dots
// hand reached limit circle
if (myentity() != NULL) {
static float hand_reach_alpha = 1.0f;
@ -700,6 +699,13 @@ frame(void)
draw_circle(entity_pos(myentity()), MAX_HAND_REACH);
}
// vision circle, what player can see
if (myentity() != NULL)
{
set_color(colhexcode(0x4685e3));
draw_circle(entity_pos(myentity()), VISION_RADIUS);
}
float halfbox = BOX_SIZE / 2.0f;
// mouse frozen, debugging tool
@ -725,6 +731,8 @@ frame(void)
}
}
static float player_scaling = 1.0f;
player_scaling = lerp(player_scaling, zoom < 6.5f ? 100.0f : 1.0f, dt * 7.0f);
for (size_t i = 0; i < gs.cur_next_entity; i++) {
Entity* e = &gs.entities[i];
if (!e->exists)
@ -826,7 +834,8 @@ frame(void)
sgp_rotate_at(entity_rotation(e), entity_pos(e).x, entity_pos(e).y);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
sgp_set_image(0, image_player);
draw_texture_rectangle_centered(entity_pos(e), PLAYER_SIZE);
printf("%f\n", zoom);
draw_texture_rectangle_centered(entity_pos(e), V2scale(PLAYER_SIZE, player_scaling));
sgp_reset_image(0);
}
}

@ -229,16 +229,23 @@ void server(void* data)
{
continue;
}
int this_player_index = (int)(int64_t)server->peers[i].data;
Entity* this_player_entity = get_entity(&gs, gs.players[this_player_index].entity);
if (this_player_entity == NULL) continue;
// @Speed don't recreate the packet for every peer, gets expensive copying gamestate over and over again
char* bytes_buffer = malloc(sizeof *bytes_buffer * MAX_BYTES_SIZE);
char* compressed_buffer = malloc(sizeof * compressed_buffer * MAX_BYTES_SIZE);
struct ServerToClient to_send;
to_send.cur_gs = &gs;
to_send.your_player = (int)(int64_t)server->peers[i].data;
to_send.your_player = this_player_index;
size_t len = 0;
into_bytes(&to_send, bytes_buffer, &len, MAX_BYTES_SIZE);
into_bytes(&to_send, bytes_buffer, &len, MAX_BYTES_SIZE, this_player_entity);
if (len > MAX_BYTES_SIZE - 8)
{
Log("Too much data quitting!\n");
exit(-1);
}
size_t compressed_len = 0;
lzo1x_1_compress(bytes_buffer, len, compressed_buffer, &compressed_len, (void*)lzo_working_mem);

@ -18,7 +18,7 @@
#define VISION_RADIUS 16.0f
#define MAX_BYTES_SIZE 1024 * 128 // maximum size of serialized gamestate buffer
#define SUN_RADIUS 10.0f
#define INSTANT_DEATH_DISTANCE_FROM_SUN 500.0f
#define INSTANT_DEATH_DISTANCE_FROM_SUN 2000.0f
#define SUN_POS ((V2){50.0f,0.0f})
#define SUN_GRAVITY_STRENGTH (9.0e2f)
#define SOLAR_ENERGY_PER_SECOND 0.02f
@ -170,6 +170,7 @@ typedef struct Entity
// boxes
bool is_box;
bool always_visible; // always serialized to the player
enum BoxType box_type;
bool is_explosion_unlock;
EntityID next_box;
@ -262,7 +263,7 @@ void destroy(struct GameState* gs);
void process(struct GameState* gs, float dt); // does in place
Entity* closest_to_point_in_radius(struct GameState* gs, V2 point, float radius);
uint64_t tick(struct GameState* gs);
void into_bytes(struct ServerToClient* gs, char* out_bytes, size_t* out_len, size_t max_len);
void into_bytes(struct ServerToClient* msg, char* bytes, size_t* out_len, size_t max_len, Entity* for_this_player);
void from_bytes(struct ServerToClient* gs, char* bytes, size_t max_len);
// entities
@ -336,9 +337,14 @@ static V2 V2scale(V2 a, float f)
};
}
static float V2lengthsqr(V2 v)
{
return v.x * v.x + v.y * v.y;
}
static float V2length(V2 v)
{
return sqrtf(v.x * v.x + v.y * v.y);
return sqrtf(V2lengthsqr(v));
}
static V2 V2normalize(V2 v)
@ -346,6 +352,7 @@ static V2 V2normalize(V2 v)
return V2scale(v, 1.0f / V2length(v));
}
static float V2dot(V2 a, V2 b)
{
return a.x * b.x + a.y * b.y;
@ -394,6 +401,11 @@ static inline float clamp01(float f)
return fmaxf(0.0f, fminf(f, 1.0f));
}
static float V2distsqr(V2 from, V2 to)
{
return V2lengthsqr(V2sub(to, from));
}
static inline float clamp(float f, float minimum, float maximum)
{
if (f < minimum)

Loading…
Cancel
Save