mirror of
https://github.com/xtreme8000/CavEX.git
synced 2025-01-22 09:11:55 -05:00
World save: preserve position and rotation
This commit is contained in:
parent
56780d9cee
commit
d7a46ed965
7 changed files with 132 additions and 15 deletions
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -36,6 +36,7 @@ struct server_rpc {
|
|||
union {
|
||||
struct {
|
||||
double x, y, z;
|
||||
float rx, ry;
|
||||
} player_pos;
|
||||
struct {
|
||||
string_t name;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue