A stable modding interface between Techblox and mods https://mod.exmods.org/
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.

129 lines
6.0KB

  1. using System;
  2. using System.Collections.Generic;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS;
  5. using Svelto.Tasks;
  6. using Svelto.Tasks.Lean;
  7. using TechbloxModdingAPI.Tasks;
  8. namespace TechbloxModdingAPI.Utility.ECS
  9. {
  10. public static partial class NativeApiExtensions
  11. {
  12. /// <summary>
  13. /// Attempts to query an entity and returns an optional that contains the result if succeeded.
  14. /// <b>This overload does not take initializer data into account.</b>
  15. /// </summary>
  16. /// <param name="entitiesDB">The entities DB</param>
  17. /// <param name="egid">The EGID to query</param>
  18. /// <typeparam name="T">The component type to query</typeparam>
  19. /// <returns>An optional that contains the result on success or is empty if not found</returns>
  20. public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EGID egid)
  21. where T : unmanaged, IEntityComponent
  22. {
  23. return entitiesDB.TryQueryEntitiesAndIndex<T>(egid, out uint index, out var array)
  24. ? new OptionalRef<T>(array, index)
  25. : new OptionalRef<T>();
  26. }
  27. /// <summary>
  28. /// Attempts to query an entity and returns the result in an optional reference.
  29. /// </summary>
  30. /// <param name="entitiesDB">The entities DB to query from</param>
  31. /// <param name="obj">The ECS object to query</param>
  32. /// <param name="group">The group of the entity if the object can have multiple</param>
  33. /// <typeparam name="T">The component to query</typeparam>
  34. /// <returns>A reference to the component or a dummy value</returns>
  35. public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
  36. ExclusiveGroupStruct group = default)
  37. where T : unmanaged, IEntityComponent
  38. {
  39. EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
  40. var opt = QueryEntityOptional<T>(entitiesDB, id);
  41. return opt ? opt : new OptionalRef<T>(obj, true);
  42. }
  43. /// <summary>
  44. /// Attempts to query an entity and returns the result or a dummy value that can be modified.
  45. /// </summary>
  46. /// <param name="entitiesDB">The entities DB to query from</param>
  47. /// <param name="obj">The ECS object to query</param>
  48. /// <param name="group">The group of the entity if the object can have multiple</param>
  49. /// <typeparam name="T">The component to query</typeparam>
  50. /// <returns>A reference to the component or a dummy value</returns>
  51. public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj,
  52. ExclusiveGroupStruct group = default)
  53. where T : unmanaged, IEntityComponent
  54. {
  55. EGID id = group == ExclusiveGroupStruct.Invalid ? obj.Id : new EGID(obj.Id.entityID, group);
  56. var opt = QueryEntityOptional<T>(entitiesDB, id);
  57. if (opt) return ref opt.Get();
  58. if (obj.InitData.Valid) return ref obj.InitData.Initializer(id).GetOrAdd<T>();
  59. /*if (!obj.InitData.Valid) return ref opt.Get(); //Default value
  60. var init = obj.InitData.Initializer(id);
  61. // Do not create the component if missing, as that can trigger Add() listeners that, in some cases, may be
  62. // invalid if (ab)using the classes in an unusual way - TODO: Check entity descriptor or something
  63. if (init.Has<T>()) return ref init.Get<T>();*/
  64. return ref opt.Get(); //Default value
  65. }
  66. /// <summary>
  67. /// Publishes an entity change, ignoring duplicate publishes and delaying changes as necessary.
  68. /// It will only publish in the next frame.
  69. /// </summary>
  70. /// <param name="entitiesDB">The entities DB to publish to</param>
  71. /// <param name="id">The ECS object that got changed</param>
  72. /// <typeparam name="T">The component that changed</typeparam>
  73. public static void PublishEntityChangeDelayed<T>(this EntitiesDB entitiesDB, EGID id)
  74. where T : unmanaged, IEntityComponent
  75. {
  76. PublishChanges<T>(entitiesDB, id).RunOn(Scheduler.leanRunner);
  77. }
  78. private static IEnumerator<TaskContract> PublishChanges<T>(EntitiesDB entitiesDB, EGID id)
  79. where T : unmanaged, IEntityComponent
  80. {
  81. yield return Yield.It;
  82. var entityStream = entitiesDB.GetEntityStream<T>();
  83. if (entityStream is null)
  84. yield break; // There is no entity stream for this type
  85. var consumers = entityStream.GetConsumers();
  86. if (consumers == null)
  87. {
  88. Console.WriteLine("Consumers is null");
  89. yield break;
  90. }
  91. bool waitForConsumers;
  92. do
  93. {
  94. waitForConsumers = false;
  95. for (int i = 0; i < consumers.count; i++)
  96. {
  97. var buffer = consumers[i].GetRingBuffer();
  98. if (buffer.Count + 1 <= buffer.Capacity) continue;
  99. waitForConsumers = true;
  100. break;
  101. }
  102. if (waitForConsumers) yield return Yield.It;
  103. } while (waitForConsumers);
  104. entitiesDB.PublishEntityChange<T>(id);
  105. }
  106. /// <summary>
  107. /// Query entities as OptionalRefs. The elements always exist, it's just a nice way to encapsulate the data.
  108. /// </summary>
  109. /// <param name="entitiesDB"></param>
  110. /// <param name="group"></param>
  111. /// <param name="select"></param>
  112. /// <typeparam name="T"></typeparam>
  113. /// <typeparam name="TR"></typeparam>
  114. /// <returns></returns>
  115. public static RefCollection<T> QueryEntitiesOptional<T>(this EntitiesDB entitiesDB, ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent
  116. {
  117. var (buffer, ids, count) = entitiesDB.QueryEntities<T>(group);
  118. return new RefCollection<T>(count, buffer, ids, group);
  119. }
  120. }
  121. }