ݺߣ

ݺߣShare a Scribd company logo
온라인 게임 처음부터 끝까지
동적언어로 만들기
㈜넥슨
프론티어팀
이승재
발표자
이승재
프로그래머
카바티나 스토리
데스크탑 히어로즈
온라인 게임 처음부터 끝까지
동적언어로 만들기
엔진은 C++
온라인 게임 처음부터 끝까지
동적언어로 만들기
엔진은 C++
루아로
발표에서 다룰 내용
사례연구: 스크립트로서의 루아
게임 로직도 루아로 만들기
실용적인 장점
프로그래밍 언어로서의 루아의 매력
단점
미지의 영역
사례연구: 스크립트로서의 루아
카바티나 스토리의 루아
맵 별 스크립트
• 던전: 어떤 몬스터들을 다 잡으면 다음 몬스터들을 젠,
무슨 스위치를 누르면 문을 연다 등
• 퀘스트: 어디에서 무슨 아이템을 사용하면 퀘스트 완료 등
이벤트
• 언제부터 언제까지 경험치 두 배
• 매일 몇 시에 PVP 맵에 입장 가능
반성
더 일찍부터 & 더 많이 쓸 걸 그랬다
몬스터 AI는 자체 포맷, 맵 스크립트는 루아
• 상호 통신 불가능
• 몬스터 AI도 루아로 짰으면 개발이 편했을 텐데…
사실 MMORPG라 느릴까봐 겁나서 못한 거지만
초기에 만든 거대 보스 AI는 C++…
반성
더 일찍부터 & 더 많이 쓸 걸 그랬다
라이브 도중 PvP 맵 추가
• 서버 로직, 클라이언트 UI 모두 루아로 만들었음
• 서버 C++ 수정은 아주 적었다 (유저간 공격가능 플래그 켜는 정도)
현실의 벽
바인딩
상호 함수 호출
객체 참조 유지
자료구조 뒤져보기
디버깅
…
(언어 사이를 넘어다니는 비용)
다양한 바인딩 도구가 있지만,
바인딩 비용을 0으로 만드는 것은 불가능!
수행 시간 비용 말고 작업 비용을 말합니다.
적절한 도구를 쓰면 비용을 상당히 줄일 수 있지만
자잘한 비용이 계속 들어가게 되고
이게 누적되면서 전체 설계에 영향을 미칩니다.
엔진
엔진과 로직과 스크립트
프로그래머가 만든다
게임 로직 프로그래머가 만든다
데이터,
스크립트
프로그래머가 아닌 사람이
주로 만든다
게임 로직과 데이터/스크립
트 사이는 기획적인 필요 때
문에 복잡하고, 변경이 자주
일어납니다.
엔진과 게임 로직 사이는 비
교적 간결하고, 변경이 자주
일어나지 않는 편입니다.
스크립트 붙이기는 어차피 해야 한다
보다 단순하고 변경이 덜 일어나는 곳에
언어 바뀌는 경계를 긋자
엔진과 로직과 스크립트
게임 로직 프로그래머가 만든다
그래서 그것을 실제로 해보았습니다
MMORPG가 아니라서 속도 부담도 없고
온라인 게임 처음부터 끝까지 동적언어로 만들기
총 개발기간 17개월
프로그래머 두 명
(한 명은 기획 및 팀장 겸임 + 학업 병행)
전작은 3D MMORPG였고 데스크탑 히어로즈는 2D 멀티플레이어 액션
게임이었습니다. 게임 로직이나 툴, 엔진 코드 등은 전혀 가져올 수 있는
것이 없었습니다.
아, UI 라이브러리 가져왔군요. 게임브리오로부터 자체 2D 엔진으로 포
팅하느라 고생 좀 했지요.
코드 분량
루아 코드 분량 툴로 편집하는 파일 제외
분류 LOC 편집 주체
게임 로직 & 툴 22,000 프로그래머
스테이지 8,000 기획자
테이블 11,000 기획자
실용적인 장점
낯선 문법 / 빌드 시간 / 에러 격리
local function TryStageStart( stageNum, party, animation, onOK )
Request( 'StageStart', stageNum, party, function( res )
if res ~= 0 then
onOK()
animation( function()
SwitchStage( stageNum )
end )
else
MessageBox{ text = ‘스테이지를 시작할 수 없어요’ }
end
end )
end
낯선, 문법
낯선, 문법
다른 언어:
다른 brain mode
뒤에서 더 설명하겠지만, C++로 코딩할 때와 루아로 코딩할 때 굉장히 다
른 코드가 나옵니다. 동작, 관용어구, 간결하게 짤 수 있는 방식이 전혀 다
르기 때문인데요. C++과 루아는 문법이 매우 다르게 생겼기 때문에, 자신
이 어떤 언어를 사용하고 있는지를 매 순간 느끼게 됩니다.
낯선, 문법
프로그래머 자체 진단 기능:
if cond then
doSomething();
}
가끔 이런 코드가 튀어나오면
‘아 좀 쉬어야겠다’ 혹은 ‘정신 좀 차려야지’
빌드 시간
C++로 게임 로직을 만들면…
• 기획자가 기능을 요청한다
• 될 때까지
{ 코드를 고치고 빌드하고 테스트한다 }
• 커밋한다
• 빌드머신이 빌드한다
• 기획자가 업데이트한다
빌드 시간 자체보다, 빌드로 인해 몰
입이 깨지는 게 더 문제입니다. 빌드
몇십초 넘어가면 다들 웹서핑이나
IRC 하지 않나요? ㅎㅎ
빌드 시간
루아로 게임 로직을 만들면…
• 기획자가 기능을 요청한다
• 될 때까지
{ 코드를 고치고 빌드하고 테스트한다 }
• 커밋한다
• 빌드머신이 빌드한다
• 기획자가 업데이트한다
루아로 프로그래밍하면 몰입이 깨질
틈이 없이 집중된 시간을 계속 유지하
게 됩니다. 덕분에 8시간 근무하고 나
면 굉장히 피곤한데요, 구현하는 분량
은 C++로 같은 시간 근무할 때보다 훨
씬 많기 때문에 야근을 거의 안 했습니
다. 사실 할 수도 없죠. 피곤하니까요.
빌드 시간
수정이 간단한 경우에는 종종 이렇게도 함
• 기획자가 기능을 요청한다
• 기획자 자리에서, 될 때까지
{ 코드를 수정하고 테스트한다 }
일종의 페어 프로그래밍
프로그래밍의 노하우… 같은 게 전달되지 않을까 기대합니다. 대화를 통해 스
펙을 분명히 하고 (그래서 미스커뮤니케이션으로 엉뚱한 기능을 만드는 경우가
없고), 기능의 사용법을 동시에 전달하는 효과도 있고요.
스크립팅 하시는 분을 의미합니다
에러의 격리
서버에서 유저당 VM 하나 할당
안전한 예외처리 가능
• 유저 요청 처리하다 에러 나면,
커넥션 끊고 유저 VM을 제거해 버린다
• PHP 에러 났다고 아파치가 죽지는 않듯이
• 물론 에러 로그는 남깁니다
루아의 재발견:
프로그래밍 언어로서의 매력
테이블 / 코루틴 / 클로저 / 메모리 관리
테이블: 기본 자료구조
키, 값으로 nil을 제외한 모든 종류의 값을 담을 수 있는
연관 배열
associative array
map<any, any>
자료구조는 이게 전부
테이블: 기본 자료구조
클래스도 없고 객체도 없어!!???
OOP 어떻게 하나요?
테이블로 다 만듭니다!
테이블: 기본 자료구조
런타임에 클래스에 멤버함수 추가
예: 패킷 정의 코드를 로딩하면서
클래스에 패킷 보내는 함수 자동 추가
객체의 동작을 런타임에 변경
예: 플레이어 애니메이션 시퀀스가 바뀔 때
스테이지 스크립트에 통지하기
코드 제너레이션이 필요 없습니다
테이블: 자료 서술 포맷
g_playerSkills[197] = {
모션 = 'guardattack';
슬롯안씀 = true;
스킬목록에표시안함 = true;
평타 = true;
근접 = {
명중간딜레이 = 0.00;
관통횟수 = 1;
명중효과 = {
경직시간 = 1.0;
경직강도 = 2;
데미지 = 11;
데미지계산 = 데미지_동일();
넉백X = 30;
넉백Y = 450;
넉백G = Const.grav*0.6;
}; …
사람이
읽고 쓰기 쉬운 XML
테이블: 자료 서술 포맷
local dmg = g_playerSkills[197].근접.명중효과.데미지;
g_playerSkills[197] = {
모션 = 'guardattack';
슬롯안씀 = true;
스킬목록에표시안함 = true;
평타 = true;
근접 = {
명중간딜레이 = 0.00;
관통횟수 = 1;
명중효과 = {
경직시간 = 1.0;
경직강도 = 2;
데미지 = 11; …
해석하기도
편해요!
테이블: 툴 제작
로직 영역의 데이터 편집 툴을 루아로 작성
• 테이블을 루아 문법으로 저장
• 파서 공짜!
• 툴 기능 추가에 아주 민첩하게 대응
엔진 영역의 데이터는 순수 C++ 툴로 편집
(루아 loadstring)
코루틴
비선점형 멀티스레딩: 명시적인 문맥 전환
파이버(Fiber) 비슷
시간 흐름에 따라 진행되는 코드를 짜기 좋다
• 게임 프로그램에서 매우 자주 나오죠!
코루틴
활용 예: 몬스터 AI
• 생성되면 먼저 ‘gen’ 시퀀스를 재생하자
• ‘gen’ 시퀀스가 끝나면 ‘stand’ 시퀀스를 재생하자
• 내 주변 영역에 적이 들어오기까지 기다리자
• 일반 AI 모드로 전환하자
이 모든 과정이 함수 한 개!
C++로 짜려면 끔찍하죠;; State pattern 같은 것을 동원해야 합니다.
코루틴
활용 예: 서버에 캐시샵 구매 요청을 보내면
• 구매 패킷을 보내고, 구매 응답을 기다린다
• 구매 응답을 처리한다. 잔액 확인 패킷을 보내고, 응답을
기다린다
• 잔액 확인 응답을 처리하고 최종 응답을 클라로 보낸다
스레드가 블록되지 않습니다!
기다리기 시작할 때 yield,
응답이 오면 resume
코루틴
다만 문맥 전환이 좀 까다로움. 적절한 래핑 필요
• 스레드 모델:
Sleep, 몹 그룹이 전멸할 때까지 대기 등
• 요청/응답 모델:
요청 보내기 함수를 호출하면 일시정지됨.
응답이 오면 코루틴 재개
• 몬스터 행동 모델:
한 틱 분량 작업을 처리한 후 yield할 의무가 있음
매 틱 자동 resume됨 예외: 인터럽트당한 경우. 넘어진다든지…
yield/resume
클로저
코드 중간에 함수를 만들면
그 순간 보이는 지역변수들이 함수에 묶임
일종의 콜백. C++이라면 function object
C++로도 function object 만들면 다 구현 가능합니다. 하지만, 하고자 하는 일과
직접 관련이 없는 코드를 굉장히 많이 써야 하고, 이름을 지어야 하고, 코드 블록
을 다른 곳에 놓아야 합니다. 바인딩 경우처럼, 이런 사소한 비용이 모여서, 전혀
다른 코드가 나오게 됩니다(C++ 0x에서는 많이 나아졌습니다).
클로저가 없는 언어로만 프로그래밍해보면, 클로저를 쓰면 코드를 어떻게 짜게
되는지, 프로그래밍이 어떻게 편해지는지를 좀처럼 이해하기 어렵습니다. 직접
겪어보는 것이 가장 좋은 방법일 듯합니다.
사실 이 발표의 제목에서 동적 언어라는 단어를 썼지만, 저는 루아의 동적 타입
보다 클로저가 더 큰 매력이라 생각합니다.
클로저
local function TryStageStart( stageNum, party, animation, onOK )
Request( 'StageStart', stageNum, party, function( res )
if res ~= 0 then
onOK();
animation( function()
SwitchStage( stageNum );
end )
else
MessageBox{ ... }
end
end )
end
클로저
효능 및 효과
한 눈에 보여서 좋던데.
읽을 수 있잖아.
점프해서 쫓아다니는 게 아니라.
내 코드 뜯어고쳐 봤냐
고칠만하던? 이해할만하던?
프로그래머 L씨
(30세, 팀장)
메모리 관리
가비지 컬렉션 해줍니다
말이 필요 없죠
weak reference 같은 것도 있습니다
단점
오타! / 메모리 사용량 / 열악한 개발환경 /
클로저의 다크 사이드
오타!
선언되지 않은 변수는 에러 없이 nil
전역변수와 지역변수는 쉽게 해결 가능
• strict.lua (기본 루아 배포에 포함)
객체 멤버가 문제!
• 결국 class를 만들었습니다…
(선언되지 않은 멤버 접근에 에러 발생)
꼭 씁시다!!!
오타!
하지만 실행해 보아야만 오타를 알 수 있다
C++이면 컴파일러가 잡아주는데…
실제 배포되었던 코드!!!
• PolitelyOpenWebPaeg( url );
• ret을 써야 할 곳에 res
메모리 사용량
서버에서 유저당 500KB 소모
• 유저당 VM 하나
• 모든 코드, 테이블을 각 VM에서 독립적으로 로드
메모리 사용량이 병목이 될 것 같은 상황
• 공통 데이터를 묶어서 스레드당 VM 하나로 빼냈습니다
• 300KB대로 줄였음
• 그래도 여전히 크다…
열악한 개발환경
만들었던 도구들 (스크립트+로직 공용)
• 호출 바인딩 (lua_tinker 많이 참고함. 감사합니다!)
• C++에서 테이블 접근
• 에러 핸들링
• UTF-8 한글 식별자 허용 패치
• …
열악한 개발환경
만들었던 도구들 (로직용)
• 간이 디버거
• 크래시 보고
• 클래스 (오타 방지/상속)
• …
열악한 개발환경
아직 더 필요한 것: 디버깅 기능 보강
• GUI, 브레이크포인트/스텝
• 외부 프로그램 붙여서 띄우기는 싫고
• 돌다가 죽으면 디버거 떠서 상황 파악할 수 있게
클로저의 다크 사이드
dlg:SetEventHandler( ‘Buy’, ‘CLICK’, function()
Request( ‘BuyItem’, …, function( ret )
(dlg의 내용을 갱신)
end );
end );
dlg:SetEventHandler( ‘Close’, function()
dlg:Remove();
dlg = nil;
end );
1. Buy 눌러서 요청 보내 놓고
2. 닫기 버튼을 눌러버린 다음
3. 응답이 온다면
dlg가 nil이에요 T_T
미지의 영역
유지보수성 / 해킹 / 수행속도
유지보수성
코드 양이 적은 대신 엄격한 규율이 필요
• 주석을 더 열심히 써야 한다
• 코드를 더 열심히 읽어야 한다
• 더 많이 테스트해야 한다
프로그래머가 많아져도 괜찮을까?
세대 교체가 이어져도 괜찮을까?
프로젝트 시작부터 지금까지 두 명. 교체 없었음
어차피 프로젝트 열 개 중에 하나만 살아남을 거라면
장기적인 확장성, 유지보수성에 투입할 자원을 돌려서
출시 전까지 결과물에의 직접적인 기여를 늘리는 것이
옳은 선택일터다.
그래서 살아남는 하나가 되면?
그 다음은 그때 걱정하기
트위터, 2010년 9월
유지보수성
클라이언트 해킹 문제
안티해킹툴의 보호를 못 받는 상황
• 데이터 패키징으로 최소한의 방어는 함
• 해킹을 염두에 두고 기획적인 안전장치 설치함
퍼포먼스
아직은 Fast enough
가비지 컬렉션 오버헤드?
• 아직 겪어보지 못함
LuaJIT이 빠르다던데…
• 마음속의 최후의 보루
결론
시불불 빠돌이일 당시 해커와 화가에서
리습으로 경쟁자들을 따돌렸다는 얘기를 보면서
에이 구라ㅎ 그랬는데
요즘 루아로 모든 게임 로직을 짜면서
미칠듯한 생산성 향상을 느끼고 있음! …
트위터, 2010년 여름
루아 좋아요
스크립트 언어로만 알려진 게 아까울 정도
기획서 뭉치를 뽑아내기보다는,
빨리 만들어 보고 재미있을지 테스트하기를 선호하는
민첩한 프로젝트에 적절
개발 환경 투자는 계속 필요
Visual Studio처럼 모든 것이 갖춰진 환경이 아니다
필요할 때마다 만들다 보면 어느 순간 음속 돌파
유지보수성은 아직 미지수
내년에 뵙겠습니다
마지막으로…
Programming in Lua
• 바이블입니다 바이블
• 이 책밖에 없다 해도 과언이 아님!
• 정말 많이 도움됩니다
입문자용 책은 아님…
Q / A
감사합니다

More Related Content

온라인 게임 처음부터 끝까지 동적언어로 만들기

  • 1. 온라인 게임 처음부터 끝까지 동적언어로 만들기 ㈜넥슨 프론티어팀 이승재
  • 3. 온라인 게임 처음부터 끝까지 동적언어로 만들기 엔진은 C++
  • 4. 온라인 게임 처음부터 끝까지 동적언어로 만들기 엔진은 C++ 루아로
  • 5. 발표에서 다룰 내용 사례연구: 스크립트로서의 루아 게임 로직도 루아로 만들기 실용적인 장점 프로그래밍 언어로서의 루아의 매력 단점 미지의 영역
  • 7. 카바티나 스토리의 루아 맵 별 스크립트 • 던전: 어떤 몬스터들을 다 잡으면 다음 몬스터들을 젠, 무슨 스위치를 누르면 문을 연다 등 • 퀘스트: 어디에서 무슨 아이템을 사용하면 퀘스트 완료 등 이벤트 • 언제부터 언제까지 경험치 두 배 • 매일 몇 시에 PVP 맵에 입장 가능
  • 8. 반성 더 일찍부터 & 더 많이 쓸 걸 그랬다 몬스터 AI는 자체 포맷, 맵 스크립트는 루아 • 상호 통신 불가능 • 몬스터 AI도 루아로 짰으면 개발이 편했을 텐데… 사실 MMORPG라 느릴까봐 겁나서 못한 거지만 초기에 만든 거대 보스 AI는 C++…
  • 9. 반성 더 일찍부터 & 더 많이 쓸 걸 그랬다 라이브 도중 PvP 맵 추가 • 서버 로직, 클라이언트 UI 모두 루아로 만들었음 • 서버 C++ 수정은 아주 적었다 (유저간 공격가능 플래그 켜는 정도)
  • 10. 현실의 벽 바인딩 상호 함수 호출 객체 참조 유지 자료구조 뒤져보기 디버깅 … (언어 사이를 넘어다니는 비용)
  • 11. 다양한 바인딩 도구가 있지만, 바인딩 비용을 0으로 만드는 것은 불가능! 수행 시간 비용 말고 작업 비용을 말합니다. 적절한 도구를 쓰면 비용을 상당히 줄일 수 있지만 자잘한 비용이 계속 들어가게 되고 이게 누적되면서 전체 설계에 영향을 미칩니다.
  • 12. 엔진 엔진과 로직과 스크립트 프로그래머가 만든다 게임 로직 프로그래머가 만든다 데이터, 스크립트 프로그래머가 아닌 사람이 주로 만든다 게임 로직과 데이터/스크립 트 사이는 기획적인 필요 때 문에 복잡하고, 변경이 자주 일어납니다. 엔진과 게임 로직 사이는 비 교적 간결하고, 변경이 자주 일어나지 않는 편입니다.
  • 13. 스크립트 붙이기는 어차피 해야 한다 보다 단순하고 변경이 덜 일어나는 곳에 언어 바뀌는 경계를 긋자 엔진과 로직과 스크립트 게임 로직 프로그래머가 만든다
  • 14. 그래서 그것을 실제로 해보았습니다 MMORPG가 아니라서 속도 부담도 없고
  • 16. 총 개발기간 17개월 프로그래머 두 명 (한 명은 기획 및 팀장 겸임 + 학업 병행) 전작은 3D MMORPG였고 데스크탑 히어로즈는 2D 멀티플레이어 액션 게임이었습니다. 게임 로직이나 툴, 엔진 코드 등은 전혀 가져올 수 있는 것이 없었습니다. 아, UI 라이브러리 가져왔군요. 게임브리오로부터 자체 2D 엔진으로 포 팅하느라 고생 좀 했지요.
  • 17. 코드 분량 루아 코드 분량 툴로 편집하는 파일 제외 분류 LOC 편집 주체 게임 로직 & 툴 22,000 프로그래머 스테이지 8,000 기획자 테이블 11,000 기획자
  • 18. 실용적인 장점 낯선 문법 / 빌드 시간 / 에러 격리
  • 19. local function TryStageStart( stageNum, party, animation, onOK ) Request( 'StageStart', stageNum, party, function( res ) if res ~= 0 then onOK() animation( function() SwitchStage( stageNum ) end ) else MessageBox{ text = ‘스테이지를 시작할 수 없어요’ } end end ) end 낯선, 문법
  • 20. 낯선, 문법 다른 언어: 다른 brain mode 뒤에서 더 설명하겠지만, C++로 코딩할 때와 루아로 코딩할 때 굉장히 다 른 코드가 나옵니다. 동작, 관용어구, 간결하게 짤 수 있는 방식이 전혀 다 르기 때문인데요. C++과 루아는 문법이 매우 다르게 생겼기 때문에, 자신 이 어떤 언어를 사용하고 있는지를 매 순간 느끼게 됩니다.
  • 21. 낯선, 문법 프로그래머 자체 진단 기능: if cond then doSomething(); } 가끔 이런 코드가 튀어나오면 ‘아 좀 쉬어야겠다’ 혹은 ‘정신 좀 차려야지’
  • 22. 빌드 시간 C++로 게임 로직을 만들면… • 기획자가 기능을 요청한다 • 될 때까지 { 코드를 고치고 빌드하고 테스트한다 } • 커밋한다 • 빌드머신이 빌드한다 • 기획자가 업데이트한다 빌드 시간 자체보다, 빌드로 인해 몰 입이 깨지는 게 더 문제입니다. 빌드 몇십초 넘어가면 다들 웹서핑이나 IRC 하지 않나요? ㅎㅎ
  • 23. 빌드 시간 루아로 게임 로직을 만들면… • 기획자가 기능을 요청한다 • 될 때까지 { 코드를 고치고 빌드하고 테스트한다 } • 커밋한다 • 빌드머신이 빌드한다 • 기획자가 업데이트한다 루아로 프로그래밍하면 몰입이 깨질 틈이 없이 집중된 시간을 계속 유지하 게 됩니다. 덕분에 8시간 근무하고 나 면 굉장히 피곤한데요, 구현하는 분량 은 C++로 같은 시간 근무할 때보다 훨 씬 많기 때문에 야근을 거의 안 했습니 다. 사실 할 수도 없죠. 피곤하니까요.
  • 24. 빌드 시간 수정이 간단한 경우에는 종종 이렇게도 함 • 기획자가 기능을 요청한다 • 기획자 자리에서, 될 때까지 { 코드를 수정하고 테스트한다 } 일종의 페어 프로그래밍 프로그래밍의 노하우… 같은 게 전달되지 않을까 기대합니다. 대화를 통해 스 펙을 분명히 하고 (그래서 미스커뮤니케이션으로 엉뚱한 기능을 만드는 경우가 없고), 기능의 사용법을 동시에 전달하는 효과도 있고요. 스크립팅 하시는 분을 의미합니다
  • 25. 에러의 격리 서버에서 유저당 VM 하나 할당 안전한 예외처리 가능 • 유저 요청 처리하다 에러 나면, 커넥션 끊고 유저 VM을 제거해 버린다 • PHP 에러 났다고 아파치가 죽지는 않듯이 • 물론 에러 로그는 남깁니다
  • 26. 루아의 재발견: 프로그래밍 언어로서의 매력 테이블 / 코루틴 / 클로저 / 메모리 관리
  • 27. 테이블: 기본 자료구조 키, 값으로 nil을 제외한 모든 종류의 값을 담을 수 있는 연관 배열 associative array map<any, any>
  • 29. 테이블: 기본 자료구조 클래스도 없고 객체도 없어!!??? OOP 어떻게 하나요? 테이블로 다 만듭니다!
  • 30. 테이블: 기본 자료구조 런타임에 클래스에 멤버함수 추가 예: 패킷 정의 코드를 로딩하면서 클래스에 패킷 보내는 함수 자동 추가 객체의 동작을 런타임에 변경 예: 플레이어 애니메이션 시퀀스가 바뀔 때 스테이지 스크립트에 통지하기 코드 제너레이션이 필요 없습니다
  • 31. 테이블: 자료 서술 포맷 g_playerSkills[197] = { 모션 = 'guardattack'; 슬롯안씀 = true; 스킬목록에표시안함 = true; 평타 = true; 근접 = { 명중간딜레이 = 0.00; 관통횟수 = 1; 명중효과 = { 경직시간 = 1.0; 경직강도 = 2; 데미지 = 11; 데미지계산 = 데미지_동일(); 넉백X = 30; 넉백Y = 450; 넉백G = Const.grav*0.6; }; … 사람이 읽고 쓰기 쉬운 XML
  • 32. 테이블: 자료 서술 포맷 local dmg = g_playerSkills[197].근접.명중효과.데미지; g_playerSkills[197] = { 모션 = 'guardattack'; 슬롯안씀 = true; 스킬목록에표시안함 = true; 평타 = true; 근접 = { 명중간딜레이 = 0.00; 관통횟수 = 1; 명중효과 = { 경직시간 = 1.0; 경직강도 = 2; 데미지 = 11; … 해석하기도 편해요!
  • 33. 테이블: 툴 제작 로직 영역의 데이터 편집 툴을 루아로 작성 • 테이블을 루아 문법으로 저장 • 파서 공짜! • 툴 기능 추가에 아주 민첩하게 대응 엔진 영역의 데이터는 순수 C++ 툴로 편집 (루아 loadstring)
  • 34. 코루틴 비선점형 멀티스레딩: 명시적인 문맥 전환 파이버(Fiber) 비슷 시간 흐름에 따라 진행되는 코드를 짜기 좋다 • 게임 프로그램에서 매우 자주 나오죠!
  • 35. 코루틴 활용 예: 몬스터 AI • 생성되면 먼저 ‘gen’ 시퀀스를 재생하자 • ‘gen’ 시퀀스가 끝나면 ‘stand’ 시퀀스를 재생하자 • 내 주변 영역에 적이 들어오기까지 기다리자 • 일반 AI 모드로 전환하자 이 모든 과정이 함수 한 개! C++로 짜려면 끔찍하죠;; State pattern 같은 것을 동원해야 합니다.
  • 36. 코루틴 활용 예: 서버에 캐시샵 구매 요청을 보내면 • 구매 패킷을 보내고, 구매 응답을 기다린다 • 구매 응답을 처리한다. 잔액 확인 패킷을 보내고, 응답을 기다린다 • 잔액 확인 응답을 처리하고 최종 응답을 클라로 보낸다 스레드가 블록되지 않습니다! 기다리기 시작할 때 yield, 응답이 오면 resume
  • 37. 코루틴 다만 문맥 전환이 좀 까다로움. 적절한 래핑 필요 • 스레드 모델: Sleep, 몹 그룹이 전멸할 때까지 대기 등 • 요청/응답 모델: 요청 보내기 함수를 호출하면 일시정지됨. 응답이 오면 코루틴 재개 • 몬스터 행동 모델: 한 틱 분량 작업을 처리한 후 yield할 의무가 있음 매 틱 자동 resume됨 예외: 인터럽트당한 경우. 넘어진다든지… yield/resume
  • 38. 클로저 코드 중간에 함수를 만들면 그 순간 보이는 지역변수들이 함수에 묶임 일종의 콜백. C++이라면 function object C++로도 function object 만들면 다 구현 가능합니다. 하지만, 하고자 하는 일과 직접 관련이 없는 코드를 굉장히 많이 써야 하고, 이름을 지어야 하고, 코드 블록 을 다른 곳에 놓아야 합니다. 바인딩 경우처럼, 이런 사소한 비용이 모여서, 전혀 다른 코드가 나오게 됩니다(C++ 0x에서는 많이 나아졌습니다). 클로저가 없는 언어로만 프로그래밍해보면, 클로저를 쓰면 코드를 어떻게 짜게 되는지, 프로그래밍이 어떻게 편해지는지를 좀처럼 이해하기 어렵습니다. 직접 겪어보는 것이 가장 좋은 방법일 듯합니다. 사실 이 발표의 제목에서 동적 언어라는 단어를 썼지만, 저는 루아의 동적 타입 보다 클로저가 더 큰 매력이라 생각합니다.
  • 39. 클로저 local function TryStageStart( stageNum, party, animation, onOK ) Request( 'StageStart', stageNum, party, function( res ) if res ~= 0 then onOK(); animation( function() SwitchStage( stageNum ); end ) else MessageBox{ ... } end end ) end
  • 40. 클로저 효능 및 효과 한 눈에 보여서 좋던데. 읽을 수 있잖아. 점프해서 쫓아다니는 게 아니라. 내 코드 뜯어고쳐 봤냐 고칠만하던? 이해할만하던? 프로그래머 L씨 (30세, 팀장)
  • 41. 메모리 관리 가비지 컬렉션 해줍니다 말이 필요 없죠 weak reference 같은 것도 있습니다
  • 42. 단점 오타! / 메모리 사용량 / 열악한 개발환경 / 클로저의 다크 사이드
  • 43. 오타! 선언되지 않은 변수는 에러 없이 nil 전역변수와 지역변수는 쉽게 해결 가능 • strict.lua (기본 루아 배포에 포함) 객체 멤버가 문제! • 결국 class를 만들었습니다… (선언되지 않은 멤버 접근에 에러 발생) 꼭 씁시다!!!
  • 44. 오타! 하지만 실행해 보아야만 오타를 알 수 있다 C++이면 컴파일러가 잡아주는데… 실제 배포되었던 코드!!! • PolitelyOpenWebPaeg( url ); • ret을 써야 할 곳에 res
  • 45. 메모리 사용량 서버에서 유저당 500KB 소모 • 유저당 VM 하나 • 모든 코드, 테이블을 각 VM에서 독립적으로 로드 메모리 사용량이 병목이 될 것 같은 상황 • 공통 데이터를 묶어서 스레드당 VM 하나로 빼냈습니다 • 300KB대로 줄였음 • 그래도 여전히 크다…
  • 46. 열악한 개발환경 만들었던 도구들 (스크립트+로직 공용) • 호출 바인딩 (lua_tinker 많이 참고함. 감사합니다!) • C++에서 테이블 접근 • 에러 핸들링 • UTF-8 한글 식별자 허용 패치 • …
  • 47. 열악한 개발환경 만들었던 도구들 (로직용) • 간이 디버거 • 크래시 보고 • 클래스 (오타 방지/상속) • …
  • 48. 열악한 개발환경 아직 더 필요한 것: 디버깅 기능 보강 • GUI, 브레이크포인트/스텝 • 외부 프로그램 붙여서 띄우기는 싫고 • 돌다가 죽으면 디버거 떠서 상황 파악할 수 있게
  • 49. 클로저의 다크 사이드 dlg:SetEventHandler( ‘Buy’, ‘CLICK’, function() Request( ‘BuyItem’, …, function( ret ) (dlg의 내용을 갱신) end ); end ); dlg:SetEventHandler( ‘Close’, function() dlg:Remove(); dlg = nil; end ); 1. Buy 눌러서 요청 보내 놓고 2. 닫기 버튼을 눌러버린 다음 3. 응답이 온다면 dlg가 nil이에요 T_T
  • 50. 미지의 영역 유지보수성 / 해킹 / 수행속도
  • 51. 유지보수성 코드 양이 적은 대신 엄격한 규율이 필요 • 주석을 더 열심히 써야 한다 • 코드를 더 열심히 읽어야 한다 • 더 많이 테스트해야 한다 프로그래머가 많아져도 괜찮을까? 세대 교체가 이어져도 괜찮을까? 프로젝트 시작부터 지금까지 두 명. 교체 없었음
  • 52. 어차피 프로젝트 열 개 중에 하나만 살아남을 거라면 장기적인 확장성, 유지보수성에 투입할 자원을 돌려서 출시 전까지 결과물에의 직접적인 기여를 늘리는 것이 옳은 선택일터다. 그래서 살아남는 하나가 되면? 그 다음은 그때 걱정하기 트위터, 2010년 9월 유지보수성
  • 53. 클라이언트 해킹 문제 안티해킹툴의 보호를 못 받는 상황 • 데이터 패키징으로 최소한의 방어는 함 • 해킹을 염두에 두고 기획적인 안전장치 설치함
  • 54. 퍼포먼스 아직은 Fast enough 가비지 컬렉션 오버헤드? • 아직 겪어보지 못함 LuaJIT이 빠르다던데… • 마음속의 최후의 보루
  • 56. 시불불 빠돌이일 당시 해커와 화가에서 리습으로 경쟁자들을 따돌렸다는 얘기를 보면서 에이 구라ㅎ 그랬는데 요즘 루아로 모든 게임 로직을 짜면서 미칠듯한 생산성 향상을 느끼고 있음! … 트위터, 2010년 여름
  • 57. 루아 좋아요 스크립트 언어로만 알려진 게 아까울 정도
  • 58. 기획서 뭉치를 뽑아내기보다는, 빨리 만들어 보고 재미있을지 테스트하기를 선호하는 민첩한 프로젝트에 적절
  • 59. 개발 환경 투자는 계속 필요 Visual Studio처럼 모든 것이 갖춰진 환경이 아니다 필요할 때마다 만들다 보면 어느 순간 음속 돌파
  • 61. 마지막으로… Programming in Lua • 바이블입니다 바이블 • 이 책밖에 없다 해도 과언이 아님! • 정말 많이 도움됩니다 입문자용 책은 아님…