///---------------------------------------------------------------------------------------------- //avoid connecting from same source protected override bool CanConnectFromSource(Node sourceNode) { if (this.IsChildOf(sourceNode)) { Logger.LogWarning("States are already connected together. Consider using multiple conditions on an existing transition instead", "Editor", this); return(false); } return(true); }
//avoid connecting to same target protected override bool CanConnectToTarget(Node targetNode) { if (this.IsParentOf(targetNode)) { Logger.LogWarning("States are already connected together. Consider using multiple conditions on an existing transition instead", "Editor", this); return(false); } return(true); }
///Raise the OnMultipleChoiceRequest event public static void RequestMultipleChoices(MultipleChoiceRequestInfo info) { if (OnMultipleChoiceRequest != null) { OnMultipleChoiceRequest(info); } else { Logger.LogWarning("Multiple Choice Request event has no subscribers. Make sure to add the default '@DialogueGUI' prefab or create your own GUI.", "Dialogue Tree"); } }
///Invokes the function and callbacks when a Return node is hit. public void InvokeAsync(Flow f, FlowHandler Callback, params object[] args) { if (isInvoking) { Logger.LogWarning("Invoking a custom function which is already running is currently not supported.", "Execution", this); return; } this.args = args; isInvoking = true; f.PushReturnData((o) => { this.returnValue = o; isInvoking = false; Callback(f); }, returns.type); onInvoke.Call(f); }
///Set all target IDialogueActors at once by provided dictionary public void SetActorReferences(Dictionary <string, IDialogueActor> actors) { foreach (var pair in actors) { var param = actorParameters.Find(p => p.name == pair.Key); if (param == null) { Logger.LogWarning(string.Format("There is no defined Actor key name '{0}'. Seting actor skiped", pair.Key), "Dialogue Tree", this); continue; } param.actor = pair.Value; } }
///Trigger a state to enter by it's name. Returns the state found and entered if any public FSMState TriggerState(string stateName, TransitionCallMode callMode) { var state = GetStateWithName(stateName); if (state != null) { EnterState(state, callMode); return(state); } Logger.LogWarning("No State with name '" + stateName + "' found on FSM '" + name + "'", LogTag.EXECUTION, this); return(null); }
///the connection context menu GenericMenu GetConnectionMenu() { var menu = new GenericMenu(); menu.AddItem(new GUIContent(infoExpanded? "Collapse Info" : "Expand Info"), false, () => { infoExpanded = !infoExpanded; }); menu.AddItem(new GUIContent(isActive? "Disable" : "Enable"), false, () => { isActive = !isActive; }); var assignable = this as ITaskAssignable; if (assignable != null) { if (assignable.task != null) { menu.AddItem(new GUIContent("Copy Assigned Condition"), false, () => { CopyBuffer.Set <Task>(assignable.task); }); } else { menu.AddDisabledItem(new GUIContent("Copy Assigned Condition")); } if (CopyBuffer.Has <Task>()) { menu.AddItem(new GUIContent(string.Format("Paste Assigned Condition ({0})", CopyBuffer.Peek <Task>().name)), false, () => { if (assignable.task == CopyBuffer.Peek <Task>()) { return; } if (assignable.task != null) { if (!EditorUtility.DisplayDialog("Paste Condition", string.Format("Connection already has a Condition assigned '{0}'. Replace assigned condition with pasted condition '{1}'?", assignable.task.name, CopyBuffer.Peek <Task>().name), "YES", "NO")) { return; } } try { assignable.task = CopyBuffer.Get <Task>().Duplicate(graph); } catch { Logger.LogWarning("Can't paste Condition here. Incombatible Types.", "Editor", this); } }); } else { menu.AddDisabledItem(new GUIContent("Paste Assigned Condition")); } } menu.AddSeparator("/"); menu.AddItem(new GUIContent("Delete"), false, () => { graph.RemoveConnection(this); }); return(menu); }
///Invokes the function and return it's return value public object Invoke(Flow f, params object[] args) { if (isInvoking) { Logger.LogWarning("Invoking a custom function which is already running is currently not supported.", "Execution", this); return(null); } this.args = args; isInvoking = true; f.PushReturnData((o) => { this.returnValue = o; }, returns.type); isInvoking = false; onInvoke.Call(f); return(returnValue); }
///Enter a state providing the state itself public bool EnterState(FSMState newState, TransitionCallMode callMode) { if (!isRunning) { Logger.LogWarning("Tried to EnterState on an FSM that was not running", LogTag.EXECUTION, this); return(false); } if (newState == null) { Logger.LogWarning("Tried to Enter Null State", LogTag.EXECUTION, this); return(false); } if (currentState != null) { if (onStateExit != null) { onStateExit(currentState); } currentState.Reset(false); if (callMode == TransitionCallMode.Stacked) { stateStack.Push(currentState); if (stateStack.Count > 5) { Logger.LogWarning("State stack exceeds 5. Ensure that you are not cycling stack calls", LogTag.EXECUTION, this); } } } if (callMode == TransitionCallMode.Clean) { stateStack.Clear(); } previousState = currentState; currentState = newState; if (onStateTransition != null) { onStateTransition(currentState); } if (onStateEnter != null) { onStateEnter(currentState); } currentState.Execute(agent, blackboard); return(true); }
///Invokes the function and callbacks when a Return node is hit. public void InvokeAsync(Flow f, FlowHandler flowCallback, params object[] args) { if (isInvoking) { Logger.LogWarning("Invoking a Custom Function which is already running.", "Execution", this); } this.args = args; isInvoking = true; FlowReturn returnCallback = (o) => { this.returnValue = o; isInvoking = false; flowCallback(f); }; var invocationFlow = new Flow(); invocationFlow.SetReturnData(returnCallback, returns.type); onInvoke.Call(invocationFlow); }
///---------------------------------------------------------------------------------------------- protected override void OnNodeInspectorGUI() { if (GUILayout.Button("Call")) { if (Application.isPlaying) { //we do this only for the debugging to show, cause it doesn if we fire the port in here (OnGUI) but it works fine otherwise send = true; } else { Logger.LogWarning("Debug Flow Signal Event will only work in PlayMode", LogTag.EDITOR, this); } } }
protected override void RegisterPorts() { if (useReturnValue) { returnPort = AddValueInput <object>("Value"); } AddFlowInput(" ", (f) => { var returnData = f.PopReturnData(); if (returnData.returnCall == null) { Fail("The 'Return' node should be called as part of a Custom Function node."); return; } if (useReturnValue) { var returnValue = returnPort.value; if (returnData.returnType == null) { if (returnValue != null) { Logger.LogWarning("Function Returns a value, but no value is required", null, this); } returnData.returnCall(returnValue); return; } var returnType = returnValue != null? returnValue.GetType() : null; if ((returnType == null && returnData.returnType.RTIsValueType()) || (returnType != null && !returnData.returnType.RTIsAssignableFrom(returnType))) { Fail(string.Format("Return Value is not of expected type '{0}'.", returnData.returnType.FriendlyName())); return; } returnData.returnCall(returnValue); } else { returnData.returnCall(null); } }); }
///A IDictionary editor public static IDictionary DictionaryEditor(GUIContent content, IDictionary dict, Type dictType, InspectedFieldInfo info) { var keyType = dictType.RTGetGenericArguments()[0]; var valueType = dictType.RTGetGenericArguments()[1]; if (object.Equals(dict, null)) { GUILayout.Label("Null Dictionary"); return(dict); } if (!CachedFoldout(dictType, content)) { return(dict); } GUILayout.BeginVertical(); var keys = dict.Keys.Cast <object>().ToList(); var values = dict.Values.Cast <object>().ToList(); if (GUILayout.Button("Add Element")) { if (!typeof(UnityObject).IsAssignableFrom(keyType)) { object newKey = null; if (keyType == typeof(string)) { newKey = string.Empty; } else { newKey = Activator.CreateInstance(keyType); } if (dict.Contains(newKey)) { Logger.LogWarning(string.Format("Key '{0}' already exists in Dictionary", newKey.ToString()), "Editor"); return(dict); } keys.Add(newKey); } else { Logger.LogWarning("Can't add a 'null' Dictionary Key", "Editor"); return(dict); } values.Add(valueType.IsValueType ? Activator.CreateInstance(valueType) : null); } //clear before reconstruct dict.Clear(); for (var i = 0; i < keys.Count; i++) { GUILayout.BeginHorizontal("box"); GUILayout.Box("", GUILayout.Width(6), GUILayout.Height(35)); GUILayout.BeginVertical(); keys[i] = ReflectedFieldInspector("K:", keys[i], keyType, info); values[i] = ReflectedFieldInspector("V:", values[i], valueType, info); GUILayout.EndVertical(); if (GUILayout.Button("X", GUILayout.Width(18), GUILayout.Height(34))) { keys.RemoveAt(i); values.RemoveAt(i); } GUILayout.EndHorizontal(); try { dict.Add(keys[i], values[i]); } catch { Logger.Log("Dictionary Key removed due to duplicate found", "Editor"); } } Separator(); GUILayout.EndVertical(); return(dict); }
sealed protected override void DrawNodeConnections(Rect drawCanvas, bool fullDrawPass, Vector2 canvasMousePos, float zoomFactor) { var e = Event.current; //Receive connections first if (clickedPort != null && e.type == EventType.MouseUp && e.button == 0) { if (rect.Contains(e.mousePosition)) { foreach (FSMConnection connection in inConnections) { if (connection.sourceNode == clickedPort.parent) { Logger.LogWarning("State is already connected to target state. Consider using multiple conditions on an existing transition instead", "Editor", this); clickedPort = null; e.Use(); return; } } graph.ConnectNodes(clickedPort.parent, this); clickedPort = null; e.Use(); } else { dragDropMisses++; if (dragDropMisses == graph.allNodes.Count && clickedPort != null) { var source = clickedPort.parent; var pos = Event.current.mousePosition; var menu = new GenericMenu(); clickedPort = null; menu.AddItem(new GUIContent("Add Action State"), false, () => { var newState = graph.AddNode <ActionState>(pos); graph.ConnectNodes(source, newState); }); //PostGUI cause of zoom factors GraphEditorUtility.PostGUI += () => { menu.ShowAsContext(); }; Event.current.Use(); e.Use(); } } } var portRectLeft = new Rect(0, 0, 20, 20); var portRectRight = new Rect(0, 0, 20, 20); var portRectBottom = new Rect(0, 0, 20, 20); portRectLeft.center = new Vector2(rect.x - 11, rect.center.y); portRectRight.center = new Vector2(rect.xMax + 11, rect.center.y); portRectBottom.center = new Vector2(rect.center.x, rect.yMax + 11); if (maxOutConnections != 0) { if (fullDrawPass || drawCanvas.Overlaps(rect)) { EditorGUIUtility.AddCursorRect(portRectLeft, MouseCursor.ArrowPlus); EditorGUIUtility.AddCursorRect(portRectRight, MouseCursor.ArrowPlus); EditorGUIUtility.AddCursorRect(portRectBottom, MouseCursor.ArrowPlus); GUI.color = new Color(1, 1, 1, 0.3f); GUI.Box(portRectLeft, string.Empty, CanvasStyles.arrowLeft); GUI.Box(portRectRight, string.Empty, CanvasStyles.arrowRight); if (maxInConnections == 0) { GUI.Box(portRectBottom, string.Empty, CanvasStyles.arrowBottom); } GUI.color = Color.white; if (GraphEditorUtility.allowClick && e.type == EventType.MouseDown && e.button == 0) { if (portRectLeft.Contains(e.mousePosition)) { clickedPort = new GUIPort(this, portRectLeft.center); dragDropMisses = 0; e.Use(); } if (portRectRight.Contains(e.mousePosition)) { clickedPort = new GUIPort(this, portRectRight.center); dragDropMisses = 0; e.Use(); } if (maxInConnections == 0 && portRectBottom.Contains(e.mousePosition)) { clickedPort = new GUIPort(this, portRectBottom.center); dragDropMisses = 0; e.Use(); } } } } if (clickedPort != null && clickedPort.parent == this) { Handles.DrawBezier(clickedPort.pos, e.mousePosition, clickedPort.pos, e.mousePosition, new Color(0.5f, 0.5f, 0.8f, 0.8f), null, 2); } for (var i = 0; i < outConnections.Count; i++) { var connection = outConnections[i] as FSMConnection; var targetState = connection.targetNode as FSMState; if (targetState == null) //In case of MissingNode type { continue; } var targetPos = targetState.GetConnectedInPortPosition(connection); var sourcePos = Vector2.zero; if (rect.center.x <= targetPos.x) { sourcePos = portRectRight.center; } if (rect.center.x > targetPos.x) { sourcePos = portRectLeft.center; } if (maxInConnections == 0 && rect.center.y < targetPos.y - 50 && Mathf.Abs(rect.center.x - targetPos.x) < 200) { sourcePos = portRectBottom.center; } var boundRect = RectUtils.GetBoundRect(sourcePos, targetPos); if (fullDrawPass || drawCanvas.Overlaps(boundRect)) { connection.DrawConnectionGUI(sourcePos, targetPos); } } }