增加自定义不是房间的消息发送

This commit is contained in:
2026-05-18 23:31:04 +08:00
parent ce9b1e85e9
commit 3daebf56ab
29 changed files with 2375 additions and 356 deletions

View File

@@ -5,6 +5,7 @@ using UnityEngine;
public interface IGlobalConfigSystem : ISystem
{
public string IP { get; }
public string GetConnectionId();
public void SetConnectionId(string connectionId);
@@ -21,6 +22,9 @@ public interface IGlobalConfigSystem : ISystem
public Texture2D GetConnectionTexture();
public void SetConnectionTexture(Texture2D connectionTexture);
public string GetUserId();
public void SetUserId(string userId);
}
public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
@@ -53,11 +57,19 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
private CancellationTokenSource _cts;
/// <summary>
/// 连接ID
/// </summary>
private string _userId;
public override void Dispose()
{
}
public string IP => "http://127.0.0.1:8080";
public string GetConnectionId()
{
if (string.IsNullOrEmpty(_connectionId))
@@ -143,6 +155,22 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
_connectionTexture = connectionTexture;
}
public string GetUserId()
{
if (string.IsNullOrEmpty(_userId))
{
Debug.LogWarning("GlobalConfigSystem: GetUserId not set");
return "";
}
return _userId;
}
public void SetUserId(string userId)
{
_userId = userId;
}
protected override void OnInit()
{
}

View File

