Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
3.6KB

  1. using System;
  2. using System.Reflection;
  3. using System.Runtime.InteropServices;
  4. using Svelto.DataStructures;
  5. using Attribute = System.Attribute;
  6. namespace Svelto.ECS.Serialization
  7. {
  8. [AttributeUsage(AttributeTargets.Field)]
  9. public class PartialSerializerFieldAttribute : Attribute
  10. {}
  11. public class PartialSerializer<T> : IComponentSerializer<T>
  12. where T : unmanaged, IEntityComponent
  13. {
  14. static PartialSerializer()
  15. {
  16. Type myType = typeof(T);
  17. FieldInfo[] myMembers = myType.GetFields();
  18. for (int i = 0; i < myMembers.Length; i++)
  19. {
  20. Object[] myAttributes = myMembers[i].GetCustomAttributes(true);
  21. for (int j = 0; j < myAttributes.Length; j++)
  22. {
  23. if (myAttributes[j] is PartialSerializerFieldAttribute)
  24. {
  25. var fieldType = myMembers[i].FieldType;
  26. if (fieldType.ContainsCustomAttribute(typeof(DoNotSerializeAttribute)) &&
  27. myMembers[i].IsPrivate == false)
  28. throw new ECSException($"field cannot be serialised {fieldType} in {myType.FullName}");
  29. var offset = Marshal.OffsetOf<T>(myMembers[i].Name);
  30. var sizeOf = (uint)Marshal.SizeOf(fieldType);
  31. offsets.Add(((uint) offset.ToInt32(), sizeOf));
  32. totalSize += sizeOf;
  33. }
  34. }
  35. }
  36. if (myType.GetProperties().Length > (ComponentBuilder<T>.HAS_EGID ? 1 : 0))
  37. throw new ECSException("serializable entity struct must be property less ".FastConcat(myType.FullName));
  38. }
  39. public bool Serialize(in T value, ISerializationData serializationData)
  40. {
  41. unsafe
  42. {
  43. fixed (byte* dataptr = serializationData.data.ToArrayFast(out _))
  44. {
  45. var entityComponent = value;
  46. foreach ((uint offset, uint size) offset in offsets)
  47. {
  48. byte* srcPtr = (byte*) &entityComponent + offset.offset;
  49. //todo move to Unsafe Copy when available as it is faster
  50. Buffer.MemoryCopy(srcPtr, dataptr + serializationData.dataPos,
  51. serializationData.data.count - serializationData.dataPos, offset.size);
  52. serializationData.dataPos += offset.size;
  53. }
  54. }
  55. }
  56. return true;
  57. }
  58. public bool Deserialize(ref T value, ISerializationData serializationData)
  59. {
  60. unsafe
  61. {
  62. T tempValue = value; //todo: temporary solution I want to get rid of this copy
  63. fixed (byte* dataptr = serializationData.data.ToArrayFast(out _))
  64. foreach ((uint offset, uint size) offset in offsets)
  65. {
  66. byte* dstPtr = (byte*) &tempValue + offset.offset;
  67. //todo move to Unsafe Copy when available as it is faster
  68. Buffer.MemoryCopy(dataptr + serializationData.dataPos, dstPtr, offset.size, offset.size);
  69. serializationData.dataPos += offset.size;
  70. }
  71. value = tempValue; //todo: temporary solution I want to get rid of this copy
  72. }
  73. return true;
  74. }
  75. public uint size => totalSize;
  76. static readonly FasterList<(uint, uint)> offsets = new FasterList<(uint, uint)>();
  77. static readonly uint totalSize;
  78. }
  79. }