부트스트랩
프레임워크 자동 시작 — 첫 씬이 로드되기 전에 23개 서비스 전부를 의존성 순서대로 등록합니다.
프레임워크 자동 시작 · 첫 씬이 로드되기 전에 한 번만 실행 · 23개 서비스 전부를 등록 · 교체 불가
무엇을 하는가
Bootstrap은 프레임워크의 자동 시작 루틴입니다. 23개 서비스 전부를 의존성 순서대로 등록하고, 이전 Play 세션에서 남은 내부 GameObject를 제거하며(에디터에서 Domain Reload가 꺼져 있을 때만 해당), Logger를 예열합니다. 여러분이 직접 호출할 일은 없습니다 — 첫 씬이 로드되기 전에 Unity가 자동으로 호출하며, Play 세션마다 정확히 한 번 실행됩니다.
시작이 끝나면 Unity 콘솔에 다음 줄이 표시됩니다:
bootstrap complete (v2.1.0, 23 services)
이 줄이 보이면 프레임워크가 가동되었고 모든 서비스가 사용 가능한 상태입니다.
빠른 예제
실제 사용에서 가장 흔한 형태는 이렇습니다: Bootstrap을 결코 직접 호출하지 않습니다. 여러분의 Awake가 실행될 때쯤이면 모든 서비스가 이미 등록되어 있습니다 — resolve해서 쓰기만 하면 됩니다.
using CommonGameSystem.Core;
using UnityEngine;
[DefaultExecutionOrder(100)] // Run AFTER framework startup — the attribute goes on the class
public class GameController : MonoBehaviour
{
void Awake()
{
// Bootstrap.Run has already fired. All services are registered.
// Resolve once and cache the references.
var time = ServiceLocator.Resolve<ITimeService>();
var pool = ServiceLocator.Resolve<IObjectPoolService>();
var bus = ServiceLocator.Resolve<IEventBus>();
// DeltaTime is a method: you pick the clock you want.
Debug.Log($"Gameplay: {time.DeltaTime(Clock.Gameplay)}, " +
$"unscaled: {time.UnscaledDeltaTime(Clock.Gameplay)}");
}
}
EditMode 테스트에서는 보통 Bootstrap이 이미 실행된 상태입니다 — 시작 훅이 테스트 도메인에서도 발동하기 때문입니다 — 따라서 서비스를 바로 resolve할 수 있습니다:
using CommonGameSystem.Core;
using NUnit.Framework;
public class BootstrapSmokeTests
{
[Test]
public void Bootstrap_RegistersCoreServices()
{
// Bootstrap.Run already fired for the test domain. Resolve and assert.
Assert.IsNotNull(ServiceLocator.Resolve<ILogger>());
Assert.IsNotNull(ServiceLocator.Resolve<IObjectPoolService>());
Assert.IsTrue(Bootstrap.HasRun);
}
}
전체 API
resolve할 것은 없습니다. Bootstrap은 Unity의 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] 훅을 통해 자동으로 발동합니다. 어떤 씬의 Awake보다도 먼저, 그리고 여러분의 코드가 서비스 로케이터를 건드리기 전에 실행됩니다.
namespace CommonGameSystem.Core
{
public static class Bootstrap
{
// Entry point — Unity calls this automatically (do NOT invoke directly).
public static void Run();
// Registers the settings-persistence backend. Public so automated
// tests can inject a stub; not part of normal use.
public static void RegisterConfigurationPersistence();
// Diagnostic-only (read-only — set internally). Editor-only:
// these two properties do not exist in player builds.
public static bool HasRun { get; }
public static int RunCount { get; }
}
}
| 멤버 | 설명 |
|---|---|
Run() | 시작 진입점. Unity가 첫 씬 로드 전에 Play 세션당 한 번 호출합니다. 직접 두 번째로 호출하면 ServiceAlreadyRegisteredException이 발생합니다. |
RegisterConfigurationPersistence() | 설정 서비스가 설정을 저장하는 스토리지 백엔드를 등록합니다: 저장/불러오기 서비스가 활성 상태면 그 서비스를, 아니면 Unity의 PlayerPrefs를 사용합니다. 테스트가 폴백을 검증할 수 있도록 public일 뿐, 일반적인 사용 대상은 아닙니다. |
HasRun | 시작이 한 번이라도 완료되면 true. 읽기 전용, 에디터 전용 — 참조를 #if UNITY_EDITOR로 감싸거나 에디터/테스트 어셈블리 안에만 두십시오. |
RunCount | 시작 실행의 누적 횟수(에디터에서 Domain Reload가 꺼져 있으면 Play 세션을 거치며 증가). 읽기 전용, 에디터 전용. |
등록 순서대로 보는 23개 서비스
Bootstrap은 아래 서비스들을 이 순서로 시작합니다. 각각은 ServiceLocator.Resolve<T>()로 resolve하는 인터페이스이며, 각자 전용 레퍼런스 페이지가 있습니다.
- ServiceLocator — 다른 모든 서비스가 담기는 레지스트리이자, 어떤 서비스든 가져올 때 호출하는 단 하나의 클래스. 서비스 로케이터 참조.
- ILogger — 카테고리별 필터를 갖춘 분류형 로깅. 로거 참조.
- IObjectPoolService — 프리팹 풀링. 오브젝트 풀 참조.
- ITimeService — 클럭별 시간, 일시정지, 슬로 모션(Gameplay/UI/Background 클럭). Time 참조.
- IEventBus — 시스템 간 타입 안전 발행/구독. 이벤트 버스 참조.
- ISaveService — 안전한 원자적 쓰기와 슬롯을 갖춘 JSON 저장 파일. 저장/불러오기 참조.
- IConfiguration — 변경 이벤트를 갖춘 타입 기반 설정 그룹. 설정 참조.
- IInputService — 입력 액션 맵 컨텍스트와 키 리바인딩. 입력 참조.
- IAudioService — AudioMixer를 거치는 음악, 효과음, 보이스. 오디오 참조.
- IPanelStack — 게임패드·키보드 포커스를 갖춘 UI 패널 push/pop. UI 프레임워크 참조.
- ISceneService — 로딩 화면, 취소 지원, 애디티브 로드/언로드를 갖춘 비동기 씬 로딩. 씬 플로우 참조.
- ILocalizationService — 키-문자열 조회와 런타임 언어 전환. 로컬라이제이션 참조.
- IAchievementService — 자동 해금을 갖춘 로컬 통계·도전 과제. 도전 과제 참조.
- IScheduler — After/Every/NextFrame 타이머와 메인 스레드 실행 디스패치. 스케줄러 참조.
- ITweenService — 31종 이징을 갖춘 일시정지 인식 값 트위닝. 트윈 참조.
- IAssetProvider — 참조 카운팅을 갖춘 Addressables 로딩. 에셋 프로바이더 참조.
- IRandomService — 이름 있는 스트림을 갖춘, 시드 기반의 재현 가능한 난수. 랜덤 참조.
- IStateMachineService — 평면 유한 상태 기계 팩토리. FSM 참조.
- IPushdownStackService — 쌓아 올리는 게임 상태 스코프(게임플레이 위의 일시정지 메뉴 등). 푸시다운 스택 참조.
- ITweenSequenceService — 순차·병렬 트윈 타임라인. 트윈 시퀀싱 참조.
- IAddressableSceneService — Addressables에서 로드하는 애디티브 씬. 어드레서블 씬 참조.
- IDeferredBus — 이벤트를 지금 큐에 넣고 나중에 플러시. 지연 이벤트 큐 참조.
- ICommandRegistry — 런타임 커맨드 레지스트리(콘솔 UI는 직접 만듭니다). 커맨드 레지스트리 참조.
내부 헬퍼 등록
Bootstrap은 자동화 테스트가 교체할 수 있도록 몇 가지 내부 헬퍼도 등록합니다: 설정 영속화 백엔드, 세 개의 내장 설정 검증기, 그리고 입력 키 맵 소스입니다. 게임 코드가 이들을 직접 resolve할 일은 없으며, 23개 서비스 수에도 포함되지 않습니다.
동작 및 엣지 케이스
-
한 번만 실행됩니다. 한 Play 세션에서
Bootstrap.Run()을 두 번 호출하면ServiceAlreadyRegisteredException이 발생합니다. Unity의 훅이 Play 진입마다 정확히 한 번의 발동을 보장하므로, 직접 호출할 필요가 전혀 없습니다. -
메인 스레드 전용. 시작 훅은 Unity 메인 스레드에서 실행됩니다. 디버그 빌드는 이를 assert하며, 위반은 초기에 잡혀 Play가 중단됩니다.
-
등록 전 정리. 서비스를 등록하기 전에 Bootstrap은 이전 Play 세션에서 남은 내부 프레임워크 GameObject를 제거합니다. 이는 에디터에서 Domain Reload가 꺼져 있을 때만 의미가 있습니다(Project Settings → Editor → "Enter Play Mode Settings"); Domain Reload가 켜져 있으면 어차피 매 Play 세션이 깨끗한 하이어라키로 시작합니다. 프레임워크는 내부 마커 컴포넌트로 자신의 잔여 오브젝트를 찾아
Object.Destroy로 파괴하는데 — 즉시가 아니라 프레임 끝에 이루어지므로 — PlayMode 테스트는 시작 후yield return null로 파괴가 정리될 시간을 주어야 합니다. 마커 컴포넌트는 프레임워크 내부용이므로 직접 붙이지 마십시오. -
Logger 예열. 시작 중에 Bootstrap은 메인 스레드에서 Logger 호출을 한 번 수행합니다. 이 호출이 static
Logger헬퍼를 준비시켜, 이후 워커 스레드에서의 호출(예: 저장 파일 I/O)이 안전해집니다. -
시작 실패는 Play를 중단합니다. 시퀀스 후반에 생성되는 서비스는 생성자를 통해 의존성을 받습니다. 생성자가 예외를 던지면 예외가 전파되어 Play가 즉시 중단됩니다 — 문제가 몇 분 뒤가 아니라 시작 시점에 드러납니다.
-
에디터 종료 훅. 에디터에서만 Bootstrap이 Play 모드 종료를 감시하여, disposable한 서비스 전부를 등록 역순으로 dispose합니다. 플레이어 빌드에는 이 훅이 들어가지 않습니다 — 일반적인 프로세스 종료에 맡깁니다.
-
Bootstrap 자체는 교체할 수 없습니다 — 다른 모든 것을 시작시키는 코드이기 때문입니다. 다만 Bootstrap이 등록하는 모든 서비스는 교체할 수 있으며, 각 서비스는 한 줄로 끼워 넣는 오프 스위치인 Null(no-op) 구현을 함께 제공합니다:
// Example: silence all diagnostics ServiceLocator.Replace<ILogger>(new NullLogger()); // Example: disable audio entirely ServiceLocator.Replace<IAudioService>(new NullAudio()); // Example: stub the scene service for testing ServiceLocator.Replace<ISceneService>(new NullSceneService());Logger에는 한 가지 주의점이 있습니다: static
Logger헬퍼는 시작 중에 백엔드를 캐시하므로, 세션 중간에 교체해도 헬퍼의 대상이 바뀌지 않습니다. 런타임에 로깅을 음소거하려면 대신Logger.MinimumLevel = LogLevel.Off를 설정하십시오 — 자세한 내용은 로거를 참조하십시오.
관련 페이지
- 서비스 로케이터 — 어떤 서비스든 가져오는 방법
- 로거 — 진단, 그리고 세션 중간의 백엔드 교체에 주의가 필요한 이유
- 시작하기 — 설치, 첫 씬, 부트 로그 라인 확인
- 매뉴얼: 무엇이 들어 있나 — 패키지 구성과 전체 기능 둘러보기
- 매뉴얼: 문제 해결 — 부트 로그 라인이 나타나지 않을 때 점검할 사항