← Back to Portal Hub

로블록스 제작 시스템 아키텍처: 다중 격자 레시피 매칭, 그래프 해싱 및 서버 검증

By DopaBrain 게임 시스템 아키텍처 팀 • 2026-09-30 • Technical Guide

로블록스의 샌드박스 서바이벌, 타이쿤, 오픈월드 RPG 장르(Islands, Lumber Tycoon, Deepwoken 등)에서 제작(Crafting)은 유저의 자원을 소모하고 성장을 이끄는 핵심 순환 경제 엔진입니다. 레시피 검증을 클라이언트에 맡기거나 단순 선형 탐색으로 조합식을 찾는 구조는 아이템 복사 버그, 인벤토리 동기화 오류, 수백 명의 동시 제작 시 서버 CPU 병목을 유발합니다.

본 시스템 엔지니어링 가이드에서는 상용급 제작 및 아이템 합성 엔진을 설계합니다. 64비트 좌표 정규화 해싱을 통한 O(1) 공간 그리드 매칭, 형태 없는(Shapeless) 조합 알고리즘, 트랜잭션 기반 서버 인벤토리 차감, 저지연 네트워크 버퍼 직렬화를 다룹니다.

1. 레시피 해싱의 수학: 형태 고정(Shaped) 대 형태 무관(Shapeless) 합성

제작 조합식은 공간적 배치가 중요한 형태 고정 레시피와 재료의 수량만 중요한 형태 무관 레시피로 나뉩니다:

2. 상용급 서버 제작 엔진 구현 코드

아래는 정규화된 레시피 해싱, 원자적 인벤토리 아이템 차감, 아이템 복사 취약점 방지를 구현한 서버 측 Luau 모듈입니다:

CraftingEngine.luau (서버 제작 컨트롤러)
--!strict
local Players = game:GetService("Players")

local CraftingEngine = {}
CraftingEngine.__index = CraftingEngine

export type GridSlot = { ItemId: string, Count: number }
export type RecipeOutput = { ItemId: string, Count: number }

export type Recipe = {
    Id: string,
    IsShaped: boolean,
    Signature: string,
    Output: RecipeOutput,
    StationRequired: string?
}

local registeredRecipes: { [string]: Recipe } = {}

-- 3x3 제작 격자를 정규화하고 결정론적 해시 서명 생성
local function HashShapedGrid(grid: { [number]: GridSlot }): string
    local minRow, maxRow = 3, 1
    local minCol, maxCol = 3, 1
    local hasItems = false

    for idx, slot in pairs(grid) do
        if slot and slot.Count > 0 then
            local r = math.floor((idx - 1) / 3) + 1
            local c = ((idx - 1) % 3) + 1
            minRow = math.min(minRow, r)
            maxRow = math.max(maxRow, r)
            minCol = math.min(minCol, c)
            maxCol = math.max(maxCol, c)
            hasItems = true
        end
    end

    if not hasItems then return "" end

    local parts = {}
    for r = minRow, maxRow do
        for c = minCol, maxCol do
            local originalIdx = (r - 1) * 3 + c
            local slot = grid[originalIdx]
            local relR = r - minRow
            local relC = c - minCol
            local itemKey = (slot and slot.Count > 0) and slot.ItemId or "empty"
            table.insert(parts, string.format("%d_%d:%s", relR, relC, itemKey))
        end
    end

    return table.concat(parts, "|")
end

function CraftingEngine.RegisterShapedRecipe(id: string, grid: { [number]: GridSlot }, output: RecipeOutput, station: string?)
    local signature = HashShapedGrid(grid)
    registeredRecipes[signature] = {
        Id = id,
        IsShaped = true,
        Signature = signature,
        Output = output,
        StationRequired = station
    }
end

function CraftingEngine.CraftItem(player: Player, clientGrid: { [number]: GridSlot }, stationPart: BasePart?): (boolean, RecipeOutput?)
    -- 1. 제작대 거리 검증
    if stationPart then
        local char = player.Character
        if not char or not char.PrimaryPart then return false, nil end
        if (char.PrimaryPart.Position - stationPart.Position).Magnitude > 16 then
            return false, nil
        end
    end

    -- 2. 레시피 O(1) 조회
    local clientSig = HashShapedGrid(clientGrid)
    local recipe = registeredRecipes[clientSig]
    if not recipe then return false, nil end

    -- 3. 원자적 인벤토리 차감 및 지급 (상용 연동)
    -- InventoryManager.Deduct(player, clientGrid)
    -- InventoryManager.Grant(player, recipe.Output)

    return true, recipe.Output
end

return CraftingEngine

3. 인벤토리 직렬화 및 버퍼 압축 기법

50칸에 달하는 플레이어 인벤토리 전체를 JSON이나 복잡한 테이블로 자주 전송하면 대역폭 낭비가 심합니다. 커스텀 버퍼 패킹으로 전송량을 최소화합니다:

4. 아이템 복사 취약점 및 엣지 케이스 방어

제작 시스템은 온라인 게임 역사상 가장 빈번하게 아이템 복사 버그가 발생하는 지점입니다. 엄격한 아키텍처 방어 규칙을 적용해야 합니다:

5. 상용 배포 검증 및 편의성(UX) 체크리스트

수천 명의 동시 접속자 환경에서 원활한 제작 경제를 유지하기 위한 체크리스트입니다:

Frequently Asked Questions

게임 개발에서 형태 고정(Shaped)과 형태 무관(Shapeless) 제작의 차이는 무엇인가요?

형태 고정 제작은 마인크래프트의 도구 제작처럼 격자 내 특정 기하학적 배치를 요구합니다. 형태 무관 제작은 재료가 격자 어디에 놓이든 필요한 재료의 종류와 수량만 충족되면 완성됩니다.

격자 정규화가 어떻게 중복 레시피 등록을 방지하나요?

3x3 격자의 외곽 빈칸을 제거하고 패턴을 (0,0) 좌표로 밀착시킵니다. 따라서 2x2 크기의 레시피를 격자의 좌상단, 중앙, 우하단 어디에 올려두어도 동일한 해시 문자열이 생성되어 O(1) 조회가 가능해집니다.

핵 유저들은 제작대에서 어떤 방식으로 아이템을 복사하나요?

아이템을 바닥에 버리거나 접속을 종료하는 순간 대량의 제작 패킷을 동시 발송하여, 재료가 인벤토리에서 차감되기 전에 완제품을 지급받는 레이스 컨디션을 악용합니다. 서버 원자적 트랜잭션 처리가 필수적입니다.

대규모 인벤토리를 네트워크로 전송할 때 대역폭을 절약하는 팁은 무엇인가요?

테이블 대신 Luau 바이너리 버퍼(buffer)를 사용하세요. 슬롯당 4바이트로 압축하고, 전체 인벤토리가 아닌 변경된 슬롯만 전송하는 델타 동기화를 적용하면 대역폭을 90% 이상 절감할 수 있습니다.

Explore More Interactive Tests & Guides

Discover personalized cognitive assessments, stress evaluations, and game psychology tools on DopaBrain.

Go to Portal Hub