게릴라 멀티플레이어 개발
작성자: 어니스트 우(Ernest Woo) 작성일: 2012년 9월 13일
스마트폰에서 네트워크 게임을 하게 하는 가장 좋은 방법은 무엇일까? 어니스트 우(Ernest Woo)는 우주 배틀 게임 <ErnCon>을 위해서 기존의 네트워크 기술을 살피고 통합시켰다. 그 결과로 여기에 iOS와 안드로이드 개발자들에게 유용한 솔루션을 공유한다.
인디 게임 개발자의 가장 큰 이점 중 하나는 만들고 싶은 게임을 만들 자유가 있다는 것이다. 아이디어를 막는 회사의 관료들 없이 어떤 말도 안 되는 아이디어라도 시도할 자유가 있다 – 스스로 뭘 하고 있는지 전혀 이해하지 못한다 해도 말이다!
나의 첫 안드로이드 게임 <FRG>에 대한 사용자들의 피드백과 <프로젝트 INF(Project INF)> 같은 초기 멀티플레이어 안드로이드 게임에서 받은 영감을 바탕으로, 나는 후속편을 3G에서도 플레이 가능한 리얼타임 멀티플레이어 총격 게임(real time multiplayer shoot ‘em up)으로 만들고 싶었다. 문제는 내가 멀티플레이어 게임을 어떻게 만드는지 모른다는 데 있었다.
결론적으로 나는 이 장애물을 극복했고 <ErnCon>을 릴리즈할 수 있었다. 그 과정에서 나는 멀티플레이어 게임을 만드는 많은 기술적인 세부 사항들을 배웠다. 여기에 공유하는 내 경험이 모바일 리얼타임 멀티플레이어 게임 개발 방식에 실마리가 되었으면 좋겠다.
어디부터 시작했는가?
나는 직업상 자바 웹 어플리케이션(Java web applications)들과 네이티브 어플리케이션들(J2ME, 안드로이드, iOS)을 개발해온 자바 개발자(Java developer)이다. 웹 앱과 네이티브 앱 간의 통신은 항상 HTTP를 이용해서 해왔다 – 리얼 타임 게임에는 적합하지 않은 기술이다! 처음에는 내가 멀티플레이어 게임 개발에 관해 걱정되는 핵심 문제의 답을 찾는 데에 초점을 맞췄다.
1. 네트워크 주소 변환 (NAT). <ErnCon>은 3G에서도 플레이 할 수 있어야 했기 때문에, 나는 휴대 전화의 전형적인 대칭형 NAT(Symmetric NAT)를 선회할 방법을 알아내야 했다. 대칭형 NAT는 내부의 주소/포트(휴대폰)에 다른 외부의 주소/포트 (통신회사/ISP의 NAT)를 매핑(mapping)함으로써 모든 목적지 주소/포트(게임 서버)에 연결한다.
소비자용 라우터(consumer-grade router) 뒤에 디지털 가입자 회선(DSL)이나 케이블 모뎀을 연결해서 실행하는 게임에서는 비교적 자유로운 NAT 유형(Full-cone, Restricted Cone, Port-restricted Cone)을 통과하는 방식이다. 하지만 이 중 어떤 것도 실제로 대칭형 NAT(Symmetric NAT)에 적용할 수 없다.
UDP 홀 펀칭(UDP Hole Punching)과 다른 NAT 통과 기술들을 알아본 뒤, 클라이언트 서버 아키텍처의 비교적 단순한 솔루션으로 정착했다. 서버가 항상 퍼블릭 IP 주소를 가진, 다시 말해 서버 자체가 NAT가 아닌 방식이다. 퍼블릭 서버와의 통신을 위해서는 특별한 NAT 통과 트릭이 필요 없다. 더 자세한 내용을 알고 싶으면 NAT에 대한 위키피디아(Wikipedia) 항목 1을 읽어 보기 바란다.
2. 단순 네트워크 모델(Simple network model). 리얼타임 멀티플레이어 게임 개발 경험이 없는 상태로, 나는 다른 게임들이 네트워크 레이어를 어떻게 구성했는지에 대한 정보를 찾았다. 에픽 게임즈(Epic Games)는 <언리얼 토너먼트(Unreal Tournament)>의 네트워크 아키텍처에 대한 정보를 공개2했다. <언리얼 엔진(Unreal Engine)>의 컨셉으로 하기엔 너무 빡빡하다는 것을 깨닫긴 했지만 말이다 – 나는 <언리얼 엔진3>를 만들고 싶지는 않았다. 내가 최종적으로 선택한 <퀘이크 3(Quake Ⅲ)>의 네트워크 모델 3 은 마지막 받은 상태에서 전체 게임 상태 업데이트를 델타 압축해서 보내는 개념으로, 훨씬 이해하기 쉬운 방식이었다.
3. 활용 기회의 축소. 나는 인디 개발자이다 보니 치트(cheat)를 강력히 감시할 자원이 없다. 게임의 아키텍처 자체가 해커를 막아야 하고, 클라이언트가 통제하는 데이터는 모두 이용될 수 있었다. 클라이언트 서버 아키텍처는 서버가 모든 게임 데이터의 유일한 권한을 갖게 만듦으로써 이러한 우려를 잠재울 수 있다.
4. 전세계에 서버 배치. 만약 세상의 모든 플레이어들이 한 장소에 위치한 서버에 연결한다면, 클라이언트 서버 아키텍처를 이용한 리얼타임 멀티플레이어 게임은 잘 작동하지 않을 것이다. 랙(lag)을 줄이고 게임 플레이 성능을 향상시키기 위해서는 서버를 전략적으로 세계 곳곳에 배치해야만 한다. 플레이어를 지역으로 분류하여 지역적으로 가까운 플레이어들이 언제나 같은 서버에서 플레이 할 수 있어야 한다. 나는 아마존 웹 서비스(AWS) 4 덕분에 미국, 유럽, 동남 아시아, 남아메리카를 포함한 여러 지역에 서버를 마련할 수 있었다.
실행 세부 사항
속담에도 있듯이, “문제는 사소한 데에 있다.” 적절한 아키텍처를 찾고 네트워크 모델을 결정하고, 고심 끝에 프로바이더(provider)를 정하는 노력이 실제 모든 것을 시행하는 데에는 무색했다. 너무 세세한 부분까지 들어가면 지루할 테니, 여기서는 내가 해결한 몇 가지 장애물에 대해서만 이야기하기로 하자.
1. 기존의 게임으로 시작하라. 나는 당장 멀티플레이어의 장점을 모두 가진 <ErnCon>을 시작하고 싶었지만, 기존에 만들었던 <FRG>에서 멀티플레이어 프로토타입을 만들기로 했다. 그 덕분에 네트워크 코드와 클라이언트 서버 개발에만 집중할 수 있었다. <FRG>의 멀티플레이어 실행 수준에 만족하고 난 뒤에야 이어서 새로운 게임을 개발할 수 있었다.
2. 자바(Java)를 이용하고 남용하라. 안드로이드 앱은 자바에서 개발할 수 있기 때문에 나도 역시 자바를 이용해 서버 개발을 간소화했다. 그렇게 해서 톰캣(Tomcat)에서 실행할 수 있는 웹 어플리케이션을 금방 만들었고 그래픽과 음향 없이 게임을 가동할 수 있게 됐다. 클라이언트와 서버 간의 코드를 공유함으로써 양 쪽 모두 같은 게임을 시뮬레이팅했는지 확인하는 수고를 덜 수 있었다.
3. 자바를 더더욱 이용하고 남용하라. <퀘이크3>의 네트워크 모델을 빨리 시행하기 위해서, 나는 자바의 실시간 어노테이션(annotations)과 리플렉션(reflection)을 광범위하게 사용했다. 어노테이션은 게임 엔티티(game-entity) 클래스에서 네트워크를 피할 수 있는 필드를 표시하는 데 사용한다. 클라이언트와 서버는 어노테이션이 달려있는 필드의 게임 엔티티 목록에 근거해 UDP 패킷(UDP packet)을 조합한다. 클라이언트와 서버 간에 코드가 공유되기 때문에, 네트워크 프로토콜(network protocol)을 한 군데에서만 바꾸면 되었다.
4. 매치메이커 서비스 (Matchmaker service). 게임에서 플레이어를 모으고, 게임 서버와 통신하고, XP, 캐시, 인벤토리 같은 플레이어 상태를 기록하기 위해선 추가 서비스가 필요하다. 아마존 웹 서비스(Amazon Web Services)는 내가 다음과 같은 매치메이커 서비스를 개발하고 배포하는데 필요한 것을 모두 제공했다.
· EC2 로드밸런서(load balancer)
· 엘라스틱캐시(Elasticache) 및 관계형 데이터베이스 서비스(RDS)를 퍼시스턴스 레이어에 제공. (근본적으로 아마존이
운영하는 맘캐시드(Mamcached)와 MySQL) Memcached.org 5 에 따르면, 맘캐시드는 “무료&오픈 소스, 고성능, 광범위
메모리 오브젝트 캐싱 시스템”이다.
· 심플 스토리지 서비스(S3)는 ErnCon 스토어에서 보여지는 아이템 이미지를 비롯한 게임 애셋과 WAR과 JAR 파일 서버를
호스팅한다.
5. 서버 배치의 용이함. 아마존이 <ErnCon>을 개발하고 배치하는 백엔드(backend)에서 도움이 되는 툴을 많이 제공했지만, 그래도 최대한 힘들지 않게 새로운 서버를 프로비저닝하기 위해서는 할 일이 여전히 많았다.
현재 나는 주문형 아마존 머신 이미지(AMI)를 보유하고 있는데 S3의 최신 매치 메이커 WAR를 가져온다. 게임서버도 마찬가지로 최신 게임 서버 WAR에서 가져온다.
게임 서버들은 자동적으로 매치메이커에 등록되어서 매치메이커가 게임을 만들고 플레이어를 게임 서버에 보내기 시작할 수 있다. 서버 코드를 업데이트할 때의 배포 절차는 다음과 같다.
1. 업데이트된 매치메이커와 게임 서버 WAR 그리고 JAR 파일들을 S3에 업로드한다.
2. 나의 주문형 AMI에서 EC2 Instance Launch Wizard를 실행해서 새로운 EC2 인스턴스(EC2 instance)를 만든다.
3. 인스턴스가 동작해서 플레이어와 게임을 받을 때까지 기다린다. 4. 모든 지역에서 반복한다.
이렇게 해서 새로운 게임 서버를 프로비저닝하는 데 전체적으로 5분도 안 걸린다.
<ErnCon>의 멀티플레이어 아키텍처는 대부분 여가시간에 개발했기 때문에 특히 자랑스럽게 생각하는 부분이다. 다음 순서는 네트워크 프로토콜이다.
※ 자세한 내용은 첨부(PDF)화일을 참고하시기 바랍니다.
|