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