breakpoint

This commit is contained in:
CortexCore
2023-06-17 16:30:53 +08:00
parent cd02761be7
commit 877ba6e548
88 changed files with 8715 additions and 988 deletions

View File

@@ -0,0 +1,124 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
namespace Net.UnityComponent
{
using global::System;
using Net.Share;
using UnityEngine;
/// <summary>
/// 网络行为基础组件
/// </summary>
[DefaultExecutionOrder(1000)]
public abstract class NetworkBehaviour : MonoBehaviour
{
public NetworkObject netObj;
[Tooltip("网络组件的ID,当FPS游戏时,自己身上只有一双手和枪,而其他客户端要显示完整模型时,用到另外的预制体,就会出现组件获取不一致问题,所以这里提供了网络组件ID,即可解决此问题")]
[SerializeField] private int netComponentID = -1;
/// <summary>
/// 网络组件id, 此组件是netobj的第几个组件
/// </summary>
public int NetComponentID
{
get { return netComponentID > 10 ? -1 : netComponentID; }
set
{
if (value > 10)
throw new Exception("组件最多不能超过10个");
netComponentID = value;
}
}
/// <summary>
/// 这个物体是本机生成的?
/// true:这个物体是从你本机实例化后, 同步给其他客户端的, 其他客户端的IsLocal为false
/// false:这个物体是其他客户端实例化后,同步到本机客户端上, IsLocal为false
/// </summary>
public bool IsLocal => netObj.isLocal;
private bool isInit;
private bool isEnabled;
public virtual void Start()
{
Init();
}
private void OnValidate()
{
if (TryGetComponent(out netObj))
return;
netObj = gameObject.GetComponentInParent<NetworkObject>(true); //此处需要加上参数true, 否则做成预制体时会找不到父组件
if (netObj == null)
netObj = gameObject.AddComponent<NetworkObject>();
}
public void Init(Operation opt = default)
{
if (isInit)
return;
isInit = true;
netObj = GetComponentInParent<NetworkObject>();
if (NetComponentID == -1)
{
NetComponentID = netObj.networkBehaviours.Count;
netObj.networkBehaviours.Add(this);
}
else
{
while (netObj.networkBehaviours.Count <= NetComponentID)
netObj.networkBehaviours.Add(null);
if (netObj.networkBehaviours[NetComponentID] != null)
throw new Exception($"索引有冲突!打开预制体设置{this}组件的NetComponentID值为唯一ID!");
netObj.networkBehaviours[NetComponentID] = this;
}
netObj.InitSyncVar(this);
if (IsLocal)
OnNetworkObjectInit(netObj.Identity);
else
OnNetworkObjectCreate(opt);
}
/// <summary>
/// 当网络物体被初始化, 只有本机实例化的物体才会被调用
/// </summary>
/// <param name="identity"></param>
public virtual void OnNetworkObjectInit(int identity) { }
/// <summary>
/// 当网络物体被创建后调用, 只有其他客户端发送创建信息给本机后才会被调用
/// </summary>
/// <param name="opt"></param>
public virtual void OnNetworkObjectCreate(Operation opt) { }
/// <summary>
/// 当网络操作到达后应当开发者进行处理
/// </summary>
/// <param name="opt"></param>
public virtual void OnNetworkOperationHandler(Operation opt) { }
/// <summary>
/// 当属性自动同步检查
/// </summary>
public virtual void OnPropertyAutoCheck() { }
/// <summary>
/// 检查组件是否启用
/// </summary>
/// <returns></returns>
public virtual bool CheckEnabled() { return isEnabled; }
public virtual void OnEnable()
{
isEnabled = true;
}
public virtual void OnDisable()
{
isEnabled = false;
}
public virtual void OnDestroy()
{
netObj.RemoveSyncVar(this);
var nbs = netObj.networkBehaviours;
for (int i = 0; i < nbs.Count; i++)
{
var nb = nbs[i];
nb.NetComponentID = i;
if (nb == this)
{
nbs.RemoveAt(i);
if (i >= 0) i--;
}
}
}
}
}
#endif

View File

