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.

196 lines
6.2KB

  1. using Svelto.ECS;
  2. using Svelto.DataStructures;
  3. using Gamecraft.Wires;
  4. using GamecraftModdingAPI.Engines;
  5. namespace GamecraftModdingAPI.Blocks
  6. {
  7. /// <summary>
  8. /// Engine which executes signal actions
  9. /// </summary>
  10. public class SignalEngine : IApiEngine
  11. {
  12. public const float POSITIVE_HIGH = 1.0f;
  13. public const float NEGATIVE_HIGH = -1.0f;
  14. public const float HIGH = 1.0f;
  15. public const float ZERO = 0.0f;
  16. public string Name { get; } = "GamecraftModdingAPISignalGameEngine";
  17. public EntitiesDB entitiesDB { set; private get; }
  18. public bool isRemovable => false;
  19. public bool IsInGame = false;
  20. public void Dispose()
  21. {
  22. IsInGame = false;
  23. }
  24. public void Ready()
  25. {
  26. IsInGame = true;
  27. }
  28. // implementations for Signal static class
  29. public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true)
  30. {
  31. signalID = GetSignalIDs(blockID, input)[0];
  32. return SetSignal(signalID, signal);
  33. }
  34. public bool SetSignal(uint signalID, float signal, bool input = true)
  35. {
  36. var array = GetSignalStruct(signalID, out uint index, input);
  37. if (array.count > 0) array[index].valueAsFloat = signal;
  38. return false;
  39. }
  40. public float AddSignal(EGID blockID, float signal, out uint signalID, bool clamp = true, bool input = true)
  41. {
  42. signalID = GetSignalIDs(blockID, input)[0];
  43. return AddSignal(signalID, signal, clamp, input);
  44. }
  45. public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true)
  46. {
  47. var array = GetSignalStruct(signalID, out uint index, input);
  48. if (array.count > 0)
  49. {
  50. ref var channelData = ref array[index];
  51. channelData.valueAsFloat += signal;
  52. if (clamp)
  53. {
  54. if (channelData.valueAsFloat > POSITIVE_HIGH)
  55. {
  56. channelData.valueAsFloat = POSITIVE_HIGH;
  57. }
  58. else if (channelData.valueAsFloat < NEGATIVE_HIGH)
  59. {
  60. channelData.valueAsFloat = NEGATIVE_HIGH;
  61. }
  62. return channelData.valueAsFloat;
  63. }
  64. }
  65. return signal;
  66. }
  67. public float GetSignal(EGID blockID, out uint signalID, bool input = true)
  68. {
  69. signalID = GetSignalIDs(blockID, input)[0];
  70. return GetSignal(signalID, input);
  71. }
  72. public float GetSignal(uint signalID, bool input = true)
  73. {
  74. var array = GetSignalStruct(signalID, out uint index, input);
  75. return array.count > 0 ? array[index].valueAsFloat : 0f;
  76. }
  77. public uint[] GetSignalIDs(EGID blockID, bool input = true)
  78. {
  79. ref BlockPortsStruct bps = ref entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
  80. uint[] signals;
  81. if (input) {
  82. signals = new uint[bps.inputCount];
  83. for (uint i = 0u; i < bps.inputCount; i++)
  84. {
  85. signals[i] = bps.firstInputID + i;
  86. }
  87. } else {
  88. signals = new uint[bps.outputCount];
  89. for (uint i = 0u; i < bps.outputCount; i++)
  90. {
  91. signals[i] = bps.firstOutputID + i;
  92. }
  93. }
  94. return signals;
  95. }
  96. public EGID[] GetSignalInputs(EGID blockID)
  97. {
  98. BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
  99. EGID[] inputs = new EGID[ports.inputCount];
  100. for (uint i = 0; i < ports.inputCount; i++)
  101. {
  102. inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup<InputPortsGroup>.Group);
  103. }
  104. return inputs;
  105. }
  106. public EGID[] GetSignalOutputs(EGID blockID)
  107. {
  108. BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
  109. EGID[] outputs = new EGID[ports.outputCount];
  110. for (uint i = 0; i < ports.outputCount; i++)
  111. {
  112. outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup<OutputPortsGroup>.Group);
  113. }
  114. return outputs;
  115. }
  116. public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists)
  117. {
  118. ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
  119. var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
  120. for (uint i = 0; i < wires.count; i++)
  121. {
  122. if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID)
  123. || (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID))
  124. {
  125. exists = true;
  126. return ref wires[i];
  127. }
  128. }
  129. exists = false;
  130. WireEntityStruct[] defRef = new WireEntityStruct[1];
  131. return ref defRef[0];
  132. }
  133. public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists)
  134. {
  135. ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
  136. var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
  137. if (port.firstChannelIndexCachedInSim < channels.count)
  138. {
  139. exists = true;
  140. return ref channels[port.firstChannelIndexCachedInSim];
  141. }
  142. exists = false;
  143. ChannelDataStruct[] defRef = new ChannelDataStruct[1];
  144. return ref defRef[0];
  145. }
  146. public EGID[] GetElectricBlocks()
  147. {
  148. var res = new FasterList<EGID>();
  149. foreach (var (coll, _) in entitiesDB.QueryEntities<BlockPortsStruct>())
  150. foreach (ref BlockPortsStruct s in coll)
  151. res.Add(s.ID);
  152. return res.ToArray();
  153. }
  154. private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
  155. {
  156. ExclusiveGroup group = input
  157. ? NamedExclusiveGroup<InputPortsGroup>.Group
  158. : NamedExclusiveGroup<OutputPortsGroup>.Group;
  159. if (entitiesDB.Exists<PortEntityStruct>(signalID, group))
  160. {
  161. index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).anyChannelIndex;
  162. var channelData =
  163. entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
  164. return channelData;
  165. }
  166. index = 0;
  167. return default; //count: 0
  168. }
  169. }
  170. }