From d07907f0e19e78bf011f42bdb6fccf202f42fb41 Mon Sep 17 00:00:00 2001 From: getnamo Date: Thu, 25 Jul 2024 19:33:54 -0700 Subject: [PATCH] Add struct <-> binary serialization; ~5x Faster than json de/serialization. --- .../Private/CUBlueprintLibrary.cpp | 64 +++++++++++++++++++ .../CoreUtility/Public/CUBlueprintLibrary.h | 16 +++++ Source/SIOJson/Private/SIOJConvert.cpp | 2 +- Source/SIOJson/Public/SIOJConvert.h | 3 +- 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Source/CoreUtility/Private/CUBlueprintLibrary.cpp b/Source/CoreUtility/Private/CUBlueprintLibrary.cpp index c7413cd..d90992b 100644 --- a/Source/CoreUtility/Private/CUBlueprintLibrary.cpp +++ b/Source/CoreUtility/Private/CUBlueprintLibrary.cpp @@ -553,4 +553,68 @@ void UCUBlueprintLibrary::CallFunctionOnThreadGraphReturn(const FString& Functio } } +bool UCUBlueprintLibrary::SerializeStruct(UStruct* Struct, void* StructPtr, TArray& OutBytes) +{ + if (!Struct || !StructPtr) + { + return false; + } + + FMemoryWriter MemoryWriter(OutBytes, true); + Struct->SerializeBin(MemoryWriter, StructPtr); + + return true; +} + +bool UCUBlueprintLibrary::DeserializeStruct(UStruct* Struct, void* StructPtr, const TArray& InBytes) +{ + if (!Struct || !StructPtr || InBytes.Num() == 0) + { + return false; + } + + FMemoryReader MemoryReader(InBytes, true); + + //Bi-directional, also works as a deserialization + Struct->SerializeBin(MemoryReader, StructPtr); + + return true; +} + +DEFINE_FUNCTION(UCUBlueprintLibrary::execBytesToStruct) +{ + // Extract the parameters + P_GET_TARRAY_REF(uint8, InBytes); + Stack.StepCompiledIn(NULL); + FStructProperty* StructProp = CastField(Stack.MostRecentProperty); + void* StructPtr = Stack.MostRecentPropertyAddress; + + P_FINISH; + + // Deserialize the struct + bool bSuccess = DeserializeStruct(StructProp->Struct, StructPtr, InBytes); + + // Return the success status + *(bool*)RESULT_PARAM = bSuccess; +} + +//custom thunk needed to handle wildcard structs +DEFINE_FUNCTION(UCUBlueprintLibrary::execStructToBytes) +{ + // Extract the parameters + Stack.StepCompiledIn(NULL); + FStructProperty* StructProp = CastField(Stack.MostRecentProperty); + void* StructPtr = Stack.MostRecentPropertyAddress; + + P_GET_TARRAY_REF(uint8, OutBytes); + + P_FINISH; + + // Serialize the struct + bool bSuccess = SerializeStruct(StructProp->Struct, StructPtr, OutBytes); + + // Return the success status + *(bool*)RESULT_PARAM = bSuccess; +} + #pragma warning( pop ) diff --git a/Source/CoreUtility/Public/CUBlueprintLibrary.h b/Source/CoreUtility/Public/CUBlueprintLibrary.h index 0cfdfa9..d766bb5 100644 --- a/Source/CoreUtility/Public/CUBlueprintLibrary.h +++ b/Source/CoreUtility/Public/CUBlueprintLibrary.h @@ -174,4 +174,20 @@ class COREUTILITY_API UCUBlueprintLibrary : public UBlueprintFunctionLibrary */ UFUNCTION(BlueprintCallable, Category = "CoreUtility|Threading", meta = (Latent, LatentInfo = "LatentInfo", WorldContext = "WorldContextObject")) static void CallFunctionOnThreadGraphReturn(const FString& Function, ESIOCallbackType ThreadType, struct FLatentActionInfo LatentInfo, UObject* WorldContextObject = nullptr); + + + UFUNCTION(BlueprintCallable, Category = "SocketIOFunctions", CustomThunk, meta = (CustomStructureParam = "AnyStruct")) + static bool StructToBytes(TFieldPath AnyStruct, TArray& OutBytes); + + DECLARE_FUNCTION(execStructToBytes); + + + UFUNCTION(BlueprintCallable, Category = "SocketIOFunctions", CustomThunk, meta = (CustomStructureParam = "OutAnyStruct")) + static bool BytesToStruct(const TArray& InBytes, TFieldPath OutAnyStruct); + + DECLARE_FUNCTION(execBytesToStruct); + + //C++ binary utility + static bool SerializeStruct(UStruct* Struct, void* StructPtr, TArray& OutBytes); + static bool DeserializeStruct(UStruct* Struct, void* StructPtr, const TArray& InBytes); }; diff --git a/Source/SIOJson/Private/SIOJConvert.cpp b/Source/SIOJson/Private/SIOJConvert.cpp index 115e333..712c212 100644 --- a/Source/SIOJson/Private/SIOJConvert.cpp +++ b/Source/SIOJson/Private/SIOJConvert.cpp @@ -12,6 +12,7 @@ #include "JsonObjectConverter.h" #include "UObject/PropertyPortFlags.h" #include "Misc/Base64.h" +#include "Serialization/MemoryWriter.h" typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriterFactory; typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriter; @@ -848,7 +849,6 @@ bool USIOJConvert::JsonFileToUStruct(const FString& FilePath, UStruct* Struct, v return JsonObjectToUStruct(ToJsonObject(JsonString), Struct, StructPtr, IsBlueprintStruct); } - bool USIOJConvert::ToJsonFile(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct /*= false*/) { //Get json object with trimmed values diff --git a/Source/SIOJson/Public/SIOJConvert.h b/Source/SIOJson/Public/SIOJConvert.h index 8b6965e..dbcfd50 100644 --- a/Source/SIOJson/Public/SIOJConvert.h +++ b/Source/SIOJson/Public/SIOJConvert.h @@ -46,8 +46,7 @@ class SIOJSON_API USIOJConvert : public UObject //Files - convenience read/write files static bool JsonFileToUStruct(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); - static bool ToJsonFile(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); - + static bool ToJsonFile(const FString& FilePath, UStruct* Struct, void* StructPtr, bool IsBlueprintStruct = false); //typically from callbacks static class USIOJsonValue* ToSIOJsonValue(const TArray>& JsonValueArray);