Calling Operations 调用操作
As described in the “
Basic Concepts
”, operations are Remote Procedure Calls, defined by some Photon Application.
作为基础概念,操作是远程过程调用,由Photon应用程序定义。
The client APIs includes a LitePeer class (or similar construct), which provides methods to call operations on the server, because we use the Lite Application most often for demos and to make your life easier
客户端APIs包括了一个LitePeer ,提供了一些方法可以去调用服务端的操作,所以我们使用Lite 应用。
For example,
LitePeer.OpJoin
wraps up the call of operation
Join. The code below will call
OpJoin
when the connection is established:
例如,
LitePeer.OpJoin
概括了加入操作。以下是连接时调用加入的代码:
public
void
PeerStatusCallback(StatusCode returnCode)
{
// handle returnCodes for connect, disconnect and errors (non-operations)
switch
(returnCode)
{
case
StatusCode.Connect:
this
.DebugReturn(
"Connect(ed)"
);
this
.peer.OpJoin(
this
.gameID);
break
;
//[...]
The LitePeer covers all Lite Application operations this way.
Operation Results from Photon 来自Photon的操作结果
Per Operation, the application on the server can send a result. Imagine a
“GetHighscores”
operation and the use for a result becomes obvious and would contain a list of scores. Other RPCs, like RaiseEvent, can safely omit the result if it’s not useful.
每个操作,服务端上的应用程序都可以发送一个结果。想象一个
GetHighscores操作和使用结果成为显而易见的一个列表。其他的远程过程调用,像RaiseEvent,如果它不是有用的可以被安全的忽略掉。
Getting the result of an operation takes a moment in general, as there is network lag. That’s why any result is provided asynchronously by a call to
IPhotonPeerListener.OperationResult
获取操作的结果,一般都存在网络延迟,所以这是通过异步调用
IPhotonPeerListener.OperationResult
实现的
Per platform, the result callback might look different. The following code is from the C# callback interface, which a game must implement:
每个平台这回调的结果可能看起来有点不同。以下是C#代码必须要实现的接口
public
interface
IPhotonPeerListener
{
//[...]
void
OnOperationResponse(OperationResponse operationResponse);
The callback
OperationResult
is only called when your game calls
peer.DispatchIncomingCommands. This makes it easier to get the callback in the right thread context. In most cases it’s enough to call
DispatchIncomingCommands
every few frames in your game loop.
当你的程序调用
peer.DispatchIncomingCommands时回调
OperationResult 。这使得它容易获得回调在正确的线程上下文。在大部分情况下在你的游戏循环中定期调用
DispatchIncomingCommands
Custom Operations 自定义操作
Custom Operations are just Operations which are not defined by Exit Games in our applications (Lite, LoadBalancing, etc.). Basically, any operation that’s not covered by the LitePeer is “custom”.
自定义操作是一个没有定义在 Exit Games中的操作。基本上,任意操作不会覆盖LitePeer 的即是自定义的。
If you look behind the scenes you will see that even non-custom operations, like
Join, use the very same methods! As example, here is the code from
LitePeer Join:
以下是加入操作的代码示例:
public
virtual
bool
OpJoin(
string
gameName, Hashtable gameProperties, Hashtable actorProperties,
bool
broadcastActorProperties)
{
if
(
this
.DebugOut >= DebugLevel.ALL)
{
this
.Listener.DebugReturn(DebugLevel.ALL,
"OpJoin("
+ gameName +
")"
);
}
Dictionary<
byte
,
object
> opParameters =
new
Dictionary<
byte
,
object
>();
opParameters[(
byte
)LiteOpKey.GameId] = gameName;
if
(actorProperties !=
null
)
{
opParameters[(
byte
)LiteOpKey.ActorProperties] = actorProperties;
}
if
(gameProperties !=
null
)
{
opParameters[(
byte
)LiteOpKey.GameProperties] = gameProperties;
}
if
(broadcastActorProperties)
{
opParameters[(
byte
)LiteOpKey.Broadcast] = broadcastActorProperties;
}
return
this
.OpCustom((
byte
)LiteOpCode.Join, opParameters,
true
, 0,
false
);
}
As you can see,
OpJoin
internally uses
OpCustom
to be sent. The method is just a wrapper to streamline the usage. This is what you should do as well.
正如你看到的,
OpJoin 内部使用的是
OpCustom 。
The call to
OpCustom
shows the parts needed to send an operation:
调用
OpCustom 需要以下部分发送在一个操作里:
- OperationCode: A single byte to identify an operation (to minimize overhead). (byte)LiteOpCode.Join equals 255, as example.
-
- Operation Parameters: Is the set of parameters expected by the server. Again, bytes are used instead of names, to minimize overhead per parameter.
-
- Reliability: The third OpCustom parameter defines if the operation must arrive at the server or might become lost (unreliable). Data that’s replaced quickly can be unreliable. Join, Authentication or similar are better sent reliable (that’s why there’s a “true” in this case).
-
- ChannelId: Is the sequence, this operation is placed into for ordering. Can be 0 in most cases.
-
- Encrypt: Optionally encrypts data between the client and the server. Should be used only where definitely needed, as it takes away some performance and it not always needed. Here: false.
-
The latter three values are not exactly operation parts, obviously.
SendReliable,
ChannelId
and
Encrypt
are communication settings which can be changed on a per-operation basis.
后三个值不是必须的操作部分。
The byte codes for the operation, parameters and result values are defined on the server-side. To call it, you need to use those on the client correspondingly.
字节码操作、参数和结果值定义在服务器端。 调用它,你需要使用这些客户端相应的代码。
Operation-call Return Value 操作调用
For simplicity, we just ignored that
OpCustom
(
OpJoin
and all other operations) have a return value. However, it has a practical impact:
简单起见,我们仅仅忽略
OpCustom 的返回值,它包括以下值:
Depending on the current client state an operation might be impossible to call. The result of OpCustom tells you if the operation can be send or is ignored right away (client side):
- True: The operation is possible and will be sent to the server (by SendOutgoingCommands()). All values you passed to OpCustom are serialized now and you can modify your data at will.
-
- False: The operation can not be sent (e.g. because the client is not connected). If this happens, you should check the debug hints that the client library provides (see DebugReturn).
-
Defining New Operations 定义新的操作
In most cases, the definition of new operations is done server-side, so the process to implement and use those is explained in that context. Read: “
Adding Operations
”.