2014년 11월 24일 월요일

Google breakpad를 이용해서 Android용 Cocos2d-x 게임 크래쉬 리포트를 HockeyApp에 전송하기

HockeyApp에 Cocos2d-x로 개발된 게임의 크래쉬 리포트를 전송하기 위해서 제공되는 HockeyApp SDK는 NDK로 빌드된 C, C++ 코드의 크래쉬 정보 덤프할 수 없기 때문에 Google에서 공개한 크래쉬 리포트 라이브러리인 breakpad를 이용하여 HockeyApp에 전송한다.


현재 3.x 대 Cocos2d-x 소스는 NDK r9d 이하에서 빌드가 가능한데 breakpad 저장소의 최신 리비전 소스는 NDK r10c 이상을 지원한다. 이전 chrome_38 브랜치 소스를 가지고 라이브러리를 빌드하여 문제를 해결한다.


breakpad 라이브러리 빌드를 위해서 (path_to_breakpad)/android/sample_app 디렉토리에 있는 샘플 프로젝트에서 Application.mk의 내용 중 APP_STL 설정을 stlport_static에서 gnustl_static으로 변경하고 jni 폴더에서 ndk-build를 실행하면 breakpad 라이브러리와 테스트 프로그램 빌드가 시작된다. 빌드가 완료된 후 obj/local/armeabi 디렉토리에 libbreakpad_client.a가 생성되어있음을 확인할 수 있다.


자 이제 Cocos2d-x Android 프로젝트에 앞에서 만들어진 breakpad 라이브러리를 추가하자. 게임 프로젝트에서 위의 그림과 같이 Application.mk의 내용중 APP_STL 설정을 c++_static에서 gnustl_static으로 APP_CPPFLAGS의 -std=c++11에서 -std=gnu++11로 변경한다.


그리고 Android.mk 파일에 breakpad 라이브러리의 헤더 경로를 지정해주고 prebuilt 라이브러리로 등록하여 링크될 수 있도록 위와 같이 설정을 추가하여 빌드한다. 생성된 apk 파일과 심볼 파일을 HockeyApp 사이트에 전송하면 아래와 같은 크래쉬 리포트를 받을 수 있다.


HockeyApp SDK 연동에 대한 자세한 설명은 여기를 참조한다.

2014년 11월 23일 일요일

IP 주소로 Windows용 Boot2Docker 외부에서 Container로 접속하기

Windows 환경에서 Docker는 Boot2Docker 커맨드라인 툴을 통해 가상화된 Linux에서 실행된다.


Boot2Docker Start 아이콘을 실행하면 위와 같은 화면이 나오고 이제 마음 것 docker 명령어를 이용할 수 있다.


실제로 Docker가 실행되는 가상화된 Linux는 Boot3Docker와 같이 설치되는 Oracle VIrtualBox 상에서 실행된다. ifconfig를 실행하면 다음과 같은 네트워크 정보를 알 수 있다.


docker0는 Docker 컨테이너들 간에 연결된 네트워크이고 eth0는 VirtualBox NAT에 연결되어 호스트(Windows)의 인터넷과 연결에 사용되고 eth1은 호스트에 설치된 가상 네트워트 아답터와 매핑되어 호스트에서 Boot2Docker에 연결할 때 사용된다.


위와 같은 호스트와 게스트의 네트워트 관계에서 호스트의 Host Only Network를 통해서 직접 게스트의 docker0 네트워크 IP에 접근할 수 없기 때문에 위의 점선과 같이 호스트의 라우팅 테이블을 수정해서 호스트의 어플리케이션이 docker 컨테이너에 접근할 수 있도록 한다.


관리자모드로 커멘드 창을 열고 route print하여 인터페이스 목록에서 위에서 확인한 VirtualBox Host-Only Ethernet Adapter #2의 인터페이스 아이디 32를 확인하고 아래와 같이 입력한다.

route -p add 172.17.0.0 mask 255.255.0.0 192.168.59.103 IF 32

간단히 설명하면 192.168.59.3이 할당된 인터페이스로 172.17.0.0으로 시작하는 IP 주소에 대한 모든 요청을 192.168.59.103 인터페이스로 돌아서 요청하라는 의미이다. -p 옵션을 주어 이 설정을 영구적으로 적용하게 하였다. 테스트로 아래와 같이 CouchBase 컨테이너를 하나 생성해본다.

docker run -d -p 11210:11210 -p 8091:7081 -p 8092:8092 dustin/couchbase

생성된 CouchBase 컨테이너는 IP 주소 172.17.0.2부터 차례로 할당되고 다음과 같이 호스트에서 CouchBase Console에 접속이 가능함을 확인할 수 있다.

2014년 11월 21일 금요일

Cocos2d-x Label에서 긴 문자열을 짧게 잘라 생략(Ellipse) 기호 붙이기

Cocos2d-x Label에서 긴 문자열을 제한된 폭으로 표시해야할 때가 종종있는데 생각보다 구현할 때 고려해야할 사항이 많다.


Cocos2d-x는 내부적으로 스트링 처리에 UTF8로 사용하기 때문에 유니코드에 대응해야하고 Label이 트루타입 폰트로 그려지는 폭을 Kerning을 고려하여 계산해야 하며, FreeType 폰트 캐쉬와 glyph 정보로 그리는 위치 또한 고려해야 한다.

아래의 코드는 Label의 폭을 limitWidth로 제한하고 생략 기호로 "..."를 붙이는 예제이다. 코드의 간략화를 위해서 함수 하나에 담았다.

void shortenLabelTTFString(Label *label, int limitWidth) {
  std::u16string utf16EllipseString;
  StringUtils::UTF8ToUTF16("...", utf16EllipseString);

  std::u16string utf16String;
  StringUtils::UTF8ToUTF16(label->getString(), utf16String);

  auto ttfConfig = label->getTTFConfig();
  auto ttfAtlas = FontAtlasCache::getFontAtlasTTF(ttfConfig);
  ttfAtlas->prepareLetterDefinitions(utf16EllipseString);

  int letterCount = 0;
  auto kerning = ttfAtlas->getFont()->getHorizontalKerningForTextUTF16(
    utf16EllipseString, letterCount);

  int ellipseWidth = 0;
  FontLetterDefinition letterDef = {0};

  for (int i = 0; i < utf16EllipseString.length(); i++) {
    ttfAtlas->getLetterDefinitionForChar(utf16EllipseString[i], letterDef);
    ellipseWidth += letterDef.xAdvance + kerning[i] + label->getAdditionalKerning();
  }

  if (kerning != nullptr)
    delete [] kerning;

  if (ellipseWidth > limitWidth) {
    label->setString("...");
    return;
  }

  letterCount = 0;
  kerning = ttfAtlas->getFont()->getHorizontalKerningForTextUTF16(
    utf16String, letterCount);

  std::string result;
  std::u16string utf16Result;
  int width = ellipseWidth;

  for (int i = 0; i < utf16String.length(); i++) {
    ttfAtlas->getLetterDefinitionForChar(utf16String[i], letterDef);

    if (width + letterDef.xAdvance > limitWidth) {
      StringUtils::UTF16ToUTF8(utf16Result, result);
      label->setString(result + "...");
      break;
    }

    width += letterDef.xAdvance + kerning[i] + label->getAdditionalKerning();

    utf16Result += utf16String[i];
  }

  if (kerning != nullptr)
    delete [] kerning;
}

2014년 11월 19일 수요일

모바일 스타트업 회사에 유용한 서비스들

스타트업 2년 차, 예전에 다녔던 회사에서는 업무 진행에 신경쓸 필요도 없던 사소한 것들을 하나씩 준비해야했다. 상황때문에 어쩔 수 없이 사용했던 서비스, 도구들이 많이 있었지만 현재 주옥같이 사용하는 것들을 정리해 보았다.

Microsoft BizSpark


등록 신청을 하면 3년인가 MS 운영체제, 오피스, 개발툴을 무료로 사용할 수 있는 라이센스 자격이 주어진다. 더우기 한달에 Azure 15만원 크레딧을 주어서 무료로 사용이 가능하다. 등록에 일주일 정도 걸린다고 했는데 오전에 신청해서 오후에 사용이 가능했다. 외부 접속용으로 사용했던 KT ucloud는 바로 해지했고 무료라서 사용 중이었던 Visual Studio Express, OpenOffice도 바로 교체, 이건 꼭 신청해야해~

