【发布时间】:2021-05-17 20:33:28
【问题描述】:
我在我的应用程序中同时使用了 Photon Pun2 和 Photon Chat 软件包。但是我找不到任何通过私信发送或接收图像、音频或视频的方法。
【问题讨论】:
标签: unity3d multiplayer photon
我在我的应用程序中同时使用了 Photon Pun2 和 Photon Chat 软件包。但是我找不到任何通过私信发送或接收图像、音频或视频的方法。
【问题讨论】:
标签: unity3d multiplayer photon
是的……但是,它非常有限。
你要寄的东西到底有多大?
在 Photon 聊天消息中,有效负载限制在 400.000 到 500.000 字节之间。我没有更详细地对其进行测试,但是如果您的消息大小达到某个限制,您将立即断开连接而没有适当的反馈,原因是^^
例子
public class MyChatListner : IChatClientListener
{
public event Action<byte[]> OnReceived;
private ChatClient cient;
public void Initialize()
{
client = new ChatClient(this);
client.ChatRegion = ...;
client.Connect(....);
}
// Sicne you already work with the chat you should know but anyway
// This has to be called continuously (who knows in what intervals)
public void Heartbeat()
{
client.Service();
}
public void SendData(string recipient, byte[] data)
{
client.SendPrivateMessage(recipient, data);
}
public void OnPrivateMessage(string sender, object message, string channelName)
{
OnReceived?.Invoke((byte[])message);
}
// also will have to implement the other methods from IChatClientListener ...
}
在 Pun2 中,我不知道是否存在这样的限制,但它肯定会延迟其他一切,直到文件完全接收。这里可以直接通过PhotonNetwork.RaiseEvent和OnEvent收发byte[](通过接口IOnEventCallback)
例子
// doesn't even have to be monobehaviour necessarily
public class FileTransmitter : IOnEventCallback
{
private const byte eventID = 42;
public event Action<byte[]> OnReceived;
public void Enable()
{
PhotonNetwork.AddCallbackTarget(this);
}
public void Disable()
{
PhotonNetwork.RemoveCallbackTarget(this);
}
public void SendData(byte[] data, SendOptions sendoptions, RaiseEventOptions raiseEventOptions = null)
{
PhotonNetwork.RaiseEvent(eventID, data, raiseEventOptions, sendoptions);
}
public void OnEvent(EventData photonEvent)
{
if(photonEvent.Code != eventID) return;
var data = (byte[]) photonEvent.CustomData;
OnReceived?.Invoke(data);
}
}
当然,您也可以直接使用RPC 并使用例如
public class FileTransfer : MonoBehaviourPun
{
[PunRPC]
void ChatMessage(string fileName, byte[] content)
{
// e.g.
File.WriteAllBytes(Path.Combine(Application.persistentDataPath, fileName), content);
}
public void SendFile(string fileName, byte[] content, PhotonPlayer targetPlayer)
{
photonView.RPC(nameof(ChatMessage), targetPlayer, fileName, content);
}
}
无论哪种方式,我个人所做的只是使用一个byte[] 并将所有必需的信息编码到其中。 Photon 无论如何都会使用所有参数执行此操作,但如果您已经确切知道您发送的数据以及如何反序列化它,那么您自己执行此操作会更有效,例如在线程/任务中。然后在接收方我再次将这些反序列化为个人信息。
【讨论】:
这是可能的并且工作得很好(即使你应该注意@derHugo 所说的限制)。我的实现使用 RPC 使用 Texture2D.EncodeToPNG 发送一个字节数组,然后在客户端收到它后对其进行解码。
要将字节数组转换回图像,可以使用Texture2D.LoadImage 方法。
发送其他多媒体类型的方法类似,只是编码/解码方法不同。
【讨论】:
PhotonStream 允许您通过网络传输任何 byte[] 数据。 理论上,任何数据类型都可以转换成byte[],并在接收端解码。
下面的示例脚本只是一个设置最少的示例。 参考自:https://frozenmist.com/docs/apis/fmetp-stream/pun2-example/
还可以使用流行的第三方插件(如 FMETP STREAM)实时流式传输视频、音频和远程命令,该插件具有本机快速编码器,可实时捕获您的游戏视图和桌面视图,甚至与移动和 VR 设备兼容。
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// ref: https://frozenmist.com/docs/apis/fmetp-stream/pun2-example/
public class FMStreamPUN : Photon.Pun.MonoBehaviourPun, IPunObservable {
private Queue<byte[]> appendQueueSendData = new Queue<byte[]>();
public int appendQueueSendDataCount { get { return appendQueueSendData.Count; } }
public UnityEventByteArray OnDataByteReadyEvent = new UnityEventByteArray();
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
//Send the meta data of the byte[] queue length
stream.SendNext(appendQueueSendDataCount);
//Sending the queued byte[]
while(appendQueueSendDataCount > 0) {
byte[] sentData = appendQueueSendData.Dequeue();
stream.SendNext(sentData);
}
}
if (stream.IsReading) {
if (!photonView.IsMine) {
//Get the queue length
int streamCount = (int)stream.ReceiveNext();
for (int i = 0; i < streamCount; i++) {
//reading stream one by one
byte[] receivedData = (byte[])stream.ReceiveNext();
OnDataByteReadyEvent.Invoke(receivedData);
}
}
}
}
public void Action_SendData(byte[] inputData) {
//inputData(byte[]) is the encoded byte[] from your encoder
//doesn't require any stream, when there is only one player in the room
if(PhotonNetwork.CurrentRoom.PlayerCount > 1) appendQueueSendData.Enqueue(inputData);
}
}
【讨论】: