summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/array.h2
-rw-r--r--include/content.h15
-rw-r--r--src/client.c234
-rw-r--r--src/server.c187
4 files changed, 311 insertions, 127 deletions
diff --git a/include/array.h b/include/array.h
index 5f81798..9affdde 100644
--- a/include/array.h
+++ b/include/array.h
@@ -6,6 +6,8 @@
#define ARRAY_H
#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
#define len(X) (sizeof X / sizeof *X)
#define array(T) struct { size_t len; T *data; }
diff --git a/include/content.h b/include/content.h
index 16118f6..ef27e22 100644
--- a/include/content.h
+++ b/include/content.h
@@ -14,9 +14,7 @@
#define PKT_NODES_MAX (50*50)
typedef enum : uint16_t {
- N_VALLEY_FLOWER = 0,
- N_MOUNTAIN_FLOWER,
- N_BIG_TREE,
+ N_BIG_TREE = 0,
N_NEEDLE_TREE,
N_ROCK,
N_WATER,
@@ -133,6 +131,7 @@ typedef uint64_t entity_id;
typedef enum : uint16_t {
ENTITY_PLAYER = 0,
+ ENTITY_FLOWER,
} entity_type;
#define ser_entity_type ser_u16
@@ -142,11 +141,21 @@ typedef enum : uint8_t {
ENTITY_ADD = 0, // type
ENTITY_REMOVE,
ENTITY_MOVE, // x y
+ ENTITY_CMD_COUNT,
} entity_cmd;
#define ser_entity_cmd ser_u8
#define deser_entity_cmd deser_u8
+typedef struct {
+ entity_id id;
+ entity_type type;
+ vec2 pos;
+ union {
+ flower_type flower;
+ };
+} entity;
+
enum : uint16_t {
CPKT_HI = 0, // len motd
CPKT_FAIL, // fail_reason
diff --git a/src/client.c b/src/client.c
index 78511c6..679fcd4 100644
--- a/src/client.c
+++ b/src/client.c
@@ -26,27 +26,35 @@ typedef struct {
str pass;
entity_id self_id;
array(player) players;
+ arraybuf(entity) entities;
str server_motd;
chunk map;
node *map_swap;
- vec2 player_pos;
- char *termbuf_buf;
- size_t termbuf_size;
- FILE *termbuf;
+ char *frame_buf;
+ size_t frame_size;
+ FILE *frame;
} client;
-void gfx_alt_buffer(bool enable)
+player *player_from_id(client *c, entity_id id)
{
- if (enable)
- printf("\e[?1049h\e[?25l");
- else
- printf("\e[?1049l\e[?25h");
- fflush(stdout);
+ for (size_t i = 0; i < c->players.len; i++)
+ if (c->players.data[i].id == id)
+ return &c->players.data[i];
+ return NULL;
}
-void gfx_clear_effects(client *c)
+entity *entity_from_id(client *c, entity_id id)
+{
+ for (size_t i = 0; i < c->entities.len; i++)
+ if (c->entities.data[i].id == id)
+ return &c->entities.data[i];
+ return NULL;
+}
+
+void gfx_alt_buffer(bool enable)
{
- fprintf(c->termbuf, "\e[0m");
+ str out = enable ? S("\e[?1049h\e[?25l") : S("\e[?1049l\e[?25h");
+ write(STDOUT_FILENO, out.data, out.len);
}
typedef struct {
@@ -55,83 +63,56 @@ typedef struct {
color old;
} color_layer;
+void gfx_clear_effects(client *c)
+{
+ fprintf(c->frame, "\e[0m");
+}
+
void gfx_set_color(client *c, color_layer *l, color col)
{
if (l->has_old && l->old.r == col.r && l->old.g == col.g && l->old.b == col.b)
return;
- fprintf(c->termbuf, "\e[%u;2;%u;%u;%um", l->bg ? 48 : 38, col.r, col.g, col.b);
+ fprintf(c->frame, "\e[%u;2;%u;%u;%um", l->bg ? 48 : 38, col.r, col.g, col.b);
l->has_old = true;
l->old = col;
}
void gfx_clear(client *c)
{
- fprintf(c->termbuf, "\e[2J");
+ fprintf(c->frame, "\e[2J");
}
#define C color_from_u32
-#define DISPLAY_BG(X) (node_display) { X, { 0 }, NULL }
-#define DISPLAY(...) (node_display) { __VA_ARGS__ }
+#define DISPLAY(...) (tile_display) { __VA_ARGS__ }
+#define DISPLAY_BG(X) (tile_display) { X, { 0 }, NULL }
#define DISPLAY_ERR DISPLAY(C(0xff0000), C(0x000000), " ?")
typedef struct {
color bg;
color fg;
char *texture;
-} node_display;
-
-bool gfx_rock_bg(node *n, color *c)
-{
- switch (n->z) {
- case 1: *c = C(0x595959); return true;
- case 2: *c = C(0x484848); return true;
- case 3: *c = C(0x373737); return true;
- default: return false;
- }
-}
-
-color gfx_grass_bg(vec2 pos)
-{
- return C(0x00880d);
-}
+} tile_display;
bool gfx_water_wave(vec2 pos)
{
return true;
}
-node_display gfx_render_node(client *c, vec2 pos, node *n)
+tile_display gfx_render_node(client *c, vec2 pos, node *n)
{
if (!n->present)
return DISPLAY(C(0x555555), C(0xffffff), " ?");
switch (n->type) {
- case N_VALLEY_FLOWER:
- case N_MOUNTAIN_FLOWER: {
- node_display d = {0};
- if (n->type == N_VALLEY_FLOWER)
- d.bg = gfx_grass_bg(pos);
- else if (!gfx_rock_bg(n, &d.bg))
- return DISPLAY_ERR;
- switch (n->variant) {
- case FLOWER_ROSE: d.texture = "🌹"; break;
- case FLOWER_HIBISCUS: d.texture = "🌺"; break;
- case FLOWER_SUNFLOWER: d.texture = "🌻"; break;
- case FLOWER_DANDELION: d.texture = "🌼"; break;
- case FLOWER_TULIP: d.texture = "🌷"; break;
- default: return DISPLAY_ERR;
- }
- return d;
- }
- case N_ROCK: {
- node_display d = {0};
- if (!gfx_rock_bg(n, &d.bg))
- return DISPLAY_ERR;
- return d;
+ case N_ROCK: switch (n->z) {
+ case 1: return DISPLAY_BG(C(0x595959));
+ case 2: return DISPLAY_BG(C(0x484848));
+ case 3: return DISPLAY_BG(C(0x373737));
+ default: return DISPLAY_ERR;
}
case N_WATER: return DISPLAY(C(0x00c6ff), C(0x0d79de),
n->variant && gfx_water_wave(pos) ? " ~" : NULL);
- case N_GRASS: return DISPLAY(gfx_grass_bg(pos), C(0x1c571e), n->variant ? " M" : NULL);
+ case N_GRASS: return DISPLAY(C(0x00880d), C(0x1c571e), n->variant ? " M" : NULL);
case N_SAND: return DISPLAY(C(0xded485), C(0xe3a112), n->variant ? " ~" : NULL);
case N_NEEDLE_TREE: return DISPLAY_BG(C(0x015100));
case N_PATH: return DISPLAY_BG(C(0xa09700));
@@ -141,49 +122,87 @@ node_display gfx_render_node(client *c, vec2 pos, node *n)
}
}
+char *gfx_render_entity(client *c, entity *e)
+{
+ switch (e->type) {
+ case ENTITY_PLAYER:
+ return e->id == c->self_id ? "🙂" : "😀";
+ case ENTITY_FLOWER: switch (e->flower) {
+ case FLOWER_ROSE: return "🌹";
+ case FLOWER_HIBISCUS: return "🌺";
+ case FLOWER_SUNFLOWER: return "🌻";
+ case FLOWER_DANDELION: return "🌼";
+ case FLOWER_TULIP: return "🌷";
+ default: return NULL;
+ }
+ default: return NULL;
+ }
+}
+
#undef C
#undef DISPLAY
#undef DISPLAY_ERR
void gfx_render(client *c, uint64_t dtime)
{
- rewind(c->termbuf);
+ rewind(c->frame);
gfx_clear(c);
- fprintf(c->termbuf, "\e[H");
- fprintf(c->termbuf, "%.*s\n", PSTR(c->server_motd));
- for (size_t i = 0; i < c->players.len; i++)
- fprintf(c->termbuf, "%.*s\n", PSTR(c->players.data[i].name));
color_layer fg = {0};
color_layer bg = {0};
bg.bg = true;
- for (size_t y = 0; y < c->map.bounds.size.y; y++) {
- for (size_t x = 0; x < c->map.bounds.size.y; x++) {
- uvec2 off = UVEC2(x, y);
- vec2 pos = vec2_add(c->map.bounds.pos, CVEC2(off));
+ // HUD
+ fprintf(c->frame, "\e[H");
+ fprintf(c->frame, "%.*s\n", PSTR(c->server_motd));
+ for (size_t i = 0; i < c->players.len; i++)
+ fprintf(c->frame, "%.*s\n", PSTR(c->players.data[i].name));
+
+ // map
+ tile_display tiles[c->map.bounds.size.x][c->map.bounds.size.y];
+ for (size_t x = 0; x < c->map.bounds.size.x; x++)
+ for (size_t y = 0; y < c->map.bounds.size.x; y++) {
+ uvec2 off = UVEC2(x, y);
+ vec2 pos = vec2_add(c->map.bounds.pos, CVEC2(off));
+ tiles[x][y] = gfx_render_node(c, pos, chunk_index(c->map, off));
+ }
- node_display dis = gfx_render_node(c, pos, chunk_index(c->map, off));
+ // entities
+ for (size_t i = 0; i < c->entities.len; i++) {
+ entity *e = &c->entities.data[i];
+ if (!box2_contains(c->map.bounds, e->pos)) // just to be safe...
+ continue;
+ vec2 pos = vec2_sub(e->pos, c->map.bounds.pos);
+ tile_display *t = &tiles[pos.x][pos.y];
+
+ char *tex = gfx_render_entity(c, e);
+ if (tex == NULL)
+ t->texture = "❓";
+ else
+ t->texture = tex;
+ }
+
+ // flush map & entities
+ for (size_t y = 0; y < c->map.bounds.size.y; y++) {
+ for (size_t x = 0; x < c->map.bounds.size.x; x++) {
+ tile_display dis = tiles[x][y];
gfx_set_color(c, &bg, dis.bg);
- if (vec2_eq(pos, c->player_pos)) {
- fprintf(c->termbuf, "🙂");
- } else if (dis.texture) {
+ if (dis.texture) {
gfx_set_color(c, &fg, dis.fg);
- fprintf(c->termbuf, "%s", dis.texture);
+ fprintf(c->frame, "%s", dis.texture);
} else {
- fprintf(c->termbuf, " ");
+ fprintf(c->frame, " ");
}
}
gfx_clear_effects(c);
- bg.has_old = false;
fg.has_old = false;
- fprintf(c->termbuf, "\n");
+ bg.has_old = false;
+ fprintf(c->frame, "\n");
}
- fflush(c->termbuf);
- fprintf(stderr, "size: %ld\n", ftell(c->termbuf));
- write(STDOUT_FILENO, c->termbuf_buf, ftell(c->termbuf));
- //fwrite(c->termbuf_buf, 1, ftell(c->termbuf), stdout);
- //fflush(stdout);
+
+ // submit
+ fflush(c->frame);
+ write(STDOUT_FILENO, c->frame_buf, ftell(c->frame));
}
void free_players(client *c)
@@ -204,12 +223,13 @@ void client_exit(client *c, int ret)
free(c->server_motd.data);
free_players(c);
+ free(c->entities.data);
peer_free(&c->conn);
tcsetattr(STDIN_FILENO, TCSANOW, &c->oldtio);
- if (c->termbuf) fclose(c->termbuf);
- free(c->termbuf_buf);
+ if (c->frame) fclose(c->frame);
+ free(c->frame_buf);
gfx_alt_buffer(false);
exit(ret);
@@ -250,6 +270,16 @@ void map_set_center(client *c, vec2 center)
chunk_clear(c->map);
chunk_copy(c->map, old);
+
+ for (size_t i = 0; i < c->entities.len;) {
+ entity *e = &c->entities.data[i];
+ if (box2_contains(c->map.bounds, e->pos)) {
+ i++;
+ continue;
+ }
+
+ ARR_REMOVE(c->entities, e);
+ }
}
bool handle_nodes(str *pkt, client *c)
@@ -276,6 +306,7 @@ bool handle_reset_map(str *pkt, client *c)
{
(void) pkt;
chunk_clear(c->map);
+ c->entities.len = 0;
return true;
}
@@ -310,29 +341,50 @@ bool handle_hi(str *pkt, client *c)
bool handle_entity(str *pkt, client *c)
{
- uint16_t num;
- if (!deser_u16(pkt, &num)) return false;
- for (uint16_t i = 0; i < num; i++) {
+ while (pkt->len > 0) {
entity_id id;
entity_cmd cmd;
if (!deser_entity_id(pkt, &id)) return false;
if (!deser_entity_cmd(pkt, &cmd)) return false;
+ entity *e = entity_from_id(c, id);
switch (cmd) {
case ENTITY_ADD: {
- entity_type type;
- if (!deser_entity_type(pkt, &type)) return false;
+ entity ent = {0};
+ ent.id = id;
+ if (!deser_entity_type(pkt, &ent.type)) return false;
+ if (!deser_vec2(pkt, &ent.pos)) return false;
+ switch (ent.type) {
+ case ENTITY_PLAYER: break;
+ case ENTITY_FLOWER:
+ if (!deser_flower_type(pkt, &ent.flower)) return false;
+ break;
+ default: return false;
+ }
+ if (e == NULL)
+ *ARR_APPEND(c->entities) = ent;
+ else
+ *e = ent; // this... shouldn't happen
} break;
- case ENTITY_REMOVE: break;
- case ENTITY_MOVE:
+ case ENTITY_REMOVE:
+ if (e == NULL) continue; // consider returning false? shouldn't happen
+ ARR_REMOVE(c->entities, e);
+ break;
+ case ENTITY_MOVE: {
vec2 pos;
if (!deser_vec2(pkt, &pos)) return false;
- if (id == c->self_id)
- map_set_center(c, c->player_pos = pos);
+ if (e == NULL) continue;
- break;
+ e->pos = pos;
+
+ // TODO: remove entity if out of bounds?
+ // shouldn't happen tho, unless for moving the self player entity...
+
+ if (id == c->self_id)
+ map_set_center(c, pos);
+ } break;
default: return false;
}
}
@@ -388,7 +440,7 @@ int main(int argc, char **argv)
str server_name = S("server");
peer_init(&c.conn, socket, &server_name);
- c.termbuf = open_memstream(&c.termbuf_buf, &c.termbuf_size);
+ c.frame = open_memstream(&c.frame_buf, &c.frame_size);
gfx_alt_buffer(true);
SEND_PKT(c.conn, SPKT_HI,
diff --git a/src/server.c b/src/server.c
index 974e396..108ae0d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -44,8 +44,7 @@ typedef struct {
bool auth;
str name;
entity_id id;
- vec2 pos;
- int8_t z;
+ int8_t z; // TODO: move to entity
peer conn;
} player;
@@ -55,9 +54,109 @@ typedef struct {
str passphrase;
array(map) maps;
arraybuf(player) players;
+ arraybuf(entity) entities;
entity_id next_entity;
} game;
+player *player_from_id(game *g, entity_id id)
+{
+ for (size_t i = 0; i < g->players.len; i++)
+ if (g->players.data[i].id == id)
+ return &g->players.data[i];
+ return NULL;
+}
+
+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)
+ return &g->entities.data[i];
+ return NULL;
+}
+
+box2 player_sight(vec2 center)
+{
+ return box2_around(center, SIGHT_RANGE);
+}
+
+void ser_entity_update(strbuf *w, entity *e, entity_cmd cmd)
+{
+ ser_entity_id(w, e->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) {
+ case ENTITY_FLOWER:
+ ser_flower_type(w, e->flower);
+ break;
+ default: break;
+ }
+ break;
+ case ENTITY_MOVE:
+ ser_vec2(w, e->pos);
+ break;
+ case ENTITY_REMOVE:
+ break;
+ case ENTITY_CMD_COUNT:
+ break; // unreachable
+ }
+}
+
+static vec2 *moved_get_pos(entity *e, entity *moved, vec2 *p_moved)
+{
+ return (e == moved) ? p_moved : &e->pos;
+}
+
+static bool moved_can_see(entity *a, entity *b, entity *moved, vec2 *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);
+}
+
+static entity_cmd moved_check_update(entity *observer, entity *target, entity *moved, vec2 *before, vec2 *after)
+{
+ bool see_before = moved_can_see(observer, target, moved, before);
+ bool see_after = moved_can_see(observer, target, moved, after);
+
+ if (see_before && !see_after)
+ return ENTITY_REMOVE;
+ else if (!see_before && see_after)
+ return ENTITY_ADD;
+ else if (see_before && see_after && target == moved)
+ return ENTITY_MOVE;
+ else
+ return ENTITY_CMD_COUNT;
+}
+
+void moved_entity(game *g, entity *moved, vec2 *before, vec2 *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);
+
+ 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];
+ entity_cmd cmd = moved_check_update(observer, target, moved, before, after);
+ if (cmd != ENTITY_CMD_COUNT)
+ ser_entity_update(&pkt, target, cmd);
+ }
+ )
+ } else {
+ entity_cmd cmd = moved_check_update(observer, moved, moved, before, after);
+ if (cmd != ENTITY_CMD_COUNT)
+ SEND_PKT(p->conn, CPKT_ENTITY, ser_entity_update(&pkt, moved, cmd);)
+ }
+ }
+}
+
node *map_node(game *g, vec2 p, int8_t z)
{
for (size_t i = 0; i < g->maps.len; i++) {
@@ -84,10 +183,24 @@ bool silly_noise(vec2 pos, uint32_t grid, double sillyness, int seed)
y += round(noise2d(y/grid, x/grid, 0, seed) * sillyness);
return x % grid == 0 && y % grid == 0;
-#undef SMOD
}
-void map_load_node(map *m, uvec2 v, color col)
+entity *spawn_entity(game *g, entity_type type, vec2 pos)
+{
+ entity *e = ARR_APPEND(g->entities);
+ e->id = g->next_entity++;
+ e->type = type;
+ e->pos = pos;
+ return e;
+}
+
+void remove_entity(game *g, entity *e)
+{
+ moved_entity(g, e, &e->pos, NULL);
+ ARR_REMOVE(g->entities, e);
+}
+
+void map_load_node(game *g, map *m, uvec2 v, color col)
{
uint32_t ucol = color_to_u32(col);
@@ -101,20 +214,21 @@ void map_load_node(map *m, uvec2 v, color col)
return;
switch (ucol) {
+ case 0xff9de2:
+ spawn_entity(g, ENTITY_FLOWER, pos)->flower = rand() % FLOWER_COUNT;
+ [[fallthrough]];
case 0x00880d: n->type = N_GRASS;
n->variant = silly_noise(pos, 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;
+ [[fallthrough]];
case 0x484848: n->type = N_ROCK; n->z = 2; break;
+ case 0x00ffe8:
+ spawn_entity(g, ENTITY_FLOWER, pos)->flower = FLOWER_DANDELION;
+ [[fallthrough]];
case 0x373737: n->type = N_ROCK; n->z = 3; break;
- case 0x00ffe8: n->type = N_MOUNTAIN_FLOWER;
- n->variant = FLOWER_DANDELION;
- n->z = 3;
- break;
- case 0x001b51: n->type = N_MOUNTAIN_FLOWER;
- n->variant = FLOWER_DANDELION;
- n->z = 2;
- break;
case 0xa09700: n->type = N_PATH; break;
case 0x015100: n->type = N_NEEDLE_TREE; break;
case 0x00c6ff: n->type = N_WATER;
@@ -122,9 +236,6 @@ void map_load_node(map *m, uvec2 v, color col)
n->z = -1;
break;
case 0x5c3b12: n->type = N_PLANK; break;
- case 0xff9de2: n->type = N_VALLEY_FLOWER;
- n->variant = rand() % FLOWER_COUNT;
- break;
case 0x016300: n->type = N_BIG_TREE; break;
case 0xfce84e: n->type = N_SAND;
n->variant = silly_noise(pos, 4, 1.0, 1);
@@ -137,7 +248,7 @@ void map_load_node(map *m, uvec2 v, color col)
}
}
-bool map_load(map *m)
+bool map_load(game *g, map *m)
{
#define TRY(expr, ...) if (!(expr)) { \
fprintf(stderr, __VA_ARGS__); \
@@ -188,7 +299,7 @@ bool map_load(map *m)
}
}*/
- map_load_node(m, UVEC2(x, y), (color) { p[0], p[1], p[2] });
+ map_load_node(g, m, UVEC2(x, y), (color) { p[0], p[1], p[2] });
}
}
@@ -225,7 +336,7 @@ void send_nodes(player *p, game *g, box2 bounds, int8_t z)
)
}
-void player_free(player *p)
+void player_cleanup(player *p)
{
peer_free(&p->conn);
if (p->auth)
@@ -234,11 +345,17 @@ void player_free(player *p)
void player_remove(player *p, game *g)
{
- player_free(p);
+ player_cleanup(p);
bool auth = p->auth;
+ entity_id id = p->id;
+
ARR_REMOVE(g->players, p);
- if (auth) send_players(g);
+
+ if (auth) {
+ remove_entity(g, entity_from_id(g, id));
+ send_players(g);
+ }
}
void game_exit(game *g, int ret)
@@ -253,7 +370,7 @@ void game_exit(game *g, int ret)
free(g->maps.data);
for (size_t i = 0; i < g->players.len; i++)
- player_free(&g->players.data[i]);
+ player_cleanup(&g->players.data[i]);
free(g->players.data);
exit(ret);
@@ -283,18 +400,23 @@ bool handle_hi(str pkt, player *p, game *g)
p->auth = true;
p->name = str_clone(name);
- p->pos.x = p->pos.y = 0;
+
+ entity *e = ARR_APPEND(g->entities);
+ e->id = p->id;
+ e->type = ENTITY_PLAYER;
+ e->pos.x = e->pos.y = 0;
p->z = 0;
SEND_PKT(p->conn, CPKT_HI, ser_str(&pkt, g->motd);)
send_players(g);
- send_nodes(p, g, box2_around(p->pos, SIGHT_RANGE), p->z);
+ moved_entity(g, e, NULL, &e->pos);
+ send_nodes(p, g, player_sight(e->pos), p->z);
return true;
}
-bool handle_move(str pkt, player *p, [[maybe_unused]] game *g)
+bool handle_move(str pkt, player *p, game *g)
{
dir d;
if (!deser_dir(&pkt, &d)) return false;
@@ -303,17 +425,16 @@ bool handle_move(str pkt, player *p, [[maybe_unused]] game *g)
if (vec2_iszero(v))
return false;
+ entity *e = entity_from_id(g, p->id);
+
// yolo
- p->pos = vec2_add(v, p->pos);
- SEND_PKT(p->conn, CPKT_ENTITY,
- ser_u16(&pkt, 1);
- ser_entity_id(&pkt, p->id);
- ser_entity_cmd(&pkt, ENTITY_MOVE);
- ser_vec2(&pkt, p->pos);
- )
+ vec2 old_pos = e->pos;
+ e->pos = vec2_add(v, e->pos);
+
+ moved_entity(g, e, &old_pos, &e->pos);
// TODO: only send newly visible nodes
- send_nodes(p, g, box2_around(p->pos, SIGHT_RANGE), p->z);
+ send_nodes(p, g, player_sight(e->pos), p->z);
return true;
}
@@ -355,7 +476,7 @@ int main()
.chunk = chunk_alloc((box2) { { -50, -50 }, { 100, 100 } }),
};
- if (!map_load(&g.maps.data[0]))
+ if (!map_load(&g, &g.maps.data[0]))
game_exit(&g, EXIT_FAILURE);
if ((g.accept_fd = socket_create("0.0.0.0", "4560", true)) < 0)