Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NetLobbyClient.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright (C) 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: NetLobbyClient.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Stream-oriented network client class
13 */
14 
15 
16 #include "MemDebug.h"
17 #include "NetLobbyClient.h"
18 #include "NetClientConfig.h"
19 #include "NetAuth.h"
20 #include "NetChat.h"
21 #include "Campaign.h"
22 #include "Player.h"
23 #include "Starshatter.h"
24 #include "ModInfo.h"
25 
26 #include "NetHost.h"
27 #include "NetPeer.h"
28 #include "NetLink.h"
29 #include "NetMsg.h"
30 #include "NetLayer.h"
31 #include "FormatUtil.h"
32 
33 extern const char* versionInfo;
34 
35 // +-------------------------------------------------------------------+
36 
38 : NetLobby(false), server_id(0), host(false), exit_code(0), temporary(false)
39 {
40  NetHost me;
41  Text server_name;
42  WORD port = 11101;
43 
44  ping_req_time = 0;
45  chat_req_time = 0;
46  user_req_time = 0;
47  camp_req_time = 0;
48  unit_req_time = 0;
49  mods_req_time = 0;
50 
52  if (ncc) {
53  NetServerInfo* info = ncc->GetSelectedServer();
54 
55  if (info) {
56  server_name = info->hostname;
57  addr = info->addr;
58  port = info->port;
59  gamepass = info->password;
60  }
61  }
62 
63  if (server_name.length() && port > 0) {
64  Print(" '%s' is a client of '%s'\n", me.Name(), server_name.data());
65  link = new(__FILE__,__LINE__) NetLink;
66  server_id = link->AddPeer(NetAddr(server_name, port));
67  }
68  else if (port == 0) {
69  Print(" '%s' invalid lobby port number %d\n", me.Name(), port);
70  }
71  else {
72  Print(" '%s' is a client without a server\n", me.Name());
73  }
74 }
75 
77 : NetLobby(true), server_id(0), addr(server_addr), host(false), exit_code(0),
78 temporary(true)
79 {
80  ping_req_time = 0;
81  chat_req_time = 0;
82  user_req_time = 0;
83  camp_req_time = 0;
84  unit_req_time = 0;
85  mods_req_time = 0;
86 
87  if (addr.IPAddr() != 0) {
88  link = new(__FILE__,__LINE__) NetLink;
90  }
91 }
92 
94 {
95  missions.destroy();
96 }
97 
98 // +--------------------------------------------------------------------+
99 
100 void
102 {
103  if (link && server_id && type > 0 && type < 255) {
104  if (msg.length())
105  link->SendMessage(server_id, (BYTE) type, msg.data(), msg.length(), NetMsg::RELIABLE);
106  else
107  link->SendMessage(server_id, (BYTE) type, 0, 0, NetMsg::RELIABLE);
108  }
109 }
110 
111 // +--------------------------------------------------------------------+
112 
113 void
115 {
117 
118  if (!temporary) {
119  // check health of server:
121  if (s && (NetLayer::GetUTC() - s->LastReceiveTime() > NET_DISCONNECT_TIME)) {
122  exit_code = 2;
123  }
124 
125  // send keep alive ping:
129  }
130  }
131 }
132 
133 // +--------------------------------------------------------------------+
134 
135 bool
136 NetLobbyClient::Login(bool host_req)
137 {
138  Player* player = Player::GetCurrentPlayer();
139  if (!player)
140  return false;
141 
142  host = host_req;
143 
144  Text login = "name \"";
145  login += SafeQuotes(player->Name());
146  login += "\" pass \"";
147  login += SafeQuotes(player->Password());
148  login += "\" version \"";
149  login += versionInfo;
150  login += "\" ";
151 
152  char buffer[256];
153 
154  sprintf_s(buffer, "host %s rank %d time %d miss %d kill %d loss %d ",
155  host ? "true" : "false",
156  player->Rank(),
157  player->FlightTime(),
158  player->Missions(),
159  player->Kills(),
160  player->Losses());
161 
162  login += buffer;
163 
164  login += "sig \"";
165  login += SafeQuotes(player->Signature());
166  login += "\" squad \"";
167  login += SafeQuotes(player->Squadron());
168  login += "\" ";
169 
170  if (gamepass.length() > 0) {
171  login += "gamepass \"";
172  login += SafeQuotes(gamepass);
173  login += "\" ";
174  }
175 
176  SendData(NET_LOBBY_LOGIN, login);
177  ExecFrame();
178  return true;
179 }
180 
181 bool
183 {
184  if (host)
185  GameStop();
186 
188  Sleep(250);
189  ExecFrame();
190  return true;
191 }
192 
193 // +--------------------------------------------------------------------+
194 
195 bool
197 {
198  Text no_data;
199 
200  SendData(NET_LOBBY_PING, no_data);
201  Sleep(100);
202 
203  SendData(NET_LOBBY_PING, no_data);
204  Sleep(100);
205 
206  SendData(NET_LOBBY_PING, no_data);
207  Sleep(100);
208 
210  Sleep(700);
211  ExecFrame();
212 
214 }
215 
216 void
218 {
220  Sleep(100);
221 
224 
225  // discard unit map selection data so that
226  // it will be refreshed when we return to
227  // the lobby after the mission:
228 
229  ClearUnitMap();
230 }
231 
232 void
234 {
236  ExecFrame();
237  Sleep(100);
238 
240 }
241 
242 // +--------------------------------------------------------------------+
243 
244 const Text&
246 {
248  return server_info.machine_info;
249 
250  return NetLobby::GetMachineInfo();
251 }
252 
253 int
255 {
257  return server_info.status;
258 
259  return NetLobby::GetStatus();
260 }
261 
262 int
264 {
266  return server_info.nplayers;
267 
268  return NetLobby::NumUsers();
269 }
270 
271 bool
273 {
275  return server_info.hosted ? true : false;
276 
277  return NetLobby::HasHost();
278 }
279 
280 WORD
282 {
284  return server_info.gameport;
285 
286  return NetLobby::GetGamePort();
287 }
288 
289 // +-------------------------------------------------------------------+
290 
291 void
292 NetLobbyClient::AddChat(NetUser* user, const char* msg, bool route)
293 {
294  if (!msg || !*msg) return;
295 
296  char buffer[280];
297  sprintf_s(buffer, "msg \"%s\"", SafeQuotes(msg));
298 
299  SendData(NET_LOBBY_CHAT, buffer);
300  ExecFrame();
301 }
302 
305 {
306  if (chat_log.size() < 1 && (NetLayer::GetUTC() - chat_req_time > 3)) {
309  }
310 
311  return chat_log;
312 }
313 
316 {
317  if (users.size() < 1 && (NetLayer::GetUTC() - user_req_time > 2)) {
320  }
321 
322  return users;
323 }
324 
327 {
328  if (server_mods.size() < 1 && (NetLayer::GetUTC() - mods_req_time > 2)) {
331  }
332 
333  return server_mods;
334 }
335 
338 {
339  bool request = selected_mission &&
340  unit_map.size() < 1 &&
342 
344  request = true;
345 
346  if (request) {
349  }
350 
351  return unit_map;
352 }
353 
354 // +--------------------------------------------------------------------+
355 
358 {
359  if (campaigns.size() < 1 && (NetLayer::GetUTC() - camp_req_time > 3)) {
362  }
363 
364  return campaigns;
365 }
366 
367 // +--------------------------------------------------------------------+
368 
369 void
371 {
372  char buffer[512];
373  sprintf_s(buffer, "user \"%s\"", SafeQuotes(user->Name()));
374  SendData(NET_LOBBY_BAN_USER, buffer);
375 }
376 
377 // +--------------------------------------------------------------------+
378 
379 void
381 {
382  char buffer[32];
383  sprintf_s(buffer, "m_id 0x%08x", id);
385 }
386 
387 void
388 NetLobbyClient::MapUnit(int n, const char* user, bool lock)
389 {
390  if (user && strlen(user) > 250)
391  return;
392 
393  char buffer[512];
394  sprintf_s(buffer, "id %d user \"%s\" lock %s",
395  n, SafeQuotes(user), lock ? "true" : "false");
396  SendData(NET_LOBBY_MAP_UNIT, buffer);
397 }
398 
399 Mission*
401 {
402  mission = 0;
403 
404  // ask server for mission:
406 
407  // wait for answer:
408  int i = 150;
409  while (i-- > 0 && !mission) {
410  Sleep(100);
411  ExecFrame();
412  }
413 
414  return mission;
415 }
416 
417 // +--------------------------------------------------------------------+
418 
419 void
421 {
422  List<NetLobbyParam> params;
423  ParseMsg(msg, params);
424 
425  int level = NetAuth::NET_AUTH_STANDARD;
426  Text salt;
427 
428  for (int i = 0; i < params.size(); i++) {
429  NetLobbyParam* p = params[i];
430 
431  int num = 0;
432  sscanf_s(p->value, "%d", &num);
433 
434  if (p->name == "level") {
435  level = num;
436  }
437 
438  else if (p->name == "salt") {
439  salt = p->value;
440  }
441  }
442 
443  Text response = NetAuth::CreateAuthResponse(level, salt);
444  if (response.length() > 0)
445  SendData(NET_LOBBY_USER_AUTH, response);
446 }
447 
448 void
450 {
451  List<NetLobbyParam> params;
452  ParseMsg(msg, params);
453 
454  for (int i = 0; i < params.size(); i++) {
455  NetLobbyParam* p = params[i];
456 
457  int num = 0;
458  sscanf_s(p->value, "%d", &num);
459 
460  if (p->name == "info") {
462  }
463 
464  else if (p->name == "version") {
466  }
467 
468  else if (p->name == "mode") {
469  server_info.status = num;
470  }
471 
472  else if (p->name == "users") {
473  server_info.nplayers = num;
474  }
475 
476  else if (p->name == "host") {
477  server_info.hosted = (p->value == "true");
478  }
479 
480  else if (p->name == "port") {
481  server_info.gameport = (WORD) num;
482  }
483  }
484 
485  params.destroy();
486 }
487 
488 void
490 {
491  List<NetLobbyParam> params;
492  ParseMsg(msg, params);
493 
494  int id = 0;
495  Text user_name;
496  Text chat_msg;
497 
498  for (int i = 0; i < params.size(); i++) {
499  NetLobbyParam* p = params[i];
500 
501  int num = 0;
502  sscanf_s(p->value, "%d", &num);
503 
504  if (p->name == "id")
505  id = num;
506 
507  else if (p->name == "user")
508  user_name = p->value;
509 
510  else if (p->name == "msg")
511  chat_msg = p->value;
512  }
513 
514  params.destroy();
515 
516  // receive chat from server:
517  if (id && chat_msg.length()) {
518  NetChatEntry* entry = new(__FILE__,__LINE__) NetChatEntry(id, user_name, chat_msg);
519 
520  if (!chat_log.contains(entry))
521  chat_log.insertSort(entry);
522  else
523  delete entry; // received duplicate
524  }
525 }
526 
527 void
529 {
530  mods_req_time = NetLayer::GetUTC() + 3600;
531 
532  List<NetLobbyParam> params;
533  ParseMsg(msg, params);
535 
536  Text name;
537  Text version;
538  Text url;
539 
540  for (int i = 0; i < params.size(); i++) {
541  NetLobbyParam* p = params[i];
542 
543  if (p->name == "mod") {
544  name = p->value;
545  }
546 
547  else if (p->name == "url") {
548  url = p->value;
549  }
550 
551  else if (p->name == "ver") {
552  version = p->value;
553 
554  ModInfo* info = new(__FILE__,__LINE__) ModInfo(name, version, url);
555  server_mods.append(info);
556  }
557  }
558 
559  params.destroy();
560 }
561 
562 void
564 {
565  List<NetLobbyParam> params;
566  ParseMsg(msg, params);
567 
568  users.destroy();
569 
570  Text user_name;
571  Text host_flag;
572  Text signature;
573  Text squadron;
574  int rank = 0;
575  int flight_time = 0;
576  int mission_count = 0;
577  int kills = 0;
578  int losses = 0;
579 
580  for (int i = 0; i < params.size(); i++) {
581  NetLobbyParam* p = params[i];
582 
583  int num = 0;
584  sscanf_s(p->value, "%d", &num);
585 
586  if (p->name == "name")
587  user_name = p->value;
588 
589  else if (p->name == "sig")
590  signature = p->value;
591 
592  else if (p->name == "squad")
593  squadron = p->value;
594 
595  else if (p->name == "rank")
596  rank = num;
597 
598  else if (p->name == "time")
599  flight_time = num;
600 
601  else if (p->name == "miss")
602  mission_count = num;
603 
604  else if (p->name == "kill")
605  kills = num;
606 
607  else if (p->name == "loss")
608  losses = num;
609 
610  else if (p->name == "host") {
611  host_flag = p->value;
612 
613  NetUser* u = new(__FILE__,__LINE__) NetUser(user_name);
614  u->SetHost((host_flag == "true") ? true : false);
615  u->SetSignature(signature);
616  u->SetSquadron(squadron);
617  u->SetRank(rank);
618  u->SetFlightTime(flight_time);
619  u->SetMissions(mission_count);
620  u->SetKills(kills);
621  u->SetLosses(losses);
622 
623  AddUser(u);
624  }
625  }
626 
627  params.destroy();
628 }
629 
630 void
632 {
633  List<NetLobbyParam> params;
634  ParseMsg(msg, params);
635 
636  if (params.size() > 2) {
637  campaigns.destroy();
638 
639  NetCampaignInfo* c = 0;
640  MissionInfo* m = 0;
641 
642  for (int i = 0; i < params.size(); i++) {
643  NetLobbyParam* p = params[i];
644 
645  if (p->name == "c_id") {
646  c = new(__FILE__,__LINE__) NetCampaignInfo;
647  sscanf_s(p->value, "0x%x", &c->id);
648  campaigns.append(c);
649 
650  m = 0;
651  }
652 
653  else if (c && p->name == "c_name") {
654  c->name = p->value;
655  }
656 
657  else if (p->name == "m_id") {
658  int id = 0;
659  sscanf_s(p->value, "0x%x", &id);
660 
661  int m_id = id & NET_MISSION_MASK;
662  int c_id = id >> NET_CAMPAIGN_SHIFT;
663 
664  for (int i = 0; i < campaigns.size(); i++) {
665  NetCampaignInfo* c = campaigns[i];
666  if (c->id == c_id) {
667  m = new(__FILE__,__LINE__) MissionInfo;
668  m->id = m_id;
669  c->missions.append(m);
670  missions.append(m); // for later garbage collection
671  break;
672  }
673  }
674  }
675 
676  else if (m && p->name == "m_name") {
677  m->name = p->value;
678  }
679 
680  else if (m && p->name == "m_desc") {
681  m->description = p->value;
682  }
683  }
684  }
685 
686  params.destroy();
687 }
688 
689 void
691 {
692  List<NetLobbyParam> params;
693  ParseMsg(msg, params);
694 
695  for (int i = 0; i < params.size(); i++) {
696  NetLobbyParam* p = params[i];
697 
698  int num = 0;
699  sscanf_s(p->value, "0x%x", &num);
700 
701  if (p->name == "m_id") {
702  if (selected_mission != (DWORD) num) {
703  selected_mission = num;
704  ClearUnitMap();
705  }
706  }
707  }
708 
709  params.destroy();
710 }
711 
712 void
714 {
715  Campaign* c = Campaign::SelectCampaign("Multiplayer Missions");
716 
717  if (c) {
718  c->LoadNetMission(99999, msg.data());
719  mission = c->GetMission(99999);
720  }
721 
722  if (msg.length()) {
723  FILE* f;
724  ::fopen_s(&f, "multi_mission_recv.def", "w");
725  if (f) {
726  ::fwrite(msg.data(), msg.length(), 1, f);
727  ::fclose(f);
728  }
729  }
730 }
731 
732 void
734 {
735  List<NetLobbyParam> params;
736  ParseMsg(msg, params);
737 
738  if (params.size() > 2) {
739  ClearUnitMap();
740 
741  Text elem_name;
742  Text design;
743  Text user_name;
744  int iff;
745  int index;
746  int lives = 1;
747  int hull = 100;
748  int role = 0;
749  int lock = 0;
750 
751  for (int i = 0; i < params.size(); i++) {
752  NetLobbyParam* p = params[i];
753 
754  if (p->name == "name") {
755  elem_name = p->value;
756  }
757  else if (p->name == "design") {
758  design = p->value;
759  }
760  else if (p->name == "user") {
761  user_name = p->value;
762  }
763  else if (p->name == "index") {
764  sscanf_s(p->value, "%d", &index);
765  }
766  else if (p->name == "iff") {
767  sscanf_s(p->value, "%d", &iff);
768  }
769  else if (p->name == "lives") {
770  sscanf_s(p->value, "%d", &lives);
771  }
772  else if (p->name == "hull") {
773  sscanf_s(p->value, "%d", &hull);
774  }
775  else if (p->name == "role") {
776  sscanf_s(p->value, "%d", &role);
777  }
778  else if (p->name == "lock") {
779  sscanf_s(p->value, "%d", &lock);
780 
781  NetUnitEntry* entry = new(__FILE__,__LINE__) NetUnitEntry(elem_name, design, iff, index);
782  entry->SetUserName(user_name);
783  entry->SetLives(lives);
784  entry->SetIntegrity(hull);
785  entry->SetMissionRole(role);
786  entry->SetLock(lock ? true : false);
787 
788  unit_map.append(entry);
789  }
790  }
791  }
792 
793  params.destroy();
794 }
795 
796 void
798 {
799 }
800 
801 void
803 {
804 }
805 
806 void
808 {
809  exit_code = 1;
810 }