00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00209
00210
00211
00212
00213 #include "stratagus.h"
00214
00215 #include <stdio.h>
00216 #include <stdlib.h>
00217 #include <stddef.h>
00218 #include <string.h>
00219 #include <list>
00220
00221 #include "net_lowlevel.h"
00222 #include "unit.h"
00223 #include "unit_manager.h"
00224 #include "unittype.h"
00225 #include "map.h"
00226 #include "actions.h"
00227 #include "player.h"
00228 #include "network.h"
00229 #include "netconnect.h"
00230 #include "commands.h"
00231 #include "replay.h"
00232 #include "interface.h"
00233 #include "results.h"
00234 #include "sound.h"
00235
00236
00237
00238
00239
00240
00244 class CNetworkCommandQueue {
00245 public:
00246 CNetworkCommandQueue() : Time(0), Type(0) {}
00247 void Clear() { this->Time = this->Type = 0; Data.Clear(); }
00248
00249 unsigned long Time;
00250 unsigned char Type;
00251 CNetworkCommand Data;
00252 };
00253
00254
00255
00256
00257
00258 int NetworkNumInterfaces;
00259 Socket NetworkFildes = (Socket)-1;
00260 int NetworkInSync = 1;
00261 int NetworkUpdates = 5;
00262 int NetworkLag = 10;
00263 unsigned long NetworkStatus[PlayerMax];
00264 unsigned long NetworkLastFrame[PlayerMax];
00265 int NetworkTimeout = 45;
00266
00267 static char NetMsgBuf[PlayerMax][128];
00268 static int NetMsgBufLen[PlayerMax];
00269 #ifdef DEBUG
00270 unsigned long MyHost;
00271 int MyPort;
00272 #endif
00273 static unsigned long NetworkDelay;
00274 static int NetworkSyncSeeds[256];
00275 static int NetworkSyncHashs[256];
00276 static CNetworkCommandQueue NetworkIn[256][PlayerMax][MaxNetworkCommands];
00277 std::list<CNetworkCommandQueue *> CommandsIn;
00278 std::list<CNetworkCommandQueue *> MsgCommandsIn;
00279
00280 #ifdef DEBUG
00281 static int NetworkReceivedPackets;
00282 static int NetworkReceivedEarly;
00283 static int NetworkReceivedLate;
00284 static int NetworkReceivedDups;
00285 static int NetworkReceivedLost;
00286
00287 static int NetworkSendPackets;
00288 static int NetworkSendResend;
00289 #endif
00290
00291 static int PlayerQuit[PlayerMax];
00292
00293 #define MAX_NCQS 100
00294 static CNetworkCommandQueue NCQs[MAX_NCQS];
00295 static int NumNCQs;
00296
00297
00298
00299
00300
00301
00302 void CNetworkCommand::Serialize(unsigned char *p) const
00303 {
00304 *(Uint16 *)p = this->Unit;
00305 p += 2;
00306 *(Uint16 *)p = this->X;
00307 p += 2;
00308 *(Uint16 *)p = this->Y;
00309 p += 2;
00310 *(Uint16 *)p = this->Dest;
00311 p += 2;
00312 }
00313
00314 void CNetworkCommand::Deserialize(unsigned char *p)
00315 {
00316 this->Unit = *(Uint16 *)p;
00317 p += 2;
00318 this->X = *(Uint16 *)p;
00319 p += 2;
00320 this->Y = *(Uint16 *)p;
00321 p += 2;
00322 this->Dest = *(Uint16 *)p;
00323 p += 2;
00324 }
00325
00326 void CNetworkExtendedCommand::Serialize(unsigned char *p)
00327 {
00328 *p++ = this->ExtendedType;
00329 *p++ = this->Arg1;
00330 *(Uint16 *)p = this->Arg2;
00331 p += 2;
00332 *(Uint16 *)p = this->Arg3;
00333 p += 2;
00334 *(Uint16 *)p = this->Arg4;
00335 p += 2;
00336 }
00337
00338 void CNetworkExtendedCommand::Deserialize(unsigned char *p)
00339 {
00340 this->ExtendedType = *p++;
00341 this->Arg1 = *p++;
00342 this->Arg2 = *(Uint16 *)p;
00343 p += 2;
00344 this->Arg3 = *(Uint16 *)p;
00345 p += 2;
00346 this->Arg4 = *(Uint16 *)p;
00347 p += 2;
00348 }
00349
00350 void CNetworkChat::Serialize(unsigned char *p)
00351 {
00352 *p++ = this->Player;
00353 memcpy(p, this->Text, 7);
00354 p += 7;
00355 }
00356
00357 void CNetworkChat::Deserialize(unsigned char *p)
00358 {
00359 this->Player = *p++;
00360 memcpy(this->Text, p, 7);
00361 p += 7;
00362 }
00363
00364 void CNetworkPacketHeader::Serialize(unsigned char *p) const
00365 {
00366 *p++ = this->Cycle;
00367 for (int i = 0; i < MaxNetworkCommands; ++i) {
00368 *p++ = this->Type[i];
00369 }
00370 }
00371
00372 void CNetworkPacketHeader::Deserialize(unsigned char *p)
00373 {
00374 this->Cycle = *p++;
00375 for (int i = 0; i < MaxNetworkCommands; ++i) {
00376 this->Type[i] = *p++;
00377 }
00378 }
00379
00380 unsigned char *CNetworkPacket::Serialize(int numcommands) const
00381 {
00382 unsigned char *buf = new unsigned char[CNetworkPacket::Size(numcommands)];
00383 unsigned char *p = buf;
00384
00385 this->Header.Serialize(p);
00386 p += CNetworkPacketHeader::Size();
00387
00388 for (int i = 0; i < numcommands; ++i) {
00389 if (this->Header.Type[i] == MessageExtendedCommand) {
00390 ((CNetworkExtendedCommand *)&this->Command[i])->Serialize(p);
00391 } else if (this->Header.Type[i] == MessageChat) {
00392 ((CNetworkChat *)&this->Command[i])->Serialize(p);
00393 } else {
00394 this->Command[i].Serialize(p);
00395 }
00396 p += CNetworkCommand::Size();
00397 }
00398
00399 return buf;
00400 }
00401
00402 int CNetworkPacket::Deserialize(unsigned char *p, unsigned int len)
00403 {
00404
00405 if (len < CNetworkPacket::Size(1) ||
00406 len > CNetworkPacket::Size(MaxNetworkCommands)) {
00407 return -1;
00408 }
00409
00410
00411 len -= CNetworkPacketHeader::Size();
00412 if ((len / CNetworkCommand::Size()) * CNetworkCommand::Size() != len) {
00413 return -1;
00414 }
00415
00416 this->Header.Deserialize(p);
00417 p += CNetworkPacketHeader::Size();
00418
00419 int commands = len / CNetworkCommand::Size();
00420
00421 for (int i = 0; i < commands; ++i) {
00422 if (this->Header.Type[i] == MessageExtendedCommand) {
00423 ((CNetworkExtendedCommand *)&this->Command[i])->Deserialize(p);
00424 } else if (this->Header.Type[i] == MessageChat) {
00425 ((CNetworkChat *)&this->Command[i])->Deserialize(p);
00426 } else {
00427 this->Command[i].Deserialize(p);
00428 }
00429 p += CNetworkCommand::Size();
00430 }
00431
00432 return commands;
00433 }
00434
00435
00436
00437
00438
00445 static void NetworkBroadcast(const CNetworkPacket *packet, int numcommands)
00446 {
00447 unsigned char *buf = packet->Serialize(numcommands);
00448
00449
00450 for (int i = 0; i < HostsCount; ++i) {
00451 NetSendUDP(NetworkFildes, Hosts[i].Host, Hosts[i].Port, buf,
00452 CNetworkPacket::Size(numcommands));
00453 }
00454
00455 delete[] buf;
00456 }
00457
00463 static void NetworkSendPacket(const CNetworkCommandQueue *ncq)
00464 {
00465 CNetworkPacket packet;
00466 int i;
00467 int numcommands;
00468
00469 #ifdef DEBUG
00470 ++NetworkSendPackets;
00471 #endif
00472
00473
00474
00475
00476 numcommands = 0;
00477 packet.Header.Cycle = ncq[0].Time & 0xFF;
00478 for (i = 0; i < MaxNetworkCommands && ncq[i].Type != MessageNone; ++i) {
00479 packet.Header.Type[i] = ncq[i].Type;
00480 packet.Command[i] = ncq[i].Data;
00481 ++numcommands;
00482 }
00483
00484 for (; i < MaxNetworkCommands; ++i) {
00485 packet.Header.Type[i] = MessageNone;
00486 }
00487
00488 NetworkBroadcast(&packet, numcommands);
00489 }
00490
00491
00492
00493
00494
00498 void InitNetwork1(void)
00499 {
00500 int i;
00501 int port;
00502
00503 NetworkFildes = (Socket)-1;
00504 NetworkInSync = 1;
00505 NetworkNumInterfaces = 0;
00506
00507 NetInit();
00508
00509 for (i = 0; i < PlayerMax; ++i) {
00510 NetMsgBufLen[i] = 0;
00511 }
00512
00513 if (NetworkUpdates <= 0) {
00514 NetworkUpdates = 1;
00515 }
00516
00517 NetworkLag = (NetworkLag / NetworkUpdates) * NetworkUpdates;
00518
00519
00520 port = NetworkPort;
00521 for (i = 0; i < 10; ++i) {
00522 NetworkFildes = NetOpenUDP(port + i);
00523 if (NetworkFildes != (Socket)-1) {
00524 break;
00525 }
00526 }
00527 if (i == 10) {
00528 fprintf(stderr, "NETWORK: No free ports %d-%d available, aborting\n",
00529 port, port + i);
00530 NetExit();
00531 return;
00532 }
00533
00534 #if 1
00535
00536 NetworkNumInterfaces = 1;
00537 #else
00538 NetworkNumInterfaces = NetSocketAddr(NetworkFildes);
00539 if (NetworkNumInterfaces) {
00540 DebugPrint("Num IP: %d\n" _C_ NetworkNumInterfaces);
00541 for (i = 0; i < NetworkNumInterfaces; ++i) {
00542 DebugPrint("IP: %d.%d.%d.%d\n" _C_ NIPQUAD(ntohl(NetLocalAddrs[i])));
00543 }
00544 } else {
00545 fprintf(stderr, "NETWORK: Not connected to any external IPV4-network, aborting\n");
00546 ExitNetwork1();
00547 return;
00548 }
00549 #endif
00550
00551 #ifdef DEBUG
00552 {
00553 char buf[128];
00554
00555 gethostname(buf, sizeof(buf));
00556 DebugPrint("%s\n" _C_ buf);
00557 MyHost = NetResolveHost(buf);
00558 MyPort = NetLastPort;
00559 DebugPrint("My host:port %d.%d.%d.%d:%d\n" _C_
00560 NIPQUAD(ntohl(MyHost)) _C_ ntohs(MyPort));
00561 }
00562 #endif
00563
00564 CommandsIn.clear();
00565 MsgCommandsIn.clear();
00566
00567 NumNCQs = 0;
00568 }
00569
00573 void ExitNetwork1(void)
00574 {
00575 if (!IsNetworkGame()) {
00576 return;
00577 }
00578
00579 #ifdef DEBUG
00580 DebugPrint("Received: %d packets, %d early, %d late, %d dups, %d lost.\n" _C_
00581 NetworkReceivedPackets _C_ NetworkReceivedEarly _C_ NetworkReceivedLate _C_
00582 NetworkReceivedDups _C_ NetworkReceivedLost);
00583 DebugPrint("Send: %d packets, %d resend\n" _C_
00584 NetworkSendPackets _C_ NetworkSendResend);
00585 #endif
00586
00587 NetCloseUDP(NetworkFildes);
00588 NetExit();
00589
00590 NetworkFildes = (Socket)-1;
00591 NetworkInSync = 1;
00592 NetPlayers = 0;
00593 HostsCount = 0;
00594 }
00595
00599 void InitNetwork2(void)
00600 {
00601 NetworkConnectSetupGame();
00602
00603 DebugPrint("Lag %d, Updates %d, Hosts %d\n" _C_
00604 NetworkLag _C_ NetworkUpdates _C_ HostsCount);
00605
00606
00607
00608
00609 memset(NetworkIn, 0, sizeof(NetworkIn));
00610 for (int i = 0; i <= NetworkLag; i += NetworkUpdates) {
00611 for (int n = 0; n < HostsCount; ++n) {
00612 for (int c = 0; c < MaxNetworkCommands; ++c) {
00613 NetworkIn[i][Hosts[n].PlyNr][c].Time = i;
00614 NetworkIn[i][Hosts[n].PlyNr][c].Type = MessageSync;
00615 }
00616 }
00617 }
00618
00619 memset(NetworkSyncSeeds, 0, sizeof(NetworkSyncSeeds));
00620 memset(NetworkSyncHashs, 0, sizeof(NetworkSyncHashs));
00621 memset(PlayerQuit, 0, sizeof(PlayerQuit));
00622 memset(NetworkStatus, 0, sizeof(NetworkStatus));
00623 memset(NetworkLastFrame, 0, sizeof(NetworkLastFrame));
00624 }
00625
00626
00627
00628
00629
00635 static CNetworkCommandQueue *AllocNCQ(void)
00636 {
00637 Assert(NumNCQs != MAX_NCQS);
00638 CNetworkCommandQueue *ncq = &NCQs[NumNCQs++];
00639 ncq->Clear();
00640 return ncq;
00641 }
00642
00648 static void FreeNCQ(CNetworkCommandQueue *ncq)
00649 {
00650 NCQs[ncq - NCQs] = NCQs[--NumNCQs];
00651 }
00652
00653
00654
00655
00656
00672 void NetworkSendCommand(int command, const CUnit *unit, int x, int y,
00673 const CUnit *dest, const CUnitType *type, int status)
00674 {
00675 CNetworkCommandQueue *ncq;
00676 std::list<CNetworkCommandQueue *>::iterator it;
00677
00678
00679 for (it = CommandsIn.begin(); it != CommandsIn.end(); ++it) {
00680 ncq = *it;
00681 if ((ncq->Type & 0x7F) == command &&
00682 ncq->Data.Unit == htons(unit->Slot) &&
00683 ncq->Data.X == htons(x) &&
00684 ncq->Data.Y == htons(y)) {
00685 if (dest && ncq->Data.Dest == htons(dest->Slot)) {
00686 return;
00687 } else if (type && ncq->Data.Dest == htons(type->Slot)) {
00688 return;
00689 } else if (ncq->Data.Dest == 0xFFFF) {
00690 return;
00691 }
00692 }
00693 }
00694
00695 ncq = AllocNCQ();
00696 CommandsIn.push_back(ncq);
00697
00698 ncq->Time = GameCycle;
00699 ncq->Type = command;
00700 if (status) {
00701 ncq->Type |= 0x80;
00702 }
00703 ncq->Data.Unit = htons(unit->Slot);
00704 ncq->Data.X = htons(x);
00705 ncq->Data.Y = htons(y);
00706 Assert (!dest || !type);
00707 if (dest) {
00708 ncq->Data.Dest = htons(dest->Slot);
00709 } else if (type) {
00710 ncq->Data.Dest = htons(type->Slot);
00711 } else {
00712 ncq->Data.Dest = htons(0xFFFF);
00713 }
00714
00715 }
00716
00729 void NetworkSendExtendedCommand(int command, int arg1, int arg2, int arg3,
00730 int arg4, int status)
00731 {
00732 CNetworkCommandQueue *ncq;
00733 CNetworkExtendedCommand *nec;
00734
00735 ncq = AllocNCQ();
00736 CommandsIn.push_back(ncq);
00737
00738 ncq->Time = GameCycle;
00739 nec = (CNetworkExtendedCommand *)&ncq->Data;
00740
00741 ncq->Type = MessageExtendedCommand;
00742 if (status) {
00743 ncq->Type |= 0x80;
00744 }
00745 nec->ExtendedType = command;
00746 nec->Arg1 = arg1;
00747 nec->Arg2 = htons(arg2);
00748 nec->Arg3 = htons(arg3);
00749 nec->Arg4 = htons(arg4);
00750 }
00751
00758 void NetworkSendSelection(CUnit **units, int count)
00759 {
00760 CNetworkPacket packet;
00761 NetworkSelectionHeader *header;
00762 CNetworkSelection *selection;
00763 int unitcount;
00764 int ref;
00765 int i;
00766 int teammates[PlayerMax];
00767 int numteammates;
00768 int nosent;
00769
00770
00771 numteammates = 0;
00772 for (i = 0; i < HostsCount; ++i) {
00773 if (Players[Hosts[i].PlyNr].Team == ThisPlayer->Team) {
00774 teammates[numteammates++] = i;
00775 }
00776 }
00777 if (!numteammates) {
00778 return;
00779 }
00780
00781
00782
00783
00784 unitcount = 0;
00785 while (unitcount < count) {
00786 header = (NetworkSelectionHeader *)&(packet.Header);
00787 if (unitcount == 0) {
00788 header->Add = 0;
00789 } else {
00790 header->Add = 1;
00791 }
00792 header->Remove = 0;
00793
00794 nosent = 0;
00795 for (i = 0; i < MaxNetworkCommands && unitcount < count; ++i) {
00796 header->Type[i] = MessageSelection;
00797 selection = (CNetworkSelection *)&packet.Command[i];
00798 for (ref = 0; ref < 4 && unitcount < count; ++ref, ++unitcount) {
00799 selection->Unit[ref] = htons(UnitNumber(units[unitcount]));
00800 ++nosent;
00801 }
00802 }
00803
00804 if (unitcount >= count) {
00805
00806 header->NumberSent = nosent;
00807 } else {
00808 header->NumberSent = MaxNetworkCommands * 4;
00809 }
00810
00811 for (; i < MaxNetworkCommands; ++i) {
00812 packet.Header.Type[i] = MessageNone;
00813 }
00814
00815
00816
00817
00818
00819 int numcommands = (nosent + 3) / 4;
00820 unsigned char *buf = packet.Serialize(numcommands);
00821
00822 for (i = 0; i < numteammates; ++i) {
00823 ref = NetSendUDP(NetworkFildes, Hosts[teammates[i]].Host, Hosts[teammates[i]].Port,
00824 buf, CNetworkPacketHeader::Size() + CNetworkSelection::Size() * numcommands);
00825 }
00826 }
00827
00828 }
00835 static void NetworkProcessSelection(CNetworkPacket *packet, int player)
00836 {
00837 CUnit *units[UnitMax];
00838 NetworkSelectionHeader *header;
00839 CNetworkSelection *selection;
00840 int adjust;
00841 int count;
00842 int unitcount;
00843
00844 header = (NetworkSelectionHeader *)&(packet->Header);
00845
00846
00847
00848 count = header->NumberSent;
00849 adjust = (header->Add << 1) | header->Remove;
00850 unitcount = 0;
00851
00852 for (int i = 0; header->Type[i] == MessageSelection; ++i) {
00853 selection = (CNetworkSelection *)&(packet->Command[i]);
00854 for (int j = 0; j < 4 && unitcount < count; ++j) {
00855 units[unitcount++] = Units[ntohs(selection->Unit[j])];
00856 }
00857 }
00858 Assert(count == unitcount);
00859
00860 ChangeTeamSelectedUnits(&Players[player], units, adjust, count);
00861 }
00862
00868 static void NetworkRemovePlayer(int player)
00869 {
00870 int i;
00871
00872
00873 for (i = 0; i < HostsCount; ++i) {
00874 if (Hosts[i].PlyNr == player) {
00875 Hosts[i] = Hosts[HostsCount - 1];
00876 --HostsCount;
00877 break;
00878 }
00879 }
00880 for (i = 0; i < 256; ++i) {
00881 for (int c = 0; c < MaxNetworkCommands; ++c) {
00882 NetworkIn[i][player][c].Time = 0;
00883 }
00884 }
00885 }
00886
00895 void NetworkEvent(void)
00896 {
00897 unsigned char buf[1024];
00898 CNetworkPacket packet;
00899 int player;
00900 int i;
00901 int commands;
00902 unsigned long n;
00903
00904 if (!IsNetworkGame()) {
00905 NetworkInSync = 1;
00906 return;
00907 }
00908
00909
00910
00911 if ((i = NetRecvUDP(NetworkFildes, &buf, sizeof(buf))) < 0) {
00912
00913
00914
00915 DebugPrint("Server/Client gone?\n");
00916
00917 NetworkInSync = 0;
00918 return;
00919 }
00920
00921 #ifdef DEBUG
00922 ++NetworkReceivedPackets;
00923 #endif
00924
00925
00926
00927
00928 if (NetConnectRunning) {
00929 if (NetworkParseSetupEvent(buf, i)) {
00930 return;
00931 }
00932 }
00933
00934 commands = packet.Deserialize(buf, i);
00935 if (commands < 0) {
00936 DebugPrint("Bad packet read\n");
00937 return;
00938 }
00939
00940 for (i = 0; i < HostsCount; ++i) {
00941 if (Hosts[i].Host == NetLastHost && Hosts[i].Port == NetLastPort &&
00942 !PlayerQuit[Hosts[i].PlyNr]) {
00943 break;
00944 }
00945 }
00946 if (i == HostsCount) {
00947 DebugPrint("Not a host in play: %d.%d.%d.%d:%d\n" _C_
00948 NIPQUAD(ntohl(NetLastHost)) _C_ ntohs(NetLastPort));
00949 return;
00950 }
00951 player = Hosts[i].PlyNr;
00952
00953
00954 if (packet.Header.Type[0] == MessageSelection || commands == 0) {
00955 NetworkProcessSelection(&packet, player);
00956 return;
00957 }
00958
00959
00960
00961
00962 for (i = 0; i < commands; ++i) {
00963 const CNetworkCommand *nc = &packet.Command[i];
00964 bool validCommand = false;
00965
00966
00967
00968
00969 if (packet.Header.Type[i] == MessageQuit) {
00970 int player = ntohs(nc->X);
00971
00972 if (player >= 0 && player < NumPlayers) {
00973 PlayerQuit[player] = 1;
00974 validCommand = true;
00975 }
00976 }
00977
00978 if (packet.Header.Type[i] == MessageResend) {
00979
00980 n = ((GameCycle + 128) & ~0xFF) | packet.Header.Cycle;
00981 if (n > GameCycle + 128) {
00982 n -= 0x100;
00983 }
00984
00985
00986
00987
00988 if (n != NetworkIn[n & 0xFF][ThisPlayer->Index][0].Time) {
00989
00990 return;
00991 }
00992
00993 NetworkSendPacket(NetworkIn[n & 0xFF][ThisPlayer->Index]);
00994
00995
00996 for (int j = 0; j < HostsCount; ++j) {
00997 for (int c = 0; c < MaxNetworkCommands; ++c) {
00998 CNetworkCommandQueue *ncq;
00999 ncq = &NetworkIn[n & 0xFF][Hosts[j].PlyNr][c];
01000 if (ncq->Time && ncq->Type == MessageQuit) {
01001 CNetworkPacket np;
01002 np.Header.Cycle = ncq->Time & 0xFF;
01003 np.Header.Type[0] = ncq->Type;
01004 np.Command[0] = ncq->Data;
01005 for (int k = 1; k < MaxNetworkCommands; ++k) {
01006 np.Header.Type[k] = MessageNone;
01007 }
01008
01009 NetworkBroadcast(&np, 1);
01010 }
01011 }
01012 }
01013
01014 return;
01015 }
01016
01017
01018 n = ((GameCycle + 128) & ~0xFF) | packet.Header.Cycle;
01019 if (n > GameCycle + 128) {
01020 n -= 0x100;
01021 }
01022
01023
01024 if (n > NetworkStatus[player]) {
01025 NetworkStatus[player] = n;
01026 }
01027 NetworkLastFrame[player] = FrameCounter;
01028
01029
01030 switch (packet.Header.Type[i] & 0x7F) {
01031 case MessageExtendedCommand:
01032
01033 validCommand = true;
01034 break;
01035 case MessageSync:
01036
01037 validCommand = true;
01038 break;
01039 case MessageQuit:
01040 case MessageQuitAck:
01041 case MessageResend:
01042 case MessageChat:
01043 case MessageChatTerm:
01044
01045 validCommand = true;
01046 break;
01047 case MessageCommandDismiss:
01048
01049 default:
01050 {
01051 unsigned int slot = ntohs(nc->Unit);
01052
01053 if (slot >= 0 && slot < UnitSlotFree &&
01054 (UnitSlots[slot]->Player->Index == player ||
01055 Players[player].IsTeamed(UnitSlots[slot]))) {
01056 validCommand = true;
01057 } else {
01058 validCommand = false;
01059 }
01060 }
01061 }
01062
01063
01064 if (validCommand) {
01065 NetworkIn[packet.Header.Cycle][player][i].Time = n;
01066 NetworkIn[packet.Header.Cycle][player][i].Type = packet.Header.Type[i];
01067 NetworkIn[packet.Header.Cycle][player][i].Data = *nc;
01068 } else {
01069 SetMessage(_("%s sent bad command"), Players[player].Name.c_str());
01070 DebugPrint("%s sent bad command: 0x%x\n" _C_
01071 Players[player].Name.c_str() _C_
01072 packet.Header.Type[i] & 0x7F);
01073 }
01074 }
01075
01076 for ( ; i < MaxNetworkCommands; ++i) {
01077 NetworkIn[packet.Header.Cycle][player][i].Time = 0;
01078 }
01079
01080
01081
01082
01083 if (!NetworkInSync) {
01084 NetworkInSync = 1;
01085 n = (GameCycle / NetworkUpdates) * NetworkUpdates + NetworkUpdates;
01086 for (player = 0; player < HostsCount; ++player) {
01087 if (NetworkIn[n & 0xFF][Hosts[player].PlyNr][0].Time != n) {
01088 NetworkInSync = 0;
01089 break;
01090 }
01091 }
01092 }
01093 }
01094
01098 void NetworkQuit(void)
01099 {
01100 if (!ThisPlayer) {
01101 return;
01102 }
01103
01104 int n = (GameCycle + NetworkUpdates) / NetworkUpdates * NetworkUpdates + NetworkLag;
01105 NetworkIn[n & 0xFF][ThisPlayer->Index][0].Type = MessageQuit;
01106 NetworkIn[n & 0xFF][ThisPlayer->Index][0].Time = n;
01107 NetworkIn[n & 0xFF][ThisPlayer->Index][0].Data.X = ThisPlayer->Index;
01108
01109 for (int i = 1; i < MaxNetworkCommands; ++i) {
01110 NetworkIn[n & 0xFF][ThisPlayer->Index][i].Type = MessageNone;
01111 }
01112
01113 NetworkSendPacket(NetworkIn[n & 0xFF][ThisPlayer->Index]);
01114 }
01115
01121 void NetworkChatMessage(const std::string &msg)
01122 {
01123 CNetworkCommandQueue *ncq;
01124 CNetworkChat *ncm;
01125 const char *cp;
01126 int n;
01127
01128 if (IsNetworkGame()) {
01129 cp = msg.c_str();
01130 n = msg.size();
01131 while (n >= (int)sizeof(ncm->Text)) {
01132 ncq = AllocNCQ();
01133 MsgCommandsIn.push_back(ncq);
01134 ncq->Type = MessageChat;
01135 ncm = (CNetworkChat *)(&ncq->Data);
01136 ncm->Player = ThisPlayer->Index;
01137 memcpy(ncm->Text, cp, sizeof(ncm->Text));
01138 cp += sizeof(ncm->Text);
01139 n -= sizeof(ncm->Text);
01140 }
01141 ncq = AllocNCQ();
01142 MsgCommandsIn.push_back(ncq);
01143 ncq->Type = MessageChatTerm;
01144 ncm = (CNetworkChat *)(&ncq->Data);
01145 ncm->Player = ThisPlayer->Index;
01146 memcpy(ncm->Text, cp, n + 1);
01147 }
01148 }
01149
01155 static void ParseNetworkCommand(const CNetworkCommandQueue *ncq)
01156 {
01157 int ply;
01158
01159 switch (ncq->Type & 0x7F) {
01160 case MessageSync:
01161 ply = ntohs(ncq->Data.X) << 16;
01162 ply |= ntohs(ncq->Data.Y);
01163 if (ply != NetworkSyncSeeds[GameCycle & 0xFF] ||
01164 ntohs(ncq->Data.Unit) != NetworkSyncHashs[GameCycle & 0xFF]) {
01165
01166 SetMessage(_("Network out of sync"));
01167 DebugPrint("\nNetwork out of sync %x!=%x! %d!=%d! Cycle %lu\n\n" _C_
01168 ply _C_ NetworkSyncSeeds[GameCycle & 0xFF] _C_
01169 ntohs(ncq->Data.Unit) _C_ NetworkSyncHashs[GameCycle & 0xFF] _C_ GameCycle);
01170 }
01171 return;
01172 case MessageChat:
01173 case MessageChatTerm: {
01174 const CNetworkChat *ncm;
01175
01176 ncm = (CNetworkChat *)(&ncq->Data);
01177 ply = ncm->Player;
01178 if (NetMsgBufLen[ply] + sizeof(ncm->Text) < 128) {
01179 memcpy(((char *)NetMsgBuf[ply]) + NetMsgBufLen[ply], ncm->Text,
01180 sizeof(ncm->Text));
01181 }
01182 NetMsgBufLen[ply] += sizeof(ncm->Text);
01183 if (ncq->Type == MessageChatTerm) {
01184 NetMsgBuf[ply][127] = '\0';
01185 SetMessage("%s", NetMsgBuf[ply]);
01186 PlayGameSound(GameSounds.ChatMessage.Sound, MaxSampleVolume);
01187 NetMsgBufLen[ply] = 0;
01188 }
01189 }
01190 break;
01191 case MessageQuit:
01192 NetworkRemovePlayer(ncq->Data.X);
01193 CommandLog("quit", NoUnitP, FlushCommands, ncq->Data.X, -1, NoUnitP, NULL, -1);
01194 CommandQuit(ncq->Data.X);
01195 break;
01196 case MessageExtendedCommand: {
01197 const CNetworkExtendedCommand *nec;
01198
01199 nec = (CNetworkExtendedCommand *)(&ncq->Data);
01200 ParseExtendedCommand(nec->ExtendedType, (ncq->Type & 0x80) >> 7,
01201 nec->Arg1, ntohs(nec->Arg2), ntohs(nec->Arg3), ntohs(nec->Arg4));
01202 }
01203 break;
01204 case MessageNone:
01205
01206 Assert(0);
01207 break;
01208 default:
01209 ParseCommand(ncq->Type, ntohs(ncq->Data.Unit),
01210 ntohs(ncq->Data.X), ntohs(ncq->Data.Y), ntohs(ncq->Data.Dest));
01211 break;
01212 }
01213 }
01214
01222 static void NetworkResendCommands(void)
01223 {
01224 CNetworkPacket packet;
01225
01226 #ifdef DEBUG
01227 ++NetworkSendResend;
01228 #endif
01229
01230
01231
01232
01233 packet.Header.Type[0] = MessageResend;
01234 packet.Header.Type[1] = MessageNone;
01235 packet.Header.Cycle =
01236 (Uint8)((GameCycle / NetworkUpdates) * NetworkUpdates + NetworkUpdates);
01237
01238 NetworkBroadcast(&packet, 1);
01239 }
01240
01244 static void NetworkSendCommands(void)
01245 {
01246 CNetworkCommandQueue *incommand;
01247 CNetworkCommandQueue *ncq;
01248 int numcommands;
01249
01250
01251
01252
01253 numcommands = 0;
01254 incommand = NULL;
01255 ncq = NetworkIn[(GameCycle + NetworkLag) & 0xFF][ThisPlayer->Index];
01256 ncq->Clear();
01257 if (CommandsIn.empty() && MsgCommandsIn.empty()) {
01258 ncq[0].Type = MessageSync;
01259 ncq[0].Data.Unit = htons(SyncHash&0xFFFF);
01260 ncq[0].Data.X = htons(SyncRandSeed>>16);
01261 ncq[0].Data.Y = htons(SyncRandSeed&0xFFFF);
01262 ncq[0].Time = GameCycle + NetworkLag;
01263 numcommands = 1;
01264 } else {
01265 while ((!CommandsIn.empty() || !MsgCommandsIn.empty()) &&
01266 numcommands < MaxNetworkCommands) {
01267 if (!CommandsIn.empty()) {
01268 incommand = CommandsIn.front();
01269 #ifdef DEBUG
01270 if (incommand->Type != MessageExtendedCommand) {
01271
01272 if (UnitSlots[ntohs(ncq->Data.Unit)]->Destroyed) {
01273 DebugPrint("Sending destroyed unit %d over network!!!!!!\n" _C_
01274 ntohs(incommand->Data.Unit));
01275 }
01276 }
01277 #endif
01278 CommandsIn.pop_front();
01279 } else {
01280 incommand = MsgCommandsIn.front();
01281 MsgCommandsIn.pop_front();
01282 }
01283 ncq[numcommands] = *incommand;
01284 ncq[numcommands].Time = GameCycle + NetworkLag;
01285 ++numcommands;
01286 FreeNCQ(incommand);
01287 }
01288 }
01289
01290 if (numcommands != MaxNetworkCommands) {
01291 ncq[numcommands].Type = MessageNone;
01292 }
01293
01294 NetworkSendPacket(ncq);
01295
01296 NetworkSyncSeeds[(GameCycle + NetworkLag) & 0xFF] = SyncRandSeed;
01297 NetworkSyncHashs[(GameCycle + NetworkLag) & 0xFF] = SyncHash & 0xFFFF;
01298 }
01299
01303 static void NetworkExecCommands(void)
01304 {
01305 CNetworkCommandQueue *ncq;
01306
01307
01308
01309
01310 for (int i = 0; i < NumPlayers; ++i) {
01311
01312
01313
01314 for (int c = 0; c < MaxNetworkCommands; ++c) {
01315 ncq = &NetworkIn[GameCycle & 0xFF][i][c];
01316 if (ncq->Type == MessageNone) {
01317 break;
01318 }
01319 if (ncq->Time) {
01320 #ifdef DEBUG
01321 if (ncq->Time != GameCycle) {
01322 DebugPrint("cycle %lu idx %lu time %lu\n" _C_
01323 GameCycle _C_ GameCycle & 0xFF _C_ ncq->Time);
01324 Assert(ncq->Time == GameCycle);
01325 }
01326 #endif
01327 ParseNetworkCommand(ncq);
01328 }
01329 }
01330 }
01331 }
01332
01336 static void NetworkSyncCommands(void)
01337 {
01338 const CNetworkCommandQueue *ncq;
01339 unsigned long n;
01340
01341
01342
01343
01344 NetworkInSync = 1;
01345 n = GameCycle + NetworkUpdates;
01346 for (int i = 0; i < HostsCount; ++i) {
01347 ncq = NetworkIn[n & 0xFF][Hosts[i].PlyNr];
01348 if (ncq[0].Time != n) {
01349 NetworkInSync = 0;
01350 NetworkDelay = FrameCounter + NetworkUpdates;
01351
01352 break;
01353 }
01354 }
01355 }
01356
01360 void NetworkCommands(void)
01361 {
01362 if (IsNetworkGame()) {
01363 if (!(GameCycle % NetworkUpdates)) {
01364
01365 NetworkSendCommands();
01366 NetworkExecCommands();
01367 NetworkSyncCommands();
01368 }
01369 }
01370 }
01371
01372
01376 void NetworkRecover(void)
01377 {
01378 if (HostsCount == 0) {
01379 NetworkInSync = 1;
01380 return;
01381 }
01382
01383 if (FrameCounter > NetworkDelay) {
01384 NetworkDelay += NetworkUpdates;
01385
01386
01387 for (int i = 0; i < HostsCount; ++i) {
01388 int secs;
01389
01390 if (!NetworkLastFrame[Hosts[i].PlyNr]) {
01391 continue;
01392 }
01393
01394 secs = (FrameCounter - NetworkLastFrame[Hosts[i].PlyNr]) /
01395 (FRAMES_PER_SECOND * VideoSyncSpeed / 100);
01396
01397 if (secs >= 3 && secs < NetworkTimeout) {
01398 if (FrameCounter % FRAMES_PER_SECOND < (unsigned long)NetworkUpdates) {
01399 SetMessage(_("Waiting for player \"%s\": %d:%02d"), Hosts[i].PlyName,
01400 (NetworkTimeout - secs) / 60, (NetworkTimeout - secs) % 60);
01401 }
01402 }
01403 if (secs >= NetworkTimeout) {
01404 CNetworkCommand nc;
01405 const CNetworkCommandQueue *ncq;
01406 unsigned long n;
01407 CNetworkPacket np;
01408
01409 n = GameCycle + NetworkUpdates;
01410 nc.X = Hosts[i].PlyNr;
01411 NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Time = n;
01412 NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Type = MessageQuit;
01413 NetworkIn[n & 0xFF][Hosts[i].PlyNr][0].Data = nc;
01414 PlayerQuit[Hosts[i].PlyNr] = 1;
01415 SetMessage(_("Timed out"));
01416
01417 ncq = &NetworkIn[n & 0xFF][Hosts[i].PlyNr][0];
01418 np.Header.Cycle = ncq->Time & 0xFF;
01419 np.Header.Type[0] = ncq->Type;
01420 np.Header.Type[1] = MessageNone;
01421
01422 NetworkBroadcast(&np, 1);
01423
01424 NetworkSyncCommands();
01425 }
01426 }
01427
01428
01429 NetworkResendCommands();
01430 }
01431 }
01432