클라이언트 지원 Part 2: 클라 리소스

게임 클라이언트에 필요한 기획데이터, 그래픽 파일, asset bundle 등의 리소스 파일들은 클라이언트와 함께 배포되는 경우가 많습니다. 하지만 이런 데이터는 게임을 운영하는 도중에 수시로 바뀔 수 있고, 이 데이터들을 갱신하기 위해서 매번 새로 클라이언트를 배포하는 것은 상당히 부담스러운 일입니다. 그 때문에 게임 클라이언트가 사용하는 리소스 파일을 외부에서 받아오게 하는 경우가 일반적입니다.

일반적으로 이렇게 외부에서 파일을 받아오기 위해서는, 클라이언트가 받아야하는 파일의 목록과 MD5 와 같은 checksum 값을 계산하고, 클라이언트가 이 정보를 받아가서 자신이 현재 가지고 있는 리소스 파일들의 정보와 일치하는지 확인하게 됩니다. 만일 파일이 추가/삭제되었거나, 파일의 checksum 값이 달라졌을 경우 클라이언트는 더 이상 필요없는 파일은 삭제하고, 새 파일은 받아와서 클라이언트에 저장하게 됩니다.

iFun Engine 에서는 이런 개발 상의 과정을 손쉽게 처리할 수 있도록 클라이언트 리소스 관리 기능을 제공합니다. 이 서비스를 사용하면 클라이언트를 업데이트하지 않고도 클라이언트 리소스를 추가/삭제/변경할 수 있습니다.

서버의 MANIFEST.json 에 간단한 설정만 하면 클라이언트 리소스 서비스를 이용하실 수 있습니다. 이 서비스는 HTTP 프로토콜을 사용합니다.

클라이언트 리소스 제공 서비스 설정

방법 1: 별도의 웹서버 없이 게임 서비스가 리소스 요청을 처리할 때

리소스 디렉토리 지정

최상위 소스 디렉토리 아래에 client_data 라는 디렉토리가 없다면 생성합니다. 그리고 client_data 디렉토리에 클라이언트가 받아가야될 파일들을 복사합니다.

만일 프로젝트 최상위 디렉토리 CMakeLists.txtRESOURCE_DIRS 항목에 client_data 가 없다면 아래와 같이 이를 추가합니다.

...
set(RESOURCE_DIRS game_data client_data src/json_protocols)
...

Tip

만일 make package 를 해도 client_data 디렉토리가 같이 묶이지 않는다면 위 CMakeLists.txt 설정을 확인하세요. 자세한 내용은 패키지에 게임 리소스 파일들 포함하기 를 참고하세요.

MANIFEST.json 설정

다음과 같이 MANIFEST.json 을 설정합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  ...
  "ClientResourceService": {
    "use_client_resource_service" : true,

    "client_resource_service_port" : 8020,

    "client_resource_dir" : "client_data",
    "client_resource_url_base": "",
    "client_resource_list_url": "",

    "client_resource_service_threads_size": 2,

    "client_resource_max_file_size": "1000000",
  }
  ...
}

이제 아이펀 엔진은 게임 서버를 시작할 때, 해당 디렉토리 아래 존재하는 파일들의 MD5 를 자동으로 계산하고 리소스 파일의 리스트를 생성합니다. 또한 각 리소스 파일을 다운로드 받기 위한 HTTP 요청도 직접 처리합니다.

.funignore 파일 및 규칙

아이펀 엔진은 client_data 디렉토리 안에 포함된 파일 중 일부를 무시할 수 있는 기능을 지원합니다. 만약 디렉토리 안에 민감한 정보를 가진 파일이 있거나 빌드 과정에서 임시 파일이 생성되는 경우 이 기능을 통해 필요한 파일만 외부로 노출시킬 수 있습니다.

비활성화 규칙은 생성된 프로젝트의 client_data 디렉토리 안에 있는 .funignore 파일에서 지정이 가능하며 Perl 정규 표현식 패턴과 일치하는 파일들을 모두 무시합니다.

기본적으로 생성되는 .funignore 파일은 아래와 같은 정규 표현식을 포함하고 있으며 # 또는 // 를 사용해 주석을 달 수 있습니다.

# 'data/specific.txt' 패턴과 일치하는 모든 파일을 무시 합니다.
.+data/specific\.txt

# 아래에 지정된 디렉토리에 포함된 파일 및 하위 디렉토리를 모두 무시하며 규칙의 적용 범위는
# 최상단 디렉토리부터 각 하위 디렉토리까지 입니다.
\.svn
\.git

# 아래 패턴과 일치하는 파일을 모두 무시합니다. 이 패턴들은 다양한 운영체제와 IDE 에서
# 범용적으로 사용되는 파일 형식이며 규칙 적용 범위는 최상단 디렉토리부터 각 하위
# 디렉토리까지 입니다.
\.DS_Store
Thumb\.db
Desktop\.ini
^[\w\s\.,-_]+\.bak
^[\w\s\.,-_]+\.log
[Bb]in
[Oo]bj
[Bb]uilds?

# Vim 임시 파일
^[\w\s\.,-_]+\.sw[ponm]

# 파이썬
venv
pip-log\.txt
^[\w\s\.,-_]+\.py[co]

방법 2: 별도의 웹서버 가 리소스 요청을 처리하게 할 때

MANIFEST.jsonclient_resource_list_urlclient_resource_url_base 을 지정하면, 아이펀 엔진은 리소스 리스트 요청 및 각 리소스 파일들의 요청을 외부 웹 서버로 redirect 할 수 있습니다.

리소스 목록 파일 생성

다음과 같이 명령을 실행합니다. 첫 번째 파라미터는 리소스가 있는 루트 폴더 경로이고 두 번째 파라미터는 생성될 리소스 리스트 파일의 경로입니다.

$ funapi_client_resource_generator <path/to/resource/base> <path/to/list.json>

이렇게 만들어진 파일을 외부 웹 서버에 복사합니다. 그리고 MANIFEST.jsonclient_resource_list_url 에 해당 파일의 URL 을 지정합니다.

리소스 파일들을 웹 서버에 복사

이제 리소스 파일들을 포함하는 폴더를 외부 웹 서버에 복사합니다. 그리고 해당 디렉토리의 URL 을 client_resource_url_base 에 지정합니다.

MANIFEST.json 설정

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  ...
  "ClientResourceService": {
    "use_client_resource_service" : true,

    "client_resource_service_port" : 8020,

    "client_resource_dir" : "",
    "client_resource_url_base": "http://my.cdn.com:80/path/to/resource/base/",
    "client_resource_list_url": "http://my.cdn.com:80/path/to/list.json",

    "client_resource_service_threads_size": 2,

    "client_resource_max_file_size": "1000000",
  }
  ...
}

이제 게임 서버가 시작할 때, 아이펀 엔진은 client_resource_list_url 로부터 리소스 리스트 파일을 받아와서 캐싱 해두고, 각 리소스 파일의 요청이 들어오면 client_resource_url_base 로 redirect 하게 됩니다.

.funignore 파일 및 규칙

.funignore 파일은 funapi_client_resource_generator 프로그램을 실행할 때도 동일하게 적용되며 Perl 정규 표현식과 일치하는 모든 디렉토리 또는 파일을 목록에서 제외시킵니다.

리소스 정보 갱신하기

서버가 구동중인 상태에서도 클라이언트 리소스 파일들을 갱신할 수 있습니다.

코드안에서 다음 메소드를 호출하면 됩니다.

ClientResourceService::Reload();
ClientResourceService.Reload();

Note

만일 게임 서버가 직접 리소스 파일을 배포하는 역할을 하고 있다면, 아이펀 엔진은 client_data 디렉토리안에 있는 파일들에 대해서 MD5 를 다시 계산할 것입니다. 그리고 만일 외부 HTTP 서버를 지정하고 client_resource_list_url 을 지정한 경우 해당 URL 에서 MD5 가 저장된 파일을 다운로드 받아서 메모리에 캐싱하고 이를 활용하게 됩니다.

Note

MD5 를 다시 계산한다고 이미 플레이하고 있는 유저들에게 새로운 리소스 파일이 전달되는 것은 아닙니다. 그러니 리소스 파일을 갱신한 경우 이미 플레이하고 있는 유저와 새로 접속하는 유저들 사이에 서로 다른 리소스 데이터를 갖게 되는 상황이 발생할 수 있음을 명심해주세요.

