NetSerializer.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. #if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA_8_1
  2. using System;
  3. using System.Reflection;
  4. using System.Collections.Generic;
  5. #if WINRT || NETCORE
  6. using System.Linq;
  7. #endif
  8. namespace FlyingWormConsole3.LiteNetLib.Utils
  9. {
  10. public interface INetSerializable
  11. {
  12. void Serialize(NetDataWriter writer);
  13. void Desereialize(NetDataReader reader);
  14. }
  15. public abstract class NetSerializerHasher
  16. {
  17. public abstract ulong GetHash(string type);
  18. public abstract void WriteHash(ulong hash, NetDataWriter writer);
  19. public abstract ulong ReadHash(NetDataReader reader);
  20. }
  21. public sealed class FNVHasher : NetSerializerHasher
  22. {
  23. private readonly Dictionary<string, ulong> _hashCache = new Dictionary<string, ulong>();
  24. private readonly char[] _hashBuffer = new char[1024];
  25. public override ulong GetHash(string type)
  26. {
  27. ulong hash;
  28. if (_hashCache.TryGetValue(type, out hash))
  29. {
  30. return hash;
  31. }
  32. hash = 14695981039346656037UL; //offset
  33. int len = type.Length;
  34. type.CopyTo(0, _hashBuffer, 0, len);
  35. for (var i = 0; i < len; i++)
  36. {
  37. hash = hash ^ _hashBuffer[i];
  38. hash *= 1099511628211UL; //prime
  39. }
  40. _hashCache.Add(type, hash);
  41. return hash;
  42. }
  43. public override ulong ReadHash(NetDataReader reader)
  44. {
  45. return reader.GetULong();
  46. }
  47. public override void WriteHash(ulong hash, NetDataWriter writer)
  48. {
  49. writer.Put(hash);
  50. }
  51. }
  52. public sealed class NetSerializer
  53. {
  54. private sealed class CustomType
  55. {
  56. public readonly CustomTypeWrite WriteDelegate;
  57. public readonly CustomTypeRead ReadDelegate;
  58. public CustomType(CustomTypeWrite writeDelegate, CustomTypeRead readDelegate)
  59. {
  60. WriteDelegate = writeDelegate;
  61. ReadDelegate = readDelegate;
  62. }
  63. }
  64. private delegate void CustomTypeWrite(NetDataWriter writer, object customObj);
  65. private delegate object CustomTypeRead(NetDataReader reader);
  66. private sealed class StructInfo
  67. {
  68. public readonly Action<NetDataWriter>[] WriteDelegate;
  69. public readonly Action<NetDataReader>[] ReadDelegate;
  70. public readonly Type[] FieldTypes;
  71. public object Reference;
  72. public Func<object> CreatorFunc;
  73. public Action<object, object> OnReceive;
  74. public readonly ulong Hash;
  75. public readonly int MembersCount;
  76. public StructInfo(ulong hash, int membersCount)
  77. {
  78. Hash = hash;
  79. MembersCount = membersCount;
  80. WriteDelegate = new Action<NetDataWriter>[membersCount];
  81. ReadDelegate = new Action<NetDataReader>[membersCount];
  82. FieldTypes = new Type[membersCount];
  83. }
  84. public void Write(NetDataWriter writer, object obj)
  85. {
  86. Reference = obj;
  87. for (int i = 0; i < MembersCount; i++)
  88. {
  89. WriteDelegate[i](writer);
  90. }
  91. }
  92. public void Read(NetDataReader reader)
  93. {
  94. for (int i = 0; i < MembersCount; i++)
  95. {
  96. ReadDelegate[i](reader);
  97. }
  98. }
  99. }
  100. private readonly Dictionary<ulong, StructInfo> _cache;
  101. private readonly Dictionary<Type, CustomType> _registeredCustomTypes;
  102. private static readonly HashSet<Type> BasicTypes = new HashSet<Type>
  103. {
  104. typeof(int),
  105. typeof(uint),
  106. typeof(byte),
  107. typeof(sbyte),
  108. typeof(short),
  109. typeof(ushort),
  110. typeof(long),
  111. typeof(ulong),
  112. typeof(string),
  113. typeof(float),
  114. typeof(double),
  115. typeof(bool)
  116. };
  117. private readonly NetDataWriter _writer;
  118. private readonly NetSerializerHasher _hasher;
  119. private const int MaxStringLenght = 1024;
  120. public NetSerializer() : this(new FNVHasher())
  121. {
  122. }
  123. public NetSerializer(NetSerializerHasher hasher)
  124. {
  125. _hasher = hasher;
  126. _cache = new Dictionary<ulong, StructInfo>();
  127. _registeredCustomTypes = new Dictionary<Type, CustomType>();
  128. _writer = new NetDataWriter();
  129. }
  130. private bool RegisterCustomTypeInternal<T>(Func<T> constructor) where T : INetSerializable
  131. {
  132. var t = typeof(T);
  133. if (_registeredCustomTypes.ContainsKey(t))
  134. {
  135. return false;
  136. }
  137. var rwDelegates = new CustomType(
  138. (writer, obj) =>
  139. {
  140. ((T)obj).Serialize(writer);
  141. },
  142. reader =>
  143. {
  144. var instance = constructor();
  145. instance.Desereialize(reader);
  146. return instance;
  147. });
  148. _registeredCustomTypes.Add(t, rwDelegates);
  149. return true;
  150. }
  151. /// <summary>
  152. /// Register custom property type
  153. /// </summary>
  154. /// <typeparam name="T">INetSerializable structure</typeparam>
  155. /// <returns>True - if register successful, false - if type already registered</returns>
  156. public bool RegisterCustomType<T>() where T : struct, INetSerializable
  157. {
  158. return RegisterCustomTypeInternal(() => new T());
  159. }
  160. /// <summary>
  161. /// Register custom property type
  162. /// </summary>
  163. /// <typeparam name="T">INetSerializable class</typeparam>
  164. /// <returns>True - if register successful, false - if type already registered</returns>
  165. public bool RegisterCustomType<T>(Func<T> constructor) where T : class, INetSerializable
  166. {
  167. return RegisterCustomTypeInternal(constructor);
  168. }
  169. /// <summary>
  170. /// Register custom property type
  171. /// </summary>
  172. /// <param name="writeDelegate"></param>
  173. /// <param name="readDelegate"></param>
  174. /// <returns>True - if register successful, false - if type already registered</returns>
  175. public bool RegisterCustomType<T>(Action<NetDataWriter, T> writeDelegate, Func<NetDataReader, T> readDelegate)
  176. {
  177. var t = typeof(T);
  178. if (BasicTypes.Contains(t) || _registeredCustomTypes.ContainsKey(t))
  179. {
  180. return false;
  181. }
  182. var rwDelegates = new CustomType(
  183. (writer, obj) => writeDelegate(writer, (T)obj),
  184. reader => readDelegate(reader));
  185. _registeredCustomTypes.Add(t, rwDelegates);
  186. return true;
  187. }
  188. private static Delegate CreateDelegate(Type type, MethodInfo info)
  189. {
  190. #if WINRT || NETCORE
  191. return info.CreateDelegate(type);
  192. #else
  193. return Delegate.CreateDelegate(type, info);
  194. #endif
  195. }
  196. private static Func<TClass, TProperty> ExtractGetDelegate<TClass, TProperty>(MethodInfo info)
  197. {
  198. return (Func<TClass, TProperty>)CreateDelegate(typeof(Func<TClass, TProperty>), info);
  199. }
  200. private static Action<TClass, TProperty> ExtractSetDelegate<TClass, TProperty>(MethodInfo info)
  201. {
  202. return (Action<TClass, TProperty>)CreateDelegate(typeof(Action<TClass, TProperty>), info);
  203. }
  204. private StructInfo RegisterInternal<T>() where T : class
  205. {
  206. Type t = typeof(T);
  207. ulong nameHash = _hasher.GetHash(t.Name);
  208. StructInfo info;
  209. if (_cache.TryGetValue(nameHash, out info))
  210. {
  211. return info;
  212. }
  213. #if WINRT || NETCORE
  214. var props = t.GetRuntimeProperties().ToArray();
  215. int propsCount = props.Count();
  216. #else
  217. var props = t.GetProperties(
  218. BindingFlags.Instance |
  219. BindingFlags.Public |
  220. BindingFlags.GetProperty |
  221. BindingFlags.SetProperty);
  222. int propsCount = props.Length;
  223. #endif
  224. if (props == null || propsCount < 0)
  225. {
  226. throw new ArgumentException("Type does not contain acceptable fields");
  227. }
  228. info = new StructInfo(nameHash, propsCount);
  229. for (int i = 0; i < props.Length; i++)
  230. {
  231. var property = props[i];
  232. var propertyType = property.PropertyType;
  233. //Set field type
  234. info.FieldTypes[i] = propertyType.IsArray ? propertyType.GetElementType() : propertyType;
  235. #if WINRT || NETCORE
  236. bool isEnum = propertyType.GetTypeInfo().IsEnum;
  237. var getMethod = property.GetMethod;
  238. var setMethod = property.SetMethod;
  239. #else
  240. bool isEnum = propertyType.IsEnum;
  241. var getMethod = property.GetGetMethod();
  242. var setMethod = property.GetSetMethod();
  243. #endif
  244. if (isEnum)
  245. {
  246. var underlyingType = Enum.GetUnderlyingType(propertyType);
  247. if (underlyingType == typeof(byte))
  248. {
  249. info.ReadDelegate[i] = reader =>
  250. {
  251. property.SetValue(info.Reference, Enum.ToObject(propertyType, reader.GetByte()), null);
  252. };
  253. info.WriteDelegate[i] = writer =>
  254. {
  255. writer.Put((byte)property.GetValue(info.Reference, null));
  256. };
  257. }
  258. else if (underlyingType == typeof(int))
  259. {
  260. info.ReadDelegate[i] = reader =>
  261. {
  262. property.SetValue(info.Reference, Enum.ToObject(propertyType, reader.GetInt()), null);
  263. };
  264. info.WriteDelegate[i] = writer =>
  265. {
  266. writer.Put((int)property.GetValue(info.Reference, null));
  267. };
  268. }
  269. else
  270. {
  271. throw new Exception("Not supported enum underlying type: " + underlyingType.Name);
  272. }
  273. }
  274. else if (propertyType == typeof(string))
  275. {
  276. var setDelegate = ExtractSetDelegate<T, string>(setMethod);
  277. var getDelegate = ExtractGetDelegate<T, string>(getMethod);
  278. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetString(MaxStringLenght));
  279. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference), MaxStringLenght);
  280. }
  281. else if (propertyType == typeof(bool))
  282. {
  283. var setDelegate = ExtractSetDelegate<T, bool>(setMethod);
  284. var getDelegate = ExtractGetDelegate<T, bool>(getMethod);
  285. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetBool());
  286. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  287. }
  288. else if (propertyType == typeof(byte))
  289. {
  290. var setDelegate = ExtractSetDelegate<T, byte>(setMethod);
  291. var getDelegate = ExtractGetDelegate<T, byte>(getMethod);
  292. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetByte());
  293. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  294. }
  295. else if (propertyType == typeof(sbyte))
  296. {
  297. var setDelegate = ExtractSetDelegate<T, sbyte>(setMethod);
  298. var getDelegate = ExtractGetDelegate<T, sbyte>(getMethod);
  299. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetSByte());
  300. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  301. }
  302. else if (propertyType == typeof(short))
  303. {
  304. var setDelegate = ExtractSetDelegate<T, short>(setMethod);
  305. var getDelegate = ExtractGetDelegate<T, short>(getMethod);
  306. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetShort());
  307. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  308. }
  309. else if (propertyType == typeof(ushort))
  310. {
  311. var setDelegate = ExtractSetDelegate<T, ushort>(setMethod);
  312. var getDelegate = ExtractGetDelegate<T, ushort>(getMethod);
  313. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUShort());
  314. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  315. }
  316. else if (propertyType == typeof(int))
  317. {
  318. var setDelegate = ExtractSetDelegate<T, int>(setMethod);
  319. var getDelegate = ExtractGetDelegate<T, int>(getMethod);
  320. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetInt());
  321. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  322. }
  323. else if (propertyType == typeof(uint))
  324. {
  325. var setDelegate = ExtractSetDelegate<T, uint>(setMethod);
  326. var getDelegate = ExtractGetDelegate<T, uint>(getMethod);
  327. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUInt());
  328. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  329. }
  330. else if (propertyType == typeof(long))
  331. {
  332. var setDelegate = ExtractSetDelegate<T, long>(setMethod);
  333. var getDelegate = ExtractGetDelegate<T, long>(getMethod);
  334. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetLong());
  335. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  336. }
  337. else if (propertyType == typeof(ulong))
  338. {
  339. var setDelegate = ExtractSetDelegate<T, ulong>(setMethod);
  340. var getDelegate = ExtractGetDelegate<T, ulong>(getMethod);
  341. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetULong());
  342. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  343. }
  344. else if (propertyType == typeof(float))
  345. {
  346. var setDelegate = ExtractSetDelegate<T, float>(setMethod);
  347. var getDelegate = ExtractGetDelegate<T, float>(getMethod);
  348. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetFloat());
  349. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  350. }
  351. else if (propertyType == typeof(double))
  352. {
  353. var setDelegate = ExtractSetDelegate<T, double>(setMethod);
  354. var getDelegate = ExtractGetDelegate<T, double>(getMethod);
  355. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetDouble());
  356. info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
  357. }
  358. // Array types
  359. else if (propertyType == typeof(string[]))
  360. {
  361. var setDelegate = ExtractSetDelegate<T, string[]>(setMethod);
  362. var getDelegate = ExtractGetDelegate<T, string[]>(getMethod);
  363. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetStringArray(MaxStringLenght));
  364. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference), MaxStringLenght);
  365. }
  366. else if (propertyType == typeof(byte[]))
  367. {
  368. var setDelegate = ExtractSetDelegate<T, byte[]>(setMethod);
  369. var getDelegate = ExtractGetDelegate<T, byte[]>(getMethod);
  370. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetBytesWithLength());
  371. info.WriteDelegate[i] = writer => writer.PutBytesWithLength(getDelegate((T)info.Reference));
  372. }
  373. else if (propertyType == typeof(short[]))
  374. {
  375. var setDelegate = ExtractSetDelegate<T, short[]>(setMethod);
  376. var getDelegate = ExtractGetDelegate<T, short[]>(getMethod);
  377. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetShortArray());
  378. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  379. }
  380. else if (propertyType == typeof(ushort[]))
  381. {
  382. var setDelegate = ExtractSetDelegate<T, ushort[]>(setMethod);
  383. var getDelegate = ExtractGetDelegate<T, ushort[]>(getMethod);
  384. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUShortArray());
  385. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  386. }
  387. else if (propertyType == typeof(int[]))
  388. {
  389. var setDelegate = ExtractSetDelegate<T, int[]>(setMethod);
  390. var getDelegate = ExtractGetDelegate<T, int[]>(getMethod);
  391. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetIntArray());
  392. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  393. }
  394. else if (propertyType == typeof(uint[]))
  395. {
  396. var setDelegate = ExtractSetDelegate<T, uint[]>(setMethod);
  397. var getDelegate = ExtractGetDelegate<T, uint[]>(getMethod);
  398. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUIntArray());
  399. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  400. }
  401. else if (propertyType == typeof(long[]))
  402. {
  403. var setDelegate = ExtractSetDelegate<T, long[]>(setMethod);
  404. var getDelegate = ExtractGetDelegate<T, long[]>(getMethod);
  405. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetLongArray());
  406. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  407. }
  408. else if (propertyType == typeof(ulong[]))
  409. {
  410. var setDelegate = ExtractSetDelegate<T, ulong[]>(setMethod);
  411. var getDelegate = ExtractGetDelegate<T, ulong[]>(getMethod);
  412. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetULongArray());
  413. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  414. }
  415. else if (propertyType == typeof(float[]))
  416. {
  417. var setDelegate = ExtractSetDelegate<T, float[]>(setMethod);
  418. var getDelegate = ExtractGetDelegate<T, float[]>(getMethod);
  419. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetFloatArray());
  420. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  421. }
  422. else if (propertyType == typeof(double[]))
  423. {
  424. var setDelegate = ExtractSetDelegate<T, double[]>(setMethod);
  425. var getDelegate = ExtractGetDelegate<T, double[]>(getMethod);
  426. info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetDoubleArray());
  427. info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
  428. }
  429. else
  430. {
  431. CustomType registeredCustomType;
  432. bool array = false;
  433. if (propertyType.IsArray)
  434. {
  435. array = true;
  436. propertyType = propertyType.GetElementType();
  437. }
  438. if (_registeredCustomTypes.TryGetValue(propertyType, out registeredCustomType))
  439. {
  440. if (array) //Array type serialize/deserialize
  441. {
  442. info.ReadDelegate[i] = reader =>
  443. {
  444. ushort arrLength = reader.GetUShort();
  445. Array arr = Array.CreateInstance(propertyType, arrLength);
  446. for (int k = 0; k < arrLength; k++)
  447. {
  448. arr.SetValue(registeredCustomType.ReadDelegate(reader), k);
  449. }
  450. property.SetValue(info.Reference, arr, null);
  451. };
  452. info.WriteDelegate[i] = writer =>
  453. {
  454. Array arr = (Array)property.GetValue(info.Reference, null);
  455. writer.Put((ushort)arr.Length);
  456. for (int k = 0; k < arr.Length; k++)
  457. {
  458. registeredCustomType.WriteDelegate(writer, arr.GetValue(k));
  459. }
  460. };
  461. }
  462. else //Simple
  463. {
  464. info.ReadDelegate[i] = reader =>
  465. {
  466. property.SetValue(info.Reference, registeredCustomType.ReadDelegate(reader), null);
  467. };
  468. info.WriteDelegate[i] = writer =>
  469. {
  470. registeredCustomType.WriteDelegate(writer, property.GetValue(info.Reference, null));
  471. };
  472. }
  473. }
  474. else
  475. {
  476. throw new Exception("Unknown property type: " + propertyType.Name);
  477. }
  478. }
  479. }
  480. _cache.Add(nameHash, info);
  481. return info;
  482. }
  483. /// <summary>
  484. /// Reads all available data from NetDataReader and calls OnReceive delegates
  485. /// </summary>
  486. /// <param name="reader">NetDataReader with packets data</param>
  487. public void ReadAllPackets(NetDataReader reader)
  488. {
  489. while (reader.AvailableBytes > 0)
  490. {
  491. ReadPacket(reader);
  492. }
  493. }
  494. /// <summary>
  495. /// Reads all available data from NetDataReader and calls OnReceive delegates
  496. /// </summary>
  497. /// <param name="reader">NetDataReader with packets data</param>
  498. /// <param name="userData">Argument that passed to OnReceivedEvent</param>
  499. public void ReadAllPackets<T>(NetDataReader reader, T userData)
  500. {
  501. while (reader.AvailableBytes > 0)
  502. {
  503. ReadPacket(reader, userData);
  504. }
  505. }
  506. /// <summary>
  507. /// Reads one packet from NetDataReader and calls OnReceive delegate
  508. /// </summary>
  509. /// <param name="reader">NetDataReader with packet</param>
  510. public void ReadPacket(NetDataReader reader)
  511. {
  512. ReadPacket(reader, null);
  513. }
  514. private StructInfo ReadInfo(NetDataReader reader)
  515. {
  516. ulong hash = _hasher.ReadHash(reader);
  517. StructInfo info;
  518. if (!_cache.TryGetValue(hash, out info))
  519. {
  520. throw new Exception("Undefined packet received");
  521. }
  522. return info;
  523. }
  524. /// <summary>
  525. /// Reads packet with known type
  526. /// </summary>
  527. /// <param name="reader">NetDataReader with packet</param>
  528. /// <returns>Returns packet if packet in reader is matched type</returns>
  529. public T ReadKnownPacket<T>(NetDataReader reader) where T : class, new()
  530. {
  531. var info = ReadInfo(reader);
  532. ulong typeHash = _hasher.GetHash(typeof(T).Name);
  533. if (typeHash != info.Hash)
  534. {
  535. return null;
  536. }
  537. info.Reference = info.CreatorFunc != null ? info.CreatorFunc() : Activator.CreateInstance<T>();
  538. info.Read(reader);
  539. return (T)info.Reference;
  540. }
  541. /// <summary>
  542. /// Reads packet with known type (non alloc variant)
  543. /// </summary>
  544. /// <param name="reader">NetDataReader with packet</param>
  545. /// <param name="target">Deserialization target</param>
  546. /// <returns>Returns true if packet in reader is matched type</returns>
  547. public bool ReadKnownPacket<T>(NetDataReader reader, T target) where T : class, new()
  548. {
  549. var info = ReadInfo(reader);
  550. ulong typeHash = _hasher.GetHash(typeof(T).Name);
  551. if (typeHash != info.Hash)
  552. {
  553. return false;
  554. }
  555. info.Reference = target;
  556. info.Read(reader);
  557. return true;
  558. }
  559. /// <summary>
  560. /// Reads one packet from NetDataReader and calls OnReceive delegate
  561. /// </summary>
  562. /// <param name="reader">NetDataReader with packet</param>
  563. /// <param name="userData">Argument that passed to OnReceivedEvent</param>
  564. public void ReadPacket(NetDataReader reader, object userData)
  565. {
  566. var info = ReadInfo(reader);
  567. if (info.CreatorFunc != null)
  568. {
  569. info.Reference = info.CreatorFunc();
  570. }
  571. info.Read(reader);
  572. info.OnReceive(info.Reference, userData);
  573. }
  574. /// <summary>
  575. /// Register and subscribe to packet receive event
  576. /// </summary>
  577. /// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
  578. /// <param name="packetConstructor">Method that constructs packet intead of slow Activator.CreateInstance</param>
  579. public void Subscribe<T>(Action<T> onReceive, Func<T> packetConstructor) where T : class, new()
  580. {
  581. var info = RegisterInternal<T>();
  582. info.CreatorFunc = () => packetConstructor();
  583. info.OnReceive = (o, userData) => { onReceive((T)o); };
  584. }
  585. /// <summary>
  586. /// Register packet type for direct reading (ReadKnownPacket)
  587. /// </summary>
  588. /// <param name="packetConstructor">Method that constructs packet intead of slow Activator.CreateInstance</param>
  589. public void Register<T>(Func<T> packetConstructor = null) where T : class, new()
  590. {
  591. var info = RegisterInternal<T>();
  592. if (packetConstructor != null)
  593. {
  594. info.CreatorFunc = () => packetConstructor();
  595. }
  596. info.OnReceive = (o, userData) => { };
  597. }
  598. /// <summary>
  599. /// Register and subscribe to packet receive event (with userData)
  600. /// </summary>
  601. /// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
  602. /// <param name="packetConstructor">Method that constructs packet intead of slow Activator.CreateInstance</param>
  603. public void Subscribe<T, TUserData>(Action<T, TUserData> onReceive, Func<T> packetConstructor) where T : class, new()
  604. {
  605. var info = RegisterInternal<T>();
  606. info.CreatorFunc = () => packetConstructor();
  607. info.OnReceive = (o, userData) => { onReceive((T)o, (TUserData)userData); };
  608. }
  609. /// <summary>
  610. /// Register and subscribe to packet receive event
  611. /// This metod will overwrite last received packet class on receive (less garbage)
  612. /// </summary>
  613. /// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
  614. public void SubscribeReusable<T>(Action<T> onReceive) where T : class, new()
  615. {
  616. var info = RegisterInternal<T>();
  617. info.Reference = new T();
  618. info.OnReceive = (o, userData) => { onReceive((T)o); };
  619. }
  620. /// <summary>
  621. /// Register and subscribe to packet receive event
  622. /// This metod will overwrite last received packet class on receive (less garbage)
  623. /// </summary>
  624. /// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
  625. public void SubscribeReusable<T, TUserData>(Action<T, TUserData> onReceive) where T : class, new()
  626. {
  627. var info = RegisterInternal<T>();
  628. info.Reference = new T();
  629. info.OnReceive = (o, userData) => { onReceive((T)o, (TUserData)userData); };
  630. }
  631. /// <summary>
  632. /// Serialize struct to NetDataWriter (fast)
  633. /// </summary>
  634. /// <param name="writer">Serialization target NetDataWriter</param>
  635. /// <param name="obj">Struct to serialize</param>
  636. public void Serialize<T>(NetDataWriter writer, T obj) where T : class, new()
  637. {
  638. var info = RegisterInternal<T>();
  639. _hasher.WriteHash(info.Hash, writer);
  640. info.Write(writer, obj);
  641. }
  642. /// <summary>
  643. /// Serialize struct to byte array
  644. /// </summary>
  645. /// <param name="obj">Struct to serialize</param>
  646. /// <returns>byte array with serialized data</returns>
  647. public byte[] Serialize<T>(T obj) where T : class, new()
  648. {
  649. _writer.Reset();
  650. Serialize(_writer, obj);
  651. return _writer.CopyData();
  652. }
  653. }
  654. }
  655. #endif