public override RunStatus Tick(object context)
        {
            try
            {
                return(base.Tick(context));
            }

            catch (Exception except)
            {
                if (except.GetType() != typeof(ThreadAbortException))
                {
                    var message = QBCLog.BuildMessageWithContext(_questBehaviorBase.Element,
                                                                 "{0} EXCEPTION CONTEXT ({1}):",
                                                                 QBCLog.VersionedBehaviorName,
                                                                 except.GetType().Name);

                    if (QuestBehaviorCoreSettings.Instance.LogProfileContextOnExceptions)
                    {
                        QBCLog.Error(message);
                        SystemSounds.Asterisk.Play();
                    }
                    else
                    {
                        QBCLog.DeveloperInfo(message);
                    }
                }

                throw;
            }
        }
        // 19Apr2013-05:58UTC chinajade
        public void UsageCheck_SemanticCoherency(XElement xElement, bool incoherencyPredicate, ProvideStringDelegate messageDelegate)
        {
            if (incoherencyPredicate)
            {
                QBCLog.Error(QBCLog.BuildMessageWithContext(xElement,
                                                            "PROFILE ERROR: {0}",
                                                            UtilFormatMessage(messageDelegate(null))));
                IsAttributeProblem = true;

                AudibleNotifyOn(QuestBehaviorCoreSettings.Instance.AudibleNotify_OnSemanticIncoherency);
            }
        }
Пример #3
0
        /// <summary>
        /// <para>Exception situations occur when bad data/input is provided, and no corrective actions can be taken.</para>
        /// </summary>
        /// <param name="except"></param>
        /// <param name="formatForPrefix"></param>
        /// <param name="argsForPrefix"></param>
        public static void Exception(Exception except, string formatForPrefix = null, params object[] argsForPrefix)
        {
            var messagePrefix =
                (formatForPrefix == null)
                ? "MAINTENANCE PROBLEM"
                : string.Format(formatForPrefix, argsForPrefix);

            QBCLog.Error("[{0}]: {1}\nFROM HERE ({2}):\n{3}\n",
                         messagePrefix,
                         except.Message,
                         except.GetType().Name,
                         except.StackTrace);
        }
        public static bool Provides(bool isContractOkay, ProvideStringDelegate provideStringProviderDelegate)
        {
            if (!isContractOkay)
            {
                // TODO: (Future enhancement) Build a string representation of isContractOkay if stringProviderDelegate is null
                string message = provideStringProviderDelegate(null) ?? "NO MESSAGE PROVIDED";
                var    trace   = new StackTrace(1);

                QBCLog.Error("[CONTRACT VIOLATION] {0}\nLocation:\n{1}", message, trace.ToString());
                throw new ContractException(message);
            }

            return(isContractOkay);
        }
 private async Task LogWarning()
 {
     QBCLog.Error("Honorbuddy may not be looting because your bags are full.");
 }
