insong
← 블로그

게임 엔진 안에서 기획데이터를 관리하면 생기는 일

언리얼 엔진을 기획데이터의 원본으로 쓰면 어떤 문제가 생기는지, 그리고 왜 기획데이터는 처음부터 독립이어야 하는지.

game-dev architecture design-data

언리얼 엔진 안에서 기획데이터를 작업하는 방향이 결정된 적이 있다. uasset이나 actor에 직접 값을 입력하고, 서버에서 필요한 것만 필터해서 export하는 구조. 기획자 입장에서는 네이밍이나 참조 걱정 없이 엔진 안에서 에셋을 직접 연결하면 되니까 매력적인 제안이었다.

문제는 그 다음부터였다.

언리얼 path는 key로 쓸 수 없다

언리얼에서 에셋 간 참조는 path 기반이다. 파일을 옮기거나 이름을 바꾸면 redirector가 생기고, 이전 경로로 접근하면 새 위치로 라우팅된다. 유연한 구조지만, path를 데이터의 key로 쓰는 순간 문제가 생긴다.

서버는 DB에 저장된 데이터에 불변하는 key가 필요하다. path가 바뀌면 — 설령 redirector로 처리가 되더라도 — 원칙적으로는 key가 바뀐 셈이다. 서버 팀은 “절대 path를 바꾸지 말아줘”라고 요청하게 되고, 기획과 클라이언트는 그 요청에 소극적으로 반응하게 된다. 엔진의 유연함이 오히려 발목을 잡는 상황이 된다.

클라이언트가 원본이 되면 순환 참조가 생긴다

더 큰 문제는 클라이언트를 기획데이터의 원본으로 쓸 때 발생한다.

서버는 기획데이터를 검증해야 한다. 검증 로직을 서버에 두는 건 자연스럽다 — 서버는 검증이 필수라고 생각하고, 클라이언트는 상대적으로 소극적이니까. 그런데 검증할 데이터를 얻으려면 클라이언트 빌드에서 export가 일어나야 한다. 클라이언트 빌드를 돌리려면 서버가 패킷 정의와 enum을 먼저 생성해줘야 한다. 그 enum을 생성하려면… 기획데이터가 필요하다.

전형적인 순환 참조다.

평소에는 서버가 공유 enum을 발급하고, 클라이언트와 기획데이터가 그것을 가져다 쓰는 게 일반적인 흐름이다. 클라이언트가 원본이 되면 이 순서가 꼬인다. 누가 먼저 빌드를 돌려야 하는지 불분명해지고, 빌드 파이프라인에서 수작업이 끼어들기 시작한다.

그나마 정리된 순서

이 순환을 풀기 위해 나온 방향이 하나 있다.

  1. 클라이언트에서 기획데이터 전체가 아니라 스키마만 export한다
  2. 서버는 그 스키마로 검증기를 빌드하고, 패킷과 enum을 생성한다
  3. 클라이언트는 서버에서 만들어진 결과물을 받아 최신 빌드를 돌린다
  4. 기획데이터를 export해서 서버 검증기로 검사한다

순환은 깨지지만, 선후관계가 복잡하다. 조금이라도 순서가 틀리면 검증을 건너뛰게 되고, 빌드 파이프라인을 완전히 자동화하지 않으면 운영하기 어렵다.

enum은 누가 발급해야 하는가

기획데이터 독립화를 이야기할 때 자주 빠지는 주제가 enum이다. enum을 어디서 정의하고 누가 가져다 쓸지는, 그 enum이 어느 영역에서 의미를 갖는지에 따라 결정된다.

기획데이터에서 의미가 있는 enum — 몬스터 종류, 아이템 등급, 스킬 타입처럼 기획표에 직접 등장하는 값은 기획데이터에서 발급한다. 서버와 클라이언트는 이 정의를 가져다 쓴다. 기획자가 값을 추가하거나 바꿀 때 서버나 클라이언트 코드를 건드릴 필요가 없다.

서버와 클라이언트가 공유하지만 기획데이터와 무관한 enum — 패킷 타입, 에러 코드처럼 기획표에 등장하지 않는 공유 정의는 서버에서 발급한다. 클라이언트는 서버가 내려준 정의를 참조한다. 서버가 원본이 되면 클라이언트가 임의로 값을 추가해서 서버와 불일치가 생기는 상황을 막을 수 있다.

한쪽만 쓰는 enum — 클라이언트 내부 렌더링 상태나 서버 내부 처리 단계처럼 상대방이 알 필요 없는 값은 각자 정의한다. 굳이 공유 레이어를 거칠 이유가 없다.

이 구분이 무너지면 순환 의존이 생긴다. 서버가 클라이언트 enum을 기다리거나, 클라이언트가 서버 빌드를 먼저 받아야 빌드가 되는 상황은 대부분 발급 주체가 잘못 정해진 결과다.

기획데이터는 처음부터 독립이어야 한다

결국 근본적인 문제는 기획데이터를 클라이언트나 서버 어느 한쪽에 종속시킨 것이다.

기획데이터를 독립적으로 관리하면 클라이언트와 서버가 각자 가져다 쓰면 된다. 둘 사이에 의존성이 생기지 않는다. 서버는 서버대로 검증하고, 클라이언트는 클라이언트대로 사용하면 된다. 빌드 순서를 맞추느라 시간을 쓸 필요가 없다.

key 문제도 마찬가지다. 불변하는 ID를 발급하는 방식이 맞다. 엔진 path처럼 파일 시스템 상태에 의존하는 값을 key로 쓰면, 언제든 변할 수 있는 값을 기준으로 데이터를 참조하게 된다. 별도의 ID 컬럼을 두고, path는 그냥 에디터 편의를 위한 참조로만 쓰는 게 낫다.

게임 엔진은 기획 작업을 편하게 만들어주는 도구지, 데이터의 원본이 되기에 좋은 위치가 아니다.