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

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

Removed some unused client code and made the client update player positions as well as recieve them from the server.

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