using Svelto.ECS; using Gamecraft.Wires; using GamecraftModdingAPI.Engines; namespace GamecraftModdingAPI.Blocks { /// /// Engine which executes signal actions /// public class SignalEngine : IApiEngine { public const float POSITIVE_HIGH = 1.0f; public const float NEGATIVE_HIGH = -1.0f; public const float HIGH = 1.0f; public const float ZERO = 0.0f; public string Name { get; } = "GamecraftModdingAPISignalGameEngine"; public EntitiesDB entitiesDB { set; private get; } public bool isRemovable => false; public bool IsInGame = false; public void Dispose() { IsInGame = false; } public void Ready() { IsInGame = true; } // implementations for Signal static class public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true) { signalID = GetSignalIDs(blockID, input)[0]; return SetSignal(signalID, signal); } public bool SetSignal(uint signalID, float signal, bool input = true) { var array = GetSignalStruct(signalID, out uint index, input); if (array != null) array[index].valueAsFloat = signal; return false; } public float AddSignal(EGID blockID, float signal, out uint signalID, bool clamp = true, bool input = true) { signalID = GetSignalIDs(blockID, input)[0]; return AddSignal(signalID, signal, clamp, input); } public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true) { var array = GetSignalStruct(signalID, out uint index, input); if (array != null) { ref var channelData = ref array[index]; channelData.valueAsFloat += signal; if (clamp) { if (channelData.valueAsFloat > POSITIVE_HIGH) { channelData.valueAsFloat = POSITIVE_HIGH; } else if (channelData.valueAsFloat < NEGATIVE_HIGH) { channelData.valueAsFloat = NEGATIVE_HIGH; } return channelData.valueAsFloat; } } return signal; } public float GetSignal(EGID blockID, out uint signalID, bool input = true) { signalID = GetSignalIDs(blockID, input)[0]; return GetSignal(signalID, input); } public float GetSignal(uint signalID, bool input = true) { var array = GetSignalStruct(signalID, out uint index, input); return array?[index].valueAsFloat ?? 0f; } public uint[] GetSignalIDs(EGID blockID, bool input = true) { ref BlockPortsStruct bps = ref entitiesDB.QueryEntity(blockID); uint[] signals; if (input) { signals = new uint[bps.inputCount]; for (uint i = 0u; i < bps.inputCount; i++) { signals[i] = bps.firstInputID + i; } } else { signals = new uint[bps.outputCount]; for (uint i = 0u; i < bps.outputCount; i++) { signals[i] = bps.firstOutputID + i; } } return signals; } public EGID[] GetSignalInputs(EGID blockID) { BlockPortsStruct ports = entitiesDB.QueryEntity(blockID); EGID[] inputs = new EGID[ports.inputCount]; for (uint i = 0; i < ports.inputCount; i++) { inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup.Group); } return inputs; } public EGID[] GetSignalOutputs(EGID blockID) { BlockPortsStruct ports = entitiesDB.QueryEntity(blockID); EGID[] outputs = new EGID[ports.outputCount]; for (uint i = 0; i < ports.outputCount; i++) { outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup.Group); } return outputs; } public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists) { ref PortEntityStruct port = ref entitiesDB.QueryEntity(portID); WireEntityStruct[] wires = entitiesDB.QueryEntities(NamedExclusiveGroup.Group).ToFastAccess(out uint count); for (uint i = 0; i < count; i++) { if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID) || (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID)) { exists = true; return ref wires[i]; } } exists = false; WireEntityStruct[] defRef = new WireEntityStruct[1]; return ref defRef[0]; } public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists) { ref PortEntityStruct port = ref entitiesDB.QueryEntity(portID); ChannelDataStruct[] channels = entitiesDB.QueryEntities(NamedExclusiveGroup.Group).ToFastAccess(out uint count); if (port.firstChannelIndexCachedInSim < count) { exists = true; return ref channels[port.firstChannelIndexCachedInSim]; } exists = false; ChannelDataStruct[] defRef = new ChannelDataStruct[1]; return ref defRef[0]; } public EGID[] GetElectricBlocks() { uint count = entitiesDB.Count(BlockIdentifiers.OWNED_BLOCKS) + entitiesDB.Count(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); uint i = 0; EGID[] res = new EGID[count]; foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities(BlockIdentifiers.OWNED_BLOCKS)) { res[i] = s.ID; i++; } foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS)) { res[i] = s.ID; i++; } return res; } private ChannelDataStruct[] GetSignalStruct(uint signalID, out uint index, bool input = true) { ExclusiveGroup group = input ? NamedExclusiveGroup.Group : NamedExclusiveGroup.Group; if (entitiesDB.Exists(signalID, group)) { index = entitiesDB.QueryEntity(signalID, group).anyChannelIndex; ChannelDataStruct[] channelData = entitiesDB .QueryEntities(NamedExclusiveGroup.Group) .ToFastAccess(out uint _); return channelData; } index = 0; return null; } } }