Network 개요
VIVEN 의 네트워크 동기화는 VObject · View · RPC · Room 프로퍼티 4가지 축으로 구성됩니다. 각 개념과 사용 예시, 소유권 모델을 한번에 정리합니다.
VIVEN 은 다음 네 가지 방법으로 네트워크 동기화를 수행합니다.
- VObject + View — 지속적인 데이터 동기화
- RPC — 단방향 이벤트성 동기화
- Room 프로퍼티 — 방 단위 영속 데이터
이 문서는 각 개념과 소유권(Ownership) 모델을 정리합니다.
VObject
VObject 컴포넌트는 오브젝트를 서버와 동기화하는 기본 단위입니다.
- 서로 다른 클라이언트에 존재하는 VObject 들은 동일한
NetworkID를 가집니다. - 서버는
NetworkID를 기반으로 개체를 식별하고 상태를 동기화합니다. - RPC 호출, 상호작용, View 동기화 등 모든 네트워크 작업은 VObject 를 통해 이루어집니다.
서버 연결이 끊어지는 경우
다음 상황에서 VObject 는 서버와 연결이 끊어지며, 상호작용을 수행할 수 없습니다.
- 네트워크 오류로 인한 연결 해제
- 중복된 Network ID 가 동일 공간에 존재
- 유효하지 않거나 서버에 등록되지 않은 Network ID
VMap 빌드 과정에서는 NetworkID 중복을 검증하지 않습니다. 빌드 후 "Network ID가
이미 존재한다"는 에러가 발생할 수 있으니, VObject 추가 시 ID가 중복되지 않는지
직접 확인하세요. 또한 런타임에 GameObject.Instantiate 로 VObject 를 동적
생성하는 기능은 현재 제공되지 않습니다.
소유권 (Ownership)
- 모든 VObject 는 한 명의 소유자를 가지며, 두 명 이상이 동시에 소유할 수 없습니다.
- 소유권은 서버에서만 관리됩니다. 클라이언트가 임의로 변경할 수 없습니다.
- 상호작용, 방 입장/퇴장 등에 따라 자동으로 변경됩니다.
- 방에 아무도 없을 경우 VObject 는 소유권이 존재하지 않을 수 있습니다.
여기서 말하는 "소유"는 네트워크 객체의 소유권을 의미합니다. 게임 내 아이템 인벤토리와는 다른 개념입니다.
VObject 주요 Field
| 필드 | 설명 |
|---|---|
displayName | 오브젝트의 표시 이름 |
objectId | 동기화 식별자. 컴포넌트 부착 시 자동 생성 |
objectSyncType | Continuous (매 틱 동기화) 또는 Manual (지정 타이밍만) |
contentType | 오브젝트의 Content Type |
View 컴포넌트
View 컴포넌트는 Unity 컴포넌트를 네트워크와 연결합니다. 하나의 VObject 에 여러 View 를 추가할 수 있습니다.
View 는 VObject 의 소유권에 따라 동작이 달라집니다.
IsMine == true— 현재 로컬 상태를 서버로 송신IsMine == false— 서버에서 받은 데이터를 로컬 컴포넌트에 적용
예를 들어 TransformView 는:
- 내가 소유자면 → 내 Transform 을 서버로 보내고
- 내가 소유자가 아니면 → 서버에서 받은 Transform 으로 업데이트
이를 통해 다른 사용자가 소유한 오브젝트도 자연스럽게 내 화면에서 움직이는 것처럼 보입니다.
제공되는 View
TransformView— 위치·회전·스케일 동기화RigidbodyView— 물리 상태 동기화Viven Grabbable Rigid View— GrabbableModule 전용 동기화VivenCustomSyncView— 커스텀 데이터를 직접 설계해서 동기화 (Viven Script 에서 사용)
상세 API 는 VivenCustomSyncView Reference 를 참고하세요.
RPC (Remote Procedure Call)
다른 유저의 VObject 에서 특정 함수를 원격으로 호출하는 기능입니다. View 와 달리 연속 동기화가 아닌 단방향 이벤트성 동기화입니다.
RPC 를 사용하려면 대상 오브젝트에 VivenCustomSyncView 가 붙어 있어야 합니다.
SendRPC — 모두에게 또는 나를 제외한 모두에게
-- 나를 포함한 모든 방 유저에게 전달
function sendToAll()
local opt = RPCSendOption.All
-- parameters: (메소드 이름, RPC option, 인자 테이블)
SyncView:SendRPC("onBroadcast", opt, nil)
end
function onBroadcast()
-- 모든 유저가 실행
end
-- 나를 제외한 모두에게 전달
function sendToOthers()
local opt = RPCSendOption.Others
local args = { 9, 1 }
SyncView:SendRPC("onOthers", opt, args)
end
function onOthers(a, b)
-- 나를 제외한 유저가 실행
-- args = {9, 1} 이었으므로 a = 9, b = 1
end
SendTargetRPC — 특정 유저에게만
function sendToTarget()
local players = {}
players[1] = Network:GetRoomUserId("targetPlayerNickname")
SyncView:SendTargetRPC("onTarget", players, nil)
end
function onTarget()
-- 닉네임이 "targetPlayerNickname" 인 유저만 실행
end
RPC 로 실행할 함수는 overload 하지 않아야 합니다. Lua 함수는 매개변수 정보가 런타임에 보이지 않아 RPC 는 함수 이름으로만 대상 함수를 찾기 때문입니다. 오버로드는 의도치 않은 동작을 유발합니다.
Room 프로퍼티
방마다 존재하는 key-value 테이블입니다. VObject 단위가 아닌 방 단위로 동기화되며 서버에 저장됩니다.
- 라이프사이클은 방과 동일합니다. 방이 생성될 때 정의되고, 방이 삭제될 때 함께 삭제됩니다.
- 플레이어가 맵에 없어도 유지됩니다.
- 리더보드, 방 진행도 저장 등 방 내에서 영구적으로 남아야 하는 데이터에 적합합니다.
사용 예
-- 값 설정
self.setRoomProp("score", 42)
-- 값 요청 (비동기)
self.getRoomProp("score")
-- 수신 콜백
function onGetRoomProp()
-- Room 프로퍼티 수신 시 호출
end
Room 프로퍼티는 데이터 무결성을 보장하지 않습니다. 네트워크 상태에 따라 지연되거나 누락될 수 있으며, 여러 클라이언트에서 동시에 수정하면 데이터가 덮어씌워질 수 있습니다. 설정 완료 여부를 반드시 확인하고 사용하세요.
무엇을 언제 쓸까?
| 상황 | 추천 방식 |
|---|---|
| 물체의 위치·회전·물리 상태 지속 동기화 | View (TransformView, RigidbodyView 등) |
| 커스텀 필드 지속 동기화 | VivenCustomSyncView + Viven Script |
| "버튼을 눌렀다" 같은 1회성 이벤트 | RPC |
| 방 전체 점수, 진행도 | Room 프로퍼티 |
| 플레이어가 퇴장해도 남아야 하는 데이터 | Room 프로퍼티 |
다음 단계
- 상세 API: VivenCustomSyncView
- Interaction 개요 — Grabbable 이 네트워크 동기화와 어떻게 맞물리는지