]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client.c
Add mountain generation
[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 "camera.h"
13 #include "client.h"
14 #include "clientmap.h"
15 #include "clientnode.h"
16 #include "cube.h"
17 #include "hud.h"
18 #include "input.h"
19 #include "signal.h"
20 #include "shaders.h"
21 #include "util.h"
22
23 Client client;
24
25 void client_disconnect(bool send, const char *detail)
26 {
27         pthread_mutex_lock(&client.mtx);
28         if (client.state != CS_DISCONNECTED) {
29                 if (send)
30                         write_u32(client.fd, SC_DISCONNECT);
31
32                 client.state = CS_DISCONNECTED;
33                 printf("Disconnected %s%s%s\n", INBRACES(detail));
34                 close(client.fd);
35         }
36         pthread_mutex_unlock(&client.mtx);
37 }
38
39 #include "network.c"
40
41 static void *reciever_thread(__attribute__((unused)) void *unused)
42 {
43         handle_packets(&client);
44
45         if (errno != EINTR)
46                 client_disconnect(false, "network error");
47
48         return NULL;
49 }
50
51 static void framebuffer_size_callback(__attribute__((unused)) GLFWwindow* window, int width, int height)
52 {
53         glViewport(0, 0, width, height);
54
55         camera_on_resize(width, height);
56         hud_on_resize(width, height);
57         input_on_resize(width, height);
58 }
59
60 static void cursor_pos_callback(__attribute__((unused)) GLFWwindow* window, double current_x, double current_y)
61 {
62         input_on_cursor_pos(current_x, current_y);
63 }
64
65 static void window_pos_callback(__attribute__((unused)) GLFWwindow* window, int x, int y)
66 {
67         input_on_window_pos(x, y);
68 }
69
70 static void client_loop()
71 {
72         if(! glfwInit()) {
73                 printf("Failed to initialize GLFW\n");
74                 return;
75         }
76
77         glfwWindowHint(GLFW_SAMPLES, 8);
78         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
79         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
80         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
81
82         int width, height;
83         width = 1250;
84         height = 750;
85
86         GLFWwindow *window = glfwCreateWindow(width, height, "Dragonblocks", NULL, NULL);
87
88         if (! window) {
89                 fprintf(stderr, "Failed to create window\n");
90                 glfwTerminate();
91                 return;
92         }
93
94         glfwMakeContextCurrent(window);
95         if (glewInit() != GLEW_OK) {
96                 fprintf(stderr, "Failed to initialize GLEW\n");
97                 return;
98         }
99
100         glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
101
102         ShaderProgram *prog = create_shader_program(RESSOURCEPATH "shaders");
103         if (! prog) {
104                 fprintf(stderr, "Failed to create shader program\n");
105                 return;
106         }
107
108         init_client_node_definitions();
109         clientmap_start_meshgen();
110
111         glUseProgram(prog->id);
112
113         init_camera(window, prog);
114
115         set_camera_position((v3f) {0.0f, 0.0f, 0.0f});
116         set_camera_angle(0.0f, 0.0f);
117
118         camera_on_resize(width, height);
119
120         hud_init(prog);
121         hud_on_resize(width, height);
122
123         hud_add(RESSOURCEPATH "textures/crosshair.png", (v3f) {0.0f, 0.0f, 0.0f}, (v2f) {1.0f, 1.0f}, HUD_SCALE_TEXTURE);
124
125         init_input(&client, window);
126         input_on_resize(width, height);
127
128         clientplayer_add_to_scene(&client.player);
129
130         glfwSetFramebufferSizeCallback(window, &framebuffer_size_callback);
131         glfwSetCursorPosCallback(window, &cursor_pos_callback);
132         glfwSetWindowPosCallback(window, &window_pos_callback);
133
134         struct timespec ts, ts_old;
135         clock_gettime(CLOCK_REALTIME, &ts_old);
136
137         while (! glfwWindowShouldClose(window) && client.state != CS_DISCONNECTED && ! interrupted) {
138                 clock_gettime(CLOCK_REALTIME, &ts);
139                 f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1000000000.0;
140                 ts_old = ts;
141
142                 glEnable(GL_DEPTH_TEST);
143                 glEnable(GL_BLEND);
144                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
145                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
146                 glClearColor(0.52941176470588f, 0.8078431372549f, 0.92156862745098f, 1.0f);
147
148                 process_input();
149                 clientplayer_tick(&client.player, dtime);
150
151                 camera_enable();
152                 scene_render(client.scene, prog);
153
154                 hud_render();
155
156                 glfwSwapBuffers(window);
157                 glfwPollEvents();
158         }
159
160         delete_shader_program(prog);
161         hud_deinit();
162 }
163
164 static bool client_name_prompt()
165 {
166         printf("Enter name: ");
167         fflush(stdout);
168         char name[NAME_MAX];
169         if (scanf("%s", name) == EOF)
170                 return false;
171         client.name = strdup(name);
172         pthread_mutex_lock(&client.mtx);
173         if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) {
174                 client.state = CS_AUTH;
175                 printf("Authenticating...\n");
176         }
177         pthread_mutex_unlock(&client.mtx);
178         return true;
179 }
180
181 static bool client_authenticate()
182 {
183         for ever {
184                 switch (client.state) {
185                         case CS_CREATED:
186                                 if (client_name_prompt())
187                                         break;
188                                 else
189                                         return false;
190                         case CS_AUTH:
191                                 if (interrupted)
192                                         return false;
193                                 else
194                                         sched_yield();
195                                 break;
196                         case CS_ACTIVE:
197                                 return true;
198                         case CS_DISCONNECTED:
199                                 return false;
200                 }
201         }
202         return false;
203 }
204
205 static void client_start(int fd)
206 {
207         client.fd = fd;
208         pthread_mutex_init(&client.mtx, NULL);
209         client.state = CS_CREATED;
210         client.name = NULL;
211         client.map = map_create();
212         client.scene = scene_create();
213
214         clientplayer_init(&client);
215         clientmap_init(&client);
216
217         pthread_t recv_thread;
218         pthread_create(&recv_thread, NULL, &reciever_thread, NULL);
219
220         if (client_authenticate())
221                 client_loop();
222
223         if (client.state != CS_DISCONNECTED)
224                 client_disconnect(true, NULL);
225
226         if (client.name)
227                 free(client.name);
228
229         clientmap_deinit();
230
231         map_delete(client.map);
232         scene_delete(client.scene);
233
234         pthread_mutex_destroy(&client.mtx);
235 }
236
237 int main(int argc, char **argv)
238 {
239         program_name = argv[0];
240
241         if (argc < 3)
242                 internal_error("missing address or port");
243
244         struct addrinfo hints = {
245                 .ai_family = AF_UNSPEC,
246                 .ai_socktype = SOCK_STREAM,
247                 .ai_protocol = 0,
248                 .ai_flags = AI_NUMERICSERV,
249         };
250
251         struct addrinfo *info = NULL;
252
253         int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
254
255         if (gai_state != 0)
256                 internal_error(gai_strerror(gai_state));
257
258         int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
259
260         if (fd == -1)
261                 syscall_error("socket");
262
263         if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
264                 syscall_error("connect");
265
266         char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
267         printf("Connected to %s\n", addrstr);
268         free(addrstr);
269
270         freeaddrinfo(info);
271
272         init_signal_handlers();
273         client_start(fd);
274
275         return EXIT_SUCCESS;
276 }