예제 #1
0
        ///----------------------------------------------------------------------------------------------

        ///Add a listener to several messages
        public void Register(object target, params string[] messages)
        {
            if (target == null)
            {
                return;
            }

            for (var i = 0; i < messages.Length; i++)
            {
                var method = target.GetType().GetMethod(messages[i], METHOD_FLAGS);
                if (method == null)
                {
                    Logger.LogError(string.Format("Type '{0}' does not implement a method named '{1}', for the registered event to use.", target.GetType().FriendlyName(), messages[i]), "Events", target);
                    continue;
                }

                List <object> targetObjects = null;
                if (!listeners.TryGetValue(messages[i], out targetObjects))
                {
                    targetObjects          = new List <object>();
                    listeners[messages[i]] = targetObjects;
                }

                if (!targetObjects.Contains(target))
                {
                    targetObjects.Add(target);
                }
            }
        }
예제 #2
0
        ///<summary>Duplicate the connection providing a new source and target</summary>
        public Connection Duplicate(Node newSource, Node newTarget)
        {
            if (newSource == null || newTarget == null)
            {
                Logger.LogError("Can't Duplicate a Connection without providing NewSource and NewTarget Nodes");
                return(null);
            }

            //deep clone
            var newConnection = JSONSerializer.Clone <Connection>(this);

            UndoUtility.RecordObject(newSource.graph, "Duplicate Connection");

            newConnection._UID       = null;
            newConnection.sourceNode = newSource;
            newConnection.targetNode = newTarget;
            newSource.outConnections.Add(newConnection);
            newTarget.inConnections.Add(newConnection);

            if (newSource.graph != null)
            {
                foreach (var task in Graph.GetTasksInElement(newConnection))
                {
                    task.Validate(newSource.graph);
                }
            }
            //--

            newConnection.OnValidate(newSource.outConnections.Count - 1, newTarget.inConnections.Count - 1);
            UndoUtility.SetDirty(newSource.graph);
            return(newConnection);
        }
예제 #3
0
        ///Resolves and gets an actor based on the key name
        public IDialogueActor GetActorReferenceByName(string paramName)
        {
            //Check for INSTIGATOR selection
            if (paramName == INSTIGATOR_NAME)
            {
                //return it directly if it implements IDialogueActor
                if (agent is IDialogueActor)
                {
                    return((IDialogueActor)agent);
                }

                //Otherwise use the default actor and set name and transform from agent
                if (agent != null)
                {
                    return(new ProxyDialogueActor(agent.gameObject.name, agent.transform));
                }

                return(new ProxyDialogueActor("Null Instigator", null));
            }

            //Check for non INSTIGATOR selection. If there IS an actor reference return it
            var refData = actorParameters.Find(r => r.name == paramName);

            if (refData != null && refData.actor != null)
            {
                return(refData.actor);
            }

            //Otherwise use the default actor and set the name to the key and null transform
            Logger.Log(string.Format("An actor entry '{0}' on DialogueTree has no reference. A dummy Actor will be used with the entry Key for name", paramName), "Dialogue Tree", this);
            return(new ProxyDialogueActor(paramName, null));
        }
예제 #4
0
        ///<summary>Create a new Connection. Use this for constructor</summary>
        public static Connection Create(Node source, Node target, int sourceIndex = -1, int targetIndex = -1)
        {
            if (source == null || target == null)
            {
                Logger.LogError("Can't Create a Connection without providing Source and Target Nodes");
                return(null);
            }

            if (source is MissingNode)
            {
                Logger.LogError("Creating new Connections from a 'MissingNode' is not allowed. Please resolve the MissingNode node first");
                return(null);
            }

            var newConnection = (Connection)System.Activator.CreateInstance(source.outConnectionType);

            UndoUtility.RecordObject(source.graph, "Create Connection");

            var resultSourceIndex = newConnection.SetSourceNode(source, sourceIndex);
            var resultTargetIndex = newConnection.SetTargetNode(target, targetIndex);

            newConnection.OnValidate(resultSourceIndex, resultTargetIndex);
            newConnection.OnCreate(resultSourceIndex, resultTargetIndex);
            UndoUtility.SetDirty(source.graph);

            return(newConnection);
        }
예제 #5
0
        //Create and set a UnityObject variable node on drop
        protected override void OnDropAccepted(Object o, Vector2 mousePos)
        {
            if (o == null)
            {
                return;
            }

            if (UnityEditor.EditorUtility.IsPersistent(this) && !UnityEditor.EditorUtility.IsPersistent(o))
            {
                Logger.Log("This Graph is an asset. The dragged object is a scene reference. The reference will not persist!", LogTag.EDITOR);
            }

            var targetType = o.GetType();
            var menu       = new UnityEditor.GenericMenu();

            menu = AppendDragAndDropObjectMenu(menu, o, "", mousePos);
            menu.AddSeparator("/");
            menu = this.AppendTypeReflectionNodesMenu(menu, targetType, "", mousePos, null, o);
            if (o is GameObject)
            {
                foreach (var component in (o as GameObject).GetComponents <Component>().Where(c => c.hideFlags == 0))
                {
                    var cType = component.GetType();
                    menu = AppendDragAndDropObjectMenu(menu, component, cType.Name + "/", mousePos);
                    menu = this.AppendTypeReflectionNodesMenu(menu, cType, "", mousePos, null, component);
                }
            }

            menu.ShowAsBrowser("Add Node For Drag & Drop Instance");
            Event.current.Use();
        }
