World save: preserve position and rotation

This commit is contained in:
xtreme8000 2023-02-11 17:18:11 +01:00
parent 56780d9cee
commit d7a46ed965
7 changed files with 132 additions and 15 deletions

View file

@ -178,7 +178,7 @@ void camera_update(struct camera* c, float dt) {
c->controller.vz = 0;
}
c->ry = fminf(M_PI - glm_rad(0.5F), fmaxf(glm_rad(0.5F), c->ry));
c->ry = glm_clamp(c->ry, glm_rad(0.5F), M_PI - glm_rad(0.5F));
glm_perspective(glm_rad(gstate.config.fov),
(float)gfx_width() / (float)gfx_height(), 0.1F,

View file

@ -93,9 +93,9 @@ void clin_process(struct client_rpc* call) {
gstate.camera.x = call->payload.player_pos.position[0];
gstate.camera.y = call->payload.player_pos.position[1];
gstate.camera.z = call->payload.player_pos.position[2];
gstate.camera.rx = glm_rad(call->payload.player_pos.rotation[0]);
gstate.camera.ry
= glm_rad(call->payload.player_pos.rotation[1] + 90.0F);
gstate.camera.rx = glm_rad(-call->payload.player_pos.rotation[0]);
gstate.camera.ry = glm_rad(glm_clamp(
call->payload.player_pos.rotation[1] + 90.0F, 0.0F, 180.0F));
gstate.world_loaded = true;
break;
case CRPC_WORLD_RESET:
@ -148,6 +148,8 @@ void clin_update() {
.payload.player_pos.x = gstate.camera.x,
.payload.player_pos.y = gstate.camera.y,
.payload.player_pos.z = gstate.camera.z,
.payload.player_pos.rx = -glm_deg(gstate.camera.rx),
.payload.player_pos.ry = glm_deg(gstate.camera.ry) - 90.0F,
});
last_pos_update = time_get();
}

View file

