Commands
概述
Quantum命令是通往Quantum標準API的一個輸入資料路徑。他們類似於Quantum輸入,但是 不 需要在每個刷新被發送。
Quantum命令完全可靠。伺服器將 總是 接受它們並且確認它,無論它們被發送的時間為何。這產生一個取捨;那就是本機客戶端,包含發送命令的客戶端,將無法預測模擬收到命令的那個刷新。雖然如果需要的話可以顯示視覺預測,但模擬將只會在伺服器已經確認命令作為刷新的一部分 之後 接收命令。
命令作為一個常規的C#類別被執行,其繼承於Photon.Deterministic.DeterministicCommand
。它們可以含有任何可序列化的資料。
C#
using Photon.Deterministic;
namespace Quantum
{
public class CommandSpawnEnemy : DeterministicCommand
{
public long enemyPrototypeGUID;
public override void Serialize(BitStream stream)
{
stream.Serialize(ref enemyPrototypeGUID);
}
public void Execute(Frame f)
{
var enemyPrototype = f.FindAsset<EntityPrototype>(enemyPrototypeGUID);
enemyPrototype.Container.CreateEntity(f);
}
}
}
在模擬中的命令系統設定
為了使命令被Quantum發送,需要針對它們來建立一個系統,並且使其注意到可用的命令。
- 在Quantum 2.1及之後版本中,命令需要被註冊在
CommandSetup.User.cs
中。 - 在Quantum 2.0中,命令需要被註冊在
CommandSetup.cs
中。
確定性命令設定
命令需要被新增到CommandSetup.User.cs
中的命令處理站,以在運行階段可用。
請注意: CommandSetup.Legacy.cs
並不是直接在此設定中被使用;而是,它需要被保存於2.1中以符合相容性要求。
C#
// CommandSetup.User.cs
namespace Quantum {
public static partial class DeterministicCommandSetup {
static partial void AddCommandFactoriesUser(ICollection<IDeterministicCommandFactory> factories, RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
// user commands go here
// new instances will be created when a FooCommand is received (de-serialized)
factories.Add(new FooCommand());
// BazCommand instances will be acquired from/disposed back to a pool automatically
factories.Add(new DeterministicCommandPool<BazCommand>());
}
}
}
----------
// CommandSetup.Legacy.cs
using Photon.Deterministic;
namespace Quantum {
public static class CommandSetup {
public static DeterministicCommand[] CreateCommands(RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
return new null;
}
}
}
命令設定(只針對2.0!)
在Quantum 2.0中,命令需要在CommandSetup.cs
中被註冊,以在運行階段可用。
請注意: 此系統在Quantum的較新版本中已過時;請參見DeterministicCommandSetup
以取得更多資訊。
C#
using Photon.Deterministic;
namespace Quantum {
public static class CommandSetup {
public static DeterministicCommand[] CreateCommands(RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
return new DeterministicCommand[] {
// user commands go here
new CommandSpawnEnemy(),
};
}
}
}
從檢視發送命令
可從Unity中的任何地方發送命令。
C#
using Quantum;
using UnityEngine;
public class UISpawnEnemy : MonoBehaviour
{
[SerializeField] private EntityPrototypeAsset enemyPrototype = null;
private PlayerRef _playerRef;
public void Initialize(PlayerRef playerRef) {
_playerRef = playerRef;
}
public void SpawnEnemy() {
CommandSpawnEnemy command = new CommandSpawnEnemy()
{
enemyPrototypeGUID = enemyPrototype.Settings.Guid.Value,
};
QuantumRunner.Default.Game.SendCommand(command);
}
}
從檢視發送複合命令
請注意: 這只在Quantum 2.1及之後的版本中才可用。
為了一次發送多個命令,只需建立一個CompoundCommand
,並且在發送它之前新增各個獨立的DeterministicCommand
到其上。
C#
var compound = new Quantum.Core.CompoundCommand();
compound.Commands.Add(new FooCommand());
compound.Commands.Add(new BazCommand());
QuantumRunner.Default.Game.SendCommand(compound);
多載
SendCommand()
有兩個多載。
C#
void SendCommand(DeterministicCommand command);
void SendCommand(Int32 player, DeterministicCommand command);
如果多位玩家由同一台機器控制,請指定玩家索引(PlayerRef)。只有一位本機玩家的遊戲,可以忽略玩家索引欄位。
從模擬輪詢命令
為了在模擬中接收及處理命令,請針對一個特定的玩家來輪詢幀:
C#
using Photon.Deterministic;
namespace Quantum
{
public class PlayerCommandsSystem : SystemMainThread
{
public override void Update(Frame f)
{
for (int i = 0; i < f.PlayerCount; i++)
{
var command = f.GetPlayerCommand(i) as CommandSpawnEnemy;
command?.Execute(f);
}
}
}
}
如同任何其他的系統,處理命令輪詢及取用的系統,需要被包含在SystemSetup.cs
之中
C#
namespace Quantum {
public static class SystemSetup {
public static SystemBase[] CreateSystems(RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
return new SystemBase[] {
// pre-defined core systems
[...]
// user systems go here
new PlayerCommandsSystem(),
};
}
}
}
注意事項
API並不強制,也不執行針對命令的一個特定的回調機制或設計模式。這取決於開發者,以選擇如何使用、解譯和執行命令;舉例而言,透過將他們編碼到信號、使用一個責任鏈,或是執行命令執行,以作為一個方法。
針對集合的實例
清單
C#
using System.Collections.Generic;
using Photon.Deterministic;
namespace Quantum
{
public class ExampleCommand : DeterministicCommand
{
public List<EntityRef> Entities = new List<EntityRef>();
public override void Serialize(BitStream stream)
{
var count = Entities.Count;
stream.Serialize(ref count);
if (stream.Writing)
{
foreach (var e in Entities)
{
var copy = e;
stream.Serialize(ref copy.Index);
stream.Serialize(ref copy.Version);
}
}
else
{
for (int i = 0; i < count; i++)
{
EntityRef readEntity = default;
stream.Serialize(ref readEntity.Index);
stream.Serialize(ref readEntity.Version);
Entities.Add(readEntity);
}
}
}
}
}
陣列
C#
using Photon.Deterministic;
namespace Quantum
{
public class ExampleCommand : DeterministicCommand
{
public EntityRef[] Entities;
public override void Serialize(BitStream stream)
{
stream.SerializeArrayLength(ref Entities);
for (int i = 0; i < Cars.Length; i++)
{
EntityRef e = Entities[i];
stream.Serialize(ref e.Index);
stream.Serialize(ref e.Version);
Entities[i] = e;
}
}
}
}
複合命令實例
每個刷新中,只有一個命令可以被附加到一個輸入串流。縱使一個客戶端在每個刷新中可以發送多個確定性命令,命令將不會在同一個刷新中到達模擬,而是將在接續的刷新中各自到達。為了繞過這個限制,您可以將多個確定性命令打包到一個單一的CompoundCommand
中。
Quantum 2.1已經提供這個類別。並且針對先前的版本,它可以像這樣被新增:
C#
public class CompoundCommand : DeterministicCommand {
public static DeterministicCommandSerializer CommandSerializer;
public List<DeterministicCommand> Commands = new List<DeterministicCommand>();
public override void Serialize(BitStream stream) {
if (CommandSerializer == null) {
CommandSerializer = new DeterministicCommandSerializer();
CommandSerializer.RegisterPrototypes(CommandSetup.CreateCommands(null, null));
}
var count = Commands.Count;
stream.Serialize(ref count);
if (stream.Reading) {
Commands.Clear();
}
for (var i = 0; i < count; i++) {
if (stream.Reading) {
CommandSerializer.ReadNext(stream, out var cmd);
Commands.Add(cmd);
} else {
CommandSerializer.PackNext(stream, Commands[i]);
}
}
}
}
為了接著分派已複合的命令:
C#
public override void Update(Frame f) {
for (var i = 0; i < f.PlayerCount; i++) {
var compoundCommand = f.GetPlayerCommand(i) as CompoundCommand;
if (compoundCommand != null) {
foreach (var cmd in compoundCommand.Commands) {
}
}
}
}
Back to top