언리얼 모듈 & 플러그인 만들기

김혁·2025년 9월 4일

모듈이란?

개념

  • 모듈은 간단하게 말하면, 엔진이나 게임 프로젝트의 기능 단위 패키지
  • 언리얼 엔진의 C++ 코드는 모듈 단위로 나누어져 있음
  • 모듈은 하나의 빌드 단위이자 런타임 로딩 단위
  • 각각의 모듈은 .Build.cs 파일을 가지고 있어서 어떤 라이브러리에 의존하는지, 어떤 방식으로 로드되는지 정의

예시

  • Engine 모듈 : Core, CoreUObject, Engine, InputCore
  • 게임 프로젝트 모듈 : MyGame, MyGameEditor
  • 플러그인 모듈 : 애플리케이션에 특정 기능을 추가하는 플러그인

모듈의 로딩 방식 종류

  • Runtime : 게임 실행 중 항상 로드됨
  • RuntimeLoaded : 필요할 때만 로드됨
  • Developer : 에디터 개발 시에만 로드됨
  • Editor : 에디터 전용 모듈
  • EditorNoCommandlet : 커맨드렛 실행 시는 로드하지 않음
  • DeveloperTool : 툴 제작 시만 사용
    -> 모듈마다 로딩 방식을 지정해서 필요할 때만 사용할 수 있음

모듈 만들기

Source 폴더 구조

  1. 타겟 설정 파일들
    • 해당 프로젝트가 사용할, 즉 빌드 대상을 지정함
    • {프로젝트명}.Target.cs : 실행 파일 빌드 설정 파일
    • {프로젝트명}Editor.Target.cs : 에디터 빌드 설정 파일
  2. 모듈 설정 파일
    • 해당 모듈을 빌드하기 위한 C++ 프로젝트 설정 정보
    • {모듈명}.Build.cs : 엔진에 있는 다른 모듈을 사용하기 위해 모듈들을 추가한 파일
  3. 모듈 C++ 소스파일
    • 모듈의 소스코드가 작성된 파일들

모듈 제작 (예 : 모듈명 "Test")

  1. Source 폴더 -> 새 폴더 "Test"
  2. Test 폴더 -> 새 파일 "Test.Build.cs" -> 모듈의 의존성 정의
  3. Test 폴더 -> 새 파일 "Test.h", "Test.cpp" -> 모듈 시작/종료 지점 정의
// Test.Build.cs

using UnrealBuildTool;

public class Test : ModuleRules
{
	public Test(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

		// 해당 모듈을 헤더 파일과 cpp 파일 모두에서 사용 가능
		PublicDependencyModuleNames.AddRange(new string[]
			{
				// Initial Modules
				"Core", "CoreUObject", "Engine", "InputCore",
			}
		);

		// 해당 모듈은 cpp 파일에서만 사용 가능
		PrivateDependencyModuleNames.AddRange(new string[] { });

	}
}
// Test.cpp

#include "Test.h"
#include "Modules/ModuleManager.h"

IMPLEMENT_MODULE( FDefaultModuleImpl, Test );

모듈 정의 매크로

  • IMPLEMENT_PRIMARY_GAME_MODULE() : 주 게임 모듈
  • IMPLEMENT_GAME_MODULE() : 게임 모듈
  • IMPLEMENT_MODULE() : 일반 모듈
    -> 일반적으로 하나의 게임 프로젝트에는 하나의 주 게임 모듈 매크로가 선언되어야 함

모듈 연결하기

1. 새로운 모듈의 빌드 등록

  • 해당 모듈의 소스코드도 빌드되도록 등록
  • {프로젝트명}.Target.cs, {프로젝트명}Editor.Target.cs
    -> 빌드 타겟 설정에 해당 모듈을 추가
// ModuleAndPlugin.Target.cs

using UnrealBuildTool;
using System.Collections.Generic;

public class ModuleAndPluginTarget : TargetRules
{
	public ModuleAndPluginTarget(TargetInfo Target) : base(Target)
	{
		Type = TargetType.Game;
		DefaultBuildSettings = BuildSettingsVersion.V5;
		IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_5;
		ExtraModuleNames.Add("ModuleAndPlugin");
		ExtraModuleNames.Add("Test");
	}
}
// ModuleAndPluginEditor.Target.cs

using UnrealBuildTool;
using System.Collections.Generic;

public class ModuleAndPluginEditorTarget : TargetRules
{
	public ModuleAndPluginEditorTarget(TargetInfo Target) : base(Target)
	{
		Type = TargetType.Editor;
		DefaultBuildSettings = BuildSettingsVersion.V5;
		IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_5;
		ExtraModuleNames.Add("ModuleAndPlugin");
		ExtraModuleNames.Add("Test");
	}
}

2. 언리얼 에디터가 해당 .dll 파일도 로딩하도록 설정

  • {프로젝트명}.uproject -> 모듈에 추가로 설정
  • 주의 : 메인 프로젝트의 AdditionalDependencies에 추가하지 않을 경우 해당 모듈을 인식하지 못함
// ModuleAndPlugin.uproject

{
	...
	"Modules": [
		{
			"Name": "Test",
			"Type": "Runtime",
			"LoadingPhase": "PreDefault",
			"AdditionalDependencies": [
				"Engine"
			]
		},
		{
			"Name": "ModuleAndPlugin",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"Engine",
				"Test"
			]
		}
	],
	"Plugins": [
		...
	]
}