예제: 외부 웹 서버 활용의 경우

아래는 리소스 파일로 data/items.json 과 data/stages.json 이 존재하며, 이를 외부 웹 서버를 통해서 클라이언트에게 전달하는 예제입니다.

리소스 리스트 받아오기

웹 브라우저 상에서 http://localhost:8020 를 입력해 봅니다. 결과는 다음과 유사하게 나올겁니다.

{
  data: [
    {
    path: "data/items.json",
    size: 2042,
    md5: "d41d8cd98f00b204e9800998ecf8427e"
    },
    {
    path: "data/stages.json",
    size: 2044527,
    md5: "9ab9626a301c2bf1444893a69a1bfac7",
    md5_front: "8fdd96188cadababf2fbcb812b43e6fb"
    }
  ],
  url: "http://my.cdn.com:80/path/to/resource/base/"
}

Tip

md5_front 는 파일 시작 부분 1MB에 대한 md5 값입니다. 이는 클라이언트가 큰 파일의 MD5 를 모두 계산하는 것을 방지하기 위한 것이며, 1MB 까지의 MD5 가 다르다면 바로 다운로드를 시작합니다. 만일 md5_front 가 동일하다면 전체 파일에 대해서 MD5 계산을 계속합니다. 이 필드는 1MB 보다 큰 파일들에 대해서만 생성됩니다.

각 리소스 파일 받아오기

이제 http://localhost:8020/data/items.json 를 브라우저에 입력하면 아이펀 엔진은 이를 http://my.cdn.com:80/path/to/resource/base/data/items.json 으로 redirect 하고 파일을 다운로드 하게 됩니다.

클라이언트 코드

서버에서 리소스를 다운받는 기능은 아이펀 엔진 클라이언트 플러그인에 구현되어있습니다.

플러그인이 자동으로 MD5 list 를 요청하고 거기 있는 파일들의 존재 유무를 살펴, 자신이 가지고 있는 MD5 와 비교한 후, 갱신되거나 추가된 파일은 다운로드 하고 삭제된 파일은 지우는 작업을 합니다. 또한 MD5 계산을 빠르게 하기 위해서 계산한 MD5 파일을 캐싱합니다.

보다 자세한 내용은 클라이언트 플러그인 을 참고하세요.

클라이언트 리소스 정보 제공 서비스 설정 파리미터

MANIFEST.json 의 ClientResourceService 섹션에 다음과 같은 값들을 설정할 수 있습니다.

공통 설정:

  • use_client_resource_service: 기능을 활성화 시킬지 여부 (type=bool, default=false)

  • client_resource_service_port: 클라이언트 리소스 서비스가 바인딩할 HTTP 포트. (type=uint64, default=0)

  • client_resource_max_file_size: 한 클라이언트 리소스 파일의 최대 사이즈. 바이트 단위. 만일 이보다 큰 파일이 존재한다면 게임 서버는 뜨지 않습니다. (type=uint64, default=10485760)

별도 웹서버 없이 게임 서버가 처리하는 경우:

  • client_resource_dir: Client 가 다운로드 받을 리소스를 저장하는 디렉토리 경로. (type=string, default=””)

별도 웹서버를 사용하는 경우:

  • client_resource_list_url: 클라이언트 리소스들의 리스트를 담고 있는 파일의 URL. 목록 파일의 생성에 대해서는 리소스 목록 파일 생성 를 참고하세요. (type=string, default=””)

  • client_resource_url_base: 클라이언트 리소스를 받기 위한 베이스 URL (예, CDN 베이스 경로) 만일 이것이 세팅되면, 클라이언트 리소스 서비스는 파일 리스트만 클라이언트에게 전송하고 실제 파일은 해당 베이스 URL 에서 받게 redirect 한다. 이 값이 입력되면 client_resource_dir 값은 무시되며, client_resource_list_url 이 반드시 존재해야됨. (type=string, default=””)

직접 설정을 바꿀 일이 거의 없는 설정들

  • client_resource_service_threads_size: 클라이언트 리소스 서비스에 할당된 쓰레드 개수. (type=uint64, default=2)