@@ -0,0 +1,299 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
using Net.Client;
using Net.Event;
using Net.Share;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System;
using Net.Helper;
using Cysharp.Threading.Tasks;
namespace Net.Component
{
[Serializable]
public class ClientGourp
{
public string name;
public ClientBase _client;
public TransportProtocol protocol = TransportProtocol.Tcp;
public string ip = "127.0.0.1";
public int port = 9543;
#if UNITY_EDITOR
public bool localTest;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#endif
public bool debugRpc = true;
public bool authorize;
public bool startConnect = true;
public bool md5CRC;
public bool singleThread;
public int reconnectCount = 10;
public int reconnectInterval = 2000;
public byte heartLimit = 5;
public int heartInterval = 1000;
[Header("<22><><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
public SerializeAdapterType type;
public bool isEncrypt = false;//<2F><><EFBFBD>ݼ<EFBFBD><DDBC><EFBFBD>?
public int password = 758426581;
public ClientBase Client
{
get
{
if (_client != null)
return _client;
var typeName = $"Net.Client.{protocol}Client";
var type = AssemblyHelper.GetType(typeName);
if (type == null)
throw new Exception($"<22><EFBFBD><EBB5BC>:{protocol}Э<><D0AD>!!!");
_client = Activator.CreateInstance(type, new object[] { true }) as ClientBase;
_client.host = ip;
_client.port = port;
_client.LogRpc = debugRpc;
_client.MD5CRC = md5CRC;
_client.IsMultiThread = !singleThread;
_client.ReconnectCount = reconnectCount;
_client.ReconnectInterval = reconnectInterval;
_client.SetHeartTime(heartLimit, heartInterval);
return _client;
}
set { _client = value; }
}
public UniTask<bool> Connect()
{
_client = Client;
var ips = Dns.GetHostAddresses(ip);
if (ips.Length > 0)
_client.host = ips[RandomHelper.Range(0, ips.Length)].ToString();
else
_client.host = ip;
#if UNITY_EDITOR
if (localTest) _client.host = "127.0.0.1";
#endif
_client.port = port;
switch (type)
{
case SerializeAdapterType.Default:
break;
case SerializeAdapterType.PB_JSON_FAST:
_client.AddAdapter(new Adapter.SerializeFastAdapter() { IsEncrypt = isEncrypt, Password = password });
break;
case SerializeAdapterType.Binary:
_client.AddAdapter(new Adapter.SerializeAdapter() { IsEncrypt = isEncrypt, Password = password });
break;
case SerializeAdapterType.Binary2:
_client.AddAdapter(new Adapter.SerializeAdapter2() { IsEncrypt = isEncrypt, Password = password });
break;
case SerializeAdapterType.Binary3:
_client.AddAdapter(new Adapter.SerializeAdapter3() { IsEncrypt = isEncrypt, Password = password });
break;
}
return _client.Connect(result =>
{
if (result)
{
_client.Send(new byte[1]);//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽ<EFBFBD>:<3A><><EFBFBD>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>OnUnClientRequest<73><74><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>˺ŵ<CBBA>¼, <20><><EFBFBD><EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
});
}
public UniTask<bool> Connect(string ip, int port)
{
this.ip = ip;
this.port = port;
return Connect();
}
}
public class NetworkManager : SingleCase<NetworkManager>
{
public LogMode logMode = LogMode.Default;
public bool dontDestroyOnLoad = true;
#if UNITY_2020_1_OR_NEWER
[NonReorderable]
#endif
public List<ClientGourp> clients = new List<ClientGourp>();
public ClientBase this[int index]
{
get { return clients[index].Client; }
set { clients[index].Client = value; }
}
protected override void Awake()
{
base.Awake();
if (dontDestroyOnLoad) DontDestroyOnLoad(gameObject);
Application.runInBackground = true;
}
// Use this for initialization
void Start()
{
switch (logMode)
{
case LogMode.Default:
NDebug.BindLogAll(Debug.Log, Debug.LogWarning, Debug.LogError);
break;
case LogMode.LogAll:
NDebug.BindLogAll(Debug.Log);
break;
case LogMode.LogAndWarning:
NDebug.BindLogAll(Debug.Log, Debug.Log, Debug.LogError);
break;
case LogMode.WarnAndError:
NDebug.BindLogAll(Debug.Log, Debug.LogError, Debug.LogError);
break;
case LogMode.OnlyError:
NDebug.BindLogAll(null, null, Debug.LogError);
break;
case LogMode.OnlyWarnAndError:
NDebug.BindLogAll(null, Debug.LogError, Debug.LogError);
break;
}
foreach (var client in clients)
{
if (client.startConnect)
client.Connect();
}
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < clients.Count; i++)
{
if (clients[i]._client == null)
continue;
clients[i]._client.NetworkTick();
}
}
void OnDestroy()
{
for (int i = 0; i < clients.Count; i++)
{
if (clients[i]._client == null)
continue;
clients[i]._client.Close();
}
switch (logMode)
{
case LogMode.Default:
NDebug.RemoveLogAll(Debug.Log, Debug.LogWarning, Debug.LogError);
break;
case LogMode.LogAll:
NDebug.RemoveLogAll(Debug.Log);
break;
case LogMode.LogAndWarning:
NDebug.RemoveLogAll(Debug.Log, Debug.Log, Debug.LogError);
break;
case LogMode.WarnAndError:
NDebug.RemoveLogAll(Debug.Log, Debug.LogError, Debug.LogError);
break;
case LogMode.OnlyError:
NDebug.RemoveLogAll(null, null, Debug.LogError);
break;
case LogMode.OnlyWarnAndError:
NDebug.RemoveLogAll(null, Debug.LogError, Debug.LogError);
break;
}
}
public static void BindNetworkAll(INetworkHandle handle)
{
foreach (var item in I.clients)
{
item.Client.BindNetworkHandle(handle);
}
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>rpc, Ҳ<><D2B2><EFBFBD><EFBFBD>1<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>
/// </summary>
/// <param name="target"></param>
public static void AddRpcOne(object target)
{
I.clients[0].Client.AddRpc(target);
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>, Ҳ<><D2B2><EFBFBD><EFBFBD>2<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>
/// </summary>
/// <param name="target"></param>
public static void AddRpcTwo(object target)
{
I.clients[1].Client.AddRpc(target);
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>rpc, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1>0<EFBFBD><30>Ϊȫ<CEAA><C8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
/// <param name="clientIndex"></param>
/// <param name="target"></param>
public static void AddRpc(int clientIndex, object target)
{
if (clientIndex < 0)
foreach (var item in I.clients)
item.Client.AddRpc(target);
else I.clients[clientIndex].Client.AddRpc(target);
}
/// <summary>
/// <20>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>rpc, Ҳ<><D2B2><EFBFBD><EFBFBD>1<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>
/// </summary>
/// <param name="target"></param>
public static void RemoveRpcOne(object target)
{
I.clients[0].Client.RemoveRpc(target);
}
/// <summary>
/// <20>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>rpc, Ҳ<><D2B2><EFBFBD><EFBFBD>2<EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>
/// </summary>
/// <param name="target"></param>
public static void RemoveRpcTwo(object target)
{
var i = Instance;
if (i == null)
return;
i.clients[1].Client.RemoveRpc(target);
}
/// <summary>
/// <20>Ƴ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀͻ<C4BF><CDBB><EFBFBD>rpc, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1>0<EFBFBD><30>Ϊȫ<CEAA><C8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
/// <param name="clientIndex"></param>
/// <param name="target"></param>
public static void RemoveRpc(int clientIndex, object target)
{
var i = Instance;
if (i == null)
return;
if (clientIndex < 0)
foreach (var item in i.clients)
item.Client.RemoveRpc(target);
else i.clients[clientIndex].Client.RemoveRpc(target);
}
public static void Close(bool v1, int v2)
{
foreach (var item in I.clients)
{
item.Client.Close(v1, v2);
}
}
public static void CallUnity(Action ptr)
{
I.clients[0].Client.WorkerQueue.Enqueue(ptr);
}
public static void DispatcherRpc(ushort hash, params object[] parms)
{
I.clients[1].Client.DispatchRpc(hash, parms);
}
}
}
#endif

View File

@@ -0,0 +1,269 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
namespace Net.UnityComponent
{
using global::System.Collections.Generic;
using Net.Client;
using Net.Component;
using Net.Helper;
using Net.Share;
using Net.System;
using UnityEngine;
/// <summary>
/// 网络物体标识组件
/// </summary>
[DisallowMultipleComponent]
[DefaultExecutionOrder(1000)]
public class NetworkObject : MonoBehaviour
{
internal static int IDENTITY { get; private set; } = -1;
internal static int IDENTITY_MAX { get; private set; }
internal static Queue<int> IDENTITY_POOL = new Queue<int>();
public static int Capacity { get; private set; }
public static bool IsInitIdentity => IDENTITY != -1;
private int m_identity = -1;
[Tooltip("自定义唯一标识, 当值不为0后,可以不通过NetworkSceneManager的registerObjects去设置, 直接放在设计的场景里面, 不需要做成预制体")]
[SerializeField] private int identity;//可以设置的id
[Tooltip("注册的网络物体索引, registerObjectIndex要对应NetworkSceneManager的registerObjects数组索引, 如果设置了自定义唯一标识, 则此字段无效!")]
public int registerObjectIndex;
[SerializeField] internal bool isLocal = true;
internal List<NetworkBehaviour> networkBehaviours = new List<NetworkBehaviour>();
internal MyDictionary<ushort, SyncVarInfo> syncVarInfos = new MyDictionary<ushort, SyncVarInfo>();
private int syncVarID = 1;
[Tooltip("是否初始化? 如果不想让Identity在Start被自动分配ID, 则可以设置此字段为true")]
[SerializeField] internal bool isInit;
public bool IsDispose { get; internal set; }
/// <summary>
/// 此物体是否是本机实例化?
/// </summary>
public bool IsLocal { get => isLocal; set => isLocal = value; }
/// <summary>
/// 每个网络对象的唯一标识
/// </summary>
public int Identity { get => m_identity; set => m_identity = value; }
/// <summary>
/// 获取或设置是否初始化
/// </summary>
public bool IsInitialize { get => isInit; set => isInit = value; }
public virtual void Start()
{
Init();
}
public void ReInit()
{
isInit = false;
Init();
}
public void Init()
{
if (isInit)
return;
isInit = true;
if (IDENTITY == -1 & identity == 0)//全局netobj
{
Debug.LogError("网络标识未初始化请调用NetworkObject.Init(5000);初始化");
Destroy(gameObject);
return;
}
var sm = NetworkSceneManager.I;
if (sm == null)
{
Debug.Log("没有找到NetworkSceneManager组件NetworkIdentity组件无效");
Destroy(gameObject);
return;
}
if (!isLocal | m_identity > 0)
{
goto J1;
}
if (identity > 0)
{
m_identity = identity;
goto J1;
}
if (IDENTITY_POOL.Count > 0)
{
m_identity = IDENTITY_POOL.Dequeue();
goto J1;
}
if (IDENTITY < IDENTITY_MAX)
{
m_identity = IDENTITY++;
goto J1;
}
else
{
Debug.LogError("网络标识已用完! 如果有需要请加大网络标识数量NetworkObject.Init(10000);");
Destroy(gameObject);
return;
}
J1:
if (!sm.identitys.TryAdd(m_identity, this, out var oldNetObj))
{
if (oldNetObj == this | oldNetObj == null)
return;
oldNetObj.m_identity = -1;
Debug.Log($"uid:{m_identity}发生了两次实例化! 本地的实例化和网络同步下来的identity冲突");
Destroy(oldNetObj.gameObject);
}
}
public void InitAll(Operation opt = default)
{
Init();
var nbs = GetComponentsInChildren<NetworkBehaviour>();
foreach (var np in nbs)
{
np.Init(opt);
}
}
internal void InitSyncVar(object target)
{
ClientBase.Instance.AddRpcHandle(target, false, (info) =>
{
info.id = (ushort)syncVarID++;
syncVarInfos.Add(info.id, info);
if (!isLocal)
{
ClientBase.Instance.AddOperation(new Operation(NetCmd.SyncVarGet, m_identity)
{
index = registerObjectIndex,
index1 = info.id,
});
}
});
}
internal void CheckSyncVar()
{
if (syncVarInfos.Count == 0)
return;
var buffer = SyncVarHelper.CheckSyncVar(isLocal, syncVarInfos);
if (buffer != null)
SyncVarSend(buffer);
}
private void SyncVarSend(byte[] buffer)
{
ClientBase.Instance.AddOperation(new Operation(NetCmd.SyncVarNetObj, m_identity)
{
uid = ClientBase.Instance.UID,
index = registerObjectIndex,
buffer = buffer
});
}
internal void SyncVarHandler(Operation opt)
{
if (opt.uid == ClientBase.Instance.UID)
return;
SyncVarHelper.SyncVarHandler(syncVarInfos, opt.buffer);
}
internal void RemoveSyncVar(NetworkBehaviour target)
{
SyncVarHelper.RemoveSyncVar(syncVarInfos, target);
}
internal void PropertyAutoCheckHandler()
{
for (int i = 0; i < networkBehaviours.Count; i++)
{
var networkBehaviour = networkBehaviours[i];
if (!networkBehaviour.CheckEnabled())
continue;
networkBehaviour.OnPropertyAutoCheck();
}
}
public virtual void OnDestroy()
{
if (IsDispose)
return;
IsDispose = true;
if (m_identity == -1)
return;
var sm = NetworkSceneManager.Instance;
if (sm == null)
return;
if (!isLocal | m_identity < 10000)//0-10000是场景可用标识
{
sm.waitDestroyList.Add(new WaitDestroy(m_identity, false, Time.time + 1f));
return;
}
sm.waitDestroyList.Add(new WaitDestroy(m_identity, true, Time.time + 1f));
if (ClientBase.Instance == null)
return;
if (!ClientBase.Instance.Connected)
return;
ClientBase.Instance.AddOperation(new Operation(Command.Destroy, m_identity));
}
internal static void PushIdentity(int identity)
{
if (IDENTITY == -1)
return;
IDENTITY_POOL.Enqueue(identity);
}
/// <summary>
/// 初始化网络唯一标识
/// </summary>
/// <param name="capacity">一个客户端可以用的唯一标识容量</param>
public static void Init(int capacity = 5000)
{
//要实时可初始化要不然每次切换场景都无法初始化id或者切换账号后uid变了就得不到真正的identity值了
Capacity = capacity;
//0-10000是公共id10000-15000是玩家uid也就是同时在线5000个玩家每个玩家占用一个id15000-20000是uid=10000的网络物体id
//每个玩家可以实例化5000个网络物体并且id都是唯一的如果超出则报错
IDENTITY = 10000 + ((ClientBase.Instance.UID + 1 - 10000) * capacity);
IDENTITY_MAX = IDENTITY + capacity;
IDENTITY_POOL.Clear();
}
/// <summary>
/// 释放初始化的identity
/// </summary>
public static void UnInit()
{
IDENTITY = -1;
IDENTITY_MAX = 0;
Capacity = 0;
IDENTITY_POOL.Clear();
}
/// <summary>
/// 获取玩家id的偏移量, 此方法算出来每个玩家可实例化多少个网络对象
/// </summary>
/// <param name="uid"></param>
/// <returns></returns>
public static int GetUserIdOffset(int uid)
{
//0-10000是公共id10000-15000是玩家uid也就是同时在线5000个玩家每个玩家占用一个id15000-20000是uid=10000的网络物体id
//每个玩家可以实例化5000个网络物体并且id都是唯一的如果超出则报错
return 10000 + ((uid + 1 - 10000) * Capacity);
}
#if UNITY_EDITOR
private void OnValidate()
{
var networkBehaviours = gameObject.GetComponentsInChildren<NetworkBehaviour>(true);
for (int i = 0; i < networkBehaviours.Length; i++)
{
var networkBehaviour = networkBehaviours[i];
if (networkBehaviour.NetComponentID == -1)
{
networkBehaviour.NetComponentID = i;
UnityEditor.EditorUtility.SetDirty(networkBehaviour);
}
}
}
#endif
}
}
#endif

View File

@@ -0,0 +1,75 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
using System;
using UnityEngine;
using Net.Component;
using System.Collections.Generic;
using Object = UnityEngine.Object;
namespace Net.UnityComponent
{
[Serializable]
public class ObjectRecord
{
public int ID;
public Object obj;
public string path;//编辑器模式使用,任何物体都可以同步
}
/// <summary>
/// 网络资源同步
/// 此类主要用于同步字段为unity的组件或者基于UnityEngine.Objec的类型
/// 在编辑器模式下是任何物体都可以同步的, 注意: 在编译项目后, 只能同步在Resources文件夹下的预制体或物体
/// </summary>
public class NetworkResources : SingleCase<NetworkResources>
{
public ObjectRecord[] objectRecords;
public Dictionary<Object, ObjectRecord> dic = new Dictionary<Object, ObjectRecord>();
public Dictionary<string, ObjectRecord> dic1 = new Dictionary<string, ObjectRecord>();
protected override void Awake()
{
base.Awake();
var objects = Resources.LoadAll<Object>("");
objectRecords = new ObjectRecord[objects.Length];
for (int i = 0; i < objects.Length; i++)
{
objectRecords[i] = new ObjectRecord() { ID = i, obj = objects[i] };
dic.Add(objects[i], objectRecords[i]);
}
}
internal bool TryGetValue(Object obj, out ObjectRecord objectRecord)
{
#if UNITY_EDITOR
if (!dic.TryGetValue(obj, out objectRecord))
{
var path = UnityEditor.AssetDatabase.GetAssetPath(obj);
objectRecord = new ObjectRecord() { ID = dic.Count, obj = obj, path = path };
dic.Add(obj, objectRecord);
}
return true;
#else
return dic.TryGetValue(obj, out objectRecord);
#endif
}
internal T GetObject<T>(int index, string path) where T : Object
{
#if UNITY_EDITOR
if(string.IsNullOrEmpty(path))
return null;
if (!dic1.TryGetValue(path, out ObjectRecord objectRecord))
{
var obj = UnityEditor.AssetDatabase.LoadAssetAtPath(path, typeof(T));
objectRecord = new ObjectRecord() { ID = dic1.Count, obj = obj, path = path };
dic1.Add(path, objectRecord);
}
return (T)objectRecord.obj;
#else
return (T)objectRecords[index].obj;
#endif
}
}
}
#endif

View File

@@ -0,0 +1,323 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
namespace Net.UnityComponent
{
using global::System;
using global::System.Collections.Generic;
using Net.Client;
using Net.Component;
using Net.Share;
using Net.System;
using UnityEngine;
using Cysharp.Threading.Tasks;
[Serializable]
public class WaitDestroy
{
public int identity;
public bool isPush;
public float time;
public WaitDestroy(int identity, bool isPush, float time)
{
this.identity = identity;
this.isPush = isPush;
this.time = time;
}
}
[DefaultExecutionOrder(1)]
public class NetworkSceneManager : SingleCase<NetworkSceneManager>
{
public List<NetworkObject> registerObjects = new List<NetworkObject>();
[HideInInspector]
public MyDictionary<int, NetworkObject> identitys = new MyDictionary<int, NetworkObject>();
[Tooltip("如果onExitDelectAll=true 当客户端退出游戏,客户端所创建的所有网络物体也将随之被删除? onExitDelectAll=false只删除玩家物体")]
public bool onExitDelectAll = true;
internal List<WaitDestroy> waitDestroyList = new List<WaitDestroy>();
protected ClientBase client; //当多场景时, 退出战斗场景, 回主场景时, 先进入主场景再卸载战斗场景, 而ClientBase.Instance被赋值到其他多连接客户端对象上就会出现OnDestry时没有正确移除OnOperationSync事件
protected Queue<Action> waitNetworkIdentityQueue = new Queue<Action>();
public virtual void Start()
{
_ = WaitConnecting();
if (NetworkTime.Instance == null)
gameObject.AddComponent<NetworkTime>();
}
public virtual async UniTaskVoid WaitConnecting()
{
var outTime = DateTime.Now.AddSeconds(10);
while (DateTime.Now < outTime)
{
if (ClientBase.Instance == null)
await UniTask.Yield();
else if (!ClientBase.Instance.Connected)
await UniTask.Yield();
else
break;
}
if (DateTime.Now > outTime)
{
Debug.Log("连接超时!");
return;
}
OnConnected();
client = ClientBase.Instance;
client.OnOperationSync += OperationSync;
while (waitNetworkIdentityQueue.Count > 0)
waitNetworkIdentityQueue.Dequeue()?.Invoke();
}
public virtual void OnConnected()
{
NetworkObject.Init(5000);
}
/// <summary>
/// 等待网络标识初始化, 当标识初始化完成调用onInitComplete委托
/// </summary>
/// <param name="onInitComplete"></param>
public virtual void WaitNetworkIdentityInit(Action onInitComplete)
{
if (NetworkObject.IsInitIdentity)
onInitComplete?.Invoke();
else
waitNetworkIdentityQueue.Enqueue(onInitComplete);
}
public virtual void Update()
{
if (NetworkTime.CanSent)
{
for (int i = 0; i < identitys.count; i++)
{
if (identitys.entries[i].hashCode == -1)
continue;
var identity = identitys.entries[i].value;
if (identity == null)
continue;
if (!identity.enabled)
continue;
if (identity.IsDispose)
continue;
identity.CheckSyncVar();
identity.PropertyAutoCheckHandler();
}
}
WaitDestroy waitDestroy;
for (int i = 0; i < waitDestroyList.Count; i++)
{
waitDestroy = waitDestroyList[i];
if (Time.time >= waitDestroy.time)
{
RemoveIdentity(waitDestroy.identity);
waitDestroyList.RemoveAt(i);
if (!waitDestroy.isPush)
continue;
NetworkObject.PushIdentity(waitDestroy.identity);
}
}
}
private void OperationSync(OperationList list)
{
foreach (var opt in list.operations)
OnNetworkOperSync(opt);
}
private void OnNetworkOperSync(Operation opt)
{
switch (opt.cmd)
{
case Command.Transform:
OnBuildOrTransformSync(opt);
break;
case Command.BuildComponent:
OnBuildOrTransformSync(opt);
break;
case Command.Destroy:
OnNetworkObjectDestroy(opt);
break;
case Command.OnPlayerExit:
OnPlayerExit(opt);
break;
case NetCmd.SyncVarNetObj:
OnSyncVarHandler(opt);
break;
case NetCmd.SyncVarGet:
SyncVarGetHandler(opt);
break;
case NetCmd.CallRpc:
var data = client.OnDeserializeRPC(opt.buffer, 0, opt.buffer.Length);
if(!string.IsNullOrEmpty(data.name))
client.DispatchRpc(data.name, data.pars);
else if(data.hash != 0)
client.DispatchRpc(data.hash, data.pars);
break;
default:
OnOtherOperator(opt);
break;
}
}
/// <summary>
/// 当检查网络标识物体,如果不存在就会实例化 --- 在这里用到了<see cref="Operation.identity"/>作为网络物体标识, <see cref="Operation.index"/>作为要实例化<see cref="registerObjects"/>的物体索引
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
public virtual NetworkObject OnCheckIdentity(Operation opt)
{
if (!identitys.TryGetValue(opt.identity, out NetworkObject identity))
{
if (opt.index >= registerObjects.Count)
return null;
identity = Instantiate(registerObjects[opt.index]);
identity.Identity = opt.identity;
identity.isLocal = false;
identity.isInit = true;
identity.InitAll(opt);
identitys.TryAdd(opt.identity, identity);
OnNetworkObjectCreate(opt, identity);
}
return identity;
}
/// <summary>
/// 当BuildComponent指令或Transform指令同步时调用
/// </summary>
/// <param name="opt"></param>
public virtual void OnBuildOrTransformSync(Operation opt)
{
var identity = OnCheckIdentity(opt);
if (identity == null)
return;
if (identity.IsDispose)
return;
var nb = identity.networkBehaviours[opt.index1];
nb.OnNetworkOperationHandler(opt);
}
public virtual void OnSyncVarHandler(Operation opt)
{
var identity = OnCheckIdentity(opt);
if (identity == null)
return;
if (identity.IsDispose)
return;
identity.SyncVarHandler(opt);
}
public virtual void SyncVarGetHandler(Operation opt)
{
var identity = OnCheckIdentity(opt);
if (identity == null)
return;
if (identity.IsDispose)
return;
if (!identity.isLocal)
return;
identity.syncVarInfos[(ushort)opt.index1].SetDefaultValue();
}
/// <summary>
/// 当其他网络物体被删除(入口1)
/// </summary>
/// <param name="opt"></param>
public virtual void OnNetworkObjectDestroy(Operation opt)
{
if (identitys.TryGetValue(opt.identity, out NetworkObject identity))
{
OnPlayerDestroy(identity, false);
}
}
public virtual void OnPlayerExit(Operation opt)
{
if (identitys.TryGetValue(opt.identity, out NetworkObject identity))//删除退出游戏的玩家游戏物体
OnPlayerDestroy(identity, true);
if (onExitDelectAll)//删除此玩家所创建的所有游戏物体
{
var uid = NetworkObject.GetUserIdOffset(opt.identity);
var count = uid + NetworkObject.Capacity;
foreach (var item in identitys)
if (item.Key >= uid & item.Key < count)
OnPlayerDestroy(item.Value, false);
}
}
private void OnPlayerDestroy(NetworkObject identity, bool isPlayer)
{
if (identity == null)
return;
if (identity.IsDispose)
return;
if(isPlayer)
OnOtherExit(identity);
OnOtherDestroy(identity);
}
public void RemoveIdentity(int identity)
{
identitys.Remove(identity);
}
/// <summary>
/// 当其他网络物体被创建(实例化)
/// </summary>
/// <param name="opt"></param>
/// <param name="identity"></param>
public virtual void OnNetworkObjectCreate(Operation opt, NetworkObject identity)
{
}
/// <summary>
/// 当其他网络物体被删除(入口2)
/// </summary>
/// <param name="identity"></param>
public virtual void OnOtherDestroy(NetworkObject identity)
{
Destroy(identity.gameObject);
}
/// <summary>
/// 当其他玩家网络物体退出(删除)
/// </summary>
/// <param name="identity"></param>
public virtual void OnOtherExit(NetworkObject identity)
{
}
/// <summary>
/// 当其他操作指令调用
/// </summary>
/// <param name="opt"></param>
public virtual void OnOtherOperator(Operation opt)
{
}
private void OnApplicationQuit()
{
ExitSceneHandler();
}
/// <summary>
/// 当退出场景时有些网络物体是不应该被销毁的
/// </summary>
public void ExitSceneHandler()
{
foreach (var identity in identitys)
{
identity.Value.Identity = -1;
}
}
public virtual void OnDestroy()
{
NetworkObject.UnInit();//每次离开战斗场景都要清除初始化identity
if (client == null)
return;
client.OnOperationSync -= OperationSync;
}
}
}
#endif

View File

@@ -0,0 +1,14 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
using UnityEngine;
namespace Net.UnityComponent
{
/// <summary>
/// 网络Transform同步组件基类
/// </summary>
[DefaultExecutionOrder(1000)]
public class NetworkTransform : NetworkTransformBase
{
}
}
#endif

View File

@@ -0,0 +1,202 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
namespace Net.UnityComponent
{
using Net.Client;
using Net.Component;
using Net.Share;
using UnityEngine;
using UnityEngine.UIElements;
public enum SyncMode
{
/// <summary>
/// 自身同步, 只有自身才能控制, 同步给其他客户端, 其他客户端无法控制这个物体的移动
/// </summary>
Local,
/// <summary>
/// 完全控制, 所有客户端都可以移动这个物体, 并且其他客户端都会被同步
/// 同步条件是哪个先移动这个物体会有<see cref="NetworkTransformBase.interval"/>秒完全控制,
/// 其他客户端无法控制,如果先移动的客户端一直移动这个物体,则其他客户端无法移动,只有先移动的客户端停止操作,下个客户端才能同步这个物体
/// </summary>
Control,
/// <summary>
/// 无效
/// </summary>
Authorize,
/// <summary>
/// 自身同步在其他客户端显示的状态
/// </summary>
Synchronized,
/// <summary>
/// 完全控制在其他客户端显示的状态
/// </summary>
SynchronizedAll,
/// <summary>
/// 空同步
/// </summary>
None,
}
/// <summary>
/// 网络Transform同步组件基类
/// </summary>
[DefaultExecutionOrder(1000)]
public abstract class NetworkTransformBase : NetworkBehaviour
{
protected Net.Vector3 position;
protected Net.Quaternion rotation;
protected Net.Vector3 localScale;
public SyncMode syncMode = SyncMode.Local;
public bool syncPosition = true;
public bool syncRotation = true;
public bool syncScale = false;
[HideInInspector] public SyncMode currMode = SyncMode.None;
internal float sendTime;
public float interval = 0.5f;
protected Net.Vector3 netPosition;
protected Net.Quaternion netRotation;
protected Net.Vector3 netLocalScale;
public float rate = 30f;//网络帧率, 一秒30次
public float lerpSpeed = 0.3f;
public bool fixedSync = true;
public float fixedSendTime = 1f;//固定发送时间
internal float fixedTime;
// Update is called once per frame
public virtual void Update()
{
if (netObj.Identity == -1 | currMode == SyncMode.None)
return;
if (currMode == SyncMode.Synchronized)
{
SyncTransform();
}
else if (Time.time > sendTime)
{
Check();
sendTime = Time.time + (1f / rate);
}
}
public virtual void Check()
{
if (transform.position != position | transform.rotation != rotation | transform.localScale != localScale | (Time.time > fixedTime & fixedSync))
{
position = transform.position;
rotation = transform.rotation;
localScale = transform.localScale;
fixedTime = Time.time + fixedSendTime;
StartSyncTransformState();
}
}
public virtual void StartSyncTransformState()
{
ClientBase.Instance.AddOperation(new Operation(Command.Transform, netObj.Identity, syncScale ? localScale : Net.Vector3.zero, syncPosition ? position : Net.Vector3.zero, syncRotation ? rotation : Net.Quaternion.zero)
{
cmd1 = (byte)currMode,
index = netObj.registerObjectIndex,
index1 = NetComponentID,
uid = ClientBase.Instance.UID
});
}
public virtual void SyncTransform()
{
if (syncPosition)
transform.position = Vector3.Lerp(transform.position, netPosition, lerpSpeed);
if (syncRotation)
if (netRotation != Net.Quaternion.identity)
transform.rotation = Quaternion.Lerp(transform.rotation, netRotation, lerpSpeed);
if (syncScale)
transform.localScale = netLocalScale;
}
public virtual void SyncControlTransform()
{
if (syncPosition)
{
position = netPosition;//位置要归位,要不然就会发送数据
transform.position = netPosition;
}
if (syncRotation)
{
rotation = netRotation;
transform.rotation = netRotation;
}
if (syncScale)
{
localScale = netLocalScale;
transform.localScale = netLocalScale;
}
}
public override void OnNetworkObjectInit(int identity)
{
currMode = syncMode;
}
public override void OnNetworkObjectCreate(Operation opt)
{
if (opt.cmd == Command.Transform)
{
var mode1 = (SyncMode)opt.cmd1;
if (mode1 == SyncMode.Control | mode1 == SyncMode.SynchronizedAll)
currMode = SyncMode.SynchronizedAll;
else
currMode = SyncMode.Synchronized;
}
netPosition = opt.position;
netRotation = opt.rotation;
netLocalScale = opt.direction;
SyncControlTransform();
}
public override void OnNetworkOperationHandler(Operation opt)
{
if (ClientBase.Instance.UID == opt.uid)
return;
sendTime = Time.time + interval;
netPosition = opt.position;
netRotation = opt.rotation;
netLocalScale = opt.direction;
if (currMode == SyncMode.SynchronizedAll | currMode == SyncMode.Control)
SyncControlTransform();
else if (currMode == SyncMode.None)
{
var mode1 = (SyncMode)opt.cmd1;
if (mode1 == SyncMode.Control | mode1 == SyncMode.SynchronizedAll)
currMode = SyncMode.SynchronizedAll;
else
currMode = SyncMode.Synchronized;
}
}
public void SetNetworkPosition(Net.Vector3 position)
{
netPosition = position;
}
public void SetNetworkRotation(Net.Quaternion rotation)
{
netRotation = rotation;
}
public void SetNetworkPositionAndRotation(Net.Vector3 position, Net.Quaternion rotation)
{
netPosition = position;
netRotation = rotation;
}
public override void OnDestroy()
{
base.OnDestroy();
if (ClientBase.Instance == null)
return;
//如果在退出游戏或者退出场景后不让物体被销毁则需要查找netobj组件设置Identity等于-1或者查找此组件设置currMode等于None或者在点击处理的时候调用ClientBase.Instance.Close方法
if ((currMode == SyncMode.SynchronizedAll | currMode == SyncMode.Control) & netObj.Identity != -1 & ClientBase.Instance.Connected)
ClientBase.Instance.AddOperation(new Operation(Command.Destroy, netObj.Identity));
}
}
}
#endif

View File

@@ -0,0 +1,159 @@
#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
namespace Net.UnityComponent
{
using Net.Component;
using Net.Share;
using global::System;
using UnityEngine;
using Net.Client;
/// <summary>
/// 网络Transform同步组件基类
/// </summary>
[DefaultExecutionOrder(1000)]
public class NetworkTransformMulti : NetworkTransformBase
{
public ChildTransform[] childs;
public override void Start()
{
base.Start();
for (int i = 0; i < childs.Length; i++)
{
childs[i].Init(i + 1);
}
}
public override void Update()
{
if (netObj.Identity == -1 | currMode == SyncMode.None)
return;
if (currMode == SyncMode.Synchronized)
{
SyncTransform();
for (int i = 0; i < childs.Length; i++)
{
childs[i].SyncTransform();
}
}
else if (Time.time > sendTime)
{
Check();
for (int i = 0; i < childs.Length; i++)
{
childs[i].Check(netObj.Identity, netObj.registerObjectIndex, NetComponentID);
}
sendTime = Time.time + (1f / rate);
}
}
public override void StartSyncTransformState()
{
ClientBase.Instance.AddOperation(new Operation(Command.Transform, netObj.Identity, syncScale ? localScale : Net.Vector3.zero, syncPosition ? position : Net.Vector3.zero, syncRotation ? rotation : Net.Quaternion.zero)
{
cmd1 = (byte)currMode,
index = netObj.registerObjectIndex,
index1 = NetComponentID,
uid = ClientBase.Instance.UID
});
}
public override void OnNetworkOperationHandler(Operation opt)
{
if (ClientBase.Instance.UID == opt.uid)
return;
sendTime = Time.time + interval;
if (opt.index2 == 0)
{
netPosition = opt.position;
netRotation = opt.rotation;
netLocalScale = opt.direction;
if (currMode == SyncMode.SynchronizedAll | currMode == SyncMode.Control)
SyncControlTransform();
else if (currMode == SyncMode.None)
{
var mode1 = (SyncMode)opt.cmd1;
if (mode1 == SyncMode.Control | mode1 == SyncMode.SynchronizedAll)
currMode = SyncMode.SynchronizedAll;
else
currMode = SyncMode.Synchronized;
}
}
else
{
var child = childs[opt.index2 - 1];
child.netPosition = opt.position;
child.netRotation = opt.rotation;
child.netLocalScale = opt.direction;
if (child.mode == SyncMode.SynchronizedAll | child.mode == SyncMode.Control)
child.SyncControlTransform();
}
}
}
[Serializable]
public class ChildTransform
{
public string name;
public Transform transform;
internal Net.Vector3 position;
internal Net.Quaternion rotation;
internal Net.Vector3 localScale;
public SyncMode mode = SyncMode.Control;
public bool syncPosition = true;
public bool syncRotation = true;
public bool syncScale = false;
public int identity = -1;//自身id
internal Net.Vector3 netPosition;
internal Net.Quaternion netRotation;
internal Net.Vector3 netLocalScale;
internal void Init(int identity)
{
this.identity = identity;
position = transform.localPosition;
rotation = transform.localRotation;
localScale = transform.localScale;
}
internal void Check(int identity, int index, int netIndex)
{
if (transform.localPosition != position | transform.localRotation != rotation | transform.localScale != localScale)
{
position = transform.localPosition;
rotation = transform.localRotation;
localScale = transform.localScale;
ClientBase.Instance.AddOperation(new Operation(Command.Transform, identity, syncScale ? localScale : Net.Vector3.zero, syncPosition ? position : Net.Vector3.zero, syncRotation ? rotation : Net.Quaternion.zero)
{
cmd1 = (byte)mode,
uid = ClientBase.Instance.UID,
index = index,
index1 = netIndex,
index2 = this.identity
});
}
}
public void SyncTransform()
{
if (syncPosition)
transform.localPosition = Vector3.Lerp(transform.localPosition, netPosition, 0.3f);
if (syncRotation)
if (netRotation != Net.Quaternion.identity)
transform.localRotation = Quaternion.Lerp(transform.localRotation, netRotation, 0.3f);
if (syncScale)
transform.localScale = netLocalScale;
}
public void SyncControlTransform()
{
if (syncPosition)
transform.localPosition = netPosition;
if (syncRotation)
transform.localRotation = netRotation;
if (syncScale)
transform.localScale = netLocalScale;
}
}
}
#endif