]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/client_player.c
ccbd059e0aeb32101ad2202c59e489f353206df2
[dragonblocks_alpha.git] / src / client / client_player.c
1 #include <stdio.h>
2 #include <stdlib.h>
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"
12 #include "physics.h"
13
14 struct ClientPlayer client_player;
15
16 static ClientEntity *player_entity;
17 static pthread_rwlock_t lock_player_entity;
18
19 static Model *player_model;
20
21 // updat epos/rot box/eye functions
22
23 static void update_camera()
24 {
25         vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
26
27         ClientPlayerData *data = player_entity->extra;
28
29         if (data->bones.eyes)
30                 mat4x4_mul_vec4(dst, data->bones.eyes->abs, src);
31         else
32                 vec4_dup(dst, src);
33
34         camera_set_position((v3f32) {dst[0], dst[1], dst[2]});
35 }
36
37 static void update_pos()
38 {
39         debug_menu_changed(ENTRY_POS);
40         debug_menu_changed(ENTRY_HUMIDITY);
41         debug_menu_changed(ENTRY_TEMPERATURE);
42 }
43
44 static void update_rot()
45 {
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);
49 }
50
51 static void update_transform()
52 {
53         client_entity_transform(player_entity);
54         update_camera();
55 }
56
57 static void send_pos_rot()
58 {
59         update_transform();
60
61         dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) {
62                 .pos = player_entity->data.pos,
63                 .rot = player_entity->data.rot,
64         });
65 }
66
67 static void recv_pos_rot()
68 {
69         update_transform();
70
71         update_pos();
72         update_rot();
73 }
74
75 // entity callbacks
76
77 static void on_add(ClientEntity *entity)
78 {
79         entity->model = model_clone(player_model);
80         entity->model->extra = refcount_grb(&entity->rc);
81
82         ClientPlayerData *data = entity->extra = malloc(sizeof *data);
83         data->bones = (struct ClientPlayerBones) {NULL};
84
85         model_get_bones(entity->model, (ModelBoneMapping[9]) {
86                 {"nametag",        &data->bones.nametag   },
87                 {"neck",           &data->bones.neck      },
88                 {"neck.head.eyes", &data->bones.eyes      },
89                 {"arm_left",       &data->bones.arm_left  },
90                 {"arm_right",      &data->bones.arm_right },
91                 {"arm_left.hand",  &data->bones.hand_left },
92                 {"arm_right.hand", &data->bones.hand_right},
93                 {"leg_left",       &data->bones.leg_left  },
94                 {"leg_right",      &data->bones.leg_right },
95         }, 9);
96
97         entity->nametag_offset = data->bones.nametag ? &data->bones.nametag->abs : NULL;
98         entity->box_collision = (aabb3f32) {{-0.45f, 0.0f, -0.45f}, {0.45f, 1.8f, 0.45f}};
99
100         client_inventory_init_player(entity);
101
102         model_scene_add(entity->model);
103         client_entity_transform(entity);
104 }
105
106 static void on_remove(ClientEntity *entity)
107 {
108         entity->model->flags.delete = 1;
109         entity->model = NULL;
110 }
111
112 static void on_free(ClientEntity *entity)
113 {
114         client_inventory_init_player(entity);
115         free(entity->extra);
116 }
117
118 static void on_transform(ClientEntity *entity)
119 {
120         ClientPlayerData *data = entity->extra;
121
122         entity->model->root->rot.x = entity->model->root->rot.z = 0.0f;
123
124         if (data->bones.neck) {
125                 data->bones.neck->rot.x = entity->data.rot.x;
126                 model_node_transform(data->bones.neck);
127         }
128 }
129
130 static void local_on_add(ClientEntity *entity)
131 {
132         pthread_rwlock_wrlock(&lock_player_entity);
133
134         if (player_entity) {
135                 fprintf(stderr, "[error] attempt to re-add localplayer entity\n");
136                 exit(EXIT_FAILURE);
137         }
138
139         on_add(entity);
140
141         player_entity = refcount_grb(&entity->rc);
142         recv_pos_rot();
143
144         entity->type->update_nametag(entity);
145
146         pthread_rwlock_unlock(&lock_player_entity);
147 }
148
149 static void local_on_remove(ClientEntity *entity)
150 {
151         pthread_rwlock_wrlock(&lock_player_entity);
152         refcount_drp(&entity->rc);
153         player_entity = NULL;
154         pthread_rwlock_unlock(&lock_player_entity);
155
156         on_remove(entity);
157 }
158
159 static void local_on_update_pos_rot(__attribute__((unused)) ClientEntity *entity)
160 {
161         recv_pos_rot();
162 }
163
164 static void local_on_update_nametag(ClientEntity *entity)
165 {
166         if (entity->data.nametag) {
167                 free(entity->data.nametag);
168                 entity->data.nametag = NULL;
169         }
170 }
171
172 static void __attribute__((unused)) on_model_step(Model *model, __attribute__((unused)) f64 dtime)
173 {
174         ClientPlayerData *data = ((ClientEntity *) model->extra)->extra;
175         (void) data; // ToDo: animations
176 }
177
178 static void on_model_delete(Model *model)
179 {
180         if (model->extra)
181                 refcount_drp(&((ClientEntity *) model->extra)->rc);
182 }
183
184 // called on startup
185 void client_player_init()
186 {
187         client_player.movement = (ToClientMovement) {
188                 .flight = false,
189                 .collision = true,
190                 .speed = 0.0f,
191                 .jump = 0.0f,
192                 .gravity = 0.0f,
193         };
194
195         client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
196                 .add = &on_add,
197                 .remove = &on_remove,
198                 .free = &on_free,
199                 .update_pos_rot = NULL,
200                 .update_nametag = NULL,
201                 .transform = &on_transform,
202         };
203
204         client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
205                 .add = &local_on_add,
206                 .remove = &local_on_remove,
207                 .free = &on_free,
208                 .update_pos_rot = &local_on_update_pos_rot,
209                 .update_nametag = &local_on_update_nametag,
210                 .transform = &on_transform,
211         };
212
213         pthread_rwlock_init(&client_player.lock_movement, NULL);
214
215         player_entity = NULL;
216         pthread_rwlock_init(&lock_player_entity, NULL);
217 }
218
219 // called on shutdown
220 void client_player_deinit()
221 {
222         pthread_rwlock_destroy(&client_player.lock_movement);
223         pthread_rwlock_destroy(&lock_player_entity);
224 }
225
226 void client_player_gfx_init()
227 {
228         player_model = model_load(
229                 RESSOURCE_PATH "models/player.txt", RESSOURCE_PATH "textures/models/player",
230                 &client_entity_cube, &client_entity_shader);
231
232         player_model->callbacks.step = &on_model_step;
233         player_model->callbacks.delete = &on_model_delete;
234 }
235
236 void client_player_gfx_deinit()
237 {
238         model_delete(player_model);
239 }
240
241 ClientEntity *client_player_entity(u64 id)
242 {
243         ClientEntity *entity = client_entity_grab(id);
244
245         if (entity->type == &client_entity_types[ENTITY_LOCALPLAYER] 
246                         || entity->type == &client_entity_types[ENTITY_PLAYER])
247                 return entity;
248
249         refcount_drp(&entity->rc);
250         return NULL;
251 }
252
253 ClientEntity *client_player_entity_local()
254 {
255         ClientEntity *entity = NULL;
256
257         pthread_rwlock_rdlock(&lock_player_entity);
258         if (player_entity)
259                 entity = refcount_grb(&player_entity->rc);
260         pthread_rwlock_unlock(&lock_player_entity);
261
262         return entity;
263 }
264
265 void client_player_update_pos(ClientEntity *entity)
266 {
267         pthread_rwlock_rdlock(&lock_player_entity);
268
269         if (entity == player_entity) {
270                 update_pos();
271                 send_pos_rot();
272         }
273
274         pthread_rwlock_unlock(&lock_player_entity);
275 }
276
277 void client_player_update_rot(ClientEntity *entity)
278 {
279         pthread_rwlock_rdlock(&lock_player_entity);
280
281         if (entity == player_entity) {
282                 update_rot();
283                 send_pos_rot();
284         }
285
286         pthread_rwlock_unlock(&lock_player_entity);
287 }
288
289 // jump if possible
290 void client_player_jump()
291 {
292         ClientEntity *entity = client_player_entity_local();
293         if (!entity)
294                 return;
295
296         pthread_rwlock_rdlock(&entity->lock_pos_rot);
297         pthread_rwlock_rdlock(&entity->lock_box_off);
298
299         if (physics_ground(
300                 client_terrain,
301                 client_player.movement.collision,
302                 entity->box_collision,
303                 &entity->data.pos,
304                 &client_player.velocity
305         ))
306                 client_player.velocity.y += client_player.movement.jump;
307
308         pthread_rwlock_unlock(&entity->lock_box_off);
309         pthread_rwlock_unlock(&entity->lock_pos_rot);
310
311         refcount_drp(&entity->rc);
312 }
313
314 // to be called every frame
315 void client_player_tick(f64 dtime)
316 {
317         ClientEntity *entity = client_player_entity_local();
318         if (!entity)
319                 return;
320
321         pthread_rwlock_rdlock(&client_player.lock_movement);
322         pthread_rwlock_wrlock(&entity->lock_pos_rot);
323         pthread_rwlock_rdlock(&entity->lock_box_off);
324
325         if (physics_step(
326                 client_terrain,
327                 client_player.movement.collision,
328                 entity->box_collision,
329                 &entity->data.pos,
330                 &client_player.velocity,
331                 &(v3f64) {
332                         0.0,
333                         client_player.movement.flight ? 0.0 : -client_player.movement.gravity,
334                         0.0,
335                 },
336                 dtime
337         ))
338                 client_player_update_pos(entity);
339
340         pthread_rwlock_unlock(&entity->lock_box_off);
341         pthread_rwlock_unlock(&entity->lock_pos_rot);
342         pthread_rwlock_unlock(&client_player.lock_movement);
343
344         refcount_drp(&entity->rc);
345 }