Skip to content

Commit

Permalink
Unreal SDK - Added counters to unreal sdk (#3935)
Browse files Browse the repository at this point in the history
* added counters to unreal sdk

* Update unreal.md

* reduce amount of copy-paste code

* Fix comments in AgonesComponent.h

* Update AgonesComponent.cpp

* Update AgonesComponent.h

* Fix unreal GetCounter

Found an issue with default initialized content string that by default {} (braces). That caused Get req. to fail.

---------

Co-authored-by: igooch <[email protected]>
  • Loading branch information
GloryOfNight and igooch authored Sep 6, 2024
1 parent 127183c commit 0625ae5
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 7 deletions.
22 changes: 22 additions & 0 deletions sdks/unreal/Agones/Source/Agones/Classes/Classes.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,25 @@ struct FConnectedPlayersResponse
JsonObject->TryGetStringArrayField(TEXT("list"), ConnectedPlayers);
}
};

USTRUCT(BlueprintType)
struct FCounterResponse
{
GENERATED_BODY()

FCounterResponse()
{
}

UPROPERTY(BlueprintReadOnly, Category = "Agones")
int64 Count;

UPROPERTY(BlueprintReadOnly, Category = "Agones")
int64 Capacity;

explicit FCounterResponse(const TSharedPtr<FJsonObject> JsonObject)
{
JsonObject->TryGetNumberField(TEXT("count"), Count);
JsonObject->TryGetNumberField(TEXT("capacity"), Capacity);
}
};
102 changes: 102 additions & 0 deletions sdks/unreal/Agones/Source/Agones/Private/AgonesComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "HttpModule.h"
#include "Interfaces/IHttpResponse.h"
#include "JsonObjectConverter.h"
#include "Policies/CondensedJsonPrintPolicy.h"
#include "TimerManager.h"
#include "IWebSocket.h"
#include "WebSocketsModule.h"
Expand All @@ -30,6 +31,15 @@ typedef UTF8CHAR UTF8FromType;
typedef ANSICHAR UTF8FromType;
#endif

template <typename CharType = TCHAR, typename PrintPolicy = TCondensedJsonPrintPolicy<TCHAR>>
bool JsonObjectToJsonString(const TSharedRef<FJsonObject>& JsonObject, FString& OutJson, int32 Indent = 0)
{
TSharedRef<TJsonWriter<CharType, PrintPolicy>> JsonWriter = TJsonWriterFactory<CharType, PrintPolicy>::Create(&OutJson, Indent);
bool bSuccess = FJsonSerializer::Serialize(JsonObject, JsonWriter);
JsonWriter->Close();
return bSuccess;
}

UAgonesComponent::UAgonesComponent()
{
PrimaryComponentTick.bCanEverTick = false;
Expand Down Expand Up @@ -65,6 +75,44 @@ void UAgonesComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
}
}

void UAgonesComponent::UpdateCounter(const FString& Key, const int64* Count, const int64* Capacity, const int64* CountDiff, FUpdateCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
TSharedRef<FJsonObject> JsonObject = MakeShareable(new FJsonObject());

if (Count)
{
JsonObject->SetNumberField(TEXT("count"), *Count);
}
if (Capacity)
{
JsonObject->SetNumberField(TEXT("capacity"), *Capacity);
}
if (CountDiff)
{
JsonObject->SetNumberField(TEXT("countDiff"), *CountDiff);
}

FString Json;
if (!JsonObjectToJsonString(JsonObject, Json))
{
ErrorDelegate.ExecuteIfBound({ TEXT("Failed to serializing request") });
return;
}

FHttpRequestRef Request = BuildAgonesRequest(FString::Format(TEXT("v1beta1/counters/{0}"), { Key }), FHttpVerb::Patch, Json);
Request->OnProcessRequestComplete().BindWeakLambda(this,
[SuccessDelegate, ErrorDelegate](FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, const bool bSucceeded)
{
if (!IsValidResponse(bSucceeded, HttpResponse, ErrorDelegate))
{
return;
}

SuccessDelegate.ExecuteIfBound({});
});
Request->ProcessRequest();
}

