· 14 min read

OFF — 오픈 월드 게임 서버 프레임워크를 만들고 있다

엔진 독립적인 분산 오픈 월드 게임 서버 프레임워크, OFF(Open Field Framework) 소개

엔진 독립적인 분산 오픈 월드 게임 서버 프레임워크, OFF(Open Field Framework) 소개

OFF — 무한히 확장되는 분산 게임 월드

왜 만들게 되었나

Unity에서 오픈 월드를 만들어본 사람이라면 알 것이다. 넓은 월드, 많은 플레이어, 실시간 동기화 — 이 셋을 동시에 달성하는 순간 엔진이 발목을 잡기 시작한다.

처음에는 Unity DOTS 기반으로 오픈 월드 프레임워크를 구상했다. DOTS의 데이터 지향 설계는 성능 면에서 매력적이었지만, 프레임워크가 커질수록 엔진 종속성이 문제가 됐다. 서버 사이드 로직이 Unity Editor와 렌더링 파이프라인에 묶여 있는 게 점점 부자연스러워졌다. 클라이언트와 서버가 같은 엔진 위에 있어야 할 이유가 있나?

결심했다. 엔진에서 독립적인 .NET 기반 서버 프레임워크로 방향을 바꾸자.

그렇게 OFF(Open Field Framework)가 시작됐다.

이걸로 뭘 할 수 있나

“오픈 월드 서버 프레임워크”라고 하면 와닿지 않을 수 있다. 구체적으로 OFF 위에서 어떤 것들이 가능한지 먼저 이야기하겠다.

끝이 없는 월드. OFF의 좌표계는 BigInteger 기반이다. 이론상 무한하다. 대륙 하나가 10km×10km이고, 대륙 좌표가 무한 정밀도 정수이므로, 서버를 추가하는 만큼 월드가 확장된다. “맵 경계”라는 개념 자체가 없다.

서버를 넘나드는 엔티티. 플레이어가 대륙 경계를 넘으면 엔티티 상태가 자동으로 다음 서버로 이전된다. 좀비가 플레이어를 쫓아 서버를 넘고, 생태계의 동물이 대륙 사이를 이동한다. ZombieSurvival 데모에서 이미 동작하고 있다.

분산 복셀 월드. VoxelWorld 데모는 Minecraft 같은 블록 월드를 여러 서버에 분산시킨다. 각 서버가 자기 영역의 청크를 관리하고, 경계에서는 자동으로 동기화한다. JavaScript로 지형 생성 로직을 런타임에 바꿀 수 있고, 자연어로 AI에게 구조물 생성을 요청할 수도 있다.

대규모 시뮬레이션. EcoSystem 데모는 풀→초식동물→육식동물의 먹이사슬을 시뮬레이션한다. 수천 개의 AI 에이전트가 번식하고, 죽고, 이동한다. 서버 하나의 한계를 넘어서면 옆 대륙으로 확장하면 된다.

엔진을 가리지 않는다. 서버는 순수 .NET이고, 클라이언트 프로토콜은 TCP(MemoryPack)와 SignalR을 지원한다. Unity 클라이언트, 웹 브라우저 대시보드, 모니터링 툴 — 전부 같은 서버에 붙는다. 지금 Blazor 웹 대시보드에서 Canvas 2D와 Three.js로 월드를 실시간 모니터링하고 있다.

결국 OFF가 지향하는 건 “서버를 몇 대 띄우든, 하나의 심리스 월드처럼 동작하는 프레임워크”다.

OFF가 풀려는 문제

float 정밀도 한계

게임에서 위치를 표현하는 float는 약 2^24(16,777,216) 유닛 이상부터 정밀도가 급격히 떨어진다. 오픈 월드에서 원점으로부터 수십 km만 떨어져도 오브젝트가 떨리고, 물리 연산이 깨진다. 대부분의 게임이 “충분히 넓은 하나의 맵”으로 타협하지만, 진짜 무한한 월드를 원한다면 근본적인 해결이 필요하다.

단일 서버 한계

하나의 서버 프로세스가 감당할 수 있는 동시접속자 수에는 물리적 한계가 있다. 수천 명이 같은 월드에서 플레이하려면 월드를 분할하고, 서버 간 엔티티를 이동시키고, 경계 영역의 동기화를 처리해야 한다.

엔진 종속

Unity로 만들면 Unity 클라이언트만, Unreal로 만들면 Unreal만. 서버 프레임워크가 특정 엔진에 종속되면 클라이언트 선택지가 제한된다. 웹 클라이언트도 붙이고 싶고, 모니터링 대시보드도 만들고 싶은데 전부 엔진 안에서 해야 한다면?

핵심 설계

무한 좌표계

OFF의 좌표계는 3단계 계층 구조다.

무한 좌표계 — 3단계 계층 구조

가장 상위 계층인 BigInteger2는 .NET의 System.Numerics.BigInteger를 사용해 무한 정밀도의 대륙 인덱스를 표현한다. 대륙 안에서는 정수 기반 Coordinate로 섹터를 식별하고, 섹터 안에서는 Vector3로 로컬 위치를 표현한다.

핵심은 float를 섹터 내부의 상대 위치에만 사용한다는 점이다. 그 위의 계층은 모두 정수이기 때문에 정밀도 문제가 구조적으로 발생하지 않는다.

섹터 스트리밍

플레이어가 이동하면 주변 섹터를 동적으로 로드하고, 멀어지면 언로드한다. ISectorSource 인터페이스를 통해 섹터 데이터의 출처를 추상화했다 — 파일에서 읽어올 수도, 프로시저럴 생성을 할 수도, 원격 서버에서 받아올 수도 있다.

분산 서버 클러스터

