跳转到主要内容

基本环境设置

本文介绍在Unreal Engine C++中使用PlayNANOO REST API的基本环境设置方法。

1. 前置准备

需要提前在PlayNANOO控制台获取以下信息。

获取API认证信息

请登录PlayNANOO控制台确认以下信息。

发放路径: 控制台 > 频道 > 设置 > API & 平台管理

需要获取的信息:

  • Game ID: 频道唯一标识符
  • Service Key: API请求时使用的服务密钥
  • Secret Key: 用于生成安全签名的私密密钥
安全 注意事项

Secret Key绝不能泄露,请通过环境变量或单独的配置文件进行管理。

2. Unreal Engine C++实现

以下是在Unreal Engine中调用PlayNANOO API的实现方法。

2.1 添加模块依赖

首先在项目的Build.cs文件中添加HTTP相关模块。

// YourProject.Build.cs
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"Engine",
"InputCore",
"Http", // HTTP 요청
"Json", // JSON 파싱
"JsonUtilities" // JSON 유틸리티
});

2.2 设备信息结构体 (FDeviceInfo)

所有API请求都需要包含客户端设备信息。使用以下结构体自动收集设备信息。

// DeviceInfo.h
#pragma once

#include "CoreMinimal.h"
#include "Json.h"
#include "GenericPlatform/GenericPlatformMisc.h"
#include "Internationalization/Internationalization.h"

struct FDeviceInfo
{
FString UUID;
FString Nickname;
FString DeviceId;
FString Version;
FString Platform;
FString DeviceModel;
FString DeviceOS;
FString DeviceLanguage;
FString DeviceCountry;
FString DeviceTimeOffset;

FDeviceInfo()
{
// 게임에서 관리하는 플레이어 정보 (로그인 후 설정)
UUID = UGameDataManager::Get()->GetUUID();
Nickname = UGameDataManager::Get()->GetNickname();

// 기기 정보 자동 수집
DeviceId = FPlatformMisc::GetDeviceId();
Version = UGameDataManager::Get()->GetVersionNumber();
Platform = GetPlatformName();
DeviceModel = FPlatformMisc::GetDefaultDeviceProfileName();
DeviceOS = FPlatformMisc::GetOSVersion();
DeviceLanguage = GetDeviceLanguage();
DeviceCountry = GetCountryCode();
DeviceTimeOffset = FString::FromInt(GetTimeOffset());
}

// JSON 객체에 기기 정보 추가
void AddToJson(TSharedPtr<FJsonObject>& JsonObject) const
{
JsonObject->SetStringField(TEXT("uuid"), UUID);
JsonObject->SetStringField(TEXT("nickname"), Nickname);
JsonObject->SetStringField(TEXT("device_id"), DeviceId);
JsonObject->SetStringField(TEXT("version"), Version);
JsonObject->SetStringField(TEXT("platform"), Platform);
JsonObject->SetStringField(TEXT("device_model"), DeviceModel);
JsonObject->SetStringField(TEXT("device_os"), DeviceOS);
JsonObject->SetStringField(TEXT("device_language"), DeviceLanguage);
JsonObject->SetStringField(TEXT("device_country"), DeviceCountry);
JsonObject->SetStringField(TEXT("device_timeoffset"), DeviceTimeOffset);
}

private:
FString GetPlatformName() const
{
#if PLATFORM_WINDOWS
return TEXT("Windows");
#elif PLATFORM_MAC
return TEXT("Mac");
#elif PLATFORM_IOS
return TEXT("iOS");
#elif PLATFORM_ANDROID
return TEXT("Android");
#elif PLATFORM_LINUX
return TEXT("Linux");
#else
return TEXT("Unknown");
#endif
}

FString GetDeviceLanguage() const
{
FString Culture = FInternationalization::Get().GetCurrentCulture()->GetTwoLetterISOLanguageName();
return Culture.ToUpper();
}

FString GetCountryCode() const
{
FString Culture = FInternationalization::Get().GetCurrentCulture()->GetRegion();
if (Culture.IsEmpty())
{
FString Language = GetDeviceLanguage();
if (Language == TEXT("KO")) return TEXT("KR");
if (Language == TEXT("JA")) return TEXT("JP");
if (Language == TEXT("ZH")) return TEXT("CN");
if (Language == TEXT("DE")) return TEXT("DE");
if (Language == TEXT("FR")) return TEXT("FR");
if (Language == TEXT("ES")) return TEXT("ES");
return TEXT("US");
}
return Culture.ToUpper();
}

int32 GetTimeOffset() const
{
FDateTime Now = FDateTime::Now();
FDateTime UtcNow = FDateTime::UtcNow();
FTimespan Offset = Now - UtcNow;
return FMath::RoundToInt(Offset.GetTotalSeconds());
}
};
数据管理

UGameDataManager是需要在游戏中直接实现的单例类。用于管理UUID、Nickname、AccessToken等玩家信息。

2.3 请求Body生成辅助函数

在所有API请求中自动包含设备信息的辅助函数。

// PlayNANOOHelper.h
#pragma once

#include "CoreMinimal.h"
#include "Json.h"
#include "Http.h"
#include "DeviceInfo.h"
#include "PlayNANOOAuth.h"

class FPlayNANOOHelper
{
public:
static TSharedPtr<FJsonObject> CreateRequestBody()
{
TSharedPtr<FJsonObject> Body = MakeShareable(new FJsonObject());
FDeviceInfo DeviceInfo;
DeviceInfo.AddToJson(Body);
return Body;
}

static FString ToJsonString(const TSharedPtr<FJsonObject>& JsonObject)
{
FString JsonBody;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonBody);
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);
return JsonBody;
}

static void SetCommonHeaders(TSharedRef<IHttpRequest>& Request, bool bRequireToken = true)
{
Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
Request->SetHeader(TEXT("Accept"), TEXT("application/json"));
Request->SetHeader(TEXT("X-Playnanoo-Key"), FPlayNANOOAuth::ServiceKey);
Request->SetHeader(TEXT("X-Playnanoo-Id"), FPlayNANOOAuth::GameId);

if (bRequireToken)
{
FString AccessToken = UGameDataManager::Get()->GetAccessToken();
Request->SetHeader(TEXT("Authorization"), FString::Printf(TEXT("Bearer %s"), *AccessToken));
}
}
};

2.4 API请求示例

void UMyGame::SaveStorage(const FString& Key, const FString& Value)
{
TSharedPtr<FJsonObject> Body = FPlayNANOOHelper::CreateRequestBody();
Body->SetStringField(TEXT("key"), Key);
Body->SetStringField(TEXT("value"), Value);

FString JsonBody = FPlayNANOOHelper::ToJsonString(Body);

TSharedRef<IHttpRequest> Request = FHttpModule::Get().CreateRequest();
Request->SetURL(TEXT("https://service-api.playnanoo.com/storage/v20220701/set"));
Request->SetVerb(TEXT("PUT"));
FPlayNANOOHelper::SetCommonHeaders(Request, true);
Request->SetContentAsString(JsonBody);

Request->OnProcessRequestComplete().BindLambda(
[](FHttpRequestPtr Req, FHttpResponsePtr Res, bool bSuccess)
{
if (bSuccess && Res.IsValid())
{
UE_LOG(LogTemp, Log, TEXT("저장 성공: %s"), *Res->GetContentAsString());
}
});

Request->ProcessRequest();
}