Reddit

We ported the original Doom to SQL

오리지널 둠을 SQL로 포팅했습니다

CedarDB 개발자가 1993년판 Doom의 게임 로직과 렌더러를 SQL로 구현했습니다. 게임은 데이터베이스 안에서 35Hz로 작동하고, Ryzen 노트북에서 장면에 따라 초당 35~60프레임을 그립니다. 글은 BSP 렌더링과 SQL 성능, 트랜잭션을 활용한 멀티플레이 구현 과정을 설명합니다.

AI 요약

CedarDB 개발자가 1993년판 Doom의 게임 로직과 렌더러를 데이터베이스 안에 구현한 SQLDoom을 공개했습니다. Python은 입력 처리와 시간 관리, 데이터베이스가 만든 비트맵 표시만 담당합니다. 게임 로직은 원작과 같은 초당 35틱으로 실행하며, 렌더러는 게임 상태를 읽어 320×200 해상도의 프레임을 만듭니다. 원작 첫 에피소드의 데스매치도 최대 4명이 함께 즐길 수 있습니다.

게임 로직과 상태 관리

앞서 만든 DOOMQL은 광선 추적(ray casting) 방식이라 Wolfenstein 3D에 가까웠습니다. 이번 구현은 원작처럼 BSP 트리로 공간을 나누고, 벽과 적, 바닥 높이가 달라지는 Doom의 구조를 따릅니다. 저자는 실제 게임처럼 보이는 것뿐 아니라 움직임과 적의 행동까지 원작에 가깝게 만드는 것을 목표로 삼았습니다.

게임 데이터는 WAD 파일에서 데이터베이스 테이블로 옮깁니다. 정점(vertex), 선분(linedef), 구역(sector), 사물(thing) 같은 요소가 관계형 데이터로 들어가며, Doom 1 전체를 적재하는 데 노트북에서 약 18초가 걸립니다. 게임 로직은 약 5,900줄의 SQL로 작성했습니다. 적의 상태 전이, 이동, 공격, 아이템 획득, 무기 동작 등을 여러 SQL 함수와 갱신문으로 처리합니다.

틱마다 처리할 작업은 CedarDB의 스크립팅 언어인 cedarscript로 순서를 정합니다. 원작의 게임 시계에 맞춰 35Hz로 실행하고, 각 틱에 쓸 수 있는 시간은 약 28.6ms입니다. 적 46마리가 문을 향해 몰려드는 가장 느린 틱도 10.45ms였고, 적 6마리가 깨어 있는 보통 상황에서는 평균 2.15ms가 걸렸습니다. 데이터베이스가 행 단위로 엔티티를 하나씩 도는 대신 조건에 맞는 행을 한꺼번에 갱신하는 방식은 저자가 ECS(Entity Component System)를 이해하는 데에도 도움이 됐습니다. 엔티티 구성 요소는 테이블로, 시스템은 조인과 갱신문으로 표현합니다.

BSP와 프레임 렌더링

렌더러는 게임 상태와 플레이어 위치를 입력으로 받아 픽셀마다 RGB 값을 돌려주는 SQL 쿼리입니다. 구현은 주석을 빼고 약 1,300줄이며, 89개의 CTE(Common Table Expression)로 구성됩니다. 원작 Doom은 BSP 트리를 순회해 가까운 구역부터 그려 먼 물체를 건너뜁니다. SQLDoom은 로딩 단계에서 각 BSP 경로를 미리 저장합니다. 카메라가 각 분기에서 앞쪽을 보는지 뒤쪽을 보는지를 비트로 인코딩하고, 정렬해 구역을 앞에서 뒤 순서로 나열합니다. 이렇게 재귀 순회를 정렬 작업으로 바꿉니다. 가장 깊은 원작 맵도 BSP 깊이가 32라 40비트 키에 들어갑니다.

벽은 화면 열과 픽셀 행으로 펼쳐 그립니다. 바닥과 천장은 원작의 가변 배열을 직접 갱신하는 대신, 각 벽 구간이 남긴 화면 영역을 윈도 함수로 계산합니다. 스프라이트와 벽, 바닥에서 같은 픽셀 후보가 여럿 나오면 깊이와 표면 우선순위를 하나의 정수 키에 묶고, 픽셀별로 가장 작은 값을 골라 최종 색을 정합니다. 이 깊이 판정은 프레임에서 가장 비싼 부분으로 평균 8.2ms를 차지합니다. 바닥과 천장 렌더링은 보통 약 3ms, 벽 렌더링은 평균 1.7ms입니다. Ryzen 7 PRO 7840U 노트북에서 보통 초당 약 60프레임을 내고, 복잡한 장면에서는 35프레임까지 내려갑니다.

데이터베이스와 멀티플레이

무기 능력치와 애니메이션 상태도 테이블에 저장합니다. 산탄총의 탄환 수나 피해량을 행으로 바꾸면 게임 데이터를 조회하고 수정하기 쉽습니다. 예를 들어 산탄총은 한 발에 산탄 7개를 발사하며 각 산탄은 3d5 피해를 줍니다. 저자는 데이터베이스 제약 조건으로 수정 시 데이터 유효성을 검사하고, 변경 사항을 다시 불러오지 않고 적용할 수 있다고 설명합니다.