@ -24,16 +24,12 @@
bool level_archive_create(struct level_archive* la, string_t filename) {
assert(la && filename);
string_t tmp;
string_init_printf(tmp, "saves/%s/level.dat", string_get_cstr(filename));
char* c_tmp = string_clear_get_str(tmp);
la->modified = false;
if(!c_tmp)
return false;
string_init_printf(la->file_name, "saves/%s/level.dat",
string_get_cstr(filename));
la->data = nbt_parse_path(c_tmp);
free(c_tmp);
la->data = nbt_parse_path(string_get_cstr(la->file_name));
return la->data;
}
@ -78,6 +74,38 @@ bool level_archive_read(struct level_archive* la, struct level_archive_tag tag,
return level_archive_read_internal(la->data, tag, result, length);
}
static bool level_archive_write_internal(nbt_node* root,
struct level_archive_tag tag,
void* data) {
assert(root && data);
nbt_node* node = nbt_find_by_path(root, tag.name);
if(!node || node->type != tag.type)
return false;
switch(tag.type) {
case TAG_LONG: node->payload.tag_long = *(int64_t*)data; return true;
case TAG_INT: node->payload.tag_int = *(int32_t*)data; return true;
case TAG_SHORT: node->payload.tag_short = *(int16_t*)data; return true;
case TAG_BYTE: node->payload.tag_byte = *(int8_t*)data; return true;
default: return false;
}
}
bool level_archive_write(struct level_archive* la, struct level_archive_tag tag,
void* data) {
assert(la && data);
assert(la->data);
if(level_archive_write_internal(la->data, tag, data)) {
la->modified = true;
return true;
}
return false;
}
bool level_archive_read_inventory(struct level_archive* la,
struct item_data* inventory, size_t length) {
assert(la && inventory);
@ -154,6 +182,65 @@ static bool read_vector(nbt_node* node, nbt_type type, vec3 result,
return k == amount;
}
static bool write_vector(nbt_node* node, nbt_type type, vec3 data,
size_t amount) {
assert(node && node->type == TAG_LIST && data && amount <= 3);
size_t k = 0;
struct list_head* current;
list_for_each(current, &node->payload.tag_list->entry) {
nbt_node* obj = list_entry(current, struct nbt_list, entry)->data;
if(obj && obj->type == type && k < amount) {
switch(type) {
case TAG_DOUBLE: obj->payload.tag_double = data[k++]; break;
case TAG_FLOAT: obj->payload.tag_float = data[k++]; break;
default: return false;
}
} else {
return false;
}
}
return k == amount;
}
bool level_archive_write_player(struct level_archive* la, vec3 position,
vec2 rotation, vec3 velocity,
enum world_dim dimension) {
assert(la && la->data);
nbt_node* pos;
if(!level_archive_read(la, LEVEL_PLAYER_POSITION, &pos, 0))
return false;
nbt_node* vel;
if(!level_archive_read(la, LEVEL_PLAYER_VELOCITY, &vel, 0))
return false;
nbt_node* rot;
if(!level_archive_read(la, LEVEL_PLAYER_ROTATION, &rot, 0))
return false;
int32_t dim = dimension;
if(!level_archive_write(la, LEVEL_PLAYER_DIMENSION, &dim))
return false;
if(position && !write_vector(pos, TAG_DOUBLE, position, 3))
return false;
if(velocity && !write_vector(vel, TAG_DOUBLE, velocity, 3))
return false;
if(rotation
&& !write_vector(rot, TAG_FLOAT, (vec3) {rotation[0], rotation[1], 0.0F},
2))
return false;
la->modified = true;
return true;
}
bool level_archive_read_player(struct level_archive* la, vec3 position,
vec2 rotation, vec3 velocity,
enum world_dim* dimension) {
@ -172,7 +259,7 @@ bool level_archive_read_player(struct level_archive* la, vec3 position,
return false;
int32_t* dim;
if(!level_archive_read(la, LEVEL_PLAYER_DIMENSION, &dim, 0))
if(dimension && !level_archive_read(la, LEVEL_PLAYER_DIMENSION, &dim, 0))
return false;
if(position && !read_vector(pos, TAG_DOUBLE, position, 3))
@ -199,5 +286,16 @@ bool level_archive_read_player(struct level_archive* la, vec3 position,
void level_archive_destroy(struct level_archive* la) {
assert(la && la->data);
if(la->modified) {
FILE* f = fopen(string_get_cstr(la->file_name), "wb");
if(f) {
nbt_dump_file(la->data, f, STRAT_GZIP);
fclose(f);
}
}
string_clear(la->file_name);
nbt_free(la->data);
}

View file

@ -70,11 +70,18 @@ struct level_archive_tag {
struct level_archive {
nbt_node* data;
string_t file_name;
bool modified;
};
bool level_archive_create(struct level_archive* la, string_t filename);
bool level_archive_read(struct level_archive* la, struct level_archive_tag tag,
void* result, size_t length);
bool level_archive_write(struct level_archive* la, struct level_archive_tag tag,
void* data);
bool level_archive_write_player(struct level_archive* la, vec3 position,
vec2 rotation, vec3 velocity,
enum world_dim dimension);
bool level_archive_read_inventory(struct level_archive* la,
struct item_data* inventory, size_t length);
bool level_archive_read_player(struct level_archive* la, vec3 position,

View file

@ -36,6 +36,7 @@ struct server_rpc {
union {
struct {
double x, y, z;
float rx, ry;
} player_pos;
struct {
string_t name;

View file

@ -42,6 +42,8 @@ static void server_local_process(struct server_rpc* call, void* user) {
s->player.x = call->payload.player_pos.x;
s->player.y = call->payload.player_pos.y;
s->player.z = call->payload.player_pos.z;
s->player.rx = call->payload.player_pos.rx;
s->player.ry = call->payload.player_pos.ry;
s->player.has_pos = true;
}
break;
@ -67,6 +69,10 @@ static void server_local_process(struct server_rpc* call, void* user) {
.payload.world_reset.dimension = WORLD_DIM_OVERWORLD,
});
level_archive_write_player(
&s->level, (vec3) {s->player.x, s->player.y, s->player.z},
(vec2) {s->player.rx, s->player.ry}, NULL, s->player.dimension);
server_world_destroy(&s->world);
level_archive_destroy(&s->level);
@ -82,13 +88,15 @@ static void server_local_process(struct server_rpc* call, void* user) {
if(level_archive_create(&s->level, s->level_name)) {
vec3 pos;
vec2 rot;
enum world_dim dim;
if(level_archive_read_player(&s->level, pos, NULL, NULL,
&dim)) {
if(level_archive_read_player(&s->level, pos, rot, NULL, &dim)) {
server_world_create(&s->world, s->level_name, dim);
s->player.x = pos[0];
s->player.y = pos[1];
s->player.z = pos[2];
s->player.rx = rot[0];
s->player.ry = rot[1];
s->player.dimension = dim;
s->player.has_pos = true;
}

View file

@ -35,6 +35,7 @@
struct server_local {
struct {
double x, y, z;
float rx, ry;
enum world_dim dimension;
bool has_pos;
bool finished_loading;