SyncObjectProcessor.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. using System.Collections.Generic;
  2. using Mono.CecilX;
  3. namespace Mirror.Weaver
  4. {
  5. public static class SyncObjectProcessor
  6. {
  7. // ulong = 64 bytes
  8. const int SyncObjectsLimit = 64;
  9. // Finds SyncObjects fields in a type
  10. // Type should be a NetworkBehaviour
  11. public static List<FieldDefinition> FindSyncObjectsFields(Writers writers, Readers readers, Logger Log, TypeDefinition td, ref bool WeavingFailed)
  12. {
  13. List<FieldDefinition> syncObjects = new List<FieldDefinition>();
  14. foreach (FieldDefinition fd in td.Fields)
  15. {
  16. if (fd.FieldType.Resolve().IsDerivedFrom<SyncObject>())
  17. {
  18. if (fd.IsStatic)
  19. {
  20. Log.Error($"{fd.Name} cannot be static", fd);
  21. WeavingFailed = true;
  22. continue;
  23. }
  24. // SyncObjects always needs to be readonly to guarantee.
  25. // Weaver calls InitSyncObject on them for dirty bits etc.
  26. // Reassigning at runtime would cause undefined behaviour.
  27. // (C# 'readonly' is called 'initonly' in IL code.)
  28. //
  29. // NOTE: instead of forcing readonly, we could also scan all
  30. // instructions for SyncObject assignments. this would
  31. // make unit tests very difficult though.
  32. if (!fd.IsInitOnly)
  33. {
  34. // just a warning for now.
  35. // many people might still use non-readonly SyncObjects.
  36. Log.Warning($"{fd.Name} should have a 'readonly' keyword in front of the variable because {typeof(SyncObject)}s always need to be initialized by the Weaver.", fd);
  37. // only log, but keep weaving. no need to break projects.
  38. //WeavingFailed = true;
  39. }
  40. GenerateReadersAndWriters(writers, readers, fd.FieldType, ref WeavingFailed);
  41. syncObjects.Add(fd);
  42. }
  43. }
  44. // SyncObjects dirty mask is 64 bit. can't sync more than 64.
  45. if (syncObjects.Count > 64)
  46. {
  47. Log.Error($"{td.Name} has > {SyncObjectsLimit} SyncObjects (SyncLists etc). Consider refactoring your class into multiple components", td);
  48. WeavingFailed = true;
  49. }
  50. return syncObjects;
  51. }
  52. // Generates serialization methods for synclists
  53. static void GenerateReadersAndWriters(Writers writers, Readers readers, TypeReference tr, ref bool WeavingFailed)
  54. {
  55. if (tr is GenericInstanceType genericInstance)
  56. {
  57. foreach (TypeReference argument in genericInstance.GenericArguments)
  58. {
  59. if (!argument.IsGenericParameter)
  60. {
  61. readers.GetReadFunc(argument, ref WeavingFailed);
  62. writers.GetWriteFunc(argument, ref WeavingFailed);
  63. }
  64. }
  65. }
  66. if (tr != null)
  67. {
  68. GenerateReadersAndWriters(writers, readers, tr.Resolve().BaseType, ref WeavingFailed);
  69. }
  70. }
  71. }
  72. }