summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2024-07-13 13:26:12 +0200
committerLizzy Fleckenstein <lizzy@vlhl.dev>2024-07-13 13:26:12 +0200
commit1c53c39feed656194daf2fc24ddc4d2ee6abf728 (patch)
treef204d520c9c9b15e1b1e1f16a097119530a84e80
parent591232eba1809643df1f4a6075ff9581b8bb2f7a (diff)
server: handle entity z coordinate
Signed-off-by: Lizzy Fleckenstein <lizzy@vlhl.dev>
-rw-r--r--src/server.c126
1 files changed, 78 insertions, 48 deletions
diff --git a/src/server.c b/src/server.c
index 108ae0d..bab8c03 100644
--- a/src/server.c
+++ b/src/server.c
@@ -24,6 +24,11 @@
#include "sig.h"
#include "chunk.h"
+#define MAYBE(T) \
+ typedef struct { bool present; T value; } maybe_##T; \
+ maybe_##T some_##T(T value) { return (maybe_##T) { true, value }; } \
+ maybe_##T none_##T = { 0 };
+
typedef enum {
MAP_VALLEY,
MAP_ISLAND,
@@ -33,6 +38,18 @@ typedef enum {
} map_type;
typedef struct {
+ entity base;
+ int8_t z;
+} srv_entity;
+
+typedef struct {
+ vec2 xy;
+ int8_t z;
+} pos;
+
+MAYBE(pos)
+
+typedef struct {
const char *filename;
str name;
map_type type;
@@ -44,7 +61,6 @@ typedef struct {
bool auth;
str name;
entity_id id;
- int8_t z; // TODO: move to entity
peer conn;
} player;
@@ -54,7 +70,7 @@ typedef struct {
str passphrase;
array(map) maps;
arraybuf(player) players;
- arraybuf(entity) entities;
+ arraybuf(srv_entity) entities;
entity_id next_entity;
} game;
@@ -66,37 +82,42 @@ player *player_from_id(game *g, entity_id id)
return NULL;
}
-entity *entity_from_id(game *g, entity_id id)
+srv_entity *entity_from_id(game *g, entity_id id)
{
for (size_t i = 0; i < g->entities.len; i++)
- if (g->entities.data[i].id == id)
+ if (g->entities.data[i].base.id == id)
return &g->entities.data[i];
return NULL;
}
+pos entity_pos(srv_entity *e)
+{
+ return (pos) { e->base.pos, e->z };
+}
+
box2 player_sight(vec2 center)
{
return box2_around(center, SIGHT_RANGE);
}
-void ser_entity_update(strbuf *w, entity *e, entity_cmd cmd)
+void ser_entity_update(strbuf *w, srv_entity *e, entity_cmd cmd)
{
- ser_entity_id(w, e->id);
+ ser_entity_id(w, e->base.id);
ser_entity_cmd(w, cmd);
switch (cmd) {
case ENTITY_ADD:
- ser_entity_type(w, e->type);
- ser_vec2(w, e->pos);
- switch (e->type) {
+ ser_entity_type(w, e->base.type);
+ ser_vec2(w, e->base.pos);
+ switch (e->base.type) {
case ENTITY_FLOWER:
- ser_flower_type(w, e->flower);
+ ser_flower_type(w, e->base.flower);
break;
default: break;
}
break;
case ENTITY_MOVE:
- ser_vec2(w, e->pos);
+ ser_vec2(w, e->base.pos);
break;
case ENTITY_REMOVE:
break;
@@ -105,19 +126,22 @@ void ser_entity_update(strbuf *w, entity *e, entity_cmd cmd)
}
}
-static vec2 *moved_get_pos(entity *e, entity *moved, vec2 *p_moved)
+static maybe_pos moved_get_pos(srv_entity *e, srv_entity *moved, maybe_pos p_moved)
{
- return (e == moved) ? p_moved : &e->pos;
+ return (e == moved) ? p_moved : some_pos(entity_pos(e));
}
-static bool moved_can_see(entity *a, entity *b, entity *moved, vec2 *p_moved)
+static bool moved_can_see(srv_entity *a, srv_entity *b, srv_entity *moved, maybe_pos p_moved)
{
- vec2 *p_a = moved_get_pos(a, moved, p_moved);
- vec2 *p_b = moved_get_pos(b, moved, p_moved);
- return p_a && p_b && box2_contains(player_sight(*p_a), *p_b);
+ maybe_pos p_a = moved_get_pos(a, moved, p_moved);
+ maybe_pos p_b = moved_get_pos(b, moved, p_moved);
+ return p_a.present
+ && p_b.present
+ && p_a.value.z == p_b.value.z
+ && box2_contains(player_sight(p_a.value.xy), p_b.value.xy);
}
-static entity_cmd moved_check_update(entity *observer, entity *target, entity *moved, vec2 *before, vec2 *after)
+static entity_cmd moved_check_update(srv_entity *observer, srv_entity *target, srv_entity *moved, maybe_pos before, maybe_pos after)
{
bool see_before = moved_can_see(observer, target, moved, before);
bool see_after = moved_can_see(observer, target, moved, after);
@@ -132,18 +156,18 @@ static entity_cmd moved_check_update(entity *observer, entity *target, entity *m
return ENTITY_CMD_COUNT;
}
-void moved_entity(game *g, entity *moved, vec2 *before, vec2 *after)
+void moved_entity(game *g, srv_entity *moved, maybe_pos before, maybe_pos after)
{
for (size_t i = 0; i < g->players.len; i++) {
player *p = &g->players.data[i];
if (!p->auth) continue;
- entity *observer = entity_from_id(g, p->id);
+ srv_entity *observer = entity_from_id(g, p->id);
if (observer == moved) {
SEND_PKT(p->conn, CPKT_ENTITY,
for (size_t j = 0; j < g->entities.len; j++) {
- entity *target = &g->entities.data[j];
+ srv_entity *target = &g->entities.data[j];
entity_cmd cmd = moved_check_update(observer, target, moved, before, after);
if (cmd != ENTITY_CMD_COUNT)
ser_entity_update(&pkt, target, cmd);
@@ -185,18 +209,19 @@ bool silly_noise(vec2 pos, uint32_t grid, double sillyness, int seed)
return x % grid == 0 && y % grid == 0;
}
-entity *spawn_entity(game *g, entity_type type, vec2 pos)
+srv_entity *spawn_entity(game *g, entity_type type, pos p)
{
- entity *e = ARR_APPEND(g->entities);
- e->id = g->next_entity++;
- e->type = type;
- e->pos = pos;
+ srv_entity *e = ARR_APPEND(g->entities);
+ e->base.id = g->next_entity++;
+ e->base.type = type;
+ e->base.pos = p.xy;
+ e->z = p.z;
return e;
}
-void remove_entity(game *g, entity *e)
+void remove_entity(game *g, srv_entity *e)
{
- moved_entity(g, e, &e->pos, NULL);
+ moved_entity(g, e, some_pos(entity_pos(e)), none_pos);
ARR_REMOVE(g->entities, e);
}
@@ -204,7 +229,7 @@ void map_load_node(game *g, map *m, uvec2 v, color col)
{
uint32_t ucol = color_to_u32(col);
- vec2 pos = vec2_add(m->chunk.bounds.pos, CVEC2(v));
+ pos p = { vec2_add(m->chunk.bounds.pos, CVEC2(v)), m->z };
node *n = chunk_index(m->chunk, v);
*n = (node) { 0 };
@@ -215,30 +240,30 @@ void map_load_node(game *g, map *m, uvec2 v, color col)
switch (ucol) {
case 0xff9de2:
- spawn_entity(g, ENTITY_FLOWER, pos)->flower = rand() % FLOWER_COUNT;
+ spawn_entity(g, ENTITY_FLOWER, p)->base.flower = rand() % FLOWER_COUNT;
[[fallthrough]];
case 0x00880d: n->type = N_GRASS;
- n->variant = silly_noise(pos, 3, 1.0, 0);
+ n->variant = silly_noise(p.xy, 3, 1.0, 0);
break;
case 0x595959: n->type = N_ROCK; n->z = 1; break;
case 0x001b51:
- spawn_entity(g, ENTITY_FLOWER, pos)->flower = FLOWER_DANDELION;
+ spawn_entity(g, ENTITY_FLOWER, p)->base.flower = FLOWER_DANDELION;
[[fallthrough]];
case 0x484848: n->type = N_ROCK; n->z = 2; break;
case 0x00ffe8:
- spawn_entity(g, ENTITY_FLOWER, pos)->flower = FLOWER_DANDELION;
+ spawn_entity(g, ENTITY_FLOWER, p)->base.flower = FLOWER_DANDELION;
[[fallthrough]];
case 0x373737: n->type = N_ROCK; n->z = 3; break;
case 0xa09700: n->type = N_PATH; break;
case 0x015100: n->type = N_NEEDLE_TREE; break;
case 0x00c6ff: n->type = N_WATER;
- n->variant = silly_noise(pos, 3, 0.7, 1);
+ n->variant = silly_noise(p.xy, 3, 0.7, 1);
n->z = -1;
break;
case 0x5c3b12: n->type = N_PLANK; break;
case 0x016300: n->type = N_BIG_TREE; break;
case 0xfce84e: n->type = N_SAND;
- n->variant = silly_noise(pos, 4, 1.0, 1);
+ n->variant = silly_noise(p.xy, 4, 1.0, 1);
break;
default:
fprintf(stderr, "invalid color in map %.*s at %"PRIu32" %"PRIu32": %06x\n",
@@ -348,7 +373,7 @@ void player_remove(player *p, game *g)
player_cleanup(p);
bool auth = p->auth;
- entity_id id = p->id;
+ entity_id id = p->id;
ARR_REMOVE(g->players, p);
@@ -401,17 +426,19 @@ bool handle_hi(str pkt, player *p, game *g)
p->auth = true;
p->name = str_clone(name);
- entity *e = ARR_APPEND(g->entities);
- e->id = p->id;
- e->type = ENTITY_PLAYER;
- e->pos.x = e->pos.y = 0;
- p->z = 0;
+ srv_entity *e = ARR_APPEND(g->entities);
+ e->base.id = p->id;
+ e->base.type = ENTITY_PLAYER;
+ e->base.pos.x = e->base.pos.y = 0;
+ e->z = 0;
SEND_PKT(p->conn, CPKT_HI, ser_str(&pkt, g->motd);)
send_players(g);
- moved_entity(g, e, NULL, &e->pos);
- send_nodes(p, g, player_sight(e->pos), p->z);
+ pos ent_p = entity_pos(e);
+
+ moved_entity(g, e, none_pos, some_pos(ent_p));
+ send_nodes(p, g, player_sight(ent_p.xy), ent_p.z);
return true;
}
@@ -425,16 +452,19 @@ bool handle_move(str pkt, player *p, game *g)
if (vec2_iszero(v))
return false;
- entity *e = entity_from_id(g, p->id);
+ srv_entity *e = entity_from_id(g, p->id);
+
+ pos old_pos = entity_pos(e);
// yolo
- vec2 old_pos = e->pos;
- e->pos = vec2_add(v, e->pos);
+ e->base.pos = vec2_add(v, e->base.pos);
+
+ pos new_pos = entity_pos(e);
- moved_entity(g, e, &old_pos, &e->pos);
+ moved_entity(g, e, some_pos(old_pos), some_pos(new_pos));
// TODO: only send newly visible nodes
- send_nodes(p, g, player_sight(e->pos), p->z);
+ send_nodes(p, g, player_sight(new_pos.xy), new_pos.z);
return true;
}