PUN Classic (v1), PUN 2, Bolt는 휴업 모드입니다. Unity2022에 대해서는 PUN 2에서 서포트하지만, 신기능의 추가는 없습니다. 현재 이용중인 고객님의 PUN 및 Bolt 프로젝트는 중단되지 않고, 퍼포먼스나 성능이 떨어지는 일도 없습니다. 앞으로의 새로운 프로젝트에는 Photon Fusion 또는 Quantum을 사용해 주십시오.

상태

Photon Bolt 핵심에는 상태라고 하는 개념이 있습니다. Bolt의 State 구현을 사용하여 엔티티의 네트워크 상태를 템플릿으로 정의하며(Bolt Assets 윈도우 사용) 여기에는 변환 및 여러 기본 유형에 대한 속성이 포함됩니다. 또한 상태 속성을 IProtocolToken로 구현할 수 있으며 이것은 기본적으로 임의 데이터 유형을 상태 속성으로 구현하는 방법입니다.

state definition
State 정의.

State에는 여러 행동을 구성하기 위한 내부 설정들을 가지고 있습니다:

  • 상속: 이 설정을 사용하여 상태의 계층을 생성할 수 있습니다. 간단히 말하면 상위 상태의 모든 속성이 하위 상태에 생성되므로 플레이어 및 적과 같이 상태가 매우 유사한 경우 복제할 필요가 없습니다.
  • 대역폭: 은 이 상태가 패킷당 사용할 수 있는 비트 수와 이 상태에서 동시에 패킷에 쓸 수 있는 속성수를 결정합니다.
  • 임포트 메커니즘 모드:
    • 복제 모드: 다른 상태 속성과 마찬가지로 메커니즘 속성의 동기화 방법을 설정합니다.
    • 메커니즘 모드: 애니메이터 메소드(예: animator.SetFloat)를 통해 애니메이터의 속성을 변경하는 방법을 설정하거나 Bolt 속성을 대신 사용할지 여부를 설정합니다.
  • 임포트 메커니즘 파라미터: 애니메이션 제어에 필요한 모든 파라미터들을 가져오는 기준으로 사용되는 AnimatorController를 참조합니다.
  • 압축 초기화 값: 활성화되면 상태를 기준으로 새 Bolt 엔티티를 생성할 때 초기 변환 위치를 압축하는 방법을 구성할 수 있습니다. 값의 범위를 알고 있고 엔티티를 생성할 때 비트를 저장하려는 경우 이 작업에 도움이 될 수 있습니다.

상태 설명

Bolt 상태의 장점은 사용자가 네트워크 속성을 자동으로, 변경되는 경우에만 동기화할 수 있다는 것입니다. 게다가, 상태는 늦에 참여하는 것에 대한 구현을 거의 투명하게 만듭니다. Bolt 상태 소유주가 속성을 변경할 때마다 Bolt는 해당 엔티티에 현재 범위가 지정된 클라이언트에게 해당 값을 보냅니다. 사용자는 엔티티 동작에 대한 콜백(Attached에서) 콜백을 구독할 수 있습니다. (여기 참고)

Float 또는 Transform와 같은 각 State 속성은 기본 값(변경할 수 없는)을 가지고 있으며 엔티티가 생성될 때 최초로 설정됩니다. 특정 속성 값이 기본값에서 변경되지 않은 경우 Bolt는 이 속성을 어떤 연결에도 동기화하지 않으며 전체 네트워크 전송을 최소화합니다.

상태는 원시 속성이 충분하지 않은 경우 사용자 지정 속성을 확장할 수 있습니다. 이 작업은 IProtocolToken 구현을 사용하여 수행됩니다. 토큰을 사용하면 사용자 정의 비즈니스 로직을 위한 직렬화를 완벽하게 제어할 수 있습니다. 그러나 토큰 내부의 데이터를 변경해도 Bolt가 변경된 속성을 전송하도록 트리거 하지는 않습니다. 기존 토큰을 다른 토큰으로 변경하거나 null로 설정한 경우(또는 null 토큰을 null이 아닌 토큰으로 변경하는 경우)와 같이 토큰 자체가 변경될 경우에만 Bolt가 토큰을 보냅니다. 토큰은 팩토리에서 생성되므로 Bolt에 등록해야 한다는 점을 기억하십시오.

