]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/client_player.c
Add trees
[dragonblocks_alpha.git] / src / client / client_player.c
1 #include <stdio.h>
2 #include "environment.h"
3 #include "client/camera.h"
4 #include "client/client.h"
5 #include "client/client_map.h"
6 #include "client/client_player.h"
7 #include "client/cube.h"
8 #include "client/debug_menu.h"
9 #include "client/texture.h"
10
11 struct ClientPlayer client_player;
12
13 // to be called whenever the player position changes
14 // rwlock has to be read or write locked
15 static void update_pos()
16 {
17         camera_set_position((v3f32) {client_player.pos.x, client_player.pos.y + client_player.eye_height, client_player.pos.z});
18         client_send_position(client_player.pos);
19
20         client_player.obj->pos = (v3f32) {client_player.pos.x, client_player.pos.y, client_player.pos.z};
21         object_transform(client_player.obj);
22
23         debug_menu_update_pos();
24         debug_menu_update_humidity();
25         debug_menu_update_temperature();
26 }
27
28 // get absolute player bounding box
29 // rwlock has to be read- or write locked
30 static aabb3f64 get_box()
31 {
32         return (aabb3f64) {
33                 {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},
34                 {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},
35         };
36 }
37
38 // get absolute integer box that contains all nodes a float bounding box touches
39 static aabb3s32 round_box(aabb3f64 box)
40 {
41         return (aabb3s32) {
42                 {floor(box.min.x + 0.5), floor(box.min.y + 0.5), floor(box.min.z + 0.5)},
43                 {ceil(box.max.x - 0.5), ceil(box.max.y - 0.5), ceil(box.max.z - 0.5)},
44         };
45 }
46
47 // return true if node at x, y, z is solid (or unloaded)
48 static bool is_solid(s32 x, s32 y, s32 z)
49 {
50         Node node = map_get_node(client_map.map, (v3s32) {x, y, z}).type;
51         return node == NODE_UNLOADED || node_definitions[node].solid;
52 }
53
54 // determine if player can jump currently (must be standing on a solid block)
55 // rwlock has to be read- or write locked
56 static bool can_jump()
57 {
58         if (client_player.velocity.y != 0.0)
59                 return false;
60
61         aabb3f64 fbox = get_box();
62         fbox.min.y -= 0.5;
63
64         aabb3s32 box = round_box(fbox);
65
66         if (fbox.min.y - (f64) box.min.y > 0.01)
67                 return false;
68
69         for (s32 x = box.min.x; x <= box.max.x; x++)
70                 for (s32 z = box.min.z; z <= box.max.z; z++)
71                         if (is_solid(x, box.min.y, z))
72                                 return true;
73
74         return false;
75 }
76
77 // ClientPlayer singleton constructor
78 void client_player_init()
79 {
80         client_player.pos = (v3f64) {0.0, 0.0, 0.0};
81         client_player.velocity = (v3f64) {0.0, 0.0, 0.0};
82         client_player.box = (aabb3f64) {{-0.3, 0.0, -0.3}, {0.3, 1.75, 0.3}};
83         client_player.yaw = client_player.pitch = 0.0f;
84         client_player.eye_height = 1.5;
85         client_player.fly = false;
86         client_player.collision = true;
87         pthread_rwlock_init(&client_player.rwlock, NULL);
88 }
89
90 // ClientPlayer singleton destructor
91 void client_player_deinit()
92 {
93         pthread_rwlock_destroy(&client_player.rwlock);
94 }
95
96 // create mesh object and info hud
97 void client_player_add_to_scene()
98 {
99         client_player.obj = object_create();
100         client_player.obj->scale = (v3f32) {0.6, 1.75, 0.6};
101         client_player.obj->visible = false;
102
103         object_set_texture(client_player.obj, texture_load(RESSOURCEPATH "textures/player.png", true));
104
105         for (int f = 0; f < 6; f++) {
106                 for (int v = 0; v < 6; v++) {
107                         Vertex3D vertex = cube_vertices[f][v];
108                         vertex.position.y += 0.5;
109                         object_add_vertex(client_player.obj, &vertex);
110                 }
111         }
112
113         pthread_rwlock_rdlock(&client_player.rwlock);
114         update_pos();
115         pthread_rwlock_unlock(&client_player.rwlock);
116
117         debug_menu_update_yaw();
118         debug_menu_update_pitch();
119 }
120
121 // jump if possible
122 void client_player_jump()
123 {
124         pthread_rwlock_wrlock(&client_player.rwlock);
125         if (can_jump())
126                 client_player.velocity.y += 10.0;
127         pthread_rwlock_unlock(&client_player.rwlock);
128 }
129
130 // get position (thread-safe)
131 v3f64 client_player_get_position()
132 {
133         v3f64 pos;
134
135         pthread_rwlock_rdlock(&client_player.rwlock);
136         pos = client_player.pos;
137         pthread_rwlock_unlock(&client_player.rwlock);
138
139         return pos;
140 }
141
142 // set position (thread-safe)
143 void client_player_set_position(v3f64 pos)
144 {
145         pthread_rwlock_rdlock(&client_player.rwlock);
146         client_player.pos = pos;
147         pthread_rwlock_unlock(&client_player.rwlock);
148 }
149
150 // to be called every frame
151 void client_player_tick(f64 dtime)
152 {
153         pthread_rwlock_wrlock(&client_player.rwlock);
154
155         v3f64 old_pos = client_player.pos;
156         v3f64 old_velocity = client_player.velocity;
157
158         if (! client_player.fly)
159                 client_player.velocity.y -= 32.0 * dtime;
160
161 #define GETS(vec, comp) *(s32 *) ((char *) &vec + offsetof(v3s32, comp))
162 #define GETF(vec, comp) *(f64 *) ((char *) &vec + offsetof(v3f64, comp))
163 #define PHYSICS(a, b, c) { \
164                 f64 v = (GETF(client_player.velocity, a) + GETF(old_velocity, a)) / 2.0f; \
165                 if (v == 0.0) \
166                         goto a ## _physics_done; \
167                 aabb3s32 box = round_box(get_box()); \
168                 v3f64 old_pos = client_player.pos; \
169                 GETF(client_player.pos, a) += v * dtime; \
170                 if (! client_player.collision) \
171                         goto a ## _physics_done; \
172                 s32 dir; \
173                 f64 offset; \
174                 if (v > 0.0) { \
175                         dir = +1; \
176                         offset = GETF(client_player.box.max, a); \
177                         GETS(box.min, a) = ceil(GETF(old_pos, a) + offset + 0.5); \
178                         GETS(box.max, a) = floor(GETF(client_player.pos, a) + offset + 0.5); \
179                 } else { \
180                         dir = -1; \
181                         offset = GETF(client_player.box.min, a); \
182                         GETS(box.min, a) = floor(GETF(old_pos, a) + offset - 0.5); \
183                         GETS(box.max, a) = ceil(GETF(client_player.pos, a) + offset - 0.5); \
184                 } \
185                 GETS(box.max, a) += dir; \
186                 for (s32 a = GETS(box.min, a); a != GETS(box.max, a); a += dir) { \
187                         for (s32 b = GETS(box.min, b); b <= GETS(box.max, b); b++) { \
188                                 for (s32 c = GETS(box.min, c); c <= GETS(box.max, c); c++) { \
189                                         if (is_solid(x, y, z)) { \
190                                                 GETF(client_player.pos, a) = (f64) a - offset - 0.5 * (f64) dir; \
191                                                 GETF(client_player.velocity, a) = 0.0; \
192                                                 goto a ## _physics_done; \
193                                         } \
194                                 } \
195                         } \
196                 } \
197                 a ## _physics_done: (void) 0;\
198         }
199
200         PHYSICS(x, y, z)
201         PHYSICS(y, x, z)
202         PHYSICS(z, x, y)
203
204 #undef GETS
205 #undef GETF
206 #undef PHYSICS
207
208         if (! v3f64_equals(old_pos, client_player.pos))
209                 update_pos();
210
211         pthread_rwlock_unlock(&client_player.rwlock);
212 }