#include #include #include #include "switches.h" #include "types.h" #include "file.h" #include "universe.h" #include "univupdate.h" #include "netcheck.h" #include "commandnetwork.h" #include "blobs.h" #include "globals.h" #include "titannet.h" #include "SaveGame.h" #include "randy.h" #include "titaninterfacec.h" #include "commandwrap.h" #include "stringsonly.h" #include "stats.h" #if SYNC_CHECK udword randSyncErr; udword univSyncErr; udword blobSyncErr; udword pktSyncErr; udword randSyncErrFrame; udword univSyncErrFrame; udword blobSyncErrFrame; #endif char OrigRecordPacketFileName[MAX_RECORDPACKETFILENAME_STRLEN] = ""; #ifdef GOD_LIKE_SYNC_CHECKING #define GOD_NUMBER_CHECKSUMS_REMEMBERED 16384 #define GOD_NUMBER_CHECKSUMS_REMEMBERED_MASK 16383 //checksum stack for local machine GodSyncCheckSums godnetsyncchecksums[GOD_NUMBER_CHECKSUMS_REMEMBERED]; //first frame that a sync error occurred between systems // udword godRandErrFrame; udword godUnivErrFrame; udword godBlobErrFrame; udword godShipErrFrame; sdword breaked; //typedef struct in spaceobj.h GodWritePacketHeader *godUniverseSnapShotHeader=NULL; #endif filehandle netlogfileFH; FILE *netlogfile = NULL; /*============================================================================= Private data: =============================================================================*/ #if SYNC_CHECK #define NUMBER_CHECKSUMS_REMEMBERED 128 #define NUMBER_CHECKSUMS_MASK 127 #define CHECKSUMVALID_NOT 0 #define CHECKSUMVALID_VALID 1 #define CHECKSUMVALID_CHECKED 2 #define CHECKSUMVALID_VALIDCHECKED (CHECKSUMVALID_VALID + CHECKSUMVALID_CHECKED) NetSyncChecksums netsyncchecksums[NUMBER_CHECKSUMS_REMEMBERED]; udword netsyncchecksumsValid[NUMBER_CHECKSUMS_REMEMBERED]; sdword lastchecksumCalculated; #endif filehandle playPacketFileFH; FILE *playPacketFile = NULL; /*============================================================================= Functions: =============================================================================*/ #ifdef GOD_LIKE_SYNC_CHECKING void godSyncInit() { sdword sizeofHeader,i; //init some global variables godRandErrFrame=0; godUnivErrFrame=0; godBlobErrFrame=0; godShipErrFrame=0; breaked=FALSE; //calculate sizeof the universesnapshotheader. sizeofHeader = sizeofGodHeader(syncDumpWindowSize); godUniverseSnapShotHeader=memAlloc(sizeofHeader,"SyncSnapHeader",ExtendedPool); if(godUniverseSnapShotHeader == NULL) { dbgFatalf(DBG_Loc,"\nCouldn't Allocate %d bytes for syncChecking Header.",sizeofHeader); } strcpy(godUniverseSnapShotHeader->playerName,playerNames[universe.curPlayerIndex]); godUniverseSnapShotHeader->windowSize=syncDumpWindowSize; //init all ptr's to NULL just to be sure. for(i=0;iuniverseSnapShot[i]=NULL; } } void godSyncShutDown() { sdword i; if(godUniverseSnapShotHeader != NULL) { for(i=0;iwindowSize;i++) { if(godUniverseSnapShotHeader->universeSnapShot[i]!=NULL) { memFree(godUniverseSnapShotHeader->universeSnapShot[i]); } } memFree(godUniverseSnapShotHeader); } } //pass in FALSE to generate another frame and keep it in memory //pass in TRUE to write the whole memory dump to disk without //generating a new snapshot void syncDebugDump(char *filename1,sdword counter,bool save) { filehandle syncFH; FILE *syncFP = NULL; Node *node = universe.ShipList.head; sdword numShips = universe.ShipList.num; Ship *ship; sdword i,sizeofHeader,sizeofsnapshot; char filename[200]; sizeofsnapshot = sizeofSnapShot(numShips); if(save) { //delete old file if its there. sprintf(filename,"SyncDump_CRC_%X_%X_%X_%X_Player_%s.txt",HomeworldCRC[0], HomeworldCRC[1],HomeworldCRC[2],HomeworldCRC[3], playerNames[universe.curPlayerIndex]); fileDelete(filename); syncFH = fileOpen(filename,FF_WriteMode); dbgAssert(!fileUsingBigfile(syncFH)); syncFP = fileStream(syncFH); //don't want Ptr array in file! sizeofHeader = sizeof(GodWritePacketHeader); fwrite(godUniverseSnapShotHeader,sizeofHeader,1,syncFP); } else { //not SAVEING! //operating on block syncDumpGranTrack if(godUniverseSnapShotHeader->universeSnapShot[syncDumpWindowPos] != NULL) { memFree(godUniverseSnapShotHeader->universeSnapShot[syncDumpWindowPos]); } //allocate memory for this frame godUniverseSnapShotHeader->universeSnapShot[syncDumpWindowPos] = (UniverseSnapShot *) memAlloc(sizeofsnapshot,"snapshot",ExtendedPool); if(godUniverseSnapShotHeader->universeSnapShot[syncDumpWindowPos] == NULL) { //couldn't get the memory dbgFatalf(DBG_Loc,"Memory Allocation Failure on Universe Sync SnapShot %d",counter); } } if(!save) { UniverseSnapShot *us=godUniverseSnapShotHeader->universeSnapShot[syncDumpWindowPos]; sdword j=0; us->univUpdateCounterValue = counter; us->numShips = numShips; while(node != NULL) { ship = (Ship *) listGetStructOfNode(node); us->ship[j] = *ship; //NULLify all ptrs... us->ship[j].objlink.next=0; us->ship[j].objlink.prev=0; us->ship[j].objlink.belongto=0; us->ship[j].objlink.structptr=0; us->ship[j].staticinfo=0; us->ship[j].renderlink.next=0; us->ship[j].renderlink.prev=0; us->ship[j].renderlink.belongto=0; us->ship[j].renderlink.structptr=0; us->ship[j].collMyBlob = 0; us->ship[j].newDockWithTransfer = 0; us->ship[j].currentLOD=0; us->ship[j].renderedLODs=0; us->ship[j].cameraDistanceSquared=0; us->ship[j].cameraDistanceVector.x=0; us->ship[j].cameraDistanceVector.y=0; us->ship[j].cameraDistanceVector.z=0; us->ship[j].collInfo.selCircleX=0; us->ship[j].collInfo.selCircleY=0; us->ship[j].collInfo.selCircleRadius=0; us->ship[j].collInfo.precise=0; us->ship[j].flashtimer=0; us->ship[j].shaneyPooSoundEventAnimationTypeFlag=0; us->ship[j].chatterBits=0; us->ship[j].hyperspacePing=0; us->ship[j].hotKeyGroup=0; us->ship[j].retaliateSpeechVar=0; us->ship[j].retaliateSpeechTime=0; if(us->ship[j].flags & SOF_Dead) { us->ship[j].flags|=SOF_Dead; } else { us->ship[j].flags=0; } us->ship[j].impactablelink.next=0; us->ship[j].impactablelink.prev=0; us->ship[j].impactablelink.belongto=0; us->ship[j].impactablelink.structptr=0; us->ship[j].clampInfo=0; us->ship[j].salvageInfo=0; if(us->ship[j].dockingship != NULL) { us->ship[j].dockingship=(Ship *)us->ship[j].dockingship->shipID.shipNumber; } else { us->ship[j].dockingship=-1; } us->ship[j].navLightInfo=0; us->ship[j].shiplink.next=0; us->ship[j].shiplink.prev=0; us->ship[j].shiplink.belongto=0; us->ship[j].shiplink.structptr=0; if(us->ship[j].rowGetOutOfWay != NULL) { us->ship[j].rowGetOutOfWay=(Ship *)us->ship[j].rowGetOutOfWay->shipID.shipNumber; } else { us->ship[j].rowGetOutOfWay=-1; } if(us->ship[j].playerowner != NULL) { us->ship[j].playerowner = (Player *)us->ship[j].playerowner->playerIndex; } else { us->ship[j].playerowner = -1; } if(us->ship[j].gettingrocked != NULL) { us->ship[j].gettingrocked=(Ship *)us->ship[j].gettingrocked->shipID.shipNumber; // ship which is rocking you (shooting you) } else { us->ship[j].gettingrocked=-1; } if(us->ship[j].recentAttacker != NULL) { us->ship[j].recentAttacker=(Ship *)us->ship[j].recentAttacker->shipID.shipNumber; // ship which has attacked you recently (ie, not just this AI tick) -- see recentlyAttacked } else { us->ship[j].recentAttacker=-1; } if(us->ship[j].firingAtUs != NULL) { us->ship[j].firingAtUs=(Ship *)us->ship[j].firingAtUs->shipID.shipNumber; // ship which has recently fired upon us (but needn't have hit) see recentlyFiredUpon } else { us->ship[j].firingAtUs=-1; } us->ship[j].flightmanInfo=0; us->ship[j].formationcommand = 0; if(us->ship[j].command != NULL) { us->ship[j].command = (CommandToDo *)us->ship[j].command->ordertype.order; } else { us->ship[j].command = -1; } //turn off this COMPUTER PLAYER specific variale! us->ship[j].specialFlags &= (~(SPECIAL_Resourcing|SPECIAL_Finished_Resource)); us->ship[j].attackvars.multipleAttackTargets=0; // only used by ships which can target multiple targets. us->ship[j].attackvars.attacktarget=0; us->ship[j].attackvars.myLeaderIs=0; us->ship[j].attackvars.myWingmanIs=0; if(us->ship[j].dockvars.dockship!=NULL) { us->ship[j].dockvars.dockship = us->ship[j].dockvars.dockship->shipID.shipNumber; } else { us->ship[j].dockvars.dockship=0; } us->ship[j].dockvars.busyingThisShip=0; us->ship[j].dockvars.dockstaticpoint=0; us->ship[j].dockvars.customdockinfo=0; us->ship[j].dockvars.launchpoints=0; us->ship[j].rceffect=0; us->ship[j].ShipXHarvestsResourceY = 0; us->ship[j].damageLights=0; us->ship[j].showingDamage[0][0]=0; us->ship[j].showingDamage[0][1]=0; us->ship[j].showingDamage[0][2]=0; us->ship[j].showingDamage[1][0]=0; us->ship[j].showingDamage[1][1]=0; us->ship[j].showingDamage[1][2]=0; us->ship[j].showingDamage[2][0]=0; us->ship[j].showingDamage[2][1]=0; us->ship[j].showingDamage[2][2]=0; us->ship[j].tractorbeam_playerowner=0; for(i=0;iship[j].trail[i]=0; } memset(&us->ship[j].soundevent,0,sizeof(SOUNDEVENT)); us->ship[j].slavelink.next=0; us->ship[j].slavelink.prev=0; us->ship[j].slavelink.belongto=0; us->ship[j].slavelink.structptr=0; us->ship[j].slaveinfo=0; us->ship[j].gunInfo=0; us->ship[j].dockInfo=0; us->ship[j].shipsInsideMe=0; us->ship[j].bindings=0; us->ship[j].madBindings=0; us->ship[j].shipSinglePlayerGameInfo=0; us->ship[j].lightning[0]=0; us->ship[j].lightning[1] = 0; us->ship[j].magnitudeSquared=0; us->ship[j].ShipSpecifics[0]=0; j++; node=node->next; } } else { //first find oldest... { udword oldest; sdword oldestSnapShot=0; sdword windowSize=godUniverseSnapShotHeader->windowSize; if(godUniverseSnapShotHeader->universeSnapShot[0] != NULL) { oldest = godUniverseSnapShotHeader->universeSnapShot[0]->univUpdateCounterValue; for(i=0;iwindowSize;i++) { if(godUniverseSnapShotHeader->universeSnapShot[i] == NULL) { windowSize=i; break; } if(godUniverseSnapShotHeader->universeSnapShot[i]->univUpdateCounterValue < oldest) { oldest = godUniverseSnapShotHeader->universeSnapShot[i]->univUpdateCounterValue; oldestSnapShot=i; } } for(i=oldestSnapShot;iuniverseSnapShot[i]->numShips); fwrite(&sizeofsnapshot,sizeof(sdword),1,syncFP); fwrite(godUniverseSnapShotHeader->universeSnapShot[i],sizeofsnapshot,1,syncFP); } for(i=0;iuniverseSnapShot[i]->numShips); fwrite(&sizeofsnapshot,sizeof(sdword),1,syncFP); fwrite(godUniverseSnapShotHeader->universeSnapShot[i],sizeofsnapshot,1,syncFP); } } } fileClose(syncFH); } } //Saves the sync info every so often depending on //syncDumpWindowSize - //and //syncDumpGranularity - every Xth frame it saves a window slice void industrialStrengthSyncDebugging(sdword FrameNumber) { syncDumpGranTrack++; if(syncDumpGranTrack >= syncDumpGranularity) { //exceeded granularity so lets save! syncDumpGranTrack=0; syncDebugDump("syncSnapShot.txt", FrameNumber,FALSE); syncDumpWindowPos++; if(syncDumpWindowPos >= syncDumpWindowSize) { syncDumpWindowPos = 0; //reset window position } } } void netcheckIndustrialChecksum() { sdword numShipsInChecksum; sdword num; //And with a bit mask so our 'num' cycles around a fixed number //GOD_NUMBER_CHECKSUMS_REMEMBERED 1024 num = universe.univUpdateCounter & GOD_NUMBER_CHECKSUMS_REMEMBERED_MASK; godnetsyncchecksums[num].randcheck=gamerand(); godnetsyncchecksums[num].univcheck=univGetChecksum(&numShipsInChecksum); godnetsyncchecksums[num].blobcheck=statsGetStatChecksum(); godnetsyncchecksums[num].shipcheck=univCalcShipChecksum(); godnetsyncchecksums[num].univframe=universe.univUpdateCounter; if(!IAmCaptain) { if(universe.univUpdateCounter & 7) { clSendGodSync(&godnetsyncchecksums[num],universe.curPlayerIndex,GOD_COMMAND_GOD_HALTONSYNC); } } } void netReceivedSyncFromNonCaptain(void *checksums,udword frame,udword playerIndex) { bool BREAK=FALSE; sdword num = frame & GOD_NUMBER_CHECKSUMS_REMEMBERED_MASK; if(godnetsyncchecksums[num].randcheck != ((GodSyncCheckSums *)checksums)->randcheck) { if(!godRandErrFrame) { godRandErrFrame=frame; } BREAK=TRUE; } if(godnetsyncchecksums[num].univcheck != ((GodSyncCheckSums *)checksums)->univcheck) { if(!godUnivErrFrame) { godUnivErrFrame=frame; } BREAK=TRUE; } if(godnetsyncchecksums[num].blobcheck != ((GodSyncCheckSums *)checksums)->blobcheck) { if(!godBlobErrFrame) { godBlobErrFrame=frame; } BREAK=TRUE; } if(godnetsyncchecksums[num].shipcheck != ((GodSyncCheckSums *)checksums)->shipcheck) { if(!godShipErrFrame) { godShipErrFrame=frame; } BREAK=TRUE; } if(BREAK && !breaked) { breaked=TRUE; clSendGodSync(&godnetsyncchecksums[num],universe.curPlayerIndex,GOD_COMMAND_HALTONSYNC); } } #endif void recPackInGameStartCB(char *filename) { if (recordPackets) { // already recording if (debugPacketRecord) { strcpy(OrigRecordPacketFileName,recordPacketFileName); // allow /packetRecord option and recording game too } else { return; } } strcpy(recordPacketSaveFileName,filename); strcpy(recordPacketFileName,filename); strcat(recordPacketFileName,PKTS_EXTENSION); startRecordingGameWhenSafe = TRUE; } void recPackInGameStartCBSafeToStart() { // clear file fileDelete(recordPacketSaveFileName); fileDelete(recordPacketFileName); if (!SaveGame(recordPacketSaveFileName)) { clCommandMessage(strGetString(strPatchUnableWriteFile)); return; } else { clCommandMessage(strGetString(strRecordingGame)); } recordPackets = TRUE; recordplayPacketsInGame = TRUE; if (!multiPlayerGame) { recordFakeSendPackets = TRUE; captainIndex = 0; sigsPlayerIndex = 0; sigsNumPlayers = 1; sigsPressedStartGame = TRUE; netcheckInit(); } } void recPackInGameStopCB(void) { if (!recordPackets) { return; } recordPackets = FALSE; recordplayPacketsInGame = FALSE; } void recPackRecordSaveHeader(); void recPackRecordInit(void) { char tempstr[] = "_x.pkts"; sprintf(recordPacketFileName,tpGameCreated.MapName,numPlayers); tempstr[1] = '0' + (ubyte)curPlayer; strcat(recordPacketFileName,tempstr); // clear file fileDelete(recordPacketFileName); dbgAssert(!recordplayPacketsInGame); recPackRecordSaveHeader(); } #define HEADERCHECK 0x44414548 void recPackRecordSaveHeader() { udword size = sizeof(CaptainGameInfo); udword validcheck = HEADERCHECK; filehandle fh = fileOpen(recordPacketFileName,FF_AppendMode); FILE *fp; dbgAssert(!fileUsingBigfile(fh)); fp = fileStream(fh); dbgAssert(!recordplayPacketsInGame); fwrite(&validcheck, sizeof(udword), 1 ,fp); fwrite(&size, sizeof(udword), 1, fp); fwrite(&tpGameCreated, size, 1, fp); fileClose(fh); } #define VALIDCHECK 0x4b434150 void recPackRecordPacket(ubyte *packet,udword sizeofPacket) { udword size = sizeofPacket; udword validcheck = VALIDCHECK; filehandle fh = fileOpen(recordPacketFileName,FF_AppendMode); FILE *fp; dbgAssert(!fileUsingBigfile(fh)); fp = fileStream(fh); fwrite(&validcheck, sizeof(udword), 1 ,fp); fwrite(&size, sizeof(udword), 1, fp); fwrite(packet, sizeofPacket, 1, fp); fileClose(fh); } void recPackRecordPacketFilename(ubyte *packet,udword sizeofPacket,char *filename) { udword size = sizeofPacket; udword validcheck = VALIDCHECK; filehandle fh = fileOpen(filename,FF_AppendMode); FILE *fp; dbgAssert(!fileUsingBigfile(fh)); fp = fileStream(fh); fwrite(&validcheck, sizeof(udword), 1 ,fp); fwrite(&size, sizeof(udword), 1, fp); fwrite(packet, sizeofPacket, 1, fp); fileClose(fh); } ubyte *recPackPlayGetNextPacket(udword *sizeofPacket) { udword size; udword validcheck; ubyte *packet; tryagain: if (fread(&validcheck,sizeof(udword),1,playPacketFile) == 0) return NULL; if (validcheck == HEADERCHECK) // skip headers { if (fread(&size,sizeof(udword),1,playPacketFile) == 0) return NULL; packet = memAlloc(size,"ld(loadpacket)",Pyrophoric); fread(packet,size,1,playPacketFile); memFree(packet); goto tryagain; } if (validcheck != VALIDCHECK) { dbgFatalf(DBG_Loc,"Bad packet recording in file %s",recordPacketFileName); } if (fread(&size,sizeof(udword),1,playPacketFile) == 0) return NULL; packet = memAlloc(size,"ld(loadpacket)",Pyrophoric); fread(packet,size,1,playPacketFile); *sizeofPacket = size; return packet; } bool recPackPlayLoadHeader() { udword size; udword validcheck; if (fread(&validcheck,sizeof(udword),1,playPacketFile) == 0) return FALSE; if (validcheck == HEADERCHECK) { if (fread(&size,sizeof(udword),1,playPacketFile) == 0) return FALSE; if (size != sizeof(tpGameCreated)) return FALSE; fread(&tpGameCreated,size,1,playPacketFile); return TRUE; } else { // woops, we read something that isn't header, seek back and ignore fseek(playPacketFile,-((sdword)sizeof(udword)),SEEK_CUR); return FALSE; } return FALSE; } void recPackPlayInGameInit(void) { playPackets = TRUE; recordplayPacketsInGame = TRUE; playPacketFileFH = fileOpen(recordPacketFileName, 0); dbgAssert(!fileUsingBigfile(playPacketFileFH)); playPacketFile = fileStream(playPacketFileFH); netcheckInit(); } void recPackPlayInit(void) { char *str; playPacketFileFH = fileOpen(recordPacketFileName, 0); dbgAssert(!fileUsingBigfile(playPacketFileFH)); playPacketFile = fileStream(playPacketFileFH); dbgAssert(!recordplayPacketsInGame); str = strstr(recordPacketFileName,".pkts"); dbgAssert(str); str -= 3; // backup three bytes dbgAssert(str[1] == '_'); numPlayers = str[0] - '0'; curPlayer = str[2] - '0'; dbgAssert(numPlayers > 0); dbgAssert(numPlayers <= MAX_MULTIPLAYER_PLAYERS); dbgAssert(curPlayer < MAX_MULTIPLAYER_PLAYERS); recPackPlayLoadHeader(); } void recPackPlayClose(void) { if (playPacketFileFH) { fileClose(playPacketFileFH); playPacketFile = NULL; } } /*----------------------------------------------------------------------------- Name : netcheckReset Description : resets netCheck module Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void netcheckReset(void) { #if SYNC_CHECK sdword i; for (i=0;ichecksums.randcheck = 0; // indicates all checksums should be ignored return; } dbgAssert(netsyncchecksumsValid[lastchecksumCalculated] & CHECKSUMVALID_VALID); packet->checksums = netsyncchecksums[lastchecksumCalculated]; } #endif #if SYNC_CHECK /*----------------------------------------------------------------------------- Name : netcheckCheckChecksum Description : checks the checksum with previously stored checksums in netsyncchecksums Inputs : checksum Outputs : Return : ----------------------------------------------------------------------------*/ void netcheckCheckChecksum(NetSyncChecksums *checksum) { udword checkthisentry; uword checknum; if (checksum->randcheck == 0) { return; // ignore if randcheck is == 0 } checknum = checksum->packetnum; checkthisentry = checknum & NUMBER_CHECKSUMS_MASK; if ((netsyncchecksumsValid[checkthisentry] & (CHECKSUMVALID_VALID|CHECKSUMVALID_CHECKED)) == CHECKSUMVALID_VALID) { if (checknum == netsyncchecksums[checkthisentry].packetnum) { // now we can check if in sync if (netsyncchecksums[checkthisentry].randcheck != checksum->randcheck) { if(!randSyncErr) { randSyncErrFrame = universe.univUpdateCounter; /* if(intOnSync) { //user wants an int 3 _asm int 3; } syncDebugDump("SyncRand.txt"); */ } randSyncErr++; //if (intOnSync) clSendMisc(&universe.mainCommandLayer,NULL,MISCCOMMAND_HALTONSYNC,0); } if (netsyncchecksums[checkthisentry].univcheck != checksum->univcheck) { if(!univSyncErr) { univSyncErrFrame = universe.univUpdateCounter; /*if(intOnSync) { //user wants an int 3 _asm int 3; } syncDebugDump("SyncUniv.txt");*/ } univSyncErr++; //if (intOnSync) clSendMisc(&universe.mainCommandLayer,NULL,MISCCOMMAND_HALTONSYNC,0); } if (netsyncchecksums[checkthisentry].blobcheck != checksum->blobcheck) { if(!blobSyncErr) { blobSyncErrFrame = universe.univUpdateCounter; /*if(intOnSync) { //user wants an int 3 _asm int 3; } syncDebugDump("SyncBlob.txt");*/ if (multiPlayerGame) SendCheatDetect(); } blobSyncErr++; //if (intOnSync) clSendMisc(&universe.mainCommandLayer,NULL,MISCCOMMAND_HALTONSYNC,0); } netsyncchecksumsValid[checkthisentry] |= CHECKSUMVALID_CHECKED; // don't bother checking this one again } } } #endif /*----------------------------------------------------------------------------- Name : netcheckShow Description : prints out packet received, and synchronization information to log file to ensure game is in sync. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void netcheckShow(HWPacketHeader *packet) { sdword numShipsInChecksum; real32 univcheck = univGetChecksum(&numShipsInChecksum); udword blobcheck = statsGetStatChecksum(); uword randcheck = gamerand(); uword packetnum = packet->frame; #if SYNC_CHECK udword storehere; // regardless of whether I am captain or not, store checksums: storehere = ((udword)packetnum) & NUMBER_CHECKSUMS_MASK; netsyncchecksums[storehere].packetnum = packetnum; netsyncchecksums[storehere].randcheck = randcheck; netsyncchecksums[storehere].univcheck = univcheck; netsyncchecksums[storehere].blobcheck = blobcheck; netsyncchecksumsValid[storehere] = CHECKSUMVALID_VALID; lastchecksumCalculated = (sdword)storehere; netcheckCheckChecksum(&packet->checksums); #endif if (netlogfile) { #if BINNETLOG if (logEnable == LOG_VERBOSE) { binnetlogPacket binnetlog; binnetlog.header = makenetcheckHeader('P','P','P','P'); binnetlog.packetnum = packetnum; binnetlog.randcheck = randcheck; binnetlog.univcheck = univcheck; binnetlog.blobcheck = blobcheck; binnetlog.numShipsInChecksum = numShipsInChecksum; binnetlog.numBlobsInChecksum = 0; binnetlog.univUpdateCounter = universe.univUpdateCounter; fwrite(&binnetlog, sizeof(binnetlogPacket), 1 ,netlogfile); } else #endif fprintf(netlogfile,"Packet:%d Rand:%d Checksum:%f %d CDET:%d\n",packetnum,randcheck,univcheck,numShipsInChecksum,blobcheck); } }