일부분만 대략적으로만 살펴본 상태라 좀 부족하지만, 나름대로 줄여서 적어봅니다.

0. 차례

- 소개 (1/3)
자바를 활용하는 것에 대한 간단한 소개와 자바 클래스 파일의 구성에 대해 간단히 다루어본다.
샘플 : 자바 클래스 파일 파서

- 구현 (2/3)
JVM 구현을 위한 바이트 코드 인터프리팅, 함수 invoke, 가비지 컬렉트등을 구현한다.
샘플 : 게임을 위한 JVM 인터프리터

- 응용 (3/3)
게임에 적용해 볼만한 간단한 아이디어들

1. 게임 스크립트 언어 선택

게임의 결과물과 상관없이 생산성이나 작업 효율은 개발에 있어서 중요한 요소입니다. 스크립트 시스템은 개발 기간을 단축하고 유지 보수를 쉽게 하는 여러 가지 방법 중에서 가장 일반적인 방법입니다.

스크립트 시스템을 적용하는 분야는 이벤트나 게임 진행에 관한 것부터, 오브젝트 처리, 인공지능까지 다양하기 때문에 여러가지를 고려하여 가장 적합한 언어를 선택하여 사용하는 것이 중요할 것입니다.
기본적으로 고려해야 할 요소는 작업자, 스트립트의 복잡도, 실행 속도, 개발 기간일 것입니다. 만약, 작업자가 프로그래밍에 문외한이거나 처리하고자 하는 것이 단순히 명령어와 기초적인 분기 명령으로 충분히 처리 가능한 수준이라면 간이 스크립트를 만드는 것이 적합할 것입니다. 속도에 따라 최적화된 중간 코드가 필요하기도 하고, 개발 기간이나 난이도에 따라 외부 언어를 사용해야 하기도 합니다.
여러 가지를 따져서 선택할 수 있는 것은 간이 스크립트부터, 최근에 인기 있는 파이썬, 루아까지 다양합니다. 이 중에 전통의 강호 자바를 게임 스크립팅 언어로 사용하는 것을 다루어 보겠습니다.

자바는 기본적으로 프로그래밍 언어에 경험이 있어야 하는 단점이 있습니다. 하지만 메모리 처리는 물론, 함수사용, 상속등의 강력한 기능을 자유롭게 사용할 수 있기 때문에 지능적인 처리가 가능하고, 스트립팅 코드 자체의 생산성도 높일 수 있습니다. 이런 이유로 인공 지능이나 오브젝트 처리등의 스크립트 언어로 고려해 볼만 하다고 하겠습니다.

2. 스크립팅 언어로서의 자바 활용 방안

'Starcraft:Ghost'를 제작하고 있는 개발사 Nihilistic Software 에서 제작한 RPG 게임, 'Vampire:The Masquerade' 에서 자바를 사용한 사례가 있으며 [ROB1], ID software 의 존칼막씨도 "퀘이크3 아레나" 개발 초기엔 자바를 사용을 언급한 적이 있습니다. (여러 가지 여건 때문에 포기했지만, 차후에 다시 적용할 계획이 있다고 얘기하고 있습니다.) [GAMA1]

자바를 스크립팅 언어로 사용한다는 것은 일반적으로 JNI (Java Native Interface)를 사용한다는 얘기입니다. [JNI] JNI는 시스템의 JVM(Java Virtual Machine)을 이용해서 자바코드를 실행하고, 자바코드를 이용해 내부 게임의 실행 코드를 호출하는 방식입니다. JVM 에 의해서 시스템에 최적화된 상태로 스크립트 언어가 실행되며, 소켓, 벡터, 데이타베이스, 메모리 관리등의 강력한 기능을 그대로 사용할 수 있기 때문에 많은 개발자들이 선호하고 있습니다. (이 방식은 주로 java 가 메인이 되는 방식입니다.)
만약 이상적인 환경이 조성된다면 플렛폼 별로 네이트 코드만 작성해주면 별도의 포팅의 번거로움 없이 시스템에 최적화되어 실행될 것입니다. 하지만 아직 많은 플렛폼상에서 안정적으로 지원해주는 가에 대한 검증은 부족한 형편입니다. (퀘이크 3에서 채택되지 못한 가장 큰 이유이기도 한데, 만약 자바가 채용되었다면 자바로 제작된 MOD들은 같은 바이너리로 리눅스, 맥, 윈도우에 상관없이 시스템에 최적화 되어 실행되었을 것입니다.)