예제 #6
0
        //...
        protected override void OnValidate()
        {
            base.OnValidate();

#if UNITY_EDITOR
            if (UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null)
            {
                return;
            }
#endif

            if (Application.isPlaying || IsPrefabAsset())
            {
                return;
            }
            if (!_allGlobals.Contains(this))
            {
                _allGlobals.Add(this);
            }
            if (string.IsNullOrEmpty(_identifier))
            {
                _identifier = gameObject.name;
            }
            var existing = Find(identifier);
            if (existing != this && existing != null)
            {
                Logger.LogError(string.Format("Another blackboard with the same identifier name '{0}' exists. Please rename either.", identifier), LogTag.BLACKBOARD, this);
            }
        }
예제 #7
0
        protected override void RegisterPorts()
        {
            var returnPort = AddValueInput <object>("Value");

            AddFlowInput(" ", (f) =>
            {
#if UNITY_EDITOR
                if (f.Return == null)
                {
                    Fail("The 'Return' node should be called as part of a Custom Function node.");
                    return;
                }
                var returnValue = returnPort.value;
                var returnType  = returnValue != null? returnValue.GetType() : null;
                if (f.ReturnType != null && !f.ReturnType.RTIsAssignableFrom(returnType))
                {
                    Fail(string.Format("Return Value is not of expected type '{0}'.", f.ReturnType.FriendlyName()));
                    return;
                }

                if (f.ReturnType == null && returnValue != null)
                {
                    Logger.LogWarning("Function Returns a value, but no value is required", null, this);
                }
#endif

                f.Return(returnPort.value);
            });
        }
예제 #8
0
 //...
 protected void OnEnable()
 {
     if (IsPrefabAsset())
     {
         return;
     }
     if (string.IsNullOrEmpty(_identifier))
     {
         _identifier = gameObject.name;
     }
     if (Application.isPlaying)
     {
         if (Find(identifier) != null)
         {
             Logger.Log(string.Format("There exist more than one Global Blackboards with same identifier name '{0}'. The old one will now be destroyed.", identifier), LogTag.BLACKBOARD, this);
             if (_singletonMode == SingletonMode.DestroyComponentOnly)
             {
                 Destroy(this);
             }
             if (_singletonMode == SingletonMode.DestroyEntireGameObject)
             {
                 Destroy(this.gameObject);
             }
             return;
         }
         if (_dontDestroyOnLoad)
         {
             DontDestroyOnLoad(this.gameObject);
         }
     }
     if (!_allGlobals.Contains(this))
     {
         _allGlobals.Add(this);
     }
 }
예제 #9
0
        protected override void RegisterPorts()
        {
            var 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;
                }

                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);
            });
        }
예제 #10
0
        void OnEnable()
        {
            current = this;
            var canvasIcon = (Texture)Resources.Load("CanvasIcon");

            titleContent = new GUIContent("Canvas", canvasIcon);

            willRepaint    = true;
            fullDrawPass   = true;
            wantsMouseMove = true;
            guiSkin        = (GUISkin)Resources.Load(EditorGUIUtility.isProSkin? "NodeCanvasSkin" : "NodeCanvasSkinLight");
            minSize        = new Vector2(700, 300);

                        #if UNITY_2017_2_OR_NEWER
            EditorApplication.playModeStateChanged -= PlayModeChange;
            EditorApplication.playModeStateChanged += PlayModeChange;
                        #else
            EditorApplication.playmodeStateChanged -= PlayModeChange;
            EditorApplication.playmodeStateChanged += PlayModeChange;
                        #endif
            Selection.selectionChanged -= OnSelectionChange;
            Selection.selectionChanged += OnSelectionChange;
            Logger.RemoveListener(OnLogMessageReceived);
            Logger.AddListener(OnLogMessageReceived);
        }
예제 #11
0
 protected override void OnGraphPaused()
 {
     Logger.Log(string.Format("Dialogue Paused '{0}'", this.name), "Dialogue Tree", this);
     if (OnDialoguePaused != null)
     {
         OnDialoguePaused(this);
     }
 }
예제 #12
0
 void OnCustomEvent(string eventName, IEventData data)
 {
     if (eventName.Equals(this.eventName.value, System.StringComparison.OrdinalIgnoreCase))
     {
         Logger.Log(string.Format("Event Received from ({0}): '{1}'", agent.gameObject.name, name), LogTag.EVENT, this);
         YieldReturn(true);
     }
 }
예제 #13
0
        ///----------------------------------------------------------------------------------------------

        //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);
        }
예제 #14
0
 //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);
 }
