서버 권한 모델에서 서버는 전체 게임 상태에 대한 단일 진실의 출처이며, 클라이언트는 자신의 입력만 보고하는 것이 신뢰됩니다. 이 아키텍처는 클라이언트가 자신의 위치나 상태를 보고하는 것을 신뢰하지 않기 때문에 플라이 해킹이나 스피드 해킹과 같은 전체적인 치트를 방지하여 공정하고 경쟁적인 게임의 핵심 네트코드 기반이 됩니다.
장점
단순한 서버 소유 시스템에서는 클라이언트가 자신의 입력을 서버에 보내고 서버가 보낸 게임 결과를 표시합니다. 기술적으로는 올바르지만, 이러한 시스템은 모든 플레이어의 행동이 서버로 전송되고 처리된 후 결과가 클라이언트로 다시 전송되어야 하므로 상당한 입력 지연에 직면하게 됩니다. 대부분의 게임, 특히 빠른 게임에서는 이러한 왕복 지연으로 인해 게임 플레이가 느리게 느껴지고 반응이 없으며 플레이할 수 없게 됩니다.
Roblox의 서버 권한 모델에서는 클라이언트가 입력을 서버에 보내는 것 외에도 즉시 예측하여 입력의 효과를 보상합니다. 예를 들어, 플레이어가 키를 누르면 클라이언트는 서버의 응답을 기다리지 않고 마지막으로 알려진 서버 상태보다 몇 프레임 앞서 예측합니다. 이렇게 하면 클라이언트가 입력 동작의 결과를 즉시 표시할 수 있어 네트워크 지연을 효과적으로 숨기고 게임이 반응성이 뛰어나게 느껴집니다.
때때로 클라이언트는 예측을 잘못할 수 있으며 (잘못된 예측) 네트워크 지연으로 인해 클라이언트는 몇 프레임 동안 실수를 했다는 것을 알지 못합니다. 예를 들어:
잘못된 예측이 감지되면 클라이언트는 서버의 권위 있는 상태를 기반으로 예측을 수정해야 합니다. 권위 있는 상태가 클라이언트의 예측 상태와 다르면 클라이언트는 롤백하고 재시뮬레이션해야 합니다. 클라이언트 측 예측, 롤백 및 재시뮬레이션 시스템은 "지연 보상"으로 알려져 있으며 서버 권한 멀티플레이어 게임이 부드럽고 반응성이 뛰어나게 느껴지도록 도와줍니다.
설정
서버 권한 모델은 올바르게 작동하기 위해 특정 다른 엔진 기술이 필요합니다. 탐색기에서 Workspace 객체의 다음 속성 설정을 확인하세요:
- Workspace.AuthorityMode는 Server여야 합니다(이 설정은 자동으로 다음 다섯 가지를 설정합니다).
- Workspace.NextGenerationReplication이 활성화되어야 합니다.
- Workspace.PlayerScriptsUseInputActionSystem이 활성화되어야 합니다.
- Workspace.SignalBehavior는 Deferred여야 합니다.
- Workspace.UseFixedSimulation이 활성화되어야 합니다.
- Workspace.StreamingEnabled이 활성화되어야 합니다.
개념
서버 권한 시스템은 다음과 같은 몇 가지 핵심 개념에서 실행됩니다.
클라이언트 예측
클라이언트 예측을 통해 클라이언트는 마지막으로 알려진 서버 상태보다 몇 프레임 앞서 시뮬레이션하여 플레이어 입력의 효과를 즉시 예측합니다. 이는 입력 지연을 숨기지만, 예측이 나중에 잘못된 것으로 판명될 수 있으며 (클라이언트 잘못된 예측) 따라서 수정이 필요합니다. 클라이언트는 입력이 서버에 의도된 프레임에 도착하도록 마지막으로 알려진 권위 있는 서버 상태보다 충분히 앞서 시뮬레이션하려고 합니다. 클라이언트가 알려진 서버 상태보다 예측할 프레임 수는 클라이언트와 서버 간의 지연에 따라 달라집니다.
클라이언트 잘못된 예측
클라이언트가 서버로부터 권위 있는 상태를 수신하면, 해당 상태를 로컬에서 예측한 역사적 기록과 비교합니다. 클라이언트가 예측한 것과 서버가 실제로 수행한 것 사이에 차이가 있을 때, 이것은 잘못된 예측입니다. 잘못된 예측은 네트워크 지연의 변화, 클라이언트가 예상하지 못한 방식으로 행동하는 다른 플레이어, 특정 논리가 서버에서만 실행되는 경우 등 여러 가지 이유로 발생할 수 있습니다.
권위 있는 상태가 클라이언트의 예측 상태와 다르면 클라이언트는 롤백하고 재시뮬레이션해야 합니다.
롤백 및 재시뮬레이션
클라이언트가 잘못된 예측을 감지하면, 서버의 권위 있는 상태로 재설정한 다음 예측된 프레임으로 점프하기 위해 재시뮬레이션해야 합니다. 네트워크 지연에 따라 클라이언트는 입력이 서버에 의도된 프레임에 도착하도록 마지막으로 알려진 권위 있는 서버 상태보다 충분히 앞서 시뮬레이션하려고 합니다.
요약하자면, 클라이언트는:
- 서버로부터 권위 있는 상태를 수신하고 이를 자신의 예측 상태와 비교합니다.
- 클라이언트의 예측이 잘못된 경우:
- 클라이언트는 서버로부터 수신한 마지막 알려진 권위 있는 상태로 롤백합니다.
- 클라이언트는 권위 있는 상태에서 예측 상태로 재시뮬레이션하며, 모든 로컬 입력을 다시 적용합니다.
구현
네트워크 소유권 및 예측
서버 권한 모델에서는 핵심 게임 플레이 객체를 서버 소유로 유지하면서 일반적으로 서버 소유와 관련된 입력 지연 비용을 발생시키지 않을 수 있습니다. 자동차, 플레이어 캐릭터 또는 기타 게임 플레이에 중요한 객체와 같은 것들은 다른 플레이어와 상호작용할 때에도 서버 소유로 남을 수 있습니다.
기본적으로 Roblox는 로컬 플레이어 Character 근처의 시뮬레이션 접근을 통해 속성을 자동으로 예측하지만, 더 세밀한 제어가 필요하다면 RunService:SetPredictionMode()를 사용하여 인스턴스의 예측을 명시적으로 켜거나 끌 수 있습니다.
시뮬레이션 동기화
서버 권한 모델에서는 클라이언트와 서버가 모두 핵심 시뮬레이션을 실행해야 하며, 클라이언트의 시뮬레이션은 롤백하고 재시뮬레이션할 수 있어야 합니다. 이를 가능하게 하려면, RunService:BindToSimulation()을 통해 바인딩된 함수 내에서 핵심 논리를 작성해야 하며, 이는 클라이언트와 서버 모두에서 초기화된 ModuleScript 내에 있어야 합니다.

