基本环境设置
本文介绍在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();
}