|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- 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;
-
- protected byte startPort;
-
- protected byte endPort;
-
- public static Wire Connect(SignalingBlock start, byte startPort, SignalingBlock end, byte endPort)
- {
- WireEntityStruct wire = signalEngine.CreateNewWire(start.Id, startPort, end.Id, endPort);
- return new Wire(wire, start, end);
- }
-
- /// <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;
- endPort = wire.destinationPortUsage;
- startPort = wire.sourcePortUsage;
- }
- 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
- endPort = wire.sourcePortUsage;
- startPort = wire.destinationPortUsage;
- }
- 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");
- }
- this.startPort = startPort;
- this.endPort = endPort;
- }
-
- /// <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;
- endPortEGID = signalEngine.MatchBlockInputToPort(wire.destinationBlockEGID, wire.destinationPortUsage, out bool exists);
- if (!exists) throw new WireInvalidException("Wire end port not found");
- startPortEGID = signalEngine.MatchBlockOutputToPort(wire.sourceBlockEGID, wire.sourcePortUsage, out exists);
- if (!exists) throw new WireInvalidException("Wire start port not found");
- this.endPort = wire.destinationPortUsage;
- this.startPort = wire.sourcePortUsage;
- }
-
- internal Wire(WireEntityStruct wire, SignalingBlock src, SignalingBlock dest)
- {
- this.wireEGID = wire.ID;
- this.startBlockEGID = wire.sourceBlockEGID;
- this.endBlockEGID = wire.destinationBlockEGID;
- inputToOutput = false;
- endPortEGID = signalEngine.MatchBlockInputToPort(dest, wire.destinationPortUsage, out bool exists);
- if (!exists) throw new WireInvalidException("Wire end port not found");
- startPortEGID = signalEngine.MatchBlockOutputToPort(src, wire.sourcePortUsage, out exists);
- if (!exists) throw new WireInvalidException("Wire start port not found");
- this.endPort = wire.destinationPortUsage;
- this.startPort = wire.sourcePortUsage;
- }
-
- /// <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 => startPort;
- }
-
- /// <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 => endPort;
- }
-
- /// <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 flow 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;
- byte tempPortNumber = endPort;
- endPort = startPort;
- startPort = tempPortNumber;
- }
- }
-
- public override string ToString()
- {
- if (signalEngine.Exists<WireEntityStruct>(wireEGID))
- {
- return $"{nameof(Id)}: {Id}, Start{nameof(Start.Id)}: {Start.Id}, End{nameof(End.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(End.Id)}: {End.Id}, ({Start.Type}::{StartPort} -> {End.Type}::{EndPort})";
- }
-
- internal static void Init() { }
- }
- }
|