각 서버 인스턴스는 하나의 대륙을 담당한다. 인접 대륙(|distX| < 2 && |distY| < 2)을 자동 탐지해서 클러스터를 구성하고, 플레이어가 대륙 경계를 넘으면 크로스서버 엔티티 전송이 일어난다. 엔티티 상태를 직렬화해서 대상 서버로 보내고, 클라이언트는 새 서버에 재연결한다.

분산 서버 클러스터 — 대륙 그리드

Zone 시스템

하나의 대륙 안에서 엔티티의 위치에 따라 Zone이 결정된다. 대륙 중심으로부터의 거리(Chebyshev, 정사각형 기준)로 분류한다.

Zone 시스템 — 하나의 대륙 내부 구조

  • Green (70%): 이 서버가 완전한 소유권을 가진다. 인접 서버에 아무것도 전송하지 않는다.
  • PreGray (60~70%): 아직 Green이지만 경계에 가까워지고 있다. 인접 서버에 고스트(읽기 전용 복제본)를 미리 생성해서, Gray 진입 시 “갑자기 엔티티가 나타나는” 현상을 방지한다.
  • Gray (70~110%): 이 서버와 인접 서버의 영역이 겹치는 구간이다. 인접 서버에 고스트가 존재하고, 매 프레임 동기화된다. 8방향(N, NE, E, SE, S, SW, W, NW) 중 어느 이웃에 해당하는지도 추적한다.
  • Red (110%+): 엔티티가 사실상 인접 서버의 영역에 진입했다. 소유권 이전(TransferObject)이 발생하고, 인접 서버가 ACK를 보내면 원본이 삭제된다.

경계에서의 깜빡임을 방지하기 위해 5% 히스테리시스를 적용한다. Gray에서 Green으로 돌아가려면 70%가 아닌 65%까지 들어와야 한다.

AoI (Area of Interest)

5,000개의 엔티티가 있는 월드에서 50명의 클라이언트 각각에게 전체 상태를 브로드캐스트하면 네트워크가 터진다. AoI는 각 클라이언트에게 보이는 엔티티만 보내서 트래픽을 극적으로 줄인다.

OFF의 AoI는 Box2D DynamicTree로 공간 인덱싱을 한다. 매 프레임마다 클라이언트의 중심 위치에서 반경 내 엔티티를 쿼리하고, 이전 프레임의 visible set과 비교해 Spawn/Despawn 이벤트를 합성한다. 히스테리시스 마진을 두어 경계에서의 깜빡임도 방지한다.

벤치마크 결과 5,000 엔티티/50 클라이언트 기준 ~99% 메시지 감소를 달성했다.

아키텍처

OFF 아키텍처 — 3-Layer 구조

Layer 3 — Games 위에 Layer 2 — Simulation Runtime (Arch ECS, Zone, AoI 등), 그 아래 Layer 1 — Framework Core (순수 .NET, 엔진 의존성 없음)가 쌓여 있다.

Layer 1은 순수 .NET이다. 엔진 의존성이 없다. Layer 2는 Arch ECS 기반 시뮬레이션 런타임이고, Layer 3에서 실제 게임을 만든다.

기술 스택

영역기술
언어/런타임C#, .NET 10
ECSArch ECS
TCP 네트워킹SuperSocket + MemoryPack
서버-서버 통신gRPC
웹 클라이언트SignalR + Blazor
공간 인덱싱Box2D DynamicTree
게임 클라이언트Unity 6 (DOTS)
스크립팅Jint (JavaScript)
테스트NUnit, BenchmarkDotNet, Playwright

현재 상태

v0.5.0 — Core Stabilization 완료. 30개 프로젝트, ~2,000개 테스트(유닛/통합 1,992 + E2E 91).

데모

데모설명하이라이트
ZombieSurvivalWASD 조작, 감염/데미지, 크로스서버 좀비 추적멀티서버 간 엔티티 추적
EcoSystem풀 → 초식동물 → 육식동물 먹이사슬동적 AI 개체군 시뮬레이션
ParticleSwarmBoid 군집 알고리즘대규모 에이전트 동기화
GameOfLife콘웨이 생명 게임분산 그리드 시뮬레이션
VoxelWorld1024×1024×64 복셀 월드, JS 스크립팅, AI 구조물 생성~67M 복셀, RLE 압축(85MB→3.5MB), LOD 렌더링

VoxelWorld가 현재 가장 발전된 데모다. Jint 기반 JavaScript 스크립트 엔진으로 런타임에 월드를 조작할 수 있고, 최근에는 LOD 렌더링 최적화로 카메라 이동 중 FPS를 3배 향상시켰다.

모니터링은 Blazor WebDashboard로 한다. Canvas 2D로 월드 맵을 실시간 렌더링하고, Three.js로 3D 뷰를 제공한다.

앞으로의 연재 계획

이 글을 시작으로 OFF의 핵심 기술들을 하나씩 풀어갈 예정이다. 순서는 정해져 있지 않고, 작업 흐름에 따라 자유롭게 쓴다.

  • 무한 좌표계: BigInteger2의 설계와 구현
  • 섹터 기반 월드 스트리밍
  • AoI 시스템: Box2D DynamicTree로 대역폭 절감하기
  • 크로스서버 엔티티 전송과 분산 아키텍처
  • Arch ECS로 엔진 독립 시뮬레이션 만들기
  • 네트워킹: SuperSocket + MemoryPack + gRPC
  • Real-Time Netcode: Client Prediction과 Server Reconciliation
  • Grid Streaming: 청크 기반 월드 데이터 압축과 전송
  • VoxelWorld 개발기
  • AI In-World Build: 자연어로 구조물 생성하기
  • Blazor 웹 대시보드

각 글이 올라오면 여기에 링크를 업데이트할 예정이다.

Back to Blog

Related Posts

View All Posts »