Hello,
My game is on the edge to be finished but I’m having some trouble with the reliability of the HTTP library. Sometimes my request simply doesn’t get a response! The server handles it just fine as shown in the server logs but the game doesn’t get a response
This is my class.
#pragma once
#include "CoreMinimal.h"
#include "Runtime/Online/HTTP/Public/Http.h"
#include "Json.h"
#include "PlayerCharacter.h"
#include "Inventory.h"
#include "MasterServer.generated.h"
#define LOCAL_ENVIRONMENT false
#define MASTER_SERVER_IP "XXXXXXX"
#define LOCAL_MASTER_SERVER_IP "127.0.0.1:5000"
UCLASS()
class DAYDSERVER_API UMasterServer : public UObject
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
UMasterServer(const class FObjectInitializer& ObjectInitializer);
FHttpModule* Http;
void RequestCharacterData(uint64 steam_id, TFunction<void(uint64 steam_id, FVector position, FRotator rotation, TArray<FItemInformation> gear, TArray<FItemInformation> pockets)> Callback);
void ReceivedCharacterData(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful, TFunction<void(uint64 steam_id, FVector position, FRotator rotation, TArray<FItemInformation> gear, TArray<FItemInformation> pockets)> Callback);
void CommitCharacterData(uint64 steam_id, float position[3], float yaw, APlayerCharacter* player_character);
};
And my class body is as follows:
#include "MasterServer.h"
UMasterServer::UMasterServer(const class FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
{
Http = &FHttpModule::Get();
}
void UMasterServer::RequestCharacterData(uint64 steam_id, TFunction<void(uint64 steam_id, FVector position, FRotator rotation, TArray<FItemInformation> gear, TArray<FItemInformation> pockets)> Callback)
{
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
Request->OnProcessRequestComplete().BindUObject(this, &UMasterServer::ReceivedCharacterData, Callback);
FString url = FString::Printf(TEXT("http://%s/user/%llu"), *FString(LOCAL_ENVIRONMENT ? LOCAL_MASTER_SERVER_IP : MASTER_SERVER_IP), steam_id);
Request->SetURL(url);
Request->SetVerb("GET");
Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");
Request->SetHeader("Content-Type", TEXT("application/json"));
Request->ProcessRequest();
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("Requested player data"), false);
}
void UMasterServer::ReceivedCharacterData(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful, TFunction<void(uint64 steam_id, FVector position, FRotator rotation, TArray<FItemInformation> gear, TArray<FItemInformation> pockets)> Callback)
{
if (bWasSuccessful && Request->GetResponse()->GetResponseCode() == 200)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("Player data arrived"), false);
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
if (FJsonSerializer::Deserialize(Reader, JsonObject))
{
FString steam_id_string = JsonObject->GetStringField("steam_id");
FVector position = FVector((float)JsonObject->GetNumberField("pos_x"), (float)JsonObject->GetNumberField("pos_y"), (float)JsonObject->GetNumberField("pos_z"));
FRotator rotation = FRotator(0.0f, (float)JsonObject->GetNumberField("yaw"), 0.0f);
uint64 steam_id = FCString::Strtoui64(*steam_id_string, NULL, 10);
TArray<FItemInformation> gear;
TArray<FItemInformation> pockets;
TArray<TSharedPtr<FJsonValue>> inventories = JsonObject->GetArrayField("inventories");
for (int i = 0; i < inventories.Num(); i++) {
TSharedPtr<FJsonObject> inventory = inventories[i]->AsObject();
int item_id = inventory->GetIntegerField("item_id");
int inventory_id = inventory->GetIntegerField("inventory_id");
int position_x = inventory->GetIntegerField("position_x");
int position_y = inventory->GetIntegerField("position_y");
int amount = inventory->GetIntegerField("amount");
FItemInformation item;
item.id = item_id;
item.inventory_position_x = position_x;
item.inventory_position_y = position_y;
item.amount = amount;
switch (inventory_id)
{
case (uint8)InventoryTypes::Gear:
gear.Add(item);
break;
case (uint8)InventoryTypes::Pockets:
pockets.Add(item);
break;
}
}
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Data parsed"), false);
Callback(steam_id, position, rotation, gear, pockets);
}
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Green, TEXT("Character data request failed"), false);
}
}
void UMasterServer::CommitCharacterData(uint64 steam_id, float position[3], float yaw, APlayerCharacter* player_character)
{
FHttpModule* Http = &FHttpModule::Get();
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
FString url = FString::Printf(TEXT("http://%s/user/%llu"), *FString(LOCAL_ENVIRONMENT ? LOCAL_MASTER_SERVER_IP : MASTER_SERVER_IP), steam_id);
Request->SetURL(url);
Request->SetVerb("POST");
Request->SetHeader("Content-Type", TEXT("application/json"));
FString payload = FString::Printf(TEXT("{\"pos_x\":%f, \"pos_y\":%f, \"pos_z\":%f, \"yaw\":%f, \"inventory\": ["), position[0], position[1], position[2], yaw);
bool first = true;
for (FItemInformation item_information : player_character->gear->items)
{
if (!first)
payload.Append(",");
payload.Append(FString::Printf(TEXT("{ \"item_id\":%d, \"inventory_id\":%d, \"position_x\":%d, \"position_y\":%d, \"amount\":%d }"),
item_information.id,
(uint8)InventoryTypes::Gear,
item_information.inventory_position_x,
item_information.inventory_position_y,
item_information.amount));
first = false;
}
for (FItemInformation item_information : player_character->pockets->items)
{
if (!first)
payload.Append(",");
payload.Append(FString::Printf(TEXT("{ \"item_id\":%d, \"inventory_id\":%d, \"position_x\":%d, \"position_y\":%d, \"amount\":%d }"),
item_information.id,
(uint8)InventoryTypes::Pockets,
item_information.inventory_position_x,
item_information.inventory_position_y,
item_information.amount));
first = false;
}
payload.Append("]}");
Request->SetContentAsString(payload);
Request->ProcessRequest();
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Player data commited"), false);
}
Anyone has any clues why ReceivedCharacterData is more often than not, not called?? The server is a Python API running on GUnicorn and NGINX handling requests. I also run this same script with a simple Python server and the behavior persists.