├── .gitignore ├── JSONQuery ├── Resources │ └── Icon128.png ├── Samples │ ├── Blueprint │ │ ├── README.md │ │ └── JSONQueryDev │ │ │ ├── Widgets │ │ │ └── UMG_DebugText.uasset │ │ │ └── Blueprints │ │ │ └── BP_JSONTest.uasset │ └── jsonquery-server-sample.php ├── Source │ └── JSONQuery │ │ ├── Classes │ │ ├── JSONQueryModule.h │ │ └── JsonFieldData.h │ │ ├── JSONQuery.Build.cs │ │ └── Private │ │ ├── JSONQueryModule.cpp │ │ └── JsonFieldData.cpp └── JSONQuery.uplugin └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries/ 2 | Intermediate/ -------------------------------------------------------------------------------- /JSONQuery/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RVillani/UnrealJSONQuery/HEAD/JSONQuery/Resources/Icon128.png -------------------------------------------------------------------------------- /JSONQuery/Samples/Blueprint/README.md: -------------------------------------------------------------------------------- 1 | # How to install the Blueprint sample 2 | Copy the **JSONQueryDev** folder into your project's **Content** folder. -------------------------------------------------------------------------------- /JSONQuery/Samples/Blueprint/JSONQueryDev/Widgets/UMG_DebugText.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RVillani/UnrealJSONQuery/HEAD/JSONQuery/Samples/Blueprint/JSONQueryDev/Widgets/UMG_DebugText.uasset -------------------------------------------------------------------------------- /JSONQuery/Samples/Blueprint/JSONQueryDev/Blueprints/BP_JSONTest.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RVillani/UnrealJSONQuery/HEAD/JSONQuery/Samples/Blueprint/JSONQueryDev/Blueprints/BP_JSONTest.uasset -------------------------------------------------------------------------------- /JSONQuery/Source/JSONQuery/Classes/JSONQueryModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Modules/ModuleManager.h" 4 | 5 | DECLARE_LOG_CATEGORY_CLASS(JSONQueryLog, Log, All); 6 | 7 | class JSONQueryModule : public IModuleInterface 8 | { 9 | private: 10 | 11 | public: 12 | JSONQueryModule(); 13 | 14 | virtual void StartupModule() override; 15 | virtual void ShutdownModule() override; 16 | }; 17 | -------------------------------------------------------------------------------- /JSONQuery/Source/JSONQuery/JSONQuery.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. 2 | using UnrealBuildTool; 3 | 4 | public class JSONQuery : ModuleRules 5 | { 6 | public JSONQuery(ReadOnlyTargetRules Rules) : base(Rules) 7 | { 8 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 9 | 10 | PublicDependencyModuleNames.AddRange( 11 | new string[] { 12 | "Core", 13 | "CoreUObject", 14 | "Engine", 15 | "HTTP", 16 | "Json" 17 | } 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /JSONQuery/Samples/jsonquery-server-sample.php: -------------------------------------------------------------------------------- 1 | info = "This script returns some types of JSON properties and the JSON sent from Unreal as a sub-object."; 7 | $response_json->boolean = true; 8 | $response_json->integer = 1; 9 | $response_json->float = 2.0; 10 | $response_json->null = null; 11 | $response_json->object = $post_json; 12 | 13 | echo json_encode($response_json); 14 | 15 | ?> -------------------------------------------------------------------------------- /JSONQuery/JSONQuery.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion" : 3, 3 | 4 | "FriendlyName" : "JSON Query", 5 | "Version" : 6, 6 | "VersionName": "1.0.0", 7 | "CreatedBy" : "Rodrigo Villani", 8 | "CreatedByURL" : "http://rvillani.com/", 9 | "Description" : "Exposes nodes to Blueprint that allow you to easily post and request pages on webservers through the JSON protocol.", 10 | "Category" : "Web", 11 | "EnabledByDefault" : true, 12 | 13 | "Modules" : 14 | [ 15 | { 16 | "Name" : "JSONQuery", 17 | "Type" : "Runtime" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /JSONQuery/Source/JSONQuery/Private/JSONQueryModule.cpp: -------------------------------------------------------------------------------- 1 | #include "JSONQueryModule.h" 2 | 3 | IMPLEMENT_MODULE(JSONQueryModule, JSONQuery); 4 | 5 | #define LOCTEXT_NAMESPACE "JSONQuery" 6 | 7 | JSONQueryModule::JSONQueryModule() 8 | {} 9 | 10 | void JSONQueryModule::StartupModule() 11 | { 12 | // Startup LOG MSG 13 | UE_LOG(JSONQueryLog, Warning, TEXT("JSONQuery: Log Started")); 14 | } 15 | 16 | void JSONQueryModule::ShutdownModule() 17 | { 18 | // Shutdown LOG MSG 19 | UE_LOG(JSONQueryLog, Warning, TEXT("JSONQuery: Log Ended")); 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSONQuery for Unreal 2 | Adds nodes for Blueprint communication with servers using JSON. 3 | 4 | ## Usage 5 | 6 | ### Installation 7 | 8 | You can clone this repo to your computer and compile it with your project or download a ZIP from the [releases](https://github.com/RVillani/UnrealJSONQuery/releases) page with the binaries. **Current Unreal Engine supported version is 4.19.2** 9 | 10 | 1. Close the Project. 11 | 1. Create a folder named **Plugins** in your project folder (if there isn't one). 12 | 1. Copy the folder **JSONQuery** into your **Plugins** folder. 13 | 1. Launch the project. 14 | 15 | ### Nodes 16 | 17 | #### To send data to a server/web-service 18 | 19 | 1. Use the ```CreateJSON``` node to get a new JSON object. 20 | 1. Pull a line from this node and add the Key/Values you want with the ```AddX``` nodes. 21 | 1. **Always pull the next line from the last Add node.** If you pull the line from the CreateJSON node everytime, you'll be adding each Key/Value to a different JSON object. 22 | 1. After the last Add node, pull a line from it's Return Value and call ```PostJSONRequest``` with the URL. 23 | 1. If you want to know when the request was completed, pull another line and call ```BindEventToOnGetResult```. 24 | 25 | #### To get data from a server/web-service 26 | 27 | 1. Use the ```GetJSONRequest``` node with the URL. 28 | 1. Pull a line from this node's Return Value and call ```BindEventToOnGetResult```. 29 | 1. From the resulting event you can get the answer from the server using the JSON variable. 30 | 31 | ### Examples 32 | 33 | In the [releases](https://github.com/RVillani/UnrealJSONQuery/releases) ZIP files you'll find a **Samples** folder with an advanced Blueprint example as well as a PHP script for reading the JSON in the server. 34 | 35 | ## Troubleshooting 36 | 37 | The plugin will always display the received answer from the server on the **Output Log** window. Even if it's not a valid JSON, in which case it'll be highlighted in red. 38 | *If you don't have the Output Log window opened, find it on **Window > Developer Tools > Output Log**.* 39 | 40 | ## Support 41 | 42 | I strongly advice you to go to the [forum thread](https://forums.unrealengine.com/showthread.php?7045-JSON-Query&goto=newpost) for help, as it's already filled with people using the plugin and helping each other. 43 | -------------------------------------------------------------------------------- /JSONQuery/Source/JSONQuery/Classes/JsonFieldData.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. 2 | #pragma once 3 | 4 | #include "CoreMinimal.h" 5 | #include "Http.h" 6 | #include "Json.h" 7 | #include "JsonFieldData.generated.h" 8 | 9 | /** 10 | * The possible status of a JSON POST/GET call. 11 | */ 12 | UENUM(BlueprintType, Category = "JSON") 13 | enum class EJSONResult : uint8 14 | { 15 | Success = 0, 16 | HttpFailed, 17 | JSONParsingFailed 18 | }; 19 | 20 | /** 21 | * Possible location to read the JSON file from 22 | */ 23 | UENUM(BlueprintType, Category = "JSON") 24 | enum class EFolder : uint8 25 | { 26 | Content, 27 | Project 28 | }; 29 | 30 | // Generate a delegate for the OnGetResult event 31 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnGetResult, const bool, bSuccess, class UJsonFieldData*, JSON, const EJSONResult, Status); 32 | 33 | UCLASS(BlueprintType, Blueprintable, Category = "JSON") 34 | class UJsonFieldData : public UObject 35 | { 36 | GENERATED_BODY() 37 | 38 | private: 39 | 40 | /** 41 | * Callback for IHttpRequest::OnProcessRequestComplete() 42 | * 43 | * @param Request HTTP request pointer 44 | * @param Response Response pointer 45 | * @param bWasSuccessful Whether the request was successful or not 46 | */ 47 | void OnReady(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); 48 | 49 | /** 50 | * Resets the current page data 51 | */ 52 | void Reset(); 53 | 54 | /** 55 | * Prefixes the input URL with http:// if necessary 56 | * 57 | * @param inputURL The input URL 58 | * 59 | * @return The output URL 60 | */ 61 | static FString CreateURL(FString inputURL); 62 | 63 | /** 64 | * This function will write the supplied key and value to the JsonWriter 65 | * 66 | * @param writer The JsonWriter to use 67 | * @param key Object key 68 | * @param value Object value 69 | */ 70 | static void WriteObject(TSharedRef> writer, FString key, FJsonValue* value); 71 | 72 | public: 73 | /************************************************************************/ 74 | /* STATICS */ 75 | /************************************************************************/ 76 | 77 | /** 78 | * Create a new instance of the UJsonFieldData class, for use in Blueprint graphs. 79 | * 80 | * @return A pointer to the newly created post data 81 | */ 82 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Create JSON", Keywords = "new"), Category = "JSON") 83 | static UJsonFieldData* Create(); 84 | 85 | /** 86 | * Loads JSON data from a file relative to the game folder 87 | * 88 | * @param FilePath JSON file path relative to folder passed as RelativeTo 89 | * @param RelativeTo The File path will be relative to this path 90 | * 91 | * @return JsonFieldData Object if successful or null otherwise 92 | */ 93 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "JSON From File"), Category = "JSON") 94 | static UJsonFieldData* FromFile(const FString FilePath, const EFolder RelativeTo); 95 | 96 | /* The actual field data */ 97 | TSharedPtr Data; 98 | 99 | /** 100 | * Event which triggers after the request returned something. Check bSuccess to know if it worked. 101 | * Check Status to know what happened on error. 102 | */ 103 | UPROPERTY(BlueprintAssignable, Category = "JSON") 104 | FOnGetResult OnGetResult; 105 | 106 | /** 107 | * Constructor 108 | */ 109 | UJsonFieldData(); 110 | 111 | /** 112 | * Get the JSON object as a string. 113 | */ 114 | UFUNCTION(BlueprintPure, meta = (DisplayName = "JSON To String", CompactNodeTitle = "->", Keywords = "cast text convert serialize"), Category = "JSON") 115 | FString ToString() const; 116 | 117 | /** 118 | * Checks if a field exists in the JSON object 119 | * 120 | * @param key The field name to check 121 | * 122 | * @return True if the field exists 123 | */ 124 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Check Field Exists"), Category = "JSON") 125 | bool HasField(const FString& key) const; 126 | 127 | /** 128 | * Adds the supplied string to the post data, under the given key 129 | * 130 | * @param key Key 131 | * @param value Object value 132 | * 133 | * @return The object itself 134 | */ 135 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add String Field"), Category = "JSON") 136 | UJsonFieldData* SetString(const FString& key, const FString& value); 137 | 138 | /** 139 | * Adds the supplied bool to the post data, under the given key 140 | * 141 | * @param key Key 142 | * @param value Object value 143 | * 144 | * @return The object itself 145 | */ 146 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Boolean Field"), Category = "JSON") 147 | UJsonFieldData* SetBoolean(const FString& key, const bool value); 148 | 149 | /** 150 | * Adds the supplied float to the post data, under the given key 151 | * 152 | * @param key Key 153 | * @param value Object value 154 | * 155 | * @return The object itself 156 | */ 157 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Float Field"), Category = "JSON") 158 | UJsonFieldData* SetFloat(const FString& key, const float value); 159 | 160 | /** 161 | * Adds the supplied integer to the post data, under the given key 162 | * 163 | * @param key Key 164 | * @param value Object value 165 | * 166 | * @return The object itself 167 | */ 168 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Integer Field"), Category = "JSON") 169 | UJsonFieldData* SetInt(const FString& key, const int32 value); 170 | 171 | /** 172 | * Adds a null value to the post data, under the given key 173 | * 174 | * @param key Key 175 | * 176 | * @return The object itself 177 | */ 178 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Null Field"), Category = "JSON") 179 | UJsonFieldData* SetNull(const FString& key); 180 | 181 | /** 182 | * Adds the supplied string array to the post data, under the given key 183 | * 184 | * @param key Key 185 | * @param data Array 186 | * 187 | * @return The object itself 188 | */ 189 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add String Array Field"), Category = "JSON") 190 | UJsonFieldData* SetStringArray(const FString& key, const TArray& data); 191 | 192 | /** 193 | * Adds the supplied boolean array to the post data, under the given key 194 | * 195 | * @param key Key 196 | * @param data Array 197 | * 198 | * @return The object itself 199 | */ 200 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Boolean Array Field"), Category = "JSON") 201 | UJsonFieldData* SetBoolArray(const FString& key, const TArray& data); 202 | 203 | /** 204 | * Adds the supplied float array to the post data, under the given key 205 | * 206 | * @param key Key 207 | * @param data Array 208 | * 209 | * @return The object itself 210 | */ 211 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Float Array Field"), Category = "JSON") 212 | UJsonFieldData* SetFloatArray(const FString& key, const TArray& data); 213 | 214 | /** 215 | * Adds the supplied integer array to the post data, under the given key 216 | * 217 | * @param key Key 218 | * @param data Array 219 | * 220 | * @return The object itself 221 | */ 222 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Integer Array Field"), Category = "JSON") 223 | UJsonFieldData* SetIntArray(const FString& key, const TArray& data); 224 | 225 | /** 226 | * Adds null array to the post data, under the given key, with the given number of nulls 227 | * 228 | * @param key Key 229 | * @param length Number of null entries 230 | * 231 | * @return The object itself 232 | */ 233 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Null Array Field"), Category = "JSON") 234 | UJsonFieldData* SetNullArray(const FString& key, const int32& length); 235 | 236 | /** 237 | * Adds the supplied object to the post data, under the given key 238 | * 239 | * @param key Key 240 | * @param objectData Object data 241 | * 242 | * @return The object itself 243 | */ 244 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Object Field"), Category = "JSON") 245 | UJsonFieldData* SetObject(const FString& key, const UJsonFieldData* objectData); 246 | 247 | /** 248 | * Adds the supplied object array to the post data, under the given key 249 | * 250 | * @param key Key 251 | * @param arrayData Array of object data 252 | * 253 | * @return The object itself 254 | */ 255 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Add Object Array Field"), Category = "JSON") 256 | UJsonFieldData* SetObjectArray(const FString& key, const TArray& arrayData); 257 | 258 | /** 259 | * Tries to get a string from the field data by key, returns the string when successful 260 | * 261 | * @param key Key 262 | * @param success Was the string field found? 263 | * 264 | * @return The requested string, empty if failed 265 | */ 266 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get String Field"), Category = "JSON") 267 | FString GetString(const FString& key, bool& success) const; 268 | 269 | /** 270 | * Tries to get a boolean from the field data by key, returns the boolean when successful 271 | * 272 | * @param key Key 273 | * @param success Was the boolean field found? 274 | * 275 | * @return The requested boolean, always false when failed 276 | */ 277 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Boolean Field"), Category = "JSON") 278 | bool GetBool(const FString& key, bool& success) const; 279 | 280 | /** 281 | * Tries to get an integer from the field data by key, returns the integer when successful 282 | * 283 | * @param key Key 284 | * @param success Was the integer field found? 285 | * 286 | * @return The requested integer, always 0 when failed 287 | */ 288 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Integer Field"), Category = "JSON") 289 | int32 GetInt(const FString& key, bool& success) const; 290 | 291 | /** 292 | * Tries to get a float from the field data by key, returns the float when successful 293 | * 294 | * @param key Key 295 | * @param success Was the float field found? 296 | * 297 | * @return The requested float, always 0.0 when failed 298 | */ 299 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Float Field"), Category = "JSON") 300 | float GetFloat(const FString& key, bool& success) const; 301 | 302 | /** 303 | * Checks if a field is null 304 | * 305 | * @param key Key 306 | * @param fieldExists Was the field found? 307 | * 308 | * @return If the field is null. False if it's not or it was not found. 309 | */ 310 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Field Is Null"), Category = "JSON") 311 | bool GetIsNull(const FString& key, bool& fieldExists) const; 312 | 313 | /** 314 | * Gets a string array from the post data with the given key 315 | * 316 | * @param key Key 317 | * @param success Was the field found? 318 | * 319 | * @return The requested array of strings 320 | */ 321 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get String Array Field"), Category = "JSON") 322 | TArray GetStringArray(const FString& key, bool& success); 323 | 324 | /** 325 | * Gets a boolean array from the post data with the given key 326 | * 327 | * @param key Key 328 | * @param success Was the field found? 329 | * 330 | * @return The requested array of booleans 331 | */ 332 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Boolean Array Field"), Category = "JSON") 333 | TArray GetBoolArray(const FString& key, bool& success); 334 | 335 | /** 336 | * Gets an integer array from the post data with the given key 337 | * 338 | * @param key Key 339 | * @param success Was the field found? 340 | * 341 | * @return The requested array of integers 342 | */ 343 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Integer Array Field"), Category = "JSON") 344 | TArray GetIntArray(const FString& key, bool& success); 345 | 346 | /** 347 | * Gets a float array from the post data with the given key 348 | * 349 | * @param key Key 350 | * @param success Was the field found? 351 | * 352 | * @return The requested array of floats 353 | */ 354 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Float Array Field"), Category = "JSON") 355 | TArray GetFloatArray(const FString& key, bool& success); 356 | 357 | /** 358 | * Gets the post data object from the post data with the given key 359 | * 360 | * @param key Key 361 | * @param success Was the object field found? 362 | * 363 | * @return The object itself 364 | */ 365 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Object Field"), Category = "JSON") 366 | UJsonFieldData* GetObject(const FString& key, bool& success); 367 | 368 | /** 369 | * Gets an object array from the post data with the given key 370 | * 371 | * @param key Key 372 | * @param success Was the field found? 373 | * 374 | * @return The requested post data objects 375 | */ 376 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Object Array Field"), Category = "JSON") 377 | TArray GetObjectArray(const FString& key, bool& success); 378 | 379 | /** 380 | * Gets the keys from the supplied object 381 | * 382 | * @return Array of keys 383 | */ 384 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Object Keys"), Category = "JSON") 385 | TArray GetObjectKeys() const; 386 | 387 | /** 388 | * Sets the fields from the supplied JSON string 389 | * 390 | * @param dataString The JSON string 391 | */ 392 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "From String"), Category = "JSON") 393 | bool FromString(const FString& dataString); 394 | 395 | /** 396 | * Posts the current request data to the internet 397 | * 398 | * @param url The URL to post to 399 | */ 400 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Post JSON Request"), Category = "JSON") 401 | void PostRequest(const FString& url); 402 | 403 | /** 404 | * Posts the current request data to the internet, together with a file 405 | * 406 | * @param FilePath The absolute path for a file 407 | * @param Url The URL to post to 408 | */ 409 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Post JSON Request and File"), Category = "JSON") 410 | void PostRequestWithFile(FString FilePath, const FString& Url); 411 | 412 | /** 413 | * Grabs a page from the internet 414 | * 415 | * @param url The URL to request 416 | * 417 | * @return The newly created post data that will be filled with the url response. 418 | */ 419 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "Get JSON Request"), Category = "JSON") 420 | static UJsonFieldData* GetRequest(const FString& url); 421 | }; 422 | -------------------------------------------------------------------------------- /JSONQuery/Source/JSONQuery/Private/JsonFieldData.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. 2 | #include "JsonFieldData.h" 3 | 4 | #include "JSONQueryModule.h" 5 | #include "Engine/Engine.h" 6 | 7 | ////////////////////////////////////////////////////////////////////////// 8 | // UJsonFieldData 9 | 10 | /** 11 | * Constructor 12 | */ 13 | UJsonFieldData::UJsonFieldData() 14 | { 15 | Reset(); 16 | } 17 | 18 | UJsonFieldData* UJsonFieldData::GetRequest(const FString &url) 19 | { 20 | // Create new page data for the response 21 | UJsonFieldData* dataObj = Create(); 22 | 23 | // Create the HTTP request 24 | TSharedRef< IHttpRequest, ESPMode::ThreadSafe > HttpRequest = FHttpModule::Get().CreateRequest(); 25 | HttpRequest->SetVerb("GET"); 26 | HttpRequest->SetURL(CreateURL(url)); 27 | HttpRequest->OnProcessRequestComplete().BindUObject(dataObj, &UJsonFieldData::OnReady); 28 | 29 | dataObj->AddToRoot(); 30 | 31 | // Execute the request 32 | HttpRequest->ProcessRequest(); 33 | 34 | // Return the page data 35 | return dataObj; 36 | } 37 | 38 | UJsonFieldData* UJsonFieldData::Create() 39 | { 40 | // Construct the object and return it 41 | UJsonFieldData* fieldData = NewObject(); 42 | return fieldData; 43 | } 44 | 45 | UJsonFieldData* UJsonFieldData::FromFile(const FString FilePath, EFolder RelativeTo) 46 | { 47 | FString Result; 48 | FString StartPath; 49 | switch (RelativeTo) 50 | { 51 | case EFolder::Content: StartPath = FPaths::ProjectContentDir(); break; 52 | case EFolder::Project: 53 | default: StartPath = FPaths::ProjectDir(); break; 54 | } 55 | const FString FullJsonPath = FPaths::ConvertRelativePathToFull(StartPath / FilePath); 56 | if (!FFileHelper::LoadFileToString(Result, *FullJsonPath)) 57 | { 58 | UE_LOG(JSONQueryLog, Error, TEXT("Can't load json data from %s"), *FullJsonPath); 59 | return nullptr; 60 | } 61 | UJsonFieldData* JSON(Create()); 62 | JSON->FromString(Result); 63 | return JSON; 64 | } 65 | 66 | FString UJsonFieldData::CreateURL(FString inputURL) 67 | { 68 | if (!inputURL.StartsWith("http")) 69 | { 70 | return "http://" + inputURL; 71 | } 72 | 73 | return inputURL; 74 | } 75 | 76 | void UJsonFieldData::WriteObject(TSharedRef> writer, FString key, FJsonValue* value) 77 | { 78 | if (value->Type == EJson::Null) 79 | { 80 | // Write simple entry, don't a key when it isn't set 81 | if (key.Len() > 0) 82 | { 83 | writer->WriteNull(key); 84 | } 85 | else 86 | { 87 | writer->WriteNull(); 88 | } 89 | } 90 | if (value->Type == EJson::String) 91 | { 92 | // Write simple string entry, don't a key when it isn't set 93 | if (key.Len() > 0) 94 | { 95 | writer->WriteValue(key, value->AsString()); 96 | } 97 | else 98 | { 99 | writer->WriteValue(value->AsString()); 100 | } 101 | } 102 | if (value->Type == EJson::Boolean) 103 | { 104 | // Write simple entry, don't a key when it isn't set 105 | if (key.Len() > 0) 106 | { 107 | writer->WriteValue(key, value->AsBool()); 108 | } 109 | else 110 | { 111 | writer->WriteValue(value->AsBool()); 112 | } 113 | } 114 | if (value->Type == EJson::Number) 115 | { 116 | // Write simple entry, don't a key when it isn't set 117 | if (key.Len() > 0) 118 | { 119 | writer->WriteValue(key, value->AsNumber()); 120 | } 121 | else 122 | { 123 | writer->WriteValue(value->AsNumber()); 124 | } 125 | } 126 | else if (value->Type == EJson::Object) 127 | { 128 | // Write object entry 129 | if (key.Len() > 0) 130 | { 131 | writer->WriteObjectStart(key); 132 | } 133 | else 134 | { 135 | writer->WriteObjectStart(); 136 | } 137 | 138 | // Loop through all the values in the object data 139 | TSharedPtr objectData = value->AsObject(); 140 | for (auto objectValue = objectData->Values.CreateIterator(); objectValue; ++objectValue) 141 | { 142 | // Using recursion to write the key and value to the writer 143 | WriteObject(writer, objectValue.Key(), objectValue.Value().Get()); 144 | } 145 | 146 | writer->WriteObjectEnd(); 147 | } 148 | else if (value->Type == EJson::Array) 149 | { 150 | // Process array entry 151 | writer->WriteArrayStart(key); 152 | 153 | TArray> objectArray = value->AsArray(); 154 | for (int32 i = 0; i < objectArray.Num(); i++) 155 | { 156 | // Use recursion with an empty key to process all the values in the array 157 | WriteObject(writer, "", objectArray[i].Get()); 158 | } 159 | 160 | writer->WriteArrayEnd(); 161 | } 162 | } 163 | 164 | void UJsonFieldData::PostRequest(const FString &url) 165 | { 166 | const FString outStr = ToString(); 167 | 168 | // Log the post data for the user (OPTIONAL) 169 | UE_LOG(LogTemp, Warning, TEXT("Post data: %s"), *outStr); 170 | 171 | // Create the post request with the generated data 172 | TSharedRef< IHttpRequest, ESPMode::ThreadSafe > HttpRequest = FHttpModule::Get().CreateRequest(); 173 | HttpRequest->SetVerb("POST"); 174 | HttpRequest->SetHeader("User-Agent", "UnrealEngine4Client/1.0"); 175 | HttpRequest->SetURL(CreateURL(url)); 176 | HttpRequest->SetHeader("Content-Type", "application/json"); 177 | HttpRequest->SetContentAsString(outStr); 178 | HttpRequest->OnProcessRequestComplete().BindUObject(this, &UJsonFieldData::OnReady); 179 | 180 | AddToRoot(); 181 | // Execute the request 182 | HttpRequest->ProcessRequest(); 183 | } 184 | 185 | void UJsonFieldData::PostRequestWithFile(FString FilePath, const FString &Url) 186 | { 187 | FPaths::NormalizeFilename(FilePath); 188 | TArray RawFileData; 189 | if (!FFileHelper::LoadFileToArray(RawFileData, *FilePath)) 190 | { 191 | OnGetResult.Broadcast(false, this, EJSONResult::JSONParsingFailed); 192 | return; 193 | } 194 | 195 | // The post content 196 | static const FString Boundary = "UnrealEngine4FormDataBoundary"; 197 | TArray Buffer; 198 | 199 | // Add the JSON as a POST var named 'json' 200 | const FString JSONStr = ToString(); 201 | FString Text = FString("\r\n--") + Boundary + "\r\n" 202 | + "Content-Type: text/plain; charset=\"utf-8\"\r\n" 203 | + "Content-disposition: form-data; name=\"json\"\r\n\r\n" 204 | + JSONStr; 205 | 206 | // add the file 207 | FString PathPart, Filename, Extension; 208 | FPaths::Split(FilePath, PathPart, Filename, Extension); 209 | Filename += FString(".") + Extension; 210 | Text += FString("\r\n--") + Boundary + "\r\n" 211 | + "Content-Type: application/octet-stream\r\n" 212 | + "Content-disposition: form-data; name=\"file\"; filename=\"" + Filename + "\"\r\n\r\n"; 213 | const FTCHARToUTF8 Converter1(*Text); 214 | Buffer.Append(reinterpret_cast(const_cast(Converter1.Get())), Converter1.Length()); 215 | Buffer.Append(RawFileData); 216 | 217 | // end POST variables 218 | Text = FString("\r\n--") + Boundary + "--\r\n"; 219 | const FTCHARToUTF8 Converter2(*Text); 220 | Buffer.Append(reinterpret_cast(const_cast(Converter2.Get())), Converter2.Length()); 221 | 222 | // Create the post request with the generated data 223 | TSharedRef< IHttpRequest, ESPMode::ThreadSafe > HttpRequest = FHttpModule::Get().CreateRequest(); 224 | HttpRequest->SetVerb("POST"); 225 | HttpRequest->SetHeader("User-Agent", "UnrealEngine4Client/1.0"); 226 | HttpRequest->SetHeader("Content-Type", FString("multipart/form-data; boundary=") + Boundary); 227 | HttpRequest->SetURL(CreateURL(Url)); 228 | HttpRequest->SetContent(Buffer); 229 | HttpRequest->OnProcessRequestComplete().BindUObject(this, &UJsonFieldData::OnReady); 230 | 231 | // Log the post data for the user (OPTIONAL) 232 | UE_LOG(LogTemp, Warning, TEXT("Post data: %s"), *JSONStr); 233 | 234 | AddToRoot(); 235 | // Execute the request 236 | HttpRequest->ProcessRequest(); 237 | } 238 | 239 | UJsonFieldData* UJsonFieldData::SetString(const FString& key, const FString& value) 240 | { 241 | Data->SetStringField(*key,*value); 242 | return this; 243 | } 244 | 245 | UJsonFieldData* UJsonFieldData::SetBoolean(const FString& key, const bool value) 246 | { 247 | Data->SetBoolField(*key, value); 248 | return this; 249 | } 250 | 251 | UJsonFieldData* UJsonFieldData::SetFloat(const FString& key, const float value) 252 | { 253 | Data->SetNumberField(*key, static_cast(value)); 254 | return this; 255 | } 256 | 257 | UJsonFieldData* UJsonFieldData::SetInt(const FString& key, const int32 value) 258 | { 259 | Data->SetNumberField(*key, static_cast(value)); 260 | return this; 261 | } 262 | 263 | UJsonFieldData* UJsonFieldData::SetNull(const FString& key) 264 | { 265 | Data->SetObjectField(*key, nullptr); 266 | return this; 267 | } 268 | 269 | UJsonFieldData* UJsonFieldData::SetObject(const FString& key, const UJsonFieldData* objectData) 270 | { 271 | Data->SetObjectField(*key, objectData->Data); 272 | return this; 273 | } 274 | 275 | UJsonFieldData* UJsonFieldData::SetObjectArray(const FString& key, const TArray& objectData) 276 | { 277 | TArray> *dataArray = new TArray>(); 278 | 279 | // Loop through the array and create new shared FJsonValueObject instances for every FJsonObject 280 | for (int32 i = 0; i < objectData.Num(); i++) { 281 | dataArray->Add(MakeShareable(new FJsonValueObject(objectData[i]->Data))); 282 | } 283 | 284 | Data->SetArrayField(*key, *dataArray); 285 | return this; 286 | } 287 | 288 | UJsonFieldData* UJsonFieldData::SetStringArray(const FString& key, const TArray& stringData) 289 | { 290 | TArray> *dataArray = new TArray>(); 291 | 292 | // Loop through the input array and add new shareable FJsonValueString instances to the data array 293 | for (int32 i=0; i < stringData.Num(); i++) 294 | { 295 | dataArray->Add(MakeShareable(new FJsonValueString(stringData[i]))); 296 | } 297 | 298 | Data->SetArrayField(*key, *dataArray); 299 | return this; 300 | } 301 | 302 | UJsonFieldData* UJsonFieldData::SetBoolArray(const FString& key, const TArray& data) 303 | { 304 | TArray> *dataArray = new TArray>(); 305 | 306 | // Loop through the input array and add new shareable FJsonValueString instances to the data array 307 | for (int32 i = 0; i < data.Num(); i++) 308 | { 309 | dataArray->Add(MakeShareable(new FJsonValueBoolean(data[i]))); 310 | } 311 | 312 | Data->SetArrayField(*key, *dataArray); 313 | return this; 314 | } 315 | 316 | UJsonFieldData* UJsonFieldData::SetFloatArray(const FString& key, const TArray& data) 317 | { 318 | TArray> *dataArray = new TArray>(); 319 | 320 | // Loop through the input array and add new shareable FJsonValueString instances to the data array 321 | for (int32 i = 0; i < data.Num(); i++) 322 | { 323 | dataArray->Add(MakeShareable(new FJsonValueNumber(static_cast(data[i])))); 324 | } 325 | 326 | Data->SetArrayField(*key, *dataArray); 327 | return this; 328 | } 329 | 330 | UJsonFieldData* UJsonFieldData::SetIntArray(const FString& key, const TArray& data) 331 | { 332 | TArray> *dataArray = new TArray>(); 333 | 334 | // Loop through the input array and add new shareable FJsonValueString instances to the data array 335 | for (int32 i = 0; i < data.Num(); i++) 336 | { 337 | dataArray->Add(MakeShareable(new FJsonValueNumber(static_cast(data[i])))); 338 | } 339 | 340 | Data->SetArrayField(*key, *dataArray); 341 | return this; 342 | } 343 | 344 | UJsonFieldData* UJsonFieldData::SetNullArray(const FString& key, const int32& length) 345 | { 346 | TArray> *dataArray = new TArray>(); 347 | 348 | // Loop through the input array and add new shareable FJsonValueString instances to the data array 349 | for (int32 i = 0; i < length; i++) 350 | { 351 | dataArray->Add(MakeShareable(new FJsonValueNull())); 352 | } 353 | 354 | Data->SetArrayField(*key, *dataArray); 355 | return this; 356 | } 357 | 358 | UJsonFieldData* UJsonFieldData::GetObject(const FString& key, bool& success) 359 | { 360 | // Try to get the object field from the data 361 | const TSharedPtr *outPtr; 362 | if (!Data->TryGetObjectField(*key, outPtr)) 363 | { 364 | // Throw an error and return nullptr when the key could not be found 365 | UE_LOG(JSONQueryLog, Error, TEXT("Entry '%s' not found in the field data!"), *key); 366 | success = false; 367 | return nullptr; 368 | } 369 | 370 | // Create a new field data object and assign the data 371 | UJsonFieldData* FieldObj = UJsonFieldData::Create(); 372 | FieldObj->Data = *outPtr; 373 | 374 | // Return the newly created object 375 | success = true; 376 | return FieldObj; 377 | } 378 | 379 | TArray UJsonFieldData::GetStringArray(const FString& key, bool& success) 380 | { 381 | TArray stringArray; 382 | 383 | // Try to get the array field from the post data 384 | const TArray> *arrayPtr; 385 | if (Data->TryGetArrayField(*key, arrayPtr)) 386 | { 387 | // Iterate through the array and use the string value from all the entries 388 | for (int32 i=0; i < arrayPtr->Num(); i++) 389 | { 390 | stringArray.Add((*arrayPtr)[i]->AsString()); 391 | } 392 | success = true; 393 | } 394 | else 395 | { 396 | // Throw an error when the entry could not be found in the field data 397 | UE_LOG(JSONQueryLog, Error, TEXT("Array entry '%s' not found in the field data!"), *key); 398 | success = false; 399 | } 400 | 401 | // Return the array, if unsuccessful the array will be empty 402 | return stringArray; 403 | } 404 | 405 | TArray UJsonFieldData::GetBoolArray(const FString& key, bool& success) 406 | { 407 | TArray array; 408 | 409 | // Try to get the array field from the post data 410 | const TArray> *arrayPtr; 411 | if (Data->TryGetArrayField(*key, arrayPtr)) 412 | { 413 | // Iterate through the array and use the bool value from all the entries 414 | for (int32 i = 0; i < arrayPtr->Num(); i++) 415 | { 416 | array.Add((*arrayPtr)[i]->AsBool()); 417 | } 418 | success = true; 419 | } 420 | else 421 | { 422 | // Throw an error when the entry could not be found in the field data 423 | UE_LOG(JSONQueryLog, Error, TEXT("Array entry '%s' not found in the field data!"), *key); 424 | success = false; 425 | } 426 | 427 | // Return the array, if unsuccessful the array will be empty 428 | return array; 429 | } 430 | 431 | TArray UJsonFieldData::GetIntArray(const FString& key, bool& success) 432 | { 433 | TArray array; 434 | 435 | // Try to get the array field from the post data 436 | const TArray> *arrayPtr; 437 | if (Data->TryGetArrayField(*key, arrayPtr)) 438 | { 439 | // Iterate through the array and use the bool value from all the entries 440 | for (int32 i = 0; i < arrayPtr->Num(); i++) 441 | { 442 | array.Add(static_cast((*arrayPtr)[i]->AsNumber())); 443 | } 444 | success = true; 445 | } 446 | else 447 | { 448 | // Throw an error when the entry could not be found in the field data 449 | UE_LOG(JSONQueryLog, Error, TEXT("Array entry '%s' not found in the field data!"), *key); 450 | success = false; 451 | } 452 | 453 | // Return the array, if unsuccessful the array will be empty 454 | return array; 455 | } 456 | 457 | TArray UJsonFieldData::GetFloatArray(const FString& key, bool& success) 458 | { 459 | TArray array; 460 | 461 | // Try to get the array field from the post data 462 | const TArray> *arrayPtr; 463 | if (Data->TryGetArrayField(*key, arrayPtr)) 464 | { 465 | // Iterate through the array and use the bool value from all the entries 466 | for (int32 i = 0; i < arrayPtr->Num(); i++) 467 | { 468 | array.Add(static_cast((*arrayPtr)[i]->AsNumber())); 469 | } 470 | success = true; 471 | } 472 | else 473 | { 474 | // Throw an error when the entry could not be found in the field data 475 | UE_LOG(JSONQueryLog, Error, TEXT("Array entry '%s' not found in the field data!"), *key); 476 | success = false; 477 | } 478 | 479 | // Return the array, if unsuccessful the array will be empty 480 | return array; 481 | } 482 | 483 | TArray UJsonFieldData::GetObjectArray(const FString& key, bool& success) 484 | { 485 | TArray objectArray; 486 | 487 | // Try to fetch and assign the array to the array pointer 488 | const TArray> *arrayPtr; 489 | if (Data->TryGetArrayField(*key, arrayPtr)) 490 | { 491 | // Iterate through the input array and create new post data objects for every entry and add them to the objectArray 492 | for (int32 i = 0; i < arrayPtr->Num(); i++) 493 | { 494 | UJsonFieldData* pageData = Create(); 495 | pageData->Data = (*arrayPtr)[i]->AsObject(); 496 | objectArray.Add(pageData); 497 | } 498 | success = true; 499 | } 500 | else 501 | { 502 | // Throw an error, since the value with the supplied key could not be found 503 | UE_LOG(JSONQueryLog, Error, TEXT("Array entry '%s' not found in the field data!"), *key); 504 | success = false; 505 | } 506 | 507 | // Return the array, will be empty if unsuccessful 508 | return objectArray; 509 | } 510 | 511 | TArray UJsonFieldData::GetObjectKeys() const 512 | { 513 | TArray stringArray; 514 | 515 | for (auto currJsonValue = Data->Values.CreateConstIterator(); currJsonValue; ++currJsonValue) 516 | { 517 | stringArray.Add((*currJsonValue).Key); 518 | } 519 | 520 | // Return the array, will be empty if unsuccessful 521 | return stringArray; 522 | } 523 | 524 | FString UJsonFieldData::GetString(const FString& key, bool& success) const 525 | { 526 | FString outString; 527 | 528 | // If the current post data isn't valid, return an empty string 529 | if (!Data->TryGetStringField(*key, outString)) 530 | { 531 | UE_LOG(JSONQueryLog, Error, TEXT("String entry '%s' not found in the field data!"), *key); 532 | success = false; 533 | return ""; 534 | } 535 | 536 | success = true; 537 | return outString; 538 | } 539 | 540 | bool UJsonFieldData::GetBool(const FString& key, bool& success) const 541 | { 542 | bool value; 543 | 544 | // If the current post data isn't valid, return an empty string 545 | if (!Data->TryGetBoolField(*key, value)) 546 | { 547 | UE_LOG(JSONQueryLog, Error, TEXT("Boolean entry '%s' not found in the field data!"), *key); 548 | success = false; 549 | return false; 550 | } 551 | 552 | success = true; 553 | return value; 554 | } 555 | 556 | int32 UJsonFieldData::GetInt(const FString& key, bool& success) const 557 | { 558 | int32 value; 559 | 560 | // If the current post data isn't valid, return an empty string 561 | if (!Data->TryGetNumberField(*key, value)) 562 | { 563 | UE_LOG(JSONQueryLog, Error, TEXT("Number entry '%s' not found in the field data!"), *key); 564 | success = false; 565 | return 0; 566 | } 567 | 568 | success = true; 569 | return value; 570 | } 571 | 572 | float UJsonFieldData::GetFloat(const FString& key, bool& success) const 573 | { 574 | double value; 575 | 576 | // If the current post data isn't valid, return an empty string 577 | if (!Data->TryGetNumberField(*key, value)) 578 | { 579 | UE_LOG(JSONQueryLog, Error, TEXT("Number entry '%s' not found in the field data!"), *key); 580 | success = false; 581 | return 0.0f; 582 | } 583 | 584 | success = true; 585 | return static_cast(value); 586 | } 587 | 588 | bool UJsonFieldData::GetIsNull(const FString& key, bool& success) const 589 | { 590 | // If the current post data isn't valid, return an empty string 591 | if (!Data->HasField(key)) 592 | { 593 | UE_LOG(JSONQueryLog, Error, TEXT("Number entry '%s' not found in the field data!"), *key); 594 | success = false; 595 | return false; 596 | } 597 | 598 | success = true; 599 | return Data->HasTypedField(key); 600 | } 601 | 602 | void UJsonFieldData::Reset() 603 | { 604 | // If the post data is valid 605 | if (Data.IsValid()) 606 | { 607 | // Clear the current post data 608 | Data.Reset(); 609 | } 610 | 611 | // Create a new JSON object 612 | Data = MakeShareable(new FJsonObject()); 613 | } 614 | 615 | bool UJsonFieldData::FromString(const FString& dataString) 616 | { 617 | const TSharedRef> JsonReader = TJsonReaderFactory::Create(dataString); 618 | 619 | // Deserialize the JSON data 620 | const bool isDeserialized = FJsonSerializer::Deserialize(JsonReader, Data); 621 | 622 | if (!isDeserialized || !Data.IsValid()) 623 | { 624 | UE_LOG(JSONQueryLog, Error, TEXT("JSON data is invalid! Input:\n'%s'"), *dataString); 625 | return false; 626 | } 627 | 628 | return true; 629 | } 630 | 631 | void UJsonFieldData::OnReady(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) 632 | { 633 | RemoveFromRoot(); 634 | if (!bWasSuccessful) 635 | { 636 | UE_LOG(JSONQueryLog, Error, TEXT("Response was invalid! Please check the URL.")); 637 | 638 | // Broadcast the failed event 639 | OnGetResult.Broadcast(false, this, EJSONResult::HttpFailed); 640 | return; 641 | } 642 | 643 | // Process the string 644 | if (!FromString(Response->GetContentAsString())) 645 | { 646 | OnGetResult.Broadcast(false, this, EJSONResult::JSONParsingFailed); 647 | } 648 | 649 | // Broadcast the result event 650 | OnGetResult.Broadcast(true, this, EJSONResult::Success); 651 | } 652 | 653 | FString UJsonFieldData::ToString() const 654 | { 655 | FString outStr; 656 | TSharedRef> JsonWriter = TJsonWriterFactory::Create(&outStr); 657 | 658 | // Start writing the response 659 | WriteObject(JsonWriter, "", new FJsonValueObject(Data)); 660 | JsonWriter->Close(); 661 | 662 | return outStr; 663 | } 664 | 665 | bool UJsonFieldData::HasField(const FString& key) const 666 | { 667 | return Data->HasField(key); 668 | } 669 | --------------------------------------------------------------------------------