@@ -23,6 +23,7 @@ namespace GamecraftModdingAPI | |||
protected static readonly RotationEngine RotationEngine = new RotationEngine(); | |||
protected static readonly RemovalEngine RemovalEngine = new RemovalEngine(); | |||
protected static readonly BlockEngine BlockEngine = new BlockEngine(); | |||
protected static readonly SignalEngine SignalEngine = new SignalEngine(); | |||
/// <summary> | |||
/// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position. | |||
@@ -74,8 +74,8 @@ namespace GamecraftModdingAPI.Blocks | |||
if (exists) | |||
return ref entitiesDB.QueryEntity<T>(blockID); | |||
T[] structHolder = new T[1]; | |||
ref T structRef = ref structHolder[0]; | |||
return ref structRef; | |||
//ref T defRef = ref structHolder[0]; | |||
return ref structHolder[0]; | |||
} | |||
public bool BlockExists(EGID id) | |||
@@ -0,0 +1,113 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Motor : Block | |||
{ | |||
/// <summary> | |||
/// Places a new motor. | |||
/// Any valid motor type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new Motor PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.MotorS || block == BlockIDs.MotorM)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {typeof(Motor).Name} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
Sync(); | |||
return new Motor(id); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
} | |||
return null; | |||
} | |||
public Motor(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<MotorReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Motor(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<MotorReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom motor properties | |||
/// <summary> | |||
/// The motor's maximum rotational velocity. | |||
/// </summary> | |||
public float TopSpeed | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).maxVelocity; | |||
} | |||
set | |||
{ | |||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id); | |||
motor.maxVelocity = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The motor's maximum rotational force. | |||
/// </summary> | |||
public float Torque | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).maxForce; | |||
} | |||
set | |||
{ | |||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id); | |||
motor.maxForce = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The motor's direction. | |||
/// </summary> | |||
public bool Reverse | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id).reverse; | |||
} | |||
set | |||
{ | |||
ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo<MotorReadOnlyStruct>(Id); | |||
motor.reverse = value; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Piston : Block | |||
{ | |||
/// <summary> | |||
/// Places a new piston. | |||
/// Any valid piston type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new Piston PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.ServoPiston || block == BlockIDs.StepperPiston || block == BlockIDs.PneumaticPiston)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {typeof(Piston).Name} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
Sync(); | |||
return new Piston(id); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
} | |||
return null; | |||
} | |||
public Piston(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<PistonReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Piston(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<PistonReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom piston properties | |||
/// <summary> | |||
/// The piston's max extension distance. | |||
/// </summary> | |||
public float MaximumExtension | |||
{ | |||
get => BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id).maxDeviation; | |||
set | |||
{ | |||
ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id); | |||
piston.maxDeviation = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The piston's max extension force. | |||
/// </summary> | |||
public float MaximumForce | |||
{ | |||
get => BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id).maxForce; | |||
set | |||
{ | |||
ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo<PistonReadOnlyStruct>(Id); | |||
piston.maxForce = value; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Servo : Block | |||
{ | |||
/// <summary> | |||
/// Places a new servo. | |||
/// Any valid servo type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new Servo PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.ServoAxle || block == BlockIDs.ServoHinge || block == BlockIDs.ServoPiston)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {typeof(Servo).Name} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
Sync(); | |||
return new Servo(id); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
} | |||
return null; | |||
} | |||
public Servo(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ServoReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Servo(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<ServoReadOnlyStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom servo properties | |||
/// <summary> | |||
/// The servo's minimum angle. | |||
/// </summary> | |||
public float MinimumAngle | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).minDeviation; | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.minDeviation = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The servo's maximum angle. | |||
/// </summary> | |||
public float MaximumAngle | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).maxDeviation; | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.maxDeviation = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The servo's maximum force. | |||
/// </summary> | |||
public float MaximumForce | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).maxForce; | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.maxForce = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The servo's direction. | |||
/// </summary> | |||
public bool Reverse | |||
{ | |||
get => BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id).reverse; | |||
set | |||
{ | |||
ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo<ServoReadOnlyStruct>(Id); | |||
servo.reverse = value; | |||
} | |||
} | |||
} | |||
} |
@@ -10,6 +10,11 @@ namespace GamecraftModdingAPI.Blocks | |||
/// </summary> | |||
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; } | |||
@@ -58,13 +63,13 @@ namespace GamecraftModdingAPI.Blocks | |||
channelData.valueAsFloat += signal; | |||
if (clamp) | |||
{ | |||
if (channelData.valueAsFloat > Signals.POSITIVE_HIGH) | |||
if (channelData.valueAsFloat > POSITIVE_HIGH) | |||
{ | |||
channelData.valueAsFloat = Signals.POSITIVE_HIGH; | |||
channelData.valueAsFloat = POSITIVE_HIGH; | |||
} | |||
else if (channelData.valueAsFloat < Signals.NEGATIVE_HIGH) | |||
else if (channelData.valueAsFloat < NEGATIVE_HIGH) | |||
{ | |||
channelData.valueAsFloat = Signals.NEGATIVE_HIGH; | |||
channelData.valueAsFloat = NEGATIVE_HIGH; | |||
} | |||
return channelData.valueAsFloat; | |||
@@ -106,6 +111,60 @@ namespace GamecraftModdingAPI.Blocks | |||
return signals; | |||
} | |||
public EGID[] GetSignalInputs(EGID blockID) | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID); | |||
EGID[] inputs = new EGID[ports.inputCount]; | |||
for (uint i = 0; i < ports.inputCount; i++) | |||
{ | |||
inputs[i] = new EGID(i + ports.firstInputID, NamedExclusiveGroup<InputPortsGroup>.Group); | |||
} | |||
return inputs; | |||
} | |||
public EGID[] GetSignalOutputs(EGID blockID) | |||
{ | |||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID); | |||
EGID[] outputs = new EGID[ports.outputCount]; | |||
for (uint i = 0; i < ports.outputCount; i++) | |||
{ | |||
outputs[i] = new EGID(i + ports.firstOutputID, NamedExclusiveGroup<OutputPortsGroup>.Group); | |||
} | |||
return outputs; | |||
} | |||
public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists) | |||
{ | |||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID); | |||
WireEntityStruct[] wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.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<PortEntityStruct>(portID); | |||
ChannelDataStruct[] channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.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<BlockPortsStruct>(BlockIdentifiers.OWNED_BLOCKS) + entitiesDB.Count<BlockPortsStruct>(BlockIdentifiers.FUNCTIONAL_BLOCK_PARTS); | |||
@@ -0,0 +1,131 @@ | |||
using System; | |||
using Gamecraft.Wires; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
/// <summary> | |||
/// Common implementation for blocks that support wiring. | |||
/// </summary> | |||
public class SignalingBlock : Block | |||
{ | |||
/// <summary> | |||
/// Places a new signaling block. | |||
/// Any valid functional block type with IO ports will work. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new SignalingBlock PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
Sync(); | |||
return new SignalingBlock(id); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
} | |||
return null; | |||
} | |||
public SignalingBlock(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public SignalingBlock(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
protected ref BlockPortsStruct GetBlockPortsStruct() | |||
{ | |||
return ref BlockEngine.GetBlockInfo<BlockPortsStruct>(Id); | |||
} | |||
/// <summary> | |||
/// Generates the input port identifiers. | |||
/// </summary> | |||
/// <returns>The input identifiers.</returns> | |||
protected EGID[] GetInputIds() | |||
{ | |||
return SignalEngine.GetSignalInputs(Id); | |||
} | |||
/// <summary> | |||
/// Generates the output port identifiers. | |||
/// </summary> | |||
/// <returns>The output identifiers.</returns> | |||
protected EGID[] GetOutputIds() | |||
{ | |||
return SignalEngine.GetSignalOutputs(Id); | |||
} | |||
/// <summary> | |||
/// Gets the port struct. | |||
/// </summary> | |||
/// <returns>The port struct.</returns> | |||
/// <param name="portId">Port identifier.</param> | |||
protected ref PortEntityStruct GetPortStruct(EGID portId) | |||
{ | |||
return ref BlockEngine.GetBlockInfo<PortEntityStruct>(portId); | |||
} | |||
/// <summary> | |||
/// Gets the connected wire. | |||
/// </summary> | |||
/// <returns>The connected wire.</returns> | |||
/// <param name="portId">Port identifier.</param> | |||
/// <param name="connected">Whether the port has a wire connected to it.</param> | |||
protected ref WireEntityStruct GetConnectedWire(EGID portId, out bool connected) | |||
{ | |||
return ref SignalEngine.MatchPortToWire(portId, Id, out connected); | |||
} | |||
/// <summary> | |||
/// [EXPERIMENTAL] Gets the channel data. | |||
/// </summary> | |||
/// <returns>The channel data.</returns> | |||
/// <param name="portId">Port identifier.</param> | |||
/// <param name="exists">Whether the channel actually exists.</param> | |||
protected ref ChannelDataStruct GetChannelData(EGID portId, out bool exists) | |||
{ | |||
return ref SignalEngine.GetChannelDataStruct(portId, out exists); | |||
} | |||
/// <summary> | |||
/// The input port count. | |||
/// </summary> | |||
public uint InputCount | |||
{ | |||
get => GetBlockPortsStruct().inputCount; | |||
} | |||
/// <summary> | |||
/// The output port count. | |||
/// </summary> | |||
public uint OutputCount | |||
{ | |||
get => GetBlockPortsStruct().outputCount; | |||
} | |||
} | |||
} |
@@ -1,177 +0,0 @@ | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
/// <summary> | |||
/// [EXPERIMENTAL] Common block signal operations | |||
/// The functionality in this class only works when in a game. | |||
/// </summary> | |||
public static class Signals | |||
{ | |||
// Signal constants | |||
public static readonly float HIGH = 1.0f; | |||
public static readonly float POSITIVE_HIGH = HIGH; | |||
public static readonly float NEGATIVE_HIGH = -1.0f; | |||
public static readonly float LOW = 0.0f; | |||
private static SignalEngine signalEngine = new SignalEngine(); | |||
/// <summary> | |||
/// Set the electric block's (first) signal value. | |||
/// </summary> | |||
/// <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 && GameState.IsSimulationMode()) | |||
{ | |||
signalEngine.SetSignal(egid, signal, out uint _, input); | |||
} | |||
} | |||
public static void SetSignalByBlock(EGID blockID, float signal, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && GameState.IsSimulationMode()) | |||
{ | |||
signalEngine.SetSignal(blockID, signal, out uint _, input); | |||
} | |||
} | |||
/// <summary> | |||
/// Set the signal's value. | |||
/// </summary> | |||
/// <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 && GamecraftModdingAPI.Utility.GameState.IsSimulationMode()) | |||
{ | |||
signalEngine.SetSignal(signalID, signal, input); | |||
} | |||
} | |||
/// <summary> | |||
/// Add a value to an electric block's signal. | |||
/// </summary> | |||
/// <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 && GamecraftModdingAPI.Utility.GameState.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 && GamecraftModdingAPI.Utility.GameState.IsSimulationMode()) | |||
{ | |||
return signalEngine.AddSignal(blockID, signal, out uint _, clamp, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Add a value to a conductive cluster channel. | |||
/// </summary> | |||
/// <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 && GamecraftModdingAPI.Utility.GameState.IsSimulationMode()) | |||
{ | |||
return signalEngine.AddSignal(signalID, signal, clamp, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Get a electric block's signal's (first) value. | |||
/// </summary> | |||
/// <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 && GamecraftModdingAPI.Utility.GameState.IsSimulationMode()) | |||
{ | |||
return signalEngine.GetSignal(egid, out uint _, input); | |||
} | |||
return 0f; | |||
} | |||
public static float GetSignalByBlock(EGID blockID, bool input = true) | |||
{ | |||
if (signalEngine.IsInGame && GamecraftModdingAPI.Utility.GameState.IsSimulationMode()) | |||
{ | |||
return signalEngine.GetSignal(blockID, out uint _, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Get a signal's value. | |||
/// </summary> | |||
/// <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 && GamecraftModdingAPI.Utility.GameState.IsSimulationMode()) | |||
{ | |||
return signalEngine.GetSignal(signalID, input); | |||
} | |||
return 0f; | |||
} | |||
/// <summary> | |||
/// Get the ID of every electric block in the game world. | |||
/// </summary> | |||
/// <returns>The block IDs.</returns> | |||
public static EGID[] GetElectricBlocks() | |||
{ | |||
return signalEngine.GetElectricBlocks(); | |||
} | |||
/// <summary> | |||
/// Get the unique identifiers for the input wires connected to an electric block. | |||
/// </summary> | |||
/// <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) | |||
{ | |||
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() | |||
{ | |||
GameEngineManager.AddGameEngine(signalEngine); | |||
} | |||
} | |||
} |
@@ -1,98 +0,0 @@ | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
/// <summary> | |||
/// Common tweakable stats operations. | |||
/// The functionality of this class works best in build mode. | |||
/// </summary> | |||
public static class Tweakable | |||
{ | |||
private static TweakableEngine tweakableEngine = new TweakableEngine(); | |||
/// <summary> | |||
/// Get the tweakable stat's value using a dynamic variable type. | |||
/// This is similar to GetStat<T> but without strong type enforcement. | |||
/// This should be used in dynamically-typed languages like Python. | |||
/// </summary> | |||
/// <returns>The stat's value.</returns> | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="stat">The stat's enumerated id.</param> | |||
public static dynamic GetStatD(uint blockID, TweakableStat stat) | |||
{ | |||
return tweakableEngine.GetStatDynamic(blockID, stat); | |||
} | |||
/// <summary> | |||
/// Get the tweakable stat's value. | |||
/// If T is not the same type as the stat, an InvalidCastException will be thrown. | |||
/// </summary> | |||
/// <returns>The stat's value.</returns> | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="stat">The stat's enumerated id.</param> | |||
/// <typeparam name="T">The stat's type.</typeparam> | |||
public static T GetStat<T>(uint blockID, TweakableStat stat) | |||
{ | |||
return tweakableEngine.GetStatAny<T>(blockID, stat); | |||
} | |||
/// <summary> | |||
/// Set the tweakable stat's value using dynamically-typed variables. | |||
/// This is similar to SetStat<T> but without strong type enforcement. | |||
/// This should be used in dynamically-typed languages like Python. | |||
/// </summary> | |||
/// <returns>The stat's new value.</returns> | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="stat">The stat's enumerated id.</param> | |||
/// <param name="value">The stat's new value.</param> | |||
public static dynamic SetStatD(uint blockID, TweakableStat stat, dynamic value) | |||
{ | |||
return tweakableEngine.SetStatDynamic(blockID, stat, value); | |||
} | |||
/// <summary> | |||
/// Set the tweakable stat's value. | |||
/// If T is not the stat's actual type, an InvalidCastException will be thrown. | |||
/// </summary> | |||
/// <returns>The stat's new value.</returns> | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="stat">The stat's enumerated id.</param> | |||
/// <param name="value">The stat's new value.</param> | |||
/// <typeparam name="T">The stat's type.</typeparam> | |||
public static T SetStat<T>(uint blockID, TweakableStat stat, T value) | |||
{ | |||
return tweakableEngine.SetStatAny<T>(blockID, stat, value); | |||
} | |||
/// <summary> | |||
/// Add another value to the tweakable stat's value using dynamically-typed variables. | |||
/// This is similar to AddStat<T> but without strong type enforcement. | |||
/// This should be used in dynamically-typed languages like Python. | |||
/// </summary> | |||
/// <returns>The stat's new value.</returns> | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="stat">The stat's enumerated id.</param> | |||
/// <param name="value">The value to be added to the stat.</param> | |||
public static dynamic AddStatD(uint blockID, TweakableStat stat, dynamic value) | |||
{ | |||
return tweakableEngine.AddStatDynamic(blockID, stat, value); | |||
} | |||
/// <summary> | |||
/// Add another value to the tweakable stat's value. | |||
/// If T is not the stat's actual type, an InvalidCastException will be thrown. | |||
/// </summary> | |||
/// <returns>The stat's new value.</returns> | |||
/// <param name="blockID">The block's id.</param> | |||
/// <param name="stat">The stat's enumerated id.</param> | |||
/// <param name="value">The value to be added to the stat.</param> | |||
/// <typeparam name="T">The stat's type.</typeparam> | |||
public static T AddStat<T>(uint blockID, TweakableStat stat, T value) | |||
{ | |||
return tweakableEngine.AddStatAny<T>(blockID, stat, value); | |||
} | |||
public static void Init() | |||
{ | |||
GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(tweakableEngine); | |||
} | |||
} | |||
} |
@@ -1,452 +0,0 @@ | |||
using RobocraftX.Blocks; | |||
using Gamecraft.Wires; | |||
using Svelto.ECS; | |||
using GamecraftModdingAPI.Engines; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class TweakableEngine : IApiEngine | |||
{ | |||
public string Name { get; } = "GamecraftModdingAPITweakableGameEngine"; | |||
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 Tweakable static class | |||
public T GetStatAny<T>(EGID blockID, TweakableStat stat) | |||
{ | |||
switch (stat) | |||
{ | |||
case TweakableStat.TopSpeed: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxVelocity; | |||
} | |||
break; | |||
case TweakableStat.Torque: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxForce; | |||
} | |||
break; | |||
case TweakableStat.MaxExtension: | |||
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID).maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.MinAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).minDeviation; | |||
} | |||
break; | |||
case TweakableStat.MaxAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.Reverse: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).reverse; | |||
} | |||
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).reverse; | |||
} | |||
break; | |||
case TweakableStat.StartValue: | |||
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID)) | |||
{ | |||
return (T)(object)entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID).startValue; | |||
} | |||
break; | |||
} | |||
return default(T); | |||
} | |||
public T GetStatAny<T>(uint blockID, TweakableStat stat) | |||
{ | |||
return GetStatAny<T>(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat); | |||
} | |||
public dynamic GetStatDynamic(EGID blockID, TweakableStat stat) | |||
{ | |||
switch (stat) | |||
{ | |||
case TweakableStat.TopSpeed: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxVelocity; | |||
} | |||
break; | |||
case TweakableStat.Torque: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).maxForce; | |||
} | |||
break; | |||
case TweakableStat.MaxExtension: | |||
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID).maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.MinAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).minDeviation; | |||
} | |||
break; | |||
case TweakableStat.MaxAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.Reverse: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID).reverse; | |||
} | |||
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID).reverse; | |||
} | |||
break; | |||
case TweakableStat.StartValue: | |||
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID)) | |||
{ | |||
return entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID).startValue; | |||
} | |||
break; | |||
} | |||
return null; | |||
} | |||
public dynamic GetStatDynamic(uint blockID, TweakableStat stat) | |||
{ | |||
return GetStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat); | |||
} | |||
public T SetStatAny<T>(EGID blockID, TweakableStat stat, T value) | |||
{ | |||
switch (stat) | |||
{ | |||
case TweakableStat.TopSpeed: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxVelocity = (float)(object)value; | |||
return (T)(object)refStruct.maxVelocity; | |||
} | |||
break; | |||
case TweakableStat.Torque: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxForce = (float)(object)value; | |||
return (T)(object)refStruct.maxForce; | |||
} | |||
break; | |||
case TweakableStat.MaxExtension: | |||
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID)) | |||
{ | |||
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation = (float)(object)value; | |||
return (T)(object)refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.MinAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.minDeviation = (float)(object)value; | |||
return (T)(object)refStruct.minDeviation; | |||
} | |||
break; | |||
case TweakableStat.MaxAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation = (float)(object)value; | |||
return (T)(object)refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.Reverse: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.reverse = (bool)(object)value; | |||
return (T)(object)refStruct.reverse; | |||
} | |||
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.reverse = (bool)(object)value; | |||
return (T)(object)refStruct.reverse; | |||
} | |||
break; | |||
case TweakableStat.StartValue: | |||
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID)) | |||
{ | |||
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID); | |||
refStruct.startValue = (float)(object)value; | |||
return (T)(object)refStruct.startValue; | |||
} | |||
break; | |||
} | |||
return default(T); | |||
} | |||
public T SetStatAny<T>(uint blockID, TweakableStat stat, T value) | |||
{ | |||
return SetStatAny<T>(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); | |||
} | |||
public dynamic SetStatDynamic(EGID blockID, TweakableStat stat, dynamic value) | |||
{ | |||
switch (stat) | |||
{ | |||
case TweakableStat.TopSpeed: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxVelocity = value; | |||
return refStruct.maxVelocity; | |||
} | |||
break; | |||
case TweakableStat.Torque: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxForce = value; | |||
return refStruct.maxForce; | |||
} | |||
break; | |||
case TweakableStat.MaxExtension: | |||
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID)) | |||
{ | |||
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation = value; | |||
return refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.MinAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.minDeviation = value; | |||
return refStruct.minDeviation; | |||
} | |||
break; | |||
case TweakableStat.MaxAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation = value; | |||
return refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.Reverse: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.reverse = value; | |||
return refStruct.reverse; | |||
} | |||
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.reverse = value; | |||
return refStruct.reverse; | |||
} | |||
break; | |||
case TweakableStat.StartValue: | |||
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID)) | |||
{ | |||
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID); | |||
refStruct.startValue = value; | |||
return refStruct.startValue; | |||
} | |||
break; | |||
} | |||
return null; | |||
} | |||
public dynamic SetStatDynamic(uint blockID, TweakableStat stat, dynamic value) | |||
{ | |||
return SetStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); | |||
} | |||
public T AddStatAny<T>(EGID blockID, TweakableStat stat, T value) | |||
{ | |||
switch (stat) | |||
{ | |||
case TweakableStat.TopSpeed: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxVelocity += (float)(object)value; | |||
return (T)(object)refStruct.maxVelocity; | |||
} | |||
break; | |||
case TweakableStat.Torque: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxForce += (float)(object)value; | |||
return (T)(object)refStruct.maxForce; | |||
} | |||
break; | |||
case TweakableStat.MaxExtension: | |||
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID)) | |||
{ | |||
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation += (float)(object)value; | |||
return (T)(object)refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.MinAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.minDeviation += (float)(object)value; | |||
return (T)(object)refStruct.minDeviation; | |||
} | |||
break; | |||
case TweakableStat.MaxAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation += (float)(object)value; | |||
return (T)(object)refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.Reverse: | |||
// '+' is associated with logical OR in some fields, so it technically isn't invalid to "add" booleans | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.reverse = refStruct.reverse || (bool)(object)value; | |||
return (T)(object)refStruct.reverse; | |||
} | |||
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.reverse = refStruct.reverse || (bool)(object)value; | |||
return (T)(object)refStruct.reverse; | |||
} | |||
break; | |||
case TweakableStat.StartValue: | |||
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID)) | |||
{ | |||
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID); | |||
refStruct.startValue += (float)(object)value; | |||
return (T)(object)refStruct.startValue; | |||
} | |||
break; | |||
} | |||
return default(T); | |||
} | |||
public T AddStatAny<T>(uint blockID, TweakableStat stat, T value) | |||
{ | |||
return AddStatAny<T>(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); | |||
} | |||
public dynamic AddStatDynamic(EGID blockID, TweakableStat stat, dynamic value) | |||
{ | |||
switch (stat) | |||
{ | |||
case TweakableStat.TopSpeed: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxVelocity += value; | |||
return refStruct.maxVelocity; | |||
} | |||
break; | |||
case TweakableStat.Torque: | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.maxForce += value; | |||
return refStruct.maxForce; | |||
} | |||
break; | |||
case TweakableStat.MaxExtension: | |||
if (entitiesDB.Exists<PistonReadOnlyStruct>(blockID)) | |||
{ | |||
ref PistonReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<PistonReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation += value; | |||
return refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.MinAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.minDeviation += value; | |||
return refStruct.minDeviation; | |||
} | |||
break; | |||
case TweakableStat.MaxAngle: | |||
if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.maxDeviation += value; | |||
return refStruct.maxDeviation; | |||
} | |||
break; | |||
case TweakableStat.Reverse: | |||
// '+' is associated with logical OR in some fields, so it technically isn't invalid to "add" booleans | |||
if (entitiesDB.Exists<MotorReadOnlyStruct>(blockID)) | |||
{ | |||
ref MotorReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<MotorReadOnlyStruct>(blockID); | |||
refStruct.reverse = refStruct.reverse || value; | |||
return refStruct.reverse; | |||
} | |||
else if (entitiesDB.Exists<ServoReadOnlyStruct>(blockID)) | |||
{ | |||
ref ServoReadOnlyStruct refStruct = ref entitiesDB.QueryEntity<ServoReadOnlyStruct>(blockID); | |||
refStruct.reverse = refStruct.reverse || value; | |||
return refStruct.reverse; | |||
} | |||
break; | |||
case TweakableStat.StartValue: | |||
if (entitiesDB.Exists<SignalGeneratorEntityStruct>(blockID)) | |||
{ | |||
ref SignalGeneratorEntityStruct refStruct = ref entitiesDB.QueryEntity<SignalGeneratorEntityStruct>(blockID); | |||
refStruct.startValue += value; | |||
return refStruct.startValue; | |||
} | |||
break; | |||
} | |||
return null; | |||
} | |||
public dynamic AddStatDynamic(uint blockID, TweakableStat stat, dynamic value) | |||
{ | |||
return AddStatDynamic(new EGID(blockID, BlockIdentifiers.OWNED_BLOCKS), stat, value); | |||
} | |||
} | |||
} |
@@ -1,13 +0,0 @@ | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public enum TweakableStat | |||
{ | |||
TopSpeed, // MotorReadOnlyStruct | |||
Torque, // MotorReadOnlyStruct | |||
MaxExtension, // PistonReadOnlyStruct | |||
MinAngle, // ServoReadOnlyStruct | |||
MaxAngle, // ServoReadOnlyStruct | |||
Reverse, // MotorReadOnlyStruct or ServoReadOnlyStruct | |||
StartValue, // SignalGeneratorEntityStruct | |||
} | |||
} |
@@ -63,8 +63,6 @@ namespace GamecraftModdingAPI | |||
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine); | |||
// init block implementors | |||
Logging.MetaDebugLog($"Initializing Blocks"); | |||
Blocks.Signals.Init(); | |||
Blocks.Tweakable.Init(); | |||
// init inventory | |||
Inventory.Hotbar.Init(); | |||
// init input | |||
@@ -146,35 +146,6 @@ namespace GamecraftModdingAPI.Tests | |||
.Action((float x, float y, float z) => { Block.PlaceNew(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); }) | |||
.Build(); | |||
System.Random random = new System.Random(); // for command below | |||
CommandBuilder.Builder() | |||
.Name("RandomizeSignalsInputs") | |||
.Description("Do the thing") | |||
.Action(() => { | |||
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); | |||
}).Build(); | |||
CommandBuilder.Builder("getBlock") | |||
.Action(() => uREPL.Log.Output(new Player(Players.PlayerType.Local).GetBlockLookedAt()+"")).Build(); | |||
@@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI" | |||
# could be handy for archiving the generated documentation or if some version | |||
# control system is used. | |||
PROJECT_NUMBER = "v1.0.0" | |||
PROJECT_NUMBER = "v1.1.0" | |||
# Using the PROJECT_BRIEF tag one can provide an optional one line description | |||
# for a project that appears at the top of each page and should give viewer a | |||