Mirror of Svelto.ECS because we're a fan of it
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

249 lignes
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. for (int index = 0; index < entityComponentsToSerialise.Length; index++)
  24. {
  25. var entityBuilder = entityComponentsToSerialise[index];
  26. serializationData.BeginNextEntityComponent();
  27. SerializeEntityComponent(egid, entityBuilder, serializationData, serializationType);
  28. }
  29. }
  30. public EntityInitializer DeserializeNewEntity(EGID egid, ISerializationData serializationData,
  31. int serializationType)
  32. {
  33. //todo: SerializableEntityHeader may be needed to be customizable
  34. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  35. uint descriptorHash = serializableEntityHeader.descriptorHash;
  36. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  37. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  38. IDeserializationFactory factory = serializationDescriptorMap.GetSerializationFactory(descriptorHash);
  39. return factory.BuildDeserializedEntity(egid, serializationData, entityDescriptor, serializationType,
  40. this, _enginesRoot.GenerateEntityFactory(), _enginesRoot is SerializingEnginesRoot);
  41. }
  42. public void DeserializeEntity(ISerializationData serializationData, int serializationType)
  43. {
  44. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  45. EGID egid = serializableEntityHeader.egid;
  46. DeserializeEntityInternal(serializationData, egid, serializableEntityHeader, serializationType);
  47. }
  48. public void DeserializeEntity(EGID egid, ISerializationData serializationData, int serializationType)
  49. {
  50. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  51. DeserializeEntityInternal(serializationData, egid, serializableEntityHeader, serializationType);
  52. }
  53. public void DeserializeEntityComponents(ISerializationData serializationData,
  54. ISerializableEntityDescriptor entityDescriptor, ref EntityInitializer initializer,
  55. int serializationType)
  56. {
  57. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  58. {
  59. serializationData.BeginNextEntityComponent();
  60. serializableEntityBuilder.Deserialize(serializationData, initializer, serializationType);
  61. }
  62. }
  63. /// <summary>
  64. /// Note this has been left undocumented and forgot over the months. The initial version was obviously
  65. /// wrong, as it wasn't looking for T but only assuming that T was the first component in the entity.
  66. /// It's also weird or at least must be revalidated, the fact that serializationData works only as
  67. /// a tape, so we need to reset datapos in case we do not want to forward the head.
  68. /// </summary>
  69. /// <param name="serializationData"></param>
  70. /// <param name="entityDescriptor"></param>
  71. /// <param name="serializationType"></param>
  72. /// <typeparam name="T"></typeparam>
  73. /// <returns></returns>
  74. public T DeserializeEntityComponent<T>(ISerializationData serializationData,
  75. ISerializableEntityDescriptor entityDescriptor, int serializationType)
  76. where T : unmanaged, IEntityComponent
  77. {
  78. var readPos = serializationData.dataPos;
  79. T entityComponent = default;
  80. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  81. {
  82. if (serializableEntityBuilder is SerializableComponentBuilder<T> entityBuilder)
  83. {
  84. entityBuilder.Deserialize(serializationData, ref entityComponent, serializationType);
  85. break;
  86. }
  87. else
  88. serializationData.dataPos += (uint)serializableEntityBuilder.Size(serializationType);
  89. }
  90. serializationData.dataPos = readPos;
  91. return entityComponent;
  92. }
  93. public void DeserializeEntityToSwap(EGID fromEGID, EGID toEGID, [CallerMemberName] string caller = null)
  94. {
  95. EntitiesDB entitiesDb = _enginesRoot._entitiesDB;
  96. ref var serializableEntityComponent = ref entitiesDb.QueryEntity<SerializableEntityComponent>(fromEGID);
  97. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  98. uint descriptorHash = serializableEntityComponent.descriptorHash;
  99. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  100. _enginesRoot.CheckRemoveEntityID(fromEGID, entityDescriptor.realType, caller);
  101. _enginesRoot.CheckAddEntityID(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. }