@@ -19,6 +19,7 @@ using Svelto.ECS.EntityStructs; | |||
using Unity.Transforms; | |||
using Unity.Mathematics; | |||
using UnityEngine; | |||
using Gamecraft.Wires; | |||
using GamecraftModdingAPI.Utility; | |||
@@ -35,11 +36,7 @@ namespace GamecraftModdingAPI.Blocks | |||
public bool IsInGame = false; | |||
private Stack<uint> cubesStack = new Stack<uint>(); | |||
private bool stackInUse = false; | |||
private FasterList<uint> cubesList = new FasterList<uint>(); | |||
private bool listInUse = false; | |||
private System.Random random = new System.Random(); | |||
public void Dispose() | |||
{ | |||
@@ -51,137 +48,130 @@ namespace GamecraftModdingAPI.Blocks | |||
IsInGame = true; | |||
} | |||
public void DoTheThing() | |||
{ | |||
GamecraftModdingAPI.Tasks.Repeatable thing = new GamecraftModdingAPI.Tasks.Repeatable( | |||
() => { Thing(); }, | |||
() => { return IsSimulationMode(); } ); | |||
GamecraftModdingAPI.Tasks.Scheduler.Schedule(thing); | |||
} | |||
public void Thing() | |||
{ | |||
uint count = 0; | |||
EGID[] eBlocks = GetElectricBlocks(); | |||
for (uint i = 0u; i < eBlocks.Length; i++) | |||
{ | |||
uint[] ids = GetSignalIDs(eBlocks[i]); | |||
for (uint j = 0u; j < ids.Length; j++) | |||
{ | |||
SetSignal(ids[j], (float)random.NextDouble()); | |||
count++; | |||
} | |||
} | |||
Logging.Log($"Did the thing on {count} inputs"); | |||
} | |||
// implementations for Signal static class | |||
public bool SetSignal(uint blockID, uint channel, float signal, out EGID clusterID) | |||
public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true) | |||
{ | |||
clusterID = GetClusterEGID(blockID, channel); | |||
return SetSignal(clusterID, signal); | |||
signalID = GetSignalIDs(blockID, input)[0]; | |||
return SetSignal(signalID, signal); | |||
} | |||
public bool SetSignal(EGID clusterID, float signal) | |||
public bool SetSignal(uint signalID, float signal, bool input = true) | |||
{ | |||
if (entitiesDB.Exists<ChannelOutputSignalDataStruct>(clusterID)) | |||
ExclusiveGroup group = input ? NamedExclusiveGroup<InputPortsGroup>.Group : NamedExclusiveGroup<OutputPortsGroup>.Group; | |||
if (entitiesDB.Exists<PortEntityStruct>(signalID, group)) | |||
{ | |||
entitiesDB.QueryEntity<ChannelOutputSignalDataStruct>(clusterID).outputSignal = signal; | |||
return true; | |||
entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).value = signal; | |||
return true; | |||
} | |||
return false; | |||
} | |||
public float AddSignal(uint blockID, uint channel, float signal, out EGID clusterID, bool clamp = true) | |||
public float AddSignal(EGID blockID, float signal, out uint signalID, bool clamp = true, bool input = true) | |||
{ | |||
clusterID = GetClusterEGID(blockID, channel); | |||
return AddSignal(clusterID, signal, clamp); | |||
signalID = GetSignalIDs(blockID, input)[0]; | |||
return AddSignal(signalID, signal, clamp, input); | |||
} | |||
public float AddSignal(EGID clusterID, float signal, bool clamp=true) | |||
public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = 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; | |||
} | |||
} | |||
ExclusiveGroup group = input ? NamedExclusiveGroup<InputPortsGroup>.Group : NamedExclusiveGroup<OutputPortsGroup>.Group; | |||
if (entitiesDB.Exists<PortEntityStruct>(signalID, group)) | |||
{ | |||
ref PortEntityStruct pes = ref entitiesDB.QueryEntity<PortEntityStruct>(signalID, group); | |||
pes.value += signal; | |||
if (clamp) | |||
{ | |||
if (pes.value > Signals.POSITIVE_HIGH) | |||
{ | |||
pes.value = Signals.POSITIVE_HIGH; | |||
} | |||
else if (pes.value < Signals.NEGATIVE_HIGH) | |||
{ | |||
pes.value = Signals.NEGATIVE_HIGH; | |||
} | |||
return pes.value; | |||
} | |||
} | |||
return signal; | |||
} | |||
public float GetSignal(uint blockID, uint channel, out EGID clusterID) | |||
public float GetSignal(EGID blockID, out uint signalID, bool input = true) | |||
{ | |||
clusterID = GetClusterEGID(blockID, channel); | |||
return GetSignal(clusterID); | |||
signalID = GetSignalIDs(blockID, input)[0]; | |||
return GetSignal(signalID, input); | |||
} | |||
public float GetSignal(EGID clusterID) | |||
public float GetSignal(uint signalID, bool input = true) | |||
{ | |||
if (entitiesDB.Exists<ChannelOutputSignalDataStruct>(clusterID)) | |||
ExclusiveGroup group = input ? NamedExclusiveGroup<InputPortsGroup>.Group : NamedExclusiveGroup<OutputPortsGroup>.Group; | |||
if (entitiesDB.Exists<PortEntityStruct>(signalID, group)) | |||
{ | |||
return entitiesDB.QueryEntity<ChannelOutputSignalDataStruct>(clusterID).outputSignal; | |||
return entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).value; | |||
} | |||
return 0f; | |||
} | |||
public EGID GetClusterEGID(uint blockID, uint channel) | |||
{ | |||
//uint[] connectedCubeIDs = GetConductivelyConnectedBlocks(blockID); | |||
//uint index; | |||
//ElectricityEntityStruct[] structs; | |||
EGID elecEGID = new EGID(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); | |||
if (!entitiesDB.Exists<ElectricityEntityStruct>(elecEGID)) | |||
{ | |||
elecEGID = new EGID(blockID, CommonExclusiveGroups.FUNCTIONAL_BLOCK_PART_GROUP); | |||
} | |||
if (!entitiesDB.Exists<ElectricityEntityStruct>(elecEGID)) | |||
{ | |||
return default; | |||
} | |||
ref ElectricityEntityStruct eStruct = ref entitiesDB.QueryEntity<ElectricityEntityStruct>(elecEGID); | |||
ref ConductiveClusterID clusterId = ref entitiesDB.QueryEntity<ConductiveClusterIdStruct>(eStruct.ID).clusterId; | |||
uint operatingChannel = entitiesDB.QueryEntity<SignalOperatingChannelStruct>(eStruct.ID).operatingChannel; | |||
EGID eGID = new EGID(channel, BlockIdentifiers.OUTPUT_SIGNAL_CHANNELS + clusterId.ID); | |||
if (clusterId.initialized && clusterId.isConductive && entitiesDB.Exists<ChannelOutputSignalDataStruct>(eGID)) | |||
{ | |||
return eGID; | |||
} | |||
return default; | |||
} | |||
public uint[] GetSignalIDs(EGID blockID, bool input = true) | |||
{ | |||
ref BlockPortsStruct bps = ref entitiesDB.QueryEntity<BlockPortsStruct>(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 uint[] GetElectricBlocks() | |||
{ | |||
uint count = entitiesDB.Count<ElectricityEntityStruct>(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD[0]) | |||
+ entitiesDB.Count<ElectricityEntityStruct>(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD[1]); | |||
public EGID[] GetElectricBlocks() | |||
{ | |||
uint count = entitiesDB.Count<BlockPortsStruct>(BlockIdentifiers.OWNED_BLOCKS) + entitiesDB.Count<BlockPortsStruct>(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
uint i = 0; | |||
uint[] res = new uint[count]; | |||
foreach (ref var ees in entitiesDB.QueryEntities<ElectricityEntityStruct>(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD)) | |||
EGID[] res = new EGID[count]; | |||
foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities<BlockPortsStruct>(BlockIdentifiers.OWNED_BLOCKS)) | |||
{ | |||
res[i] = ees.ID.entityID; | |||
res[i] = s.ID; | |||
i++; | |||
} | |||
return res; | |||
} | |||
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 g.isIsolator; }); | |||
uint[] res = cubesList.ToArray(); | |||
stackInUse = false; | |||
listInUse = false; | |||
foreach (var id in res) | |||
{ | |||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; | |||
} | |||
return res; | |||
} | |||
else | |||
foreach (ref BlockPortsStruct s in entitiesDB.QueryEntities<BlockPortsStruct>(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS)) | |||
{ | |||
Stack<uint> cubeStack = new Stack<uint>(); | |||
FasterList<uint> cubeList = new FasterList<uint>(); | |||
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return g.isIsolator; }); | |||
uint[] res = cubesList.ToArray(); | |||
foreach (var id in res) | |||
{ | |||
entitiesDB.QueryEntity<GridConnectionsEntityStruct>(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; | |||
} | |||
return res; | |||
res[i] = s.ID; | |||
i++; | |||
} | |||
return res; | |||
} | |||
public bool IsSimulationMode() | |||
@@ -24,110 +24,155 @@ namespace GamecraftModdingAPI.Blocks | |||
private static SignalEngine signalEngine = new SignalEngine(); | |||
/// <summary> | |||
/// Set the electric block's channel to a value | |||
/// Set the electric block's (first) signal value. | |||
/// </summary> | |||
/// <param name="id">The block's id</param> | |||
/// <param name="channel">The channel (1 to 99)</param> | |||
/// <param name="signal">The signal value (-1 to 1; not enforced)</param> | |||
public static void SetSignalConnectedBlocks(uint id, uint channel, float signal) | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="signal">The signal value (-1 to 1; not enforced).</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param> | |||
public static void SetSignalByBlock(uint blockID, float signal, bool input = true, bool owned = true) | |||
{ | |||
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
signalEngine.SetSignal(id, channel, signal, out EGID _); | |||
signalEngine.SetSignal(egid, signal, out uint _, input); | |||
} | |||
} | |||
public static void SetSignalByBlock(EGID blockID, float signal, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
signalEngine.SetSignal(blockID, signal, out uint _, input); | |||
} | |||
} | |||
/// <summary> | |||
/// Set a conductive cluster channel to a value | |||
/// Set a signal's value. | |||
/// </summary> | |||
/// <param name="clusterID">The channel cluster's id</param> | |||
/// <param name="signal">The signal value (-1 to 1; not enforced)</param> | |||
public static void SetSignalCluster(EGID clusterID, float signal) | |||
/// <param name="signalID">The channel cluster's id.</param> | |||
/// <param name="signal">The signal value (-1 to 1; not enforced).</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
public static void SetSignalByID(uint signalID, float signal, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
signalEngine.SetSignal(clusterID, signal); | |||
signalEngine.SetSignal(signalID, signal, input); | |||
} | |||
} | |||
/// <summary> | |||
/// Add a value to an electric block's channel signal | |||
/// Add a value to an electric block's signal. | |||
/// </summary> | |||
/// <param name="id">The block's id</param> | |||
/// <param name="channel">The channel (1 to 99)</param> | |||
/// <param name="signal">The signal value to add</param> | |||
/// <param name="clamp">Whether to clamp the resulting signal value between -1 and 1</param> | |||
public static void AddSignalConnectedBlocks(uint id, uint channel, float signal, bool clamp = true) | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="signal">The signal value to add.</param> | |||
/// <param name="clamp">Whether to clamp the resulting signal value between -1 and 1.</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param> | |||
/// <returns>The signal's new value.</returns> | |||
public static float AddSignalByBlock(uint blockID, float signal, bool clamp = true, bool input = true, bool owned = true) | |||
{ | |||
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
return signalEngine.AddSignal(egid, signal, out uint _, clamp, input); | |||
} | |||
return 0f; | |||
} | |||
public static float AddSignalByBlock(EGID blockID, float signal, bool clamp = true, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
signalEngine.AddSignal(id, channel, signal, out EGID _, clamp); | |||
return signalEngine.AddSignal(blockID, signal, out uint _, clamp, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Add a value to a conductive cluster channel | |||
/// Add a value to a conductive cluster channel. | |||
/// </summary> | |||
/// <param name="clusterID">The channel cluster's id</param> | |||
/// <param name="signal">The signal value to add</param> | |||
/// <param name="clamp">Whether to clamp the resulting signal value between -1 and 1</param> | |||
public static void AddSignalCluster(EGID clusterID, float signal, bool clamp = true) | |||
/// <param name="signalID">The channel cluster's id.</param> | |||
/// <param name="signal">The signal value to add.</param> | |||
/// <param name="clamp">Whether to clamp the resulting signal value between -1 and 1.</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
/// <returns>The signal's new value.</returns> | |||
public static float AddSignalByID(uint signalID, float signal, bool clamp = true, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
signalEngine.AddSignal(clusterID, signal, clamp); | |||
return signalEngine.AddSignal(signalID, signal, clamp, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Get a electric block's channel's signal value | |||
/// Get a electric block's signal's (first) value. | |||
/// </summary> | |||
/// <param name="id">The block's id</param> | |||
/// <param name="channel">The channel (1 to 99)</param> | |||
/// <returns>The signal value</returns> | |||
public static float GetSignalBlock(uint id, uint channel) | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param> | |||
/// <returns>The signal's value.</returns> | |||
public static float GetSignalByBlock(uint blockID, bool input = true, bool owned = true) | |||
{ | |||
EGID egid = new EGID(blockID, owned? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
return signalEngine.GetSignal(id, channel, out EGID _); | |||
return signalEngine.GetSignal(egid, out uint _, input); | |||
} | |||
return 0f; | |||
} | |||
public static float GetSignalByBlock(EGID blockID, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
return signalEngine.GetSignal(blockID, out uint _, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Get a conductive cluster channel's signal value | |||
/// Get a signal's value. | |||
/// </summary> | |||
/// <param name="clusterID">The channel cluster's id</param> | |||
/// <returns>The signal value</returns> | |||
public static float GetSignalCluster(EGID clusterID) | |||
/// <param name="signalID">The signal's id.</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
/// <returns>The signal's value.</returns> | |||
public static float GetSignalByID(uint signalID, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) | |||
{ | |||
return signalEngine.GetSignal(clusterID); | |||
return signalEngine.GetSignal(signalID, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Get the ID of every electricity consumer in the game world | |||
/// Get the ID of every electric block in the game world. | |||
/// </summary> | |||
/// <returns>The block IDs</returns> | |||
public static uint[] GetElectricBlocks() | |||
/// <returns>The block IDs.</returns> | |||
public static EGID[] GetElectricBlocks() | |||
{ | |||
return signalEngine.GetElectricBlocks(); | |||
} | |||
/// <summary> | |||
/// Get the conductive cluster's unique identifier for an electric block | |||
/// Get the unique identifiers for the input wires connected to an electric block. | |||
/// </summary> | |||
/// <param name="id">The block's id</param> | |||
/// <param name="channel"></param> | |||
/// <returns>The unique ID</returns> | |||
public static EGID GetClusterID(uint id, uint channel) | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="input">Whether to retrieve input IDs (true) or output IDs (false).</param> | |||
/// <param name="owned">Whether the block is in the owned group (true) or functional group (false)</param> | |||
/// <returns>The unique IDs.</returns> | |||
public static uint[] GetSignalIDs(uint blockID, bool input = true, bool owned = true) | |||
{ | |||
return signalEngine.GetClusterEGID(id, channel); | |||
EGID egid = new EGID(blockID, owned ? BlockIdentifiers.OWNED_BLOCKS : BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
return signalEngine.GetSignalIDs(egid, input); | |||
} | |||
public static uint[] GetSignalIDs(EGID blockID, bool input = true, bool owned = true) | |||
{ | |||
return signalEngine.GetSignalIDs(blockID, input); | |||
} | |||
public static void Init() | |||
{ | |||
@@ -51,13 +51,7 @@ namespace GamecraftModdingAPI.Tests | |||
//AnalyticsDisablerPatch.DisableAnalytics = true; | |||
// disable background music | |||
Logging.MetaDebugLog("Audio Mixers: "+string.Join(",", AudioTools.GetMixers())); | |||
//AudioTools.SetVolume(0.0f, "Music"); // The game now sets this from settings again after this is called | |||
/*if (!FMODUnity.RuntimeManager.HasBankLoaded("Modded")) | |||
{ | |||
FMODUnity.RuntimeManager.LoadBank("Modded", true); | |||
} | |||
FMODUnity.RuntimeManager.PlayOneShot("event:/ModEvents/KillDashNine3D");*/ | |||
//AudioTools.SetVolume(0.0f, "Music"); // The game now sets this from settings again after this is called :( | |||
// debug/test handlers | |||
EventManager.AddEventHandler(new SimpleEventHandlerEngine(() => { Logging.Log("App Inited event!"); }, () => { }, | |||
@@ -99,7 +93,34 @@ namespace GamecraftModdingAPI.Tests | |||
CommandManager.AddCommand(new SimpleCustomCommandEngine<string>( | |||
(s) => { Analytics.DeltaDNAHelper.SendActionCompletedEvent(in plp, s.Replace(", ", " ")); }, | |||
"SendAnalyticsAction", "Send an analytics action")); | |||
System.Random random = new System.Random(); // for command below | |||
CommandManager.AddCommand(new SimpleCustomCommandEngine( | |||
() => { | |||
if (!GameState.IsSimulationMode()) | |||
{ | |||
Logging.CommandLogError("You must be in simulation mode for this to work!"); | |||
return; | |||
} | |||
Tasks.Repeatable task = new Tasks.Repeatable(() => { | |||
uint count = 0; | |||
EGID[] eBlocks = Blocks.Signals.GetElectricBlocks(); | |||
for (uint i = 0u; i < eBlocks.Length; i++) | |||
{ | |||
uint[] ids = Blocks.Signals.GetSignalIDs(eBlocks[i]); | |||
for (uint j = 0u; j < ids.Length; j++) | |||
{ | |||
Blocks.Signals.SetSignalByID(ids[j], (float)random.NextDouble()); | |||
count++; | |||
} | |||
} | |||
Logging.MetaDebugLog($"Did the thing on {count} inputs"); | |||
}, | |||
() => { return GameState.IsSimulationMode(); }); | |||
Tasks.Scheduler.Schedule(task); | |||
}, "RandomizeSignalsInputs", "Do the thing")); | |||
} | |||
// dependency test | |||
if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0"))) | |||
{ | |||
Logging.LogWarning("You're in GamecraftScripting dependency hell"); | |||