// ---------------------------------------------------------------------- public void RebuildStateConnection(iCS_EditorObject fromStatePort, iCS_EditorObject toStatePort) { if (fromStatePort == null || toStatePort == null) { return; } var commonParent = GraphInfo.GetCommonParent(fromStatePort, toStatePort); if (commonParent == null) { Debug.LogWarning("iCanScript: Unable to find common parent after relocating state !!!"); return; } var transitionPackage = GetTransitionPackage(toStatePort); if (transitionPackage == null) { return; } if (transitionPackage.ParentNode == commonParent) { return; } ChangeParent(transitionPackage, commonParent); LayoutTransitionPackage(transitionPackage); }
// =================================================================== // EDITOR ENTRY POINT // ------------------------------------------------------------------- /// Port specific information. public void OnGUI() { // -- Display port name. -- EditName("Port Name"); // -- Edit the value of the port. -- EditPortValue(); // -- Edit port specification. -- var variableType = ConvertEnum(vsObject.PortSpec, GraphInfo.GetAllowedPortSpecification(vsObject)); variableType = EditorGUILayout.EnumPopup("Variable Specification", variableType); SetPortSpec(ConvertEnum(variableType, PortSpecification.Default)); // -- Show port type. -- var portValue = vsObject.Value; if (portValue != null) { EditorGUILayout.LabelField("Variable Type", iCS_Types.TypeName(portValue.GetType())); } // -- Show port index. -- EditorGUILayout.IntField("Parameter Index", vsObject.PortIndex); // -- Edit port description. -- EditDescription(); }
// =================================================================== /// Returns the allowed types of variable the given port can support. /// /// @param port The port used to filter the types of variable. /// @return The filtered port specification. /// public static Enum GetAllowedPortSpecification(iCS_EditorObject port) { var producerPort = GetProducerPort(port); if (MustBeATypeVariable(producerPort)) { return(TypeVariables.PublicVariable); } if (MustBeAParameter(producerPort)) { return(ParameterVariable.Parameter); } if (producerPort.IsInDataOrControlPort) { var isFunctionDefinition = producerPort.ParentNode.IsFunctionDefinition; var runtimeType = producerPort.RuntimeType; if (iCS_Types.IsA <UnityEngine.Object>(runtimeType)) { if (runtimeType == typeof(GameObject) || runtimeType == typeof(Transform)) { if (isFunctionDefinition) { return(InFunctionDefinitionOwnerAndUnityObjectVariableType.PublicVariable); } return(InOwnerAndUnityObjectVariableType.PublicVariable); } else { if (isFunctionDefinition) { return(InFunctionDefinitionUnityObjectVariableType.PublicVariable); } if (GraphInfo.IsLocalType(producerPort)) { return(InOwnerAndUnityObjectVariableType.Owner); } return(InUnityObjectVariableType.PublicVariable); } } else { if (isFunctionDefinition) { return(InFunctionDefinitionVariableType.PublicVariable); } if (GraphInfo.IsLocalType(producerPort)) { return(InTypeVariableWithOwner.Owner); } return(InVariableType.PublicVariable); } } else if (producerPort.IsOutDataOrControlPort) { return(OutVariableType.PublicVariable); } return(TypeVariables.PublicVariable); }
// ------------------------------------------------------------------------- iCS_EditorObject[] FilterMultiSelectionUnderSameParent() { var multiSelectedObjects = GetMultiSelectedObjects(); if (multiSelectedObjects == null || multiSelectedObjects.Length == 0) { Debug.LogWarning("No selected object found!!!"); return(null); } // Find common parent. if (multiSelectedObjects.Length == 1) { return(multiSelectedObjects); } var commonParent = GraphInfo.GetCommonParent(multiSelectedObjects); // Special case for when the common parent is one of the selected objects. List <iCS_EditorObject> valid = new List <iCS_EditorObject>(); foreach (var obj in multiSelectedObjects) { if (obj == commonParent) { valid.Add(obj); } } if (valid.Count != 0) { return(valid.ToArray()); } // Find the proper node just below common parent. foreach (var o in multiSelectedObjects) { var obj = o; while (obj.ParentNode != null && obj.ParentNode != commonParent) { obj = obj.ParentNode; } if (obj.ParentNode == commonParent) { valid.Add(obj); } } /* * TODO : Filter for uniqu entries. */ return(valid.ToArray()); }
// ------------------------------------------------------------------------- /// Determines if the enable port is always _true_. /// /// @param enablePort The enable port. /// @return _true_ if the enable is always true. _false_ otherwise. /// public static bool IsEnableAlwaysTrue(iCS_EditorObject enablePort) { var producerPort = GraphInfo.GetProducerPort(enablePort); if (producerPort.IsInputPort) { var initialValue = producerPort.Value; if (initialValue is UndefinedTag) { return(false); } var value = (bool)initialValue; return(value == true); } return(false); }
// =================================================================== /// Sets the port specififcation. /// /// @param vsObject An object that is part of the connection. /// @param portSpec The new port specification. /// public static void SetPortSpec(iCS_EditorObject vsObject, PortSpecification portSpec) { var allConnectedPorts = GraphInfo.GetAllConnectedPorts(vsObject); foreach (var p in allConnectedPorts) { if (p.IsEnablePort) { p.PortSpec = PortSpecification.Enable; } else { p.PortSpec = portSpec; } AdjustPortIndexes(p.ParentNode); } }
// ====================================================================== /// Sets the default port specification for the given port. /// /// @param p The port on which to set the default port specification. /// public static void SetDefaultPortSpec(iCS_EditorObject p) { // -- Setup spec for control ports. -- var parentNode = p.ParentNode; var producerPort = GraphInfo.GetProducerPort(p); // -- Only valid for the producer port. -- if (producerPort != p) { return; } // -- Determine default port spec. -- if (parentNode.IsFunctionDefinition) { if (p.IsInDataOrControlPort) { GraphEditor.SetPortSpec(p, PortSpecification.Parameter); } } else if (parentNode.IsEventHandler) { if (p.IsFixDataPort) { GraphEditor.SetPortSpec(p, PortSpecification.Parameter); } else { GraphEditor.SetPortSpec(p, PortSpecification.PublicVariable); } } else if (parentNode.IsVariableDefinition) { if (p.IsOutDataOrControlPort) { GraphEditor.SetPortSpec(p, PortSpecification.PublicVariable); } else if (p.IsInDataOrControlPort) { GraphEditor.SetPortSpec(p, PortSpecification.Constant); } } else if (parentNode.IsConstructor) { if (p.IsInDataOrControlPort) { GraphEditor.SetPortSpec(p, PortSpecification.Constant); } else if (p.IsOutDataOrControlPort) { // -- Determine if this is a local variable of not. -- bool isLocal = false; parentNode.ForEachChildPort( cp => { if (cp.IsInDataOrControlPort) { if (cp.ProducerPort != null) { isLocal = true; } } } ); if (isLocal) { GraphEditor.SetPortSpec(p, PortSpecification.LocalVariable); } else { GraphEditor.SetPortSpec(p, PortSpecification.PublicVariable); } } } // TODO: Needs to be verified... else if (parentNode.IsKindOfFunction) { if (p.IsInDataOrControlPort) { var initialValue = p.Value; if (initialValue != null) { GraphEditor.SetPortSpec(p, PortSpecification.Constant); } else { var runtimeType = p.RuntimeType; if (p.IsTargetPort && (runtimeType == typeof(GameObject) || runtimeType == typeof(Transform) || GraphInfo.IsLocalType(p))) { GraphEditor.SetPortSpec(p, PortSpecification.Owner); p.Value = null; } else { GraphEditor.SetPortSpec(p, PortSpecification.PublicVariable); } } } else if (p.IsOutDataOrControlPort) { if (GraphInfo.MustBeATypeVariable(p)) { GraphEditor.SetPortSpec(p, PortSpecification.PrivateVariable); } else { GraphEditor.SetPortSpec(p, PortSpecification.LocalVariable); } } } else if (parentNode.IsInstanceNode) { if (p.IsInDataOrControlPort) { var runtimeType = p.RuntimeType; if (p.IsTargetPort && (runtimeType == typeof(GameObject) || runtimeType == typeof(Transform) || GraphInfo.IsLocalType(p))) { GraphEditor.SetPortSpec(p, PortSpecification.Owner); p.Value = null; } else { GraphEditor.SetPortSpec(p, PortSpecification.PublicVariable); } } } else if (parentNode.IsKindOfPackage) { if (p.IsInDataOrControlPort) { GraphEditor.SetPortSpec(p, PortSpecification.PublicVariable); } } else { GraphEditor.SetPortSpec(p, PortSpecification.LocalVariable); } }
// =================================================================== /// Refreshes the port specififcation of a connection. /// /// @param vsObject An object that is part of the connection. /// public static void RefreshPortSpec(iCS_EditorObject vsObject) { var producerPort = GraphInfo.GetProducerPort(vsObject); SetPortSpec(producerPort, producerPort.PortSpec); }
// ---------------------------------------------------------------------- void RebuildDataConnection(iCS_EditorObject outputPort, iCS_EditorObject inputPort) { #if DEBUG Debug.Log("iCanScript: RebuildDataConnection: output= " + outputPort.DisplayName + " input= " + inputPort.DisplayName); #endif // Have we completed rebuilding ... if so return. if (inputPort == outputPort) { return; } var inputNode = inputPort.ParentNode; var outputNode = outputPort.ParentNode; if (inputNode == outputNode) { return; } // outputPort is inside the node with the inputPort. var commonParentNode = GraphInfo.GetCommonParent(outputPort, inputPort); if (inputNode == commonParentNode) { // Rebuild moving down from the common parent towards the output port. var newInputNode = outputPort.ParentNode; while (newInputNode != inputNode && newInputNode.ParentNode != inputNode) { newInputNode = newInputNode.ParentNode; } var existingPort = IStorage.FindPortWithSourceEndPoint(newInputNode, outputPort); if (existingPort != null) { var prevSource = inputPort.ProducerPort; if (prevSource != existingPort) { inputPort.ProducerPort = existingPort; if (prevSource.IsDynamicDataPort && !inputPort.IsPartOfConnection(prevSource)) { IStorage.CleanupHangingConnection(prevSource); } } RebuildDataConnection(outputPort, existingPort); } else { iCS_EditorObject newPort = IStorage.CreatePort(inputPort.DisplayName, newInputNode.InstanceId, inputPort.RuntimeType, VSObjectType.OutDynamicDataPort); IStorage.SetBestPositionForAutocreatedPort(newPort, outputPort.GlobalPosition, inputPort.GlobalPosition); newPort.ProducerPort = inputPort.ProducerPort; inputPort.ProducerPort = newPort; RebuildDataConnection(outputPort, newPort); } return; } var inputNodeParent = inputNode.ParentNode; if (inputNodeParent == commonParentNode) { // Rebuild traversing from moving upwards to downwords. var newDstNode = outputPort.ParentNode; while (newDstNode != commonParentNode && newDstNode.ParentNode != commonParentNode) { newDstNode = newDstNode.ParentNode; } var existingPort = IStorage.FindPortWithSourceEndPoint(newDstNode, outputPort); if (existingPort != null) { var prevSource = inputPort.ProducerPort; if (prevSource != existingPort) { inputPort.ProducerPort = existingPort; if (prevSource.IsDynamicDataPort && !inputPort.IsPartOfConnection(prevSource)) { IStorage.CleanupHangingConnection(prevSource); } } RebuildDataConnection(outputPort, existingPort); } else { iCS_EditorObject newPort = IStorage.CreatePort(inputPort.DisplayName, newDstNode.InstanceId, inputPort.RuntimeType, VSObjectType.OutDynamicDataPort); IStorage.SetBestPositionForAutocreatedPort(newPort, outputPort.GlobalPosition, inputPort.GlobalPosition); newPort.ProducerPort = inputPort.ProducerPort; inputPort.ProducerPort = newPort; RebuildDataConnection(outputPort, newPort); } return; } else { // Rebuilding moving up from the consumer port towards the common parent. var existingPort = IStorage.FindPortWithSourceEndPoint(inputNodeParent, outputPort); if (existingPort != null) { var prevSource = inputPort.ProducerPort; if (prevSource != existingPort) { inputPort.ProducerPort = existingPort; if (prevSource.IsDynamicDataPort && !inputPort.IsPartOfConnection(prevSource)) { IStorage.CleanupHangingConnection(prevSource); } } RebuildDataConnection(outputPort, existingPort); } else { iCS_EditorObject newPort = IStorage.CreatePort(inputPort.DisplayName, inputNodeParent.InstanceId, inputPort.RuntimeType, VSObjectType.InDynamicDataPort); IStorage.SetBestPositionForAutocreatedPort(newPort, outputPort.GlobalPosition, inputPort.GlobalPosition); newPort.ProducerPort = inputPort.ProducerPort; inputPort.ProducerPort = newPort; RebuildDataConnection(outputPort, newPort); } } }
// ---------------------------------------------------------------------- // Builds a list of parent nodes. The list is sorted from the top most // parent to the bottom most leaf. public iCS_EditorObject[] BuildListOfParentNodes() { return(GraphInfo.BuildListOfParentNodes(this)); }
// ---------------------------------------------------------------------- /// Performs a snaity check on the visual script object. /// /// @param serviceKey The service key to use when registering with the /// error controller. /// @return _true_ is return if object is sane. _false_ otherwise. /// public bool SanityCheck(string serviceKey) { var visualScript = IStorage.VisualScript; // Verify that the runtime portion still exists. if (IsKindOfFunction) { var runtimeType = RuntimeType; var memberInfo = runtimeType != null?LibraryController.LibraryDatabase.GetLibraryType(runtimeType) : null; if (memberInfo == null && !GraphInfo.IsLocalType(this)) { var message = "Unable to find the runtime code for " + FullName; ErrorController.AddError(serviceKey, message, visualScript, InstanceId); return(false); } } if (IsTargetPort) { if (ProducerPort == null || ProducerPort == this) { var parentNode = ParentNode; if (parentNode.IsKindOfFunction) { if (!IsOwner && !IsTypeVariable) { var message = "<color=red><b>Value</b></color> for <b>Target</b> port is not valid for node: <b>" + FullName + "</b>"; ErrorController.AddError(serviceKey, message, visualScript, InstanceId); return(false); } else { if (parentNode.IsFunction("get_transform", "GameObject", "UnityEngine")) { var message = "When <b>'Target'</b> is set to <b>'Owner'</b>, the generated code has no effect. The node can be removed safely: <b>" + ParentNode.FullName + "</b>"; ErrorController.AddWarning(serviceKey, message, visualScript, ParentNode.InstanceId); } } } } } if (IsEnablePort) { var producerPort = SegmentProducerPort; if (producerPort != this) { // -- Verify for unnecessary OR function -- var producerNode = producerPort.ParentNode; if (producerNode.IsFunction("Or", "iCS_Boolean", "")) { if (producerPort.SegmentEndConsumerPorts.Length <= 1) { var message = "Consider using additional 'Enable(s)' ports instead of an OR function. => " + producerNode.FullName; ErrorController.AddWarning(serviceKey, message, visualScript, producerNode.InstanceId); ErrorController.AddWarning(serviceKey, message, visualScript, producerNode.InstanceId); } } // -- Verify for unnecessary trigger->enble binding when // data flow already exist -- var parentNode = ParentNode; if (producerPort.IsTriggerPort && producerNode.IsKindOfFunction && parentNode.IsKindOfFunction) { bool doesDataFlowExist = false; parentNode.ForEachChildPort( p => { if (p.IsInDataPort) { var pp = p.SegmentProducerPort; if (pp.ParentNode == producerNode) { doesDataFlowExist = true; } } } ); if (doesDataFlowExist) { var message = "<b>Trigger</b> to <b>Enable</b> connection not needed since data flow already exist between nodes. Consider removing the control flow."; ErrorController.AddWarning(serviceKey, message, visualScript, InstanceId); ErrorController.AddWarning(serviceKey, message, visualScript, producerPort.InstanceId); } // -- Determine if self to target connection should be used for // sequencing operation on same object. var producerNodeTargetPort = producerNode.TargetPort; var parentNodeTargetPort = parentNode.TargetPort; if (producerNodeTargetPort != null && parentNodeTargetPort != null) { var targetProducerPort = parentNodeTargetPort.SegmentProducerPort; if (producerNodeTargetPort.SegmentProducerPort == targetProducerPort) { var targetProducerNode = targetProducerPort.ParentNode; var producerNodeSelfPort = producerNode.SelfPort; var message = "Consider connecting the <b>Self</b> port of '<b>" + producerNode.DisplayName + "</b>' to the <b>Target</b> port of '<b>" + parentNode.DisplayName + "</b> to sequence operations on <b>" + targetProducerNode.DisplayName + "</b>."; ErrorController.AddWarning(serviceKey, message, visualScript, parentNodeTargetPort.InstanceId); ErrorController.AddWarning(serviceKey, message, visualScript, producerNodeSelfPort.InstanceId); } } } } } return(true); }