멀티플레이에서는 데이터베이스의 트랜잭션과 권한 기능을 활용합니다. 게임 틱을 하나의 트랜잭션으로 처리해 플레이어가 틱 처리 전이나 커밋 후의 일관된 상태를 읽도록 합니다. 플레이어 계정은 내부 테이블에 직접 접근하지 않고 제한된 API 함수만 호출합니다. 입력값도 함수 안에서 허용 범위로 제한합니다. 게임은 최대 4인 데스매치를 지원하며, 저자는 클라이언트당 코어 3개로 안정적인 35FPS를 유지했다고 보고합니다.

CedarDB는 쿼리를 LLVM IR로 내린 뒤 기계어로 컴파일하는 데이터베이스입니다. 글은 오브젝트 이동 로직의 생성 코드를 원작 C와 비교합니다. C 코드는 48개 명령어, SQLDoom은 117개 명령어를 사용했고, SQL 쪽에서 추가된 명령어 42개는 결과를 테이블에 다시 저장하는 작업에 쓰였습니다. 저자는 데이터베이스 쿼리 최적화와 컴파일 과정을 거친 코드가 원본 C와 비교해 예상보다 가까웠다고 설명합니다. 프로젝트는 CedarDB Community Edition과 Python, Doom IWAD로 직접 실행할 수 있습니다.

Reddit 반응

  • @u/Hip-Death-Goddess — Doom과 SQL이라니, 자연스러운 조합이네요. 하나는 희망이 죽고 가장 강한 의지도 끝없이 몰려드는 이름 모를 고통스러운 괴물들에게 무너지는 악마의 지옥이고, 다른 하나는 id Software의 게임이니까요.
    • @u/Amlethus — 더 나쁠 수도 있죠. SharePoint일 수도 있으니까요.
    • @u/bulbousgrandpa — 지난 직장에서 SQL 업무에 더해 SharePoint 관리자까지 맡게 된 뒤 아직 회복하지 못했습니다.
  • @u/EliteACEz — 부끄럽지도 않으신가요...
    • @u/Yaruxi — 할 수 있는지 알아보려다가, 그래야 하는지는 생각해보지 않았습니다...
  • @u/ketralnis — 우리는 매일 신의 빛에서 더 멀어지고 있습니다.
    • @u/MarkIsARedditAddict — Doom에서 점점 더 깊은 지옥으로 들어가며 악마와 싸우고 있으니까요.
  • @u/Ok-Bit8726 — CedarDB는 처음 들어봤지만 정말 인상적입니다. 바이트코드 비교도 꽤 흥미로웠습니다.
  • @u/ArtOfWarfare — 이게 표준 SQL이 아니라 특정 SQL 구현에 강하게 묶여 있어 아쉽습니다. 그래도 데이터베이스에서 렌더링하는 건 멋지지만 분명 어리석은 일이네요. RTS 게임에서 렌더링을 뺀 나머지를 데이터베이스로 처리할 수 있을지 궁금해졌습니다.
    • @u/Yaruxi — 맞는 지적입니다. cedarscript의 틱 드라이버를 제외하면 표준 PostgreSQL SQL입니다. 그 부분도 PL/pgSQL로 꽤 쉽게 옮길 수 있지만 CedarDB가 아직 지원하지 않습니다. 게임 로직을 SQL로 표현하는 일이 성능도 좋고 자연스럽고 우아하다고 진지하게 생각합니다.
    • @u/scrdest — SpacetimeDB 쪽에서 한참 전부터 바로 그 주장을 했습니다. ECS 아키텍처가 이미 컬럼형 데이터베이스와 비슷한 방향으로 가고 있으니, SQL을 쓰지 않는 척할 이유가 없다는 논리죠.
  • @u/wasdie639 — 그런데... 왜요?
    • @u/Yaruxi — 솔직히 말하면, 누군가 제 이전 구현에는 BSP 트리가 없다고 해서 고쳐야겠다고 생각했습니다.
  • @u/admalledd — 게임 데이터를 데이터로 관리하는 방식은 일반적인 게임 개발에서도 권장됩니다. 게임 엔진과 게임 데이터를 분리하면 모딩도 쉬워집니다. 게임에 SQL 데이터베이스를 통째로 넣는 건 늘 동의하진 않지만, ECS 같은 데이터 중심 설계에는 유용한 패턴입니다.
  • @u/PanicInTheSkreet — 입력 지연이 조금 크지만, 그래도 꽤 멋지고 플레이할 만합니다.
  • @u/SteelBalls1867 — LLM에 시켜서 만든 거라면 이런 건 멋지지 않습니다.
    • @u/UnexpectedAnanas — 그런데 그렇게 보이진 않는데요.

원문: CedarDB / 번역·요약: Trawling