Photon Fusion 2
Photon Fusion 2
메모
NetworkRunner
- 포톤 매니저
- 포톤과 관련된 설정, 조작을 하기 위한
- INetworkRunnerCallbacks
- 포톤 이벤트를 받기 위한 인터페이스, 매개변수에 runner가 들어감
- runner.Spawn (네트워크 Instantiate)
- runner.Despawn (네트워크 Destroy)
NetworkObject
- 동기화 되기 위한 모든 오브젝트는 NetworkObject가 달려있어야 함
- 특별한 기능은 없고, 단순히 네트워크 상에서 누군지 구별하는 ID를 제공하는 컴포넌트
NetworkTransform
- Transform을 동기화 시키는 Class
이를 상속 받으면 마찬가지로 Transform을 동기화
- Interpolation
- 네트워크 상의 이유로 움직임이 뚝뚝 끊겨보이는 것을 보간시켜주는
- 때문에 최상위/부모 오브젝트가 아니라, 자식 오브젝트(Mesh, Sprite 등 시각적인 표현)를 타겟으로 지정해줘야 함
NetworkBehaviour
- FixedUpdateNetwork를 사용할 수 있음
FixedUpdateNetwork
- 시뮬레이션 틱,
예측
과실제 연산
, 재예측 등 한 프레임에 여러 번 실행 될 수 있음 - Update, FixedUpdate 대신 사용
- (Update, FixedUpdate는 유니티 이벤트니까 여러 번 실행되면 어색하니까)
GetInput(out 입력 구조체)로 입력을 받아올 수 있음
- Fusion2
- Proxies 더 이상 기본적으로 FixedUpdateNetwork를 실행하지 않음
Runner.SetIsSimulated(Object, true)
로 설정 가능 (Spawned에서 실행하는 게 베스트)
Runner.Spawn
onBeforeSpawned
은 Server/Host에서만 동작하기 때문에, Network 속성을 변경하는 것에 쓸 것
Spawned
if (Object.HasStateAuthority == false) return;
와 함께 쓴다면, VRChat에서 Start-IsMaster 같이 마스터(Host)가 딱 한 번 실행하는 명령 가능- 게임 상태, 오브젝트 상태 초기화
PlayerRef
- 플레이어를 구분 짓는
- NetworkObject Spawn 시, 이 오브젝트의 입력 권한을 누가 가질지 PlayerRef로 설정 가능
- NetworkBehaviour의 FixedUpdateNetwork, GetInput에서 어떤 입력 데이터를 가져올 지
TickTimer
- 처음 생성된 시각 기준 Timer
- TickTimer.CreateFromSeonds(Runner, 시간)
FixedUpdateNetwork에서 timer.Expired(Runner)로 체크하고 Despawn
- Awake는 네트워크랑 동기화 되지않기 때문에 Awake에서 초기화하면 안됨
- 오브젝트 생성 시 콜백 함수로 초기화해야 함 (그래야 처음 생성될 때 동기화)
물리 연산
- Rigidbody, NetworkRigidbody
- 성능 상의 이유로 dll(어셈블리)로
- NetworkTransform 마찬 가지로 Interpolation
- NetworkTransform를 붙이지 않음
- 성능이 안좋아서 사용 자제
입력
- OnInput을 통해 입력을 받음 (INetworkRunnerCallbacks)
- INetworkInput을 상속 받는, 사용자 정의 입력 데이터 구조체를 정의해야 함 (i.e. NetworkInputData)
- OnInput에서 입력 데이터 구조체를 만들어 값을 설정하고,
input.Set(구조체);
로 할당
입력을 받아올 때도 이를 받아와야 함
- 왜 이렇게 하느냐
- 서버가 이동을 시켜야 하기 때문
- 네트워크는 기본적으로 시간 지연이 발생한다
- 한 명이 모든 권한을 가지는 서버가 되고, 클라는 서버에 데이터를 보내 서버가 처리를 하도록 하는데,
- 클라가 공격 버튼을 눌렀다
- 서버에서 승인을 받아야 하는데
- 가는데 2틱, 돌아오는데 2틱 -> 4틱 후에 공격 하는 게 보여짐 (지연)
- 클라이언트 사이드 예측을 사용
- 2틱 정도 걸릴거라 예상하고 2틱 이후 미리 로컬로 공격
- 클라는 이동에 관한 권한은 없고, 입력에 관한 권한만 있음
- 서버가 이동 시킴
- 클라가 이동 시킨 것은 예측
- 서버가 이동을 시켜야 하기 때문
예측
- 예를 들어 총알이나 공
- 모든 이동을 서버로 검증 받으면 뚝뚝 끊겨 보일 것
- 하지만 앞으로 계속해서 갈 것 같음 -> 딜레이 만큼 예측
- 딜레이 이후 서버로부터 이동 데이터가 도착한 이후 다시 또 딜레이 만큼 예측, 반복
- 참고: 예측할 때 마다 FixedUpdateNetwork가 실행, FixedUpdateNetwork를 기반으로 예측
NetworkBool
- 내부적으로 어셈블리 마다 불 바이트 크기가 다르다?
- 통신할 때 바이트 크기가 다르면 문제가 될 수 있어서
- 크기가 같은 것이 보장되도록, NetworkBool
- 다른 데이터는 상관 없음
Network 어트리뷰트
- 프로퍼티 동기화
- StateAuthority 플레이어 기준
- OnChanged = nameof(함수 이름)
- FixedUpdateNetwork는 예측, 실제 연산, 재예측 등 여러 번 호출 될 수 있음
- OnChanged는 프레임 기준으로 변화를 감지
- 한 프레임 사이에 True, False, True로 변화했다면, 한 프레임 사이에 값이 변화하지 않았음으로 OnChanged가 호출되지 않음
VRChat과 마찬가지로, StateAuthority(VRChat에선 Owner)가 아닌 플레이어가 값을 변경하면, 로컬로만 동작하고, 언제든지 StateAuthority(Owner)의 값으로 동기화 될 수 있음
- Fusion 2
- 프로퍼티의 Get/Set을 커스텀 코드로 대신하기 때문에, Get/Set을 기준으로 변화를 감지하면 안되고, 별도의 Setter 구현도 로컬로만 동작함
Spawned
에서ChangeDetector
변수에GetChangeDetector(ChangeDetector.Scoure.SimulationState)
를 할당하고,Render
에서 아래와 같이 변화를 감지
1
2
3
4
5
6
7
8
9
10
11
12
public override void Render()
{
foreach (var change in _changeDetector.DetectChanges(this))
{
switch (change)
{
case nameof(변수):
// 변화 시 수행할 명령
break;
}
}
}
- 이러한 동작은 여러 번 실행될 수 있고 (예측 이후 틀린 예측을 고치려고 한 번 더 실행된다던지), 스킵 될 수 있고 (데이터가 도달하기도 채 전에 원래 값으로 돌아온다던지), 누락될 수 있음 (Packet Drop)
RPC보다 빠른 시점에 변화를 감지할 수 있음 (값이 변화한 네트워크 Tick 이후 바로)
- Spawned가 실행되는 시점에는 이미 Network 어트리뷰트가 붙은 속성들이 모두 동기화 된 이후
Render
- 시각적인 계산은 Render에서 Like LateUpdate
- FixedUpdateNetwork는 예측, 실제 연산, 재예측 등 여러 번 호출 될 수 있기 때문에, 네트워크가 필요없는 시각 적인 연산은 중복 연산으로 자원 낭비가 될 수 있음
Remote Procedure Calls, RPC
- 원격 Procedure/함수 콜
- 엄격하게 동기화 되지 않음, 틱도 사용 안함
- 지연되거나, 로스, 손실될 수 있음
- Update에서 그냥 보냄
if (Input && Object.HasInputAuthority) RPC_SendMessage("Sans");
- 크게 중요하지 않은 것, Like 하스 감정표현
ETC
- 위는 호스트 모드
- Shared Mode: 각자 이동 권한을 가짐
- Predictive Spawn: 클라에서 Spawning도 예측
- Lag Compensation: 지연 보상, 클라 기존으로 판정 (핵 문제)
- Area Of Interest: Interest Area에 있지 않는 오브젝트는 동기화하지 않는
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.