Пример #6
0
        /// <summary>
        ///     <para>Uses item defined by ITEMID.</para>
        ///     <para>
        ///         Notes:
        ///         <list type="bullet">
        ///             <item>
        ///                 <description>
        ///                     <para>
        ///                         * It is up to the caller to assure that all preconditions have been met for
        ///                         using the item (i.e., the item is off cooldown, etc).
        ///                     </para>
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <description>
        ///                     <para>
        ///                         * If item use was successful, coroutine returns 'true';
        ///                         otherwise, 'false' is returned (e.g., item is not ready for use,
        ///                         item use was interrupted by combat, etc).
        ///                     </para>
        ///                 </description>
        ///             </item>
        ///         </list>
        ///     </para>
        /// </summary>
        /// <param name="itemId">The item provided should be viable, and ready for use.</param>
        /// <param name="actionOnMissingItemDelegate">This delegate will be called if the item
        /// is missing from our backpack.  This delegate may not be null.</param>
        /// <param name="actionOnFailedItemUseDelegate">If non-null, this delegate will be called
        /// if we attempted to use the item, and it was unsuccessful.  Examples include attemtping
        /// to use the item on an invalid target, or being interrupted or generally unable to use
        /// the item at this time.</param>
        /// <param name="actionOnSuccessfulItemUseDelegate">If non-null, this delegate will be called
        /// once the item has been used successfully.</param>
        /// <returns></returns>
        /// <remarks>20140305-19:01UTC, Highvoltz/chinajade</remarks>
        public static async Task <bool> UseItem(
            int itemId,
            System.Action actionOnMissingItemDelegate,
            System.Action actionOnFailedItemUseDelegate     = null,
            System.Action actionOnSuccessfulItemUseDelegate = null)
        {
            // Waits for global cooldown to end to successfully use the item
            await Coroutine.Wait(500, () => !SpellManager.GlobalCooldown);

            // Is item in our bags?
            var itemToUse = Me.CarriedItems.FirstOrDefault(i => (i.Entry == itemId));

            if (!Query.IsViable(itemToUse))
            {
                QBCLog.Error("{0} is not in our bags.", Utility.GetItemNameFromId(itemId));
                if (actionOnMissingItemDelegate != null)
                {
                    actionOnMissingItemDelegate();
                }
                return(false);
            }
            var itemName = itemToUse.SafeName;

            // Wait for Item to be usable...
            // NB: WoWItem.Usable does not account for cooldowns.
            if (!itemToUse.Usable || (itemToUse.Cooldown > 0))
            {
                TreeRoot.StatusText =
                    string.Format(
                        "{0} is not usable, yet. (cooldown remaining: {1})",
                        itemName,
                        Utility.PrettyTime(itemToUse.CooldownTimeLeft));
                return(false);
            }

            // Notify user of intent...
            QBCLog.DeveloperInfo("Attempting use of '{0}'", itemName);

            // Set up 'interrupted use' detection, and use item...
            using (var castMonitor = SpellCastMonitor.Start(null))
            {
                itemToUse.Use();
                // NB: The target or the item may not be valid after this point...
                // Some targets will go 'invalid' immediately afer interacting with them.
                // Most of the time this happens, the target is immediately and invisibly replaced with
                // an identical looking target with a different script.
                // Some items are consumed when used.
                // We must assume our target and item is no longer available for use after this point.
                await Coroutine.Sleep((int)Delay.AfterItemUse.TotalMilliseconds);

                // Wait for any casting to complete...
                // NB: Some interactions or item usages take time, and the WoWclient models this as spellcasting.
                // NB: We can't test for IsCasting or IsChanneling--we must instead look for a valid spell being cast.
                //      There are some quests that require actions where the WoWclient returns 'true' for IsCasting,
                //      but there is no valid spell being cast.  We want the behavior to move on immediately in these
                //      conditions.  An example of such an interaction is removing 'tangler' vines in the Tillers
                //      daily quest area.
                var castResult = await castMonitor.GetResult();

                if (castResult != SpellCastResult.Succeeded && castResult != SpellCastResult.NoCastStarted)
                {
                    string reason = castResult == SpellCastResult.UnknownFail ? castMonitor.FailReason : castResult.ToString();

                    QBCLog.Warning("Use of {0} interrupted. Reason: {1}", itemName, reason);
                    // Give whatever issue encountered a chance to settle...
                    // NB: --we want the Sequence to fail when delay completes.
                    if (castResult != SpellCastResult.LineOfSight &&
                        castResult != SpellCastResult.OutOfRange &&
                        castResult != SpellCastResult.TooClose)
                    {
                        await Coroutine.Sleep(1500);
                    }

                    if (actionOnFailedItemUseDelegate != null)
                    {
                        actionOnFailedItemUseDelegate();
                    }
                    return(false);
                }
            }

            QBCLog.DeveloperInfo("Use of '{0}' succeeded.", itemName);

            if (actionOnSuccessfulItemUseDelegate != null)
            {
                actionOnSuccessfulItemUseDelegate();
            }
            return(true);
        }
Пример #7
0
        /// <summary>
        ///     <para>Uses item defined by ITEMID on target defined by SELECTEDTARGET.</para>
        ///     <para>
        ///         Notes:
        ///         <list type="bullet">
        ///             <item>
        ///                 <description>
        ///                     <para>
        ///                         * It is up to the caller to assure that all preconditions have been met for
        ///                         using the item (i.e., the target is in range, the item is off cooldown, etc).
        ///                     </para>
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <description>
        ///                     <para>
        ///                         * If item use was successful, coroutine returns 'true';
        ///                         otherwise, 'false' is returned (e.g., item is not ready for use,
        ///                         item use was interrupted by combat, etc).
        ///                     </para>
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <description>
        ///                     <para>
        ///                         * It is up to the caller to blacklist the target, or select a new target
        ///                         after successful item use.  The actionOnFailedItemUseDelegate argument
        ///                         can facilitate these activities.
        ///                     </para>
        ///                 </description>
        ///             </item>
        ///         </list>
        ///     </para>
        /// </summary>
        /// <param name="selectedTarget">The target provided should be viable.</param>
        /// <param name="itemId">The item provided should be viable, and ready for use.</param>
        /// <param name="actionOnMissingItemDelegate">This delegate will be called if the item
        /// is missing from our backpack.  This delegate may not be null.</param>
        /// <param name="actionOnFailedItemUseDelegate">If non-null, this delegate will be called
        /// if we attempted to use the item, and it was unsuccessful.  Examples include attemtping
        /// to use the item on an invalid target, or being interrupted or generally unable to use
        /// the item at this time.</param>
        /// <param name="actionOnSuccessfulItemUseDelegate">If non-null, this delegate will be called
        /// once the item has been used successfully.</param>
        /// <returns></returns>
        /// <remarks>20140305-19:01UTC, Highvoltz/chinajade</remarks>
        public static async Task <bool> UseItemOnTarget(
            int itemId,
            WoWObject selectedTarget,
            System.Action actionOnMissingItemDelegate,
            System.Action actionOnFailedItemUseDelegate     = null,
            System.Action actionOnSuccessfulItemUseDelegate = null)
        {
            // Waits for global cooldown to end to successfully use the item
            await Coroutine.Wait(500, () => !SpellManager.GlobalCooldown);

            // qualify...
            // Viable target?
            // NB: Since target may go invalid immediately upon using the item,
            // we cache its name for use in subsequent log entries.;
            if (!Query.IsViable(selectedTarget))
            {
                QBCLog.Warning("Target is not viable!");
                if (actionOnFailedItemUseDelegate != null)
                {
                    actionOnFailedItemUseDelegate();
                }
                return(false);
            }
            var targetName = selectedTarget.SafeName;

            // Is item in our bags?
            var itemToUse = Me.CarriedItems.FirstOrDefault(i => (i.Entry == itemId));

            if (!Query.IsViable(itemToUse))
            {
                QBCLog.Error("{0} is not in our bags.", Utility.GetItemNameFromId(itemId));
                if (actionOnMissingItemDelegate != null)
                {
                    actionOnMissingItemDelegate();
                }
                return(false);
            }
            var itemName = itemToUse.SafeName;

            // Need to be facing target...
            // NB: Not all items require this, but many do.
            Utility.Target(selectedTarget, true);

            // Wait for Item to be usable...
            // NB: WoWItem.Usable does not account for cooldowns.
            if (!itemToUse.Usable || (itemToUse.Cooldown > 0))
            {
                TreeRoot.StatusText =
                    string.Format(
                        "{0} is not usable, yet. (cooldown remaining: {1})",
                        itemName,
                        Utility.PrettyTime(itemToUse.CooldownTimeLeft));
                return(false);
            }

            // Notify user of intent...
            var message = string.Format("Attempting use of '{0}' on '{1}'", itemName, targetName);

            var selectedTargetAsWoWUnit = selectedTarget as WoWUnit;

            if (selectedTargetAsWoWUnit != null)
            {
                if (selectedTargetAsWoWUnit.IsDead)
                {
                    message += " (dead)";
                }
                else
                {
                    message += string.Format(" (health: {0:F1})", selectedTargetAsWoWUnit.HealthPercent);
                }
            }
            QBCLog.DeveloperInfo(message);

            // Set up 'interrupted use' detection, and use item...
            // MAINTAINER'S NOTE: Once these handlers are installed, make sure all possible exit paths from the outer
            // Sequence unhook these handlers.  I.e., if you plan on returning RunStatus.Failure, be sure to call
            // UtilityBehaviorSeq_UseItemOn_HandlersUnhook() first.

            // Set up 'interrupted use' detection, and use item...
            using (var castMonitor = SpellCastMonitor.Start(null))
            {
                itemToUse.Use(selectedTarget.Guid);

                // NB: The target or the item may not be valid after this point...
                // Some targets will go 'invalid' immediately afer interacting with them.
                // Most of the time this happens, the target is immediately and invisibly replaced with
                // an identical looking target with a different script.
                // Some items are consumed when used.
                // We must assume our target and item is no longer available for use after this point.
                await Coroutine.Sleep((int)Delay.AfterItemUse.TotalMilliseconds);

                await CastPendingSpell(selectedTarget);


                // Wait for any casting to complete...
                // NB: Some interactions or item usages take time, and the WoWclient models this as spellcasting.
                // NB: We can't test for IsCasting or IsChanneling--we must instead look for a valid spell being cast.
                //      There are some quests that require actions where the WoWclient returns 'true' for IsCasting,
                //      but there is no valid spell being cast.  We want the behavior to move on immediately in these
                //      conditions.  An example of such an interaction is removing 'tangler' vines in the Tillers
                //      daily quest area.
                var castResult = await castMonitor.GetResult();

                if (castResult != SpellCastResult.Succeeded && castResult != SpellCastResult.NoCastStarted)
                {
                    string reason = castResult == SpellCastResult.UnknownFail ? castMonitor.FailReason : castResult.ToString();

                    QBCLog.Warning("Use of {0} interrupted. Reason: {1}", itemName, reason);
                    // Give whatever issue encountered a chance to settle...
                    // NB: --we want the Sequence to fail when delay completes.
                    if (castResult != SpellCastResult.LineOfSight &&
                        castResult != SpellCastResult.OutOfRange &&
                        castResult != SpellCastResult.TooClose)
                    {
                        await Coroutine.Sleep(1500);
                    }

                    if (actionOnFailedItemUseDelegate != null)
                    {
                        actionOnFailedItemUseDelegate();
                    }
                    return(false);
                }
            }

            QBCLog.DeveloperInfo("Use of '{0}' on '{1}' succeeded.", itemName, targetName);
            if (actionOnSuccessfulItemUseDelegate != null)
            {
                actionOnSuccessfulItemUseDelegate();
            }
            return(true);
        }