using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using RobocraftX; using RobocraftX.Blocks; using RobocraftX.Blocks.Ghost; using RobocraftX.Common; using RobocraftX.Multiplayer; using RobocraftX.SimulationModeState; using RobocraftX.UECS; using Unity.Entities; using Svelto.Context; using Svelto.ECS; using Svelto.ECS.EntityStructs; using Unity.Transforms; using Unity.Mathematics; using UnityEngine; using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { /// /// Engine which executes block movement actions /// public class SignalEngine : IApiEngine { public string Name { get; } = "GamecraftModdingAPISignalGameEngine"; public IEntitiesDB entitiesDB { set; private get; } public bool IsInGame = false; private Stack cubesStack = new Stack(); private bool stackInUse = false; private Gamecraft.DataStructures.FasterList cubesList = new Gamecraft.DataStructures.FasterList(); private bool listInUse = false; public void Dispose() { IsInGame = false; } public void Ready() { IsInGame = true; } // implementations for Signal static class public bool SetSignal(uint blockID, uint channel, float signal, out EGID clusterID) { clusterID = GetClusterEGID(blockID, channel); return SetSignal(clusterID, signal); } public bool SetSignal(EGID clusterID, float signal) { if (entitiesDB.Exists(clusterID)) { entitiesDB.QueryEntity(clusterID).outputSignal = signal; return true; } return false; } public float AddSignal(uint blockID, uint channel, float signal, out EGID clusterID, bool clamp = true) { clusterID = GetClusterEGID(blockID, channel); return AddSignal(clusterID, signal, clamp); } public float AddSignal(EGID clusterID, float signal, bool clamp=true) { if (entitiesDB.Exists(clusterID)) { ref ChannelOutputSignalDataStruct chanOutSig = ref entitiesDB.QueryEntity(clusterID); chanOutSig.outputSignal += signal; if (clamp) { if (chanOutSig.outputSignal > Signals.POSITIVE_HIGH) { chanOutSig.outputSignal = Signals.POSITIVE_HIGH; } else if (chanOutSig.outputSignal < Signals.NEGATIVE_HIGH) { chanOutSig.outputSignal = Signals.NEGATIVE_HIGH; } return chanOutSig.outputSignal; } } return signal; } public float GetSignal(uint blockID, uint channel, out EGID clusterID) { clusterID = GetClusterEGID(blockID, channel); return GetSignal(clusterID); } public float GetSignal(EGID clusterID) { if (entitiesDB.Exists(clusterID)) { return entitiesDB.QueryEntity(clusterID).outputSignal; } return 0f; } public EGID GetClusterEGID(uint blockID, uint channel) { uint[] connectedCubeIDs = GetConductivelyConnectedBlocks(blockID); uint index; ElectricityEntityStruct[] structs; Logging.CommandLog($"Found {connectedCubeIDs.Length} connected cubes"); for (int i = 0; i < connectedCubeIDs.Length; i++) { if (entitiesDB.TryQueryEntitiesAndIndex(new EGID(connectedCubeIDs[i], CommonExclusiveGroups.OWNED_BLOCKS_GROUP), out index, out structs) || entitiesDB.TryQueryEntitiesAndIndex(new EGID(connectedCubeIDs[i], CommonExclusiveGroups.FUNCTIONAL_BLOCK_PART_GROUP), out index, out structs)) { ref ConductiveClusterID clusterId = ref entitiesDB.QueryEntity(structs[index].ID).clusterId; uint operatingChannel = entitiesDB.QueryEntity(structs[index].ID).operatingChannel; Logging.CommandLog($"Channel {operatingChannel} found"); EGID eGID = new EGID(channel, BlockIdentifiers.OUTPUT_SIGNAL_CHANNELS + clusterId.ID); if (clusterId.initialized && clusterId.isConductive && entitiesDB.Exists(eGID)) { return eGID; } } } // failsafe; not 100% reliable foreach (ref ConductiveClusterIdStruct clusterIdStruct in entitiesDB.QueryEntities(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD)) { EGID eGID = new EGID(channel, BlockIdentifiers.OUTPUT_SIGNAL_CHANNELS + clusterIdStruct.clusterId.ID); if (clusterIdStruct.clusterId.initialized && clusterIdStruct.clusterId.isConductive && entitiesDB.Exists(eGID)) { return eGID; } } return default; } private uint[] GetConductivelyConnectedBlocks(uint blockID) { if (!(stackInUse || listInUse)) { stackInUse = true; listInUse = true; cubesStack.Clear(); cubesList.FastClear(); ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return false; }); uint[] res = cubesList.ToArray(); stackInUse = false; listInUse = false; return res; } Stack cubeStack = new Stack(); Gamecraft.DataStructures.FasterList cubeList = new Gamecraft.DataStructures.FasterList(); ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return false; }); return cubeList.ToArray(); } public bool IsSimulationMode() { return SimModeUtil.IsSimulationMode(this.entitiesDB); } } }