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.

94 lines
3.0KB

  1. using System;
  2. using System.Runtime.InteropServices;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS;
  5. namespace TechbloxModdingAPI.Utility
  6. {
  7. [StructLayout(LayoutKind.Explicit)] //Make the array and managedArray fields take up the same space
  8. public ref struct OptionalRef<T> where T : struct, IEntityComponent
  9. {
  10. [FieldOffset(0)] private readonly State state;
  11. [FieldOffset(1)] private readonly uint index;
  12. [FieldOffset(5)] private NB<T> array;
  13. [FieldOffset(5)] private MB<T> managedArray;
  14. [FieldOffset(1)] private readonly EntityInitializer initializer;
  15. //The possible fields are: (index && (array || managedArray)) || initializer
  16. public OptionalRef(NB<T> array, uint index)
  17. {
  18. state = State.Native;
  19. this.array = array;
  20. this.index = index;
  21. initializer = default;
  22. }
  23. public OptionalRef(MB<T> array, uint index)
  24. {
  25. state = State.Managed;
  26. managedArray = array;
  27. this.index = index;
  28. initializer = default;
  29. this.array = default;
  30. }
  31. /// <summary>
  32. /// Wraps the initializer data, if present.
  33. /// </summary>
  34. /// <param name="obj">The object with the initializer</param>
  35. /// <param name="unmanaged">Whether the struct is unmanaged</param>
  36. public OptionalRef(EcsObjectBase obj, bool unmanaged)
  37. {
  38. if (obj.InitData.Valid)
  39. {
  40. initializer = obj.InitData.Initializer(obj.Id);
  41. state = (unmanaged ? State.Native : State.Managed) | State.Initializer;
  42. }
  43. else
  44. {
  45. initializer = default;
  46. state = State.Empty;
  47. }
  48. array = default;
  49. index = default;
  50. }
  51. /// <summary>
  52. /// Returns the value or a default value if empty. Supports objects that are being initialized.
  53. /// </summary>
  54. /// <returns>The value or the default value</returns>
  55. public ref T Get()
  56. {
  57. if (state == State.Empty) return ref CompRefCache.Default;
  58. if ((state & State.Initializer) != State.Empty) return ref initializer.GetOrCreate<T>();
  59. if ((state & State.Native) != State.Empty) return ref array[index];
  60. return ref managedArray[index];
  61. }
  62. public bool Exists => state != State.Empty;
  63. public static implicit operator T(OptionalRef<T> opt) => opt.Get();
  64. public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty;
  65. /// <summary>
  66. /// Creates an instance of a struct T that can be referenced.
  67. /// </summary>
  68. internal struct CompRefCache
  69. {
  70. public static T Default;
  71. }
  72. /// <summary>
  73. /// A byte that holds state in its bits.
  74. /// </summary>
  75. [Flags]
  76. private enum State : byte
  77. {
  78. Empty,
  79. Native,
  80. Managed,
  81. Initializer = 4
  82. }
  83. }
  84. }