사용자:Senouis/Xash3D 분석
Xash3D는 미국의 밸브 코퍼레이션의 첫 게임 엔진인 하프라이프 엔진(흔히 GoldSource 엔진으로 알려졌다)과 호환되면서 Open-source, cross-platform을 지향하는 게임 엔진이다. 하프라이프는 게임 소스 코드 공개를 통한 2차 창작 MOD를 장려하였기 때문에 Xash3D 엔진으로 돌아가는 게임이 많다.
현재는 FWGS(Flying With Gauss의 약어라지만 뭔가 Freeware GoldSource의 약어 같기도 하다)이라는 이름의 동인 개발 서클에 의해 관리되고 있다(러시아 쪽 다큐먼트가 거의 공식 영어 도큐먼트 수준으로 자세하고 러시아 쪽에서 인기 있는 모드의 지원이 많아 러시아인들이 주축이 된 팀으로 보인다)
Xash3D 엔진의 최신 소스 코드는 여기에서 확인할 수 있다.
한편 Emscripten 트랜스컴파일러로 javascript 코드로 C/C++ 코드 컴파일을 한 Github 리포지토리가 있다. 링크
Xash3D 개요
- 개발 언어: C/C++
- 지원 플랫폼: 윈도우즈 / 맥 / 리눅스 계통 / iOS / 안드로이드 / Nintendo 3DS
과거에는 Emscripten을 통한 웹 버전으로 컴파일이 되었으나 CMake 대신 Waf로 빌드 스크립트 구성 프로그램을 바꾸는 바람에 지원이 중단되었다. 따라서 Xash3D의 현 버전은 웹에 적용하려면 지나치게 많은 비용이 든다. 그러나 2000년대 게임들을 돌리는 것을 주 목적으로 하기에 언리얼 엔진 / 유니티 엔진에 비해 코드가 간결하다는 점에서 레거시 버전이라도 리버티게임에 가젯 형태로 자바스크립트로 트랜스컴파일된 물건을 포팅하는 것이 의미가 있다.
Xash3D 전체 구조
Xash3D는 크게 filesystem IO를 담당하는 라이브러리, 메인 메뉴 UI 관련 코드가 있는 라이브러리, 핵심 엔진 기능을 담은 라이브러리, 그리고 그래픽스 라이브러리가 있다. 이 중 레거시가 된 웹 버전인 상단의 HTML5 버전 레포지토리는 다음과 같이 javascript 파일이 생성되었다.
- 파일시스템 IO: browserfs.min.js(browserfs 라이브러리의 최소 기능 컴파일 버전)이 대행하여 애셋 압축 파일을 읽는다.
- 메인 메뉴 UI: menu.js
- 게임 엔진 본체: xash.js
- 클라이언트/서버 측에서만 돌아가는 게임 코드: client.js, server.js
그 외에는 게임별 애셋 로드 코드 등이다.
Xash3D의 구동 과정
사실 모든 게임 엔진은 다음 구조로 동작한다.
- 게임 실행 파일이 xash 라이브러리 파일(어떻게 컴파일했는지에 따라 xash.js, xash.dll, ...) 가져온 다음, 클라이언트 측 코드와 서버 측 코드를 가져와 진입점으로 들어간다.
- 특정 플랫폼에서만 작동하는 네이티브 코드의 경우 Client 측에서 Initialize, VidInitf를 호출하고 Server 측에서는 GameDLLInit를 호출한다.
- 게임 로직은 서버 측 코드에 다 적혀 있고, 클라이언트 측은 주로 입력 처리, 네트워크 데이터를 메세지로 받아 처리한 다음 HUD 표시 및 뷰포트와 카메라, 렌더링 및 그에 필요한 간단한 수학 행렬 연산 정도만 한다.
- 서버 측에서는 주로 게임 모드, 네트워크로 전송할 데이터 값, 개발 콘솔 창에서 쓸 수 있는 변수, 사용자로부터 날아온 각종 이벤트(입력, 무기 사용 등)에 대한 콜백, 그리고 각 엔티티별 코드로 구성되어 있다.
- 게임 모드의 경우 CGameRules 클래스에서 파생하고, 네트워크 데이터 전송 값은 REG_USER_MSG 매크로, 콘솔 변수는 GET_CVAR_***나 CVAR_REGISTER 매크로를 사용해 크기와 종류를 결정하고, 이벤트는 EV_HookEvent에 이벤트 콜백 함수를 등록하며, 엔티티별 코드는 CBaseEntity 클래스에서 파생한다.
그래서 사실 CBaseEntity와 CGameRules 클래스 및 그 특성을 상속한 클래스들 정도만 컴파일해도 이론상으로는 서버 측 코드가 작동한다. 다만 그러면 할 수 있는 것이 없어 보통 하프라이프 코드를 가져와 고치는 식으로 게임 제작이 이루어진다.
여기까지는 게임 코드에서 다루는 것이고, 이제 Xash3D 엔진 자체를 다뤄보자.
Xash3D 모듈
wrapper(index.js)
- mod.js를 리버티게임 내에서 정의하면 인식하도록 script 태그를 페이지에 JavaScript로 추가
- 이 경우 client-(게임 이름).js를 클라이언트 상호작용 스크립트(하프라이프 웹 포트의 client.js의 역할)로 가져와야 함
engine(xash.js)
현재 이슈
- 현재 Multiplayer가 작동하지 않음: 아마도 WebSocket 문제로 추정 + 포트 27015을 리플리케이팅 특화 코드를 사용할 용도로 서버에서 개방해야 하나?
- Secure WebSocket Connection 필요: 리플리케이터(replicator.js) 작성 후 microndk/build-emscripten-module.mk에서 WEBSOCKET_URL을 "wss://libertyga.me/xash3d/replicator.js" 아래로 설정하고 테스트할 것
- 위키 사용자 명칭을 가져오지 못함: Console을 다시 활성화하고 playername 확인 필요 - 완료
- 한글 닉네임을 인식하고 출력하지 못함: 유니코드 라이브러리를 같이 컴파일 해야함
- 소스 엔진 애셋을 직접 가져올 수 없음: VTFLib 결합 필요
- VTFLib는 엔비디아가 만든 구형 DXT 라이브러리를 쓰기 때문에 Libsquish를 사용하도록 개조 필요
- 게임패드를 인식하지 못함: 브라우저 Gamepad API 관련 MDN 문서를 참조해 수정
- quit 명령어 제거: 쓸모 없으며 에러만 일으킴
현재 이슈
- Multiplayer 항목 진입시 사용자 명칭을 계속 물어봄: engine에서 인식하는데도 이러면 mainui 내 코드를 고쳐서 뜨지 않게 할 것 - 완료
- Multiplayer 리플리케이터가 완성될 때까지 Main UI에서 Multiplayer 항목 비활성화
추가 모듈
- 리플리케이션만 전문으로 하는 라우팅 서버용 리플리케이터 js 파일(replicator.js)을 제작
- UDP 통신이 기본
- 웹소켓으로 접속시 다음과 같은 통신을 함
- 클라이언트 -> 서버: 라우팅 서버에 접속 시 모드 ID와 서버 ID 값을 저장하고 해당 유저가 서버에 데이터를 보낼 때 해당하는 서버와 통신을 주선함
- 서버 -> 클라이언트: 서버의 통신 요청 시 모드 ID와 서버 ID 값이 같은 유저들을 찾아 전부 리플리케이트하고, 1대1 통신(TCP)의 경우에만 해당 유저를 찾아 통신을 중계
- 위키 사이트 서버에 전용 서버를 설치할 수 없으므로 이런 조치를 취함