@@ -1,3 +1,4 @@
using System.Net;
using RenderStreaming;
using Stary.Evo;
using Stary.Evo.UIFarme;
@@ -8,6 +9,11 @@ public class Main : MonoBehaviour, IController
{
private void Start()
{
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) =>
{
return true; // 信任所有证书,仅开发环境使用
};
this.GetSystem<IPanelSystem>().PushQueue<StartPanel>();
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1645e864f3c440ea9e6155be8f97d045
timeCreated: 1779019467

View File

@@ -0,0 +1,201 @@
using System;
using System.Collections;
using System.IO;
using RenderStreaming;
using Stary.Evo;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
namespace Script
{
public class ContactEntryController : MonoBehaviour, IController
{
private Transform _background;
private Transform _backgroundName;
private GameObject _confirmBtnTime;
private Text _confirmBtnTimeText;
private Button _confirmButton;
private bool _isCountingDown;
private MeetingContacts _meetingContacts;
private Transform _messageText;
private Transform _nameText;
private MeetingContacts.UsersItem _usersItem;
private void OnDestroy()
{
StopAllCoroutines();
_isCountingDown = false;
}
public IArchitecture GetArchitecture()
{
return MainArchitecture.Interface;
}
public void SetData(MeetingContacts.UsersItem item, MeetingContacts meetingContactsController)
{
_usersItem = item;
_meetingContacts = meetingContactsController;
///头像赋值
if (string.IsNullOrEmpty(item.avatar))
{
var randomColor = GetRandomColor();
_background = transform.Find("headBackground");
if (_background != null)
{
var image = _background.GetComponent<Image>();
if (image != null) image.color = randomColor;
}
_backgroundName = _background.transform.Find("Name");
if (_backgroundName != null)
{
var textComponent = _backgroundName.GetComponent<Text>();
if (textComponent != null && !string.IsNullOrEmpty(item.name))
textComponent.text = item.name.Substring(0, 1);
}
}
else
{
_background = transform.Find("headBackground");
if (_background != null)
{
var imageComponent = _background.GetComponent<Image>();
if (imageComponent != null) DownloadAndSetAvatar(item.avatar, imageComponent);
}
_backgroundName = _background.transform.Find("Name");
if (_backgroundName != null) _backgroundName.GetComponent<Text>().text = "";
}
if (!string.IsNullOrEmpty(item.name))
_nameText = transform.Find("Name");
if (_nameText != null)
{
var textComponent = _nameText.GetComponent<Text>();
if (textComponent != null) textComponent.text = item.name;
}
if (!string.IsNullOrEmpty(item.userId))
{
_messageText = transform.Find("Message");
if (_messageText != null)
{
var textComponent = _messageText.GetComponent<Text>();
if (textComponent != null) textComponent.text = item.userId;
}
}
if (!string.IsNullOrEmpty(item.role))
{
var role = item.role;
var idle = transform.Find("Name/state/idle");
var participant = transform.Find("Name/state/participant");
var host = transform.Find("Name/state/host");
if (role.Equals("host"))
{
host.gameObject.SetActive(true);
participant.gameObject.SetActive(false);
idle.gameObject.SetActive(false);
}
else if (role.Equals("participant"))
{
participant.gameObject.SetActive(true);
host.gameObject.SetActive(false);
idle.gameObject.SetActive(false);
}
else if (role.Equals("idle"))
{
idle.gameObject.SetActive(true);
host.gameObject.SetActive(false);
participant.gameObject.SetActive(false);
}
}
_confirmButton = transform.Find("callBtn").GetComponent<Button>();
_confirmButton.onClick.AddListener(OnClickEntry);
_confirmBtnTime = _confirmButton.transform.Find("timebg").gameObject;
_confirmBtnTimeText = _confirmBtnTime.transform.Find("Text").GetComponent<Text>();
_confirmBtnTime.gameObject.SetActive(false);
}
private void OnClickEntry()
{
if (_isCountingDown)
{
Debug.Log("倒计时进行中,无法点击");
return;
}
Debug.Log($"点击了联系人: {_usersItem.name}");
// 这里可以添加点击联系人后的逻辑,比如打开聊天窗口
// 或者发送邀请请求等
_meetingContacts.ClickContactEntry(_background.GetComponent<Image>().sprite,
_backgroundName.GetComponent<Text>().text, _usersItem);
_meetingContacts.CurrentEntry = this;
}
public void StartCountdown()
{
if (_isCountingDown) return;
_isCountingDown = true;
_confirmButton.interactable = false;
_confirmBtnTime.gameObject.SetActive(true);
StartCoroutine(CountdownCoroutine(50));
}
private IEnumerator CountdownCoroutine(int seconds)
{
Debug.Log($"开始{seconds}秒倒计时");
for (var i = seconds; i >= 0; i--)
{
_confirmBtnTimeText.text = i.ToString();
Debug.Log($"倒计时: {i}秒");
yield return new WaitForSeconds(1);
}
Debug.Log("倒计时结束");
_isCountingDown = false;
_confirmButton.interactable = true;
_confirmBtnTime.gameObject.SetActive(false);
}
private Color GetRandomColor()
{
return new Color(
Random.Range(0.2f, 0.8f),
Random.Range(0.2f, 0.8f),
Random.Range(0.2f, 0.8f),
1f
);
}
private async void DownloadAndSetAvatar(string avatarUrl, Image targetImage)
{
try
{
var tempPath = Path.Combine(Application.temporaryCachePath, $"avatar_{Guid.NewGuid()}.png");
var result = await WebRequestSystem.GetFile(avatarUrl, tempPath);
if (result.code == 200)
{
var bytes = File.ReadAllBytes(tempPath);
var texture = new Texture2D(2, 2);
texture.LoadImage(bytes);
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height),
Vector2.one * 0.5f);
targetImage.sprite = sprite;
File.Delete(tempPath);
}
}
catch (Exception e)
{
Debug.LogError($"下载头像失败: {e.Message}");
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c16475152291466fa053f892d1ec0c8b
timeCreated: 1779100629

View File

@@ -17,6 +17,8 @@ namespace Script
/// </summary>
private Text _idText;
private MeetingContacts _meetingContacts;
/// <summary>
/// 房间人数
/// </summary>
@@ -36,7 +38,6 @@ namespace Script
public override string UIPath => "Canvas";
public override void Initialize(GameObject panelGo)
{
base.Initialize(panelGo);
@@ -45,11 +46,14 @@ namespace Script
_arrowLeft = panelGo.transform.Find("Header/arrow-left").GetComponent<Button>();
_idText = panelGo.transform.Find("MeetingInfoCard/meeting/id").GetComponent<Text>();
_roomPeopleNumText = panelGo.transform.Find("MeetingInfoCard/numberOfPeople/number").GetComponent<Text>();
_meetingContacts = new MeetingContacts();
_meetingContacts.Initialize(panelGo.transform.Find("MeetingContacts").gameObject);
}
public override void OnEnter(Action complete = null)
{
base.OnEnter(complete);
_meetingContacts.OnEnter();
_arrowLeft.onClick.AddListener(OnArrowLeftClick);
}
@@ -57,6 +61,7 @@ namespace Script
public override void OnExit(float delay = 0)
{
base.OnExit(delay);
_meetingContacts.OnExit();
_arrowLeft.onClick.RemoveListener(OnArrowLeftClick);
}

View File

@@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using RenderStreaming;
using Stary.Evo;
using Unity.RenderStreaming;
using UnityEngine;
using UnityEngine.UI;
namespace Script
{
public class MeetingContacts : IController
{
/// <summary>
/// 联系人列表项字典
/// Key: 参与者ID
/// Value: 联系人列表项实例
/// </summary>
private readonly Dictionary<GameObject, ContactEntryController> _contactEntries = new();
private Image _avatarImage;
private Button _cancelButton;
private Button _confirmButton;
private GameObject _confirmingPop;
/// <summary>
/// 联系人列表项预制体
/// </summary>
private GameObject _contactEntryPrefab;
/// <summary>
/// 全部联系人列表容器
/// </summary>
private Transform _content;
private Text _idText;
private InputField _leaveMessage;
private Text _messageText;
private Text _nameText;
private GameObject _panelGo;
public ContactEntryController CurrentEntry { get; set; }
public IArchitecture GetArchitecture()
{
return MainArchitecture.Interface;
}
public void Initialize(GameObject panelGo)
{
_panelGo = panelGo;
_contactEntryPrefab = Resources.Load<GameObject>("ContactEntry");
_content = _panelGo.transform.Find("MeetingGrid/Viewport/Content");
//邀请界面
_confirmingPop = _panelGo.transform.Find("MeetingGrid/ConfirmingPop").gameObject;
_confirmingPop.SetActive(false);
//确认邀请
_idText = _confirmingPop.transform.Find("bg/id").GetComponent<Text>();
_leaveMessage = _confirmingPop.transform.Find("bg/leaveMessage").GetComponent<InputField>();
_confirmButton = _confirmingPop.transform.Find("bg/invite").GetComponent<Button>();
_cancelButton = _confirmingPop.transform.Find("bg/cancel").GetComponent<Button>();
_avatarImage = _confirmingPop.transform.Find("ParticipantEntry/head").GetComponent<Image>();
_nameText = _confirmingPop.transform.Find("ParticipantEntry/Name").GetComponent<Text>();
_messageText = _confirmingPop.transform.Find("ParticipantEntry/Message").GetComponent<Text>();
}
public async void OnEnter()
{
var response =
await WebRequestSystem.Get<ResponseUsers>(this.GetSystem<IGlobalConfigSystem>().IP, "/signaling/users");
if (response != null && response.totalCount > 0)
for (var i = 0; i < response.totalCount; i++)
{
var item = response.users[i];
if (string.IsNullOrEmpty(item.name) ||
string.IsNullOrEmpty(item.userId)) continue;
var entry = GameObject.Instantiate(_contactEntryPrefab, _content);
var contactEntryController = entry.GetOrAddComponent<ContactEntryController>();
contactEntryController.SetData(item, this);
}
}
public void OnExit()
{
}
public void ClickContactEntry(Sprite avatarImage, string name, UsersItem item)
{
_confirmingPop.SetActive(true);
_idText.text = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
_avatarImage.sprite = avatarImage;
var avatarName = _avatarImage.transform.Find("Name").GetComponent<Text>();
avatarName.text = name;
_nameText.text = item.name;
_messageText.text = item.userId;
_confirmButton.onClick.AddListener(() =>
{
_confirmingPop.SetActive(false);
CurrentEntry.StartCountdown();
// var avatar = _profileImage.sprite.name.Replace("(Clone)", "");
var userInfo = new
{
type = "invite-call",
data = new
{
connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId(),
targetSocketId = item.socketId,
targetUserId = item.userId,
inviterUserId = this.GetSystem<IGlobalConfigSystem>().GetUserId(),
inviterName = this.GetSystem<IGlobalConfigSystem>().GetConnectionName(),
inviterAvatar =
$"{this.GetSystem<IGlobalConfigSystem>().IP}/images/head/" +
$"{this.GetSystem<IGlobalConfigSystem>().GetConnectionTexture().name}.png"
}
};
SignalingMessageHelper.SendMessage(JsonConvert.SerializeObject(userInfo));
});
_cancelButton.onClick.AddListener(() =>
{
_confirmingPop.SetActive(false);
CurrentEntry = null;
});
}
public class ContactEntryData
{
public string avatar;
public GameObject entry;
public Toggle invitationTog;
public string name;
public string participantId;
public string role;
}
[Serializable]
public class ResponseUsers
{
/// <summary>
/// </summary>
public List<UsersItem> users { get; set; }
/// <summary>
/// </summary>
public int totalCount { get; set; }
}
[Serializable]
public class UsersItem
{
/// <summary>
/// </summary>
public string socketId { get; set; }
/// <summary>
/// </summary>
public string connectionId { get; set; }
/// <summary>
/// </summary>
public string participantId { get; set; }
/// <summary>
/// </summary>
public string role { get; set; }
/// <summary>
/// </summary>
public string userId { get; set; }
/// <summary>
/// </summary>
public string name { get; set; }
/// <summary>
/// </summary>
public string avatar { get; set; }
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 05ce391aaa7a4698941ba9f6b0157614
timeCreated: 1779019493

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Script;
using Stary.Evo;
using Stary.Evo.UIFarme;
@@ -91,6 +92,24 @@ namespace Unity.RenderStreaming
public override void Initialize(GameObject panelGo)
{
base.Initialize(panelGo);
_arrowLeft = panelGo.transform.Find("Herder/arrow-left").GetComponent<Button>();
_profilePhoto = panelGo.transform.Find("HeadPortraits/MeetingInfoCard").GetComponent<Button>();
_profileImage = _profilePhoto.transform.Find("mask/sprite").GetComponent<Image>();
_meetingNameInput = panelGo.transform.Find("card/search/InputField").GetComponent<InputField>();
_meetingId = panelGo.transform.Find("card/huiyiID/connectionId").GetComponent<Text>();
_randomMeetingId = panelGo.transform.Find("card/huiyiID/Button").GetComponent<Button>();
_timeDropdown = panelGo.transform.Find("card/time/Dropdown").GetComponent<Dropdown>();
_startButton = panelGo.transform.Find("invite").GetComponent<Button>();
_spriteAtlas = Resources.Load<SpriteAtlas>("SpriteAtlas");
if (_spriteAtlas != null)
{
_profileSprites = new Sprite[_spriteAtlas.spriteCount];
_spriteAtlas.GetSprites(_profileSprites);
}
_profileSpriteIndex = 0;
OnClickProfilePhoto();
renderStreaming = GameObject.FindObjectOfType<SignalingManager>();
hostConnection = GameObject.FindObjectOfType<HostConnection>();
videoStreamSender = hostConnection.GetComponent<VideoStreamSender>();
@@ -110,23 +129,6 @@ namespace Unity.RenderStreaming
if (settings?.SignalingSettings != null)
renderStreaming.SetSignalingSettings(settings.SignalingSettings);
renderStreaming.Run();
_arrowLeft = panelGo.transform.Find("Herder/arrow-left").GetComponent<Button>();
_profilePhoto = panelGo.transform.Find("HeadPortraits/MeetingInfoCard").GetComponent<Button>();
_profileImage = _profilePhoto.transform.Find("mask/sprite").GetComponent<Image>();
_meetingNameInput = panelGo.transform.Find("card/search/InputField").GetComponent<InputField>();
_meetingId = panelGo.transform.Find("card/huiyiID/connectionId").GetComponent<Text>();
_randomMeetingId = panelGo.transform.Find("card/huiyiID/Button").GetComponent<Button>();
_timeDropdown = panelGo.transform.Find("card/time/Dropdown").GetComponent<Dropdown>();
_startButton = panelGo.transform.Find("invite").GetComponent<Button>();
_spriteAtlas = Resources.Load<SpriteAtlas>("SpriteAtlas");
if (_spriteAtlas != null)
{
_profileSprites = new Sprite[_spriteAtlas.spriteCount];
_spriteAtlas.GetSprites(_profileSprites);
}
_profileSpriteIndex = 0;
OnClickProfilePhoto();
}
public override void OnEnter(Action complete = null)
@@ -183,13 +185,38 @@ namespace Unity.RenderStreaming
if (string.IsNullOrEmpty(_meetingNameInput.text)) _meetingNameInput.text = $"{meetingId}的房间";
}
private string OnClickRandomUserId()
{
return $"user_{Random.Range(100, 999)}";
}
private void OnClickStartButton()
{
this.GetSystem<IGlobalConfigSystem>().SetUserId(OnClickRandomUserId());
this.GetSystem<IGlobalConfigSystem>().SetConnectionTimeType(_timeDropdown.value);
this.GetSystem<IGlobalConfigSystem>().SetConnectionId(_meetingId.text);
hostConnection.RoomConnectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
this.GetSystem<IGlobalConfigSystem>().SetConnectionName(_meetingNameInput.text);
this.GetSystem<IGlobalConfigSystem>().SetConnectionTexture(Texture2D.whiteTexture);
this.GetSystem<IGlobalConfigSystem>().SetConnectionTexture(_profileImage.sprite.texture);
if (!SignalingMessageHelper.IsReady())
{
Debug.LogError("Signaling 未就绪");
return;
}
var avatar = _profileImage.sprite.name.Replace("(Clone)", "");
var userInfo = new
{
type = "host-userInfo",
data = new
{
connectionId = hostConnection.RoomConnectionId,
id = this.GetSystem<IGlobalConfigSystem>().GetUserId(),
name = _meetingNameInput.text,
avatar = $"{this.GetSystem<IGlobalConfigSystem>().IP}/images/head/{avatar}.png"
}
};
SignalingMessageHelper.SendMessage(JsonConvert.SerializeObject(userInfo));
SetUp();
PanelSystem.PopQueue<StartPanel>();
PanelSystem.PushQueue<MainPanel>();

View File

@@ -0,0 +1,509 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
namespace Stary.Evo
{
public static class WebRequestSystem
{
private static string authorization;
static WebRequestSystem()
{
#if UNITY_EDITOR
authorization = CustomEditorPrefs.GetString("Authorization");
#else
authorization = CustomPlayerPrefs.GetString("Authorization");
#endif
}
public static async Task<bool> Login(string url, string username, string password)
{
var data = new
{
username,
password,
roleType = "client"
};
var postData = JsonConvert.SerializeObject(data);
try
{
using var webRequest = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
webRequest.downloadHandler = new DownloadHandlerBuffer();
if (string.IsNullOrEmpty(postData))
{
Debug.LogError("WebRequestSystem.Login postData is null");
return false;
}
var postBytes = Encoding.UTF8.GetBytes(postData);
webRequest.uploadHandler = new UploadHandlerRaw(postBytes);
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.timeout = 10;
await webRequest.SendWebRequest();
webRequest.uploadHandler?.Dispose();
// 更新错误检查方式
if (webRequest.result == UnityWebRequest.Result.ConnectionError ||
webRequest.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(webRequest.error);
}
else
{
var authResponse =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
Debug.Log("UnityEvo:ResultMessageEntity" + authResponse.data);
if (authResponse.code == 200)
{
var authResponseData =
JsonConvert.DeserializeObject<AuthenticationResponse>(authResponse.data.ToString());
Debug.Log("UnityEvo:AuthenticationResponse" + authResponseData.Token);
authorization = authResponseData.Token;
#if UNITY_EDITOR
CustomEditorPrefs.SetString("Authorization", authorization);
#else
CustomPlayerPrefs.SetString("Authorization",authorization);
#endif
Debug.Log("UnityEvo:登录成功");
return true;
}
}
return false;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Login" + e.Message);
return false;
}
}
/// <summary>
/// GET请求数据
/// </summary>
/// <param name="url">请求数据的URL地址</param>
/// <param name="token">token验证的参数此处为authorization</param>
/// <returns></returns>
public static async Task<bool> GetValidateToken(string url)
{
#if UNITY_EDITOR
authorization = CustomEditorPrefs.GetString("Authorization");
#else
authorization = CustomPlayerPrefs.GetString("Authorization");
#endif
try
{
using var webRequest =
new UnityWebRequest($"{url}?token={authorization}", UnityWebRequest.kHttpVerbGET);
//using UnityWebRequest webRequest = UnityWebRequest.Get($"{url}?token={authorization}");
webRequest.downloadHandler = new DownloadHandlerBuffer();
webRequest.timeout = 10;
await webRequest.SendWebRequest();
// 增强错误处理
if (webRequest.result != UnityWebRequest.Result.Success)
{
var errorMsg = $"HTTP {webRequest.responseCode}\n" +
$"URL: {url}\n" +
$"Error: {webRequest.error}\n" +
$"Response: {webRequest.downloadHandler.text}";
Debug.LogError(errorMsg);
return false;
}
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code == 200)
return true; // 添加返回值
return false;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.GetValidateToken" + e.Message);
return false;
}
}
/// <summary>
/// POST请求数据
/// </summary>
/// <param name="url">获取Token值的服务URL地址很重要</param>
/// <param name="postData">传入请求的参数此处参数为JOSN格式</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> PostFile(string url, string[] path,
Dictionary<string, string> headers = null, Action<float> uploadProgress = null)
{
//UnityWebRequest[] files = new UnityWebRequest[3];
var form = new WWWForm();
for (var i = 0; i < path.Length; i++)
{
var bytes = await File.ReadAllBytesAsync(path[i]);
form.AddBinaryData("files[]", bytes, Path.GetFileName(path[i]));
}
try
{
using var webRequest = UnityWebRequest.Post(url, form);
webRequest.SetRequestHeader("Authorization", authorization);
if (headers != null)
foreach (var header in headers)
webRequest.SetRequestHeader(header.Key, header.Value);
webRequest.disposeUploadHandlerOnDispose = true;
webRequest.disposeDownloadHandlerOnDispose = true;
webRequest.disposeCertificateHandlerOnDispose = true;
webRequest.timeout = 60;
// 发送请求但不等待完成
var operation = webRequest.SendWebRequest();
// 轮询获取上传进度
while (!operation.isDone)
{
// 调用进度回调函数
uploadProgress?.Invoke(webRequest.uploadProgress);
// 等待一帧,避免阻塞
await UniTask.Yield();
}
webRequest.uploadHandler?.Dispose();
// 更新错误检查方式
if (webRequest.result == UnityWebRequest.Result.ConnectionError ||
webRequest.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(webRequest.error);
return new ResultMessageEntity
{
code = 5001,
message = webRequest.error
};
}
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code != 200) Debug.LogError("上传异常,无文件数据返回!!");
return resultMessageEntity;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.PostFile" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
}
}
/// <summary>
/// GET请求数据
/// </summary>
/// <param name="url">请求数据的URL地址</param>
/// <param name="token">token验证的参数此处为authorization</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> GetFile(string url, string tempPath,
Action<float> downloadProgress = null)
{
try
{
using var webRequest = UnityWebRequest.Get(url);
webRequest.downloadHandler = new DownloadHandlerFile(tempPath);
if (authorization != null)
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
var operation = webRequest.SendWebRequest();
while (!operation.isDone)
{
downloadProgress?.Invoke(webRequest.downloadProgress);
await UniTask.Yield();
}
// 增强错误处理
if (webRequest.result != UnityWebRequest.Result.Success)
{
var errorMsg = $"HTTP {webRequest.responseCode}\n" +
$"URL: {url}\n" +
$"Error: {webRequest.error}\n";
Debug.LogError(errorMsg);
return new ResultMessageEntity
{
code = 5001,
message = errorMsg
};
}
return new ResultMessageEntity
{
code = 200,
message = "下载成功"
};
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.GetFile" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
}
}
/// <summary>
/// GET请求数据
/// 携带数据:否
/// 幂等性:是
/// </summary>
/// <param name="url">请求数据的URL地址</param>
/// <param name="path">请求数据的路径</param>
/// <returns></returns>
public static async Task<T> Get<T>(string url, string path)
{
try
{
var fullUrl = url.TrimEnd('/') + "/" + path.TrimStart('/');
using var webRequest = new UnityWebRequest(fullUrl, UnityWebRequest.kHttpVerbGET);
webRequest.downloadHandler = new DownloadHandlerBuffer();
if (authorization != null)
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
webRequest.timeout = 20;
await webRequest.SendWebRequest();
// 增强错误处理
if (webRequest.result != UnityWebRequest.Result.Success)
{
var errorMsg = $"HTTP {webRequest.responseCode}\n" +
$"URL: {url}\n" +
$"Error: {webRequest.error}\n" +
$"Response: {webRequest.downloadHandler.text}";
Debug.LogError(errorMsg);
}
var resultMessageEntity =
JsonConvert.DeserializeObject<T>(webRequest.downloadHandler.text);
return resultMessageEntity;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Get" + e.Message);
}
return default;
}
/// <summary>
/// POST请求数据
/// 携带数据:是
/// 幂等性:否
/// </summary>
/// <param name="url">获取Token值的服务URL地址很重要</param>
/// <param name="postData">传入请求的参数此处参数为JOSN格式</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> Post(string url, string postData)
{
try
{
using var webRequest = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
// #if UNITY_2021_3_OR_NEWER
// using (UnityWebRequest webRequest = UnityWebRequest.PostWwwForm(url, postData)) //第二种写法此行注释
// #else
// using (UnityWebRequest webRequest = UnityWebRequest.PostWwwForm(url, postData)) //第二种写法此行注释
// #endif
webRequest.downloadHandler = new DownloadHandlerBuffer();
var postBytes = Encoding.UTF8.GetBytes(postData);
webRequest.uploadHandler = new UploadHandlerRaw(postBytes);
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SetRequestHeader("Authorization", authorization);
webRequest.disposeUploadHandlerOnDispose = true;
webRequest.disposeDownloadHandlerOnDispose = true;
webRequest.disposeCertificateHandlerOnDispose = true;
webRequest.timeout = 30;
await webRequest.SendWebRequest();
webRequest.uploadHandler?.Dispose();
// 更新错误检查方式
if (webRequest.result == UnityWebRequest.Result.ConnectionError ||
webRequest.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(webRequest.error);
return new ResultMessageEntity
{
code = 5001,
message = webRequest.error
};
}
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code != 200) Debug.LogError(resultMessageEntity.message);
return resultMessageEntity;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Post" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
}
}
/// <summary>
/// Delete请求数据
/// 携带数据:否
/// 幂等性:是
/// </summary>
/// <param name="url">请求数据的URL地址</param>
/// <param name="path">请求数据的路径</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> Delete(string url, string path)
{
try
{
// 修复URL拼接
var fullUrl = url.TrimEnd('/') + "/" + path.TrimStart('/');
using var webRequest = new UnityWebRequest(fullUrl, UnityWebRequest.kHttpVerbDELETE);
webRequest.downloadHandler = new DownloadHandlerBuffer();
if (authorization != null)
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
webRequest.timeout = 20;
await webRequest.SendWebRequest();
// 增强错误处理
if (webRequest.result != UnityWebRequest.Result.Success)
{
var errorMsg = $"HTTP {webRequest.responseCode}\n" +
$"URL: {url}\n" +
$"Error: {webRequest.error}\n" +
$"Response: {webRequest.downloadHandler.text}";
Debug.LogError(errorMsg);
return new ResultMessageEntity
{
code = 5001,
message = errorMsg
};
}
// 修复空响应处理
var responseText = webRequest.downloadHandler.text;
if (string.IsNullOrEmpty(responseText))
return new ResultMessageEntity
{
code = 200,
message = "删除成功"
};
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code != 200) Debug.LogError(resultMessageEntity.message);
return resultMessageEntity;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Get" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
}
}
/// <summary>
/// PUT请求数据
/// 携带数据:是
/// 幂等性:是
/// </summary>
/// <param name="url">请求数据的URL地址</param>
/// <param name="path">请求数据的路径</param>
/// <param name="putData">要更新的数据JSON格式</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> Put(string url, string putData)
{
try
{
// 修复URL拼接
using var webRequest = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPUT);
// 设置上传处理器
var putBytes = Encoding.UTF8.GetBytes(putData);
webRequest.uploadHandler = new UploadHandlerRaw(putBytes);
webRequest.downloadHandler = new DownloadHandlerBuffer();
// 设置请求头
webRequest.SetRequestHeader("Content-Type", "application/json");
if (authorization != null)
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
webRequest.timeout = 20;
await webRequest.SendWebRequest();
// 增强错误处理
if (webRequest.result != UnityWebRequest.Result.Success)
{
var errorMsg = $"HTTP {webRequest.responseCode}\n" +
$"URL: {url}\n" +
$"Error: {webRequest.error}\n" +
$"Response: {webRequest.downloadHandler.text}";
Debug.LogError(errorMsg);
return new ResultMessageEntity
{
code = 5001,
message = errorMsg
};
}
// 处理空响应
var responseText = webRequest.downloadHandler.text;
if (string.IsNullOrEmpty(responseText))
return new ResultMessageEntity
{
code = 200,
message = "更新成功"
};
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code != 200) Debug.LogError(resultMessageEntity.message);
return resultMessageEntity;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Put" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1c54940c4eaf5c34c8b143ec9c131d53
timeCreated: 1741230908

View File

@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
@@ -11,17 +10,14 @@ namespace Unity.RenderStreaming
{
public class MessageChannel : DataChannelBase
{
public event Action<string, UserInfo> OnUserInfoMessageReceived;
public event Action<string, MediaStateChange> OnMediaStateChangeReceived;
private const int MAX_HISTORY = 100;
[Header("消息记录")] [SerializeField, TextArea(1, 3)]
[Header("消息记录")] [SerializeField] [TextArea(1, 3)]
private string lastReceivedMessage;
[SerializeField] private int receivedMessageCount;
[SerializeField] private List<MessageRecord> messageHistory = new List<MessageRecord>();
private const int MAX_HISTORY = 100;
[SerializeField] private List<MessageRecord> messageHistory = new();
public IReadOnlyList<MessageRecord> MessageHistory => messageHistory;
public int ReceivedMessageCount => receivedMessageCount;
@@ -31,18 +27,18 @@ namespace Unity.RenderStreaming
label = "on-message";
}
public event Action<string, UserInfo> OnUserInfoMessageReceived;
public event Action<string, MediaStateChange> OnMediaStateChangeReceived;
public override void OnMessage(string message)
{
try
{
Debug.Log($"[MessageChannel] Received: {message}");
var record = JsonConvert.DeserializeObject<MessageRecord>(message);
if (record == null)
{
record = new MessageRecord { type = "raw", data = message };
}
if (record == null) record = new MessageRecord { type = "raw", data = message };
record.timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
ConnectionId=record.connectionId;
ConnectionId = record.connectionId;
JObject json = null;
switch (record.type)
{
@@ -79,9 +75,9 @@ namespace Unity.RenderStreaming
var record = new MessageRecord
{
type = type,
data = JsonConvert.SerializeObject(data)
data = data
};
string json = JsonConvert.SerializeObject(record);
var json = JsonConvert.SerializeObject(record);
Send(json);
record.isSent = true;
@@ -90,14 +86,6 @@ namespace Unity.RenderStreaming
messageHistory.RemoveAt(0);
}
public void SendMessage(string message)
{
Send(message);
var record = new MessageRecord { type = "raw", data = message, isSent = true };
messageHistory.Add(record);
if (messageHistory.Count > MAX_HISTORY)
messageHistory.RemoveAt(0);
}
public void ClearHistory()
{
@@ -110,11 +98,11 @@ namespace Unity.RenderStreaming
public class MessageRecord
{
public string type;
public object data;
public bool isSent;
public string timestamp = DateTime.Now.ToString();
public string connectionId;
public string participantId;
public object data;
}
}
}

View File

@@ -0,0 +1,85 @@
// Assets/Script/WebRtc/SignalingMessageHelper.cs
using System;
using System.Reflection;
using UnityEngine;
namespace Unity.RenderStreaming
{
public static class SignalingMessageHelper
{
private static object _webSocketSignaling;
private static MethodInfo _sendRawMessageMethod;
static SignalingMessageHelper()
{
Initialize();
}
private static void Initialize()
{
try
{
var signalingManager = GameObject.FindObjectOfType<SignalingManager>();
if (signalingManager == null)
{
Debug.LogWarning("SignalingMessageHelper: 找不到 SignalingManager");
return;
}
var managerInternalField = typeof(SignalingManager).GetField("m_instance",
BindingFlags.NonPublic | BindingFlags.Instance);
var managerInternal = managerInternalField.GetValue(signalingManager);
if (managerInternal == null)
{
Debug.LogWarning("SignalingMessageHelper: SignalingManager 内部实例为空");
return;
}
var signalingField = managerInternal.GetType().GetField("_signaling",
BindingFlags.NonPublic | BindingFlags.Instance);
_webSocketSignaling = signalingField.GetValue(managerInternal);
if (_webSocketSignaling == null)
{
Debug.LogWarning("SignalingMessageHelper: WebSocketSignaling 实例为空");
return;
}
_sendRawMessageMethod = _webSocketSignaling.GetType().GetMethod("SendMessage");
if (_sendRawMessageMethod == null) Debug.LogWarning("SignalingMessageHelper: 找不到 SendRawMessage 方法");
}
catch (Exception e)
{
Debug.LogError($"SignalingMessageHelper 初始化失败: {e.Message}");
}
}
public static bool SendMessage(string message)
{
if (_webSocketSignaling == null || _sendRawMessageMethod == null)
{
Debug.LogError("SignalingMessageHelper 未正确初始化,请确保 WebSocketSignaling 已启动");
return false;
}
try
{
_sendRawMessageMethod.Invoke(_webSocketSignaling, new[] { message });
Debug.Log("消息已发送到服务端");
return true;
}
catch (Exception e)
{
Debug.LogError($"发送消息失败: {e.Message}");
return false;
}
}
public static bool IsReady()
{
return _webSocketSignaling != null && _sendRawMessageMethod != null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cee7bdd2c1f4deb4f9abcfba0ec09ddd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: