215 lines
7.1 KiB
C#
215 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Unity.VisualScripting
|
|
{
|
|
public sealed class UnitPreservation : IPoolable
|
|
{
|
|
private struct UnitPortPreservation
|
|
{
|
|
public readonly IUnit unit;
|
|
|
|
public readonly string key;
|
|
|
|
public UnitPortPreservation(IUnitPort port)
|
|
{
|
|
unit = port.unit;
|
|
key = port.key;
|
|
}
|
|
|
|
public UnitPortPreservation(IUnit unit, string key)
|
|
{
|
|
this.unit = unit;
|
|
this.key = key;
|
|
}
|
|
|
|
public IUnitPort GetOrCreateInput(out InvalidInput newInvalidInput)
|
|
{
|
|
var key = this.key;
|
|
|
|
if (!unit.inputs.Any(p => p.key == key))
|
|
{
|
|
newInvalidInput = new InvalidInput(key);
|
|
unit.invalidInputs.Add(newInvalidInput);
|
|
}
|
|
else
|
|
{
|
|
newInvalidInput = null;
|
|
}
|
|
|
|
return unit.inputs.Single(p => p.key == key);
|
|
}
|
|
|
|
public IUnitPort GetOrCreateOutput(out InvalidOutput newInvalidOutput)
|
|
{
|
|
var key = this.key;
|
|
|
|
if (!unit.outputs.Any(p => p.key == key))
|
|
{
|
|
newInvalidOutput = new InvalidOutput(key);
|
|
unit.invalidOutputs.Add(newInvalidOutput);
|
|
}
|
|
else
|
|
{
|
|
newInvalidOutput = null;
|
|
}
|
|
|
|
return unit.outputs.Single(p => p.key == key);
|
|
}
|
|
}
|
|
|
|
private readonly Dictionary<string, object> defaultValues = new Dictionary<string, object>();
|
|
|
|
private readonly Dictionary<string, List<UnitPortPreservation>> inputConnections = new Dictionary<string, List<UnitPortPreservation>>();
|
|
|
|
private readonly Dictionary<string, List<UnitPortPreservation>> outputConnections = new Dictionary<string, List<UnitPortPreservation>>();
|
|
|
|
private bool disposed;
|
|
|
|
void IPoolable.New()
|
|
{
|
|
disposed = false;
|
|
}
|
|
|
|
void IPoolable.Free()
|
|
{
|
|
disposed = true;
|
|
|
|
foreach (var inputConnection in inputConnections)
|
|
{
|
|
ListPool<UnitPortPreservation>.Free(inputConnection.Value);
|
|
}
|
|
|
|
foreach (var outputConnection in outputConnections)
|
|
{
|
|
ListPool<UnitPortPreservation>.Free(outputConnection.Value);
|
|
}
|
|
|
|
defaultValues.Clear();
|
|
inputConnections.Clear();
|
|
outputConnections.Clear();
|
|
}
|
|
|
|
private UnitPreservation() { }
|
|
|
|
public static UnitPreservation Preserve(IUnit unit)
|
|
{
|
|
var preservation = GenericPool<UnitPreservation>.New(() => new UnitPreservation());
|
|
|
|
foreach (var defaultValue in unit.defaultValues)
|
|
{
|
|
preservation.defaultValues.Add(defaultValue.Key, defaultValue.Value);
|
|
}
|
|
|
|
foreach (var input in unit.inputs)
|
|
{
|
|
if (input.hasAnyConnection)
|
|
{
|
|
preservation.inputConnections.Add(input.key, ListPool<UnitPortPreservation>.New());
|
|
|
|
foreach (var connectedPort in input.connectedPorts)
|
|
{
|
|
preservation.inputConnections[input.key].Add(new UnitPortPreservation(connectedPort));
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var output in unit.outputs)
|
|
{
|
|
if (output.hasAnyConnection)
|
|
{
|
|
preservation.outputConnections.Add(output.key, ListPool<UnitPortPreservation>.New());
|
|
|
|
foreach (var connectedPort in output.connectedPorts)
|
|
{
|
|
preservation.outputConnections[output.key].Add(new UnitPortPreservation(connectedPort));
|
|
}
|
|
}
|
|
}
|
|
|
|
return preservation;
|
|
}
|
|
|
|
public void RestoreTo(IUnit unit)
|
|
{
|
|
if (disposed)
|
|
{
|
|
throw new ObjectDisposedException(ToString());
|
|
}
|
|
|
|
// Restore inline values if possible
|
|
|
|
foreach (var previousDefaultValue in defaultValues)
|
|
{
|
|
if (unit.defaultValues.ContainsKey(previousDefaultValue.Key) &&
|
|
unit.valueInputs.Contains(previousDefaultValue.Key) &&
|
|
unit.valueInputs[previousDefaultValue.Key].type.IsAssignableFrom(previousDefaultValue.Value))
|
|
{
|
|
unit.defaultValues[previousDefaultValue.Key] = previousDefaultValue.Value;
|
|
}
|
|
}
|
|
|
|
// Restore connections if possible
|
|
|
|
foreach (var previousInputConnections in inputConnections)
|
|
{
|
|
var previousInputPort = new UnitPortPreservation(unit, previousInputConnections.Key);
|
|
var previousOutputPorts = previousInputConnections.Value;
|
|
|
|
foreach (var previousOutputPort in previousOutputPorts)
|
|
{
|
|
RestoreConnection(previousOutputPort, previousInputPort);
|
|
}
|
|
}
|
|
|
|
foreach (var previousOutputConnections in outputConnections)
|
|
{
|
|
var previousOutputPort = new UnitPortPreservation(unit, previousOutputConnections.Key);
|
|
var previousInputPorts = previousOutputConnections.Value;
|
|
|
|
foreach (var previousInputPort in previousInputPorts)
|
|
{
|
|
RestoreConnection(previousOutputPort, previousInputPort);
|
|
}
|
|
}
|
|
|
|
GenericPool<UnitPreservation>.Free(this);
|
|
}
|
|
|
|
private void RestoreConnection(UnitPortPreservation sourcePreservation, UnitPortPreservation destinationPreservation)
|
|
{
|
|
InvalidOutput newInvalidSource;
|
|
InvalidInput newInvalidDestination;
|
|
|
|
var source = sourcePreservation.GetOrCreateOutput(out newInvalidSource);
|
|
var destination = destinationPreservation.GetOrCreateInput(out newInvalidDestination);
|
|
|
|
if (source.CanValidlyConnectTo(destination))
|
|
{
|
|
source.ValidlyConnectTo(destination);
|
|
}
|
|
else if (source.CanInvalidlyConnectTo(destination))
|
|
{
|
|
source.InvalidlyConnectTo(destination);
|
|
}
|
|
else
|
|
{
|
|
// In this case, we created invalid ports to attempt a connection,
|
|
// but even that failed (due to, for example, a cross-graph restoration).
|
|
// Therefore, we need to delete the invalid ports we created.
|
|
|
|
if (newInvalidSource != null)
|
|
{
|
|
sourcePreservation.unit.invalidOutputs.Remove(newInvalidSource);
|
|
}
|
|
|
|
if (newInvalidDestination != null)
|
|
{
|
|
destinationPreservation.unit.invalidInputs.Remove(newInvalidDestination);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|