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.

249 lines
13KB

  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS.Serialization;
  5. namespace Svelto.ECS
  6. {
  7. public partial class EnginesRoot
  8. {
  9. sealed class EntitySerialization : IEntitySerialization
  10. {
  11. public void SerializeEntity(EGID egid, ISerializationData serializationData, int serializationType)
  12. {
  13. var entitiesDb = _enginesRoot._entitiesDB;
  14. //needs to retrieve the meta data associated with the entity
  15. ref var serializableEntityComponent = ref entitiesDb.QueryEntity<SerializableEntityComponent>(egid);
  16. uint descriptorHash = serializableEntityComponent.descriptorHash;
  17. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  18. ISerializableEntityDescriptor entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  19. ISerializableComponentBuilder[] entityComponentsToSerialise = entityDescriptor.componentsToSerialize;
  20. var header =
  21. new SerializableEntityHeader(descriptorHash, egid, (byte)entityComponentsToSerialise.Length);
  22. header.Copy(serializationData);
  23. var length = entityComponentsToSerialise.Length;
  24. for (int index = 0; index < length; index++)
  25. {
  26. var entityBuilder = entityComponentsToSerialise[index];
  27. serializationData.BeginNextEntityComponent();
  28. SerializeEntityComponent(egid, entityBuilder, serializationData, serializationType);
  29. }
  30. }
  31. public EntityInitializer DeserializeNewEntity(EGID egid, ISerializationData serializationData,
  32. int serializationType)
  33. {
  34. //todo: SerializableEntityHeader may be needed to be customizable
  35. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  36. uint descriptorHash = serializableEntityHeader.descriptorHash;
  37. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  38. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  39. IDeserializationFactory factory = serializationDescriptorMap.GetSerializationFactory(descriptorHash);
  40. return factory.BuildDeserializedEntity(egid, serializationData, entityDescriptor, serializationType,
  41. this, _enginesRoot.GenerateEntityFactory(), _enginesRoot is SerializingEnginesRoot);
  42. }
  43. public void DeserializeEntity(ISerializationData serializationData, int serializationType)
  44. {
  45. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  46. EGID egid = serializableEntityHeader.egid;
  47. DeserializeEntityInternal(serializationData, egid, serializableEntityHeader, serializationType);
  48. }
  49. public void DeserializeEntity(EGID egid, ISerializationData serializationData, int serializationType)
  50. {
  51. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  52. DeserializeEntityInternal(serializationData, egid, serializableEntityHeader, serializationType);
  53. }
  54. public void DeserializeEntityComponents(ISerializationData serializationData,
  55. ISerializableEntityDescriptor entityDescriptor, ref EntityInitializer initializer,
  56. int serializationType)
  57. {
  58. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  59. {
  60. serializationData.BeginNextEntityComponent();
  61. serializableEntityBuilder.Deserialize(serializationData, initializer, serializationType);
  62. }
  63. }
  64. /// <summary>
  65. /// Note this has been left undocumented and forgot over the months. The initial version was obviously
  66. /// wrong, as it wasn't looking for T but only assuming that T was the first component in the entity.
  67. /// It's also weird or at least must be revalidated, the fact that serializationData works only as
  68. /// a tape, so we need to reset datapos in case we do not want to forward the head.
  69. /// </summary>
  70. /// <param name="serializationData"></param>
  71. /// <param name="entityDescriptor"></param>
  72. /// <param name="serializationType"></param>
  73. /// <typeparam name="T"></typeparam>
  74. /// <returns></returns>
  75. public T DeserializeEntityComponent<T>(ISerializationData serializationData,
  76. ISerializableEntityDescriptor entityDescriptor, int serializationType)
  77. where T : unmanaged, IEntityComponent
  78. {
  79. var readPos = serializationData.dataPos;
  80. T entityComponent = default;
  81. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  82. {
  83. if (serializableEntityBuilder is SerializableComponentBuilder<T> entityBuilder)
  84. {
  85. entityBuilder.Deserialize(serializationData, ref entityComponent, serializationType);
  86. break;
  87. }
  88. else
  89. serializationData.dataPos += (uint)serializableEntityBuilder.Size(serializationType);
  90. }
  91. serializationData.dataPos = readPos;
  92. return entityComponent;
  93. }
  94. public void DeserializeEntityToSwap(EGID fromEGID, EGID toEGID, [CallerMemberName] string caller = null)
  95. {
  96. EntitiesDB entitiesDb = _enginesRoot._entitiesDB;
  97. ref var serializableEntityComponent = ref entitiesDb.QueryEntity<SerializableEntityComponent>(fromEGID);
  98. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  99. uint descriptorHash = serializableEntityComponent.descriptorHash;
  100. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  101. _enginesRoot.CheckSwapEntityID(fromEGID, toEGID, entityDescriptor.realType, caller);
  102. /// Serializable Entity Descriptors can be extended so we need to use FindRealComponents
  103. _enginesRoot.QueueSwapEntityOperation(fromEGID, toEGID,
  104. _enginesRoot.FindRealComponents(fromEGID, entityDescriptor.componentsToBuild), caller);
  105. }
  106. public void DeserializeEntityToDelete(EGID egid, [CallerMemberName] string caller = null)
  107. {
  108. EntitiesDB entitiesDB = _enginesRoot._entitiesDB;
  109. ref var serializableEntityComponent = ref entitiesDB.QueryEntity<SerializableEntityComponent>(egid);
  110. uint descriptorHash = serializableEntityComponent.descriptorHash;
  111. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  112. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  113. _enginesRoot.CheckRemoveEntityID(egid, entityDescriptor.realType, caller);
  114. try
  115. {
  116. /// Serializable Entity Descriptors can be extended so we need to use FindRealComponents
  117. _enginesRoot.QueueRemoveEntityOperation(egid,
  118. _enginesRoot.FindRealComponents(egid, entityDescriptor.componentsToBuild), caller);
  119. }
  120. catch
  121. {
  122. Console.LogError(
  123. $"something went wrong while deserializing entity {entityDescriptor.realType}");
  124. throw;
  125. }
  126. }
  127. public void SkipEntityDeserialization(ISerializationData serializationData, int serializationType,
  128. int numberOfEntities)
  129. {
  130. uint dataPositionBeforeHeader = serializationData.dataPos;
  131. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  132. uint headerSize = serializationData.dataPos - dataPositionBeforeHeader;
  133. uint descriptorHash = serializableEntityHeader.descriptorHash;
  134. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  135. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  136. uint componentSizeTotal = 0;
  137. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  138. {
  139. componentSizeTotal += (uint)serializableEntityBuilder.Size(serializationType);
  140. }
  141. //When constructing an SerializableEntityHeader the data position of the serializationData is incremented by the size of the header.
  142. //Since a header is needed to get the entity descriptor, we need to account for one less header than usual, since the data has already
  143. //been incremented once.
  144. var totalBytesToSkip = (uint)(headerSize * (numberOfEntities - 1)) +
  145. (uint)(componentSizeTotal * numberOfEntities);
  146. serializationData.dataPos += totalBytesToSkip;
  147. }
  148. public uint GetHashFromGroup(ExclusiveGroupStruct groupStruct)
  149. {
  150. return GroupHashMap.GetHashFromGroup(groupStruct);
  151. }
  152. public ExclusiveGroupStruct GetGroupFromHash(uint groupHash)
  153. {
  154. return GroupHashMap.GetGroupFromHash(groupHash);
  155. }
  156. public void RegisterSerializationFactory<T>(IDeserializationFactory deserializationFactory)
  157. where T : ISerializableEntityDescriptor, new()
  158. {
  159. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  160. serializationDescriptorMap.RegisterSerializationFactory<T>(deserializationFactory);
  161. }
  162. internal EntitySerialization(EnginesRoot enginesRoot)
  163. {
  164. _root = new DataStructures.WeakReference<EnginesRoot>(enginesRoot);
  165. }
  166. void SerializeEntityComponent(EGID entityGID, ISerializableComponentBuilder componentBuilder,
  167. ISerializationData serializationData, int serializationType)
  168. {
  169. ExclusiveGroupStruct groupId = entityGID.groupID;
  170. var entityType = componentBuilder.getComponentID;
  171. if (!_enginesRoot._entitiesDB.UnsafeQueryEntityDictionary(groupId, entityType, out var safeDictionary))
  172. {
  173. throw new Exception("Entity Serialization failed");
  174. }
  175. componentBuilder.Serialize(entityGID.entityID, safeDictionary, serializationData, serializationType);
  176. }
  177. void DeserializeEntityInternal(ISerializationData serializationData, EGID egid,
  178. SerializableEntityHeader serializableEntityHeader, int serializationType)
  179. {
  180. SerializationDescriptorMap descriptorMap = _enginesRoot._serializationDescriptorMap;
  181. var entityDescriptor = descriptorMap.GetDescriptorFromHash(serializableEntityHeader.descriptorHash);
  182. if (_enginesRoot._groupEntityComponentsDB.TryGetValue(egid.groupID, out var entitiesInGroupPerType) ==
  183. false)
  184. throw new Exception("Entity Serialization failed");
  185. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  186. {
  187. entitiesInGroupPerType.TryGetValue(
  188. serializableEntityBuilder.getComponentID, out var safeDictionary);
  189. serializationData.BeginNextEntityComponent();
  190. serializableEntityBuilder.Deserialize(egid.entityID, safeDictionary, serializationData,
  191. serializationType);
  192. }
  193. }
  194. EnginesRoot _enginesRoot => _root.Target;
  195. readonly DataStructures.WeakReference<EnginesRoot> _root;
  196. }
  197. public IEntitySerialization GenerateEntitySerializer()
  198. {
  199. return new EntitySerialization(this);
  200. }
  201. }
  202. }