/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal.Experimental.NetWork { using System; using System.Collections; using UnityEngine; using NRKernal; using System.Collections.Generic; using LitJson; using System.Text; /// An observer view net worker. public class NetWorkBehaviour { /// The net work client. protected NetWorkClient m_NetWorkClient; /// The limit waitting time. private const float limitWaittingTime = 5f; /// True if is connected, false if not. private bool m_IsConnected = false; /// True if is jonin success, false if not. private bool m_IsJoninSuccess = false; /// True if is closed, false if not. private bool m_IsClosed = false; private Coroutine checkServerAvailableCoroutine = null; private Dictionary> _ResponseEvents = new Dictionary>(); public virtual void Listen() { if (m_NetWorkClient == null) { m_NetWorkClient = new NetWorkClient(); m_NetWorkClient.OnDisconnect += OnDisconnect; m_NetWorkClient.OnConnect += OnConnected; m_NetWorkClient.OnJoinRoomResult += OnJoinRoomResult; m_NetWorkClient.OnMessageResponse += OnMessageResponse; } } private void OnMessageResponse(byte[] data) { ulong msgid = BitConverter.ToUInt64(data, 0); Action callback; if (!_ResponseEvents.TryGetValue(msgid, out callback)) { NRDebugger.Warning("[NetWorkBehaviour] can not find the msgid bind event:" + msgid); return; } // Remove the header to get the msg. byte[] result = new byte[data.Length - sizeof(ulong)]; Array.Copy(data, sizeof(ulong), result, 0, result.Length); string json = Encoding.UTF8.GetString(result); callback?.Invoke(JsonMapper.ToObject(json)); NRDebugger.Info("[NetWorkBehaviour] OnMessageResponse hit..."); _ResponseEvents.Remove(msgid); } /// Check server available. /// The IP. /// The callback. public void CheckServerAvailable(string ip, Action callback) { if (string.IsNullOrEmpty(ip)) { callback?.Invoke(false); } else { if (checkServerAvailableCoroutine != null) { NRKernalUpdater.Instance.StopCoroutine(checkServerAvailableCoroutine); } checkServerAvailableCoroutine = NRKernalUpdater.Instance.StartCoroutine(CheckServerAvailableCoroutine(ip, callback)); } } /// Check server available coroutine. /// The IP. /// The callback. /// An IEnumerator. private IEnumerator CheckServerAvailableCoroutine(string ip, Action callback) { // Start to connect the server. m_NetWorkClient.Connect(ip, 6000); float timeLast = 0; while (!m_IsConnected) { if (timeLast > limitWaittingTime || m_IsClosed) { NRDebugger.Info("[ObserverView] Connect the server TimeOut!"); callback?.Invoke(false); yield break; } timeLast += Time.deltaTime; yield return new WaitForEndOfFrame(); } // Start to enter the room. m_NetWorkClient.EnterRoomRequest(); timeLast = 0; while (!m_IsJoninSuccess) { if (timeLast > limitWaittingTime || m_IsClosed) { NRDebugger.Info("[ObserverView] Join the server TimeOut!"); callback?.Invoke(false); yield break; } timeLast += Time.deltaTime; yield return new WaitForEndOfFrame(); } callback?.Invoke(true); } public void SendMsg(JsonData data, Action onResponse, float timeout = 3) { NRKernalUpdater.Instance.StartCoroutine(SendMessage(data, onResponse, timeout)); } private IEnumerator SendMessage(JsonData data, Action onResponse, float timeout) { if (data == null) { NRDebugger.Error("[NetWorkBehaviour] data is null!"); yield break; } // Add msgid(current timestamp) as the header. ulong msgid = NRTools.GetTimeStamp(); byte[] json_data = Encoding.UTF8.GetBytes(data.ToJson()); byte[] total_data = new byte[json_data.Length + sizeof(ulong)]; Array.Copy(BitConverter.GetBytes(msgid), 0, total_data, 0, sizeof(ulong)); Array.Copy(json_data, 0, total_data, sizeof(ulong), json_data.Length); if (onResponse != null) { Action onResult; AsyncTask asyncTask = new AsyncTask(out onResult); _ResponseEvents[msgid] = onResult; m_NetWorkClient.SendMessage(total_data); NRKernalUpdater.Instance.StartCoroutine(SendMsgTimeOut(msgid, timeout)); yield return asyncTask.WaitForCompletion(); onResponse?.Invoke(asyncTask.Result); } else { m_NetWorkClient.SendMessage(total_data); } } private IEnumerator SendMsgTimeOut(UInt64 id, float timeout) { yield return new WaitForSeconds(timeout); Action callback; if (_ResponseEvents.TryGetValue(id, out callback)) { NRDebugger.Warning("[NetWorkBehaviour] Send msg timeout, id:{0}", id); JsonData json = new JsonData(); json["success"] = false; callback?.Invoke(json); } } #region Net msg /// Executes the 'connected' action. private void OnConnected() { NRDebugger.Info("[NetWorkBehaviour] OnConnected..."); m_IsConnected = true; } /// Executes the 'disconnect' action. private void OnDisconnect() { NRDebugger.Info("[NetWorkBehaviour] OnDisconnect..."); this.Close(); } /// Executes the 'join room result' action. /// True to result. private void OnJoinRoomResult(bool result) { NRDebugger.Info("[NetWorkBehaviour] OnJoinRoomResult :" + result); m_IsJoninSuccess = result; if (!result) { this.Close(); } } #endregion /// Closes this object. public virtual void Close() { if (checkServerAvailableCoroutine != null) { NRKernalUpdater.Instance.StopCoroutine(checkServerAvailableCoroutine); } m_NetWorkClient.ExitRoomRequest(); m_NetWorkClient?.Dispose(); m_NetWorkClient = null; checkServerAvailableCoroutine = null; m_IsClosed = true; } } }