source: network-game/client/Client/main.cpp@ cdb4bec

Last change on this file since cdb4bec was e607c0f, checked in by dportnoy <dmp1488@…>, 12 years ago

The client uses nonblocking calls to check for server messages and textboxes can now process all the standard keyboard keys

  • Property mode set to 100644
File size: 11.5 KB
Line 
1#if defined WINDOWS
2 #include <winsock2.h>
3 #include <WS2tcpip.h>
4#elif defined LINUX
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <netdb.h>
10 #include <cstring>
11#endif
12
13#include <sys/types.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string>
17#include <iostream>
18
19#include <allegro5/allegro.h>
20#include <allegro5/allegro_font.h>
21#include <allegro5/allegro_ttf.h>
22
23#include "../../common/Compiler.h"
24#include "../../common/Message.h"
25#include "../../common/Common.h"
26
27#include "Window.h"
28#include "Textbox.h"
29#include "Button.h"
30#include "chat.h"
31
32#ifdef WINDOWS
33 #pragma comment(lib, "ws2_32.lib")
34#endif
35
36using namespace std;
37
38void initWinSock();
39void shutdownWinSock();
40void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole);
41
42// callbacks
43void registerAccount();
44void login();
45void logout();
46void quit();
47void sendChatMessage();
48
49void error(const char *);
50
51const float FPS = 60;
52const int SCREEN_W = 640;
53const int SCREEN_H = 480;
54const int BOUNCER_SIZE = 32;
55enum MYKEYS {
56 KEY_UP,
57 KEY_DOWN,
58 KEY_LEFT,
59 KEY_RIGHT
60};
61
62enum STATE {
63 STATE_START,
64 STATE_LOGIN // this means you're already logged in
65};
66
67int state;
68
69bool doexit;
70
71Window* wndLogin;
72Window* wndMain;
73Window* wndCurrent;
74
75Textbox* txtUsername;
76Textbox* txtPassword;
77Textbox* txtChat;
78
79int sock;
80struct sockaddr_in server, from;
81struct hostent *hp;
82NETWORK_MSG msgTo, msgFrom;
83string username;
84chat chatConsole;
85
86int main(int argc, char **argv)
87{
88 ALLEGRO_DISPLAY *display = NULL;
89 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
90 ALLEGRO_TIMER *timer = NULL;
91 ALLEGRO_BITMAP *bouncer = NULL;
92 bool key[4] = { false, false, false, false };
93 bool redraw = true;
94 doexit = false;
95
96 float bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
97 float bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
98
99 state = STATE_START;
100
101 if(!al_init()) {
102 fprintf(stderr, "failed to initialize allegro!\n");
103 return -1;
104 }
105
106 al_init_primitives_addon();
107 al_init_font_addon();
108 al_init_ttf_addon();
109
110 ALLEGRO_FONT *font = al_load_ttf_font("../pirulen.ttf", 12, 0);
111
112 if (!font) {
113 fprintf(stderr, "Could not load 'pirulen.ttf'.\n");
114 getchar();
115 return -1;
116 }
117
118 if(!al_install_keyboard()) {
119 fprintf(stderr, "failed to initialize the keyboard!\n");
120 return -1;
121 }
122
123 if(!al_install_mouse()) {
124 fprintf(stderr, "failed to initialize the mouse!\n");
125 return -1;
126 }
127
128 timer = al_create_timer(1.0 / FPS);
129 if(!timer) {
130 fprintf(stderr, "failed to create timer!\n");
131 return -1;
132 }
133
134 display = al_create_display(SCREEN_W, SCREEN_H);
135 if(!display) {
136 fprintf(stderr, "failed to create display!\n");
137 al_destroy_timer(timer);
138 return -1;
139 }
140
141 wndLogin = new Window(0, 0, SCREEN_W, SCREEN_H);
142 wndLogin->addComponent(new Textbox(104, 40, 100, 20, font));
143 wndLogin->addComponent(new Textbox(104, 70, 100, 20, font));
144 wndLogin->addComponent(new Button(22, 100, 90, 20, font, "Register", registerAccount));
145 wndLogin->addComponent(new Button(122, 100, 60, 20, font, "Login", login));
146 wndLogin->addComponent(new Button(540, 10, 80, 20, font, "Quit", quit));
147
148 txtUsername = (Textbox*)wndLogin->getComponent(0);
149 txtPassword = (Textbox*)wndLogin->getComponent(1);
150
151 wndMain = new Window(0, 0, SCREEN_W, SCREEN_H);
152 wndMain->addComponent(new Textbox(95, 40, 525, 20, font));
153 wndMain->addComponent(new Button(95, 70, 160, 20, font, "Send Message", sendChatMessage));
154 wndMain->addComponent(new Button(540, 10, 80, 20, font, "Logout", logout));
155
156 txtChat = (Textbox*)wndMain->getComponent(0);
157
158 wndCurrent = wndLogin;
159
160 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
161 if(!bouncer) {
162 fprintf(stderr, "failed to create bouncer bitmap!\n");
163 al_destroy_display(display);
164 al_destroy_timer(timer);
165 return -1;
166 }
167
168 event_queue = al_create_event_queue();
169 if(!event_queue) {
170 fprintf(stderr, "failed to create event_queue!\n");
171 al_destroy_bitmap(bouncer);
172 al_destroy_display(display);
173 al_destroy_timer(timer);
174 return -1;
175 }
176
177 al_set_target_bitmap(bouncer);
178
179 al_clear_to_color(al_map_rgb(255, 0, 255));
180
181 al_set_target_bitmap(al_get_backbuffer(display));
182
183 al_register_event_source(event_queue, al_get_display_event_source(display));
184 al_register_event_source(event_queue, al_get_timer_event_source(timer));
185 al_register_event_source(event_queue, al_get_keyboard_event_source());
186 al_register_event_source(event_queue, al_get_mouse_event_source());
187
188 al_clear_to_color(al_map_rgb(0,0,0));
189
190 al_flip_display();
191
192 if (argc != 3) {
193 cout << "Usage: server port" << endl;
194 exit(1);
195 }
196
197 initWinSock();
198
199 sock = socket(AF_INET, SOCK_DGRAM, 0);
200 if (sock < 0)
201 error("socket");
202
203 set_nonblock(sock);
204
205 server.sin_family = AF_INET;
206 hp = gethostbyname(argv[1]);
207 if (hp==0)
208 error("Unknown host");
209
210 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
211 server.sin_port = htons(atoi(argv[2]));
212
213 al_start_timer(timer);
214
215 while(!doexit)
216 {
217 ALLEGRO_EVENT ev;
218 al_wait_for_event(event_queue, &ev);
219
220 if(wndCurrent->handleEvent(ev)) {
221 // do nothing
222 }
223 else if(ev.type == ALLEGRO_EVENT_TIMER) {
224 if(key[KEY_UP] && bouncer_y >= 4.0) {
225 bouncer_y -= 4.0;
226 }
227
228 if(key[KEY_DOWN] && bouncer_y <= SCREEN_H - BOUNCER_SIZE - 4.0) {
229 bouncer_y += 4.0;
230 }
231
232 if(key[KEY_LEFT] && bouncer_x >= 4.0) {
233 bouncer_x -= 4.0;
234 }
235
236 if(key[KEY_RIGHT] && bouncer_x <= SCREEN_W - BOUNCER_SIZE - 4.0) {
237 bouncer_x += 4.0;
238 }
239
240 redraw = true;
241 }
242 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
243 doexit = true;
244 }
245 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) {
246 switch(ev.keyboard.keycode) {
247 case ALLEGRO_KEY_UP:
248 key[KEY_UP] = true;
249 break;
250
251 case ALLEGRO_KEY_DOWN:
252 key[KEY_DOWN] = true;
253 break;
254
255 case ALLEGRO_KEY_LEFT:
256 key[KEY_LEFT] = true;
257 break;
258
259 case ALLEGRO_KEY_RIGHT:
260 key[KEY_RIGHT] = true;
261 break;
262 }
263 }
264 else if(ev.type == ALLEGRO_EVENT_KEY_UP) {
265 switch(ev.keyboard.keycode) {
266 case ALLEGRO_KEY_UP:
267 key[KEY_UP] = false;
268 break;
269
270 case ALLEGRO_KEY_DOWN:
271 key[KEY_DOWN] = false;
272 break;
273
274 case ALLEGRO_KEY_LEFT:
275 key[KEY_LEFT] = false;
276 break;
277
278 case ALLEGRO_KEY_RIGHT:
279 key[KEY_RIGHT] = false;
280 break;
281
282 case ALLEGRO_KEY_ESCAPE:
283 doexit = true;
284 break;
285 }
286 }
287
288 if (receiveMessage(&msgFrom, sock, &from) >= 0)
289 {
290 processMessage(msgFrom, state, chatConsole);
291 cout << "state: " << state << endl;
292 }
293
294 if (redraw && al_is_event_queue_empty(event_queue))
295 {
296 redraw = false;
297
298 wndCurrent->draw(display);
299
300 al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0);
301
302 chatConsole.draw(font, al_map_rgb(255,255,255));
303
304 if(wndCurrent == wndLogin) {
305 al_draw_text(font, al_map_rgb(0, 255, 0), 4, 43, ALLEGRO_ALIGN_LEFT, "Username:");
306 al_draw_text(font, al_map_rgb(0, 255, 0), 1, 73, ALLEGRO_ALIGN_LEFT, "Password:");
307 }
308 else if(wndCurrent == wndMain) {
309 al_draw_text(font, al_map_rgb(0, 255, 0), 4, 43, ALLEGRO_ALIGN_LEFT, "Message:");
310 }
311
312 al_flip_display();
313 }
314 }
315
316 #if defined WINDOWS
317 closesocket(sock);
318 #elif defined LINUX
319 close(sock);
320 #endif
321
322 shutdownWinSock();
323
324 delete wndLogin;
325 delete wndMain;
326
327 al_destroy_event_queue(event_queue);
328 al_destroy_bitmap(bouncer);
329 al_destroy_display(display);
330 al_destroy_timer(timer);
331
332 return 0;
333}
334
335// need to make a function like this that works on windows
336void error(const char *msg)
337{
338 perror(msg);
339 shutdownWinSock();
340 exit(1);
341}
342
343void initWinSock()
344{
345#if defined WINDOWS
346 WORD wVersionRequested;
347 WSADATA wsaData;
348 int wsaerr;
349
350 wVersionRequested = MAKEWORD(2, 2);
351 wsaerr = WSAStartup(wVersionRequested, &wsaData);
352
353 if (wsaerr != 0) {
354 cout << "The Winsock dll not found." << endl;
355 exit(1);
356 }else
357 cout << "The Winsock dll was found." << endl;
358#endif
359}
360
361void shutdownWinSock()
362{
363#if defined WINDOWS
364 WSACleanup();
365#endif
366}
367
368void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole)
369{
370 string response = string(msg.buffer);
371
372 switch(state)
373 {
374 case STATE_START:
375 {
376 cout << "In STATE_START" << endl;
377
378 chatConsole.addLine(response);
379
380 switch(msg.type)
381 {
382 case MSG_TYPE_REGISTER:
383 {
384 break;
385 }
386 case MSG_TYPE_LOGIN:
387 {
388 if (response.compare("Player has already logged in.") == 0)
389 {
390 username.clear();
391 cout << "User login failed" << endl;
392 }
393 else if (response.compare("Incorrect username or password") == 0)
394 {
395 username.clear();
396 cout << "User login failed" << endl;
397 }
398 else
399 {
400 state = STATE_LOGIN;
401 wndCurrent = wndMain;
402 cout << "User login successful" << endl;
403 }
404 break;
405 }
406 }
407
408 break;
409 }
410 case STATE_LOGIN:
411 {
412 chatConsole.addLine(response);
413
414 switch(msg.type)
415 {
416 case MSG_TYPE_REGISTER:
417 {
418 break;
419 }
420 case MSG_TYPE_LOGIN:
421 {
422 if (response.compare("You have successfully logged out.") == 0)
423 {
424 cout << "Logged out" << endl;
425 state = STATE_START;
426 wndCurrent = wndLogin;
427 }
428 else
429 {
430 cout << "Added new line" << endl;
431 }
432
433 break;
434 }
435 }
436
437 break;
438 }
439 default:
440 {
441 cout << "The state has an invalid value: " << state << endl;
442
443 break;
444 }
445 }
446}
447
448void registerAccount()
449{
450 string username = txtUsername->getStr();
451 string password = txtPassword->getStr();
452
453 txtUsername->clear();
454 txtPassword->clear();
455
456 msgTo.type = MSG_TYPE_REGISTER;
457
458 strcpy(msgTo.buffer, username.c_str());
459 strcpy(msgTo.buffer+username.size()+1, password.c_str());
460
461 sendMessage(&msgTo, sock, &server);
462}
463
464void login()
465{
466 string strUsername = txtUsername->getStr();
467 string strPassword = txtPassword->getStr();
468 username = strUsername;
469
470 txtUsername->clear();
471 txtPassword->clear();
472
473 msgTo.type = MSG_TYPE_LOGIN;
474
475 strcpy(msgTo.buffer, strUsername.c_str());
476 strcpy(msgTo.buffer+username.size()+1, strPassword.c_str());
477
478 sendMessage(&msgTo, sock, &server);
479}
480
481void logout()
482{
483 txtChat->clear();
484
485 msgTo.type = MSG_TYPE_LOGOUT;
486
487 strcpy(msgTo.buffer, username.c_str());
488
489 sendMessage(&msgTo, sock, &server);
490}
491
492void quit()
493{
494 doexit = true;
495}
496
497void sendChatMessage()
498{
499 string msg = txtChat->getStr();
500
501 txtChat->clear();
502
503 msgTo.type = MSG_TYPE_CHAT;
504
505 strcpy(msgTo.buffer, msg.c_str());
506
507 sendMessage(&msgTo, sock, &server);
508}
Note: See TracBrowser for help on using the repository browser.