refactor a lot of the code because it was getting messy
This commit is contained in:
parent
aab6b41d18
commit
c31078ebd5
4
TODO.gmi
4
TODO.gmi
@ -2,11 +2,11 @@
|
|||||||
A list of things I'd like to accomplish
|
A list of things I'd like to accomplish
|
||||||
|
|
||||||
## In Progress
|
## In Progress
|
||||||
* Serialise data to JSON for socket data transmission
|
|
||||||
* Send world data to client
|
|
||||||
* Have client render world data (return to pre-daemonised equivalent state)
|
* Have client render world data (return to pre-daemonised equivalent state)
|
||||||
|
|
||||||
## Completed
|
## Completed
|
||||||
|
* Serialise data to JSON for socket data transmission
|
||||||
|
* Send world data to client
|
||||||
* Initialise a world again
|
* Initialise a world again
|
||||||
* Expose a socket or pipe on the daemon for the client
|
* Expose a socket or pipe on the daemon for the client
|
||||||
* Create client to connect to daemon
|
* Create client to connect to daemon
|
||||||
|
@ -19,7 +19,7 @@ int main(void) {
|
|||||||
read(sock, ibuf, 8192);
|
read(sock, ibuf, 8192);
|
||||||
|
|
||||||
struct world_t world = { 0 };
|
struct world_t world = { 0 };
|
||||||
err = world_deserialise(&world, ibuf);
|
err = world_deserialise_str(&world, ibuf);
|
||||||
if (err != ERR_OK) goto handle_error_sock;
|
if (err != ERR_OK) goto handle_error_sock;
|
||||||
|
|
||||||
printf("CLIENT: (%zu %zu) ->", world.height++, world.width ++);
|
printf("CLIENT: (%zu %zu) ->", world.height++, world.width ++);
|
||||||
|
@ -12,6 +12,7 @@ struct entity_registrant_t {
|
|||||||
char tile;
|
char tile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum error_t entity_registrant_init(
|
enum error_t entity_registrant_init(
|
||||||
struct entity_registrant_t *,
|
struct entity_registrant_t *,
|
||||||
char const *, char
|
char const *, char
|
||||||
@ -26,7 +27,7 @@ struct entity_registry_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum error_t entity_registry_init(struct entity_registry_t *);
|
void entity_registry_init(struct entity_registry_t *);
|
||||||
void entity_registry_free(struct entity_registry_t *);
|
void entity_registry_free(struct entity_registry_t *);
|
||||||
|
|
||||||
enum error_t entity_registry_serialise(
|
enum error_t entity_registry_serialise(
|
||||||
@ -39,6 +40,20 @@ enum error_t entity_registry_deserialise(
|
|||||||
struct json_t *
|
struct json_t *
|
||||||
);
|
);
|
||||||
|
|
||||||
|
enum error_t entity_registry_resize(struct entity_registry_t *, size_t);
|
||||||
|
|
||||||
|
void entity_registry_set(
|
||||||
|
struct entity_registry_t *,
|
||||||
|
struct entity_registrant_t const *,
|
||||||
|
size_t
|
||||||
|
);
|
||||||
|
|
||||||
|
enum error_t entity_registry_try_set(
|
||||||
|
struct entity_registry_t *,
|
||||||
|
struct entity_registrant_t const *,
|
||||||
|
size_t
|
||||||
|
);
|
||||||
|
|
||||||
enum error_t entity_registry_append(
|
enum error_t entity_registry_append(
|
||||||
struct entity_registry_t *,
|
struct entity_registry_t *,
|
||||||
struct entity_registrant_t const *
|
struct entity_registrant_t const *
|
||||||
|
@ -22,11 +22,12 @@ struct world_t {
|
|||||||
enum error_t world_init(struct world_t *, size_t, size_t);
|
enum error_t world_init(struct world_t *, size_t, size_t);
|
||||||
void world_free(struct world_t *);
|
void world_free(struct world_t *);
|
||||||
|
|
||||||
// world_*_str() allocates a string that the caller must free()
|
|
||||||
// world_*_buf() uses a pre-existing buffer; results are not zero-terminated
|
|
||||||
enum error_t world_serialise_str(struct world_t *, char const **);
|
enum error_t world_serialise_str(struct world_t *, char const **);
|
||||||
|
enum error_t world_deserialise_str(struct world_t *, char const *);
|
||||||
|
// Operates on strings; serialise allocates so make sure to free
|
||||||
|
|
||||||
enum error_t world_serialise_buf(struct world_t *, char *, size_t);
|
enum error_t world_serialise_buf(struct world_t *, char *, size_t);
|
||||||
enum error_t world_deserialise(struct world_t *, char const *);
|
// Operates on buffers; need not be zero-terminated
|
||||||
|
|
||||||
enum error_t world_register_entity(struct world_t *, char const *, char);
|
enum error_t world_register_entity(struct world_t *, char const *, char);
|
||||||
enum error_t world_place_entity(struct world_t *, size_t, size_t, size_t);
|
enum error_t world_place_entity(struct world_t *, size_t, size_t, size_t);
|
||||||
|
@ -47,13 +47,13 @@ static enum error_t registrant_serialise(
|
|||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
|
||||||
struct json_t *maybe_json = json_pack(ENTITY_REGISTRANT_JSON_FMT,
|
struct json_t *registrant_json = json_pack(ENTITY_REGISTRANT_JSON_FMT,
|
||||||
"name", self->name,
|
"name", self->name,
|
||||||
"tile", self->tile
|
"tile", self->tile
|
||||||
);
|
);
|
||||||
if (maybe_json == NULL) return ERR_JSON_SERIALISE;
|
if (registrant_json == NULL) return ERR_JSON_SERIALISE;
|
||||||
|
|
||||||
*json = maybe_json;
|
*json = registrant_json;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,29 +64,29 @@ static enum error_t registrant_deserialise(
|
|||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
|
||||||
|
char const *name_borrowed = NULL;
|
||||||
int err = json_unpack(json, ENTITY_REGISTRANT_JSON_FMT,
|
int err = json_unpack(json, ENTITY_REGISTRANT_JSON_FMT,
|
||||||
"name", &self->name,
|
"name", &name_borrowed,
|
||||||
"tile", &self->tile
|
"tile", &self->tile
|
||||||
);
|
);
|
||||||
if (err < 0) return ERR_JSON_DESERIALISE;
|
if (err < 0) return ERR_JSON_DESERIALISE;
|
||||||
|
|
||||||
|
char *name_owned = calloc(strlen(name_borrowed), sizeof(char));
|
||||||
|
if (name_owned == NULL) return ERR_ALLOC;
|
||||||
|
|
||||||
|
strcpy(name_owned, name_borrowed);
|
||||||
|
|
||||||
|
self->name = name_owned;
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum error_t entity_registry_init(struct entity_registry_t *self) {
|
void entity_registry_init(struct entity_registry_t *self) {
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|
||||||
self->size = 1;
|
self->size = 0;
|
||||||
|
self->entities = NULL;
|
||||||
struct entity_registrant_t *entities = calloc(
|
|
||||||
self->size, sizeof(struct entity_registrant_t)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (entities == NULL) return ERR_ALLOC;
|
|
||||||
|
|
||||||
self->entities = entities;
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -100,6 +100,76 @@ void entity_registry_free(struct entity_registry_t *self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t entity_registry_serialise_entity(
|
||||||
|
struct entity_registry_t const *self,
|
||||||
|
struct json_t *json,
|
||||||
|
size_t index
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct json_t *entity_json = NULL;
|
||||||
|
enum error_t err = registrant_serialise(
|
||||||
|
&self->entities[index], &entity_json
|
||||||
|
);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
|
int json_err = json_array_append_new(json, entity_json);
|
||||||
|
if (json_err < 0) {
|
||||||
|
json_decref(entity_json);
|
||||||
|
return ERR_JSON_SERIALISE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t entity_registry_serialise_entities(
|
||||||
|
struct entity_registry_t const *self,
|
||||||
|
struct json_t **json
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct json_t *entities_json = json_array();
|
||||||
|
if (entities_json == NULL) return ERR_ALLOC;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < self->size; i++) {
|
||||||
|
enum error_t err = entity_registry_serialise_entity(
|
||||||
|
self, entities_json, i
|
||||||
|
);
|
||||||
|
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
json_decref(entities_json);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*json = entities_json;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t entity_registry_serialise_parts(
|
||||||
|
struct json_t *entities_json,
|
||||||
|
size_t size,
|
||||||
|
struct json_t **json
|
||||||
|
) {
|
||||||
|
assert(entities_json != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct json_t *registry_json = json_pack(ENTITY_REGISTRY_JSON_FMT,
|
||||||
|
"entities", entities_json,
|
||||||
|
"size", size
|
||||||
|
);
|
||||||
|
|
||||||
|
if (registry_json == NULL) return ERR_JSON_SERIALISE;
|
||||||
|
|
||||||
|
*json = registry_json;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum error_t entity_registry_serialise(
|
enum error_t entity_registry_serialise(
|
||||||
struct entity_registry_t const *self,
|
struct entity_registry_t const *self,
|
||||||
struct json_t **json
|
struct json_t **json
|
||||||
@ -107,34 +177,86 @@ enum error_t entity_registry_serialise(
|
|||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
|
||||||
enum error_t err = ERR_OK;
|
struct json_t *entities_json = NULL;
|
||||||
|
enum error_t err = entity_registry_serialise_entities(self, &entities_json);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
struct json_t *entities_json = json_array();
|
struct json_t *registry_json = NULL;
|
||||||
for (size_t i = 0; i < self->size; i++) {
|
err = entity_registry_serialise_parts(
|
||||||
struct json_t *maybe_entity_json;
|
entities_json, self->size,
|
||||||
err = registrant_serialise(&self->entities[i], &maybe_entity_json);
|
®istry_json
|
||||||
if (err != ERR_OK) goto error_cleanup_array;
|
|
||||||
|
|
||||||
int json_err = json_array_append_new(entities_json, maybe_entity_json);
|
|
||||||
if (json_err < 0) {
|
|
||||||
err = ERR_JSON_SERIALISE;
|
|
||||||
goto error_cleanup_array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(json_array_size(entities_json) == self->size);
|
|
||||||
|
|
||||||
struct json_t *maybe_json = json_pack(ENTITY_REGISTRY_JSON_FMT,
|
|
||||||
"entities", entities_json,
|
|
||||||
"size", self->size
|
|
||||||
);
|
);
|
||||||
if (maybe_json == NULL) goto error_cleanup_array;
|
|
||||||
|
|
||||||
*json = maybe_json;
|
if (err != ERR_OK) {
|
||||||
return ERR_OK;
|
json_decref(entities_json);
|
||||||
|
|
||||||
error_cleanup_array:
|
|
||||||
json_array_clear(entities_json);
|
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*json = registry_json;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t entity_registry_deserialise_parts(
|
||||||
|
struct json_t **entities_json,
|
||||||
|
size_t *size,
|
||||||
|
struct json_t *json
|
||||||
|
) {
|
||||||
|
assert(entities_json != NULL);
|
||||||
|
assert(size != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
int err = json_unpack(json, ENTITY_REGISTRY_JSON_FMT,
|
||||||
|
"entities", entities_json,
|
||||||
|
"size", size
|
||||||
|
);
|
||||||
|
|
||||||
|
if (err < 0) return ERR_JSON_DESERIALISE;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t entity_registry_deserialise_entity(
|
||||||
|
struct entity_registry_t *self,
|
||||||
|
struct json_t *json,
|
||||||
|
size_t index
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct json_t *entity_json = json_array_get(json, index);
|
||||||
|
if (entity_json == NULL) return ERR_JSON_DESERIALISE;
|
||||||
|
|
||||||
|
enum error_t err = registrant_deserialise(
|
||||||
|
&self->entities[index], entity_json
|
||||||
|
);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t entity_registry_deserialise_entities(
|
||||||
|
struct entity_registry_t *self,
|
||||||
|
struct json_t *json
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
self->entities = calloc(
|
||||||
|
json_array_size(json), sizeof(struct entity_registrant_t)
|
||||||
|
);
|
||||||
|
if (self->entities == NULL) return ERR_ALLOC;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < json_array_size(json); i++) {
|
||||||
|
enum error_t err = entity_registry_deserialise_entity(self, json, i);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
free(self->entities);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -145,34 +267,69 @@ enum error_t entity_registry_deserialise(
|
|||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
|
||||||
enum error_t err = ERR_OK;
|
struct entity_registry_t temp_registry = { 0 };
|
||||||
|
|
||||||
struct json_t *entities_json = NULL;
|
struct json_t *entities_json = NULL;
|
||||||
int json_err = json_unpack(json, ENTITY_REGISTRY_JSON_FMT,
|
enum error_t err = entity_registry_deserialise_parts(
|
||||||
"entities", &entities_json,
|
&entities_json, &temp_registry.size, json
|
||||||
"size", &self->size
|
|
||||||
);
|
);
|
||||||
if (json_err < 0) return ERR_JSON_DESERIALISE;
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
struct entity_registrant_t *entities = calloc(
|
err = entity_registry_deserialise_entities(&temp_registry, entities_json);
|
||||||
self->size, sizeof(struct entity_registrant_t)
|
if (err != ERR_OK) {
|
||||||
);
|
json_decref(entities_json);
|
||||||
if (entities == NULL) goto error_cleanup_entities;
|
return err;
|
||||||
|
|
||||||
for (size_t i = 0; i < json_array_size(entities_json); i++) {
|
|
||||||
struct json_t *entity_json = json_array_get(entities_json, i);
|
|
||||||
if (entity_json == NULL) goto error_cleanup_entities;
|
|
||||||
|
|
||||||
err = registrant_deserialise(&entities[i], entity_json);
|
|
||||||
if (err != ERR_OK) goto error_cleanup_entities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->entities = entities;
|
json_decref(entities_json);
|
||||||
return ERR_OK;
|
|
||||||
|
|
||||||
error_cleanup_entities:
|
*self = temp_registry;
|
||||||
free(entities);
|
return ERR_OK;
|
||||||
return ERR_JSON_DESERIALISE;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum error_t entity_registry_resize(
|
||||||
|
struct entity_registry_t *self,
|
||||||
|
size_t size
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
|
||||||
|
struct entity_registrant_t *entities = realloc(
|
||||||
|
self->entities,
|
||||||
|
size * sizeof(struct entity_registrant_t)
|
||||||
|
);
|
||||||
|
if (entities == NULL) return ERR_ALLOC;
|
||||||
|
|
||||||
|
self->size = size;
|
||||||
|
self->entities = entities;
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void entity_registry_set(
|
||||||
|
struct entity_registry_t *self,
|
||||||
|
struct entity_registrant_t const *registrant,
|
||||||
|
size_t index
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(registrant != NULL);
|
||||||
|
assert(index < self->size);
|
||||||
|
|
||||||
|
self->entities[index] = *registrant;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum error_t entity_registry_try_set(
|
||||||
|
struct entity_registry_t *self,
|
||||||
|
struct entity_registrant_t const *registrant,
|
||||||
|
size_t index
|
||||||
|
) {
|
||||||
|
if (self == NULL || registrant == NULL) return ERR_INPUT;
|
||||||
|
if (index >= self->size) return ERR_INPUT;
|
||||||
|
|
||||||
|
entity_registry_set(self, registrant, index);
|
||||||
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -180,16 +337,12 @@ enum error_t entity_registry_append(
|
|||||||
struct entity_registry_t *self,
|
struct entity_registry_t *self,
|
||||||
struct entity_registrant_t const *registrant
|
struct entity_registrant_t const *registrant
|
||||||
) {
|
) {
|
||||||
assert(self != NULL && registrant != NULL);
|
assert(self != NULL);
|
||||||
|
assert(registrant != NULL);
|
||||||
|
|
||||||
self->size += 1;
|
enum error_t err = entity_registry_resize(self, self->size + 1);
|
||||||
self->entities = realloc(
|
if (err != ERR_OK) return err;
|
||||||
self->entities,
|
|
||||||
self->size * sizeof(struct entity_registrant_t)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (self->entities == NULL) return ERR_ALLOC;
|
entity_registry_set(self, registrant, self->size - 1);
|
||||||
|
|
||||||
self->entities[self->size - 1] = *registrant;
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
@ -7,29 +7,21 @@
|
|||||||
|
|
||||||
static char const *const WORLD_JSON_FMT = "{so, so, sI, sI}";
|
static char const *const WORLD_JSON_FMT = "{so, so, sI, sI}";
|
||||||
|
|
||||||
|
|
||||||
enum error_t world_init(struct world_t *self, size_t height, size_t width) {
|
enum error_t world_init(struct world_t *self, size_t height, size_t width) {
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|
||||||
self->height = height;
|
self->height = height;
|
||||||
self->width = width;
|
self->width = width;
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_ENTITIES; i++) {
|
memset(self->entities, 0, MAX_ENTITIES * sizeof(struct entity_t));
|
||||||
self->entities[i].id = 0;
|
|
||||||
self->entities[i].x = 0;
|
|
||||||
self->entities[i].y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum error_t err = entity_registry_init(&self->registered_entities);
|
entity_registry_init(&self->registered_entities);
|
||||||
|
|
||||||
|
enum error_t err = world_register_entity(self, "NULL", '?');
|
||||||
if (err != ERR_OK) return err;
|
if (err != ERR_OK) return err;
|
||||||
|
// If this fails, nothing's been allocated to the registry,
|
||||||
struct entity_registrant_t null_entity;
|
// so there's no need to free it
|
||||||
err = entity_registrant_init(&null_entity, "NULL", '?');
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
entity_registry_free(&self->registered_entities);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->registered_entities.entities[0] = null_entity;
|
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
@ -42,97 +34,234 @@ void world_free(struct world_t *self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static enum error_t serialise(struct world_t *self, struct json_t **json) {
|
static enum error_t world_serialise_entity(
|
||||||
|
struct world_t const *self,
|
||||||
|
struct json_t *json,
|
||||||
|
size_t index
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
if (self->entities[index].id == 0) return ERR_OK;
|
||||||
|
|
||||||
|
struct json_t *entity_json = NULL;
|
||||||
|
enum error_t err = entity_serialise(&self->entities[index], &entity_json);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
|
int json_err = json_array_append_new(json, entity_json);
|
||||||
|
if (json_err < 0) {
|
||||||
|
json_decref(entity_json);
|
||||||
|
return ERR_JSON_SERIALISE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t world_serialise_entities(
|
||||||
|
struct world_t const *self,
|
||||||
|
struct json_t **json
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct json_t *entities_json = json_array();
|
||||||
|
if (entities_json == NULL) return ERR_ALLOC;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MAX_ENTITIES; i++) {
|
||||||
|
enum error_t err = world_serialise_entity(self, entities_json, i);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
json_decref(entities_json);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*json = entities_json;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t world_serialise_parts(
|
||||||
|
struct json_t *entities_json,
|
||||||
|
struct json_t *registered_entities_json,
|
||||||
|
size_t height, size_t width,
|
||||||
|
struct json_t **json
|
||||||
|
) {
|
||||||
|
assert(entities_json != NULL);
|
||||||
|
assert(registered_entities_json != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct json_t *world_json = json_pack(WORLD_JSON_FMT,
|
||||||
|
"entities", entities_json,
|
||||||
|
"registered_entities", registered_entities_json,
|
||||||
|
"height", height, "width", width
|
||||||
|
);
|
||||||
|
|
||||||
|
if (world_json == NULL) return ERR_JSON_SERIALISE;
|
||||||
|
|
||||||
|
*json = world_json;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t world_serialise(struct world_t *self, struct json_t **json) {
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
|
||||||
enum error_t err = ERR_OK;
|
enum error_t err = ERR_OK;
|
||||||
|
|
||||||
struct json_t *entities_json = json_array();
|
// Serialise existing entities
|
||||||
for (size_t i = 0; i < MAX_ENTITIES; i++) {
|
struct json_t *entities_json = NULL;
|
||||||
if (self->entities[i].id == 0) continue;
|
err = world_serialise_entities(self, &entities_json);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
struct json_t *maybe_entity_json;
|
// Serialise the entity registry
|
||||||
err = entity_serialise(&self->entities[i], &maybe_entity_json);
|
struct json_t *registered_entities_json = NULL;
|
||||||
if (err != ERR_OK) goto error_cleanup_array;
|
|
||||||
|
|
||||||
int json_err = json_array_append_new(entities_json, maybe_entity_json);
|
|
||||||
if (json_err < 0) {
|
|
||||||
err = ERR_JSON_SERIALISE;
|
|
||||||
goto error_cleanup_array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct json_t *registered_entities_json;
|
|
||||||
err = entity_registry_serialise(
|
err = entity_registry_serialise(
|
||||||
&self->registered_entities,
|
&self->registered_entities,
|
||||||
®istered_entities_json
|
®istered_entities_json
|
||||||
);
|
);
|
||||||
if (err != ERR_OK) return err;
|
if (err != ERR_OK) goto error;
|
||||||
|
|
||||||
struct json_t *maybe_json = json_pack(WORLD_JSON_FMT,
|
// Serialise the full structure
|
||||||
"entities", entities_json,
|
struct json_t *world_json = NULL;
|
||||||
"registered_entities", registered_entities_json,
|
err = world_serialise_parts(
|
||||||
"height", self->height,
|
entities_json,
|
||||||
"width", self->width
|
registered_entities_json,
|
||||||
|
self->height, self->width,
|
||||||
|
&world_json
|
||||||
);
|
);
|
||||||
if (maybe_json == NULL) return ERR_JSON_SERIALISE;
|
if (err != ERR_OK) goto error_world;
|
||||||
|
|
||||||
*json = maybe_json;
|
*json = world_json;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
|
|
||||||
error_cleanup_array:
|
error_world:
|
||||||
json_array_clear(entities_json);
|
json_decref(registered_entities_json);
|
||||||
|
error:
|
||||||
|
json_decref(entities_json);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static enum error_t deserialise(struct world_t *self, struct json_t *json) {
|
static enum error_t world_deserialise_parts(
|
||||||
|
struct json_t **entities_json,
|
||||||
|
struct json_t **registered_entities_json,
|
||||||
|
size_t *height, size_t *width,
|
||||||
|
struct json_t *json
|
||||||
|
) {
|
||||||
|
assert(entities_json != NULL);
|
||||||
|
assert(registered_entities_json != NULL);
|
||||||
|
assert(height != NULL);
|
||||||
|
assert(width != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
int err = json_unpack(json, WORLD_JSON_FMT,
|
||||||
|
"entities", entities_json,
|
||||||
|
"registered_entities", registered_entities_json,
|
||||||
|
"height", height, "width", width
|
||||||
|
);
|
||||||
|
|
||||||
|
if (err < 0) return ERR_JSON_DESERIALISE;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t world_deserialise_entity(
|
||||||
|
struct world_t *self,
|
||||||
|
struct json_t *json,
|
||||||
|
size_t index
|
||||||
|
) {
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
|
||||||
struct json_t *entities_json;
|
// The entity array may have gaps, such as [ 1, 0, 0, 2 ]
|
||||||
struct json_t *registered_entities_json;
|
// Serialisation omits entities of ID 0, and doesn't store the original
|
||||||
int json_err = json_unpack(json, WORLD_JSON_FMT,
|
// index of each entity, so the deserialiser only sees [ 1, 2 ]
|
||||||
"entities", &entities_json,
|
// If you've just serialised and deserialised to the same world_t, this
|
||||||
"registered_entities", ®istered_entities_json,
|
// could cause "ghost" entities to arise, looking like [1, 2, 0, 2 ]
|
||||||
"height", &self->height,
|
// Here, we clear out those ghost entities
|
||||||
"width", &self->width
|
if (index >= json_array_size(json)) {
|
||||||
);
|
self->entities[index].id = 0;
|
||||||
if (json_err < 0) return ERR_JSON_DESERIALISE;
|
return ERR_OK;
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_ENTITIES; i++) {
|
|
||||||
// The entity array can have gaps, but the serialisation process shifts
|
|
||||||
// all entities forwards to fill them; this zeroes out the empty space
|
|
||||||
// at the end, to ensure no "ghost" entities remain
|
|
||||||
if (i >= json_array_size(entities_json)) {
|
|
||||||
self->entities[i].id = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct json_t *entity_json = json_array_get(entities_json, i);
|
struct json_t *entity_json = json_array_get(json, index);
|
||||||
if (entity_json == NULL) return ERR_JSON_DESERIALISE;
|
if (entity_json == NULL) return ERR_JSON_DESERIALISE;
|
||||||
|
|
||||||
enum error_t err = entity_deserialise(&self->entities[i], entity_json);
|
enum error_t err = entity_deserialise(&self->entities[index], entity_json);
|
||||||
if (err != ERR_OK) return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum error_t err = entity_registry_deserialise(
|
|
||||||
&self->registered_entities,
|
|
||||||
registered_entities_json
|
|
||||||
);
|
|
||||||
if (err != ERR_OK) return err;
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t world_deserialise_entities(
|
||||||
|
struct world_t *self,
|
||||||
|
struct json_t *json
|
||||||
|
) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MAX_ENTITIES; i++) {
|
||||||
|
enum error_t err = world_deserialise_entity(self, json, i);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum error_t world_deserialise(struct world_t *self, struct json_t *json) {
|
||||||
|
assert(self != NULL);
|
||||||
|
assert(json != NULL);
|
||||||
|
|
||||||
|
struct world_t temp_world = { 0 };
|
||||||
|
// I don't want to write to self until the very end, in case an error
|
||||||
|
// occurs when we've written some fields but not all of them
|
||||||
|
|
||||||
|
struct json_t *entities_json = NULL;
|
||||||
|
struct json_t *registered_entities_json = NULL;
|
||||||
|
|
||||||
|
// Deserialise full struct into parts
|
||||||
|
enum error_t err = world_deserialise_parts(
|
||||||
|
&entities_json,
|
||||||
|
®istered_entities_json,
|
||||||
|
&temp_world.height, &temp_world.width,
|
||||||
|
json
|
||||||
|
);
|
||||||
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
|
// Deserialise the existing entities
|
||||||
|
err = world_deserialise_entities(&temp_world, entities_json);
|
||||||
|
if (err != ERR_OK) goto error;
|
||||||
|
|
||||||
|
// Deserialise the entity registry
|
||||||
|
err = entity_registry_deserialise(
|
||||||
|
&temp_world.registered_entities,
|
||||||
|
registered_entities_json
|
||||||
|
);
|
||||||
|
if (err != ERR_OK) goto error;
|
||||||
|
|
||||||
|
json_decref(entities_json);
|
||||||
|
json_decref(registered_entities_json);
|
||||||
|
|
||||||
|
*self = temp_world;
|
||||||
|
return ERR_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
json_decref(entities_json);
|
||||||
|
json_decref(registered_entities_json);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum error_t world_serialise_str(struct world_t *self, char const **strptr) {
|
enum error_t world_serialise_str(struct world_t *self, char const **strptr) {
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(strptr != NULL);
|
assert(strptr != NULL);
|
||||||
|
|
||||||
struct json_t *json;
|
struct json_t *json;
|
||||||
enum error_t err = serialise(self, &json);
|
enum error_t err = world_serialise(self, &json);
|
||||||
if (err != ERR_OK) return ERR_JSON_SERIALISE;
|
if (err != ERR_OK) return ERR_JSON_SERIALISE;
|
||||||
|
|
||||||
const char *str = json_dumps(json, 0);
|
const char *str = json_dumps(json, 0);
|
||||||
@ -149,7 +278,7 @@ enum error_t world_serialise_buf(struct world_t *self, char *buf, size_t len) {
|
|||||||
assert(len > 0);
|
assert(len > 0);
|
||||||
|
|
||||||
struct json_t *json;
|
struct json_t *json;
|
||||||
enum error_t err = serialise(self, &json);
|
enum error_t err = world_serialise(self, &json);
|
||||||
if (err != ERR_OK) return ERR_JSON_SERIALISE;
|
if (err != ERR_OK) return ERR_JSON_SERIALISE;
|
||||||
|
|
||||||
size_t bytes_written = json_dumpb(json, buf, len, 0);
|
size_t bytes_written = json_dumpb(json, buf, len, 0);
|
||||||
@ -159,15 +288,14 @@ enum error_t world_serialise_buf(struct world_t *self, char *buf, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum error_t world_deserialise(struct world_t *self, char const *str) {
|
enum error_t world_deserialise_str(struct world_t *self, char const *str) {
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(str != NULL);
|
assert(str != NULL);
|
||||||
|
|
||||||
|
|
||||||
struct json_t *json = json_loads(str, 0, NULL);
|
struct json_t *json = json_loads(str, 0, NULL);
|
||||||
if (json == NULL) return ERR_JSON_DESERIALISE;
|
if (json == NULL) return ERR_JSON_DESERIALISE;
|
||||||
|
|
||||||
enum error_t err = deserialise(self, json);
|
enum error_t err = world_deserialise(self, json);
|
||||||
if (err != ERR_OK) return ERR_JSON_DESERIALISE;
|
if (err != ERR_OK) return ERR_JSON_DESERIALISE;
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
@ -181,7 +309,7 @@ enum error_t world_register_entity(
|
|||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
assert(name != NULL);
|
assert(name != NULL);
|
||||||
|
|
||||||
enum error_t err;
|
enum error_t err = ERR_OK;
|
||||||
struct entity_registry_t *registry = &self->registered_entities;
|
struct entity_registry_t *registry = &self->registered_entities;
|
||||||
|
|
||||||
struct entity_registrant_t registrant;
|
struct entity_registrant_t registrant;
|
||||||
@ -189,7 +317,10 @@ enum error_t world_register_entity(
|
|||||||
if (err != ERR_OK) return err;
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
err = entity_registry_append(registry, ®istrant);
|
err = entity_registry_append(registry, ®istrant);
|
||||||
if (err != ERR_OK) return err;
|
if (err != ERR_OK) {
|
||||||
|
entity_registrant_free(®istrant);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ enum error_t game_loop(struct data_t *data) {
|
|||||||
char ibuf[8192] = { 0 };
|
char ibuf[8192] = { 0 };
|
||||||
read(data->socket_accept, ibuf, 8192);
|
read(data->socket_accept, ibuf, 8192);
|
||||||
|
|
||||||
err = world_deserialise(&data->world, ibuf);
|
err = world_deserialise_str(&data->world, ibuf);
|
||||||
if (err != ERR_OK) return err;
|
if (err != ERR_OK) return err;
|
||||||
|
|
||||||
printf("SERVER: \"%s\" -> \"%s\"\n", obuf, ibuf);
|
printf("SERVER: \"%s\" -> \"%s\"\n", obuf, ibuf);
|
||||||
|
Loading…
Reference in New Issue
Block a user