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
RevLine 
[4c202e0]1#include "../../common/Compiler.h"
2
[e08572c]3#if defined WINDOWS
[0dde5da]4 #include <winsock2.h>
5 #include <WS2tcpip.h>
[e08572c]6#elif defined LINUX
[0dde5da]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>
[a845faf]13#endif
[1912323]14
[d352805]15#include <sys/types.h>
[88cdae2]16#include <cstdio>
17#include <cstdlib>
[a845faf]18#include <string>
[1912323]19#include <iostream>
[88cdae2]20#include <sstream>
[1912323]21
[eb8adb1]22#include <map>
[1912323]23
[3a79253]24#include <map>
25
[d352805]26#include <allegro5/allegro.h>
27#include <allegro5/allegro_font.h>
28#include <allegro5/allegro_ttf.h>
[88cdae2]29#include <allegro5/allegro_primitives.h>
[7d7df47]30
[b53c6b3]31#include "../../common/Message.h"
[e607c0f]32#include "../../common/Common.h"
[62ee2ce]33#include "../../common/WorldMap.h"
[4c202e0]34#include "../../common/Player.h"
[7d7df47]35
[87b3ee2]36#include "Window.h"
37#include "Textbox.h"
38#include "Button.h"
[6475138]39#include "chat.h"
40
[a845faf]41#ifdef WINDOWS
[6475138]42 #pragma comment(lib, "ws2_32.lib")
[a845faf]43#endif
[1912323]44
45using namespace std;
46
[0dde5da]47void initWinSock();
48void shutdownWinSock();
[88cdae2]49void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole, map<unsigned int, Player>& mapPlayers, unsigned int& curPlayerId);
[62ee2ce]50void drawMap(WorldMap* gameMap);
[88cdae2]51void drawPlayers(map<unsigned int, Player>& mapPlayers, unsigned int curPlayerId);
[62ee2ce]52POSITION screenToMap(POSITION pos);
53POSITION mapToScreen(POSITION pos);
[87b3ee2]54
55// callbacks
56void registerAccount();
57void login();
58void logout();
59void quit();
60void sendChatMessage();
[4da5aa3]61
[1912323]62void error(const char *);
[7d7df47]63
[d352805]64const float FPS = 60;
65const int SCREEN_W = 640;
66const int SCREEN_H = 480;
[0cc431d]67
68enum STATE {
69 STATE_START,
[87b3ee2]70 STATE_LOGIN // this means you're already logged in
[d352805]71};
[87b3ee2]72
73int state;
74
75bool doexit;
76
[3a79253]77map<unsigned int, Player> mapPlayers;
78
[87b3ee2]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;
[d352805]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;
[87b3ee2]101 doexit = false;
[eb8adb1]102 map<unsigned int, Player> mapPlayers;
[88cdae2]103 unsigned int curPlayerId = -1;
[9a3e6b1]104
[87b3ee2]105 state = STATE_START;
[9a3e6b1]106
[d352805]107 if(!al_init()) {
108 fprintf(stderr, "failed to initialize allegro!\n");
109 return -1;
110 }
111
[88cdae2]112 if (al_init_primitives_addon())
113 cout << "Primitives initialized" << endl;
114 else
115 cout << "Primitives not initialized" << endl;
116
[d352805]117 al_init_font_addon();
118 al_init_ttf_addon();
119
[88cdae2]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
[d352805]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 }
[87b3ee2]136
137 if(!al_install_mouse()) {
138 fprintf(stderr, "failed to initialize the mouse!\n");
139 return -1;
140 }
[d352805]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 }
[87b3ee2]154
[384b7e0]155 WorldMap* gameMap = WorldMap::loadMapFromFile("../../data/map.txt");
[62ee2ce]156
[87b3ee2]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;
[d352805]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());
[87b3ee2]189 al_register_event_source(event_queue, al_get_mouse_event_source());
[d352805]190
191 al_clear_to_color(al_map_rgb(0,0,0));
192
193 al_flip_display();
[9a3e6b1]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
[e607c0f]206 set_nonblock(sock);
207
[9a3e6b1]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
[d352805]216 al_start_timer(timer);
[e607c0f]217
[d352805]218 while(!doexit)
219 {
220 ALLEGRO_EVENT ev;
[3d81c0d]221
[d352805]222 al_wait_for_event(event_queue, &ev);
[87b3ee2]223
224 if(wndCurrent->handleEvent(ev)) {
225 // do nothing
226 }
227 else if(ev.type == ALLEGRO_EVENT_TIMER) {
[d352805]228 redraw = true;
229 }
230 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
[9a3e6b1]231 doexit = true;
[d352805]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 }
[88cdae2]242 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
[ad5d122]243 if(wndCurrent == wndMain) {
244 msgTo.type = MSG_TYPE_PLAYER_MOVE;
[88cdae2]245
[62ee2ce]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);
[88cdae2]256
[62ee2ce]257 sendMessage(&msgTo, sock, &server);
258 }
259 else
260 cout << "Invalid point: User did not click on the map" << endl;
[ad5d122]261 }
[88cdae2]262 }
[e607c0f]263
264 if (receiveMessage(&msgFrom, sock, &from) >= 0)
[88cdae2]265 processMessage(msgFrom, state, chatConsole, mapPlayers, curPlayerId);
[d352805]266
[054b50b]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
[e607c0f]274 if (redraw && al_is_event_queue_empty(event_queue))
275 {
[d352805]276 redraw = false;
[88cdae2]277
[87b3ee2]278 wndCurrent->draw(display);
[9a3e6b1]279
[6475138]280 chatConsole.draw(font, al_map_rgb(255,255,255));
[9a3e6b1]281
[87b3ee2]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:");
[62ee2ce]288
289 drawMap(gameMap);
290 drawPlayers(mapPlayers, curPlayerId);
[87b3ee2]291 }
292
[d352805]293 al_flip_display();
294 }
295 }
[9a3e6b1]296
297 #if defined WINDOWS
298 closesocket(sock);
299 #elif defined LINUX
300 close(sock);
301 #endif
302
303 shutdownWinSock();
[d352805]304
[87b3ee2]305 delete wndLogin;
306 delete wndMain;
307
[62ee2ce]308 delete gameMap;
309
[d352805]310 al_destroy_event_queue(event_queue);
311 al_destroy_display(display);
312 al_destroy_timer(timer);
313
314 return 0;
315}
316
[4da5aa3]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
[0dde5da]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
[1912323]348}
349
[62ee2ce]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
[ca44f82]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
[88cdae2]381void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole, map<unsigned int, Player>& mapPlayers, unsigned int& curPlayerId)
[1912323]382{
[4da5aa3]383 string response = string(msg.buffer);
384
385 switch(state)
386 {
387 case STATE_START:
388 {
[e607c0f]389 cout << "In STATE_START" << endl;
390
[87b3ee2]391 switch(msg.type)
[4da5aa3]392 {
[87b3ee2]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;
[88cdae2]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;
[87b3ee2]421 }
[88cdae2]422
[87b3ee2]423 break;
424 }
[4da5aa3]425 }
426
427 break;
428 }
429 case STATE_LOGIN:
430 {
[eb8adb1]431 switch(msg.type)
[4da5aa3]432 {
[87b3ee2]433 case MSG_TYPE_REGISTER:
434 {
435 break;
436 }
437 case MSG_TYPE_LOGIN:
438 {
[eb8adb1]439 chatConsole.addLine(response);
440
[054b50b]441 cout << "Got a logout message" << endl;
[87b3ee2]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
[4c202e0]453 break;
454 }
[054b50b]455 case MSG_TYPE_LOGOUT:
456 {
457 cout << "Got a logout message, but we don't process it" << endl;
458
459 break;
460 }
[4c202e0]461 case MSG_TYPE_PLAYER:
462 {
[60776f2]463 Player p("", "");
464 p.deserialize(msg.buffer);
[054b50b]465 p.timeLastUpdated = getCurrentMillis();
[3a79253]466 mapPlayers[p.id] = p;
[4c202e0]467
[eb8adb1]468 break;
469 }
470 case MSG_TYPE_CHAT:
471 {
472 chatConsole.addLine(response);
[4c202e0]473
[87b3ee2]474 break;
475 }
[4da5aa3]476 }
[eb8adb1]477
[4da5aa3]478 break;
479 }
480 default:
481 {
482 cout << "The state has an invalid value: " << state << endl;
483
484 break;
485 }
486 }
[0dde5da]487}
[87b3ee2]488
[62ee2ce]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
[88cdae2]511void drawPlayers(map<unsigned int, Player>& mapPlayers, unsigned int curPlayerId)
512{
513 map<unsigned int, Player>::iterator it;
514
[62ee2ce]515 Player* p;
516 POSITION pos;
517
[88cdae2]518 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
519 {
[62ee2ce]520 p = &it->second;
521 pos = mapToScreen(p->pos);
[88cdae2]522
523 if (p->id == curPlayerId)
[62ee2ce]524 al_draw_filled_circle(pos.x, pos.y, 12, al_map_rgb(255, 0, 0));
[88cdae2]525 else
[62ee2ce]526 al_draw_filled_circle(pos.x, pos.y, 12, al_map_rgb(191, 0, 0));
[88cdae2]527 }
528}
529
[87b3ee2]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.