Add wiring API and improve signal support
This commit is contained in:
parent
ca0e6e089d
commit
708dbdd81d
13 changed files with 706 additions and 18 deletions
|
@ -122,6 +122,7 @@ namespace GamecraftModdingAPI
|
||||||
new Dictionary<Type, ExclusiveGroupStruct[]>
|
new Dictionary<Type, ExclusiveGroupStruct[]>
|
||||||
{
|
{
|
||||||
{typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}},
|
{typeof(ConsoleBlock), new[] {CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP}},
|
||||||
|
{typeof(LogicGate), new [] {CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP}},
|
||||||
{typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}},
|
{typeof(Motor), new[] {CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP}},
|
||||||
{typeof(MusicBlock), new[] {CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP}},
|
{typeof(MusicBlock), new[] {CommonExclusiveGroups.BUILD_MUSIC_BLOCK_GROUP}},
|
||||||
{typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}},
|
{typeof(Piston), new[] {CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP}},
|
||||||
|
@ -420,6 +421,8 @@ namespace GamecraftModdingAPI
|
||||||
GameEngineManager.AddGameEngine(BlockEngine);
|
GameEngineManager.AddGameEngine(BlockEngine);
|
||||||
GameEngineManager.AddGameEngine(BlockEventsEngine);
|
GameEngineManager.AddGameEngine(BlockEventsEngine);
|
||||||
GameEngineManager.AddGameEngine(ScalingEngine);
|
GameEngineManager.AddGameEngine(ScalingEngine);
|
||||||
|
GameEngineManager.AddGameEngine(SignalEngine);
|
||||||
|
Wire.signalEngine = SignalEngine; // requires same functionality, no need to duplicate the engine
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -40,4 +40,26 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class WiringException : BlockException
|
||||||
|
{
|
||||||
|
public WiringException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WiringException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WireInvalidException : WiringException
|
||||||
|
{
|
||||||
|
public WireInvalidException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WireInvalidException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Gamecraft.Wires;
|
||||||
|
|
||||||
using GamecraftModdingAPI;
|
using GamecraftModdingAPI;
|
||||||
using GamecraftModdingAPI.Tests;
|
using GamecraftModdingAPI.Tests;
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
namespace GamecraftModdingAPI.Blocks
|
namespace GamecraftModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
|
@ -100,6 +101,24 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
//Assert.Log(b.Track.ToString());
|
//Assert.Log(b.Track.ToString());
|
||||||
if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return;
|
if (!Assert.Equal(b.Track.ToString(), new Guid("3237ff8f-f5f2-4f84-8144-496ca280f8c0").ToString(), $"MusicBlock.Track {b.Track} does not equal default value, possibly because it failed silently.", "MusicBlock.Track is equal to default.")) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[APITestCase(TestType.EditMode)]
|
||||||
|
public static void TestLogicGate()
|
||||||
|
{
|
||||||
|
Block newBlock = Block.PlaceNew(BlockIDs.NOTLogicBlock, Unity.Mathematics.float3.zero + 1);
|
||||||
|
LogicGate b = null; // Note: the assignment operation is a lambda, which slightly confuses the compiler
|
||||||
|
Assert.Errorless(() => { b = newBlock.Specialise<LogicGate>(); }, "Block.Specialize<LogicGate>() raised an exception: ", "Block.Specialize<LogicGate>() completed without issue.");
|
||||||
|
if (!Assert.NotNull(b, "Block.Specialize<LogicGate>() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return;
|
||||||
|
if (!Assert.Equal(b.InputCount, 1u, $"LogicGate.InputCount {b.InputCount} does not equal default value, possibly because it failed silently.", "LogicGate.InputCount is default.")) return;
|
||||||
|
if (!Assert.Equal(b.OutputCount, 1u, $"LogicGate.OutputCount {b.OutputCount} does not equal default value, possibly because it failed silently.", "LogicGate.OutputCount is default.")) return;
|
||||||
|
if (!Assert.NotNull(b, "Block.Specialize<LogicGate>() returned null, possibly because it failed silently.", "Specialized LogicGate is not null.")) return;
|
||||||
|
//if (!Assert.Equal(b.PortName(0, true), "Input", $"LogicGate.PortName(0, input:true) {b.PortName(0, true)} does not equal default value, possibly because it failed silently.", "LogicGate.PortName(0, input:true) is close enough to default.")) return;
|
||||||
|
LogicGate target = null;
|
||||||
|
if (!Assert.Errorless(() => { target = Block.PlaceNew<LogicGate>(BlockIDs.ANDLogicBlock, Unity.Mathematics.float3.zero + 2); })) return;
|
||||||
|
Wire newWire = null;
|
||||||
|
if (!Assert.Errorless(() => { newWire = b.Connect(0, target, 0);})) return;
|
||||||
|
if (!Assert.NotNull(newWire, "SignalingBlock.Connect(...) returned null, possible because it failed silently.", "SignalingBlock.Connect(...) returned a non-null value.")) return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
16
GamecraftModdingAPI/Blocks/LogicGate.cs
Normal file
16
GamecraftModdingAPI/Blocks/LogicGate.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using RobocraftX.Common;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public class LogicGate : SignalingBlock
|
||||||
|
{
|
||||||
|
public LogicGate(EGID id) : base(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogicGate(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_LOGIC_BLOCK_GROUP))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using Svelto.ECS;
|
using System;
|
||||||
|
using Svelto.ECS;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Gamecraft.Wires;
|
using Gamecraft.Wires;
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Engine which executes signal actions
|
/// Engine which executes signal actions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SignalEngine : IApiEngine
|
public class SignalEngine : IApiEngine, IFactoryEngine
|
||||||
{
|
{
|
||||||
public const float POSITIVE_HIGH = 1.0f;
|
public const float POSITIVE_HIGH = 1.0f;
|
||||||
public const float NEGATIVE_HIGH = -1.0f;
|
public const float NEGATIVE_HIGH = -1.0f;
|
||||||
|
@ -20,6 +21,8 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
|
|
||||||
public EntitiesDB entitiesDB { set; private get; }
|
public EntitiesDB entitiesDB { set; private get; }
|
||||||
|
|
||||||
|
public IEntityFactory Factory { get; set; }
|
||||||
|
|
||||||
public bool isRemovable => false;
|
public bool isRemovable => false;
|
||||||
|
|
||||||
public bool IsInGame = false;
|
public bool IsInGame = false;
|
||||||
|
@ -34,7 +37,73 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
IsInGame = true;
|
IsInGame = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementations for Signal static class
|
// implementations for block wiring
|
||||||
|
|
||||||
|
public EGID CreateNewWire(EGID startBlock, byte startPort, EGID endBlock, byte endPort)
|
||||||
|
{
|
||||||
|
EGID wireEGID = new EGID(WiresExclusiveGroups.NewWireEntityId, NamedExclusiveGroup<WiresGroup>.Group);
|
||||||
|
EntityComponentInitializer wireInitializer = Factory.BuildEntity<WireEntityDescriptor>(wireEGID);
|
||||||
|
wireInitializer.Init(new WireEntityStruct
|
||||||
|
{
|
||||||
|
sourceBlockEGID = startBlock,
|
||||||
|
sourcePortUsage = startPort,
|
||||||
|
destinationBlockEGID = endBlock,
|
||||||
|
destinationPortUsage = endPort,
|
||||||
|
});
|
||||||
|
return wireEGID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref WireEntityStruct GetWire(EGID wire)
|
||||||
|
{
|
||||||
|
if (!entitiesDB.Exists<WireEntityStruct>(wire))
|
||||||
|
{
|
||||||
|
throw new WiringException($"Wire {wire} does not exist");
|
||||||
|
}
|
||||||
|
return ref entitiesDB.QueryEntity<WireEntityStruct>(wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref PortEntityStruct GetPort(EGID port)
|
||||||
|
{
|
||||||
|
if (!entitiesDB.Exists<PortEntityStruct>(port))
|
||||||
|
{
|
||||||
|
throw new WiringException($"Port {port} does not exist (yet?)");
|
||||||
|
}
|
||||||
|
return ref entitiesDB.QueryEntity<PortEntityStruct>(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref PortEntityStruct GetPortByOffset(BlockPortsStruct bps, byte portNumber, bool input)
|
||||||
|
{
|
||||||
|
ExclusiveGroup group = input
|
||||||
|
? NamedExclusiveGroup<InputPortsGroup>.Group
|
||||||
|
: NamedExclusiveGroup<OutputPortsGroup>.Group;
|
||||||
|
uint id = (input ? bps.firstInputID : bps.firstOutputID) + portNumber;
|
||||||
|
EGID egid = new EGID(id, group);
|
||||||
|
if (!entitiesDB.Exists<PortEntityStruct>(egid))
|
||||||
|
{
|
||||||
|
throw new WiringException("Port does not exist");
|
||||||
|
}
|
||||||
|
return ref entitiesDB.QueryEntity<PortEntityStruct>(egid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref PortEntityStruct GetPortByOffset(Block block, byte portNumber, bool input)
|
||||||
|
{
|
||||||
|
BlockPortsStruct bps = GetFromDbOrInitData<BlockPortsStruct>(block, block.Id, out bool exists);
|
||||||
|
if (!exists)
|
||||||
|
{
|
||||||
|
throw new BlockException("Block does not exist");
|
||||||
|
}
|
||||||
|
return ref GetPortByOffset(bps, portNumber, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T GetComponent<T>(EGID egid) where T : struct, IEntityComponent
|
||||||
|
{
|
||||||
|
return ref entitiesDB.QueryEntity<T>(egid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Exists<T>(EGID egid) where T : struct, IEntityComponent
|
||||||
|
{
|
||||||
|
return entitiesDB.Exists<T>(egid);
|
||||||
|
}
|
||||||
|
|
||||||
public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true)
|
public bool SetSignal(EGID blockID, float signal, out uint signalID, bool input = true)
|
||||||
{
|
{
|
||||||
|
@ -123,7 +192,7 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
return inputs;
|
return inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EGID[] GetSignalOutputs(EGID blockID)
|
public EGID[] GetSignalOutputs(EGID blockID)
|
||||||
{
|
{
|
||||||
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
|
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(blockID);
|
||||||
EGID[] outputs = new EGID[ports.outputCount];
|
EGID[] outputs = new EGID[ports.outputCount];
|
||||||
|
@ -134,6 +203,18 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
return outputs;
|
return outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EGID MatchBlockInputToPort(Block block, byte portUsage, out bool exists)
|
||||||
|
{
|
||||||
|
BlockPortsStruct ports = GetFromDbOrInitData<BlockPortsStruct>(block, block.Id, out exists);
|
||||||
|
return new EGID(ports.firstInputID + portUsage, NamedExclusiveGroup<InputPortsGroup>.Group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EGID MatchBlockOutputToPort(Block block, byte portUsage, out bool exists)
|
||||||
|
{
|
||||||
|
BlockPortsStruct ports = GetFromDbOrInitData<BlockPortsStruct>(block, block.Id, out exists);
|
||||||
|
return new EGID(ports.firstOutputID + portUsage, NamedExclusiveGroup<OutputPortsGroup>.Group);
|
||||||
|
}
|
||||||
|
|
||||||
public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists)
|
public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists)
|
||||||
{
|
{
|
||||||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
|
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
|
||||||
|
@ -152,6 +233,57 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
return ref defRef[0];
|
return ref defRef[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ref WireEntityStruct MatchBlocksToWire(EGID startBlock, EGID endBlock, out bool exists, byte startPort = byte.MaxValue,
|
||||||
|
byte endPort = byte.MaxValue)
|
||||||
|
{
|
||||||
|
EGID[] startPorts;
|
||||||
|
if (startPort == byte.MaxValue)
|
||||||
|
{
|
||||||
|
// search all output ports on source block
|
||||||
|
startPorts = GetSignalOutputs(startBlock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(startBlock);
|
||||||
|
startPorts = new EGID[] {new EGID(ports.firstOutputID + startPort, NamedExclusiveGroup<OutputPortsGroup>.Group) };
|
||||||
|
}
|
||||||
|
|
||||||
|
EGID[] endPorts;
|
||||||
|
if (startPort == byte.MaxValue)
|
||||||
|
{
|
||||||
|
// search all input ports on destination block
|
||||||
|
endPorts = GetSignalInputs(endBlock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BlockPortsStruct ports = entitiesDB.QueryEntity<BlockPortsStruct>(endBlock);
|
||||||
|
endPorts = new EGID[] {new EGID(ports.firstInputID + endPort, NamedExclusiveGroup<InputPortsGroup>.Group) };
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityCollection<WireEntityStruct> wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
|
||||||
|
for (int endIndex = 0; endIndex < endPorts.Length; endIndex++)
|
||||||
|
{
|
||||||
|
PortEntityStruct endPES = entitiesDB.QueryEntity<PortEntityStruct>(endPorts[endIndex]);
|
||||||
|
for (int startIndex = 0; startIndex < startPorts.Length; startIndex++)
|
||||||
|
{
|
||||||
|
PortEntityStruct startPES = entitiesDB.QueryEntity<PortEntityStruct>(startPorts[startIndex]);
|
||||||
|
for (int w = 0; w < wires.count; w++)
|
||||||
|
{
|
||||||
|
if ((wires[w].destinationPortUsage == endPES.usage && wires[w].destinationBlockEGID == endBlock)
|
||||||
|
&& (wires[w].sourcePortUsage == startPES.usage && wires[w].sourceBlockEGID == startBlock))
|
||||||
|
{
|
||||||
|
exists = true;
|
||||||
|
return ref wires[w];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exists = false;
|
||||||
|
WireEntityStruct[] defRef = new WireEntityStruct[1];
|
||||||
|
return ref defRef[0];
|
||||||
|
}
|
||||||
|
|
||||||
public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists)
|
public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists)
|
||||||
{
|
{
|
||||||
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
|
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
|
||||||
|
@ -175,6 +307,69 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
return res.ToArray();
|
return res.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EGID[] WiredToInput(EGID block, byte port)
|
||||||
|
{
|
||||||
|
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group,
|
||||||
|
(WireEntityStruct wes) => wes.destinationPortUsage == port && wes.destinationBlockEGID == block);
|
||||||
|
EGID[] result = new EGID[wireEntityStructs.Length];
|
||||||
|
for (uint i = 0; i < wireEntityStructs.Length; i++)
|
||||||
|
{
|
||||||
|
result[i] = wireEntityStructs[i].ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EGID[] WiredToOutput(EGID block, byte port)
|
||||||
|
{
|
||||||
|
WireEntityStruct[] wireEntityStructs = Search(NamedExclusiveGroup<WiresGroup>.Group,
|
||||||
|
(WireEntityStruct wes) => wes.sourcePortUsage == port && wes.sourceBlockEGID == block);
|
||||||
|
EGID[] result = new EGID[wireEntityStructs.Length];
|
||||||
|
for (uint i = 0; i < wireEntityStructs.Length; i++)
|
||||||
|
{
|
||||||
|
result[i] = wireEntityStructs[i].ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T[] Search<T>(ExclusiveGroup group, Func<T, bool> isMatch) where T : struct, IEntityComponent
|
||||||
|
{
|
||||||
|
FasterList<T> results = new FasterList<T>();
|
||||||
|
EntityCollection<T> components = entitiesDB.QueryEntities<T>(group);
|
||||||
|
for (uint i = 0; i < components.count; i++)
|
||||||
|
{
|
||||||
|
if (isMatch(components[i]))
|
||||||
|
{
|
||||||
|
results.Add(components[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ref T GetFromDbOrInitData<T>(Block block, EGID id, out bool exists) where T : struct, IEntityComponent
|
||||||
|
{
|
||||||
|
T[] defRef = new T[1];
|
||||||
|
if (entitiesDB.Exists<T>(id))
|
||||||
|
{
|
||||||
|
exists = true;
|
||||||
|
return ref entitiesDB.QueryEntity<T>(id);
|
||||||
|
}
|
||||||
|
if (block == null || block.InitData.Group == null)
|
||||||
|
{
|
||||||
|
exists = false;
|
||||||
|
return ref defRef[0];
|
||||||
|
}
|
||||||
|
EntityComponentInitializer initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
|
||||||
|
if (initializer.Has<T>())
|
||||||
|
{
|
||||||
|
exists = true;
|
||||||
|
return ref initializer.Get<T>();
|
||||||
|
}
|
||||||
|
exists = false;
|
||||||
|
return ref defRef[0];
|
||||||
|
}
|
||||||
|
|
||||||
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
|
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
|
||||||
{
|
{
|
||||||
ExclusiveGroup group = input
|
ExclusiveGroup group = input
|
||||||
|
|
|
@ -16,18 +16,10 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
public SignalingBlock(EGID id) : base(id)
|
public SignalingBlock(EGID id) : base(id)
|
||||||
{
|
{
|
||||||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignalingBlock(uint id) : base(id)
|
public SignalingBlock(uint id) : base(id)
|
||||||
{
|
{
|
||||||
if (!BlockEngine.GetBlockInfoExists<BlockPortsStruct>(this))
|
|
||||||
{
|
|
||||||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -85,5 +77,91 @@ namespace GamecraftModdingAPI.Blocks
|
||||||
{
|
{
|
||||||
get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.outputCount);
|
get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.outputCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Connect an output on this block to an input on another block.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourcePort">Output port number.</param>
|
||||||
|
/// <param name="destination">Input block.</param>
|
||||||
|
/// <param name="destinationPort">Input port number.</param>
|
||||||
|
/// <returns>The wire connection</returns>
|
||||||
|
/// <exception cref="WiringException">The wire could not be created.</exception>
|
||||||
|
public Wire Connect(byte sourcePort, SignalingBlock destination, byte destinationPort)
|
||||||
|
{
|
||||||
|
if (sourcePort >= OutputCount)
|
||||||
|
{
|
||||||
|
throw new WiringException("Source port does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destinationPort >= destination.InputCount)
|
||||||
|
{
|
||||||
|
throw new WiringException("Destination port does not exist");
|
||||||
|
}
|
||||||
|
return Wire.Connect(this, sourcePort, destination, destinationPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The port's name.
|
||||||
|
/// This is localized to the user's language, so this is not reliable for port identification.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="port">Port number.</param>
|
||||||
|
/// <param name="input">Whether the port is an input (true) or an output (false).</param>
|
||||||
|
/// <returns>The localized port name.</returns>
|
||||||
|
public string PortName(byte port, bool input)
|
||||||
|
{
|
||||||
|
BlockPortsStruct bps = BlockEngine.GetBlockInfo(this, (BlockPortsStruct a) => a);
|
||||||
|
PortEntityStruct pes = SignalEngine.GetPortByOffset(this, port, input);
|
||||||
|
return pes.portNameLocalised;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The input port's name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="port">Input port number.</param>
|
||||||
|
/// <returns>The port name, localized to the user's language.</returns>
|
||||||
|
public string InputPortName(byte port) => PortName(port, true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The output port's name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="port">Output port number.</param>
|
||||||
|
/// <returns>The port name, localized to the user's language.</returns>
|
||||||
|
public string OutputPortName(byte port) => PortName(port, false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All wires connected to the input port.
|
||||||
|
/// These wires will always be wired output -> input.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="port">Port number.</param>
|
||||||
|
/// <returns>Wires connected to the input port.</returns>
|
||||||
|
public Wire[] ConnectedToInput(byte port)
|
||||||
|
{
|
||||||
|
if (port >= InputCount) throw new WiringException($"Port input {port} does not exist");
|
||||||
|
EGID[] wireEgids = SignalEngine.WiredToInput(Id, port);
|
||||||
|
Wire[] wires = new Wire[wireEgids.Length];
|
||||||
|
for (uint i = 0; i < wireEgids.Length; i++)
|
||||||
|
{
|
||||||
|
wires[i] = new Wire(wireEgids[i]);
|
||||||
|
}
|
||||||
|
return wires;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All wires connected to the output port.
|
||||||
|
/// These wires will always be wired output -> input.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="port">Port number.</param>
|
||||||
|
/// <returns>Wires connected to the output port.</returns>
|
||||||
|
public Wire[] ConnectedToOutput(byte port)
|
||||||
|
{
|
||||||
|
if (port >= OutputCount) throw new WiringException($"Port output {port} does not exist");
|
||||||
|
EGID[] wireEgids = SignalEngine.WiredToOutput(Id, port);
|
||||||
|
Wire[] wires = new Wire[wireEgids.Length];
|
||||||
|
for (uint i = 0; i < wireEgids.Length; i++)
|
||||||
|
{
|
||||||
|
wires[i] = new Wire(wireEgids[i]);
|
||||||
|
}
|
||||||
|
return wires;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
338
GamecraftModdingAPI/Blocks/Wire.cs
Normal file
338
GamecraftModdingAPI/Blocks/Wire.cs
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Gamecraft.Wires;
|
||||||
|
using Svelto.ECS;
|
||||||
|
using Svelto.ECS.Experimental;
|
||||||
|
|
||||||
|
using GamecraftModdingAPI.Utility;
|
||||||
|
|
||||||
|
namespace GamecraftModdingAPI.Blocks
|
||||||
|
{
|
||||||
|
public class Wire
|
||||||
|
{
|
||||||
|
internal static SignalEngine signalEngine;
|
||||||
|
|
||||||
|
protected EGID startPortEGID;
|
||||||
|
|
||||||
|
protected EGID endPortEGID;
|
||||||
|
|
||||||
|
protected EGID startBlockEGID;
|
||||||
|
|
||||||
|
protected EGID endBlockEGID;
|
||||||
|
|
||||||
|
protected EGID wireEGID;
|
||||||
|
|
||||||
|
protected bool inputToOutput;
|
||||||
|
|
||||||
|
public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort)
|
||||||
|
{
|
||||||
|
EGID wireEgid = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort);
|
||||||
|
return new Wire(start, end, startPort, endPort, wireEgid, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An existing wire connection ending at the specified input.
|
||||||
|
/// If multiple exist, this will return the first one found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="end">Destination block.</param>
|
||||||
|
/// <param name="endPort">Port number.</param>
|
||||||
|
/// <returns>The wire, where the end of the wire is the block port specified, or null if does not exist.</returns>
|
||||||
|
public static Wire ConnectedToInputPort(SignalingBlock end, byte endPort)
|
||||||
|
{
|
||||||
|
EGID port = signalEngine.MatchBlockInputToPort(end, endPort, out bool exists);
|
||||||
|
if (!exists) return null;
|
||||||
|
WireEntityStruct wire = signalEngine.MatchPortToWire(port, end.Id, out exists);
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
return new Wire(new Block(wire.sourceBlockEGID), end, wire.sourcePortUsage, endPort);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An existing wire connection starting at the specified output.
|
||||||
|
/// If multiple exist, this will return the first one found.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Source block entity ID.</param>
|
||||||
|
/// <param name="startPort">Port number.</param>
|
||||||
|
/// <returns>The wire, where the start of the wire is the block port specified, or null if does not exist.</returns>
|
||||||
|
public static Wire ConnectedToOutputPort(SignalingBlock start, byte startPort)
|
||||||
|
{
|
||||||
|
EGID port = signalEngine.MatchBlockOutputToPort(start, startPort, out bool exists);
|
||||||
|
if (!exists) return null;
|
||||||
|
WireEntityStruct wire = signalEngine.MatchPortToWire(port, start.Id, out exists);
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
return new Wire(start, new Block(wire.destinationBlockEGID), startPort, wire.destinationPortUsage);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a wire object from an existing connection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Starting block ID.</param>
|
||||||
|
/// <param name="end">Ending block ID.</param>
|
||||||
|
/// <param name="startPort">Starting port number, or guess if omitted.</param>
|
||||||
|
/// <param name="endPort">Ending port number, or guess if omitted.</param>
|
||||||
|
/// <exception cref="WireInvalidException">Guessing failed or wire does not exist.</exception>
|
||||||
|
public Wire(Block start, Block end, byte startPort = Byte.MaxValue, byte endPort = Byte.MaxValue)
|
||||||
|
{
|
||||||
|
startBlockEGID = start.Id;
|
||||||
|
endBlockEGID = end.Id;
|
||||||
|
// find block ports
|
||||||
|
WireEntityStruct wire = signalEngine.MatchBlocksToWire(start.Id, end.Id, out bool exists, startPort, endPort);
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
wireEGID = wire.ID;
|
||||||
|
endPortEGID = signalEngine.MatchBlockInputToPort(end, wire.destinationPortUsage, out exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire end port not found");
|
||||||
|
startPortEGID = signalEngine.MatchBlockOutputToPort(start, wire.sourcePortUsage, out exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire start port not found");
|
||||||
|
inputToOutput = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// flip I/O around and try again
|
||||||
|
wire = signalEngine.MatchBlocksToWire(end.Id, start.Id, out exists, endPort, startPort);
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
wireEGID = wire.ID;
|
||||||
|
endPortEGID = signalEngine.MatchBlockOutputToPort(end, wire.sourcePortUsage, out exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire end port not found");
|
||||||
|
startPortEGID = signalEngine.MatchBlockInputToPort(start, wire.destinationPortUsage, out exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire start port not found");
|
||||||
|
inputToOutput = true; // end is actually the source
|
||||||
|
// NB: start and end are handled exactly as they're received as params.
|
||||||
|
// This makes wire traversal easier, but makes logic in this class a bit more complex
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new WireInvalidException("Wire not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a wire object from an existing wire connection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Starting block ID.</param>
|
||||||
|
/// <param name="end">Ending block ID.</param>
|
||||||
|
/// <param name="startPort">Starting port number.</param>
|
||||||
|
/// <param name="endPort">Ending port number.</param>
|
||||||
|
/// <param name="wire">The wire ID.</param>
|
||||||
|
/// <param name="inputToOutput">Whether the wire direction goes input -> output (true) or output -> input (false, preferred).</param>
|
||||||
|
public Wire(Block start, Block end, byte startPort, byte endPort, EGID wire, bool inputToOutput)
|
||||||
|
{
|
||||||
|
this.startBlockEGID = start.Id;
|
||||||
|
this.endBlockEGID = end.Id;
|
||||||
|
this.inputToOutput = inputToOutput;
|
||||||
|
this.wireEGID = wire;
|
||||||
|
if (inputToOutput)
|
||||||
|
{
|
||||||
|
endPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out bool exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire end port not found");
|
||||||
|
startPortEGID = signalEngine.MatchBlockInputToPort(end, endPort, out exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire start port not found");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
endPortEGID = signalEngine.MatchBlockInputToPort(end, endPort, out bool exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire end port not found");
|
||||||
|
startPortEGID = signalEngine.MatchBlockOutputToPort(start, startPort, out exists);
|
||||||
|
if (!exists) throw new WireInvalidException("Wire start port not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a wire object from an existing wire connection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wireEgid">The wire ID.</param>
|
||||||
|
public Wire(EGID wireEgid)
|
||||||
|
{
|
||||||
|
this.wireEGID = wireEgid;
|
||||||
|
WireEntityStruct wire = signalEngine.GetWire(wireEGID);
|
||||||
|
this.startBlockEGID = wire.sourceBlockEGID;
|
||||||
|
this.endBlockEGID = wire.destinationBlockEGID;
|
||||||
|
this.inputToOutput = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The wire's in-game id.
|
||||||
|
/// </summary>
|
||||||
|
public EGID Id
|
||||||
|
{
|
||||||
|
get => wireEGID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The wire's signal value, as a float.
|
||||||
|
/// </summary>
|
||||||
|
public float Float
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return 0f;
|
||||||
|
return cds.valueAsFloat;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return;
|
||||||
|
cds.valueAsFloat = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The wire's string signal.
|
||||||
|
/// </summary>
|
||||||
|
public string String
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return "";
|
||||||
|
return cds.valueAsEcsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return;
|
||||||
|
cds.valueAsEcsString.Set(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The wire's raw string signal.
|
||||||
|
/// </summary>
|
||||||
|
public ECSString ECSString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return default;
|
||||||
|
return cds.valueAsEcsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return;
|
||||||
|
cds.valueAsEcsString = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The wire's signal id.
|
||||||
|
/// I'm 50% sure this is useless.
|
||||||
|
/// </summary>
|
||||||
|
public uint SignalId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return uint.MaxValue;
|
||||||
|
return cds.valueAsID;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ref ChannelDataStruct cds = ref signalEngine.GetChannelDataStruct(startPortEGID, out bool exists);
|
||||||
|
if (!exists) return;
|
||||||
|
cds.valueAsID = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block at the beginning of the wire.
|
||||||
|
/// </summary>
|
||||||
|
public SignalingBlock Start
|
||||||
|
{
|
||||||
|
get => new SignalingBlock(startBlockEGID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The port number that the beginning of the wire connects to.
|
||||||
|
/// </summary>
|
||||||
|
public byte StartPort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
WireEntityStruct wire = signalEngine.GetWire(wireEGID);
|
||||||
|
if (inputToOutput)
|
||||||
|
{
|
||||||
|
return wire.destinationPortUsage;
|
||||||
|
}
|
||||||
|
return wire.sourcePortUsage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The block at the end of the wire.
|
||||||
|
/// </summary>
|
||||||
|
public SignalingBlock End
|
||||||
|
{
|
||||||
|
get => new SignalingBlock(endBlockEGID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The port number that the end of the wire connects to.
|
||||||
|
/// </summary>
|
||||||
|
public byte EndPort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
WireEntityStruct wire = signalEngine.GetWire(wireEGID);
|
||||||
|
if (inputToOutput)
|
||||||
|
{
|
||||||
|
return wire.sourcePortUsage;
|
||||||
|
}
|
||||||
|
return wire.destinationPortUsage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a copy of the wire object where the direction of the wire is guaranteed to be from a block output to a block input.
|
||||||
|
/// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A copy of the wire object.</returns>
|
||||||
|
public Wire OutputToInputCopy()
|
||||||
|
{
|
||||||
|
return new Wire(wireEGID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert the wire object to the direction the signal flows.
|
||||||
|
/// Signals on wires always flows from a block output port to a block input port.
|
||||||
|
/// This is simply a different memory configuration and does not affect the in-game wire (which is always output -> input).
|
||||||
|
/// </summary>
|
||||||
|
public void OutputToInputInPlace()
|
||||||
|
{
|
||||||
|
if (inputToOutput)
|
||||||
|
{
|
||||||
|
inputToOutput = false;
|
||||||
|
// swap inputs and outputs
|
||||||
|
EGID temp = endBlockEGID;
|
||||||
|
endBlockEGID = startBlockEGID;
|
||||||
|
startBlockEGID = temp;
|
||||||
|
temp = endPortEGID;
|
||||||
|
endPortEGID = startPortEGID;
|
||||||
|
startPortEGID = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (signalEngine.Exists<WireEntityStruct>(wireEGID))
|
||||||
|
{
|
||||||
|
return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(Id)}: {End.Id}, ({Start.Type}::{StartPort} aka {Start.PortName(StartPort, inputToOutput)}) -> ({End.Type}::{EndPort} aka {End.PortName(EndPort, !inputToOutput)})";
|
||||||
|
}
|
||||||
|
return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(Id)}: {End.Id}, ({Start.Type}::{StartPort}) -> ({End.Type}::{EndPort})";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init() { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ namespace GamecraftModdingAPI.Events
|
||||||
/// Keeps track of event handlers and emitters.
|
/// Keeps track of event handlers and emitters.
|
||||||
/// This is used to add, remove and get API event handlers and emitters.
|
/// This is used to add, remove and get API event handlers and emitters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete]
|
[Obsolete("This will be removed in an upcoming update. Use the new C# event architecture from GamecraftModdingAPI.App")]
|
||||||
public static class EventManager
|
public static class EventManager
|
||||||
{
|
{
|
||||||
private static Dictionary<string, IEventEmitterEngine> _eventEmitters = new Dictionary<string, IEventEmitterEngine>();
|
private static Dictionary<string, IEventEmitterEngine> _eventEmitters = new Dictionary<string, IEventEmitterEngine>();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<Version>1.4.0</Version>
|
<Version>1.5.0</Version>
|
||||||
<Authors>Exmods</Authors>
|
<Authors>Exmods</Authors>
|
||||||
<PackageLicenseExpression>GNU General Public Licence 3+</PackageLicenseExpression>
|
<PackageLicenseExpression>GNU General Public Licence 3+</PackageLicenseExpression>
|
||||||
<PackageProjectUrl>https://git.exmods.org/modtainers/GamecraftModdingAPI</PackageProjectUrl>
|
<PackageProjectUrl>https://git.exmods.org/modtainers/GamecraftModdingAPI</PackageProjectUrl>
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using GamecraftModdingAPI.Blocks;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
|
||||||
using GamecraftModdingAPI.Utility;
|
using GamecraftModdingAPI.Utility;
|
||||||
|
@ -49,6 +49,7 @@ namespace GamecraftModdingAPI
|
||||||
harmony.PatchAll(currentAssembly);
|
harmony.PatchAll(currentAssembly);
|
||||||
// init utility
|
// init utility
|
||||||
Logging.MetaDebugLog($"Initializing Utility");
|
Logging.MetaDebugLog($"Initializing Utility");
|
||||||
|
#pragma warning disable 0612,0618
|
||||||
Utility.GameState.Init();
|
Utility.GameState.Init();
|
||||||
Utility.VersionTracking.Init();
|
Utility.VersionTracking.Init();
|
||||||
// create default event emitters
|
// create default event emitters
|
||||||
|
@ -61,6 +62,7 @@ namespace GamecraftModdingAPI
|
||||||
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false));
|
EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false));
|
||||||
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.buildEngine);
|
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.buildEngine);
|
||||||
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine);
|
EventManager.AddEventEmitter(GameHostTransitionDeterministicGroupEnginePatch.simEngine);
|
||||||
|
#pragma warning restore 0612,0618
|
||||||
// init block implementors
|
// init block implementors
|
||||||
Logging.MetaDebugLog($"Initializing Blocks");
|
Logging.MetaDebugLog($"Initializing Blocks");
|
||||||
// init inventory
|
// init inventory
|
||||||
|
@ -70,6 +72,7 @@ namespace GamecraftModdingAPI
|
||||||
// init object-oriented classes
|
// init object-oriented classes
|
||||||
Player.Init();
|
Player.Init();
|
||||||
Block.Init();
|
Block.Init();
|
||||||
|
Wire.Init();
|
||||||
GameClient.Init();
|
GameClient.Init();
|
||||||
AsyncUtils.Init();
|
AsyncUtils.Init();
|
||||||
GamecraftModdingAPI.App.Client.Init();
|
GamecraftModdingAPI.App.Client.Init();
|
||||||
|
|
|
@ -68,6 +68,7 @@ namespace GamecraftModdingAPI.Tests
|
||||||
//Utility.VersionTracking.Enable();//(very) unstable
|
//Utility.VersionTracking.Enable();//(very) unstable
|
||||||
|
|
||||||
// debug/test handlers
|
// debug/test handlers
|
||||||
|
#pragma warning disable 0612
|
||||||
HandlerBuilder.Builder()
|
HandlerBuilder.Builder()
|
||||||
.Name("appinit API debug")
|
.Name("appinit API debug")
|
||||||
.Handle(EventType.ApplicationInitialized)
|
.Handle(EventType.ApplicationInitialized)
|
||||||
|
@ -115,7 +116,7 @@ namespace GamecraftModdingAPI.Tests
|
||||||
.Handle(EventType.Menu)
|
.Handle(EventType.Menu)
|
||||||
.OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); })
|
.OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); })
|
||||||
.Build();
|
.Build();
|
||||||
|
#pragma warning restore 0612
|
||||||
/*HandlerBuilder.Builder("enter game from menu test")
|
/*HandlerBuilder.Builder("enter game from menu test")
|
||||||
.Handle(EventType.Menu)
|
.Handle(EventType.Menu)
|
||||||
.OnActivation(() =>
|
.OnActivation(() =>
|
||||||
|
@ -253,6 +254,19 @@ namespace GamecraftModdingAPI.Tests
|
||||||
Logging.CommandLog($"Blocks placed in {sw.ElapsedMilliseconds} ms");
|
Logging.CommandLog($"Blocks placed in {sw.ElapsedMilliseconds} ms");
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
CommandBuilder.Builder()
|
||||||
|
.Name("WireTest")
|
||||||
|
.Description("Place two blocks and then wire them together")
|
||||||
|
.Action(() =>
|
||||||
|
{
|
||||||
|
LogicGate notBlock = Block.PlaceNew<LogicGate>(BlockIDs.NOTLogicBlock, new float3(1, 2, 0));
|
||||||
|
LogicGate andBlock = Block.PlaceNew<LogicGate>(BlockIDs.ANDLogicBlock, new float3(2, 2, 0));
|
||||||
|
// connect NOT Gate output to AND Gate input #2 (ports are zero-indexed, so 1 is 2nd position and 0 is 1st position)
|
||||||
|
Wire conn = notBlock.Connect(0, andBlock, 1);
|
||||||
|
Logging.CommandLog(conn.ToString());
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
GameClient.SetDebugInfo("InstalledMods", InstalledMods);
|
GameClient.SetDebugInfo("InstalledMods", InstalledMods);
|
||||||
Block.Placed += (sender, args) =>
|
Block.Placed += (sender, args) =>
|
||||||
|
|
|
@ -209,7 +209,7 @@ namespace GamecraftModdingAPI.Tests
|
||||||
{
|
{
|
||||||
Assert.Fail($"Build test '{m}' raised an exception: {e.ToString()}");
|
Assert.Fail($"Build test '{m}' raised an exception: {e.ToString()}");
|
||||||
}
|
}
|
||||||
yield return Yield.It;
|
yield return Yield.It;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ PROJECT_NAME = "GamecraftModdingAPI"
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "v1.3.0"
|
PROJECT_NUMBER = "v1.5.0"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# 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
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|
Loading…
Reference in a new issue