Naver Works

예전에는 Google Apps를 무료(5인 이하)로 사용했었는데 사원 수가 많아져서 Naver Works로 바꾸었다. 네이버에 접속하거나 Outlook을 사용하여 메일 서비스를 이용할 수도 있고 모바일 앱으로도 제공되어 매우 편리하다. Google Apps의 경우 우리 LDAP 서버와 계정을 동기화해주는 툴을 제공해서 잘 사용했었는데 Naver Works에서는 이와 유사한 기능이 없는 것이 아쉽다. 하지만 네이버 캘린더, 메모, 주소록, NDrive 등을 모바일에서도 같이 사용할 수 있는 것은 참 좋다. 땡큐 네이버!

Google Docs

1년 정도 모든 기획서를 Atlassian Confluence를 사용해서 작업했었는데 어느 순간 사용하게 되었다. 단순한 기능만큼 간편하게 문서 공유 및 협업이 가능해서 별 불만 없이 사용 중이다. 공문서(아래아한글 파일 .hwp)을 볼 수 없는 것이 최대의 약점인데 이것은 Naver Office를 사용해서 해결 중이다. ^^;

Atlassian JIRA onDemand

프로젝트 관리 및 이슈트래킹을 위해 Confluence와 Jira를 설치해 사용해 오다가 관리의 압박에 못이겨 지금은 클라우드 OnDemand 서비스를 이용하고 있다. 회선 속도가 느린 것과 fisheye 연동 시 반드시 80포트를 사용해야한다는 것만 빼면 매우 만족한다. 한달에 $10...

HockeyApp


iOS, Android 앱을 사용자에게 배포하고 크래쉬 리포트와 피드백을 받을 수 있는 서비스이다. 앱에 SDK를 적용하면 간단하게 버전별로 취합된 크래쉬 리포트 관리가 가능하고 사용 중인 JIRA와도 잘 연계된다. 다만 NDK를 사용한 Android 앱의 경우 크래쉬 리포트를 얻기 위해 Google breakpad 라이브러리를 별도로 빌드해서 사용해야 하는데 앱에서 사용하는 NDK 버전과 breakpad에서 사용하는 버전이 안 맞아서 문제가 발생할 수 있다. 앱에서 사용하는 NDK 버전에 맞는 breakpad 소스 branch를 찾아서 빌드하면 된다. 한 달에 $10...

개발 중인 신규 게임 개발환경

내년 초 라인에 출시할 게임의 개발환경을 대충 그려보니 아래와 같은 모습이 되었다.


올 5월에 출시한 게임의 개발환경과의 비교해보면 메인 DB가 MySQL에서 CouchBase로 바뀌었고 테스트 배포 및 크래쉬 리포트 취합을 위해서 HockeyApp 서비스를 이용한 것을 제외하면 거의 유사하다. CouchBase로 바꾸면서 샤딩이나 캐슁을 위해 필요한 복잡한 구성이 단순화된게 가장 큰 이점이기는 하지만 RDBMS에 특화된 툴을 사용할 수 없어 운영툴에 많은 기능이 필요로했다. 현재 게임은 내부 테스트 중으로 HockeyApp을 통해서 배포하면 등록된 테스터에 알람이 가고 iOS, Android 단말기에서 바로 다운받아서 실행이 가능하다. 실행 중 크래쉬가 발생하면 다음 실행 시 리포트를 HockeyApp 사이트에 전송하며 별도의 Issue Tracker를 사용한다면 연동이 가능하다.


우리 같은 경우 사용 중인 Jira OnDemand로 크래쉬를 이슈로 등록해 준다. 이렇게 훌륭한 서비스를 매달 단돈 $10에 사용이 가능하니 정말로 좋은 세상이다. 아직 용도는 생각 못 해보았지만 시간이 허락된다면 CouchBase XDCR(Cross Data Center Replication)의 대상을 ElasticSearch로 하여 서비스에 활용하는 방안을 고민 중이다.