From bb48ecd8ccfb0006e23555863f486646a7afc61f Mon Sep 17 00:00:00 2001 From: mordentral Date: Wed, 29 Jun 2016 15:33:41 -0400 Subject: [PATCH] Testing new library --- .../Classes/NetworkPackageLibrary.h | 233 ++++++++++++++++++ .../Private/NetworkPackageLibrary.cpp | 44 ++++ 2 files changed, 277 insertions(+) create mode 100644 Source/AdvancedSessions/Classes/NetworkPackageLibrary.h create mode 100644 Source/AdvancedSessions/Private/NetworkPackageLibrary.cpp diff --git a/Source/AdvancedSessions/Classes/NetworkPackageLibrary.h b/Source/AdvancedSessions/Classes/NetworkPackageLibrary.h new file mode 100644 index 0000000..40ebd77 --- /dev/null +++ b/Source/AdvancedSessions/Classes/NetworkPackageLibrary.h @@ -0,0 +1,233 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "OnlineSubSystemHeader.h" +#include "NetworkPackageLibrary.generated.h" + + +//General Advanced Sessions Log +DECLARE_LOG_CATEGORY_EXTERN(NetworkPackageLibraryLog, Log, All); + +// A struct to contain information about a chunk send over network +USTRUCT() +struct FNetworkPackage +{ + GENERATED_BODY() +public: + UPROPERTY() + uint8 ThisPackageNumber; + UPROPERTY() + uint8 TotalExpectedPackages; + UPROPERTY() + TArray ChunkData; + UPROPERTY() + uint32 PackageID; + UPROPERTY() + uint32 StartLocation; + UPROPERTY() + uint32 PackageSize; + UPROPERTY() + uint32 TotalDataSize; + UPROPERTY() + uint8 PackageType; + + FNetworkPackage() + { + ThisPackageNumber = 0; + TotalExpectedPackages = 0; + PackageID = 0; + PackageType = 0; + } +}; + +USTRUCT() +struct FNetworkPackageBin +{ + GENERATED_BODY() +public: + TArray RemainingPackageNumbers; + //TArray ChunkDataBin; + uint8 TotalExpectedPackages; + TArray ChunkData; + int32 PackageID; + uint8 PackageType; + uint32 TotalDataSize; + + bool bFinishedReceiving; + + FNetworkPackageBin() + { + TotalExpectedPackages = 0; + bFinishedReceiving = false; + PackageID = 0; + TotalDataSize = 0; + PackageType = 0; + } + + FNetworkPackageBin(const FNetworkPackage & Package) + { + bFinishedReceiving = false; + TotalExpectedPackages = 0; + InitializeFromPackage(Package); + } + + void InitializeFromPackage(const FNetworkPackage & Package) + { + for (int i = 0; i < Package.TotalExpectedPackages; ++i) + RemainingPackageNumbers.Add(i + 1); + + ChunkData.AddUninitialized(Package.TotalDataSize); + + FMemory::Memcpy(ChunkData.GetData() + Package.StartLocation, Package.ChunkData.GetData(), Package.PackageSize); + + TotalDataSize = Package.TotalDataSize; + PackageType = Package.PackageType; + + TotalExpectedPackages = Package.TotalExpectedPackages; + PackageID = Package.PackageID; + } + + // Returns true if this was the last package it was waiting on + bool AddPackage(const FNetworkPackage & Package) + { + if (Package.ThisPackageNumber <= TotalExpectedPackages && RemainingPackageNumbers.Find(Package.ThisPackageNumber) == INDEX_NONE) + { + RemainingPackageNumbers.Remove(Package.ThisPackageNumber); + + FMemory::Memcpy(ChunkData.GetData() + Package.StartLocation, Package.ChunkData.GetData(), Package.PackageSize); + + if (!RemainingPackageNumbers.Num()) + { + bFinishedReceiving = true; + UncompressData(); + return true; + } + } + else + { + return false; // Already received this package, something is wrong + } + + return false; + } + + void UncompressData() + { + FBufferArchive DecompressedBinaryArray; + FArchiveLoadCompressedProxy Decompressor = FArchiveLoadCompressedProxy(ChunkData, ECompressionFlags::COMPRESS_ZLIB); + + if (Decompressor.GetError()) + { + // File was not compressed + return; + } + + Decompressor << DecompressedBinaryArray; + Decompressor.FlushCache(); + Decompressor.Close(); + + ChunkData.Empty(); + DecompressedBinaryArray << ChunkData; + } +}; + + +// An actor component meant to handle sending large data array's across the network +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent)) +class UNetworkPackageLibraryComponent : public UActorComponent +{ + GENERATED_UCLASS_BODY() + ~UNetworkPackageLibraryComponent(); + +public: +#pragma region NETWORKING Networking Region + + // NETWORKING FUNCTIONS + //UPROPERTY(Replicated, BlueprintReadOnly) + int32 IncrementalPackageID; + + int32 GetPackageID() { return IncrementalPackageID++; } + + TArray NetworkPackageQueue; + + UFUNCTION(BlueprintCallable, Category = "NetworkPackageLibrary") + bool DeleteQueuedDataPackage(int32 NetworkPackageID) + { + for (int i = 0; i < NetworkPackageQueue.Num(); ++i) + { + if (NetworkPackageQueue[i].PackageID == NetworkPackageID) + { + NetworkPackageQueue.RemoveAt(i); + return true; + } + } + + return false; + } + + UFUNCTION(BlueprintImplementableEvent, Category = "NetworkPackageLibrary") + void BPEventNotifyPackageReady(int32 PackageID, uint8 PackageType); + + UFUNCTION(Server, Reliable, WithValidation) + virtual void ReceiveChunkDataPackage(FNetworkPackage Package); + + UFUNCTION(BlueprintCallable, Category = "NetworkPackageLibrary") + virtual void NetworkReplicateChunkData_ToServer(TArray ChunkData, uint8 PackageType) + { + // I can up this to 32 byte structures instead of the 8 bytes structure to get up to 64 KB per packet, right now it is 16kb per packet max with the 64bit size + int MAX_ARRAY_SIZE = 2048; + + FNetworkPackage newPackage; + newPackage.PackageID = GetPackageID(); + + FBufferArchive ToBinary; + ToBinary << ChunkData; + + // Compress File + TArray CompressedData; + FArchiveSaveCompressedProxy Compressor = FArchiveSaveCompressedProxy(CompressedData, ECompressionFlags::COMPRESS_ZLIB); + + //Send entire binary array/archive to compressor + Compressor << ToBinary; + + //send archive serialized data to binary array + Compressor.Flush(); + Compressor.FlushCache(); + Compressor.Close(); + + uint32 numPackages = FMath::CeilToInt(CompressedData.Num() / MAX_ARRAY_SIZE); + if ((CompressedData.Num() % MAX_ARRAY_SIZE) > 0) + numPackages++; + + newPackage.TotalDataSize = CompressedData.Num(); + newPackage.TotalExpectedPackages = numPackages; + newPackage.PackageType = PackageType; + + uint32 curLoc = 0; + + for (uint32 i = 0; i < numPackages; ++i) + { + if (curLoc >= (uint32)CompressedData.Num()) + return; // End here, no more to send + + FNetworkPackage pack = newPackage; + pack.ThisPackageNumber = i; + pack.StartLocation = curLoc; + + uint32 thisCount = FMath::Clamp((uint32)(newPackage.TotalDataSize - curLoc), 0, MAX_ARRAY_SIZE); + pack.ChunkData.AddUninitialized(FMath::CeilToInt(thisCount / sizeof(uint64))); + pack.PackageSize = thisCount; + FMemory::Memcpy(pack.ChunkData.GetData(), CompressedData.GetData() + curLoc, thisCount); + + // Send it up the pipeline + ReceiveChunkDataPackage(pack); + //TargetController->ReceiveChunkDataPackage(this, pack); + curLoc += MAX_ARRAY_SIZE; + } + } + + // END NETWORKING FUNCTIONS + +#pragma endregion End of networking Region + +}; diff --git a/Source/AdvancedSessions/Private/NetworkPackageLibrary.cpp b/Source/AdvancedSessions/Private/NetworkPackageLibrary.cpp new file mode 100644 index 0000000..b5559fe --- /dev/null +++ b/Source/AdvancedSessions/Private/NetworkPackageLibrary.cpp @@ -0,0 +1,44 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "NetworkPackageLibrary.h" + +//General Log +DEFINE_LOG_CATEGORY(NetworkPackageLibraryLog); + +UNetworkPackageLibraryComponent::UNetworkPackageLibraryComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PrimaryComponentTick.bCanEverTick = false; +} + +//============================================================================= +UNetworkPackageLibraryComponent::~UNetworkPackageLibraryComponent() +{ +} + +bool UNetworkPackageLibraryComponent::ReceiveChunkDataPackage_Validate(FNetworkPackage Package) +{ + return true; +} + +void UNetworkPackageLibraryComponent::ReceiveChunkDataPackage_Implementation(FNetworkPackage Package) +{ + for (int i = 0; i < NetworkPackageQueue.Num(); ++i) + { + if (NetworkPackageQueue[i].PackageID == Package.PackageID) + { + if (NetworkPackageQueue[i].AddPackage(Package)) + { + if (NetworkPackageQueue[i].bFinishedReceiving) + BPEventNotifyPackageReady(i, NetworkPackageQueue[i].PackageType); + //else + // NOTIFY BAD SEND + } + return; + } + } + + // Else need to add a new package + FNetworkPackageBin newBin(Package); + NetworkPackageQueue.Add(Package); +}