이 글에서 접근해 보고자 하는 것은 JNI 같이 시스템적인 측면이 아니라 단순히 언어로써의 자바입니다. (물론 시스템적인 면에서도 접근은 합니다만.) 자바의 중간 코드에 해당하는 자바 바이트 코드 인터프리터를 작성해서 메모리사용, 상속, 함수 호출등의 언어적인 이점을 얻어보자는 것입니다. 단순히 인퍼프리팅 하는 수준이므로 특별한 플렛폼 제한없이 사용할 수 있을 것입니다. (JNI 수준의 빠른 실행 속도를 얻을 수는 없지만, 게임에서 스크립트 호출이 차지하는 비중을 적당히 조절한다면 차이를 줄일 수 있을 것입니다.)

- 자바 바이트 코드 활용
- 인터프리터 수준의 JVM 작성
- 예외적인 상황들은 심각하게 고려하지 않는 다.

위의 것들이 제안하고자 하는 것의 자바 활용안입니다. 요점은 JVM을 구현하되 게임에 최적화된 형태로 구현하자는 것입니다.

게임 분야는 약간의 제한을 두면 예외를 고려하지 않아도 된다는 점이 해당 분야에서 다루는 것보다 쉽게 접근할 있는 편리한 점입니다.
(단순히 bmp를 제어한다고 했을 때 내부 rle 엔코딩은 사용 안한다는 조건만 있다면 rle 디코딩 루틴은 작성하지 않아고 되며, 리소스 파일이 깨졌을 경우에 대한 상황도 고려하지 않아도 되기 때문에 그래픽 프로그램의 bmp 로더 보다는 훨씬 간단하게 작성할 수 있을 것입니다.)
이런 이유로 자바를 게임 스크립팅 언어로 사용한다고 했을 때는 JVM의 중요한 한 과정인 검증 (verify) 과정등은 생략할 수 있을 것입니다. (악의적인 바이트 코드 변형이 있다고 생각할 수 없기 때문.)
과정 뿐 아니라 필요할 경우 기능을 축소하는 것도 가능할 것입니다. (64비트 long 형을 사용하지 않는 다는 조건을 두면 long 형에 대한 처리는 하지 않아도 되겠죠.)
구현상 편의를 위해 가비지 컬렉트를 구현하지 않고 메모리 해제 메소드를 만들어 C 처럼 처리할 수도 있을 것입니다.

중심을 '게임에 최적화 된' 형태로 jvm 을 구현하는 데 두고 구현한다면 어려운 문제들을 피해 쉽게 구현할 수 있을 것입니다.

3. 구성

JVM 에 해당하는 부분을 직접 작성해야 하는 데, 단순히 구현의 관점에서 보면 아래와 같은 작업이 필요합니다.

- 클래스 파일 로더 (바이트코드읽기)
- 스택 기반 인터프리터 (바이트코드실행)
- Heap 메모리 매니저 (메모리할당, 가비지컬렉트)

클래스 파일은 C 파일을 컴파일하면 생성되는 .OBJ파일 처럼 자바파일(.java)을 컴파일 했을 때 생성되는 파일(.class)입니다. 클래스 파일에는 클래스의 정의와 코드에 대한 정보들을 포함하고 있습니다.
실행 코드에 해당하는 자바 바이트 코드는 스택 기반의 명령어 코드로 이루어져 있습니다. 이 명령들은 처리하는 인터프리터와 메모리의 할당과 해제를 위한 메모리 매니저를 만들어야 할 것입니다. (자바는 특별한 해제 명령은 없는 데, 내부적인 가비지 컬렉트 방식으로 처리를 하는 데, 이에 대한 처리도 필요하겠습니다.)

4. 클래스 파일 로더

파일포맷에 관한 부분이나 명령에 관한 설명은 The Java Virtual Machine Specification [JVM1]에 자세히 나와 있습니다. 거의 교과서 같은 책이므로 자바 바이트 코드를 활용하고자 한다면 반드시 봐야 할 책입니다.

