bool FChunkManifestGenerator::SaveAssetRegistry(const FString& SandboxPath)
{
	UE_LOG(LogChunkManifestGenerator, Display, TEXT("Saving asset registry."));

	// Create asset registry data
	FArrayWriter SerializedAssetRegistry;
	TMap<FName, FAssetData*> GeneratedAssetRegistryData;
	for (auto& AssetData : AssetRegistryData)
	{
		// Add only assets that have actually been cooked and belong to any chunk
		if (AssetData.ChunkIDs.Num() > 0)
		{
			GeneratedAssetRegistryData.Add(AssetData.ObjectPath, &AssetData);
		}
	}
	AssetRegistry.SaveRegistryData(SerializedAssetRegistry, GeneratedAssetRegistryData, GeneratedAssetRegistryData.Num());
	UE_LOG(LogChunkManifestGenerator, Display, TEXT("Generated asset registry num assets %d, size is %5.2fkb"), GeneratedAssetRegistryData.Num(), (float)SerializedAssetRegistry.Num() / 1024.f);

	// Save the generated registry for each platform
	for (auto Platform : Platforms)
	{
		FString PlatformSandboxPath = SandboxPath.Replace(TEXT("[Platform]"), *Platform->PlatformName());
		FFileHelper::SaveArrayToFile(SerializedAssetRegistry, *PlatformSandboxPath);
	}

	UE_LOG(LogChunkManifestGenerator, Display, TEXT("Done saving asset registry."));

	return true;
}
bool FChunkManifestGenerator::SaveAssetRegistry(const FString& SandboxPath, const TArray<FName>* IgnorePackageList)
{
    UE_LOG(LogChunkManifestGenerator, Display, TEXT("Saving asset registry."));


    TSet<FName> IgnorePackageSet;
    if (IgnorePackageList != nullptr)
    {
        for (const auto& IgnorePackage : *IgnorePackageList)
        {
            IgnorePackageSet.Add(IgnorePackage);
        }
    }


    // Create asset registry data
    FArrayWriter SerializedAssetRegistry;
    SerializedAssetRegistry.SetFilterEditorOnly(true);
    TMap<FName, FAssetData*> GeneratedAssetRegistryData;
    for (auto& AssetData : AssetRegistryData)
    {
        if (IgnorePackageSet.Contains(AssetData.PackageName))
        {
            continue;
        }

        // Add only assets that have actually been cooked and belong to any chunk
        if (AssetData.ChunkIDs.Num() > 0)
        {
            GeneratedAssetRegistryData.Add(AssetData.ObjectPath, &AssetData);
        }
    }
    AssetRegistry.SaveRegistryData(SerializedAssetRegistry, GeneratedAssetRegistryData);
    UE_LOG(LogChunkManifestGenerator, Display, TEXT("Generated asset registry num assets %d, size is %5.2fkb"), GeneratedAssetRegistryData.Num(), (float)SerializedAssetRegistry.Num() / 1024.f);

    // Save the generated registry for each platform
    for (auto Platform : Platforms)
    {
        FString PlatformSandboxPath = SandboxPath.Replace(TEXT("[Platform]"), *Platform->PlatformName());
        FFileHelper::SaveArrayToFile(SerializedAssetRegistry, *PlatformSandboxPath);
    }

    UE_LOG(LogChunkManifestGenerator, Display, TEXT("Done saving asset registry."));

    return true;
}
void FUdpMessageBeacon::SendSegment(EUdpMessageSegments::Type SegmentType)
{
	FUdpMessageSegment::FHeader Header;

	Header.SenderNodeId = NodeId;
	Header.ProtocolVersion = UDP_MESSAGING_TRANSPORT_PROTOCOL_VERSION;
	Header.SegmentType = SegmentType;

	FArrayWriter Writer;
	
	Writer << Header;
	Writer << NodeId;

	int32 Sent;

	Socket->Wait(ESocketWaitConditions::WaitForWrite, BeaconInterval);
	Socket->SendTo(Writer.GetData(), Writer.Num(), Sent, *MulticastAddress);
}
void FUdpMessageProcessor::AcknowledgeReceipt( int32 MessageId, const FNodeInfo& NodeInfo )
{
	FUdpMessageSegment::FHeader Header;

	Header.RecipientNodeId = NodeInfo.NodeId;
	Header.SenderNodeId = LocalNodeId;
	Header.ProtocolVersion = UDP_MESSAGING_TRANSPORT_PROTOCOL_VERSION;
	Header.SegmentType = EUdpMessageSegments::Acknowledge;

	FUdpMessageSegment::FAcknowledgeChunk AcknowledgeChunk;

	AcknowledgeChunk.MessageId = MessageId;

	FArrayWriter Writer;

	Writer << Header;
	Writer << AcknowledgeChunk;

	int32 Sent;

	Socket->SendTo(Writer.GetData(), Writer.Num(), Sent, *NodeInfo.Endpoint.ToInternetAddr());
}
bool FTcpMessageTransportConnection::SendMessages()
{
	if (Outbox.IsEmpty() && bSentHeader)
	{
		return true;
	}

	if (!Socket->Wait(ESocketWaitConditions::WaitForWrite, FTimespan::Zero()))
	{
		return true;
	}

	if (!bSentHeader)
	{
		FArrayWriter HeaderData;
		FTcpMessageHeader MessageHeader(LocalNodeId);
		HeaderData << MessageHeader;

		if (!BlockingSend(HeaderData.GetData(), sizeof(FTcpMessageHeader)))
		{
			return false;
		}

		bSentHeader = true;
		TotalBytesSent += sizeof(FTcpMessageHeader);
	}
	else
	{
		FTcpSerializedMessagePtr Message;
		while (Outbox.Dequeue(Message))
		{
			int32 BytesSent = 0;
			const TArray<uint8>& Payload = Message->GetDataArray();

			// send the payload size
			FArrayWriter MessagesizeData = FArrayWriter(true);
			uint32 Messagesize = Payload.Num();
			MessagesizeData << Messagesize;

			if (!BlockingSend(MessagesizeData.GetData(), sizeof(uint32)))
			{
				return false;
			}

			TotalBytesSent += sizeof(uint32);

			// send the payload
			if (!BlockingSend(Payload.GetData(), Payload.Num()))
			{
				return false;
			}

			TotalBytesSent += Payload.Num();

			// return if the socket is no longer writable, or that was the last message
			if (Outbox.IsEmpty() || !Socket->Wait(ESocketWaitConditions::WaitForWrite, FTimespan::Zero()))
			{
				return true;
			}
		}
	}
	return true;
}
bool FChunkManifestGenerator::SaveAssetRegistry(const FString& SandboxPath, const TArray<FName>* IgnorePackageList)
{
	UE_LOG(LogChunkManifestGenerator, Display, TEXT("Saving asset registry."));


	TSet<FName> IgnorePackageSet;
	if (IgnorePackageList != nullptr)
	{
		for (const auto& IgnorePackage : *IgnorePackageList)
		{
			IgnorePackageSet.Add(IgnorePackage);
		}
	}
	

	// Create asset registry data
	TArray<FName> MapList;
	FArrayWriter SerializedAssetRegistry;
	SerializedAssetRegistry.SetFilterEditorOnly(true);
	TMap<FName, FAssetData*> GeneratedAssetRegistryData;
	for (auto& AssetData : AssetRegistryData)
	{
		if (IgnorePackageSet.Contains(AssetData.PackageName))
		{
			continue;
		}

		// Add only assets that have actually been cooked and belong to any chunk
		if (AssetData.ChunkIDs.Num() > 0)
		{
			GeneratedAssetRegistryData.Add(AssetData.PackageName, &AssetData);

			if (ContainsMap(AssetData.PackageName))
			{
				MapList.Add(AssetData.PackageName);
		}
	}
	}

	AssetRegistry.SaveRegistryData(SerializedAssetRegistry, GeneratedAssetRegistryData, &MapList);
	UE_LOG(LogChunkManifestGenerator, Display, TEXT("Generated asset registry num assets %d, size is %5.2fkb"), GeneratedAssetRegistryData.Num(), (float)SerializedAssetRegistry.Num() / 1024.f);

	auto CookerFileOrderString = CreateCookerFileOrderString(GeneratedAssetRegistryData, MapList);

	// Save the generated registry for each platform
	for (auto Platform : Platforms)
	{
		FString PlatformSandboxPath = SandboxPath.Replace(TEXT("[Platform]"), *Platform->PlatformName());
		FFileHelper::SaveArrayToFile(SerializedAssetRegistry, *PlatformSandboxPath);

		if (CookerFileOrderString.Len())
		{
			auto OpenOrderFilename = FString::Printf(TEXT("%sBuild/%s/FileOpenOrder/CookerOpenOrder.log"), *FPaths::GameDir(), *Platform->PlatformName());
			FFileHelper::SaveStringToFile(CookerFileOrderString, *OpenOrderFilename);
		}
	}

	UE_LOG(LogChunkManifestGenerator, Display, TEXT("Done saving asset registry."));

	return true;
}