Http and Json

Today games, it is very common that game is using databases in some way. It might be to do something really complex like keeping track of the player progress in MMORPG style game (World of Warcraft), or as simple as just keeping up the highscores (Spelunky). Knowing how to use Http requests and serializing or deserializing incoming data to Json is essential to achieve that! Json is the most common way to handle the data transfers in http requests.

In this tutorial we ain’t going details about creating the database and setting up the server to communicating with it. We are going to check how to handle it with Unreal Engine side. To check out how to create server, i suggest you to watch some other youtube videos about it.


Starting up!

 

To start up using the http and json, we first need to edit the YourProject.Build.CS file inside the Source/YourProject. We need to add ”Http”, ”Json”, ”JsonUtilities” to modules.

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class SQLProject : ModuleRules
{
  public SQLProject(ReadOnlyTargetRules Target) : base(Target)
  {
    PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "Http", "Json", "JsonUtilities" });
  }
}

 


Dwelving inside the code

Let’s start building our http / json connection next. Create a C++ class based of UObject named C_HttpConnector. We are using this class only to handle the request so we just need the most basic of the classes that is the UObject. If the Constructor wasn’t build automatically, we first need to add it. And at the same time, let’s create the HttpModule module. For that, we also need to #include it.

#include "Runtime/Online/HTTP/Public/Http.h"

 

// Basic Constructor
UC_HttpConnector();
// Module named Http
FHttpModule* Http

We declare our Constructor in .CPP. In Constructor we are going to get Http data into our Http variable.

UC_HttpConnector::UC_HttpConnector()
{
  Http = &FHttpModule::Get();
}

Next we are going to create two function to our header file. File is for sending the request and other is to run some code when request is succeeded. Add these in public section.

FUNCTION(BlueprintCallable, Category = "Http")
// This is where we can set our parameters that is going to be sent with our request. For now, it is just FString types, Data1 and Data2
  void SendHttpRequest(const FString &Data1, const FString &Data2);
// Note that this is the binding response! You cannot add your own parameters or remove the default ones!
  void OnHtttRequestResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccesful);

In .CPP We declare them. Let’s first declare the SendHttpRequest

void UC_HttpConnector::SendHttpRequest(const FString &Data1, const FString &Data2)
{
  // We create a Request Object
  TSharedRef<IHttpRequest> Request = Http->CreateRequest();
  // We are going to bind our request to a function.
  Request->OnProcessRequestComplete().BindUObject(this, &UC_AccountCreator::OnAccountCreationRequestResponse); 
  // This is where we type URL and can set the parameters.
  Request->SetURL(FString::Printf(TEXT("http://MyWebsite.com/MyPhpFile.php?IncomingData1=%s&IncomingData2=%s"), *Data1, *Data2));
  // We are using GET
  Request->SetVerb("GET");
  // We are going to use the Unreal Engine Default
  Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");
  // Our Data is sent as a text or json
  Request->SetHeader("Content-Type", TEXT("application/json"));
  // We sent the request
  Request->ProcessRequest();
}

Now, we set the function if our request is successfull.

void UC_HttpConnector::OnHttpRequestResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccesful)
{
  // We create a JSonObject Object
  TSharedPtr<FJsonObject> JsonObject;
  // We create a JsonReader Object and get convert the data to String
  TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
  if (FJsonSerializer::Deserialize(Reader, JsonObject))
  {
    // We can get bool calues using GetBoolField
    bool GetBool = JsonObject->GetBoolField("SomeBooLFieldReturning");
    // We can get FString values by using GetStringField
    FString GetString = JsonObject->GetStringField("SomeStringFieldReturning");
    // And same as int32
    int32 Getint32 = JsonObject->GetIntegerField("SomeIntReturning");


  }
}

To Clarify, the json that could have returned in this case would have been something like this:

{"SomeBoolFieldReturning":false,"SomeIntReturning":33,"SomeStringFieldReturning":"I Am String"}

Now, in some other class we can either create our C_HttpConnector class in blueprints or in C++. To Create and use it in C++, you could do this.

UC_HttpConnector* HttpConnector;
// Create object from nothing!
HttpConnector = NewObject<UC_HttpConnector>(UC_HttpConnector::StaticClass(), FName("HTTP Connector"));
// Call the function and give Parameters
HttpConnector->SendHttpRequest(FString("MyString"), FString("MyString2"));

In Blueprints, we would search node called Construct object from class and add our UC_HttpConnector to parameter then call the functions from constructed object.


That’s it about creating fully working Http request and then converting incoming data to json and getting the data from it! Of course, these is lot more functions within the Http request object you can use. Just toy with them and try different things. For example, if you know you are getting payload as image, you would want to use

Request->SetHeader("Content-Type", TEXT("multipart form-data/json"));

and then get it using this. Note that if you are sending images or any other data through http, it will comes as raw data. So in this case, image would be just a array on uint8:s that you would need to convert to Texture2D or what ever you want :).

TArray<uint8> Bytes;
Bytes = Response->GetContent();

Creating our own Json.

Now that we know we can read the Json why stop only to http? We can use Json to save and load our game data! To create Json we would do this.

// Create JsonObject from new JsonObject. We need to convert the created object to Shared Pointer because our JsonSaveFile is TSharedPtr.
TSharedPtr<FJsonObject> JsonSaveFile = MakeShareable(new FJsonObject);
// Here we can set our fields!
  JsonSaveFile->SetStringField("Name", "Player");
  JsonSaveFile->SetNumberField("Value", 344);
  JsonSaveFile->SetBoolField("IsTrue", false);
  
// We are going to write our file. Notice that JsonOutputString is a FString that will store the Json stringData. It is plain text. I created it in header file so i can access it in every function.
  TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonOutputString);
// We serialize our Json to JsonOutputString
  FJsonSerializer::Serialize(JsonSaveFile.ToSharedRef(), Writer);

Now to load our custom Json, we ain’t using the GetContentAsString() function. It is only for http requests! Instead we create it from our FString.

TSharedPtr<FJsonObject> JsonObject;
// Create reader and give our FString we created in header file as parameter
  TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonOutputString);

// This is exactly same as Deserializing the Json that came through the http.
  if (FJsonSerializer::Deserialize(Reader, JsonObject))
  {
    bool bBoolField = JsonObject->GetBoolField("IsTrue");
    FString StringField = JsonObject->GetStringField("Name");
    int32 IntField = JsonObject->GetNumberField("Value");
    UE_LOG(LogTemp, Warning, TEXT("%s, %i"), *StringField, IntField);
  }

Of course, loading Json and saving Json should propably be in different functions. That’s it about the Http and Json. Have fun coding and trying! If you have any questions, feel free to ask!

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *