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

Last change on this file since 80b3f94 was 88cdae2, checked in by Dmitry Portnoy <dmp1488@…>, 12 years ago

The user can now move around the screen by clicking once they're logged in. A new message of type MSG_TYPE_PLAYER_MOVE is sent to the server.

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