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