FHttpRequestRef UAgonesComponent::BuildAgonesRequest(const FString Path, const FHttpVerb Verb, const FString Content)
{
FHttpModule* Http = &FHttpModule::Get();
Expand Down Expand Up @@ -460,6 +508,60 @@ void UAgonesComponent::SetPlayerCapacity(
Request->ProcessRequest();
}

void UAgonesComponent::GetCounter(FString Key, FGetCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
FHttpRequestRef Request = BuildAgonesRequest(FString::Format(TEXT("v1beta1/counters/{0}"), {Key}), FHttpVerb::Get, "");
Request->OnProcessRequestComplete().BindWeakLambda(this,
[SuccessDelegate, ErrorDelegate](FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, const bool bSucceeded)
{
TSharedPtr<FJsonObject> JsonObject;
if (!IsValidJsonResponse(JsonObject, bSucceeded, HttpResponse, ErrorDelegate))
{
return;
}

SuccessDelegate.ExecuteIfBound(FCounterResponse(JsonObject));
});
Request->ProcessRequest();
}

void UAgonesComponent::IncrementCounter(FString Key, int64 Amount, FIncrementCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
const auto UpdateSuccessDelegate = FUpdateCounterDelegate::CreateLambda([SuccessDelegate](const FEmptyResponse&)
{
SuccessDelegate.ExecuteIfBound({});
});
UpdateCounter(Key, nullptr, nullptr, &Amount, UpdateSuccessDelegate, ErrorDelegate);
}

void UAgonesComponent::DecrementCounter(FString Key, int64 Amount, FDecrementCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
const int64 NegativeAmount = -Amount;
const auto UpdateSuccessDelegate = FUpdateCounterDelegate::CreateLambda([SuccessDelegate](const FEmptyResponse&)
{
SuccessDelegate.ExecuteIfBound({});
});
UpdateCounter(Key, nullptr, nullptr, &NegativeAmount, UpdateSuccessDelegate, ErrorDelegate);
}

void UAgonesComponent::SetCounterCount(FString Key, int64 Count, FSetCounterCountDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
const auto UpdateSuccessDelegate = FUpdateCounterDelegate::CreateLambda([SuccessDelegate](const FEmptyResponse&)
{
SuccessDelegate.ExecuteIfBound({});
});
UpdateCounter(Key, &Count, nullptr, nullptr, UpdateSuccessDelegate, ErrorDelegate);
}

void UAgonesComponent::SetCounterCapacity(FString Key, int64 Capacity, FSetCounterCapacityDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
const auto UpdateSuccessDelegate = FUpdateCounterDelegate::CreateLambda([SuccessDelegate](const FEmptyResponse&)
{
SuccessDelegate.ExecuteIfBound({});
});
UpdateCounter(Key, nullptr, &Capacity, nullptr, UpdateSuccessDelegate, ErrorDelegate);
}

void UAgonesComponent::GetPlayerCapacity(FGetPlayerCapacityDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate)
{
FHttpRequestRef Request = BuildAgonesRequest("alpha/player/capacity", FHttpVerb::Get, "");
Expand Down
67 changes: 66 additions & 1 deletion sdks/unreal/Agones/Source/Agones/Public/AgonesComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ DECLARE_DYNAMIC_DELEGATE_OneParam(FSetLabelDelegate, const FEmptyResponse&, Resp

DECLARE_DYNAMIC_DELEGATE_OneParam(FSetPlayerCapacityDelegate, const FEmptyResponse&, Response);

DECLARE_DYNAMIC_DELEGATE_OneParam(FGetCounterDelegate, const FCounterResponse&, Response);

DECLARE_DYNAMIC_DELEGATE_OneParam(FIncrementCounterDelegate, const FEmptyResponse&, Response);

DECLARE_DYNAMIC_DELEGATE_OneParam(FDecrementCounterDelegate, const FEmptyResponse&, Response);

DECLARE_DYNAMIC_DELEGATE_OneParam(FSetCounterCountDelegate, const FEmptyResponse&, Response);

DECLARE_DYNAMIC_DELEGATE_OneParam(FSetCounterCapacityDelegate, const FEmptyResponse&, Response);

DECLARE_DYNAMIC_DELEGATE_OneParam(FShutdownDelegate, const FEmptyResponse&, Response);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FConnectedDelegate, const FGameServerResponse&, Response);
Expand All @@ -63,7 +73,8 @@ class FHttpVerb
{
Get,
Post,
Put
Put,
Patch
};

// ReSharper disable once CppNonExplicitConvertingConstructor
Expand All @@ -79,6 +90,8 @@ class FHttpVerb
return TEXT("POST");
case Put:
return TEXT("PUT");
case Patch:
return TEXT("PATCH");
case Get:
default:
return TEXT("GET");
Expand Down Expand Up @@ -290,7 +303,59 @@ class AGONES_API UAgonesComponent final : public UActorComponent
UFUNCTION(BlueprintCallable, Category = "Agones | Alpha | Player Tracking")
void SetPlayerCapacity(int64 Count, FSetPlayerCapacityDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

/**
* \brief [Beta] GetCounter return counter (count and capacity) associated with a Key.
* \param Key - Key to counter value
* \param SuccessDelegate - Called on Successful call.
* \param ErrorDelegate - Called on Unsuccessful call.
*/
UFUNCTION(BlueprintCallable, Category = "Agones | Beta | Counters")
void GetCounter(FString Key, FGetCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

/**
* \brief [Beta] IncrementCounter incremenets counter associated with a Key by 1.
* \param Key - Key to counter value
* \param Amount - Amount that would be added to count.
* \param SuccessDelegate - Called on Successful call.
* \param ErrorDelegate - Called on Unsuccessful call.
*/
UFUNCTION(BlueprintCallable, Category = "Agones | Beta | Counters")
void IncrementCounter(FString Key, int64 Amount, FIncrementCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

/**
* \brief [Beta] DecrementCounter decremenets counter associated with a Key by 1.
* \param Key - Key to counter value
* \param Amount - Amount that would be decremented from count.
* \param SuccessDelegate - Called on Successful call.
* \param ErrorDelegate - Called on Unsuccessful call.
*/
UFUNCTION(BlueprintCallable, Category = "Agones | Beta | Counters")
void DecrementCounter(FString Key, int64 Amount, FDecrementCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

/**
* \brief [Beta] SetCounterCount set counter count associated with a Key.
* \param Key - Key to counter value
* \param Count - Active sessions count.
* \param SuccessDelegate - Called on Successful call.
* \param ErrorDelegate - Called on Unsuccessful call.
*/
UFUNCTION(BlueprintCallable, Category = "Agones | Beta | Counters")
void SetCounterCount(FString Key, int64 Count, FSetCounterCountDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

/**
* \brief [Beta] SetCounterCount set counter capacity associated with a Key.
* \param Key - Key to counter value
* \param Capacity - Capacity of game server.
* \param SuccessDelegate - Called on Successful call.
* \param ErrorDelegate - Called on Unsuccessful call.
*/
UFUNCTION(BlueprintCallable, Category = "Agones | Beta | Counters")
void SetCounterCapacity(FString Key, int64 Capacity, FSetCounterCapacityDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

private:
DECLARE_DELEGATE_OneParam(FUpdateCounterDelegate, const FEmptyResponse&);
void UpdateCounter(const FString& Key, const int64* Count, const int64* Capacity, const int64* CountDiff, FUpdateCounterDelegate SuccessDelegate, FAgonesErrorDelegate ErrorDelegate);

FHttpRequestRef BuildAgonesRequest(
FString Path = "", const FHttpVerb Verb = FHttpVerb::Post, const FString Content = "{}");

Expand Down
12 changes: 6 additions & 6 deletions site/content/en/docs/Guides/Client SDKs/unreal.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ Check the [Client SDK Documentation]({{< relref "_index.md" >}}) for more detail
| Configuration | Watch | ✔️ |
| Metadata | SetAnnotation | ✔️ |
| Metadata | SetLabel | ✔️ |
| Counters | GetCounterCount | |
| Counters | SetCounterCount | |
| Counters | IncrementCounter | |
| Counters | DecrementCounter | |
| Counters | SetCounterCapacity | |
| Counters | GetCounterCapacity | |
| Counters | GetCounterCount | ✔️ |
| Counters | SetCounterCount | ✔️ |
| Counters | IncrementCounter | ✔️ |
| Counters | DecrementCounter | ✔️ |
| Counters | SetCounterCapacity | ✔️ |
| Counters | GetCounterCapacity | ✔️ |
| Lists | AppendListValue ||
| Lists | DeleteListValue ||
| Lists | SetListCapacity ||
Expand Down

0 comments on commit 0625ae5

Please sign in to comment.