Exemple #1
0
LocFile* LocFileNew( char* path, unsigned int flags )
{
	FILE* fp = fopen( path, "rb" );
	if( fp == NULL )
	{
		INFO("Cannot open file %s (file does not exist?)..\n", path );
		return NULL;
	}
	
	struct stat st;
	if( stat( path, &st ) < 0 )
	{
		INFO( "Cannot stat file.\n" );
		fclose( fp );
		return NULL;
	}
	
	if( S_ISDIR( st.st_mode ) )
	{
		INFO( "Is a directory. Can not open.\n" );
		fclose( fp );
		return NULL;
	}
	
	LocFile* fo = (LocFile*) calloc( 1, sizeof(LocFile) );
	if( fo != NULL )
	{
		int len = strlen( path );
		fo->lf_Path = StringDuplicateN( path, len );
		fo->lf_Filename = GetFileNamePtr( path, len );
	
		fo->fp = fp;
		fseek( fp, 0L, SEEK_END );
		fo->filesize = ftell( fp );

		if( flags & FILE_READ_NOW )
		{
			LocFileRead( fo, 0, fo->filesize );
		}
	}
	else
	{
		ERROR("Cannot allocate memory for LocFile\n");
	}

	return fo;
}
Exemple #2
0
bool udtBaseParser::ParseSnapshot()
{
	//
	// Read in the new snapshot to a temporary buffer
	// We will only save it if it is valid.
	// We will have read any new server commands in this
	// message before we got to svc_snapshot.
	//

	if(_inProtocol == udtProtocol::Dm3)
	{
		_inMsg.ReadLong(); // Client command sequence.
	}

	_inServerTime = _inMsg.ReadLong();

	idLargestClientSnapshot newSnap;
	Com_Memset(&newSnap, 0, sizeof(newSnap));
	newSnap.serverCommandNum = _inServerCommandSequence;
	newSnap.serverTime = _inServerTime;
	newSnap.messageNum = _inServerMessageSequence;

	s32 deltaNum = _inMsg.ReadByte();
	if(!deltaNum) 
	{
		newSnap.deltaNum = -1;
	} 
	else 
	{
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}

	newSnap.snapFlags = _inMsg.ReadByte();

	//
	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message.
	//

	idClientSnapshotBase* oldSnap;
	if(newSnap.deltaNum <= 0) 
	{
		newSnap.valid = true; // Uncompressed frame.
		oldSnap = NULL;
	} 
	else 
	{
		if(deltaNum >= PACKET_BACKUP)
		{
			_context->LogWarning("udtBaseParser::ParseSnapshot: deltaNum %d invalid.", deltaNum);
		}

		if(newSnap.deltaNum > _inServerMessageSequence)
		{
			_context->LogWarning("udtBaseParser::ParseSnapshot: Need delta from read ahead.");
		}

		oldSnap = GetClientSnapshot(newSnap.deltaNum & PACKET_MASK);
		if(!oldSnap->valid) 
		{
			// Should never happen.
			_context->LogWarning("udtBaseParser::ParseSnapshot: Delta from invalid frame %d (not supposed to happen!).", deltaNum);
		} 
		else if(oldSnap->messageNum != newSnap.deltaNum) 
		{
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			_context->LogWarning("udtBaseParser::ParseSnapshot: Delta frame %d too old.", deltaNum);
		} 
		else if(_inParseEntitiesNum - oldSnap->parseEntitiesNum > ID_MAX_PARSE_ENTITIES - 128) 
		{
			_context->LogWarning("udtBaseParser::ParseSnapshot: Delta parseEntitiesNum %d too old.", _inParseEntitiesNum);
		} 
		else 
		{
			newSnap.valid = true;
		}
	}

	//
	// Read the area mask.
	//

	const s32 areaMaskLength = _inMsg.ReadByte();
	if(areaMaskLength > (s32)sizeof(newSnap.areamask))
	{
		_context->LogError("udtBaseParser::ParseSnapshot: Invalid size %d for areamask (in file: %s)", areaMaskLength, GetFileNamePtr());
		return false;
	}
	_inMsg.ReadData(&newSnap.areamask, areaMaskLength);
	
	// Read the player info.
	if(!_inMsg.ReadDeltaPlayer(oldSnap ? GetPlayerState(oldSnap, _inProtocol) : NULL, GetPlayerState(&newSnap, _inProtocol)))
	{
		return false;
	}

	// Read in all entities.
	if(!ParsePacketEntities(_inMsg, oldSnap, &newSnap))
	{
		return false;
	}

	// Did we write enough snapshots already?
	const bool noDelta = _outSnapshotsWritten < deltaNum;
	if(noDelta) 
	{
		deltaNum = 0;
		oldSnap = NULL;
	}

	// If not valid, dump the entire thing now that 
	// it has been properly read.
	if(!newSnap.valid)
	{
		return true;
	}

	//
	// Clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer.
	//

	s32 oldMessageNum = _inSnapshot.messageNum + 1;
	if(newSnap.messageNum - oldMessageNum >= PACKET_BACKUP)
	{
		oldMessageNum = newSnap.messageNum - (PACKET_BACKUP - 1);
	}

	for(; oldMessageNum < newSnap.messageNum; ++oldMessageNum)
	{
		GetClientSnapshot(oldMessageNum & PACKET_MASK)->valid = false;
	}

	// Copy to the current good spot.
	_inSnapshot = newSnap;

	// Save the frame off in the backup array for later delta comparisons.
	Com_Memcpy(GetClientSnapshot(_inSnapshot.messageNum & PACKET_MASK), &_inSnapshot, (size_t)_inProtocolSizeOfClientSnapshot);

	// Don't give the same stuff to the plug-ins more than once.
	if(newSnap.messageNum == _inLastSnapshotMessageNumber)
	{
		return true;
	}
	_inLastSnapshotMessageNumber = newSnap.messageNum;

	//
	// Process plug-ins now so that modifiers can alter the snapshots.
	//

	if(EnablePlugIns && !PlugIns.IsEmpty())
	{
		udtSnapshotCallbackArg info;
		info.ServerTime = _inServerTime;
		info.SnapshotArrayIndex = _inSnapshot.messageNum & PACKET_MASK;
		info.Snapshot = &newSnap;
		info.OldSnapshot = oldSnap;
		info.Entities = _inChangedEntities.GetStartAddress();
		info.EntityCount = _inChangedEntities.GetSize();
		info.RemovedEntities = _inRemovedEntities.GetStartAddress();
		info.RemovedEntityCount = _inRemovedEntities.GetSize();
		info.CommandNumber = newSnap.serverCommandNum;
		info.MessageNumber = newSnap.messageNum;

		for(u32 i = 0, count = PlugIns.GetSize(); i < count; ++i)
		{
			PlugIns[i]->ProcessSnapshotMessage(info, *this);
		}
	}

	//
	// Write to the output message.
	//

	if(ShouldWriteMessage())
	{
		_outMsg.WriteByte(svc_snapshot);
		_outMsg.WriteLong(newSnap.serverTime);
		_outMsg.WriteByte(deltaNum);
		_outMsg.WriteByte(newSnap.snapFlags);
		_outMsg.WriteByte(areaMaskLength);
		_outMsg.WriteData(&newSnap.areamask, areaMaskLength);
		_protocolConverter->StartSnapshot(newSnap.serverTime);
		if(_outProtocol == _inProtocol)
		{
			_outMsg.WriteDeltaPlayer(oldSnap ? GetPlayerState(oldSnap, _outProtocol) : NULL, GetPlayerState(&newSnap, _outProtocol));
			EmitPacketEntities(deltaNum ? oldSnap : NULL, &newSnap);
		}
		else
		{
			idLargestClientSnapshot oldSnapOutProto;
			idLargestClientSnapshot newSnapOutProto;
			if(oldSnap)
			{
				_protocolConverter->ConvertSnapshot(oldSnapOutProto, *oldSnap);
			}
			_protocolConverter->ConvertSnapshot(newSnapOutProto, newSnap);
			_outMsg.WriteDeltaPlayer(oldSnap ? GetPlayerState(&oldSnapOutProto, _outProtocol) : NULL, GetPlayerState(&newSnapOutProto, _outProtocol));
			EmitPacketEntities(deltaNum ? &oldSnapOutProto : NULL, &newSnapOutProto);
		}
		++_outSnapshotsWritten;
	}

	return true;
}
Exemple #3
0
bool udtBaseParser::ParseServerMessage()
{
	_outMsg.Init(_outMsgData, sizeof(_outMsgData));

	_outMsg.SetHuffman(_outProtocol >= udtProtocol::Dm66);
	_inMsg.SetHuffman(_inProtocol >= udtProtocol::Dm66);

	//
	// Using the message sequence number as acknowledge number will help avoid 
	// the command overflow playback error for dm3 and dm_48 demos converted to dm_68.
	// For reference in the Q3 source code: "Client command overflow".
	//
	s32 reliableSequenceAcknowledge = _inServerMessageSequence;
	if(_inProtocol > udtProtocol::Dm3)
	{
		const s32 sequAck = _inMsg.ReadLong(); // Reliable sequence acknowledge.
		if(_inProtocol >= udtProtocol::Dm68)
		{
			reliableSequenceAcknowledge = sequAck;
		}
	}
	_inReliableSequenceAcknowledge = reliableSequenceAcknowledge;
	if(ShouldWriteMessage())
	{
		_outMsg.WriteLong(_inReliableSequenceAcknowledge);
	}

	if(EnablePlugIns && !PlugIns.IsEmpty())
	{
		udtMessageBundleCallbackArg info;
		info.ReliableSequenceAcknowledge = reliableSequenceAcknowledge;
		for(u32 i = 0, count = PlugIns.GetSize(); i < count; ++i)
		{
			PlugIns[i]->ProcessMessageBundleStart(info, *this);
		}
	}

	for(;;)
	{
		if(_inMsg.Buffer.readcount > _inMsg.Buffer.cursize) 
		{
			_context->LogError("udtBaseParser::ParseServerMessage: Read past the end of the server message (in file: %s)", GetFileNamePtr());
			return false;
		}

		if(_inMsg.Buffer.readcount == _inMsg.Buffer.cursize)
		{
			break;
		}

		const s32 command = _inMsg.ReadByte();
		if(command == svc_EOF || (_inProtocol <= udtProtocol::Dm48 && command == svc_bad))
		{
			break;
		}

		// @NOTE: We don't write the command byte already, we leave that decision for later.

		switch(command) 
		{
		case svc_nop:
			if(ShouldWriteMessage())
			{
				_outMsg.WriteByte(svc_nop);
			}
			break;

		case svc_serverCommand:
			if(!ParseCommandString()) return false;
			break;

		case svc_gamestate:
			if(!ParseGamestate()) return false;
			break;

		case svc_snapshot:
			if(!ParseSnapshot()) return false;
			break;

		case svc_download:
		case svc_voip:
		default:
			_context->LogError("udtBaseParser::ParseServerMessage: Unrecognized server message command byte: %d (in file: %s)", command, GetFileNamePtr());
			return false;
		}

		if(_inProtocol <= udtProtocol::Dm48)
		{
			_inMsg.GoToNextByte();
		}
	}

	if(ShouldWriteMessage())
	{
		_outMsg.WriteByte(svc_EOF);
	}

	if(EnablePlugIns && !PlugIns.IsEmpty())
	{
		udtMessageBundleCallbackArg info;
		info.ReliableSequenceAcknowledge = reliableSequenceAcknowledge;
		for(u32 i = 0, count = PlugIns.GetSize(); i < count; ++i)
		{
			PlugIns[i]->ProcessMessageBundleEnd(info, *this);
		}
	}

	if(_cuts.GetSize() > 0)
	{
		const udtCutInfo cut = _cuts[0];
		const s32 gameTime = _inServerTime;

		if(_inGameStateIndex == cut.GameStateIndex && !_outWriteMessage &&
		   gameTime >= cut.StartTimeMs && gameTime <= cut.EndTimeMs)
		{
			const bool wroteMessage = _outWriteMessage;
			_outWriteMessage = true;
			_outWriteFirstMessage = _outWriteMessage && !wroteMessage;
		}
		else if((_inGameStateIndex == cut.GameStateIndex && _outWriteMessage && gameTime > cut.EndTimeMs) ||
				(_inGameStateIndex > cut.GameStateIndex && _outWriteMessage))
		{
			WriteLastMessage();
			_outWriteMessage = false;
			_outWriteFirstMessage = false;
			_outServerCommandSequence = 0;
			_outSnapshotsWritten = 0;
			_outFile.Close();
			_cuts.Remove(0);
			if(_cuts.GetSize() == 0)
			{
				// It was the last cut, we're done parsing the file now.
				return false;
			}
		}
	}

	if(_outWriteFirstMessage)
	{
		udtCutInfo& cut = _cuts[0];
		udtString filePath;
		if(cut.FilePath != NULL)
		{
			filePath = udtString::NewConstRef(cut.FilePath);
		}
		else
		{
			udtDemoStreamCreatorArg info;
			memset(&info, 0, sizeof(info));
			info.StartTimeMs = cut.StartTimeMs;
			info.EndTimeMs = cut.EndTimeMs;
			info.Parser = this;
			info.VeryShortDesc = cut.VeryShortDesc;
			info.UserData = cut.UserData;
			info.TempAllocator = &_tempAllocator;
			info.FilePathAllocator = &_persistentAllocator;
			filePath = (*cut.StreamCreator)(info);
		}
		_outFile.Close();
		if(_outFile.Open(filePath.GetPtr(), udtFileOpenMode::Write))
		{
			_outFilePath = filePath;
			udtPath::GetFileName(_outFileName, _persistentAllocator, filePath);
			_outMsg.SetFileName(_outFileName);
			WriteFirstMessage();
			_outWriteFirstMessage = false;
		}
		else
		{
			_cuts.Remove(0);
		}
	}
	else if(_outWriteMessage)
	{
		WriteNextMessage();
	}

	return true;
}
Exemple #4
0
bool udtBaseParser::ParseGamestate()
{
	// @TODO: Reset some data, but not for the 1st gamestate message.
	ResetForGamestateMessage();

	// A game state always marks a server command sequence.
	_inServerCommandSequence = _inMsg.ReadLong();

	//
	// Parse all the config strings and baselines.
	//

	for(;;)
	{
		const s32 command = _inMsg.ReadByte();

		if(_inProtocol <= udtProtocol::Dm48 && command == svc_bad)
		{
			break;
		}

		if(command == svc_EOF)
		{
			break;
		}

		if(command == svc_configstring)
		{
			const s32 index = _inMsg.ReadShort();
			if(index < 0 || index >= MAX_CONFIGSTRINGS) 
			{
				_context->LogError("udtBaseParser::ParseGamestate: Config string index out of range: %d (in file: %s)", index, GetFileNamePtr());
				return false;
			}

			s32 configStringLength = 0;
			const char* const configStringTemp = _inMsg.ReadBigString(configStringLength);
			
			// Copy the string to a safe location.
			_inConfigStrings[index] = udtString::NewClone(_configStringAllocator, configStringTemp, configStringLength);
		} 
		else if(command == svc_baseline)
		{
			const s32 newIndex = _inMsg.ReadBits(GENTITYNUM_BITS);
			if(newIndex < 0 || newIndex >= MAX_GENTITIES) 
			{
				_context->LogError("udtBaseParser::ParseGamestate: Baseline number out of range: %d (in file: %s)", newIndex, GetFileNamePtr());
				return false;
			}
			
			idLargestEntityState nullState;
			idEntityStateBase* const newState = GetBaseline(newIndex);

			// We delta from the null state because we read a full entity.
			Com_Memset(&nullState, 0, sizeof(nullState));
			bool addedOrChanged = false;
			if(!_inMsg.ReadDeltaEntity(addedOrChanged, &nullState, newState, newIndex))
			{
				return false;
			}
		} 
		else 
		{
			_context->LogError("udtBaseParser::ParseGamestate: Unrecognized command byte: %d (in file: %s)", command, GetFileNamePtr());
			return false;
		}
	}

	if(_inProtocol >= udtProtocol::Dm66)
	{
		_inClientNum = _inMsg.ReadLong();
		_inChecksumFeed = _inMsg.ReadLong();
	}
	else
	{
		_inClientNum = -1;
		_inChecksumFeed = 0;
	}

	if(EnablePlugIns && !PlugIns.IsEmpty())
	{
		udtGamestateCallbackArg info;
		info.ServerCommandSequence = _inServerCommandSequence;
		info.ClientNum = _inClientNum;
		info.ChecksumFeed = _inChecksumFeed;

		for(u32 i = 0, count = PlugIns.GetSize(); i < count; ++i)
		{
			PlugIns[i]->ProcessGamestateMessage(info, *this);
		}
	}

	++_inGameStateIndex;
	_inGameStateFileOffsets.Add(_inFileOffset);

	return true;
}
Exemple #5
0
/**
 * Create new LocFile structure and read file from provided path
 *
 * @param path pointer to char table with path
 * @param flags additional flags used to open file
 * @return pointer to new LocFile when success, otherwise NULL
 */
LocFile* LocFileNew( char* path, unsigned int flags )
{
	if( path == NULL )
	{
		FERROR("File path is null\n");
		return NULL;
	}
	FILE* fp = fopen( path, "rb" );
	if( fp == NULL )
	{
		FERROR("Cannot open file %s (file does not exist?)..\n", path );
		return NULL;
	}
	
	struct stat st;
	if( stat( path, &st ) < 0 )
	{
		FERROR( "Cannot stat file: '%s'.\n", path );
		fclose( fp );
		return NULL;
	}
	
	if( S_ISDIR( st.st_mode ) )
	{
		FERROR( "'%s' is a directory. Can not open.\n", path );
		fclose( fp );
		return NULL;
	}
	DEBUG("Read local file %s\n", path );
	
	LocFile* fo = (LocFile*) FCalloc( 1, sizeof(LocFile) );
	if( fo != NULL )
	{
		fo->lf_PathLength = strlen( path );
		fo->lf_Path = StringDuplicateN( path, fo->lf_PathLength );
		fo->lf_Filename = StringDuplicate( GetFileNamePtr( path, fo->lf_PathLength ) );
		
		MURMURHASH3( fo->lf_Path, fo->lf_PathLength, fo->hash );
		
		DEBUG("PATH: %s\n", fo->lf_Path );
		
		memcpy(  &(fo->lf_Info),  &st, sizeof( struct stat) );

		fseek( fp, 0, SEEK_END );
		long fsize = ftell( fp );
		fseek( fp, 0, SEEK_SET );  //same as rewind(f);
		fo->lf_FileSize = fsize;// st.st_size; //ftell( fp );

		if( flags & FILE_READ_NOW )
		{
#if LOCFILE_USE_MMAP == 0
			LocFileRead( fo, fp, 0, fo->lf_FileSize );
#else

			fo->lf_Buffer = mmap(NULL/*address can be anywhere*/,
					fo->lf_FileSize/*map whole file*/,
					PROT_READ,
					MAP_SHARED | MAP_POPULATE,
					fileno(fp),
					0/*beginning of file*/);
			//DEBUG("***************** Mapping length: %d at %p\n", fo->lf_FileSize, fo->lf_Buffer);

#endif
		}
	}
	else
	{
		FERROR("Cannot allocate memory for LocFile\n");
	}
	
#if LOCFILE_USE_MMAP == 0
	fclose( fp );
#endif
	
	return fo;
}