Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NetGameServer.cpp
Go to the documentation of this file.
1 /* Project Starshatter 5.0
2  Destroyer Studios LLC
3  Copyright © 1997-2007. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: NetGameServer.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Server-Side Network Game Manager class
13 */
14 
15 #include "MemDebug.h"
16 #include "NetGameServer.h"
17 #include "NetServerConfig.h"
18 #include "NetLobbyServer.h"
19 #include "NetPlayer.h"
20 #include "NetUser.h"
21 #include "NetMsg.h"
22 #include "NetData.h"
23 #include "StarServer.h"
24 #include "Ship.h"
25 #include "ShipDesign.h"
26 #include "Shield.h"
27 #include "Sim.h"
28 #include "SimEvent.h"
29 #include "Element.h"
30 #include "HUDView.h"
31 #include "RadioMessage.h"
32 #include "RadioView.h"
33 #include "Instruction.h"
34 #include "Hangar.h"
35 #include "FlightDeck.h"
36 #include "Mission.h"
37 
38 #include "NetLayer.h"
39 #include "NetHost.h"
40 #include "NetPeer.h"
41 #include "NetUtil.h"
42 #include "Game.h"
43 #include "Light.h"
44 
45 // +--------------------------------------------------------------------+
46 
47 const int MAX_NET_FPS = 20;
48 const int MIN_NET_FRAME = 1000 / MAX_NET_FPS;
49 
50 // +--------------------------------------------------------------------+
51 
53 {
54  Print("Constructing NetGameServer\n");
55 
56  WORD server_port = 11101;
57 
59  server_port = NetServerConfig::GetInstance()->GetGamePort();
60 
61  NetAddr server(NetHost().Address().IPAddr(), server_port);
62 
63  link = new(__FILE__,__LINE__) NetLink(server);
64 
65  ListIter<SimRegion> rgn_iter = sim->GetRegions();
66  while (++rgn_iter) {
67  SimRegion* rgn = rgn_iter.value();
68 
69  ListIter<Ship> iter = rgn->Ships();
70  while (++iter) {
71  Ship* s = iter.value();
72  s->SetObjID(GetNextObjID());
73  Observe(s);
74  ships.append(s);
75  }
76  }
77 
78  if (local_player) {
81  }
82 }
83 
85 {
87  while (++player) {
88  NetPlayer* p = player.value();
89 
90  if (p->GetShip())
91  p->GetShip()->SetRespawnCount(0);
92 
94  }
95 
96  Sleep(500);
97 
98  ListIter<Ship> iter = ships;
99  while (++iter) {
100  Ship* s = iter.value();
101  s->SetRespawnCount(0);
102  }
103 
104  zombies.destroy();
105  ships.clear();
106 }
107 
108 // +--------------------------------------------------------------------+
109 
110 void
112 {
114  CheckSessions();
115 
116  ListIter<SimRegion> rgn_iter = sim->GetRegions();
117  while (++rgn_iter) {
118  SimRegion* rgn = rgn_iter.value();
119 
120  ListIter<Ship> iter = rgn->Ships();
121  while (++iter) {
122  Ship* s = iter.value();
123 
124  if (s->GetObjID() == 0) {
125  s->SetObjID(GetNextObjID());
126  Observe(s);
127  ships.append(s);
128 
129  NetJoinAnnounce join_ann;
130  join_ann.SetShip(s);
131  join_ann.SetName("Server A.I. Ship");
132  SendData(&join_ann);
133  }
134  }
135  }
136 
137 
138  static DWORD time_mark = 0;
139 
140  if (!time_mark) time_mark = Game::RealTime();
141  else if (Game::RealTime() - time_mark > 60000) {
142  time_mark = Game::RealTime();
143 
144  if (link && players.size() > 0) {
145  Print("Server Stats\n-------------\n");
146  Print(" packets sent %d\n", link->GetPacketsSent());
147  Print(" packets recv %d\n", link->GetPacketsRecv());
148  Print(" bytes sent %d\n", link->GetBytesSent());
149  Print(" bytes recv %d\n", link->GetBytesRecv());
150  Print(" retries %d\n", link->GetRetries());
151  Print(" drops %d\n", link->GetDrops());
152  Print(" avg lag %d msec\n", link->GetLag());
153  }
154  }
155 }
156 
157 void
159 {
160  if (!link)
161  return;
162 
164  while (++iter) {
165  NetPlayer* player = iter.value();
166  NetPeer* peer = link->FindPeer(player->GetNetID());
167 
168  if (peer && (NetLayer::GetUTC() - peer->LastReceiveTime()) > NET_DISCONNECT_TIME) {
169  // announce drop:
170  NetPlayer* zombie = iter.removeItem();
171  HUDView::Message(Game::GetText("NetGameServer.remote-discon").data(), zombie->Name());
172 
173  // tell everyone else:
174  NetQuitAnnounce quit_ann;
175  quit_ann.SetObjID(zombie->GetObjID());
176  quit_ann.SetDisconnected(true);
177  SendData(&quit_ann);
178 
179  // return remote ship to ship pool:
180  Ship* s = zombie->GetShip();
181  if (s) {
182  Observe(s);
183  ships.append(s);
184  s->SetNetworkControl(0);
185  zombie->SetShip(0);
186 
187  NetJoinAnnounce join_ann;
188  join_ann.SetShip(s);
189  join_ann.SetName("Server A.I. Ship");
190  SendData(&join_ann);
191  }
192 
193  zombies.append(zombie);
194  }
195  }
196 }
197 
198 NetPlayer*
200 {
201  for (int i = 0; i < zombies.size(); i++) {
202  NetPlayer* p = zombies[i];
203 
204  if (p->GetObjID() == objid)
205  return p;
206  }
207 
208  return 0;
209 }
210 
211 // +--------------------------------------------------------------------+
212 
213 void
215 {
216  if (!msg) return;
217 
218  bool unpause = players.isEmpty();
219 
220  NetJoinRequest join_req;
221  if (join_req.Unpack(msg->Data())) {
222  HUDView::Message(Game::GetText("NetGameServer::join-request").data(), join_req.GetName(), join_req.GetElement(), join_req.GetIndex());
223 
224  DWORD nid = msg->NetID();
225  Text name = join_req.GetName();
226  Text serno = join_req.GetSerialNumber();
227  Text elem_name = join_req.GetElement();
228  int index = join_req.GetIndex();
229  Ship* ship = 0;
230  Sim* sim = Sim::GetSim();
231 
232  if (sim) {
233  Element* element = sim->FindElement(elem_name);
234 
235  if (element)
236  ship = element->GetShip(index);
237  }
238 
239  if (!ship) {
240  Print(" JOIN DENIED: could not locate ship for remote player\n");
241  return;
242  }
243 
244  if (!ship->GetObjID()) {
245  Print(" JOIN DENIED: remote player requested ship with objid = 0\n");
246  return;
247  }
248 
250 
251  if (lobby) {
252  NetUser* user = lobby->FindUserByName(name);
253 
254  if (!user)
255  user = lobby->FindUserByNetID(nid);
256 
257  if (!user) {
258  Print(" JOIN DENIED: remote player '%s' not found in lobby\n", name.data());
259  return;
260  }
261 
262  else if (!user->IsAuthOK()) {
263  Print(" JOIN DENIED: remote player '%s' not authenticated\n", name.data());
264  return;
265  }
266  }
267 
268  NetPlayer* remote_player = FindPlayerByNetID(nid);
269  if (remote_player && remote_player->GetShip() != ship) {
270  Print(" disconnecting remote player from ship '%s'\n", ship->Name());
271  players.remove(remote_player);
272  delete remote_player;
273  remote_player = 0;
274  }
275 
276  if (!remote_player) {
277  Ignore(ship);
278  ships.remove(ship);
279 
280  remote_player = new(__FILE__,__LINE__) NetPlayer(nid);
281  remote_player->SetName(name);
282  remote_player->SetSerialNumber(serno);
283  remote_player->SetObjID(ship->GetObjID());
284  remote_player->SetShip(ship);
285 
286  HUDView::Message(Game::GetText("NetGameServer::join-announce").data());
287  Print("remote player name = %s\n", name.data());
288  Print(" obj = %d\n", ship->GetObjID());
289  Print(" ship = %s\n", ship->Name());
290 
291  remote_player->SetObjID(ship->GetObjID());
292 
293  // tell the new player about the server:
294  if (local_player) {
295  NetJoinAnnounce join_ann;
296  join_ann.SetShip(local_player);
297  join_ann.SetName(player_name);
298  link->SendMessage(remote_player->GetNetID(), join_ann.Pack(), NetJoinAnnounce::SIZE, NetMsg::RELIABLE);
299  }
300 
301  // tell the new player about the existing remote players:
303  while (++iter) {
304  Ship* s = iter->GetShip();
305 
306  if (s) {
307  NetJoinAnnounce join_ann;
308  join_ann.SetShip(s);
309  join_ann.SetName(iter->Name());
310  join_ann.SetObjID(iter->GetObjID());
311  link->SendMessage(remote_player->GetNetID(), join_ann.Pack(), NetJoinAnnounce::SIZE, NetMsg::RELIABLE);
312  }
313  }
314 
315  // tell the new player about the A.I. controlled ships:
316  ListIter<Ship> ai_iter = ships;
317  while (++ai_iter) {
318  Ship* s = ai_iter.value();
319  if (s != local_player) {
320  NetJoinAnnounce join_ann;
321  join_ann.SetShip(s);
322  join_ann.SetName("Server A.I. Ship");
323  link->SendMessage(remote_player->GetNetID(), join_ann.Pack(), NetJoinAnnounce::SIZE, NetMsg::RELIABLE);
324  }
325  }
326 
327  // make the new player an "existing" remote player:
328  players.append(remote_player);
329 
330  // tell existing players about the new player:
331  // NOTE, this also provides the net id to the new player!
332  iter.reset();
333  while (++iter) {
334  Ship* s = remote_player->GetShip();
335 
336  NetJoinAnnounce join_ann;
337  join_ann.SetShip(s);
338  join_ann.SetName(remote_player->Name());
339  join_ann.SetObjID(remote_player->GetObjID());
341  }
342 
343  if (unpause) {
345  if (s)
346  s->Pause(false);
347  }
348  }
349  }
350 }
351 
352 void
354 {
355  if (!msg) return;
356 
357  NetJoinAnnounce join_ann;
358  if (join_ann.Unpack(msg->Data())) {
359  Print("Server received Join Announce from '%s'\n", join_ann.GetName());
360  }
361 }
362 
363 void
365 {
366  if (!msg) return;
367 
368  NetPlayer* player = FindPlayerByNetID(msg->NetID());
369 
370  if (player) {
371  NetPlayer* zombie = players.remove(player);
372  HUDView::Message(Game::GetText("NetGameServer.remote-quit").data(), zombie->Name());
373 
374  // tell everyone else:
375  NetQuitAnnounce quit_ann;
376  quit_ann.SetObjID(zombie->GetObjID());
377  SendData(&quit_ann);
378 
379  // return remote ship to ship pool:
380  Ship* s = zombie->GetShip();
381  if (s) {
382  Observe(s);
383  ships.append(s);
384  s->SetNetworkControl(0);
385  zombie->SetShip(0);
386 
387  NetJoinAnnounce join_ann;
388  join_ann.SetShip(s);
389  join_ann.SetName("Server A.I. Ship");
390  SendData(&join_ann);
391  }
392 
393  zombies.append(zombie);
394  }
395  else {
396  Print("Quit Request from unknown player NetID: %08X\n", msg->NetID());
397  }
398 }
399 
400 void
402 {
403  if (!msg) return;
404  Print("Server received Quit Announce from NetID: %08x\n", msg->NetID());
405 }
406 
407 void
409 {
410  if (!msg) return;
411  Print("Server received Game Over from NetID: %08x\n", msg->NetID());
412 }
413 
414 void
416 {
417  if (!msg) return;
418  Print("Server received Disconnect from NetID: %08x\n", msg->NetID());
419 }
420 
421 void
423 {
424  if (!msg) return;
425 
426  NetObjLoc obj_loc;
427  obj_loc.Unpack(msg->Data());
428 
429  NetPlayer* player = FindPlayerByObjID(obj_loc.GetObjID());
430  if (player && player->GetShip()) {
431  player->DoObjLoc(&obj_loc);
432  }
433 
434  else {
435  player = FindZombieByObjID(obj_loc.GetObjID());
436 
437  if (player)
438  SendDisconnect(player);
439  }
440 }
441 
442 void
444 {
445  if (!msg) return;
446  Print("Server received OBJ DAMAGE from NetID: %08x (ignored)\n", msg->NetID());
447 }
448 
449 void
451 {
452  if (!msg) return;
453 
454  NetObjKill obj_kill;
455  obj_kill.Unpack(msg->Data());
456 
457  if (obj_kill.GetKillType() != NetObjKill::KILL_DOCK) {
458  Print("Server received OBJ KILL from NetID: %08x (ignored)\n", msg->NetID());
459  return;
460  }
461 
462  Ship* ship = FindShipByObjID(obj_kill.GetObjID());
463  if (ship) {
464  Ship* killer = FindShipByObjID(obj_kill.GetKillerID());
465  Text killer_name = Game::GetText("NetGameServer.unknown");
466 
467  if (killer)
468  killer_name = killer->Name();
469 
470  ShipStats* killee = ShipStats::Find(ship->Name());
471  if (killee)
472  killee->AddEvent(SimEvent::DOCK, killer_name);
473 
474  FlightDeck* deck = killer->GetFlightDeck(obj_kill.GetFlightDeck());
475  sim->NetDockShip(ship, killer, deck);
476  }
477 }
478 
479 void
481 {
482  if (!msg) return;
483  Print("Server received OBJ SPAWN from NetID: %08x (ignored)\n", msg->NetID());
484 }
485 
486 void
488 {
489  if (!msg) return;
490  Print("Server received OBJ HYPER from NetID: %d\n", msg->NetID());
491 
492  NetObjHyper obj_hyper;
493  obj_hyper.Unpack(msg->Data());
494 
495  NetPlayer* player = FindPlayerByObjID(obj_hyper.GetObjID());
496  if (player && player->GetShip()) {
497  if (player->DoObjHyper(&obj_hyper)) {
498  SendData(&obj_hyper);
499  }
500  }
501  else {
502  player = FindZombieByObjID(obj_hyper.GetObjID());
503 
504  if (player)
505  SendDisconnect(player);
506  }
507 }
508 
509 void
511 {
512  if (!msg) return;
513 
514  NetObjTarget obj_target;
515  obj_target.Unpack(msg->Data());
516 
517  NetPlayer* player = FindPlayerByObjID(obj_target.GetObjID());
518  if (player) {
519  player->DoObjTarget(&obj_target);
520  }
521  else {
522  player = FindZombieByObjID(obj_target.GetObjID());
523 
524  if (player)
525  SendDisconnect(player);
526  }
527 }
528 
529 void
531 {
532  if (!msg) return;
533 
534  NetObjEmcon obj_emcon;
535  obj_emcon.Unpack(msg->Data());
536 
537  NetPlayer* player = FindPlayerByObjID(obj_emcon.GetObjID());
538  if (player) {
539  player->DoObjEmcon(&obj_emcon);
540  }
541  else {
542  player = FindZombieByObjID(obj_emcon.GetObjID());
543 
544  if (player)
545  SendDisconnect(player);
546  }
547 }
548 
549 // +--------------------------------------------------------------------+
550 
551 void
553 {
554  if (!msg) return;
555 
556  NetSysDamage sys_damage;
557  sys_damage.Unpack(msg->Data());
558 
559  NetPlayer* player = FindZombieByObjID(sys_damage.GetObjID());
560 
561  if (player)
562  SendDisconnect(player);
563 }
564 
565 void
567 {
568  if (!msg) return;
569 
570  NetSysStatus sys_status;
571  sys_status.Unpack(msg->Data());
572 
573  Ship* ship = FindShipByObjID(sys_status.GetObjID());
574  NetPlayer* player = FindPlayerByNetID(msg->NetID());
575 
576  if (ship) {
577  if (!player || ship->GetObjID() != player->GetObjID()) {
583  return;
584  }
585 
586  player->DoSysStatus(&sys_status);
587 
588  // rebroadcast:
589  System* sys = ship->GetSystem(sys_status.GetSystem());
590  NetUtil::SendSysStatus(ship, sys);
591  }
592 
593  else {
594  player = FindZombieByObjID(sys_status.GetObjID());
595 
596  if (player)
597  SendDisconnect(player);
598  }
599 }
600 
601 // +--------------------------------------------------------------------+
602 
603 void
605 {
606  if (!msg) return;
607 
608  NetElemRequest elem_request;
609  elem_request.Unpack(msg->Data());
610 
611  Sim* sim = Sim::GetSim();
612  Element* elem = sim->FindElement(elem_request.GetName());
613 
614  if (elem) {
615  int squadron = -1;
616  int slots[] = { -1,-1,-1,-1 };
617  Ship* carrier = elem->GetCarrier();
618 
619  if (carrier && carrier->GetHangar()) {
620  Hangar* hangar = carrier->GetHangar();
621 
622  for (int i = 0; i < 4; i++) {
623  hangar->FindSquadronAndSlot(elem->GetShip(i+1), squadron, slots[i]);
624  }
625  }
626 
627  NetUtil::SendElemCreate(elem, squadron, slots, false, true);
628  }
629 }
630 
631 // +--------------------------------------------------------------------+
632 
633 void
635 {
636  if (!msg) return;
637 
638  NetElemCreate elem_create;
639  elem_create.Unpack(msg->Data());
640 
641  Sim* sim = Sim::GetSim();
642  Element* elem = sim->CreateElement(elem_create.GetName(),
643  elem_create.GetIFF(),
644  elem_create.GetType());
645 
646  int* load = elem_create.GetLoadout();
647  int* slots = elem_create.GetSlots();
648  int squadron = elem_create.GetSquadron();
649  int code = elem_create.GetObjCode();
650  Text target = elem_create.GetObjective();
651  bool alert = elem_create.GetAlert();
652 
653  elem->SetIntelLevel(elem_create.GetIntel());
654  elem->SetLoadout(load);
655 
656  if (code > Instruction::RTB || target.length() > 0) {
657  Instruction* obj = new(__FILE__,__LINE__) Instruction(code, target);
658  elem->AddObjective(obj);
659  }
660 
661  Ship* carrier = sim->FindShip(elem_create.GetCarrier());
662  if (carrier) {
663  elem->SetCarrier(carrier);
664 
665  Hangar* hangar = carrier->GetHangar();
666  if (hangar) {
667  Text squadron_name = hangar->SquadronName(squadron);
668  elem->SetSquadron(squadron_name);
669 
670  FlightDeck* deck = 0;
671  int queue = 1000;
672 
673  for (int i = 0; i < carrier->NumFlightDecks(); i++) {
674  FlightDeck* d = carrier->GetFlightDeck(i);
675 
676  if (d && d->IsLaunchDeck()) {
677  int dq = hangar->PreflightQueue(d);
678 
679  if (dq < queue) {
680  queue = dq;
681  deck = d;
682  }
683  }
684  }
685 
686  for (int i = 0; i < 4; i++) {
687  int slot = slots[i];
688  if (slot > -1) {
689  hangar->GotoAlert(squadron, slot, deck, elem, load, !alert);
690  }
691  }
692  }
693  }
694 
696  elem_create.GetSquadron(),
697  elem_create.GetSlots(),
698  elem_create.GetAlert());
699 }
700 
701 void
703 {
704  if (!msg) return;
705 
706  NetShipLaunch ship_launch;
707  ship_launch.Unpack(msg->Data());
708 
709  Sim* sim = Sim::GetSim();
710  int squadron = ship_launch.GetSquadron();
711  int slot = ship_launch.GetSlot();
712 
713  NetPlayer* player = FindPlayerByObjID(ship_launch.GetObjID());
714  if (player) {
715  Ship* carrier = player->GetShip();
716 
717  if (carrier) {
718  Hangar* hangar = carrier->GetHangar();
719 
720  if (hangar) {
721  hangar->Launch(squadron, slot);
722  }
723 
724  NetUtil::SendShipLaunch(carrier, squadron, slot);
725  }
726  }
727 }
728 
729 void
731 {
732  if (!msg) return;
733 
734  NetNavData nav_data;
735  nav_data.Unpack(msg->Data());
736 
737  Element* elem = sim->FindElement(nav_data.GetElem());
738 
739  if (elem) {
740  if (nav_data.IsAdd()) {
741  Instruction* navpt = new(__FILE__,__LINE__) Instruction(*nav_data.GetNavPoint());
742  Instruction* after = 0;
743  int index = nav_data.GetIndex();
744 
745  if (index >= 0 && index < elem->GetFlightPlan().size())
746  after = elem->GetFlightPlan().at(index);
747 
748  elem->AddNavPoint(navpt, after, false);
749  }
750 
751  else {
752  Instruction* navpt = nav_data.GetNavPoint();
753  Instruction* exist = 0;
754  int index = nav_data.GetIndex();
755 
756  if (navpt && index >= 0 && index < elem->GetFlightPlan().size()) {
757  exist = elem->GetFlightPlan().at(index);
758  *exist = *navpt;
759  }
760  }
761 
762  SendData(&nav_data);
763  }
764 }
765 
766 void
768 {
769  if (!msg) return;
770 
771  NetNavDelete nav_delete;
772  nav_delete.Unpack(msg->Data());
773 
774  Element* elem = sim->FindElement(nav_delete.GetElem());
775 
776  if (elem) {
777  int index = nav_delete.GetIndex();
778 
779  if (index < 0) {
780  elem->ClearFlightPlan(false);
781  }
782 
783  else if (index < elem->FlightPlanLength()) {
784  Instruction* npt = elem->GetFlightPlan().at(index);
785  elem->DelNavPoint(npt, false);
786  }
787 
788  SendData(&nav_delete);
789  }
790 }
791 
792 void
794 {
795  if (!msg) return;
796 
797  NetWepTrigger trigger;
798  trigger.Unpack(msg->Data());
799 
800  NetPlayer* player = FindPlayerByObjID(trigger.GetObjID());
801  if (player) {
802  player->DoWepTrigger(&trigger);
803  }
804  else {
805  player = FindZombieByObjID(trigger.GetObjID());
806 
807  if (player)
808  SendDisconnect(player);
809  }
810 }
811 
812 void
814 {
815  if (!msg) return;
816 
817  NetWepRelease release;
818  release.Unpack(msg->Data());
819 
820  NetPlayer* player = FindPlayerByObjID(release.GetObjID());
821  if (player) {
822  player->DoWepRelease(&release);
823  }
824  else {
825  player = FindZombieByObjID(release.GetObjID());
826 
827  if (player)
828  SendDisconnect(player);
829  }
830 
831  Print("WEP RELEASE on server? objid = %d\n", release.GetObjID());
832 }
833 
834 void
836 {
837 }
838 
839 void
841 {
842  if (!msg) return;
843 
844  NetCommMsg comm_msg;
845  comm_msg.Unpack(msg->Data());
846 
847  RadioMessage* radio_msg = comm_msg.GetRadioMessage();
848 
849  NetPlayer* player = FindPlayerByObjID(comm_msg.GetObjID());
850  if (player && radio_msg) {
851  player->DoCommMessage(&comm_msg);
852 
853  int channel = comm_msg.GetRadioMessage()->Channel();
854 
856  while (++dst) {
857  NetPlayer* remote_player = dst.value();
858  if (remote_player->GetNetID() &&
859  (channel == 0 || channel == remote_player->GetIFF())) {
860 
861  BYTE* data = comm_msg.Pack();
862  int size = comm_msg.Length();
863 
864  link->SendMessage(remote_player->GetNetID(), data, size, NetMsg::RELIABLE);
865  }
866  }
867  }
868  else {
869  player = FindZombieByObjID(comm_msg.GetObjID());
870 
871  if (player)
872  SendDisconnect(player);
873  }
874 }
875 
876 void
878 {
879  if (!msg) return;
880 
881  NetChatMsg chat_msg;
882  chat_msg.Unpack(msg->Data());
883 
884  RouteChatMsg(chat_msg);
885 }
886 
887 void
889 {
890  DWORD dst_id = chat_msg.GetDstID();
891 
892  // broadcast or team:
893  if (dst_id == 0xffff || dst_id <= 10) {
894  BYTE* data = chat_msg.Pack();
895  int size = chat_msg.Length();
896 
898  while (++dst) {
899  NetPlayer* remote_player = dst.value();
900  if (remote_player->GetNetID() && chat_msg.GetName() != remote_player->Name()) {
901  if (dst_id == 0xffff || dst_id == 0 || remote_player->GetIFF() == (int) dst_id-1)
902  link->SendMessage(remote_player->GetNetID(), data, size);
903  }
904  }
905 
906  if (local_player && (dst_id == 0xffff || dst_id == 0 || local_player->GetIFF() == (int) dst_id-1)) {
907  Text name = chat_msg.GetName();
908  if (name.length() < 1)
909  name = Game::GetText("NetGameServer.chat.unknown");
910 
911  // don't echo general messages from the local player.
912  // they are already displayed by the chat entry code
913  // in starshatter.cpp
914 
915  if (name != player_name)
916  HUDView::Message("%s> %s", name.data(), chat_msg.GetText().data());
917  }
918  }
919 
920  // direct to local player:
921  else if (local_player && local_player->GetObjID() == dst_id) {
922  Text name = chat_msg.GetName();
923  if (name.length() < 1)
924  name = Game::GetText("NetGameServer.chat.unknown");
925 
926  HUDView::Message("%s> %s", name.data(), chat_msg.GetText().data());
927  }
928 
929  // ship-to-ship, but not to local player:
930  else if (!local_player || local_player->GetObjID() != dst_id) {
931  NetPlayer* remote_player = FindPlayerByObjID(dst_id);
932  if (remote_player && remote_player->GetNetID()) {
933  BYTE* data = chat_msg.Pack();
934  int size = chat_msg.Length();
935  link->SendMessage(remote_player->GetNetID(), data, size);
936  }
937 
938  // record message in server log:
939  ::Print("%s> %s\n", chat_msg.GetName().data(), chat_msg.GetText().data());
940  }
941 
942  if (dst_id == 0xffff)
943  return;
944 
945  // record message in chat log:
947 
948  if (!lobby)
949  return;
950 
951  NetUser* user = lobby->FindUserByName(chat_msg.GetName());
952 
953  if (user)
954  lobby->AddChat(user, chat_msg.GetText(), false); // don't re-route
955 }
956 
957 // +--------------------------------------------------------------------+
958 
959 const char* FormatGameTime();
960 
961 void
963 {
964  if (!msg) return;
965 
966  NetSelfDestruct self_destruct;
967  self_destruct.Unpack(msg->Data());
968 
969  Ship* ship = FindShipByObjID(self_destruct.GetObjID());
970  NetPlayer* player = FindPlayerByNetID(msg->NetID());
971 
972  if (ship) {
973  if (!player || ship->GetObjID() != player->GetObjID()) {
974  Print("NetGameServer::DoSelfDestruct - received request for ship '%s' from wrong player %s\n",
975  ship->Name(), player ? player->Name() : "null");
976 
977  return;
978  }
979 
980  ship->InflictNetDamage(self_destruct.GetDamage());
981 
982  SendData(&self_destruct);
983 
984  int ship_destroyed = (!ship->InTransition() && ship->Integrity() < 1.0f);
985 
986  // then delete the ship:
987  if (ship_destroyed) {
989  Print(" %s Self Destruct (%s)\n", ship->Name(), FormatGameTime());
990 
991  ShipStats* killee = ShipStats::Find(ship->Name());
992  if (killee)
993  killee->AddEvent(SimEvent::DESTROYED, ship->Name());
994 
995  ship->DeathSpiral();
996  }
997  }
998 }
999 
1000 // +--------------------------------------------------------------------+
1001 
1002 void
1004 {
1005  if (players.isEmpty())
1006  return;
1007 
1008  DWORD time = Game::GameTime();
1009 
1010  // don't flood the network...
1011  if (time - last_send_time < MIN_NET_FRAME)
1012  return;
1013 
1014  last_send_time = time;
1015 
1016  // tell the remote players where *we* are:
1017  if (local_player && !local_player->IsNetObserver() && objid) {
1018  double r, p, y;
1020 
1021  NetObjLoc obj_loc;
1022  obj_loc.SetObjID(objid);
1023  obj_loc.SetLocation(local_player->Location());
1024  obj_loc.SetVelocity(local_player->Velocity());
1025  obj_loc.SetOrientation(Point(r,p,y));
1026  obj_loc.SetThrottle(local_player->Throttle() > 10);
1027  obj_loc.SetAugmenter(local_player->Augmenter());
1028  obj_loc.SetGearDown(local_player->IsGearDown());
1029 
1030  Shield* shield = local_player->GetShield();
1031  if (shield)
1032  obj_loc.SetShield((int) shield->GetPowerLevel());
1033  else
1034  obj_loc.SetShield(0);
1035 
1036  SendData(&obj_loc);
1037  }
1038 
1039  // tell each remote player where all the others are:
1041  while (++src) {
1042  NetPlayer* player = src.value();
1043 
1044  Ship* player_ship = player->GetShip();
1045 
1046  if (player_ship) {
1047  double r, p, y;
1048  player_ship->Cam().Orientation().ComputeEulerAngles(r,p,y);
1049 
1050  NetObjLoc obj_loc;
1051  obj_loc.SetObjID(player->GetObjID());
1052  obj_loc.SetLocation(player_ship->Location());
1053  obj_loc.SetVelocity(player_ship->Velocity());
1054  obj_loc.SetOrientation(Point(r,p,y));
1055  obj_loc.SetThrottle(player_ship->Throttle() > 10);
1056  obj_loc.SetAugmenter(player_ship->Augmenter());
1057  obj_loc.SetGearDown(player_ship->IsGearDown());
1058 
1059  Shield* shield = player_ship->GetShield();
1060  if (shield)
1061  obj_loc.SetShield((int) shield->GetPowerLevel());
1062  else
1063  obj_loc.SetShield(0);
1064 
1065  BYTE* obj_loc_data = obj_loc.Pack();
1066 
1068  while (++dst) {
1069  NetPlayer* remote_player = dst.value();
1070  if (remote_player->GetNetID() && remote_player != player)
1071  link->SendMessage(remote_player->GetNetID(), obj_loc_data, NetObjLoc::SIZE);
1072  }
1073  }
1074  }
1075 
1076  // tell each remote player where all the A.I. ships are:
1077  ListIter<Ship> ai_iter = ships;
1078  while (++ai_iter) {
1079  Ship* s = ai_iter.value();
1080 
1081  if (s && !s->IsStatic()) {
1082  double r, p, y;
1083  s->Cam().Orientation().ComputeEulerAngles(r,p,y);
1084 
1085  NetObjLoc obj_loc;
1086  obj_loc.SetObjID(s->GetObjID());
1087  obj_loc.SetLocation(s->Location());
1088  obj_loc.SetVelocity(s->Velocity());
1089  obj_loc.SetOrientation(Point(r,p,y));
1090  obj_loc.SetThrottle(s->Throttle() > 10);
1091  obj_loc.SetAugmenter(s->Augmenter());
1092  obj_loc.SetGearDown(s->IsGearDown());
1093 
1094  Shield* shield = s->GetShield();
1095  if (shield)
1096  obj_loc.SetShield((int) shield->GetPowerLevel());
1097  else
1098  obj_loc.SetShield(0);
1099 
1100  SendData(&obj_loc);
1101  }
1102  }
1103 }
1104 
1105 // +--------------------------------------------------------------------+
1106 
1107 void
1109 {
1110  if (net_data) {
1111  BYTE* data = net_data->Pack();
1112  int size = net_data->Length();
1113  BYTE flags = 0;
1114  bool all = true; // include player with objid in net_data?
1115  DWORD oid = net_data->GetObjID();
1116 
1117  BYTE msg_type = net_data->Type();
1118 
1119  if (msg_type >= 0x10)
1120  flags |= NetMsg::RELIABLE;
1121 
1122  if (msg_type == NET_WEP_TRIGGER ||
1123  msg_type == NET_COMM_MESSAGE ||
1124  msg_type == NET_CHAT_MESSAGE ||
1125  msg_type == NET_OBJ_HYPER ||
1126  msg_type == NET_ELEM_CREATE ||
1127  msg_type == NET_NAV_DATA ||
1128  msg_type == NET_NAV_DELETE) {
1129  all = false;
1130  }
1131 
1133  while (++dst) {
1134  NetPlayer* remote_player = dst.value();
1135  if (remote_player->GetNetID() && (all || oid != remote_player->GetObjID()))
1136  link->SendMessage(remote_player->GetNetID(), data, size, flags);
1137  }
1138  }
1139 }
1140 
1141 void
1143 {
1144  if (zombie) {
1145  NetDisconnect disconnect;
1146  BYTE* data = disconnect.Pack();
1147  int size = disconnect.Length();
1148  BYTE flags = NetMsg::RELIABLE;
1149 
1150  if (zombie->GetNetID())
1151  link->SendMessage(zombie->GetNetID(), data, size, flags);
1152  }
1153 }
1154 
1155 // +--------------------------------------------------------------------+
1156 
1157 bool
1159 {
1160  if (obj->Type() == SimObject::SIM_SHIP) {
1161  Ship* s = (Ship*) obj;
1162  if (local_player == s)
1163  local_player = 0;
1164 
1165  if (ships.contains(s))
1166  ships.remove(s);
1167  }
1168 
1169  return SimObserver::Update(obj);
1170 }
1171 
1172 const char*
1174 {
1175  return "NetGameServer";
1176 }
1177 
1178 // +--------------------------------------------------------------------+
1179 
1180 void
1181 NetGameServer::Respawn(DWORD oid, Ship* spawn)
1182 {
1183  if (!oid || !spawn) return;
1184 
1185  Print("NetGameServer::Respawn(%d, %s)\n", oid, spawn->Name());
1186  spawn->SetObjID(oid);
1187  Observe(spawn);
1188 
1189  NetPlayer* p = FindPlayerByObjID(oid);
1190  if (p)
1191  p->SetShip(spawn);
1192  else
1193  ships.append(spawn);
1194 
1195  if (objid == oid) {
1196  Print(" RESPAWN LOCAL PLAYER\n\n");
1197  local_player = spawn;
1198  }
1199 }