我在官方的Photon Server论坛上问过这个问题,但它不如本网站那么活跃,所以可能会有人理解我在说什么,所以请你,如果你有时间和知识,分享它。谢谢!
这里来......
所以,我在Photon上有一个非常好的服务器工作原型和一个与服务器对话的基本Unity3D客户端。 它是根据cjrgaming上的示例构建的。
客户端可以:连接,发送请求,建立和发送加密请求 服务器可以:创建对等体,接收操作请求,向客户端发送操作响应或事件,以及我的小添加: 如果一个游戏有很多操作,你不必使用一个巨大的switch case语句,而是我将操作划分为类别(Classes),并通过使用委托和字典来调用它们。
当我觉得它已准备好发布时,我会发布一个有效的例子,但现在,我的实际问题......(对不起,我不得不解释我所知道的内容和内容。我到目前为止):
从客户端发送到服务器的实际操作是什么? 或者服务器向客户端提出的事件(所有客户端一次性?)?
起初,我认为每个操作都是游戏中特定的用户流程。例如,操作代码" 1",表示玩家X想要射击玩家Y,做某事。 但是,我意识到,根据字节数限制,你不能将所有游戏逻辑放在255个操作中,而不是将其扩展为short int或其他东西。
然后我发现那里还有一个channelID,在同一个操作代码请求中可能会有所不同......这对我来说,操作代码不是用户流,而是一个数据流客户端和服务器之间的相同/类似操作,channelID可用于区分要在服务器上计算的请求操作。
然后...!我意识到(哦,假我),从客户端发送到服务器的参数,反之亦然在字典中,这增加了另一层可能的用户流。
所以..现在我想要理解事情,但他们只是让我更加困惑。
有人可以简单解释一下操作/事件/ channelID的用途吗? 例如,如果您进行小型多人游戏,您将使用什么来制作用户(游戏)流程,例如 - >玩家击中目标,玩家在世界中拾取物品,玩家发送消息。您是否会为每个流使用唯一的操作代码,或者您是按意义分组操作并使用通道来区分请求,或者甚至在这里,您对许多用户流使用相同的channelID并使用参数中的某些ID来区分它们?
希望我有任何意义。
非常感谢大家,至少,如果有的话,请帮助!
答案 0 :(得分:14)
1) 频道是一个完全不同的主题,与区分您想要触发的不同类型的游戏逻辑无关。相反,如果操作依赖于另一个操作,那么通道用于确定优先级和状态。
A) 如果您发送拍摄操作和2个聊天操作,并且由于客户端的网络连接不是最好的,那么第一条聊天消息会在途中丢失,但正如您所声称的那样可靠地发送当服务器未确认时,Photon客户端将自动重新发送它已收到它。现在另一个聊天消息应该由Photon阻止,直到第一个成功发送,否则来自同一作者的显示的聊天消息的顺序将不再是他们已经写入的那个。现在的问题是,不仅应该阻止相同类型的操作,而且可能还有其他操作,只应在丢失的操作重复之后发送(例如“用户离开的可见结果”聊天“操作不应该显示在屏幕上,直到他最后一次聊天消息之后,他已经离开前发送了。另一方面,并非所有相同类型的操作都必须被阻止。例如,玩家可以私下与2个不同的其他用户交谈,并且当其中一个用户的一条消息没有立即通过时,则没有理由将所有消息保持到另一个消息。光子解决这个问题的方法是:在同一个通道中发送所有依赖于彼此的操作,但在另一个通道中发送独立于它们的操作。如果现在必须重复其中一个操作,其他通道中的操作将不会被阻止,但同一通道中的操作将会被阻止。
b)中 另一种通道方式是确定优先级:通道ID越低,优先级越高。因此,如果您有一些少量的高优先级数据和其他数据,这些数据只有较低的优先级,但可能会出现大量数据,那么在较低的通道上发送高优先级数据会是一个好主意。信道ID。这样它仍然可以立即退出,虽然在ID较高的频道中,可能有很多数据已经排队等待发送,但尚未发送。
2) 操作和事件都是消息。实际上有三种类型的消息:operationRequest,operationResponse和event。
A) 客户端可以通过PhotonPeer.opCustom()向服务器发送带有特定操作代码的operationRequest。一些典型的操作,如加入和离开房间,已经通过Photon应用程序层(如Lite或LoadBalancing应用程序)的应用程序实现。如果为Photon应用程序提供了客户端API,那么此API可以提供开箱即用的opJoin()函数,它使用正确的参数将调用包装到opCustom(),就像上面提到的应用程序的客户端API一样做。
b)中 根据在应用程序级别上如何实现具有某个代码的操作,服务器可能会向客户端发送operationResponse,并从该客户端收到operationReqeust。例如,LitePeer.opJoin()将从服务器触发连接响应,但LitePeer.opRaiseEvent不会触发响应。
c)中 根据在应用程序级别上实现操作的方式,服务器可能会也可能不会将事件发送到某些客户端。例如,LitePeer.opJoin()将触发一个join事件,该事件将被发送给该房间中的所有玩家。 LitePeer.opRaiseEvent()将默认让服务器为同一房间中除发送服务器之外的所有客户端引发一个事件,即保存已传递给它的有效负载。但是,opRaiseEvent()为其调用客户端提供了指定接收客户端的可能性。
3) “玩家击中目标,玩家拿起世界上的物品,玩家发送消息” 如果您需要任何特殊的服务器端逻辑,那么您可以使用不同的代码将它们实现为自己的操作。如果不是这种情况,那么您将使用opRaiseEvent()发送这些信息,但是您仍然会为每个信息指定不同的eventCode。但是,operation和eventCodes旨在用于区分不同类型的信息,比如聊天消息,点击,位置更新等等。因此,玩家a告诉玩家b他已经击中了玩家c并且玩家b告诉玩家d,他已经击中了玩家d,他们都使用相同的代码。关于哪个玩家被击中的信息 - 与击中或使用哪种武器的难度相同 - 都属于操作的有效载荷。因此,您可以将播放器的玩家ID,已被击中,弹药类型以及丢失的生命能量作为有效负载传递给opRaiseEvent()或opCustom()。