Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,38 @@
using System;
namespace Unity.VisualScripting
{
public sealed class ControlConnection : UnitConnection<ControlOutput, ControlInput>, IUnitConnection
{
[Obsolete(Serialization.ConstructorWarning)]
public ControlConnection() : base() { }
public ControlConnection(ControlOutput source, ControlInput destination) : base(source, destination)
{
if (source.hasValidConnection)
{
throw new InvalidConnectionException("Control output ports do not support multiple connections.");
}
}
#region Ports
public override ControlOutput source => sourceUnit.controlOutputs[sourceKey];
public override ControlInput destination => destinationUnit.controlInputs[destinationKey];
IUnitOutputPort IConnection<IUnitOutputPort, IUnitInputPort>.source => source;
IUnitInputPort IConnection<IUnitOutputPort, IUnitInputPort>.destination => destination;
#endregion
#region Dependencies
public override bool sourceExists => sourceUnit.controlOutputs.Contains(sourceKey);
public override bool destinationExists => destinationUnit.controlInputs.Contains(destinationKey);
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b71fe733d92c1489cb3c89d5841ea222
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,24 @@
namespace Unity.VisualScripting
{
/* Implementation notes:
*
* IUnitConnection cannot implement IConnection<IUnitOutputPort, IUnitInputPort> because
* the compiler will be overly strict and complain that types may unify.
* https://stackoverflow.com/questions/7664790
*
* Additionally, using contravariance for the type parameters will compile but
* fail at runtime, because Unity's Mono version does not properly support variance,
* even though it's supposed to be a CLR feature since .NET 1.1.
* https://forum.unity3d.com/threads/398665/
* https://github.com/jacobdufault/fullinspector/issues/9
*
* Therefore, the only remaining solution is to re-implement source and destination
* manually. This introduces ambiguity, as the compiler will warn, but it's fine
* if the implementations point both members to the same actual object.
*/
public interface IUnitConnection : IConnection<IUnitOutputPort, IUnitInputPort>, IGraphElementWithDebugData
{
new FlowGraph graph { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc809ec21d2bf44b983265840a5ed2f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,9 @@
namespace Unity.VisualScripting
{
public interface IUnitConnectionDebugData : IGraphElementDebugData
{
int lastInvokeFrame { get; set; }
float lastInvokeTime { get; set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9239efc28f45f4c848294b936db9bfa0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,4 @@
namespace Unity.VisualScripting
{
public interface IUnitRelation : IConnection<IUnitPort, IUnitPort> { }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20177830b472f40faa7374d0861ddad0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,68 @@
using System;
using System.Linq;
namespace Unity.VisualScripting
{
public sealed class InvalidConnection : UnitConnection<IUnitOutputPort, IUnitInputPort>, IUnitConnection
{
[Obsolete(Serialization.ConstructorWarning)]
public InvalidConnection() : base() { }
public InvalidConnection(IUnitOutputPort source, IUnitInputPort destination) : base(source, destination) { }
public override void AfterRemove()
{
base.AfterRemove();
source.unit.RemoveUnconnectedInvalidPorts();
destination.unit.RemoveUnconnectedInvalidPorts();
}
#region Ports
public override IUnitOutputPort source => sourceUnit.outputs.Single(p => p.key == sourceKey);
public override IUnitInputPort destination => destinationUnit.inputs.Single(p => p.key == destinationKey);
public IUnitOutputPort validSource => sourceUnit.validOutputs.Single(p => p.key == sourceKey);
public IUnitInputPort validDestination => destinationUnit.validInputs.Single(p => p.key == destinationKey);
#endregion
#region Dependencies
public override bool sourceExists => sourceUnit.outputs.Any(p => p.key == sourceKey);
public override bool destinationExists => destinationUnit.inputs.Any(p => p.key == destinationKey);
public bool validSourceExists => sourceUnit.validOutputs.Any(p => p.key == sourceKey);
public bool validDestinationExists => destinationUnit.validInputs.Any(p => p.key == destinationKey);
public override bool HandleDependencies()
{
// Replace the invalid connection with a valid connection if it can be created instead.
if (validSourceExists && validDestinationExists && validSource.CanValidlyConnectTo(validDestination))
{
validSource.ValidlyConnectTo(validDestination);
return false;
}
// Add the invalid ports to the units if need be
if (!sourceExists)
{
sourceUnit.invalidOutputs.Add(new InvalidOutput(sourceKey));
}
if (!destinationExists)
{
destinationUnit.invalidInputs.Add(new InvalidInput(destinationKey));
}
return true;
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f564c98f800f2453595d4c4e261215ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,151 @@
using System;
using UnityEngine;
namespace Unity.VisualScripting
{
/* Implementation note:
* Using an abstract base class works as a type unification workaround.
* https://stackoverflow.com/questions/22721763
* https://stackoverflow.com/a/7664919
*
* However, this forces us to use concrete classes for connections
* instead of interfaces. In other words, no IControlConnection / IValueConnection.
* If we did use interfaces, there would be ambiguity that needs to be resolved
* at every reference to the source or destination.
*
* However, using a disambiguator hack seems to confuse even recent Mono runtime versions of Unity
* and breaks its vtable. Sometimes, method pointers are just plain wrong.
* I'm guessing this is specifically due to InvalidConnection, which actually
* does unify the types; what the C# warning warned about.
* https://stackoverflow.com/q/50051657/154502
*
* THEREFORE, IUnitConnection has to be implemented at the concrete class level,
* because at that point the type unification warning is moot, because the type arguments are
* provided.
*/
public abstract class UnitConnection<TSourcePort, TDestinationPort> : GraphElement<FlowGraph>, IConnection<TSourcePort, TDestinationPort>
where TSourcePort : class, IUnitOutputPort
where TDestinationPort : class, IUnitInputPort
{
[Obsolete(Serialization.ConstructorWarning)]
protected UnitConnection() { }
protected UnitConnection(TSourcePort source, TDestinationPort destination)
{
Ensure.That(nameof(source)).IsNotNull(source);
Ensure.That(nameof(destination)).IsNotNull(destination);
if (source.unit.graph != destination.unit.graph)
{
throw new NotSupportedException("Cannot create connections across graphs.");
}
if (source.unit == destination.unit)
{
throw new InvalidConnectionException("Cannot create connections on the same unit.");
}
sourceUnit = source.unit;
sourceKey = source.key;
destinationUnit = destination.unit;
destinationKey = destination.key;
}
public virtual IGraphElementDebugData CreateDebugData()
{
return new UnitConnectionDebugData();
}
#region Ports
[Serialize]
protected IUnit sourceUnit { get; private set; }
[Serialize]
protected string sourceKey { get; private set; }
[Serialize]
protected IUnit destinationUnit { get; private set; }
[Serialize]
protected string destinationKey { get; private set; }
[DoNotSerialize]
public abstract TSourcePort source { get; }
[DoNotSerialize]
public abstract TDestinationPort destination { get; }
#endregion
#region Dependencies
public override int dependencyOrder => 1;
public abstract bool sourceExists { get; }
public abstract bool destinationExists { get; }
protected void CopyFrom(UnitConnection<TSourcePort, TDestinationPort> source)
{
base.CopyFrom(source);
}
public override bool HandleDependencies()
{
// Replace the connection with an invalid connection if the ports are either missing or incompatible.
// If the ports are missing, create invalid ports if required.
var valid = true;
IUnitOutputPort source;
IUnitInputPort destination;
if (!sourceExists)
{
if (!sourceUnit.invalidOutputs.Contains(sourceKey))
{
sourceUnit.invalidOutputs.Add(new InvalidOutput(sourceKey));
}
source = sourceUnit.invalidOutputs[sourceKey];
valid = false;
}
else
{
source = this.source;
}
if (!destinationExists)
{
if (!destinationUnit.invalidInputs.Contains(destinationKey))
{
destinationUnit.invalidInputs.Add(new InvalidInput(destinationKey));
}
destination = destinationUnit.invalidInputs[destinationKey];
valid = false;
}
else
{
destination = this.destination;
}
if (!source.CanValidlyConnectTo(destination))
{
valid = false;
}
if (!valid && source.CanInvalidlyConnectTo(destination))
{
source.InvalidlyConnectTo(destination);
Debug.LogWarning($"Could not load connection between '{source.key}' of '{sourceUnit}' and '{destination.key}' of '{destinationUnit}'.");
}
return valid;
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a8cc9b6e18b84c82a16ca1d5ae11643
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,13 @@
using System;
namespace Unity.VisualScripting
{
public class UnitConnectionDebugData : IUnitConnectionDebugData
{
public int lastInvokeFrame { get; set; }
public float lastInvokeTime { get; set; }
public Exception runtimeException { get; set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b33449365cf844e986fad5c887be657
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
using System;
namespace Unity.VisualScripting
{
public sealed class UnitRelation : IUnitRelation
{
public UnitRelation(IUnitPort source, IUnitPort destination)
{
Ensure.That(nameof(source)).IsNotNull(source);
Ensure.That(nameof(destination)).IsNotNull(destination);
if (source.unit != destination.unit)
{
throw new NotSupportedException("Cannot create relations across units.");
}
this.source = source;
this.destination = destination;
}
public IUnitPort source { get; }
public IUnitPort destination { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f3617e416d65b4e44842280c042df8a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,55 @@
using System;
namespace Unity.VisualScripting
{
public sealed class ValueConnection : UnitConnection<ValueOutput, ValueInput>, IUnitConnection
{
public class DebugData : UnitConnectionDebugData
{
public object lastValue { get; set; }
public bool assignedLastValue { get; set; }
}
public override IGraphElementDebugData CreateDebugData()
{
return new DebugData();
}
[Obsolete(Serialization.ConstructorWarning)]
public ValueConnection() : base() { }
public ValueConnection(ValueOutput source, ValueInput destination) : base(source, destination)
{
if (destination.hasValidConnection)
{
throw new InvalidConnectionException("Value input ports do not support multiple connections.");
}
if (!source.type.IsConvertibleTo(destination.type, false))
{
throw new InvalidConnectionException($"Cannot convert from '{source.type}' to '{destination.type}'.");
}
}
#region Ports
public override ValueOutput source => sourceUnit.valueOutputs[sourceKey];
public override ValueInput destination => destinationUnit.valueInputs[destinationKey];
IUnitOutputPort IConnection<IUnitOutputPort, IUnitInputPort>.source => source;
IUnitInputPort IConnection<IUnitOutputPort, IUnitInputPort>.destination => destination;
#endregion
#region Dependencies
public override bool sourceExists => sourceUnit.valueOutputs.Contains(sourceKey);
public override bool destinationExists => destinationUnit.valueInputs.Contains(destinationKey);
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b74709ab7c4674a84903b44120fcb9fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: