示例#1
0
void ReadyEvent::SendReadyStateQuery(unsigned eventId, SystemAddress address)
{
	RakNet::BitStream bs;
	bs.Write((MessageID)ID_READY_EVENT_QUERY);
	bs.Write(eventId);
	SendUnified(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, channel, address, false);
}
示例#2
0
void ConnectionGraph::OnConnectionGraphRequest(Packet *packet)
{
	char password[256];
	RakNet::BitStream inBitstream(packet->data, packet->length, false);
	inBitstream.IgnoreBits(8);
	stringCompressor->DecodeString(password,256,&inBitstream);
	if (pw && pw[0] && strcmp(pw, password)!=0)
		return;

#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
	RAKNET_DEBUG_PRINTF("ID_CONNECTION_GRAPH_REPLY ");
#endif

	RakNet::BitStream outBitstream;
	outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_REPLY);
	stringCompressor->EncodeString(pw,256,&outBitstream);
	SerializeWeightedGraph(&outBitstream, graph);
	SendUnified(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, packet->systemAddress, false);

#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
	RAKNET_DEBUG_PRINTF("from %i to %i\n", peer->GetInternalID().port, packet->systemAddress.port);
#endif

	// Add packet->systemAddress to the participant list if it is not already there
	AddParticipant(packet->systemAddress);
}
示例#3
0
void ConnectionGraph2::OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
{
	(void) isIncoming;

	// Send all existing systems to new connection
	RakNet::BitStream bs;
	bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
	bs.Write((unsigned int)1);
	bs.Write(systemAddress);
	bs.Write(rakNetGUID);
	SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true);

	// Send everyone to the new guy
	DataStructures::List<SystemAddress> addresses;
	DataStructures::List<RakNetGUID> guids;
	rakPeerInterface->GetSystemList(addresses, guids);
	bs.Reset();
	bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
	BitSize_t writeOffset = bs.GetWriteOffset();
	bs.Write((unsigned int) addresses.Size());

	unsigned int i;
	unsigned int count=0;
	for (i=0; i < addresses.Size(); i++)
	{
		if (addresses[i]==systemAddress)
			continue;
		
		bs.Write(addresses[i]);
		bs.Write(guids[i]);
		count++;
	}

	if (count>0)
	{
		BitSize_t writeOffset2 = bs.GetWriteOffset();
		bs.SetWriteOffset(writeOffset);
		bs.Write(count);
		bs.SetWriteOffset(writeOffset2);
		SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,false);
	}

	RemoteSystem* remoteSystem = RakNet::OP_NEW<RemoteSystem>(__FILE__,__LINE__);
	remoteSystem->guid=rakNetGUID;
	remoteSystems.Insert(rakNetGUID,remoteSystem,true,__FILE__,__LINE__);
}
示例#4
0
void RakVoice::RequestVoiceChannel(RakNetGUID recipient)
{
	// Send a reliable ordered message to the other system to open a voice channel
	RakNet::BitStream out;
	out.Write((unsigned char)ID_RAKVOICE_OPEN_CHANNEL_REQUEST);
	out.Write((int32_t)sampleRate);
	SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,recipient,false);	
}
示例#5
0
void RakVoice::CloseVoiceChannel(RakNetGUID recipient)
{
	FreeChannelMemory(recipient);
	
	// Send a message to the remote system telling them to close the channel
	RakNet::BitStream out;
	out.Write((unsigned char)ID_RAKVOICE_CLOSE_CHANNEL);
	SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,recipient,false);	
}
示例#6
0
void ReadyEvent::SendReadyUpdate(unsigned eventIndex, unsigned systemIndex, bool forceIfNotDefault)
{
	ReadyEventNode *ren = readyEventNodeList[eventIndex];
	RakNet::BitStream bs;
	// I do this rather than write true or false, so users that do not use BitStreams can still read the data
	if ((ren->eventStatus != ren->systemList[systemIndex].lastSentStatus) ||
	    (forceIfNotDefault && ren->eventStatus != ID_READY_EVENT_UNSET)) {
		bs.Write(ren->eventStatus);
		bs.Write(ren->eventId);
		SendUnified(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, channel, ren->systemList[systemIndex].systemAddress, false);
		ren->systemList[systemIndex].lastSentStatus = ren->eventStatus;
	}
}
示例#7
0
void Router::SendTree(PacketPriority priority, PacketReliability reliability, char orderingChannel, DataStructures::Tree<ConnectionGraph::SystemAddressAndGroupId> *tree, const char *data, BitSize_t bitLength, RakNet::BitStream *out, SystemAddressList *recipients)
{
	BitSize_t outputOffset;

	// Write routing identifer
	out->Write((MessageID)ID_ROUTE_AND_MULTICAST);

	// Write the send parameters
	out->WriteCompressed((unsigned char)priority);
	out->WriteCompressed((unsigned char)reliability);
	out->WriteCompressed((unsigned char)orderingChannel);

	// Write the user payload length
	out->Write((unsigned int)bitLength);
//	out->PrintBits();
//	payload->PrintBits();

	out->AlignWriteToByteBoundary();
//	payload->AlignReadToByteBoundary();
//	out->Write(payload, payload->GetNumberOfUnreadBits());
//	out->PrintBits();
	if ((bitLength % 8)==0)
		out->Write(data, BITS_TO_BYTES(bitLength));
	else
		out->WriteBits((const unsigned char*)data, bitLength, false);

	// Save where to start writing per-system data
	outputOffset=out->GetWriteOffset();

	// Write every child of the root of the tree (SystemAddress, isRecipient, branch)
	unsigned i;
	for (i=0; i < tree->children.Size(); i++)
	{
		// Start writing at the per-system data byte
		out->SetWriteOffset(outputOffset);

		// Write our external IP to designate the sender
		out->Write(rakPeerInterface->GetExternalID(tree->children[i]->data.systemAddress));

		// Serialize the tree
		SerializePreorder(tree->children[i], out, recipients);

		// Send to the first hop
#ifdef _DO_PRINTF
		RAKNET_DEBUG_PRINTF("%i sending to %i\n", rakPeerInterface->GetExternalID(tree->children[i]->data.systemAddress).port, tree->children[i]->data.systemAddress.port);
#endif
		SendUnified(out, priority, reliability, orderingChannel, tree->children[i]->data.systemAddress, false);
	}
}
示例#8
0
void RakVoice::CloseAllChannels(void)
{
	RakNet::BitStream out;
	out.Write((unsigned char)ID_RAKVOICE_CLOSE_CHANNEL);

	// Free the memory for all channels
	unsigned index;
	for (index=0; index < voiceChannels.Size(); index++)
	{
		SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,voiceChannels[index]->guid,false);	
		FreeChannelMemory(index,false);
	}

	voiceChannels.Clear(false, __FILE__, __LINE__);
}
示例#9
0
void RakVoice::OnOpenChannelRequest(Packet *packet)
{
	if (voiceChannels.HasData(packet->guid))
		return;

	// If the system is not initialized, just return
	if (bufferedOutput==0)
		return;

	OpenChannel(packet);

	RakNet::BitStream out;
	out.Write((unsigned char)ID_RAKVOICE_OPEN_CHANNEL_REPLY);
	out.Write((int32_t)sampleRate);
	SendUnified(&out, HIGH_PRIORITY, RELIABLE_ORDERED,0,packet->systemAddress,false);	
}
示例#10
0
void ConnectionGraph::OnConnectionGraphReply(Packet *packet)
{
	unsigned char password[256];
	RakNet::BitStream inBitstream(packet->data, packet->length, false);
	inBitstream.IgnoreBits(8);
	stringCompressor->DecodeString((char*)password,256,&inBitstream);
	if (pw && pw[0] && strcmp(pw, (const char*)password)!=0)
		return;

	// Serialize the weighted graph and send it to them
	RakNet::BitStream outBitstream;
	outBitstream.Write((MessageID)ID_CONNECTION_GRAPH_UPDATE);

#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
	RAKNET_DEBUG_PRINTF("ID_CONNECTION_GRAPH_UPDATE ");
#endif

	// Send our current graph to the sender
	SerializeWeightedGraph(&outBitstream, graph);


	// Write the systems that have processed this graph so we don't resend to these systems
	outBitstream.Write((unsigned short) 1);
	outBitstream.Write(rakPeerInterface->GetExternalID(packet->systemAddress));

#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
	RAKNET_DEBUG_PRINTF("from %i to %i\n", peer->GetInternalID().port, packet->systemAddress.port);
#endif

	SendUnified(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, packet->systemAddress, false);

	// Add packet->systemAddress to the participant list if it is not already there
	AddParticipant(packet->systemAddress);

	if (DeserializeWeightedGraph(&inBitstream, rakPeerInterface)==false)
		return;

	// Forward the updated graph to all current participants
	DataStructures::OrderedList<SystemAddress,SystemAddress> ignoreList;
	ignoreList.Insert(packet->systemAddress,packet->systemAddress, true, __FILE__, __LINE__);
	BroadcastGraphUpdate(ignoreList, rakPeerInterface);
}
示例#11
0
void ConnectionGraph2::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{
	// Send notice to all existing connections
	RakNet::BitStream bs;
	if (lostConnectionReason==LCR_CONNECTION_LOST)
		bs.Write((MessageID)ID_REMOTE_CONNECTION_LOST);
	else
		bs.Write((MessageID)ID_REMOTE_DISCONNECTION_NOTIFICATION);
	bs.Write(systemAddress);
	bs.Write(rakNetGUID);
	SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true);

	bool objectExists;
	unsigned int idx = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists);
	if (objectExists)
	{
		RakNet::OP_DELETE(remoteSystems[idx],__FILE__,__LINE__);
		remoteSystems.RemoveAtIndex(idx);
	}
}
void LightweightDatabaseServer::OnQueryRequest(Packet *packet)
{
	RakNet::BitStream inBitstream(packet->data, packet->length, false);
	LightweightDatabaseServer::DatabaseTable *databaseTable = DeserializeClientHeader(&inBitstream, rakPeerInterface, packet, 0);
	if (databaseTable==0)
		return;
	if (databaseTable->allowRemoteQuery==false)
		return;
	unsigned char numColumnSubset;
	RakNet::BitStream outBitstream;
	unsigned i;
	if (inBitstream.Read(numColumnSubset)==false)
		return;
	unsigned char columnName[256];
	unsigned columnIndicesSubset[256];
	unsigned columnIndicesCount;
	for (i=0,columnIndicesCount=0; i < numColumnSubset; i++)
		{
		stringCompressor->DecodeString((char*)columnName, 256, &inBitstream);
		unsigned colIndex = databaseTable->table.ColumnIndex((char*)columnName);
		if (colIndex!=(unsigned)-1)
			columnIndicesSubset[columnIndicesCount++]=colIndex;
		}
	unsigned char numNetworkedFilters;
	if (inBitstream.Read(numNetworkedFilters)==false)
		return;
	DatabaseFilter networkedFilters[256];
	for (i=0; i < numNetworkedFilters; i++)
		{
		if (networkedFilters[i].Deserialize(&inBitstream)==false)
			return;
		}

	unsigned rowIds[256];
	unsigned char numRowIDs;
	if (inBitstream.Read(numRowIDs)==false)
		return;
	for (i=0; i < numRowIDs; i++)
		inBitstream.Read(rowIds[i]);

	// Convert the safer and more robust networked database filter to the more efficient form the table actually uses.
	DataStructures::Table::FilterQuery tableFilters[256];
	unsigned numTableFilters=0;
	for (i=0; i < numNetworkedFilters; i++)
		{
		tableFilters[numTableFilters].columnIndex=databaseTable->table.ColumnIndex(networkedFilters[i].columnName);
		if (tableFilters[numTableFilters].columnIndex==(unsigned)-1)
			continue;
		if (networkedFilters[i].columnType!=databaseTable->table.GetColumns()[tableFilters[numTableFilters].columnIndex].columnType)
			continue;
		tableFilters[numTableFilters].operation=networkedFilters[i].operation;
		// It's important that I store a pointer to the class here or the destructor of the class will deallocate the cell twice
		tableFilters[numTableFilters++].cellValue=&(networkedFilters[i].cellValue);
		}

	DataStructures::Table queryResult;
	databaseTable->table.QueryTable(columnIndicesSubset, columnIndicesCount, tableFilters, numTableFilters, rowIds, numRowIDs, &queryResult);
	outBitstream.Write((MessageID)ID_DATABASE_QUERY_REPLY);
	TableSerializer::SerializeTable(&queryResult, &outBitstream);
	SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
}
示例#13
0
void RakVoice::Update(void)
{
	unsigned i,j, bytesAvailable, speexFramesAvailable, speexBlockSize;
	unsigned bytesWaitingToReturn;
	int bytesWritten;
	VoiceChannel *channel;
	char *inputBuffer;
	char tempOutput[2048];
	// 1 byte for ID, and 2 bytes(short) for Message number
	static const int headerSize=sizeof(unsigned char) + sizeof(unsigned short);
	// First byte is ID for RakNet
	tempOutput[0]=ID_RAKVOICE_DATA;
	
	RakNetTime currentTime = RakNet::GetTime();

	// Size of VoiceChannel::incomingBuffer and VoiceChannel::outgoingBuffer arrays
	unsigned totalBufferSize=bufferSizeBytes * FRAME_OUTGOING_BUFFER_COUNT;
	
	// Allow all channels to write, and set the output to zero in preparation
	if (zeroBufferedOutput)
	{
		for (i=0; i < bufferedOutputCount; i++)
			bufferedOutput[i]=0.0f;
		for (i=0; i < voiceChannels.Size(); i++)
			voiceChannels[i]->copiedOutgoingBufferToBufferedOutput=false;
		zeroBufferedOutput=false;
	}

	// For each channel
	for (i=0; i < voiceChannels.Size(); i++)
	{
		channel=voiceChannels[i];

		if (currentTime - channel->lastSend > 50) // Throttle to 20 sends a second
		{
			channel->isSendingVoiceData=false;

			// Circular buffer so I have to do this to count how many bytes are available
			if (channel->outgoingWriteIndex>=channel->outgoingReadIndex)
				bytesAvailable=channel->outgoingWriteIndex-channel->outgoingReadIndex;
			else
				bytesAvailable=channel->outgoingWriteIndex + (totalBufferSize-channel->outgoingReadIndex);

			// Speex returns how many frames it encodes per block.  Each frame is of byte length sampleSize.
			speexBlockSize = channel->speexOutgoingFrameSampleCount * SAMPLESIZE;

#ifdef PRINT_DEBUG_INFO
			static int lastPrint=0;
			if (i==0 && currentTime-lastPrint > 2000)
			{
				lastPrint=currentTime;
				unsigned bytesWaitingToReturn;
				if (channel->incomingReadIndex <= channel->incomingWriteIndex)
					bytesWaitingToReturn=channel->incomingWriteIndex-channel->incomingReadIndex;
				else
					bytesWaitingToReturn=totalBufferSize-channel->incomingReadIndex+channel->incomingWriteIndex;

				printf("%i bytes to send. incomingMessageNumber=%i. bytesWaitingToReturn=%i.\n", bytesAvailable, channel->incomingMessageNumber, bytesWaitingToReturn );
			}
#endif

#ifdef _TEST_LOOPBACK
			/*
			if (bufferSizeBytes<bytesAvailable)
			{
				printf("Update: bytesAvailable=%i writeIndex=%i readIndex=%i\n",bytesAvailable, channel->outgoingWriteIndex, channel->outgoingReadIndex);
				memcpy(channel->incomingBuffer + channel->incomingWriteIndex, channel->outgoingBuffer+channel->outgoingReadIndex, bufferSizeBytes);
				channel->incomingWriteIndex=(channel->incomingWriteIndex+bufferSizeBytes) % totalBufferSize;
				channel->outgoingReadIndex=(channel->outgoingReadIndex+bufferSizeBytes) % totalBufferSize;
			}
			return;
			*/
#endif

			// Find out how many frames we can read out of the buffer for speex to encode and send these out.
			speexFramesAvailable = bytesAvailable / speexBlockSize;

			// Encode all available frames and send them unreliable sequenced
			if (speexFramesAvailable > 0)
			{
				SpeexBits speexBits;
				speex_bits_init(&speexBits);
				while (speexFramesAvailable-- > 0)
				{
					speex_bits_reset(&speexBits);

					// If the input data would wrap around the buffer, copy it to another buffer first
					if (channel->outgoingReadIndex + speexBlockSize >= totalBufferSize)
					{
#ifdef _DEBUG
						RakAssert(speexBlockSize < 2048-1);
#endif
						unsigned t;
						for (t=0; t < speexBlockSize; t++)
							tempOutput[t+headerSize]=channel->outgoingBuffer[t%totalBufferSize];
						inputBuffer=tempOutput+headerSize;
					}
					else
						inputBuffer=channel->outgoingBuffer+channel->outgoingReadIndex;

#ifdef _DEBUG
					/*
					printf("In: ");
					if (shortSampleType)
					{
						short *blah = (short*) inputBuffer;
						for (int p=0; p < 5; p++)
						{
							printf("%.i ", blah[p]);
						}
					}
					else
					{
						float *blah = (float*) inputBuffer;
						for (int p=0; p < 5; p++)
						{
							printf("%.3f ", blah[p]);
						}
					}

					printf("\n");
*/
#endif
					int is_speech=1;

					// Run preprocessor if required
					if (defaultDENOISEState||defaultVADState){
						is_speech=speex_preprocess((SpeexPreprocessState*)channel->pre_state,(spx_int16_t*) inputBuffer, NULL );
					}

					if ((is_speech)||(!defaultVADState)){
						is_speech = speex_encode_int(channel->enc_state, (spx_int16_t*) inputBuffer, &speexBits);
					}

					channel->outgoingReadIndex=(channel->outgoingReadIndex+speexBlockSize)%totalBufferSize;

					// If no speech detected, don't send this frame
					if ((!is_speech)&&(defaultVADState)){
						continue;
					}

					channel->isSendingVoiceData=true;

#ifdef _DEBUG
//					printf("Update: bytesAvailable=%i writeIndex=%i readIndex=%i\n",bytesAvailable, channel->outgoingWriteIndex, channel->outgoingReadIndex);
#endif

					bytesWritten = speex_bits_write(&speexBits, tempOutput+headerSize, 2048-headerSize);
#ifdef _DEBUG
					// If this assert hits then you need to increase the size of the temp buffer, but this is really a bug because
					// voice packets should never be bigger than a few hundred bytes.
					RakAssert(bytesWritten!=2048-headerSize);
#endif

//					static int bytesSent=0;
//					bytesSent+= bytesWritten+headerSize;
//					printf("bytesSent=%i\n", bytesSent);

#ifdef PRINT_DEBUG_INFO
static int voicePacketsSent=0;
printf("%i ", voicePacketsSent++);
#endif

					// at +1, because the first byte in the buffer has the ID for RakNet.
					memcpy(tempOutput+1, &channel->outgoingMessageNumber, sizeof(unsigned short));
					channel->outgoingMessageNumber++;
					RakNet::BitStream tempOutputBs((unsigned char*) tempOutput,bytesWritten+headerSize,false);
					SendUnified(&tempOutputBs, HIGH_PRIORITY, UNRELIABLE,0,channel->guid,false);

					if (loopbackMode)
					{
						Packet p;
						p.length=bytesWritten+1;
						p.data=(unsigned char*)tempOutput;
						p.guid=channel->guid;
						p.systemAddress=rakPeerInterface->GetSystemAddressFromGuid(p.guid);
						OnVoiceData(&p);
					}
				}

				speex_bits_destroy(&speexBits);
				channel->lastSend=currentTime;
			}
		}

		// As sound buffer blocks fill up, I add their values to RakVoice::bufferedOutput .  Then when the user calls ReceiveFrame they get that value, already
		// processed.  This is necessary because that function needs to run as fast as possible so I remove all processing there that I can.  Otherwise the sound
		// plays back distorted and popping
		if (channel->copiedOutgoingBufferToBufferedOutput==false)
		{
			if (channel->incomingReadIndex <= channel->incomingWriteIndex)
				bytesWaitingToReturn=channel->incomingWriteIndex-channel->incomingReadIndex;
			else
				bytesWaitingToReturn=totalBufferSize-channel->incomingReadIndex+channel->incomingWriteIndex;

			if (bytesWaitingToReturn==0)
			{
				channel->bufferOutput=true;
			}
			else if (channel->bufferOutput==false || bytesWaitingToReturn > bufferSizeBytes*2)
			{
				// Block running this again until the user calls ReceiveFrame since every call to ReceiveFrame only gets zero or one output blocks from
				// each channel
				channel->copiedOutgoingBufferToBufferedOutput=true;

				// Stop buffering output.  We won't start buffering again until there isn't enough data to read.
				channel->bufferOutput=false;

				// Cap to the size of the output buffer.  But we do write less if less is available, with the rest silence
				if (bytesWaitingToReturn > bufferSizeBytes)
				{
					bytesWaitingToReturn=bufferSizeBytes;
				}
				else
				{
					// Align the write index so when we increment the partial block read (which is always aligned) it computes out to 0 bytes waiting
					channel->incomingWriteIndex=channel->incomingReadIndex+bufferSizeBytes;
					if (channel->incomingWriteIndex==totalBufferSize)
						channel->incomingWriteIndex=0;
				}

				short *in = (short *) (channel->incomingBuffer+channel->incomingReadIndex);
				for (j=0; j < bytesWaitingToReturn / SAMPLESIZE; j++)
				{
					// Write short to float so if the range goes over the range of a float we can still add and subtract the correct final value.
					// It will be clamped at the end
					bufferedOutput[j]+=in[j%(totalBufferSize/SAMPLESIZE)];
				}

				// Update the read index.  Always update by bufferSizeBytes, not bytesWaitingToReturn.
				// if bytesWaitingToReturn < bufferSizeBytes then the rest is silence since this means the buffer ran out or we stopped sending.
				channel->incomingReadIndex+=bufferSizeBytes;
				if (channel->incomingReadIndex==totalBufferSize)
					channel->incomingReadIndex=0;

			//	printf("%f %f\n", channel->incomingReadIndex/(float)bufferSizeBytes, channel->incomingWriteIndex/(float)bufferSizeBytes);
			}
		}
	}
}
void AutopatcherServer::Update(void)
{
	ResultTypeAndBitstream* rtab;
	while (threadPool.HasOutputFast() && threadPool.HasOutput())
	{
		rtab = threadPool.GetOutput();
		if (rtab->operation==ResultTypeAndBitstream::GET_PATCH)
		{
			if (rtab->fatalError==false)
			{
				if (rtab->patchList->fileList.Size())
					fileListTransfer->Send(rtab->patchList, 0, rtab->systemAddress, rtab->setId, priority, orderingChannel, false, repository);

				rtab->bitStream1.Write((unsigned char) ID_AUTOPATCHER_FINISHED_INTERNAL);
				stringCompressor->EncodeString(rtab->currentDate.C_String(),64,&rtab->bitStream1);
			}
			else
			{
				rtab->bitStream1.Write((unsigned char) ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR);
				stringCompressor->EncodeString(repository->GetLastError(), 256, &rtab->bitStream1);
			}
			RakNet::OP_DELETE(rtab->patchList, __FILE__, __LINE__);
		}
		else if (rtab->operation==ResultTypeAndBitstream::GET_CHANGELIST_SINCE_DATE)
		{
			if (rtab->fatalError==false)
			{
				if (rtab->deletedFiles->fileList.Size())
				{
					rtab->bitStream1.Write((unsigned char) ID_AUTOPATCHER_DELETION_LIST);
					rtab->deletedFiles->Serialize(&rtab->bitStream1);
				}

				if (rtab->addedFiles->fileList.Size())
				{
					rtab->bitStream2.Write((unsigned char) ID_AUTOPATCHER_CREATION_LIST);
					rtab->addedFiles->Serialize(&rtab->bitStream2);
					stringCompressor->EncodeString(rtab->currentDate.C_String(),64,&rtab->bitStream2);
					rtab->addedFiles->Clear();
				}
				else
				{
					rtab->bitStream2.Write((unsigned char) ID_AUTOPATCHER_FINISHED);
					stringCompressor->EncodeString(rtab->currentDate.C_String(),64,&rtab->bitStream2);
				}
			}
			else
			{
				rtab->bitStream2.Write((unsigned char) ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR);
				stringCompressor->EncodeString(repository->GetLastError(), 256, &rtab->bitStream2);	
			}
			RakNet::OP_DELETE(rtab->deletedFiles, __FILE__, __LINE__);
			RakNet::OP_DELETE(rtab->addedFiles, __FILE__, __LINE__);
		}
		if (rtab->bitStream1.GetNumberOfBitsUsed()>0)
			SendUnified(&(rtab->bitStream1), priority, RELIABLE_ORDERED, orderingChannel, rtab->systemAddress, false);
		if (rtab->bitStream2.GetNumberOfBitsUsed()>0)
			SendUnified(&(rtab->bitStream2), priority, RELIABLE_ORDERED, orderingChannel, rtab->systemAddress, false);
		RakNet::OP_DELETE(rtab, __FILE__, __LINE__);
	}	
}
void FileListTransfer::Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
{
	(void) compressData;

	if (callback)
		fileList->SetCallback(callback);

	unsigned int i, totalLength;
	RakNet::BitStream outBitstream;
	bool sendReference;
	char *dataBlocks[2];
	int lengths[2];
	totalLength=0;
	for (i=0; i < fileList->fileList.Size(); i++)
	{
		const FileListNode &fileListNode = fileList->fileList[i];
		totalLength+=fileListNode.fileLengthBytes;
	}

	// Write the chunk header, which contains the frequency table, the total number of files, and the total number of bytes
	bool anythingToWrite;
	outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_HEADER);
	outBitstream.Write(setID);
	anythingToWrite=fileList->fileList.Size()>0;
	outBitstream.Write(anythingToWrite);
	if (anythingToWrite)
	{
		outBitstream.WriteCompressed(fileList->fileList.Size());
		outBitstream.WriteCompressed(totalLength);

		if (rakPeer)
			rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		else
			SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
	
		for (i=0; i < fileList->fileList.Size(); i++)
		{
			outBitstream.Reset();
			sendReference = fileList->fileList[i].isAReference && _incrementalReadInterface!=0;
			if (sendReference)
			{
				StoreForPush(fileList->fileList[i].context, setID, fileList->fileList[i].filename, fileList->fileList[i].fullPathToFile, i, fileList->fileList[i].fileLengthBytes, fileList->fileList[i].dataLengthBytes, recipient, priority, orderingChannel, _incrementalReadInterface, _chunkSize);
				continue;
			}

			outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);
			
			outBitstream.Write(fileList->fileList[i].context);
			outBitstream.Write(setID);
			stringCompressor->EncodeString(fileList->fileList[i].filename, 512, &outBitstream);
			
			outBitstream.WriteCompressed(i);
			outBitstream.WriteCompressed(fileList->fileList[i].dataLengthBytes); // Original length in bytes

			outBitstream.AlignWriteToByteBoundary();

			dataBlocks[0]=(char*) outBitstream.GetData();
			lengths[0]=outBitstream.GetNumberOfBytesUsed();
			dataBlocks[1]=fileList->fileList[i].data;
			lengths[1]=fileList->fileList[i].dataLengthBytes;
			if (rakPeer)
				rakPeer->SendList(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
			else
				SendListUnified(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		}
	}
	else
	{
		if (rakPeer)
			rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		else
			SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
	}
}
void FileListTransfer::OnReferencePush(Packet *packet, bool fullFile)
{
	// fullFile is always true for TCP, since TCP does not return SPLIT_PACKET_NOTIFICATION

	RakNet::BitStream refPushAck;
	refPushAck.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH_ACK);
	SendUnified(&refPushAck,HIGH_PRIORITY, RELIABLE, 0, packet->systemAddress, false);

	FileListTransferCBInterface::OnFileStruct onFileStruct;
	RakNet::BitStream inBitStream(packet->data, packet->length, false);
	inBitStream.IgnoreBits(8);

	unsigned int partCount=0;
	unsigned int partTotal=1;
	unsigned int partLength=0;
	onFileStruct.fileData=0;
	if (fullFile==false)
	{
		// Disable endian swapping on reading this, as it's generated locally in ReliabilityLayer.cpp
		inBitStream.ReadBits( (unsigned char* ) &partCount, BYTES_TO_BITS(sizeof(partCount)), true );
		inBitStream.ReadBits( (unsigned char* ) &partTotal, BYTES_TO_BITS(sizeof(partTotal)), true );
		inBitStream.ReadBits( (unsigned char* ) &partLength, BYTES_TO_BITS(sizeof(partLength)), true );
		inBitStream.IgnoreBits(8);
		// The header is appended to every chunk, which we continue to read after this statement block
	}

	inBitStream.Read(onFileStruct.context);
	inBitStream.Read(onFileStruct.setID);
	FileListReceiver *fileListReceiver;
	if (fileListReceivers.Has(onFileStruct.setID)==false)
	{
		return;
	}
	fileListReceiver=fileListReceivers.Get(onFileStruct.setID);
	if (fileListReceiver->allowedSender!=packet->systemAddress)
	{
#ifdef _DEBUG
		RakAssert(0);
#endif
		return;
	}

#ifdef _DEBUG
	RakAssert(fileListReceiver->gotSetHeader==true);
#endif

	if (stringCompressor->DecodeString(onFileStruct.fileName, 512, &inBitStream)==false)
	{
#ifdef _DEBUG
		RakAssert(0);
#endif
		return;
	}

	inBitStream.ReadCompressed(onFileStruct.fileIndex);
	inBitStream.ReadCompressed(onFileStruct.finalDataLength);
	unsigned int offset;
	unsigned int chunkLength;
	inBitStream.ReadCompressed(offset);
	inBitStream.ReadCompressed(chunkLength);
//	if (chunkLength==0)
//		return;
	bool lastChunk;
	inBitStream.Read(lastChunk);
	bool finished = lastChunk && fullFile;

	if (fullFile==false)
		fileListReceiver->partLength=partLength;

	FLR_MemoryBlock mb;
	if (fileListReceiver->pushedFiles.Has(onFileStruct.fileIndex)==false)
	{
		if (chunkLength > 1000000000 || onFileStruct.finalDataLength > 1000000000)
		{
			RakAssert("FileListTransfer::OnReferencePush: file too large" && 0);
			return;
		}

		mb.allocatedLength=onFileStruct.finalDataLength;
		mb.block = (char*) rakMalloc_Ex(onFileStruct.finalDataLength, __FILE__, __LINE__);
		if (mb.block==0)
		{
			notifyOutOfMemory(__FILE__, __LINE__);
			return;
		}

		fileListReceiver->pushedFiles.SetNew(onFileStruct.fileIndex, mb);
	}
	else
		mb=fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex);

	if (offset+chunkLength > mb.allocatedLength)
	{
		// Overrun
		RakAssert("FileListTransfer::OnReferencePush: Write would overrun allocated block" && 0);
		return;
	}

	// Read header uncompressed so the data is byte aligned, for speed
	onFileStruct.compressedTransmissionLength=(unsigned int) onFileStruct.finalDataLength;

	unsigned int unreadBits = inBitStream.GetNumberOfUnreadBits();
	unsigned int unreadBytes = BITS_TO_BYTES(unreadBits);
	unsigned int amountToRead;
	if (fullFile)
		amountToRead=chunkLength;
	else
		amountToRead=unreadBytes;

	inBitStream.AlignReadToByteBoundary();
	if (fullFile || (rakPeerInterface->GetSplitMessageProgressInterval() != 0 && (int)partCount==rakPeerInterface->GetSplitMessageProgressInterval()))
	{
		inBitStream.Read(mb.block+offset, amountToRead);
	}

	onFileStruct.setCount=fileListReceiver->setCount;
	onFileStruct.setTotalCompressedTransmissionLength=fileListReceiver->setTotalCompressedTransmissionLength;
	onFileStruct.setTotalFinalLength=fileListReceiver->setTotalFinalLength;
	onFileStruct.fileData=mb.block;

	if (finished)
	{
		if (fileListReceiver->downloadHandler->OnFile(&onFileStruct))
			rakFree_Ex(onFileStruct.fileData, __FILE__, __LINE__ );
		fileListReceiver->pushedFiles.Delete(onFileStruct.fileIndex);

		fileListReceiver->filesReceived++;

		// If this set is done, free the memory for it.
		if ((int) fileListReceiver->setCount==fileListReceiver->filesReceived)
		{
			if (fileListReceiver->downloadHandler->OnDownloadComplete()==false)
			{
				fileListReceiver->downloadHandler->OnDereference();
				fileListReceivers.Delete(onFileStruct.setID);
				if (fileListReceiver->deleteDownloadHandler)
					RakNet::OP_DELETE(fileListReceiver->downloadHandler, __FILE__, __LINE__);
				RakNet::OP_DELETE(fileListReceiver, __FILE__, __LINE__);
			}
		}
	}
	else
	{
		unsigned int totalNotifications;
		unsigned int currentNotificationIndex;
		unsigned int unreadBytes;

		if (rakPeerInterface==0 || rakPeerInterface->GetSplitMessageProgressInterval()==0)
		{
			totalNotifications = onFileStruct.finalDataLength / chunkLength + 1;
			currentNotificationIndex = offset / chunkLength;
			unreadBytes = mb.allocatedLength - ((offset+1)*chunkLength);
		}
		else
		{
			totalNotifications = onFileStruct.finalDataLength / fileListReceiver->partLength + 1;
			if (fullFile==false)
				currentNotificationIndex = (offset+partCount*fileListReceiver->partLength) / fileListReceiver->partLength ;
			else
				currentNotificationIndex = (offset+chunkLength) / fileListReceiver->partLength ;
			unreadBytes = onFileStruct.finalDataLength - ((currentNotificationIndex+1) * fileListReceiver->partLength);
		}
		fileListReceiver->downloadHandler->OnFileProgress(&onFileStruct, currentNotificationIndex, totalNotifications, unreadBytes, mb.block);
	}

	return;
}
示例#17
0
void FileListTransfer::Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
{
	(void) compressData;

	if (callback)
		fileList->SetCallback(callback);

	unsigned int i, totalLength;
	RakNet::BitStream outBitstream;
	bool sendReference;
	const char *dataBlocks[2];
	int lengths[2];
	totalLength=0;
	for (i=0; i < fileList->fileList.Size(); i++)
	{
		const FileListNode &fileListNode = fileList->fileList[i];
		totalLength+=fileListNode.fileLengthBytes;
	}

	// Write the chunk header, which contains the frequency table, the total number of files, and the total number of bytes
	bool anythingToWrite;
	outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_HEADER);
	outBitstream.Write(setID);
	anythingToWrite=fileList->fileList.Size()>0;
	outBitstream.Write(anythingToWrite);
	if (anythingToWrite)
	{
		outBitstream.WriteCompressed(fileList->fileList.Size());
		outBitstream.WriteCompressed(totalLength);

		if (rakPeer)
			rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		else
			SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);

		DataStructures::Queue<FileToPush*> filesToPush;
	
		for (i=0; i < fileList->fileList.Size(); i++)
		{
			sendReference = fileList->fileList[i].isAReference && _incrementalReadInterface!=0;
			if (sendReference)
			{
				FileToPush *fileToPush = RakNet::OP_NEW<FileToPush>(__FILE__,__LINE__);
				fileToPush->fileListNode.context=fileList->fileList[i].context;
				fileToPush->setIndex=i;
				fileToPush->fileListNode.filename=fileList->fileList[i].filename;
				fileToPush->fileListNode.fullPathToFile=fileList->fileList[i].fullPathToFile;
				fileToPush->fileListNode.fileLengthBytes=fileList->fileList[i].fileLengthBytes;
				fileToPush->fileListNode.dataLengthBytes=fileList->fileList[i].dataLengthBytes;
				//	fileToPush->systemAddress=recipient;
				fileToPush->setID=setID;
				fileToPush->packetPriority=priority;
				fileToPush->orderingChannel=orderingChannel;
				fileToPush->currentOffset=0;
				fileToPush->incrementalReadInterface=_incrementalReadInterface;
				fileToPush->chunkSize=_chunkSize;
				filesToPush.Push(fileToPush,__FILE__,__LINE__);
			}
			else
			{
				outBitstream.Reset();
				outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);

				outBitstream.Write(fileList->fileList[i].context);
				outBitstream.Write(setID);
				stringCompressor->EncodeString(fileList->fileList[i].filename, 512, &outBitstream);

				outBitstream.WriteCompressed(i);
				outBitstream.WriteCompressed(fileList->fileList[i].dataLengthBytes); // Original length in bytes

				outBitstream.AlignWriteToByteBoundary();

				dataBlocks[0]=(char*) outBitstream.GetData();
				lengths[0]=outBitstream.GetNumberOfBytesUsed();
				dataBlocks[1]=fileList->fileList[i].data;
				lengths[1]=fileList->fileList[i].dataLengthBytes;
				SendListUnified(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
			}
		}

		if (filesToPush.IsEmpty()==false)
		{
			FileToPushRecipient *ftpr=0;
			filesToPushAllSameAddressMutex.Lock();
			for (unsigned int i=0; i < filesToPushAllSameAddress.Size(); i++)
			{
				if (filesToPushAllSameAddress[i]->systemAddress==recipient)
				{
					ftpr=filesToPushAllSameAddress[i];
					break;
				}
			}
			if (ftpr==0)
			{
				ftpr = RakNet::OP_NEW<FileToPushRecipient>(__FILE__,__LINE__);
				ftpr->systemAddress=recipient;
				filesToPushAllSameAddress.Push(ftpr, __FILE__,__LINE__);
			}
			while (filesToPush.IsEmpty()==false)
			{
				ftpr->filesToPush.Push(filesToPush.Pop(), __FILE__,__LINE__);
			}
			filesToPushAllSameAddressMutex.Unlock();
			SendIRIToAddress(recipient);
			return;
		}
	}
	else
	{
		if (rakPeer)
			rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		else
			SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
	}
}
示例#18
0
void ReplicaManager::Destruct(Replica *replica, SystemAddress systemAddress, bool broadcast)
{
	RakAssert(replica);

	bool sendTimestamp;
	bool objectExists;
	unsigned replicatedObjectsIndex;
	replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
	if (objectExists==false)
		return;

	// For each existing participant, send a packet telling them of this object destruction
	RakNet::BitStream outBitstream, userDataBitStream;
	unsigned i,tempIndex;
	bool replicaReferenced;
	ParticipantStruct *participantStruct;
	replicaReferenced=false;
	for (i=0; i < participantList.Size(); i++)
	{
		participantStruct=participantList[i];

		if ((broadcast==true && systemAddress!=participantStruct->systemAddress) || 
			(broadcast==false && systemAddress==participantStruct->systemAddress))
		{
			// Remove any remote object state tracking for this object, for this player
			tempIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
			if (objectExists)
			{
				// Send the destruction packet immediately
				if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID &&
					(replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_DESTRUCTION))
				{
					userDataBitStream.Reset();
					userDataBitStream.Write((MessageID)ID_REPLICA_MANAGER_DESTRUCTION);
					userDataBitStream.Write(replica->GetNetworkID());
					sendTimestamp=false;
					ReplicaReturnResult res = replica->SendDestruction(&userDataBitStream, participantStruct->systemAddress, &sendTimestamp);
					if (res==REPLICA_PROCESSING_DONE)
					{
						outBitstream.Reset();
						if (sendTimestamp)
						{
							outBitstream.Write((MessageID)ID_TIMESTAMP);
							outBitstream.Write(RakNet::GetTime());
							outBitstream.Write(&userDataBitStream);
							SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
						}
						else
							SendUnified(&userDataBitStream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
					}
				}

				participantStruct->remoteObjectList.RemoveAtIndex(tempIndex);
			}

			// Remove any pending commands that reference this object, for this player
			tempIndex = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
		//	tempIndex = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
			if (objectExists)
				participantStruct->commandList.RemoveAtIndex(tempIndex);
		}
		else if (replicaReferenced==false)
		{
			bool objectExists;
			GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
			// See if any commands or objects reference replica
			//if (participantStruct->commandList.HasData(replica))
			if (objectExists)
				replicaReferenced=true;
			else if (participantStruct->remoteObjectList.HasData(replica))
				replicaReferenced=true;
		}
	}

	// Remove replica from the list if no commands and no remote objects reference it
	if (replicaReferenced==false)
		replicatedObjects.RemoveAtIndex(replicatedObjectsIndex);
}
示例#19
0
PluginReceiveResult Router::OnReceive(Packet *packet)
{
	if (packet->data[0]==ID_ROUTE_AND_MULTICAST ||
		(packet->length>5 && packet->data[0]==ID_TIMESTAMP && packet->data[5]==ID_ROUTE_AND_MULTICAST))
	{
#ifdef _DO_PRINTF
		RAKNET_DEBUG_PRINTF("%i got routed message from %i\n", peer->GetExternalID(packet->systemAddress).port, packet->systemAddress.port);
#endif
		RakNetTime timestamp;
		PacketPriority priority;
		PacketReliability reliability;
		unsigned char orderingChannel;
		SystemAddress originalSender;
		RakNet::BitStream out;
		BitSize_t outStartingOffset;
		unsigned int payloadBitLength;
		unsigned payloadWriteByteOffset;
		RakNet::BitStream incomingBitstream(packet->data, packet->length, false);
		incomingBitstream.IgnoreBits(8);
		
		if (packet->data[0]==ID_TIMESTAMP)
		{
			incomingBitstream.Read(timestamp);
			out.Write((MessageID)ID_TIMESTAMP);
			out.Write(timestamp);
			incomingBitstream.IgnoreBits(8);
		}

		// Read the send parameters
		unsigned char c;
		incomingBitstream.ReadCompressed(c);
		priority=(PacketPriority)c;
		incomingBitstream.ReadCompressed(c);
		reliability=(PacketReliability)c;
		incomingBitstream.ReadCompressed(orderingChannel);
		incomingBitstream.Read(payloadBitLength);
		
		out.Write((MessageID)ID_ROUTE_AND_MULTICAST);
		out.WriteCompressed((unsigned char)priority);
		out.WriteCompressed((unsigned char)reliability);
		out.WriteCompressed((unsigned char)orderingChannel);
		out.Write(payloadBitLength);
		out.AlignWriteToByteBoundary();
		incomingBitstream.AlignReadToByteBoundary();
		payloadWriteByteOffset=(unsigned int) BITS_TO_BYTES(out.GetWriteOffset());
		out.Write(&incomingBitstream, payloadBitLength); // This write also does a read on incomingBitStream

		if (restrictByType)
		{
			RakNet::BitStream t(out.GetData()+payloadWriteByteOffset, sizeof(unsigned char), false);
			MessageID messageID;
			t.Read(messageID);
			if (allowedTypes.HasData(messageID)==false)
				return RR_STOP_PROCESSING_AND_DEALLOCATE; // Don't route restricted types
		}

		incomingBitstream.Read(originalSender);
		out.Write(originalSender);
		outStartingOffset=out.GetWriteOffset();

		// Deserialize the root
		bool hasData=false;
		SystemAddress recipient;
		unsigned short numberOfChildren;
		incomingBitstream.Read(hasData);
		incomingBitstream.Read(recipient); // This should be our own address
		if (incomingBitstream.ReadCompressed(numberOfChildren)==false)
		{
#ifdef _DEBUG
			RakAssert(0);
#endif
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}

		unsigned childIndex;
		bool childHasData=false;
		SystemAddress childRecipient;
		unsigned short childNumberOfChildren;
		SystemAddress immediateRecipient;
		immediateRecipient=UNASSIGNED_SYSTEM_ADDRESS;
		int pendingNodeCount=0;

		for (childIndex=0; childIndex < numberOfChildren; childIndex++)
		{
			while (pendingNodeCount!=-1)
			{
				// Copy out the serialized subtree for this child
				incomingBitstream.Read(childHasData);
				incomingBitstream.Read(childRecipient);
				if (!incomingBitstream.ReadCompressed(childNumberOfChildren))
					return RR_STOP_PROCESSING_AND_DEALLOCATE;
				if (immediateRecipient==UNASSIGNED_SYSTEM_ADDRESS)
				{
					immediateRecipient=childRecipient;
				}

				pendingNodeCount+=childNumberOfChildren-1;

				out.Write(childHasData);
				out.Write(childRecipient);
				out.WriteCompressed(childNumberOfChildren);
			}

#ifdef _DO_PRINTF
			RAKNET_DEBUG_PRINTF("%i routing to %i\n", peer->GetExternalID(packet->systemAddress).port, immediateRecipient.port);
#endif

			// Send what we got so far
			SendUnified(&out, priority, reliability, orderingChannel, immediateRecipient, false);

			// Restart writing the per recipient data
			out.SetWriteOffset(outStartingOffset);

			// Reread the top level node
			immediateRecipient=UNASSIGNED_SYSTEM_ADDRESS;

			pendingNodeCount=0;

		}

		// Write the user payload to the packet struct if this is a destination and change the sender and return true
		if (hasData)
		{
#ifdef _DO_PRINTF
			RAKNET_DEBUG_PRINTF("%i returning payload to user\n", peer->GetExternalID(packet->systemAddress).port);
#endif

			if (packet->data[0]==ID_TIMESTAMP )
			{
				memcpy( packet->data + sizeof(RakNetTime)+sizeof(unsigned char), out.GetData()+payloadWriteByteOffset, BITS_TO_BYTES(payloadBitLength) );
				packet->bitSize=BYTES_TO_BITS(sizeof(RakNetTime)+sizeof(unsigned char))+payloadBitLength;
			}
			else
			{
				memcpy( packet->data, out.GetData()+payloadWriteByteOffset, BITS_TO_BYTES(payloadBitLength) );
				packet->bitSize=payloadBitLength;
			}
			packet->length=(unsigned int) BITS_TO_BYTES(packet->bitSize);
			packet->systemAddress.systemIndex=(SystemIndex)-1;
			packet->systemAddress=originalSender;

			return RR_CONTINUE_PROCESSING;
		}

		// Absorb
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	}

	return RR_CONTINUE_PROCESSING;
}
示例#20
0
void ReplicaManager::Update(void)
{
	if (participantList.Size()==0)
		return;

	// Check for recursive calls, which is not supported and should not happen
#ifdef _DEBUG
	RakAssert(inUpdate==false);
	inUpdate=true;
#endif

	unsigned participantIndex, remoteObjectListIndex, replicatedObjectsIndex;
	ReplicaReturnResult res;
	bool sendTimestamp;
	ParticipantStruct *participantStruct;
	unsigned commandListIndex;
	RakNet::BitStream outBitstream, userDataBitstream;
	RakNetTime currentTime;
	bool objectExists;
	PacketPriority priority;
	PacketReliability reliability;
	ReceivedCommand *receivedCommand;
	Replica *replica;
//	unsigned int userFlags;
	unsigned char command;
	currentTime=0;

	// For each participant
	for (participantIndex=0; participantIndex < participantList.Size(); participantIndex++)
	{
		participantStruct = participantList[participantIndex];

		// Sends the download complete packet
		// If callDownloadCompleteCB is true then check all the remaining objects starting at commandListIndex
		// I scan every frame in case the callback returns false to delay, and after that time a new object is Replicated
		if (participantStruct->callDownloadCompleteCB)
		{
			bool anyHasConstruction;
			unsigned j;
			anyHasConstruction=false;
			for (j=0; j < participantStruct->commandList.Size(); j++)
			{
				if (participantStruct->commandList[j].command & REPLICA_EXPLICIT_CONSTRUCTION)
				{
					anyHasConstruction=true;
					break;
				}
			}
			// If none have REPLICA_EXPLICIT_CONSTRUCTION, send ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE and set callDownloadCompleteCB false
			if (anyHasConstruction==false)
			{
				ReplicaReturnResult sendDLComplete;
				userDataBitstream.Reset();
				if (_sendDownloadCompleteCB)
					sendDLComplete=_sendDownloadCompleteCB->SendDownloadComplete(&userDataBitstream, currentTime, participantStruct->systemAddress, this); // If you return false, this will be called again next update
				else
					sendDLComplete=REPLICA_CANCEL_PROCESS;
				if (sendDLComplete==REPLICA_PROCESSING_DONE)
				{
					outBitstream.Reset();
					outBitstream.Write((MessageID)ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE);
					outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
					SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
					participantStruct->callDownloadCompleteCB=false;
				}
				else if (sendDLComplete==REPLICA_CANCEL_PROCESS)
				{
					participantStruct->callDownloadCompleteCB=false;
				}
				else
				{
					RakAssert(sendDLComplete==REPLICA_PROCESS_LATER);
					// else REPLICA_PROCESS_LATER
				}
			}
		}

		// For each CommandStruct to send
		for (commandListIndex=0; commandListIndex < participantStruct->commandList.Size(); commandListIndex++)
		{
			// Only call RakNet::GetTime() once because it's slow
			if (currentTime==0)
				currentTime=RakNet::GetTime();

			replica=participantStruct->commandList[commandListIndex].replica;
			command=participantStruct->commandList[commandListIndex].command;
		//	userFlags=participantStruct->commandList[commandListIndex].userFlags;
			replicatedObjectsIndex=replicatedObjects.GetIndexFromKey(replica, &objectExists);
#ifdef _DEBUG
			RakAssert(objectExists);
#endif
			if (objectExists==false)
				continue;

			// If construction is set, call SendConstruction.  The only precondition is that the object was not already created,
			// which was checked in ReplicaManager::Replicate
			if (command & REPLICA_EXPLICIT_CONSTRUCTION)
			{
				if (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_CONSTRUCTION)
				{
					userDataBitstream.Reset();
					sendTimestamp=false;
					res=replica->SendConstruction(currentTime, participantStruct->systemAddress,
						participantStruct->commandList[commandListIndex].userFlags, &userDataBitstream, &sendTimestamp);

					if (res==REPLICA_PROCESSING_DONE)
					{
						outBitstream.Reset();
						// If SendConstruction returns true and writes to outBitStream, do this send.  Clear the construction command.  Then process the next command for this CommandStruct, if any.
						if (sendTimestamp)
						{
							outBitstream.Write((MessageID)ID_TIMESTAMP);
							outBitstream.Write(currentTime);
						}
						outBitstream.Write((MessageID)ID_REPLICA_MANAGER_CONSTRUCTION);
						// It's required to send an NetworkID if available.
						// Problem:
						// A->B->C
						//	|  |
						//	D->E
						//
						// A creates.
						// B->C->E->D->B will cycle forever.
						// Fix is to always include an networkID.  Objects are not created if that object id already is present.
						if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID)
						{
							outBitstream.Write(true);
							outBitstream.Write(replica->GetNetworkID());
						}
						else
							outBitstream.Write(false);

						outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());

						SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);

						// Turn off this bit
						participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_EXPLICIT_CONSTRUCTION;

						// Add the object to the participant's object list, indicating this object has been remotely created
						RemoteObject remoteObject;
						remoteObject.replica=replica;
						//remoteObject.inScope=defaultScope;
						remoteObject.inScope=false;
						remoteObject.lastSendTime=0;
						remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
						// Create an entry for this object.  We do this now, even if the user might refuse the SendConstruction override,
						// because that call may be delayed and other commands sent while that is pending.  We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
						participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
					}
					else if (res==REPLICA_PROCESS_IMPLICIT)
					{
						// Turn off this bit
						participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_EXPLICIT_CONSTRUCTION;

						// Add the object to the participant's object list, indicating this object has been remotely created
						RemoteObject remoteObject;
						remoteObject.replica=replica;
						//remoteObject.inScope=defaultScope;
						remoteObject.inScope=false;
						remoteObject.lastSendTime=0;
						remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
						// Create an entry for this object.  We do this now, even if the user might refuse the SendConstruction override,
						// because that call may be delayed and other commands sent while that is pending.  We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
						participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
					}
					else if (res==REPLICA_PROCESS_LATER)
					{
						continue;
					}
					else // REPLICA_CANCEL_PROCESS
					{
						RakAssert(res==REPLICA_CANCEL_PROCESS);
						participantStruct->commandList[commandListIndex].command=0;
					}
				}
				else
				{
					// Don't allow construction, or anything else for this object, as the construction send call is disallowed
					participantStruct->commandList[commandListIndex].command=0;
				}
			}
			else if (command & REPLICA_IMPLICIT_CONSTRUCTION)
			{
				// Turn off this bit
				participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_IMPLICIT_CONSTRUCTION;

				// Add the object to the participant's object list, indicating this object is assumed to be remotely created
				RemoteObject remoteObject;
				remoteObject.replica=replica;
				//remoteObject.inScope=defaultScope;
				remoteObject.inScope=false;
				remoteObject.lastSendTime=0;
				remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
				// Create an entry for this object.  We do this now, even if the user might refuse the SendConstruction override,
				// because that call may be delayed and other commands sent while that is pending.  We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
				participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
			}

			// The remaining commands, SendScopeChange and Serialize, require the object the command references exists on the remote system, so check that
			remoteObjectListIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
			if (objectExists)
			{
				command = participantStruct->commandList[commandListIndex].command;

				// Process SendScopeChange.
				if ((command & (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE)))
				{
					if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
						continue; // Not set yet so call this later.

					if (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_SCOPE_CHANGE)
					{
						bool scopeTrue = (command & REPLICA_SCOPE_TRUE)!=0;

						// Only send scope changes if the requested change is different from what they already have
						if (participantStruct->remoteObjectList[remoteObjectListIndex].inScope!=scopeTrue)
						{
							userDataBitstream.Reset();
							sendTimestamp=false;
							res=replica->SendScopeChange(scopeTrue, &userDataBitstream, currentTime, participantStruct->systemAddress, &sendTimestamp);

							if (res==REPLICA_PROCESSING_DONE)
							{
								// If the user returns true and does write to outBitstream, do this send.  Clear the scope change command. Then process the next command for this CommandStruct, if any.
								outBitstream.Reset();
								if (sendTimestamp)
								{
									outBitstream.Write((MessageID)ID_TIMESTAMP);
									outBitstream.Write(currentTime);
								}
								outBitstream.Write((MessageID)ID_REPLICA_MANAGER_SCOPE_CHANGE);
								outBitstream.Write(replica->GetNetworkID());
								outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
								SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);

								// Set the scope for this object and system
								participantStruct->remoteObjectList[remoteObjectListIndex].inScope=scopeTrue;

								// If scope is true, turn on serialize, since you virtually always want to serialize when an object goes in scope
								if (scopeTrue && autoSerializeInScope)
									participantStruct->commandList[commandListIndex].command |= REPLICA_SERIALIZE;

								// Turn off these bits - Call is processed
								participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
							}
							else if (res==REPLICA_CANCEL_PROCESS)
							{
								// Turn off these bits - Call is canceled
								participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
							}
							else
							{
								// If the user returns false and the scope is currently set to false, just continue with another CommandStruct.  Don't process serialization until scoping is resolved first.
								if (scopeTrue==false)
									continue;

								// If the user returns false and the scope is currently set to false, process the next command for this CommandStruct, if any.
							}
						}
					}
					else
					{
						// Turn off these bits - Call is disallowed
						participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);

						// Set the scope - even if the actual send is disabled we might still be able to serialize.
						participantStruct->remoteObjectList[remoteObjectListIndex].inScope=(command & REPLICA_SCOPE_TRUE)!=0;
					}
				}

				command = participantStruct->commandList[commandListIndex].command;
				// Process Serialize
				if ((command & REPLICA_SERIALIZE))
				{
					if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
						continue; // Not set yet so call this later.

					// If scope is currently false for this object in the RemoteObject list, cancel this serialize as the scope changed before the serialization went out
					if (participantStruct->remoteObjectList[remoteObjectListIndex].inScope && (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_SERIALIZE))
					{
						do 
						{
							userDataBitstream.Reset();
							priority=HIGH_PRIORITY;
							reliability=RELIABLE_ORDERED;
							sendTimestamp=false;
							res=replica->Serialize(&sendTimestamp, &userDataBitstream, participantStruct->remoteObjectList[remoteObjectListIndex].lastSendTime, &priority, &reliability, currentTime, participantStruct->systemAddress, participantStruct->remoteObjectList[remoteObjectListIndex].userFlags);

							if (res==REPLICA_PROCESSING_DONE || res==REPLICA_PROCESS_AGAIN)
							{
								participantStruct->remoteObjectList[remoteObjectListIndex].lastSendTime=currentTime;

								outBitstream.Reset();
								if (sendTimestamp)
								{
									outBitstream.Write((MessageID)ID_TIMESTAMP);
									outBitstream.Write(currentTime);
								}
								outBitstream.Write((MessageID)ID_REPLICA_MANAGER_SERIALIZE);
								outBitstream.Write(replica->GetNetworkID());
								outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
								SendUnified(&outBitstream, priority, reliability, sendChannel, participantStruct->systemAddress, false);		

								// Clear the serialize bit when done
								if (res==REPLICA_PROCESSING_DONE)
									participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
								// else res==REPLICA_PROCESS_AGAIN so it will repeat the enclosing do {} while(); loop
							}
							else if (res==REPLICA_CANCEL_PROCESS)
							{
								// Clear the serialize bit
								participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
							}
							else
							{
								// if the user returns REPLICA_PROCESS_LATER, just continue with another CommandStruct.
								RakAssert(res==REPLICA_PROCESS_LATER);
							}
						} while(res==REPLICA_PROCESS_AGAIN);
					}
					else
					{
						// Cancel this serialize
						participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
					}
				}
			}
		}

		// Go through the command list and delete all cleared commands, from back to front.  It is more efficient to do this than to delete them as we process
		commandListIndex=participantStruct->commandList.Size();
		if (commandListIndex>0)
		{
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
			while (1)
			{
				if (participantStruct->commandList[commandListIndex-1].command==0)
				{
					// If this is the last item in the list, and it probably is, then it just changes a number rather than shifts the entire array
					participantStruct->commandList.RemoveAtIndex(commandListIndex-1);
				}

				if (--commandListIndex==0)
					break;
			}
		}
		
		// Now process queued receives
		while (participantStruct->pendingCommands.Size())
		{
			receivedCommand=participantStruct->pendingCommands.Pop();
			participantStruct=GetParticipantBySystemAddress(receivedCommand->systemAddress);
			if (participantStruct)
			{
				res=ProcessReceivedCommand(participantStruct, receivedCommand);
				// Returning false means process this command again later
				if (res==REPLICA_PROCESS_LATER)
				{
					// Push the command back in the queue
					participantStruct->pendingCommands.PushAtHead(receivedCommand, 0, __FILE__,__LINE__);

					// Stop processing, because all processing is in order
					break;
				}
				else
				{
					RakAssert(res==REPLICA_CANCEL_PROCESS);
				}
			}
			
			// Done with this command, so delete it
			RakNet::OP_DELETE(receivedCommand->userData, __FILE__, __LINE__);
			RakNet::OP_DELETE(receivedCommand, __FILE__, __LINE__);
		}
	}
#ifdef _DEBUG
	inUpdate=false;
#endif
}