새 연결이 게임 세션에 참여하면 모든 엔티티가 자동으로 동기화(스코프 기준으로) 됩니다. 변경된 모든 속성도 이 플레이어에게 동기화됩니다. 엔티티/속성의 수에 따라 이 작업 시간은 가변적입니다. Bolt는 Bolt 설정에서 설정한 만큼의 초당 패킷만 전송하므로, 결국 모든 데이터가 클라이언트에 도착하게 됩니다. 이렇게 하면 늦게 참여하는 것이 매우 간단해지고 관련된 모든 일반적인 해킹(일반적으로 일종의 메시지 버퍼링)을 방지할 수 있습니다.

상태 복제

볼트는 각 송신 틱(Bolt 설정에 정의된)에서만 상태 업데이트를 전송합니다. 즉, 속성이 기본적으로 "dirty"로 표시되고 다음 송신 틱까지 평가되지 않습니다. 즉, FixedUpdate 사이에 속성 값을 여러 번 변경하면 볼트 체크 시점의 값만 전송됩니다(즉, 중간 값은 없습니다).

Bolt의 상태 및 그 속성을 다룰 때 명심해야 할 점은 엔티티 소유자만이 그 값을 바꿀 수 있고 네트워크를 통해 복제될 수 있다는 사실입니다. 여기서 유일한 예외는 속성의 복제 모드(여기 참고)를 컨트롤러를 제외한 모든 사용자로 설정한 경우입니다. 이 경우 컨트롤러도 속성 값을 변경할 수 있지만 복제되지 않으며 콜백은 로컬 Controller에서 발생됩니다.

엔티티가 연결되면 상태 속성이 모두 클라이언트에 도착한다고 보장되지는 않습니다. 일부 데이터가 절대적으로 필요한 경우 이 데이터에 대해 토큰 부착(즉, 토큰을 인스턴스화할 때 IProtocolToken로 데이터 전송)을 사용하십시오. 토큰을 부착하는 것은 상대적으로 버겁습니다. 토큰은 생성 작업이 승인될 때까지 생성 작업에 대한 각 전송 체크 표시를 전송합니다.

또한 상태 속성은 일반적으로 (Bolt 상태 설정에서 더 높은 우선순위 번호가 더 높은 경우) 우선순위 순서로 수신되지만 특정 순서로 도착한다고 보장되지는 않습니다. 이를 "궁극적인 일관성" 이라고 하며, 상태가 엔티티 소유자와 궁극적으로 일관되게 유지된다는 것입니다.

Bolt가 모든 상태 속성을 패킹할 때 우선순위에 따라 엔티티를 반복적으로 분류합니다. Bolt는 각 엔티티에 대해 더티 속성을 정렬하고 패킷 공간이 부족해질 때까지 각 엔티티에 대해 특정 번호(사용자 설정에 정의됨)를 전송(Bolt 패킷 참고)합니다. 이 절차는 연결별로 수행됩니다. 패킷 크기와 Bolt 설정 모두 때문에 상태 속성을 변경한 후 Bolt가 다음 전송 틱에 전송한다는 것은 보장되지 않습니다.

Bolt는 또한 범위 (여기에서 상세 내용 보기)라는 개념이 있으며, 이것은 특정 엔티티로부터 업데이트를 수신해야 하는 연결을 결정하며 여기에는 속성 변경 사항이 포함됩니다. 기본값은, 모든 연결이 모든 업데이트에서 수신되지만 수동 범위 모드를 사용하여 변경할 수 있습니다.

상태 속성 유형

