TechbloxModdingAPI/GamecraftModdingAPI/Blocks/SignalEngine.cs

173 lines
6.6 KiB
C#
Raw Normal View History

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
{
/// <summary>
/// Engine which executes block movement actions
/// </summary>
public class SignalEngine : IApiEngine
{
public string Name { get; } = "GamecraftModdingAPISignalGameEngine";
public IEntitiesDB entitiesDB { set; private get; }
public bool IsInGame = false;
private Stack<uint> cubesStack = new Stack<uint>();
private bool stackInUse = false;
private Gamecraft.DataStructures.FasterList<uint> cubesList = new Gamecraft.DataStructures.FasterList<uint>();
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<ChannelOutputSignalDataStruct>(clusterID))
{
entitiesDB.QueryEntity<ChannelOutputSignalDataStruct>(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<ChannelOutputSignalDataStruct>(clusterID))
{
ref ChannelOutputSignalDataStruct chanOutSig = ref entitiesDB.QueryEntity<ChannelOutputSignalDataStruct>(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<ChannelOutputSignalDataStruct>(clusterID))
{
return entitiesDB.QueryEntity<ChannelOutputSignalDataStruct>(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<ConductiveClusterIdStruct>(structs[index].ID).clusterId;
uint operatingChannel = entitiesDB.QueryEntity<SignalOperatingChannelStruct>(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<ChannelOutputSignalDataStruct>(eGID))
{
return eGID;
}
}
}
// failsafe; not 100% reliable
foreach (ref ConductiveClusterIdStruct clusterIdStruct in entitiesDB.QueryEntities<ConductiveClusterIdStruct>(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<ChannelOutputSignalDataStruct>(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<uint> cubeStack = new Stack<uint>();
Gamecraft.DataStructures.FasterList<uint> cubeList = new Gamecraft.DataStructures.FasterList<uint>();
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return false; });
return cubeList.ToArray();
}
public bool IsSimulationMode()
{
return SimModeUtil.IsSimulationMode(this.entitiesDB);
}
}
}