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

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

The server sends back an error on failed registration and sends chat messages to all players, not just the sender. The non-blocking socket function was moved to a new file in the common folder so the client can use it.

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