클래스 파일에는 클래스의 구성과 메소드들에 대한 정보를 가지고 있습니다. 구현상 필요한 부분은 아래와 같습니다.

- 상수부
상수부는 클래스나 메소드등에 필요한 것들이 선언되어 있습니다. 코드상에 나오는 상수나 문자열, 타입등을 모두 포함하고 있습니다. 클래스 파일 전체에 걸쳐 사용됩니다. (각 상수들은 계층적으로 구성되어 있기 때문에 사용하기엔 약간 까다로운 면이 있습니다.)

- 클래스 필드부
클래스 필드부는 클래스의 맴버나 맴버의 타입들이 선언되어 있습니다.

- 메소드부
클래스의 가장 핵심적인 부분은 메소드에 바이트 코드일 것이다. opcode(인스트럭션)들을 살펴보면 단순한 스택기반의 언어형태로 되어 있음을 알 수 있습니다. 명령어 자체가 명확하고, 코드도 충실하게 컴파일 되기 때문에 단순 인터프리터를 구현하고 분석하는 데 큰 어려움은 없습니다. (실제 자바의 실행 최적화는 바이트코드를 실행하는 단계에서 이루어지기 때문에, 바이트코드의 최적화는 거의 없다고 봐도 됩니다.)

그 밖에 인터페이스 선언부나 상위 클래스 등에 대한 정보, 메소드별 예외 테이블 등도 포함하고 있습니다.

클래스 파일이 bigendian 방식(0x1234 가 0x34, 0x12 로 저장되는...)으로 바이트 정렬된 것만 주의하면 다루는 데 큰 어려움은 없습니다.

5. 바이트 코드 예

바이트 코드는 실제 가장 머신에서 처리해야할 명령어들의 집합입니다.
만약 아래와 같은 자바 코드를 컴파일하면

public int align2grain(int i, int grain) {
     return ((i+grain-1)&~(grain-1));
}

아래와 같은 바이트 코드를 생성합니다.

1B 1C 60 04   64 1C 04 64   02 82 7E AC

이를 분석해보면 아래와 같다.

# methods(6)    name:"align2grain", desc:"(II)I", access:public

000 iload_1   ; local#1
001 iload_2   ; local#2
002 iadd
003 iconst_1  ; 1
004 isub
005 iload_2   ; local#2
006 iconst_1  ; 1
007 isub
008 iconst_m1 ; -1
009 ixor
010 iand
011 ireturn

함수는 static 이 아니므로 local#0 에는 오브젝트의 포인트(this 에 해당됨)가 local#1, local#2 에는 각 인자값이 대입됩니다. (static 형일 경우 각 인자는 local#0, local#1 에 매핑됩니다.)
실행 라인별로 스택의 상태를 체크해보면 아래와 같다