재시뮬레이션 중에 Roblox는 BindToSimulation()을 통해 시뮬레이션에 바인딩된 함수를 다시 실행합니다. 플레이어 입력을 처리하고, 동기화된 물리 객체와 상호작용하며, 핵심 게임 상태를 업데이트하는 것은 이러한 바인딩된 함수 내에서 이루어져야 합니다.
바인딩된 시뮬레이션 함수 내에서 애니메이션 속도를 조정하거나 시간에 따라 값을 진동시키는 등 시간 기반 논리를 위해 time()을 사용하세요. Workspace.AuthorityMode가 Enum.AuthorityMode.Server일 때, time()은 클라이언트와 서버 간에 동기화되며 고정 단계 시뮬레이션 시간을 사용합니다. 재시뮬레이션 중에는 권위 있는 프레임으로 되돌아가고 클라이언트가 프레임을 재생할 때 진행되므로 매번 시뮬레이션된 프레임에서 일관된 값을 반환합니다.
ModuleScript 이름이 Simulation인 ReplicatedStorage 내:
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Simulation = {}
Simulation.Initialize = function()
RunService:BindToSimulation(function(deltaTime)
-- 플레이어 입력 읽기
-- 게임 상태 업데이트
end)
end
return Simulation속성을 통한 상태 동기화
Roblox는 예측된 인스턴스의 시뮬레이션 접근이 있는 모든 속성을 자동으로 동기화합니다. 사용자 정의 데이터의 경우, 속성은 예측된 것으로 표시된 인스턴스를 동기화하는 주요 방법입니다. 이러한 인스턴스에서 서버의 진실의 출처와 클라이언트의 예측 간에 속성 값의 불일치가 발생하면 전체 롤백 및 재시뮬레이션이 트리거됩니다.
속성 제한
속성이 복제되기 위해서는 다음 모든 기준을 충족해야 합니다:
- Instance의 처음 64개 속성 중 하나여야 합니다.
- 이름은 최대 50자여야 합니다.
- 문자열 유형 속성의 경우, 값은 최대 50자여야 합니다.
시뮬레이션 접근
엔진 API 참조의 많은 속성과 메서드에는 시뮬레이션 접근 레이블이 포함되어 있습니다. 예를 들어 BasePart.CFrame과 같습니다. 이 레이블이 있는 속성은 서버 권한 시스템에 의해 예측됩니다. 또한, 이 레이블이 있는 속성과 메서드만 RunService:BindToSimulation()으로 바인딩된 함수 내에서 접근할 수 있습니다.
입력 작업
서버 권한 게임에서 클라이언트가 게임 상태에 영향을 미치는 주요 방법은 입력 작업 시스템을 통해 이루어집니다. 이러한 입력은 서버로 전송되며 클라이언트에서 재시뮬레이션 중에 재생됩니다. 따라서 InputActions는 핵심 시뮬레이션에 영향을 미치는 모든 입력에 사용되어야 하며, 처리되기 전에 유효성을 검사해야 합니다.
InputContexts는 엔진이 InputContext에 대한 소유권을 알 수 있도록 Player의 자식이어야 합니다. 한 가지 접근 방식은 ReplicatedStorage 아래의 폴더에 InputContexts를 추가하고 ServerScriptService 아래의 Script를 사용하여 플레이어별로 InputContexts를 복제하는 것입니다:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local InputsFolder = ReplicatedStorage:WaitForChild("Inputs")
local function onPlayerAdded(player)
local clone = InputsFolder:Clone()
clone.Parent = player
end
Players.PlayerAdded:Connect(onPlayerAdded)
for _, player in Players:GetPlayers() do
onPlayerAdded(player)
end이 패턴을 사용하면 클라이언트와 서버 모두에서 RunService:BindToSimulation() 내에서 모든 플레이어의 InputActions를 읽어 동일한 프레임에 대한 동일한 데이터를 수신하고 이전 프레임의 입력을 속성에 기록하여 RunAction 입력 작업이 트리거될 때 캐릭터가 달리도록 할 수 있습니다.
원격 이벤트
원격 이벤트는 클라이언트와 서버 간의 개별 통신을 촉진하기 위해 서버 권한 모델 내에서 여전히 사용할 수 있습니다. 예를 들어, 서버는 원격 이벤트를 사용하여 플레이어가 점수를 얻거나 물체를 집는 것에 대한 데이터를 방송할 수 있으며, 클라이언트는 버튼 누르기나 3D 세계에서 물체를 탭하는 것과 같은 입력을 서버에 보내기 위한 대체 API로 원격 이벤트를 사용할 수 있습니다.
애니메이션, 사운드 및 효과
클라이언트 측 효과인 애니메이션 및 사운드는 클라이언트 시뮬레이션이 권위 있는 서버 상태의 예측에 불과하다는 것을 염두에 두고 작성해야 합니다. BindToSimulation()은 바인딩된 함수 내에서 호출할 수 있는 속성과 메서드를 제한하여 동기화된 시뮬레이션 상태에만 작성하도록 안내합니다. 이 시뮬레이션의 결과를 표시하고 효과 및 사운드를 트리거하는 등의 작업은 시뮬레이션의 결과를 읽고 원하는 효과를 트리거하는 RenderStepped에 연결된 별도의 함수에서 수행해야 합니다.
예측된 시뮬레이션을 렌더링하는 것에 대한 추가 지침은 고급 기술 가이드에서 다룹니다.
예제 프로젝트
이 문서 외에도 다음 템플릿이 시작하는 데 도움이 될 수 있습니다:


