]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client.c
Redesign map handling
[dragonblocks_alpha.git] / src / client.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <arpa/inet.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <netdb.h>
9 #include <GL/glew.h>
10 #include <GL/gl.h>
11 #include <GLFW/glfw3.h>
12 #include "client.h"
13 #include "clientmap.h"
14 #include "signal.h"
15 #include "shaders.h"
16 #include "util.h"
17
18 Client client;
19
20 void client_disconnect(bool send, const char *detail)
21 {
22         pthread_mutex_lock(&client.mtx);
23         if (client.state != CS_DISCONNECTED) {
24                 if (send)
25                         write_u32(client.fd, SC_DISCONNECT);
26
27                 client.state = CS_DISCONNECTED;
28                 printf("Disconnected %s%s%s\n", INBRACES(detail));
29                 close(client.fd);
30         }
31         pthread_mutex_unlock(&client.mtx);
32 }
33
34 #include "network.c"
35
36 static void *reciever_thread(void *unused)
37 {
38         (void) unused;
39
40         handle_packets(&client);
41
42         if (errno != EINTR)
43                 client_disconnect(false, "network error");
44
45         return NULL;
46 }
47
48 static void update_view_matrix(ShaderProgram *prog, mat4x4 view)
49 {
50         mat4x4_translate(view, -client.pos.x, -client.pos.y, -client.pos.z);
51         glUniformMatrix4fv(prog->loc_view, 1, GL_FALSE, view[0]);
52 }
53
54 static void client_loop()
55 {
56         if(! glfwInit()) {
57                 printf("Failed to initialize GLFW\n");
58                 return;
59         }
60
61         glfwWindowHint(GLFW_SAMPLES, 8);
62         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
63         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
64         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
65
66         int width, height;
67         width = 1250;
68         height = 750;
69
70         GLFWwindow *window = glfwCreateWindow(width, height, "Dragonblocks", NULL, NULL);
71
72         if (! window) {
73                 fprintf(stderr, "Failed to create window\n");
74                 glfwTerminate();
75                 return;
76         }
77
78         glfwMakeContextCurrent(window);
79         if (glewInit() != GLEW_OK) {
80                 fprintf(stderr, "Failed to initialize GLEW\n");
81                 return;
82         }
83
84         glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
85
86         const char *shader_path;
87
88 #ifdef RELEASE
89         shader_path = "shaders";
90 #else
91         shader_path = "../shaders";
92 #endif
93
94         ShaderProgram *prog = create_shader_program(shader_path);
95         if (! prog) {
96                 fprintf(stderr, "Failed to create shader program\n");
97                 return;
98         }
99
100         mat4x4 view, projection;
101
102         update_view_matrix(prog, view);
103         mat4x4_perspective(projection, 86.1f / 180.0f * M_PI, (float) width / (float) height, 0.01f, 1000.0f);
104
105         glUseProgram(prog->id);
106         glUniformMatrix4fv(prog->loc_view, 1, GL_FALSE, view[0]);
107         glUniformMatrix4fv(prog->loc_projection, 1, GL_FALSE, projection[0]);
108
109         while (! glfwWindowShouldClose(window) && client.state != CS_DISCONNECTED && ! interrupted) {
110                 glEnable(GL_DEPTH_TEST);
111                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
112                 glClearColor(0.52941176470588f, 0.8078431372549f, 0.92156862745098f, 1.0f);
113
114                 bool pos_changed = false;
115
116                 if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
117                         pos_changed = true;
118                         client.pos.z -= 1.0f;
119                 } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
120                         pos_changed = true;
121                         client.pos.z += 1.0f;
122                 } if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
123                         pos_changed = true;
124                         client.pos.x -= 1.0f;
125                 } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
126                         pos_changed = true;
127                         client.pos.x += 1.0f;
128                 } if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
129                         pos_changed = true;
130                         client.pos.y -= 1.0f;
131                 } else if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
132                         pos_changed = true;
133                         client.pos.y += 1.0f;
134                 }
135
136                 if (pos_changed) {
137                         update_view_matrix(prog, view);
138                         pthread_mutex_lock(&client.mtx);
139                         (void) (write_u32(client.fd, SC_POS) && write_v3f32(client.fd, client.pos));
140                         pthread_mutex_unlock(&client.mtx);
141                 }
142
143                 scene_render(client.scene, prog);
144
145                 glfwSwapBuffers(window);
146                 glfwPollEvents();
147         }
148
149         delete_shader_program(prog);
150 }
151
152 static bool client_name_prompt()
153 {
154         printf("Enter name: ");
155         fflush(stdout);
156         char name[NAME_MAX];
157         if (scanf("%s", name) == EOF)
158                 return false;
159         client.name = strdup(name);
160         pthread_mutex_lock(&client.mtx);
161         if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) {
162                 client.state = CS_AUTH;
163                 printf("Authenticating...\n");
164         }
165         pthread_mutex_unlock(&client.mtx);
166         return true;
167 }
168
169 static bool client_authenticate()
170 {
171         for ever {
172                 switch (client.state) {
173                         case CS_CREATED:
174                                 if (client_name_prompt())
175                                         break;
176                                 else
177                                         return false;
178                         case CS_AUTH:
179                                 if (interrupted)
180                                         return false;
181                                 else
182                                         sched_yield();
183                                 break;
184                         case CS_ACTIVE:
185                                 return true;
186                         case CS_DISCONNECTED:
187                                 return false;
188                 }
189         }
190         return false;
191 }
192
193 static void client_start(int fd)
194 {
195         client.fd = fd;
196         pthread_mutex_init(&client.mtx, NULL);
197         client.state = CS_CREATED;
198         client.name = NULL;
199         client.map = map_create();
200         client.scene = scene_create();
201         client.pos = (v3f) {0.0f, 0.0f, 0.0f};
202
203         clientmap_init(&client);
204
205         pthread_t recv_thread;
206         pthread_create(&recv_thread, NULL, &reciever_thread, NULL);
207
208         if (client_authenticate())
209                 client_loop();
210
211         if (client.state != CS_DISCONNECTED)
212                 client_disconnect(true, NULL);
213
214         if (client.name)
215                 free(client.name);
216
217         clientmap_deinit();
218
219         map_delete(client.map);
220         scene_delete(client.scene);
221
222         pthread_mutex_destroy(&client.mtx);
223 }
224
225 int main(int argc, char **argv)
226 {
227         program_name = argv[0];
228
229         if (argc < 3)
230                 internal_error("missing address or port");
231
232         struct addrinfo hints = {
233                 .ai_family = AF_UNSPEC,
234                 .ai_socktype = SOCK_STREAM,
235                 .ai_protocol = 0,
236                 .ai_flags = AI_NUMERICSERV,
237         };
238
239         struct addrinfo *info = NULL;
240
241         int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
242
243         if (gai_state != 0)
244                 internal_error(gai_strerror(gai_state));
245
246         int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
247
248         if (fd == -1)
249                 syscall_error("socket");
250
251         if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
252                 syscall_error("connect");
253
254         char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
255         printf("Connected to %s\n", addrstr);
256         free(addrstr);
257
258         freeaddrinfo(info);
259
260         init_signal_handlers();
261         client_start(fd);
262
263         return EXIT_SUCCESS;
264 }