모든 볼트 상태는 기본적으로 속성 집합으로 만들어지며, 각 속성 집합은 데이터 형식으로 표시됩니다. 여기서는 엔티티의 상태를 구축하는 데 사용할 수 있는 모든 속성 유형과 네트워크 레이아웃에 실제 영향을 미칠 수 있는 세부 정보를 설명합니다.

각 속성 유형에는 기본 동작을 조작하는 데 사용되는 자체 구성 집합이 있으며, 압축 옵션을 조정하기 위해 복제 모드에서 구성될 수 있습니다(모든 필드에 이 설정이 있으며, 여기에서 자세한 내용을 볼 수 있습니다). 일부 에셋 유형에는 메카님이라는 옵션도 있습니다. 이 속성을 애니메이터 매개 변수로 간주해야 하는지를 제어할 수 있습니다. 이 경우 Bolt가 자동으로 속성 값을 애니메이터 컨트롤러와 동기화할 수 있습니다(이 페이지 뒷부분에서 설명).

  • Float: float 값;

    • Smoothing 알고리즘: float 값을 보간하는지에 따라 선택
    • 보간 모드: 값을 정규 부동 값 또는 각도로 간주할지 선택합니다. Bolt가 값을 보간할 때UnityEngine.Mathf.Lerp 또는 UnityEngine.Mathf.LerpAngle을 사용할지 여부를 결정합니다.
    • 압축: 여기에서 float에 대해 압축 설정을 결정합니다.
  • 정수: 정수

    • 압축: 정수 값에 대한 압축 설정
  • Matrix4x4: 유니티 Matrix4x4 인스턴스

  • Quaternion: Unity Quaternion 인스턴스

    • Smoothing 알고리즘: Quaternion 값이 보간 되는지의 여부를 선택합니다. UnityEngine.Quaternion.Slerp를 사용합니다.
    • Axes:: 축(X, Y, Z) 이 쿼터니온에 의해 고려해야 하는지 선택합니다.
    • 엄격한 비교:: 사용으로 설정한 경우, Quaternion 이 변경되었는지를 판단할 때 Quaternion (q1 != q2)의 동등 연산자를 사용하는 대신, 각 단일 값은 하나씩 비교(q1.x != q2.x || q1.y != q2.y...)됩니다.
    • Quaterinon 압축: Quaternion 에 있는 각각의 값의 압축 설정을 결정합니다.
  • 벡터: Unity Vector3 인스턴스;

    • Smoothing 알고리즘: Vector 값이 보간되어야 하는지의 여부를 결정. UnityEngine.Vector3.Lerp를 사용합니다.
    • Axes:: 어떤 축(X, Y, Z)이 이 벡터에 고려되어야 하는지 선택합니다.
    • 엄격한 비교:: 사용하는 경우,Vector가 변경되었을 때 Vector (v1 != v2)의 동등 연산자를 사용하는 대신, 하나씩 단일 값을 비교(v1.x != v2.x || v1.y != v2.y...)합니다.
    • Teleport Threshold: 값 사이를 보간하지 않고 벡터 값이 제자리에 고정되어야 하는 위치에서 크기 한계를 결정합니다.
    • Axis 압축: Vector상에 있는 각각의 값에 대한 압축 설정을 결정합니다.
  • Bool: boolean

  • String: string

    • 인코딩 & 길이:문자열 값의 직렬화에 어떤 인코딩을 사용할지와 문자 기준의 최대 길이를 설정할 수 있습니다
  • Guid: System.Guid의 인스턴스

  • 색상: Unity Color 인스턴스

  • Color32: Unity Color32 인스턴스

  • Entity: 다른 BoltEntity 참조;

  • NetworkId: Bolt.NetworkId 레퍼런스

  • PrefabId: Bolt.PrefabId 레퍼런스

  • 배열: 동일 형식의 값들의 집합, 배열 형식으로 구성됨. Floats 또는 Strings 의 배열과 유사하게 인덱스를 통해 개별 항목에 접근할 수 있습니다.

    • Element 유형: 배열의 유형 선택.
    • Element 건수: 배열에 저장되어 있는 요소의 건수.
  • Object: Object 에셋 유형을 나타냅니다. Object 에셋은 동일한 "상자" 내에 관련 데이터를 저장하는 데 사용할 수 있는 특수 유형의 컨테이너입니다. 또한 Bolt Assets 창에 정의되어 있으며 동일한 속성 집합을 State로 정의한 다음 여러 다른 State에서 'Object 정의를 재사용할 수 있으므로 하위 상태로 간주할 수 있습니다.

    • Object 유형: 여기에서 Object 유형을 선택할 수 있습니다.
  • ProtocolToken: Bolt.IProtocolToken을 구현하는 사용자 지정 토큰을 참조합니다. 다른 속성 유형에서 정상적으로 전송할 수 없는 임의 데이터를 전송하려는 경우 토큰 필드가 유용할 수 있습니다. 이미 언급한 바와 같이, 토큰 필드 값을 변경하면 값이 동기화되지 않으며, 토큰 참조(null 또는 새 토큰으로 변경되는 경우에만 해당 값이 업데이트됩니다.

  • Trigger: 트리거는 특별한 하나의 발생 상태입니다. 애니메이션 상태 변경을 트리거 하거나 무기를 발사하기 위해 실행할 수 있는 속성을 원하는 경우 이 경우 트리거 속성이 도움이 될 수 있습니다.

  • Transform: 유니티 트랜스폼 인스턴스. Transform 속성은 다른 모든 유형과 다릅니다. 선택적 단순 "렌더" 보간뿐만 아니라 보간/외삽도 투명하게 구현됩니다. 최적화로 Bolt는 변환이 이동할 때만 변환 상태를 전송합니다. 객체가 이동하지 않으면 전송되지 않습니다.

    • Space: 여기서 TransformLocal 또는 World 변환 좌표 공간을 사용하여 변환할지 여부를 정의합니다. 즉, 볼트localPosition/localRotation 또는 position/rotation을 사용하여 GameObject를 이동할 경우입니다.
    • Smoothing 알고리즘:
      • 없음: 위치와 회전이 새로운 값으로 스냅 됩니다
      • 보간: Bolt는 UnityEngine.Vector3.Lerp 과 회전 쿼터니온 UnityEngine.Quaternion.Slerp을 사용하여 위치 백터가 보간합니다.
      • 추론: Bolt는 현재 속도를 기준으로 Transform의 위치와 회전을 추정합니다. 이 기능은 방향을 너무 많이 변경하지 않고 네트워크 지연을 보상하려는 개체가 있는 경우 유용합니다.
        • 추론 가속도: Bolt가 현재 물체의 속도를 계산하거나 가져올 위치를 선택합니다.
        • 추론 설정: 여기에서 Bolt가 위치/회전을 추정하는 전방 프레임 수를 구성할 수 있습니다.
    • 위치: Vector 속성 유형과 동일한 설정
    • 회전: Quaternion 속성 유형과 동일한 설정

상태 상호 작용

생성하는 상태 에셋은 특정 엔터티에 대한 네트워크 레이아웃에 대한 설명일 뿐입니다. 계속하기 전에 예로 사용할 상태를 설정해야 합니다. SphereState라는 상태를 사용할 것이며 기본 설정인 4가지 기본 속성을 모두 포함합니다:

  • Transform 유형의 Transform
  • 3개 요소를 갖고 있는 Vector 베열 형의 Colors
  • Integer 형식의 CurrentColor
  • Trigger 형식의 Blink
example state
상태 예제.

상태 데이터와 상호 작용하고 값을 읽고 쓸 수 있으려면 다음 몇 단계를 수행해야 합니다.

  1. 새로운 Unity 프리팹을 생성하고 여기에 BoltEntity 컴포넌트를 추가합니다.
  2. State 필드에서 Bolt Assets 창에서 정의한 State를 선택합니다.
  3. 새 C# 스크립트를 생성하여 프리팹에 추가합니다.
  4. 에셋을 변경한 후에는 Bolt를 다시 컴파일해야 합니다(Bolt/Compile Assembly 메뉴).

다음에 표시된 그림과 같은 구성이 되어야 합니다:

bolt entity with state
상태를 가진 Bolt Entity.

예제의 SphereController 스크립트를 오픈합니다. Bolt Entity의 기본 구현은 다음과 유사합니다:

C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SphereController : Bolt.EntityBehaviour<ISphereState>
{
    public override void Attached()
    {
        // entity initialization
    }
}

엔티티 컨트롤러를 만들 때 상태를 관리하는 몇 가지 사항을 기억해야 합니다:

  1. Bolt.EntityBehaviour<YourStateInterface> 또는 Bolt.EntityEventListener<YourStateInterface>에서 확장되어야 합니다. 이 클래스들은 UnityEngine.MonoBehaviour에서 확장되었으므로, 모든 유니티 메소드에 접근할 수 있습니다.
  2. 클래스(YourStateInterface)를 정의할 때 제너릭 타입이 전달되며, 접근하려는 State 타입을 정의하여 GameObject 프리팹에 붙여진 BoltEntity 컴포넌트에 설정한 것과 동일해야 합니다.
  3. GameObjectBoltEntity는 일반적인 GameObject에서 수행된 Start 메소드 내부에서 Entity 설정을 하는 동안에 이루어지는 서로 다른 초기화 프로세스를 가지고 있습니다. 이 의미는 Entity는 알려져야 되고 초기화되어야 한다는 것입니다. 따라서 일반적으로 Start 메소드로 하는 모든 작업은 Attached 메소드로 수행해야 합니다.

이제 Entity를 초기화하고 몇 가지 값을 속성에 연결하는 방법을 자세히 살펴보겠습니다.

C#

public override void Attached()
{
    // Link the GameObject with the Bolt Transform Property
    state.SetTransforms(state.Transform, transform);

    // Init the Colors Array
    state.Colors[0] = new Vector3(1, 0, 0);
    state.Colors[1] = new Vector3(0, 1, 0);
    state.Colors[2] = new Vector3(0, 0, 1);

    // Set the Active Color
    state.CurrentColor = 0;
}

보시다시피 엔터티와 관련된 State를 수정하는 것은 포함된 State 변수를 사용하는 것만큼이나 간단하며 각 개별 속성에 접근할 수 있습니다. 이 작업은 상태를 수정하려는 모든 메소드에서 수행할 수 있습니다. 다른 스크립트에서 BoltEntity에 대한 참조가 있고 상태에 액세스하려면 entity.GetState<YourStateInterface>()를 호출하십시오.

이 코드에서 중요한 부분 중의 하나는 Bolt가 GameObject의 TransformTransform의 연결 방법으로 state.SetTransforms 메소드를 사용하여 Bolt는 GameObject가 움질일 때 자동적으로 위치/회전을 동기화합니다.

위의 코드에 없는 Bolt와의 다른 관련 통합은 Entity에 애니메이션이 있고 Bolt에 모든 매개 변수를 동기화하려는 경우입니다. 이 경우 Animator 참조도 해당 상태에 등록해야 합니다. 이 작업은 단 한 라인으로 수행됩니다.

C#

state.SetAnimator(GetComponentInChildren<Animator>()); // Or wherever your animator is

그런 다음 State 속성이 모두 편집기에서 올바르게 설정된 경우 연결된 속성을 변경하기만 하면 되고 Animator는 원하는 대로 복제됩니다.

앞에서 언급했듯이 엔터티의 소유자만 상태를 수정할 수 있으며, 소유자에서 코드를 실행하려면 if (entity.IsOwner)로 확인하여 감쌀 수 있습니다. 이 필드는 Entity를 생성한 피어에서만 true를 반환합니다. 예를 들어 런타임에 새 값만 할당하면 CurrentColor를 수정하여 인덱스 01 사이를 토글 할 수 있으며 관련 메소드를 호출하는 Trigger 속성도 활성화할 수 있습니다(이는 이 속성에서 특히 중요합니다). 이 페이지의 뒷부분에서 이러한 변경 사항에 대응하는 방법에 대해 설명합니다.

C#

private void Update()
{
    if (entity.IsOwner == false) { return; }

    if (Input.GetKeyDown(KeyCode.C))
    {
        var current = state.CurrentColor;
        current = ++current % 2;
        state.CurrentColor = current;
    }

    if (Input.GetKeyDown(KeyCode.R))
    {
        var idx = Random.Range(0, state.Colors.Length);
        state.Colors[idx] = new Vector3(Random.value, Random.value, Random.value);
    }

    if (Input.GetKeyDown(KeyCode.F))
    {
        state.Blink();
    }
}

복제 모드(링크)는 상태 복제 방법 및 누구에게 하는지를 수정하기 때문에 상태 관리 방식에 매우 큰 영향을 줍니다. 기본적으로 모든 속성은 Everyone 모드를 사용하여 생성됩니다. 즉, Only만 할당할 수 있고 다른 속성은 데이터를 수신하기만 합니다. 그러나 이 값을 Controller를 제외한 모두로 설정할 수도 있습니다. 즉, 컨트롤러에서 상태 속성 값도 변경할 수 있지만 복제되지는 않습니다.

  • 다음과 같은 경우 Controller를 제외한 모두를 사용하는 것이 좋습니다.

    1. 컨트롤러에 대한 모든 제어 권한을 허용하려는 속성이 있습니다.
    2. resetState==trueExecuteCommand()에서 서버/소유자로부터 결과 상태로 갱신되는 속성이 있습니다.
  • 반면, Everyone으로 관리해야 하는 경우는:

    1. 소유자가 설정하고 컨트롤러가 설정할 수 없는 속성이 있습니다.

상태 콜백

States에 값을 쓰는 것의 다른 면은 런타임 시 업데이트에 반응하는 것입니다. Bolt는 특정 속성 값이 변경되었을 때 자동으로 Bolt에 의해 호출되는 핸들러인 속성 콜백을 사용하여 이를 수행합니다. 이 기능은 다양한 방식으로 유용하지만, 가장 중요한 것은 상태를 통합할 필요가 없고 필요할 때 새로운 값을 관리하기만 하면 된다는 것입니다.

한 가지 유의할 점은 대부분의 시나리오에서 속성 콜백을 Attached 메소드에 등록한다는 것입니다. 이 이벤트를 받으면 Entity가 완전히 초기화되고 거기서 상태를 변경할 수 있으며 업데이트도 받을 수 있기 때문입니다.

속성 유형 자체와 관련된 속성 콜백의 세 가지 주요 유형인 simple, array, trigger를 지정할 수 있습니다. 다음 섹션에서는 속성 핸들러를 사용할 수 있도록 각 항목과 코드에 대해 설명합니다.

Simple 콜백

이러한 유형의 콜백은 가장 사용하기 쉽고 가장 많이 사용할 콜백입니다. 특별한 내용은 없으며, 일반 System.Action과 매우 유사한 위임자 PropertyCallbackSimple을 따라야 한다는 점입니다:

C#

public delegate void PropertyCallbackSimple();

따라서 이러한 종류의 콜백을 등록하려면 아래 코드를 따르십시오.

C#

public override void Attached()
{
    // previous entity setup...

    // Callbacks
    state.AddCallback("CurrentColor", HandlerCurrentColor);
}

void HandlerCurrentColor()
{
    Debug.LogFormat("New current color: {0}", state.CurrentColor);

    var currentColor = state.Colors[state.CurrentColor];

    var r = (byte) currentColor.x;
    var g = (byte) currentColor.y;
    var b = (byte) currentColor.z;

    GetComponent<Renderer>().material.color = new Color(r, g, b, 1);
}

보시다시피 콜백 등록을 위해 State 자체의 state.AddCallback() 메소드를 사용합니다. 첫 번째 인수는 속성의 이름을 가진 문자열입니다. 철자를 올바르게 입력했는지 확인하고 소문자/대소문자를 주의합니다. 두 번째 인수는 콜백 함수에 대한 레퍼런스일 뿐입니다.

콜백 예제에서 CurrentColor 속성은 Colors 배열에서 올바른 색 인덱스를 얻기 위해 읽습니다. 그런 다음 벡터를 UnityEngine.Color으로 변환합니다. 색상은 GameObject의 머터리얼에 할당하여 현재 렌더링 색상을 변경합니다.

객체를 가진 Simple 콜백

State에서 Object를 정의했고 각 필드에 대해 콜백을 설정하는 대신 하나의 글로벌 콜백을 원하는 경우 특정 속성에 따라 별도의 메소드를 호출하려면 스위치 문이 아닌 룩-업 테이블을 사용하는 것이 좋습니다. 이것은 필요 이상의 최적화에 가깝고 콜백이 많이 트리거 되고 객체에 많은 필드가 있는 경우에만 도움이 됩니다.

state with object property
객체 속성을 가진 상태.

위의 이미지에 표시된 정의를 기반으로 다음과 같은 Actions 룩-업 테이블을 정의할 수 있습니다.

C#

private Dictionary<string, Action> lookupTable;

public override void Attached()
{
    // previous entity setup...

    // Setup Look-up table
    lookupTable = new Dictionary<string, Action>() {
        { "equippedItems.head.ID", () => UpdateSingleArmor(0, state.equippedItems.head) },
        { "equippedItems.body.ID", () => UpdateSingleArmor(1, state.equippedItems.body) },
        { "equippedItems.arms.ID", () => UpdateSingleArmor(2, state.equippedItems.arms) }
    };

    // Callbacks
    state.AddCallback("equippedItems", UpdateNewArmor);
}

private void UpdateNewArmor(IState state, string propertyPath, ArrayIndices arrayIndices)
{
    Debug.LogFormat("Updated path {0}", propertyPath);
    lookupTable[propertyPath]();
}

private void UpdateSingleArmor(int slot, Item item)
{
    Debug.LogFormat("Slot {0} new item {1}", slot, item.ID);
}

이렇게 하면 동일한 콜백을 사용하여 특정 객체에서 업데이트를 받을 수 있습니다.

배열 콜백

배열 속성을 처리할 때는 마지막 섹션에 나와 있는 것처럼 동일한 단순 콜백을 사용할 수 있지만, 더 많은 인수를 받는 특수 위임자 PropertyCallback을 사용할 수도 있습니다.

C#

public delegate void PropertyCallback (IState state, string propertyPath, ArrayIndices arrayIndices);
  1. **Bolt.IState state:**는 메소드내에서 State 타입으로 캐스팅될 수 있습니다(note that Bolt.IState는 상속된 클래스의 모든 상태입니다).
    • 이것은 실제의 상태입니다 (일반적인 AddCallback 메서드를 사용하기 위해) 엄격한 타입이 아니며 사용자 자신의 유형에 따라 캐스트 해야 합니다.
  2. **string propertyPath:**는 속성의 전체 경로입니다.
  3. Bolt.ArrayIndices arrayIndices에는 콜백에 붙여지는 배열의 인덱스들을 포함하고 있습니다.

여기서는 이 버전의 콜백 사용 방법에 대한 몇 가지 예를 살펴보겠습니다.

단일 수준 배열

Array 속성에 대한 콜백을 등록하려면 Simple Callback에서 보았던 것과 매우 유사하지만, 다음과 같이 속성 이름 뒤에 []를 포함하면 됩니다.

C#

public override void Attached()
{
    // previous entity setup...

    // Callbacks
    state.AddCallback("Colors[]", HandlerColors);
}

void HandlerColors(IState state, string propertyPath, ArrayIndices arrayIndices)
{
    var index = arrayIndices[0];
    var localState = (ISphereState)state;

    var newColor = localState.Colors[index];

    Debug.LogFormat("Property {0} with index {1} has changed to {2}", propertyPath, index, newColor);
}

반면, 이 경우 콜백은 조금 더 복잡합니다. 앞에서 설명했듯이, 이제 여러분은 더 많은 아규먼트에 접근할 수 있지만, 정말 간단합니다. 추가적으로 고려해야 할 것은 arrayIndices 아규먼트와 관련이 있습니다.- 실제로 Array속성에서 변경된 인덱스를 나타내주는 배열입니다.

중첩 배열 콜백

또한 Bolt는 중첩된 Array 속성을 관리할 수 있으며, 매우 강력하지만 신중하게 사용해야 합니다. 이 작업은 Object 속성이 포함된 Object 에셋을 사용하여 수행됩니다. 즉, 이 Object 정의를 배열 속성의 유형으로 사용하는 State는 중첩된 수준의 배열을 생성합니다. 우리는 코드와 연결하기 위해 다음의 StateObject 설명을 예로 들겠습니다.

nested arrays
중첩된 배열.

예제에서는 배열 속성을 가진 객체가 있으며, 이 정의는 상태에서 Array Inventory의 타입으로 사용됩니다. 콜백을 등록하고 예제 Array에 대한 모든 변경 사항을 처리하려면 콜백 등록을 다음과 같이 확장하여 이 작업을 수행합니다.

C#

public override void Attached()
{
    // previous entity setup...

    // Callbacks
    state.AddCallback("Inventory[].Example[]", HandlerInventory);
}

void HandlerInventory(IState state, string propertyPath, ArrayIndices arrayIndices)
{
    var indexInventory = arrayIndices[0];
    var indexExample = arrayIndices[1];

    var localState = (ISphereState)state;

    var newValue = localState.Inventory[indexInventory].Example[indexExample];

    Debug.LogFormat("Property {0} with index {1}/{2} has changed to {3}", propertyPath, indexInventory, indexExample, newValue);
}

현재 몇 가지 중첩된 배열인 arrayIndices가 있으며 더 많은 값으로 채워지며, 각 위치는 중첩된 배열의 해당 수준에서 변경된 인덱스를 나타냅니다. 그래서 arrayIndices의 인덱스 0에는 Inventory의 인덱스 값을 가지고 있고 1 인덱스에는 Example 배열 등과 같이 담겨있습니다. 더 많은 수준의 배열을 가지고 있으면, 예제를 참고해보세요.

트리거 콜백

Trigger 속성은 일반적인 State 속성들과 약간 다르며 state.AddCallback()을 사용하는 대신 트리거는 이미 C# 위임자입니다. properties are little difference from the other regular State properties, instead of using state.AddCallback(), triggers are already C# delegates. 새 속성 콜백을 등록하기 위해 일반적인 C# 메소드를 사용하여 메서드 옵저버를 등록합니다.

C#

public override void Attached()
{
    // previous entity setup...

    // Callbacks
    state.OnBlink += HandlerBlink;
}

void HandlerBlink()
{
    Debug.Log("Blink!");
}

다른 유형의 속성과 가장 큰 차이점은 리스너를 추가할 때 On<TriggerName>라는 State 속성을 사용한다는 점입니다. 여기서 <TriggerName>은 트리거 속성의 이름입니다. 자, 예를 들어, Blink 트리거를 만들었고 이것이 우리가 state.OnBlynk를 콜백에 등록하는 이유입니다. state.Blink()는 앞에서 설명한 것처럼 실제로 트리거를 생성/활성화하는 데 사용되는 메소드입니다.

Back to top