Unreal Engine Integration (C++)
This guide shows how to integrate Scrya ads into an Unreal Engine project using FHttpModule. Works with UE5.x.
Setup
Add HTTP and Json modules to your Build.cs:
// YourGame.Build.cs
PublicDependencyModuleNames.AddRange(new string[] {
"Core", "CoreUObject", "Engine", "HTTP", "Json", "JsonUtilities"
}); HTTP Helper
// ScryaAds.h
#pragma once
#include "CoreMinimal.h"
#include "Http.h"
class YOURGAME_API FScryaAds
{
public:
static const FString ApiBase;
static FString ApiKey;
static FString GameId;
static void PostJson(const FString& Endpoint, const FString& JsonBody,
TFunction<void(FHttpResponsePtr, bool)> Callback);
};
// ScryaAds.cpp
#include "ScryaAds.h"
const FString FScryaAds::ApiBase = TEXT("https://api.scrya.com/api/ads");
FString FScryaAds::ApiKey = TEXT("sk_live_your_key_here");
FString FScryaAds::GameId = TEXT("your_game_id");
void FScryaAds::PostJson(const FString& Endpoint, const FString& JsonBody,
TFunction<void(FHttpResponsePtr, bool)> Callback)
{
auto Request = FHttpModule::Get().CreateRequest();
Request->SetURL(ApiBase + Endpoint);
Request->SetVerb(TEXT("POST"));
Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
Request->SetHeader(TEXT("Authorization"), TEXT("Bearer ") + ApiKey);
Request->SetContentAsString(JsonBody);
Request->OnProcessRequestComplete().BindLambda(
[Callback](FHttpRequestPtr Req, FHttpResponsePtr Resp, bool bSuccess)
{
Callback(Resp, bSuccess && Resp.IsValid() && Resp->GetResponseCode() == 200);
});
Request->ProcessRequest();
} Step 1: Match an Ad
void UAdComponent::MatchAd(const FString& PlayerId, const FString& Narrative,
const TArray<FString>& MoodTags)
{
TSharedPtr<FJsonObject> Root = MakeShareable(new FJsonObject);
Root->SetStringField("game_id", FScryaAds::GameId);
Root->SetStringField("user_id", PlayerId);
// Player geo
TSharedPtr<FJsonObject> Geo = MakeShareable(new FJsonObject);
Geo->SetStringField("country_code", "US");
Root->SetObjectField("player_geo", Geo);
// Game context
TSharedPtr<FJsonObject> Context = MakeShareable(new FJsonObject);
Context->SetStringField("theme_id", "3");
Context->SetStringField("category", "simulation");
Context->SetStringField("narrative", Narrative);
TArray<TSharedPtr<FJsonValue>> Moods;
for (const auto& Tag : MoodTags)
Moods.Add(MakeShareable(new FJsonValueString(Tag)));
Context->SetArrayField("mood_tags", Moods);
Root->SetObjectField("game_context", Context);
Root->SetStringField("session_id", FGuid::NewGuid().ToString());
FString JsonBody;
auto Writer = TJsonWriterFactory<>::Create(&JsonBody);
FJsonSerializer::Serialize(Root.ToSharedRef(), Writer);
FScryaAds::PostJson("/match", JsonBody,
[this](FHttpResponsePtr Response, bool bSuccess)
{
if (!bSuccess)
{
UE_LOG(LogTemp, Log, TEXT("No ad matched (normal)"));
OnAdMatched(false, "", "", "");
return;
}
TSharedPtr<FJsonObject> Json;
auto Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
FJsonSerializer::Deserialize(Reader, Json);
FString CampaignId = Json->GetStringField("campaign_id");
FString CreativeId = Json->GetStringField("creative_id");
FString Hook = Json->GetStringField("narrative_hook");
CachedCampaignId = CampaignId;
CachedCreativeId = CreativeId;
OnAdMatched(true, CampaignId, CreativeId, Hook);
});
} Step 2: Inject the Hook
void UAdComponent::OnAdMatched(bool bMatched, const FString& CampaignId,
const FString& CreativeId, const FString& NarrativeHook)
{
if (bMatched)
{
// Add to dialogue system
UDialogueSubsystem* Dialogue = GetWorld()->GetSubsystem<UDialogueSubsystem>();
if (Dialogue)
{
Dialogue->InjectLine(NarrativeHook);
}
}
} Step 3: Record Impression
void UAdComponent::RecordImpression()
{
if (CachedCampaignId.IsEmpty()) return;
TSharedPtr<FJsonObject> Root = MakeShareable(new FJsonObject);
Root->SetStringField("campaign_id", CachedCampaignId);
Root->SetStringField("creative_id", CachedCreativeId);
Root->SetStringField("game_id", FScryaAds::GameId);
FString JsonBody;
auto Writer = TJsonWriterFactory<>::Create(&JsonBody);
FJsonSerializer::Serialize(Root.ToSharedRef(), Writer);
FScryaAds::PostJson("/impressions", JsonBody,
[](FHttpResponsePtr Response, bool bSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Impression %s"),
bSuccess ? TEXT("recorded") : TEXT("failed"));
});
}