X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Fclient_player.c;h=ccbd059e0aeb32101ad2202c59e489f353206df2;hb=dde805203b320dd008718099b965f7275c04d1cd;hp=e4a3a6c744d98a9b65c75c62f7053d52ae4154dd;hpb=bca9bcffd12548954d464a7548c88190d51cee10;p=dragonblocks_alpha.git diff --git a/src/client/client_player.c b/src/client/client_player.c index e4a3a6c..ccbd059 100644 --- a/src/client/client_player.c +++ b/src/client/client_player.c @@ -1,147 +1,345 @@ +#include +#include #include "client/camera.h" #include "client/client.h" +#include "client/client_inventory.h" #include "client/client_player.h" +#include "client/client_terrain.h" #include "client/cube.h" +#include "client/debug_menu.h" #include "client/texture.h" +#include "environment.h" +#include "physics.h" struct ClientPlayer client_player; +static ClientEntity *player_entity; +static pthread_rwlock_t lock_player_entity; + +static Model *player_model; + +// updat epos/rot box/eye functions + +static void update_camera() +{ + vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f}; + + ClientPlayerData *data = player_entity->extra; + + if (data->bones.eyes) + mat4x4_mul_vec4(dst, data->bones.eyes->abs, src); + else + vec4_dup(dst, src); + + camera_set_position((v3f32) {dst[0], dst[1], dst[2]}); +} + static void update_pos() { - camera_set_position((v3f) {client_player.pos.x, client_player.pos.y + client_player.eye_height, client_player.pos.z}); - client_send_position(client_player.pos); + debug_menu_changed(ENTRY_POS); + debug_menu_changed(ENTRY_HUMIDITY); + debug_menu_changed(ENTRY_TEMPERATURE); +} - client_player.obj->pos = client_player.pos; - object_transform(client_player.obj); +static void update_rot() +{ + camera_set_angle(M_PI / 2 - player_entity->data.rot.y, -player_entity->data.rot.x); + debug_menu_changed(ENTRY_YAW); + debug_menu_changed(ENTRY_PITCH); } -void client_player_init(Map *map) +static void update_transform() { - client_player.map = map; - client_player.pos = (v3f) {0.0f, 200.0f, 0.0f}; - client_player.velocity = (v3f) {0.0f, 0.0f, 0.0f}; - client_player.box = (aabb3f) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}}; - client_player.yaw = client_player.pitch = 0.0f; - client_player.eye_height = 1.5f; + client_entity_transform(player_entity); + update_camera(); } -void client_player_add_to_scene() +static void send_pos_rot() { - client_player.obj = object_create(); - client_player.obj->scale = (v3f) {0.6f, 1.75f, 0.6f}; - client_player.obj->visible = false; + update_transform(); - object_set_texture(client_player.obj, texture_get(RESSOURCEPATH "textures/player.png")); + dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) { + .pos = player_entity->data.pos, + .rot = player_entity->data.rot, + }); +} - for (int f = 0; f < 6; f++) { - for (int v = 0; v < 6; v++) { - Vertex3D vertex = cube_vertices[f][v]; - vertex.position.y += 0.5; - object_add_vertex(client_player.obj, &vertex); - } - } +static void recv_pos_rot() +{ + update_transform(); update_pos(); + update_rot(); } -static aabb3f get_box() +// entity callbacks + +static void on_add(ClientEntity *entity) { - return (aabb3f) { - {client_player.box.min.x + client_player.pos.x, client_player.box.min.y + client_player.pos.y, client_player.box.min.z + client_player.pos.z}, - {client_player.box.max.x + client_player.pos.x, client_player.box.max.y + client_player.pos.y, client_player.box.max.z + client_player.pos.z}, - }; + entity->model = model_clone(player_model); + entity->model->extra = refcount_grb(&entity->rc); + + ClientPlayerData *data = entity->extra = malloc(sizeof *data); + data->bones = (struct ClientPlayerBones) {NULL}; + + model_get_bones(entity->model, (ModelBoneMapping[9]) { + {"nametag", &data->bones.nametag }, + {"neck", &data->bones.neck }, + {"neck.head.eyes", &data->bones.eyes }, + {"arm_left", &data->bones.arm_left }, + {"arm_right", &data->bones.arm_right }, + {"arm_left.hand", &data->bones.hand_left }, + {"arm_right.hand", &data->bones.hand_right}, + {"leg_left", &data->bones.leg_left }, + {"leg_right", &data->bones.leg_right }, + }, 9); + + entity->nametag_offset = data->bones.nametag ? &data->bones.nametag->abs : NULL; + entity->box_collision = (aabb3f32) {{-0.45f, 0.0f, -0.45f}, {0.45f, 1.8f, 0.45f}}; + + client_inventory_init_player(entity); + + model_scene_add(entity->model); + client_entity_transform(entity); +} + +static void on_remove(ClientEntity *entity) +{ + entity->model->flags.delete = 1; + entity->model = NULL; } -static aabb3s32 round_box(aabb3f box) +static void on_free(ClientEntity *entity) { - return (aabb3s32) { - {floor(box.min.x + 0.5f), floor(box.min.y + 0.5f), floor(box.min.z + 0.5f)}, - {ceil(box.max.x - 0.5f), ceil(box.max.y - 0.5f), ceil(box.max.z - 0.5f)}, + client_inventory_init_player(entity); + free(entity->extra); +} + +static void on_transform(ClientEntity *entity) +{ + ClientPlayerData *data = entity->extra; + + entity->model->root->rot.x = entity->model->root->rot.z = 0.0f; + + if (data->bones.neck) { + data->bones.neck->rot.x = entity->data.rot.x; + model_node_transform(data->bones.neck); + } +} + +static void local_on_add(ClientEntity *entity) +{ + pthread_rwlock_wrlock(&lock_player_entity); + + if (player_entity) { + fprintf(stderr, "[error] attempt to re-add localplayer entity\n"); + exit(EXIT_FAILURE); + } + + on_add(entity); + + player_entity = refcount_grb(&entity->rc); + recv_pos_rot(); + + entity->type->update_nametag(entity); + + pthread_rwlock_unlock(&lock_player_entity); +} + +static void local_on_remove(ClientEntity *entity) +{ + pthread_rwlock_wrlock(&lock_player_entity); + refcount_drp(&entity->rc); + player_entity = NULL; + pthread_rwlock_unlock(&lock_player_entity); + + on_remove(entity); +} + +static void local_on_update_pos_rot(__attribute__((unused)) ClientEntity *entity) +{ + recv_pos_rot(); +} + +static void local_on_update_nametag(ClientEntity *entity) +{ + if (entity->data.nametag) { + free(entity->data.nametag); + entity->data.nametag = NULL; + } +} + +static void __attribute__((unused)) on_model_step(Model *model, __attribute__((unused)) f64 dtime) +{ + ClientPlayerData *data = ((ClientEntity *) model->extra)->extra; + (void) data; // ToDo: animations +} + +static void on_model_delete(Model *model) +{ + if (model->extra) + refcount_drp(&((ClientEntity *) model->extra)->rc); +} + +// called on startup +void client_player_init() +{ + client_player.movement = (ToClientMovement) { + .flight = false, + .collision = true, + .speed = 0.0f, + .jump = 0.0f, + .gravity = 0.0f, + }; + + client_entity_types[ENTITY_PLAYER] = (ClientEntityType) { + .add = &on_add, + .remove = &on_remove, + .free = &on_free, + .update_pos_rot = NULL, + .update_nametag = NULL, + .transform = &on_transform, + }; + + client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) { + .add = &local_on_add, + .remove = &local_on_remove, + .free = &on_free, + .update_pos_rot = &local_on_update_pos_rot, + .update_nametag = &local_on_update_nametag, + .transform = &on_transform, }; + + pthread_rwlock_init(&client_player.lock_movement, NULL); + + player_entity = NULL; + pthread_rwlock_init(&lock_player_entity, NULL); } -static bool is_solid(s32 x, s32 y, s32 z) +// called on shutdown +void client_player_deinit() { - Node node = map_get_node(client_player.map, (v3s32) {x, y, z}).type; - return node == NODE_UNLOADED || node_definitions[node].solid; + pthread_rwlock_destroy(&client_player.lock_movement); + pthread_rwlock_destroy(&lock_player_entity); } -static bool can_jump() +void client_player_gfx_init() { - aabb3f fbox = get_box(); - fbox.min.y -= 0.5f; + player_model = model_load( + RESSOURCE_PATH "models/player.txt", RESSOURCE_PATH "textures/models/player", + &client_entity_cube, &client_entity_shader); + + player_model->callbacks.step = &on_model_step; + player_model->callbacks.delete = &on_model_delete; +} - aabb3s32 box = round_box(fbox); +void client_player_gfx_deinit() +{ + model_delete(player_model); +} - if (fbox.min.y - (f32) box.min.y > 0.01f) - return false; +ClientEntity *client_player_entity(u64 id) +{ + ClientEntity *entity = client_entity_grab(id); - for (s32 x = box.min.x; x <= box.max.x; x++) - for (s32 z = box.min.z; z <= box.max.z; z++) - if (is_solid(x, box.min.y, z)) - return true; + if (entity->type == &client_entity_types[ENTITY_LOCALPLAYER] + || entity->type == &client_entity_types[ENTITY_PLAYER]) + return entity; - return false; + refcount_drp(&entity->rc); + return NULL; } +ClientEntity *client_player_entity_local() +{ + ClientEntity *entity = NULL; + + pthread_rwlock_rdlock(&lock_player_entity); + if (player_entity) + entity = refcount_grb(&player_entity->rc); + pthread_rwlock_unlock(&lock_player_entity); + + return entity; +} + +void client_player_update_pos(ClientEntity *entity) +{ + pthread_rwlock_rdlock(&lock_player_entity); + + if (entity == player_entity) { + update_pos(); + send_pos_rot(); + } + + pthread_rwlock_unlock(&lock_player_entity); +} + +void client_player_update_rot(ClientEntity *entity) +{ + pthread_rwlock_rdlock(&lock_player_entity); + + if (entity == player_entity) { + update_rot(); + send_pos_rot(); + } + + pthread_rwlock_unlock(&lock_player_entity); +} + +// jump if possible void client_player_jump() { - if (can_jump()) - client_player.velocity.y += 10.0f; + ClientEntity *entity = client_player_entity_local(); + if (!entity) + return; + + pthread_rwlock_rdlock(&entity->lock_pos_rot); + pthread_rwlock_rdlock(&entity->lock_box_off); + + if (physics_ground( + client_terrain, + client_player.movement.collision, + entity->box_collision, + &entity->data.pos, + &client_player.velocity + )) + client_player.velocity.y += client_player.movement.jump; + + pthread_rwlock_unlock(&entity->lock_box_off); + pthread_rwlock_unlock(&entity->lock_pos_rot); + + refcount_drp(&entity->rc); } +// to be called every frame void client_player_tick(f64 dtime) { - v3f old_pos = client_player.pos; - v3f old_velocity = client_player.velocity; - - client_player.velocity.y -= 32.0f * dtime; - -#define GETS(vec, comp) *(s32 *) ((char *) &vec + offsetof(v3s32, comp)) -#define GETF(vec, comp) *(f32 *) ((char *) &vec + offsetof(v3f32, comp)) -#define PHYSICS(a, b, c) { \ - f32 v = (GETF(client_player.velocity, a) + GETF(old_velocity, a)) / 2.0f; \ - if (v == 0.0f) \ - goto a ## _physics_done; \ - aabb3s32 box = round_box(get_box()); \ - v3f old_pos = client_player.pos; \ - GETF(client_player.pos, a) += v * dtime; \ - s32 dir; \ - f32 offset; \ - if (v > 0.0f) { \ - dir = +1; \ - offset = GETF(client_player.box.max, a); \ - GETS(box.min, a) = ceil(GETF(old_pos, a) + offset + 0.5f); \ - GETS(box.max, a) = floor(GETF(client_player.pos, a) + offset + 0.5f); \ - } else { \ - dir = -1; \ - offset = GETF(client_player.box.min, a); \ - GETS(box.min, a) = floor(GETF(old_pos, a) + offset - 0.5f); \ - GETS(box.max, a) = ceil(GETF(client_player.pos, a) + offset - 0.5f); \ - } \ - GETS(box.max, a) += dir; \ - for (s32 a = GETS(box.min, a); a != GETS(box.max, a); a += dir) { \ - for (s32 b = GETS(box.min, b); b <= GETS(box.max, b); b++) { \ - for (s32 c = GETS(box.min, c); c <= GETS(box.max, c); c++) { \ - if (is_solid(x, y, z)) { \ - GETF(client_player.pos, a) = (f32) a - offset - 0.5f * (f32) dir; \ - GETF(client_player.velocity, a) = 0.0f; \ - goto a ## _physics_done; \ - } \ - } \ - } \ - } \ - a ## _physics_done: (void) 0;\ - } + ClientEntity *entity = client_player_entity_local(); + if (!entity) + return; - PHYSICS(x, y, z) - PHYSICS(y, x, z) - PHYSICS(z, x, y) + pthread_rwlock_rdlock(&client_player.lock_movement); + pthread_rwlock_wrlock(&entity->lock_pos_rot); + pthread_rwlock_rdlock(&entity->lock_box_off); -#undef GETS -#undef GETF -#undef PHYSICS + if (physics_step( + client_terrain, + client_player.movement.collision, + entity->box_collision, + &entity->data.pos, + &client_player.velocity, + &(v3f64) { + 0.0, + client_player.movement.flight ? 0.0 : -client_player.movement.gravity, + 0.0, + }, + dtime + )) + client_player_update_pos(entity); - if (old_pos.x != client_player.pos.x || old_pos.y != client_player.pos.y || old_pos.z != client_player.pos.z) - update_pos(); + pthread_rwlock_unlock(&entity->lock_box_off); + pthread_rwlock_unlock(&entity->lock_pos_rot); + pthread_rwlock_unlock(&client_player.lock_movement); + + refcount_drp(&entity->rc); }