3. 프로젝트 폴더 초기화

  • .vs, Binaries, DerivedDataCache, Intermediate, Saved 폴더 제거
  • .vsconfig, .sln 파일 제거
  • Generated Visual Studio project files

4. 언리얼 에디터의 Content Browser에서 모듈 보이게 하는 방법

  • 새로운 모듈에 속한 언리얼 오브젝트 클래스가 없을 경우 해당 모듈이 안 보임
  • 임의의 액터를 생성해서 만들 경우 아래와 같이 보이게 됨


플러그인 만들기

에디터를 활용한 쉽게 플러그인 만들기

  • 에디터 - Edit - Plugins
  • Plugins - Add
  • New Plugin - 템플릿 설정 + 이름 설정 - Create Plugin

직접 플러그인 제작 (예 : 플러그인 "Temporary")

  1. 프로젝트 폴더 -> 새 폴더 "Plugins"
  2. "Plugins" -> 새 폴더 "Temporary"
  3. "Temporary" -> 새 폴더 "Content", "Source"
  4. "Temporary" -> "Temporary.uplugin" 파일 생성
{
	"FileVersion": 3,
	"Version": 1,
	"VersionName": "1.0",
	"FriendlyName": "Temporary",
	"Description": "",
	"Category": "Other",
	"CreatedBy": "",
	"CreatedByURL": "",
	"DocsURL": "",
	"MarketplaceURL": "",
	"SupportURL": "",
	"CanContainContent": true,
	"IsBetaVersion": false,
	"IsExperimentalVersion": false,
	"Installed": false,
	"Modules": [
		{
			"Name": "Temporary",
			"Type": "Runtime",
			"LoadingPhase": "Default"
		}
	]
}
  1. "Source" -> 새 폴더 "Temporary"
  2. "Source" -> "Temporary.Build.cs" 파일 생성
// Temporary.Build.cs

using UnrealBuildTool;

public class Temporary : ModuleRules
{
	public Temporary(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
		
		PublicIncludePaths.AddRange(
			new string[] {
				// ... add public include paths required here ...
			}
			);
				
		
		PrivateIncludePaths.AddRange(
			new string[] {
				// ... add other private include paths required here ...
			}
			);
			
		
		PublicDependencyModuleNames.AddRange(
			new string[]
			{
				"Core",
				// ... add other public dependencies that you statically link with here ...
			}
			);
			
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"CoreUObject", "Engine", "Slate", "SlateCore",
				// ... add private dependencies that you statically link with here ...	
			}
			);
		
		
		DynamicallyLoadedModuleNames.AddRange(
			new string[]
			{
				// ... add any modules that your module loads dynamically here ...
			}
			);
	}
}
  1. "Source" -> "Temporary.h", "Temporary.cpp" 파일 생성
// Temporary.h

#pragma once

#include "Modules/ModuleManager.h"

class FTemporaryModule : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};
// Temporary.cpp

#include "Temporary.h"

#define LOCTEXT_NAMESPACE "FTemporaryModule"

void FTemporaryModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}

void FTemporaryModule::ShutdownModule()
{
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
	// we call this function before unloading the module.
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FTemporaryModule, Temporary)

플러그인 연결하기

1. 플러그인 속의 모듈 빌드 등록

  • 플러그인 속의 모듈의 소스코드도 빌드되도록 등록
  • {프로젝트명}.Target.cs, {프로젝트명}Editor.Target.cs
    -> 빌드 타겟 설정에 해당 모듈을 추가
// ModuleAndPlugin.Target.cs

public class ModuleAndPluginTarget : TargetRules
{
	public ModuleAndPluginTarget(TargetInfo Target) : base(Target)
	{
		...
		ExtraModuleNames.Add("Temporary");
	}
}
// ModuleAndPluginEditor.Target.cs

public class ModuleAndPluginEditorTarget : TargetRules
{
	public ModuleAndPluginEditorTarget(TargetInfo Target) : base(Target)
	{
		...
		ExtraModuleNames.Add("Temporary");
	}
}

2. 언리얼 에디터가 새로운 .dll 파일도 로딩하도록 설정

  • {프로젝트명}.uproject -> 플러그인에 등록 및 기존 프로젝트에 모듈 의존성 등록
  • 주의 : Dependencies에 추가하지 않으면 ModuleAndPlugin에서 Temporary 플러그인 인식을 하지 못함
// ModuleAndPlugin.uproject

{
	...,
	"Modules": [
		...,
		{
			"Name": "ModuleAndPlugin",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				...,
				"Temporary"
			]
		}
	],
	"Plugins": [
		{
			...
		},  
		{
			"Name": "Temporary",
			"Enabled": true
		}
	]
}

3. 프로젝트 폴더 초기화

  • .vs, Binaries, DerivedDataCache, Intermediate, Saved 폴더 제거
  • .vsconfig, .sln 파일 제거
  • Generated Visual Studio project files

4. 언리얼 에디터의 Content Browser에서 모듈 보이게 하는 방법

  • 새로운 모듈에 속한 언리얼 오브젝트 클래스가 없을 경우 해당 모듈이 안 보임
  • 임의의 액터를 생성해서 만들 경우 아래와 같이 보이게 됨
  • 주의 : Content Browser 세팅에서 Show Plugin Content가 꺼져있을 수도 있으니 켜야 함

플러그인은 웬만하면 에디터를 통해서 만들도록 하자!!



출처 : 팀스파르타 내일배움캠프
profile
게임 개발자를 향해..

0개의 댓글