3 #include "client/camera.h"
4 #include "client/client.h"
5 #include "client/client_inventory.h"
6 #include "client/client_player.h"
7 #include "client/client_terrain.h"
8 #include "client/cube.h"
9 #include "client/debug_menu.h"
10 #include "client/texture.h"
11 #include "environment.h"
14 struct ClientPlayer client_player;
16 static ClientEntity *player_entity;
17 static pthread_rwlock_t lock_player_entity;
19 static Model *player_model;
21 // updat epos/rot box/eye functions
23 static void update_camera()
25 vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
27 ClientPlayerData *data = player_entity->extra;
30 mat4x4_mul_vec4(dst, data->bones.eyes->abs, src);
34 camera_set_position((v3f32) {dst[0], dst[1], dst[2]});
37 static void update_pos()
39 debug_menu_changed(ENTRY_POS);
40 debug_menu_changed(ENTRY_HUMIDITY);
41 debug_menu_changed(ENTRY_TEMPERATURE);
44 static void update_rot()
46 camera_set_angle(M_PI / 2 - player_entity->data.rot.y, -player_entity->data.rot.x);
47 debug_menu_changed(ENTRY_YAW);
48 debug_menu_changed(ENTRY_PITCH);
51 static void update_transform()
53 client_entity_transform(player_entity);
57 static void send_pos_rot()
61 dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) {
62 .pos = player_entity->data.pos,
63 .rot = player_entity->data.rot,
67 static void recv_pos_rot()
77 static void local_on_model_before_render(__attribute__((unused)) Model *model)
79 client_entity_depth_offset(0.2f);
80 client_inventory_depth_offset(0.2f);
83 static void local_on_model_after_render(__attribute__((unused)) Model *model)
85 client_entity_depth_offset(0.0f);
86 client_inventory_depth_offset(0.0f);}
88 static void on_add(ClientEntity *entity)
90 entity->model = model_clone(player_model);
91 entity->model->extra = refcount_grb(&entity->rc);
93 ClientPlayerData *data = entity->extra = malloc(sizeof *data);
94 data->bones = (struct ClientPlayerBones) {NULL};
96 model_get_bones(entity->model, (ModelBoneMapping[9]) {
97 {"nametag", &data->bones.nametag },
98 {"neck", &data->bones.neck },
99 {"neck.head.eyes", &data->bones.eyes },
100 {"arm_left", &data->bones.arm_left },
101 {"arm_right", &data->bones.arm_right },
102 {"arm_left.hand", &data->bones.hand_left },
103 {"arm_right.hand", &data->bones.hand_right},
104 {"leg_left", &data->bones.leg_left },
105 {"leg_right", &data->bones.leg_right },
108 entity->nametag_offset = data->bones.nametag ? &data->bones.nametag->abs : NULL;
109 entity->box_collision = (aabb3f32) {{-0.45f, 0.0f, -0.45f}, {0.45f, 1.8f, 0.45f}};
111 client_inventory_init_player(entity);
113 model_scene_add(entity->model);
114 client_entity_transform(entity);
117 static void on_remove(ClientEntity *entity)
119 entity->model->flags.delete = 1;
120 entity->model = NULL;
123 static void on_free(ClientEntity *entity)
125 client_inventory_init_player(entity);
129 static void on_transform(ClientEntity *entity)
131 ClientPlayerData *data = entity->extra;
133 entity->model->root->rot.x = entity->model->root->rot.z = 0.0f;
135 if (data->bones.neck) {
136 data->bones.neck->rot.x = entity->data.rot.x;
137 model_node_transform(data->bones.neck);
141 static void local_on_add(ClientEntity *entity)
143 pthread_rwlock_wrlock(&lock_player_entity);
146 fprintf(stderr, "[error] attempt to re-add localplayer entity\n");
151 entity->model->callbacks.before_render = &local_on_model_before_render;
152 entity->model->callbacks.after_render = &local_on_model_after_render;
154 player_entity = refcount_grb(&entity->rc);
157 entity->type->update_nametag(entity);
159 pthread_rwlock_unlock(&lock_player_entity);
162 static void local_on_remove(ClientEntity *entity)
164 pthread_rwlock_wrlock(&lock_player_entity);
165 refcount_drp(&entity->rc);
166 player_entity = NULL;
167 pthread_rwlock_unlock(&lock_player_entity);
172 static void local_on_update_pos_rot(__attribute__((unused)) ClientEntity *entity)
177 static void local_on_update_nametag(ClientEntity *entity)
179 if (entity->data.nametag) {
180 free(entity->data.nametag);
181 entity->data.nametag = NULL;
185 static void on_model_delete(Model *model)
188 refcount_drp(&((ClientEntity *) model->extra)->rc);
192 void client_player_init()
194 client_player.movement = (ToClientMovement) {
202 client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
204 .remove = &on_remove,
206 .update_pos_rot = NULL,
207 .update_nametag = NULL,
208 .transform = &on_transform,
211 client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
212 .add = &local_on_add,
213 .remove = &local_on_remove,
215 .update_pos_rot = &local_on_update_pos_rot,
216 .update_nametag = &local_on_update_nametag,
217 .transform = &on_transform,
220 pthread_rwlock_init(&client_player.lock_movement, NULL);
222 player_entity = NULL;
223 pthread_rwlock_init(&lock_player_entity, NULL);
226 // called on shutdown
227 void client_player_deinit()
229 pthread_rwlock_destroy(&client_player.lock_movement);
230 pthread_rwlock_destroy(&lock_player_entity);
233 void client_player_gfx_init()
235 player_model = model_load(
236 RESSOURCE_PATH "models/player.txt", RESSOURCE_PATH "textures/models/player",
237 &client_entity_cube, &client_entity_shader);
239 player_model->callbacks.delete = &on_model_delete;
242 void client_player_gfx_deinit()
244 model_delete(player_model);
247 ClientEntity *client_player_entity(u64 id)
249 ClientEntity *entity = client_entity_grab(id);
251 if (entity->type == &client_entity_types[ENTITY_LOCALPLAYER]
252 || entity->type == &client_entity_types[ENTITY_PLAYER])
255 refcount_drp(&entity->rc);
259 ClientEntity *client_player_entity_local()
261 ClientEntity *entity = NULL;
263 pthread_rwlock_rdlock(&lock_player_entity);
265 entity = refcount_grb(&player_entity->rc);
266 pthread_rwlock_unlock(&lock_player_entity);
271 void client_player_update_pos(ClientEntity *entity)
273 pthread_rwlock_rdlock(&lock_player_entity);
275 if (entity == player_entity) {
280 pthread_rwlock_unlock(&lock_player_entity);
283 void client_player_update_rot(ClientEntity *entity)
285 pthread_rwlock_rdlock(&lock_player_entity);
287 if (entity == player_entity) {
292 pthread_rwlock_unlock(&lock_player_entity);
296 void client_player_jump()
298 ClientEntity *entity = client_player_entity_local();
302 pthread_rwlock_rdlock(&entity->lock_pos_rot);
303 pthread_rwlock_rdlock(&entity->lock_box_off);
307 client_player.movement.collision,
308 entity->box_collision,
310 &client_player.velocity
312 client_player.velocity.y += client_player.movement.jump;
314 pthread_rwlock_unlock(&entity->lock_box_off);
315 pthread_rwlock_unlock(&entity->lock_pos_rot);
317 refcount_drp(&entity->rc);
320 // to be called every frame
321 void client_player_tick(f64 dtime)
323 ClientEntity *entity = client_player_entity_local();
327 pthread_rwlock_rdlock(&client_player.lock_movement);
328 pthread_rwlock_wrlock(&entity->lock_pos_rot);
329 pthread_rwlock_rdlock(&entity->lock_box_off);
333 client_player.movement.collision,
334 entity->box_collision,
336 &client_player.velocity,
339 client_player.movement.flight ? 0.0 : -client_player.movement.gravity,
344 client_player_update_pos(entity);
346 pthread_rwlock_unlock(&entity->lock_box_off);
347 pthread_rwlock_unlock(&entity->lock_pos_rot);
348 pthread_rwlock_unlock(&client_player.lock_movement);
350 refcount_drp(&entity->rc);