Mirror of Svelto.ECS because we're a fan of it
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
12KB

  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.CheckSwapEntityID(fromEGID, toEGID, entityDescriptor.realType, caller);
  101. /// Serializable Entity Descriptors can be extended so we need to use FindRealComponents
  102. _enginesRoot.QueueSwapEntityOperation(fromEGID, toEGID,
  103. _enginesRoot.FindRealComponents(fromEGID, entityDescriptor.componentsToBuild), caller);
  104. }
  105. public void DeserializeEntityToDelete(EGID egid, [CallerMemberName] string caller = null)
  106. {
  107. EntitiesDB entitiesDB = _enginesRoot._entitiesDB;
  108. ref var serializableEntityComponent = ref entitiesDB.QueryEntity<SerializableEntityComponent>(egid);
  109. uint descriptorHash = serializableEntityComponent.descriptorHash;
  110. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  111. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  112. _enginesRoot.CheckRemoveEntityID(egid, entityDescriptor.realType, caller);
  113. try
  114. {
  115. /// Serializable Entity Descriptors can be extended so we need to use FindRealComponents
  116. _enginesRoot.QueueRemoveEntityOperation(egid,
  117. _enginesRoot.FindRealComponents(egid, entityDescriptor.componentsToBuild), caller);
  118. }
  119. catch
  120. {
  121. Console.LogError(
  122. $"something went wrong while deserializing entity {entityDescriptor.realType}");
  123. throw;
  124. }
  125. }
  126. public void SkipEntityDeserialization(ISerializationData serializationData, int serializationType,
  127. int numberOfEntities)
  128. {
  129. uint dataPositionBeforeHeader = serializationData.dataPos;
  130. var serializableEntityHeader = new SerializableEntityHeader(serializationData);
  131. uint headerSize = serializationData.dataPos - dataPositionBeforeHeader;
  132. uint descriptorHash = serializableEntityHeader.descriptorHash;
  133. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  134. var entityDescriptor = serializationDescriptorMap.GetDescriptorFromHash(descriptorHash);
  135. uint componentSizeTotal = 0;
  136. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  137. {
  138. componentSizeTotal += (uint)serializableEntityBuilder.Size(serializationType);
  139. }
  140. //When constructing an SerializableEntityHeader the data position of the serializationData is incremented by the size of the header.
  141. //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
  142. //been incremented once.
  143. var totalBytesToSkip = (uint)(headerSize * (numberOfEntities - 1)) +
  144. (uint)(componentSizeTotal * numberOfEntities);
  145. serializationData.dataPos += totalBytesToSkip;
  146. }
  147. public uint GetHashFromGroup(ExclusiveGroupStruct groupStruct)
  148. {
  149. return GroupHashMap.GetHashFromGroup(groupStruct);
  150. }
  151. public ExclusiveGroupStruct GetGroupFromHash(uint groupHash)
  152. {
  153. return GroupHashMap.GetGroupFromHash(groupHash);
  154. }
  155. public void RegisterSerializationFactory<T>(IDeserializationFactory deserializationFactory)
  156. where T : ISerializableEntityDescriptor, new()
  157. {
  158. SerializationDescriptorMap serializationDescriptorMap = _enginesRoot._serializationDescriptorMap;
  159. serializationDescriptorMap.RegisterSerializationFactory<T>(deserializationFactory);
  160. }
  161. internal EntitySerialization(EnginesRoot enginesRoot)
  162. {
  163. _root = new DataStructures.WeakReference<EnginesRoot>(enginesRoot);
  164. }
  165. void SerializeEntityComponent(EGID entityGID, ISerializableComponentBuilder componentBuilder,
  166. ISerializationData serializationData, int serializationType)
  167. {
  168. ExclusiveGroupStruct groupId = entityGID.groupID;
  169. var entityType = componentBuilder.getComponentID;
  170. if (!_enginesRoot._entitiesDB.UnsafeQueryEntityDictionary(groupId, entityType, out var safeDictionary))
  171. {
  172. throw new Exception("Entity Serialization failed");
  173. }
  174. componentBuilder.Serialize(entityGID.entityID, safeDictionary, serializationData, serializationType);
  175. }
  176. void DeserializeEntityInternal(ISerializationData serializationData, EGID egid,
  177. SerializableEntityHeader serializableEntityHeader, int serializationType)
  178. {
  179. SerializationDescriptorMap descriptorMap = _enginesRoot._serializationDescriptorMap;
  180. var entityDescriptor = descriptorMap.GetDescriptorFromHash(serializableEntityHeader.descriptorHash);
  181. if (_enginesRoot._groupEntityComponentsDB.TryGetValue(egid.groupID, out var entitiesInGroupPerType) ==
  182. false)
  183. throw new Exception("Entity Serialization failed");
  184. foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize)
  185. {
  186. entitiesInGroupPerType.TryGetValue(
  187. serializableEntityBuilder.getComponentID, out var safeDictionary);
  188. serializationData.BeginNextEntityComponent();
  189. serializableEntityBuilder.Deserialize(egid.entityID, safeDictionary, serializationData,
  190. serializationType);
  191. }
  192. }
  193. EnginesRoot _enginesRoot => _root.Target;
  194. readonly DataStructures.WeakReference<EnginesRoot> _root;
  195. }
  196. public IEntitySerialization GenerateEntitySerializer()
  197. {
  198. return new EntitySerialization(this);
  199. }
  200. }
  201. }