본문으로 건너뛰기

기본 환경 설정

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 요청 바디 생성 헬퍼 함수​

모든 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();
}