
Unreal Engine 클라이언트에 Puerts 붙이기

Client 프로젝트에 Puerts를 연동해 JavaScript를 실행시켜 봤다. 플러그인을 켜는 일부터 실제로 JS가 도는지 확인하기까지, 작업하면서 남긴 기록을 정리해 둔다.
작업 환경
이번 작업의 범위는 다음과 같다.
- 프로젝트:
D:/UnrealProject/Projects/TechDemo/Client - Unreal Engine:
5.7 - Puerts 플러그인 위치:
Plugins/unreal/Puerts - JavaScript 루트:
Content/JavaScript - 테스트 엔트리:
Content/JavaScript/main.js
플러그인 켜기
먼저 Client.uproject의 Plugins 목록에 Puerts를 직접 적어 넣었다.
{
"Name": "Puerts",
"Enabled": true
}
Puerts의 .uplugin 파일에는 이미 EnabledByDefault가 켜져 있다. 그래도 프로젝트 설정에 한 번 더 명시해 두면 프로젝트 단위로 활성화 상태가 훨씬 분명해진다.
플러그인이 제대로 마운트됐는지는 에디터 로그의 이 문자열로 확인할 수 있다.
LogPluginManager: Mounting Project plugin Puerts
C++ 모듈 의존성 추가
다음으로 Source/Client/Client.Build.cs의 PrivateDependencyModuleNames에 Puerts 런타임 모듈을 넣었다.
PrivateDependencyModuleNames.AddRange(new string[]
{
"JsEnv",
"Puerts",
"Slate",
"SlateCore",
});
JsEnv는 PUERTS_NAMESPACE::FJsEnv를 쓰기 위한 핵심 모듈이고, Puerts는 플러그인 런타임 모듈이다.
JavaScript 엔트리 만들기
동작 검증부터 해보려고 Content/JavaScript/main.js를 하나 추가했다.
"use strict";
console.log("[Puerts] Client JavaScript bootstrap loaded");
Puerts의 FJsEnv는 TEXT("JavaScript")를 루트로 생성했다. 그래서 Start(TEXT("main.js"))를 호출하면 Content/JavaScript/main.js가 실행된다.
런타임 헬퍼로 묶기
Puerts 환경 생성을 한곳에서 관리하려고 Source/Client/Private/ClientJavaScriptRuntime.*를 추가했다. 핵심 로직은 이게 전부다.
GClientJavaScriptEnvironment = MakeUnique<PUERTS_NAMESPACE::FJsEnv>(TEXT("JavaScript"));
GClientJavaScriptEnvironment->Start(TEXT("main.js"));
StartIfNeeded()는 환경이 이미 살아 있으면 중복으로 만들지 않고, Shutdown()은 들고 있던 FJsEnv를 해제한다.
지금 구현 파일은 두 개다.
Source/Client/Private/ClientJavaScriptRuntime.hSource/Client/Private/ClientJavaScriptRuntime.cpp
GameInstance에 연결하기
UClientGameInstance::Init()에서 JavaScript 런타임을 시작하도록 호출을 걸었다.
FClientJavaScriptRuntime::StartIfNeeded(TEXT("GameInstance"));
Shutdown()에서는 다시 런타임을 해제한다.
FClientJavaScriptRuntime::Shutdown(TEXT("GameInstance"));
상태를 확인할 수 있게 BlueprintCallable 함수도 하나 추가했다.
UFUNCTION(BlueprintCallable, Category = "Client|JavaScript")
bool IsJavaScriptEnvironmentStarted() const;
이 함수는 FClientJavaScriptRuntime::IsStarted()를 그대로 반환한다.
PIE 검증에서 잠깐 우회
처음 검증할 때 UClientGameInstance::Init() 로그가 PIE 로그에 바로 잡히지 않았다. 그래서 PIE에서 확실히 불리는 AClientPlayerController::ReceivedPlayer() 경로에 JavaScript 시작 호출을 임시로 붙여 확인했다.
당시 임시 검증 코드는 이랬다.
void AClientPlayerController::ReceivedPlayer()
{
Super::ReceivedPlayer();
FClientJavaScriptRuntime::StartIfNeeded(TEXT("PlayerController"));
RefreshPlayerInput();
}
이 경로로 PIE를 돌리니 아래 로그가 찍혔다.
Puerts: [Puerts] Client JavaScript bootstrap loaded
LogClient: Puerts JavaScript runtime started (PlayerController)
검증이 끝난 뒤 시작 호출은 다시 걷어냈다. 지금 ReceivedPlayer()는 입력 갱신만 한다.
void AClientPlayerController::ReceivedPlayer()
{
Super::ReceivedPlayer();
RefreshPlayerInput();
}
지금 코드 상태
현재 기준으로 남아 있는 Puerts 관련 상태를 정리하면 이렇다.
Client.uproject: Puerts enabledClient.Build.cs:JsEnv,Puerts의존성 유지Content/JavaScript/main.js: 테스트 로그 스크립트 존재ClientJavaScriptRuntime.*: PuertsFJsEnv생성/해제 헬퍼 존재UClientGameInstance::Init():StartIfNeeded(TEXT("GameInstance"))호출UClientGameInstance::Shutdown():Shutdown(TEXT("GameInstance"))호출AClientPlayerController::ReceivedPlayer(): JavaScript 시작 호출 제거됨AClientPlayerController::EndPlay():Shutdown(TEXT("PlayerController"))호출 존재
AClientPlayerController::EndPlay()의 shutdown 호출은 런타임이 시작돼 있지 않으면 아무 일도 하지 않는다.
빌드와 검증
빌드는 UnrealBuildTool로 했다.
& "C:\Program Files\Epic Games\UE_5.7\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.exe" ClientEditor Win64 Development -Project="D:\UnrealProject\Projects\TechDemo\Client\Client.uproject" -WaitMutex -NoHotReloadFromIDE
여기서 한 가지 주의할 점. 에디터가 켜져 있으면 Binaries/Win64/UnrealEditor-Client.dll을 물고 있어서 링크 단계에서 빌드가 깨질 수 있다.
대표적인 실패 로그는 이렇다.
LINK : fatal error LNK1104: 'D:\UnrealProject\Projects\TechDemo\Client\Binaries\Win64\UnrealEditor-Client.dll' 파일을 열 수 없음
이럴 때는 Unreal Editor와 Rider 디버거(LLDBFrontend.exe)를 닫고 다시 빌드하면 된다.
확인용 로그 문자열 모음
작업하면서 단계별로 기준이 됐던 로그들을 모아 둔다.
Puerts 플러그인 로드 확인:
LogPluginManager: Mounting Project plugin Puerts
JavaScript 엔트리 실행 확인:
[Puerts] Client JavaScript bootstrap loaded
C++ 런타임 헬퍼 시작 확인:
Puerts JavaScript runtime started
앞으로 정리할 거리
테스트 목적이 끝났다면, 다음 항목은 프로젝트 방향에 맞춰 정리하면 된다.
- 실제 JS 런타임을 계속 쓸 계획이면
ClientJavaScriptRuntime.*는 그대로 유지한다. - 당장 Puerts 진입점이 필요 없다면
main.js의 테스트 로그를 지우거나 파일을 비워 둔다. - 정식 런타임 진입점은
GameInstance,GameSubsystem,WorldSubsystem중 하나로 명확히 정해 두는 편이 좋다.
역인 글
텐센트 PUER TypeScript 라이브러리
소개의 말 : 중국에서 게임개발을 하면서 경험?한 바로는 콘텐트 프로그래밍은 주로 스크립트 기반에서 개발하는 경향을 띄고 있다고 말 할 수 있겠습니다. 2022년 출시 했던 드레곤헤어 침묵의
techartnomad.tistory.com
'UNREAL ENGINE' 카테고리의 다른 글
| Game Animation Technologies: Technical Comparison (0) | 2026.06.02 |
|---|---|
| 텐센트 SLua-Unreal — PUBG Mobile이 선택한 UE Lua 스크립팅, 그리고 중국 시장에서 Lua가 필수인 이유 (2) | 2026.05.04 |
| BP 편집 모드 Viewport 카메라 FOV 추가. 깃-패치 제공 (0) | 2026.01.24 |
| [메모] UE 프로젝트에 대한 HLSL 지원 설정 (0) | 2026.01.07 |
| Unreal Engine의 숨겨진 최적화: Roughness 1.0이 만드는 마법 (0) | 2025.10.28 |