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.

125 lines
4.2KB

  1. using System;
  2. using System.Linq;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS;
  5. using TechbloxModdingAPI.Common;
  6. namespace TechbloxModdingAPI.Utility
  7. {
  8. public ref struct OptionalRef<T> where T : struct, IBaseEntityComponent
  9. {
  10. private readonly EGID entityId;
  11. private readonly State state;
  12. private readonly uint index;
  13. private NB<T> array;
  14. private MB<T> managedArray;
  15. private readonly EntityInitializer initializer;
  16. //The possible fields are: (index && (array || managedArray)) || initializer
  17. private readonly EcsObjectBase obj;
  18. public OptionalRef(NB<T> array, uint index, EGID entityId = default)
  19. {
  20. state = State.Native;
  21. this.array = array;
  22. this.index = index;
  23. this.entityId = entityId;
  24. initializer = default;
  25. managedArray = default;
  26. obj = default;
  27. }
  28. public OptionalRef(MB<T> array, uint index, EGID entityId = default)
  29. {
  30. state = State.Managed;
  31. managedArray = array;
  32. this.index = index;
  33. this.entityId = entityId;
  34. initializer = default;
  35. this.array = default;
  36. obj = default;
  37. }
  38. /// <summary>
  39. /// Wraps the initializer data, if present.
  40. /// </summary>
  41. /// <param name="obj">The object with the initializer</param>
  42. /// <param name="unmanaged">Whether the struct is unmanaged</param>
  43. public OptionalRef(EcsObjectBase obj, bool unmanaged, EGID entityId = default)
  44. {
  45. this.entityId = entityId;
  46. if (obj.InitData.Valid)
  47. {
  48. initializer = obj.InitData.Initializer(obj.Id);
  49. state = (unmanaged ? State.Native : State.Managed) | State.Initializer;
  50. }
  51. else
  52. {
  53. initializer = default;
  54. state = State.Empty;
  55. }
  56. array = default;
  57. index = default;
  58. managedArray = default;
  59. this.obj = obj;
  60. }
  61. /// <summary>
  62. /// Returns the value or a default value if empty. Supports objects that are being initialized.
  63. /// </summary>
  64. /// <returns>The value or the default value</returns>
  65. public ref T Get()
  66. {
  67. CompRefCache.Default = default; //The default value can be changed by mods
  68. if (state == State.Empty) return ref CompRefCache.Default;
  69. // If initializing the entity, check if the component is allowed by the descriptor, otherwise it could cause
  70. // issues in the game with Add() calls running unexpectedly
  71. if ((state & State.Initializer) != State.Empty && obj.AllowedEntityComponents.Contains(typeof(T)))
  72. return ref initializer.GetOrAdd<T>();
  73. if ((state & State.Native) != State.Empty) return ref array[index];
  74. return ref managedArray[index];
  75. }
  76. /// <summary>
  77. /// A non-by-ref view that allows getting and setting the value.
  78. /// </summary>
  79. public T Value
  80. {
  81. get => Get();
  82. set => Get() = value;
  83. }
  84. /// <summary>
  85. /// The ID of the entity this component belongs to or default if it doesn't exist.
  86. /// </summary>
  87. public EGID EGID => entityId;
  88. public bool Exists => state != State.Empty;
  89. public T? Nullable() => this ? Get() : default;
  90. public static implicit operator T(OptionalRef<T> opt) => opt.Get();
  91. public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty;
  92. public static implicit operator EGID(OptionalRef<T> opt) => opt.entityId;
  93. /// <summary>
  94. /// Creates an instance of a struct T that can be referenced.
  95. /// </summary>
  96. private struct CompRefCache
  97. {
  98. public static T Default;
  99. }
  100. /// <summary>
  101. /// A byte that holds state in its bits.
  102. /// </summary>
  103. [Flags]
  104. private enum State : byte
  105. {
  106. Empty,
  107. Native,
  108. Managed,
  109. Initializer = 4
  110. }
  111. }
  112. }