예제 #15
0
        ///Set the target IDialogueActor for the provided key parameter name
        public void SetActorReference(string paramName, IDialogueActor actor)
        {
            var param = actorParameters.Find(p => p.name == paramName);

            if (param == null)
            {
                Logger.LogError(string.Format("There is no defined Actor key name '{0}'", paramName), "Dialogue Tree", this);
                return;
            }
            param.actor = actor;
        }
예제 #16
0
 ///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");
     }
 }
예제 #17
0
        protected override void OnGraphUnpaused()
        {
            currentNode = currentNode != null ? currentNode : (DTNode)primeNode;
            EnterNode(currentNode);

            Logger.Log(string.Format("Dialogue Resumed '{0}'", this.name), "Dialogue Tree", this);
            if (OnDialogueStarted != null)
            {
                OnDialogueStarted(this);
            }
        }
예제 #18
0
 void OnCustomEvent(string eventName, ParadoxNotion.IEventData msg)
 {
     if (eventName.Equals(this.eventName.value, System.StringComparison.OrdinalIgnoreCase))
     {
         var senderGraph = Graph.GetElementGraph(msg.sender);
         this.sender   = senderGraph != null ? senderGraph.agent as GraphOwner : null;
         this.receiver = ResolveReceiver(msg.receiver);
         Logger.Log(string.Format("Event Received from ({0}): '{1}'", receiver.name, eventName), LogTag.EVENT, this);
         onReceived.Call(new Flow());
     }
 }
예제 #19
0
 ///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);
 }
예제 #20
0
 void IUpdatable.Update()
 {
     if (send)
     {
         send = false;
         var sw = new Stopwatch();
         sw.Start();
         o.Call(new Flow());
         sw.Stop();
         Logger.Log(string.Format("Debug Event Elapsed Time: {0} ms.", sw.ElapsedMilliseconds), LogTag.EDITOR, this);
     }
 }
 void OnCustomEvent(string eventName, ParadoxNotion.IEventData msg)
 {
     if (eventName.Equals(this.eventName.value, System.StringComparison.OrdinalIgnoreCase))
     {
         var receivedValue = msg.valueBoxed;
         if (ObjectUtils.AnyEquals(receivedValue, value.value))
         {
             Logger.Log(string.Format("Event Received from ({0}): '{1}'", agent.gameObject.name, eventName), LogTag.EVENT, this);
             YieldReturn(true);
         }
     }
 }
예제 #22
0
        protected override void OnGraphStoped()
        {
            currentDialogue  = previousDialogue;
            previousDialogue = null;
            currentNode      = null;

            Logger.Log(string.Format("Dialogue Finished '{0}'", this.name), "Dialogue Tree", this);
            if (OnDialogueFinished != null)
            {
                OnDialogueFinished(this);
            }
        }
예제 #23
0
 void OnDisable()
 {
     current                = null;
     welcomeShown           = false;
     Graph.currentSelection = null;
                 #if UNITY_2017_2_OR_NEWER
     EditorApplication.playModeStateChanged -= PlayModeChange;
                 #else
     EditorApplication.playmodeStateChanged -= PlayModeChange;
                 #endif
     Selection.selectionChanged -= OnSelectionChange;
     Logger.RemoveListener(OnLogMessageReceived);
 }
예제 #24
0
        ///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);
        }
예제 #25
0
 ///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;
     }
 }
예제 #26
0
        ///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);
        }
예제 #27
0
        ///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);
        }
예제 #29
0
 ///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);
 }
        ///Called after the node has GatherPorts to gather the references and validate the binding connection
        public void GatherAndValidateTargetPort()
        {
            _targetPort = null; //refetch
            if (targetPort != null)
            {
                //all good
                if (targetPort.type == bindingType)
                {
                    targetPortID = targetPort.ID;
                    targetPort.connections++;
                    return;
                }

                //replace binder connection type if possible
                if (targetPort is ValueInput && sourcePort is ValueOutput)
                {
                    if (TypeConverter.HasConvertion(sourcePort.type, targetPort.type))
                    {
                        graph.RemoveConnection(this);
                        Create(sourcePort, targetPort);
                        targetPortID = targetPort.ID;
                        targetPort.connections++;
                        return;
                    }
                    //the cast is invalid
                    Logger.LogError(string.Format("Input Port with ID '{0}' cast is invalid.", targetPortID), LogTag.VALIDATION, targetNode);
                    targetPort.FlagInvalidCast();
                    targetPortID = targetPort.ID;
                    targetPort.connections++;
                    return;
                }
            }

            //the id is missing...
            Logger.LogError(string.Format("Input Port with ID '{0}' is missing on node {1}", targetPortID, targetNode.name), LogTag.VALIDATION, targetNode);
            var  target      = targetNode as FlowNode;
            Port missingPort = null;

            if (bindingType == typeof(Flow))
            {
                missingPort = target.AddFlowInput(targetPortID, targetPortID, (f) => { throw new System.Exception("Port is missing"); });
            }
            else
            {
                missingPort = target.AddValueInput(targetPortID, targetPortID, typeof(object));
            }
            missingPort.FlagMissing();
            missingPort.connections++;
        }