000 [local#1]
001 [local#1], [local#2]
002 [local#1 + local#2]
003 [local#1 + local#2], [1]
004 [local#1 + local#2 - 1]
005 [local#1 + local#2 - 1], [local#2]
006 [local#1 + local#2 - 1], [local#2], [1]
007 [local#1 + local#2 - 1], [local#2 - 1]
008 [local#1 + local#2 - 1], [local#2 - 1], [-1]
009 [local#1 + local#2 - 1], [(local#2 - 1) ^ (-1)]
010 [(local#1 + local#2 - 1) & ((local#2 - 1) ^ (-1))]
011 ireturn

결국 마지막 스텍에 남는 값은 자바로 구현했던 것과 같음을 볼 수 있습니다. (not 명령어가 없기 때문에 xor 을 이용해서 구현되어 있네요.)

단순한 바이트 코드만 처리하는 인터프리터를 만든다면 자바의 모든 코드를 사용할 수 있는 것입니다. 함수의 호출이라던가 명령들이 스택방식으로 예외없이 완전하게 맞추어져 있기 때문에 특별한 예외 사항을 고려하지 않아도 된다. (iadd 명령에서 스택위의 두개의 인자값이 모두 int 형이 아닐 경우는 전혀 생각하지 않아도 됩니다.)

6. 샘플 소스

위에 언급한 The Java Virtual Machine Specification 을 보고 최대한 설명되어 있는 그대로를 토대로 작성한 샘플입니다. 클래스 파일을 읽어서 의미가능한 텍스트로 출력하는 것인데, 우선적으로 구현해본 셈플입니다. 스크립트 처리하는 거 구현하면서 약간 잘못된 부분은 고쳤는 데, 아무래도 검증은 많이 안된 것이기 때문에 그냥 이런식으로 구현되기도 하는 구나 정도로 보시면 좋겠습니다.

상수부에서 utf8이 유니코드값으로 가지고 있어서 (자바의 문자형인 char은 16비트입니다.) 일반적인 완성형 한글을 사용하기 위해서 약간의 변환 코드를 추가했습니다. 구현의 간략성을 위해 별도의 테이블은 사용하지 않고 그냥 윈도우에서 제공하는 내부 함수를 사용했습니다. 만약 다른 플렛폼에서 쓰려면 변환 테이블을 만들어야 할 거 같습니다.

같이 제공되는 test.java 는 확인차 책에 나온 예제들을 토대로 작성한 것들이고 출력되는 결과와 책의 내용을 비교해보면 도움이 될겁니다. (test.txt 에 캡쳐해 놓았습니다.)

7. 레퍼런스

- 참고서적

[JVM1]
The Java Virtual Machine Specification
Tim Lindholm, Frank Yellin 저
Addison Wesley

Programming for the java virtual machine
Joshua Engel 저
Addison Wesley
(번역서 : 자바 가상머신 프로그래밍 - 인포북)

- 참고 페이지

[JNI]
"JNI 기술(JNI Technology)"
http://www.javastudy.co.kr/docs/jhan/javaadvance/jni.html

"JNI를 이용한 JAVA Script Engine"
http://home.dreamx.net/evans00/jni/default.htm

[ROB1]
"Postmortem of Nihilistic Software's Vampire: The Masquerade -- Redemption"
http://www.gamasutra.com/features/20000802/huebner_01.htm

[GAMA1]
"id Abandons Java for Quake 3: Arena"
"Embedded Java in Vampire: The Masquerade"
http://www.gamasutra.com/features/19990611/java_13.htm

[Python]
"the official website for the Python language"
http://www.python.org/

"gpgiki - python_script"
http://www.gpgstudy.com/gpgiki/python_script

[Lua]
"The Programming Language Lua"
http://www.lua.org/

"redwiki.net LUA 이야기"
http://www.redwiki.net/wiki/moin.cgi/LUA_20_c0_cc_be_df_b1_e2

[GameScripting]
"Adding Languages to Game Engines"
http://www.gamasutra.com/features/19971003/huebner_01.htm

"Fast Scripting - a pre-compiled approach"
http://www.gamedev.net/reference/articles/article1381.asp

"Dirty Java: Using the Java Native Interface Within Games"
http://www.gamasutra.com/features/19990611/java_01.htm

"레이디안 이러케 만들어따 - 스크립트 인코딩/디코딩"
http://board0.dreamwiz.com/BIN/Board.cgi?path=deadfish&db=dreamwizkng&cmd=view&no=20

[JAVA]
"자바 스터디 네트워크"
http://www.javastudy.co.kr

7. (보너스)

첫번째 얘기를 마치면서 자바에 흥미를 드리고자 자바 얘기를 해보겠습니다.

초기의 자바는 많은 강점에도 불구하고 속도가 느리다는 평을 받았습니다. 초기 자바 버추얼 머신은 인터프리트 방식이었기 때문이기 때문에 아무래도 직접 시스템 코드로 실행되는 것보다는 느릴 수 밖에 없었습니다. 하지만 최근에는 JIT (Just In Time) 컴파일러를 통해서 런타임에서 자바 바이트 코드를 네이티브 코드로 컴파일한 후 그 실행 코드를 실행하는 방식으로 전환되면 속도 문제가 많이 해결되고 있습니다.

자바의 바이트 코드는 일종의 소스 역할을 하며, 실행될 때는 JITs를 통해 먼저 머신에 최적화된 실행코드로 컴파일한 후 그 코드를 실행하는 흐름입니다. 컴파일러의 성능이 발전함에 따라, 속도도 점점 시스템에 최적화해서 작성하는 어플리케이션 수준에 근접해가고 있습니다.

Write Once, Run Anywhere

이 말이 단순히 여러 환경에서 실행만 한다는 얘기는 아닙니다. JIT 컴파일러가 똑똑하다며 각각 RISC, CISC, 메모리가 빠른 시스템, 레지스터가 많은 시스템, 병렬처리가 빠른 시스템에 최적화된 실행 코드를 생성해 줄것이고, 동일한 바이트 코드로 각 시스템에 최적되어 실행된다는 얘기가 됩니다.
자바로 만든 3차원 그래픽 렌더링 프로그램이 있다면, 회사에 렌더링 걸어놓고, 전철로 이동하면서도 포켓윈도우기반의 pda나 임베디드 리눅스기반의 핸드폰으로도 렌더링을 할 수 있을 것입니다. (아마 몇년 뒤에는 지금 작성한 소프트웨어들이 64비트 병렬 CPU에서 최적화 되어 돌아가고 있겠죠.)

언제가 될지는 모르겠습니다만 기반만 잡힌다면 게임쪽에서도 많이 퍼지지 않을 까 예상합니다. (이상적이지만 ps2, xbox, gamecube, pc 에 똑똑한 JVM이 탑재된다면 모든 플랫폼에서 실행되는 게임 패키지가 일반화 될지도...)

지금부터 자바 공부하자는 얘기는 아니고, 영 맘에 안들어 하시는 분이라면 괜한 고정관념은 버리자고 꺼내본 얘기입니다. 자바를 대안으로 이해하시는 분들은 거부감을 많이 가지시는 데, 자바가 활성화되어도 지금의 언어나 환경들은 여전히 존재하고 서로 발전할 것이기 때문에 크게 거부감 가질 필요는 없을 거 같습니다. (어차피 임베디드 자바 머신이 아니라면 자바 자체로는 의미가 없죠.)

댓글을 달아 주세요

  1. evans00 2004/01/06 21:50  댓글주소  수정/삭제  댓글쓰기

    저도 자바를 예전에 스크립트로 썼었습니다만..그 당시에는 왜 인지 상속 클래스는 제대로 상위 클래스의 메소드가 호출 안되더군요. 그리고 넘 느리다는 느낌이라..결국 다른걸로 바꿨습니다;

  2. the horse trader 2007/10/18 08:01  댓글주소  수정/삭제  댓글쓰기

    많은 감사 우수한 위치! 나는 너의 웹사이트를 사랑한다!

  3. barefoot ladies of wrestling 2008/05/23 04:16  댓글주소  수정/삭제  댓글쓰기

    나는 배웠다 매우…

  4. bondage clothes 2008/05/23 04:43  댓글주소  수정/삭제  댓글쓰기

    나는 배웠다 매우…

  5. sexy wrestling 2008/05/23 05:17  댓글주소  수정/삭제  댓글쓰기

    나는 배웠다 매우…

  6. young girls sexy dancing 2008/05/23 05:48  댓글주소  수정/삭제  댓글쓰기

    나의 너의 친구는 위치의 현재 팬이 되었다!

  7. albany escorts 2008/05/23 06:59  댓글주소  수정/삭제  댓글쓰기

    그런 위치를 경이롭 위해 많게의 감사!

  8. blaster creative driver sound 2008/05/23 07:02  댓글주소  수정/삭제  댓글쓰기

    친구는 너의 현재 위치의 팬이 되었다!

  9. sexy girls pussy 2008/05/23 07:43  댓글주소  수정/삭제  댓글쓰기

    좋은 영역! 걸출한 영역!

  10. defloration porn 2008/05/24 00:08  댓글주소  수정/삭제  댓글쓰기

    좋은 위치는 찾아본 그것 즐겼다!

  11. nude patch for sims 2 2008/05/24 01:47  댓글주소  수정/삭제  댓글쓰기

    중대한 축하!경이롭 위치 위치!

  12. sex offender registry home 2008/05/24 02:01  댓글주소  수정/삭제  댓글쓰기

    나는 배웠다 매우…

  13. transwomen sexual experiences 2008/05/24 03:07  댓글주소  수정/삭제  댓글쓰기

    너는 아주 보는 좋은 위치가 있는다!

  14. a sex chat 2008/05/24 03:25  댓글주소  수정/삭제  댓글쓰기

    유용한 정보. 좋은 디자인.