Remote Procedure Calls
概述
遠端程序調用,簡稱RPC,是共享即時遊戲事件的理想選擇;相比之下,輸入架構和[Networked]
屬性是在不斷變化的網路客戶端之間共享狀態的首選解決方案。
例如,當玩家想要與一個它沒有輸入授權的物件進行少見的複雜互動時,例如使用他們庫存物件中的特定鑰匙打開一扇鎖著的門。雖然從技術上講,可以透過在輸入中包含額外的欄位來實現這些操作,但這會使輸入結構變得混亂,使其難以操作。
此外,輸入結構作為不可靠的訊息發送,即封包可能會遺失。對於需要持續輸入的東西(例如角色移動)來說,這很少能被注意到,但當這影響到玩家期望得到保證的單個一次性動作時,將會對玩家體驗造成傷害。在這種情況下,遠端程序調用是最佳實務做法。
設定
Fusion為RPC提供了一種簡單而強大的語法。一般來說,RPC有三種類型:
- 執行個體RPC;
- 靜態RPC;與,
- 目標RPC。
以下章節將介紹各個類型。
執行個體RPC
要在NetworkObject
上的任何NetworkBehaviour
上定義RPC,只需執行以下步驟:
- 宣告一個傳回類型為
void
或RpcInvokeInfo
的常規CSharp方法(如下所述); - 使用「RPC」對方法名稱進行前綴或後綴(不區分大小寫);
- 在方法宣告前新增
[Rpc]
屬性;並且, - 設置
RpcSources
和RpcTargets
參數,以控制RPC的調用位置和執行位置。
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color){
playerName = name;
playerColor = color;
}
注意: RPC的方法名稱中必須有一個「rpc」前綴或後綴(不區分大小寫)。
靜態RPC
靜態RPC遵循略有不同的規則,它們:
- 忽略
RpcSources
和RpcTargets
參數;和 - 要求方法的第一個參數為
NetworkRunner
。 - 可以在任何
SimulationBehaviour
(而不僅僅是NetworkBehaviour
)上實作,因為回調接收器不綁定到特定的NetworkObject
。
因為沒有源和目標篩選器,所以可以從 任何 客戶端調用靜態RPC,並將其發送到 所有 客戶端。請注意,您仍然可以將RPC目標定位到特定的PlayerRef
(請參閱「目標RPC」),以控制誰將接收調用。
C#
[Rpc]
public static void Rpc_MyStaticRpc(NetworkRunner runner, int a) { }
RPC屬性參數
源與目標
RpcSources
和RpcTargets
是篩選器。RpcSources
定義了哪些同儕節點可以發送RPC,而RpcTargets
則定義了RPC在哪個同儕節點上執行。
All
:可以由遊戲階段中的所有同儕節點(包括伺服器)發送/執行。Proxies
:可以由對物件沒有輸入授權或狀態授權的同儕節點發送/執行。InputAuthority
:可以由對物件具有輸入授權的同儕節點發送/執行。StateAuthority
:可以由對物件具有狀態授權的同儕節點發送/執行。
重要: RPC沒有明確的狀態。延遲加入的客戶端和中斷連線並重新連線的客戶端會忘記這件事曾經發生過。因此,確保RPC滿足以下任一條件至關重要:
- 真正暫時,沒有任何狀態(例如聊天消息);或者,
- 其效果間接記錄在
[Networked]
屬性中。
C#
public class Player : NetworkBehaviour {
[Networked] public string playerName { get; set; }
[Networked] public Color playerColor { get; set; }
[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color) {
playerName = name;
playerColor = color;
}
}
可選的RPC屬性參數
除了RpcSources
和RpcTargets
屬性外,[Rpc]
屬性還提供了幾個可選參數。
Channel
(預設為Reliable
):如果RPC在傳輸過程中可能遺失,則設定為Unreliable
。InvokeLocal
(預設為真):真表示將在本機客戶端上叫用RPC。InvokeResim
(預設為偽):真表示將在重新模擬期間叫用RPC。TickAligned
(預設為真):如果您不希望接收端將RPC的執行延遲到發送輸入的刷新或之後,則設定為偽。
C#
[Rpc (RpcSources.All, RpcTargets.All, InvokeLocal = true, InvokeResim = true, TickAligned = false )]
void RpcStartBoost(){
m_BoostAnim.StartBoostAnimation();
}
RPC方法參數
RPC在運行階段被序列化。因此,建議使用常規CLR類型(例如bool
)而不是Fusion特定的CLR類型(如NetworkBool
)。
允許資料參數
- 基元
- byte、sbyte
- Int16、Int32、Int64
- UInt16、UInt32、UInt64
- float
- double
- float
- double
- Unity架構類型(在ILWeaver.cs中定義)
- Vector2、Vector3、Vector4
- Quaternion
- Matrix4x4
- Vector2Int、Vector3Int
- BoundingSphere
- Bounds
- Rect
- BoundsInt
- RectInt
- Color、Color32
- System.Guid
- 使用者定義的INetworkStructs
- Fusion定義的INetworkStructs
- NetworkString<IFixedStorage>
- NetworkBool
- Ptr
- Angle
- BitSet64、BitSet128、BitSet192、BitSet256
- PlayerRefSet
- NetworkId
- NetworkButtons
- NetworkRNG
- NetworkObjectGuid
- NetworkPrefabRef
- NetworkObjectHeader
- NetworkPrefabId
- SceneRef
- TickTimer
- IFixedStorage (_2, _4, _8, _16, _32, _64, _128, _256, _512)
- Fusion類型
- NetworkObject(序列化為
NetworkId
) - NetworkBehaviour(序列化為
NetworkId
與NetworkBehaviour
索引) - PlayerRef(序列化為
PlayerRef.PlayerId
)
- NetworkObject(序列化為
- 字串
- 上列任何類型的陣列
Rpc資訊
RPC 方法 宣告 可以接受類型為RpcInfo
的可選參數,該參數公開了有關RPC的以下中繼資訊:
Tick
:它是在哪個刷新發出的。Source
:哪個玩家(PlayerRef
)發送了它。Channel
:它是作為Unreliable
還是Reliable
的RPC發送的。IsInvokeLocal
:最初叫用此RPC的是本機玩家嗎。
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color, RpcInfo info = default){
playerName = name;
playerColor = color;
}
參數 總是 宣告為 RpcInfo info = default
。
伺服器與主機端來源
在ServerMode
中使用Fusion時,伺服器發送的RPC中包含的RpcInfo.Source
將被設定為“PlayerRef.None
,因為伺服器不是玩家。
然而,當在HostMode
下使用Fusion時,主機客戶端會運行伺服器與玩家 兩者。預設情況下,主機發送的任何RPC都將與伺服器功能相同,並設定RpcInfo.Source
為PlayerRef.None
。為了包含主機的本機PlayerRef
,必須將HostMode
屬性設定為RpcHostMode.SourceIsHostPlayer
。
HostMode
可以設定為兩種模式之一:
RpcHostMode.SourceIsServer
(預設):RpcInfo.Source
設定為PlayerRef.None
。RpcHostMode.SourceIsHostPlayer
:當Fusion在HostMode
下運行時,RpcInfo.Source
設定為本機PlayerRef
。
為了將主機的PlayerRef
包含在RpcSource.Info
中,前面的程式碼片段可以調整如下:
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority, HostMode = RpcHostMode.SourceIsHostPlayer)]
public void RPC_Configure(string name, Color color, RpcInfo info = default){
playerName = name;
playerColor = color;
}
Rpc叫用資訊
RPC方法可以選擇將RpcInvokeInfo
定義為傳回值。當叫用RPC方法時,RpcInvokeInfo
傳回值將包含有關RPC叫用和發送操作的資訊。
LocalInvokeResult
:RpcLocalInvokeResult
列舉值,指示本機叫用操作的成功或失敗原因。SendCullResult
:RpcSendCullResult
列舉值,指示遠端同儕節點RPC叫用的成功或失敗原因。SendResult
:RpcSendResult
架構,包含有關RPC發送操作的中繼資訊。Result
:此RPC訊息發送操作的RpcSendMessageResult
結果旗標。MessageSize
:RPC套件的大小。Receivers
:包含的PlayerRef
的集合作為此RPC操作的接收器。CulledReceivers
:從這個RPC發送操作中篩選並排除為接收器的PlayerRef
的集合。
注意: 這不是關於 交付 成功或失敗的資訊,而只是 叫用 和 發送 操作的結果。
C#
[Rpc]
public RpcInvokeInfo RpcFoo() {
// RPC action
return default;
}
public override void FixedUpdateNetwork() {
var info = RpcFoo();
Debug.Log(info);
}
目標Rpc
當RPC打算在特定玩家的機器上專屬執行時,會使用目標RPC。透過在[RpcTarget]
屬性前新增PlayerRef
參數,執行個體RPC和靜態RPC都可以轉換為目標RPC。一個典型的用例是團隊聊天,其中訊息僅針對自己團隊中的特定玩家。
注意: 為[RpcTarget]
參數傳遞PlayerRef.None
將以伺服器為目標!
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.All)]
public void Rpc_TargetedInstanceMessage([RpcTarget] PlayerRef player, string message){}
或
C#
[Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.All)]
public static void Rpc_MyTargetedStaticMessage(NetworkRunner runner, [RpcTarget] PlayerRef player, string message) { };
重要: 在方法宣告 中 使用的[RpcTarget]
屬性與方法聲明 前 的[Rpc]
屬性中的RpcTargets
參數 不同。