private void UpdateContext() { // Subscribe to the map change event, so we can automatically update the context. if (!_contextEventSubscribed) { // Subscribe to OnBattlegroundEntered. Just 'cause. BotEvents.Battleground.OnBattlegroundEntered += e => UpdateContext(); _contextEventSubscribed = true; } var current = CurrentWoWContext; // Can't update the context when it doesn't exist. if (current == WoWContext.None) { return; } if (current != _lastContext && OnWoWContextChanged != null) { DescribeContext(); try { OnWoWContextChanged(this, new WoWContextEventArg(current, _lastContext)); } catch { // Eat any exceptions thrown. } _lastContext = current; } }
public void ContextChange(object sender, LuaEventArgs args) { talent.Reset(); glyph.Reset(); spell.Reset(); line_cds.Clear(); PlayerAuras.Reset(); PetAuras.Reset(); _class = StyxWoW.Me.Class; //_spec = Me.Specialization; var oldctx = Context; Context = (StyxWoW.Me.CurrentMap.IsArena || StyxWoW.Me.CurrentMap.IsBattleground) ? WoWContext.PvP : WoWContext.PvE; if (Context != oldctx) { SimcraftImpl.Write("Switching to " + Context + " Mode"); } ooc = DateTime.Now; RebuildBehaviors(); }
public HolyPriestHealSettings HolyHealLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) { return(StyxWoW.Me.CurrentMap.IsRaid ? HolyRaid : HolyInstance); } return(HolyBattleground); }
public DiscPriestHealSettings DiscHealLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) { return(StyxWoW.Me.CurrentMap.IsRaid ? DiscRaid : DiscInstance); } return(DiscBattleground); }
public BehaviorAttribute(BehaviorType type, WoWClass @class = WoWClass.None, WoWSpec spec =(WoWSpec) int.MaxValue, WoWContext context = WoWContext.All, int priority = 0) { Type = type; SpecificClass = @class; SpecificSpec = spec; SpecificContext = context; PriorityLevel = priority; }
public BehaviorAttribute(BehaviorType type, WoWClass @class = WoWClass.None, WoWSpec spec = (WoWSpec)int.MaxValue, WoWContext context = WoWContext.All, int priority = 0) { Type = type; SpecificClass = @class; SpecificSpec = spec; SpecificContext = context; PriorityLevel = priority; }
public static Composite GetComposite(WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount) { behaviourCount = 0; if (_methods.Count <= 0) { Logger.Write("Building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { // All behavior methods should not be generic, and should have zero parameters, with their return types being of type Composite. _methods.AddRange( type.GetMethods(BindingFlags.Static | BindingFlags.Public).Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0).Where( mi => mi.ReturnType.IsAssignableFrom(typeof (Composite)))); } Logger.Write("Added " + _methods.Count + " methods"); } var matchedMethods = new Dictionary<BehaviorAttribute, Composite>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) continue; // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) continue; // Check if our behavior matches with what we want. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { Logger.Write(string.Format("Matched {0} to behavior {1} for {2} {3} with priority {4}", mi.Name, behavior, wowClass.ToString().CamelToSpaced(), spec.ToString().CamelToSpaced(), attribute.PriorityLevel)); // if it blows up here, you defined a method with the exact same attribute and priority as one already found matchedMethods.Add(attribute, mi.Invoke(null, null) as Composite); } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return null; } var result = new PrioritySelector(); foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { result.AddChild(kvp.Value); behaviourCount++; } return result; }
public ShamanOffHealSettings OffHealSettingsLookup(WoWContext ctx) { if (ctx == WoWContext.Battlegrounds) { return(OffhealBattleground); } return(OffhealPVE); }
private void UpdateContext() { // Subscribe to the map change event, so we can automatically update the context. if (!_contextEventSubscribed) { // Subscribe to OnBattlegroundEntered. Just 'cause. BotEvents.Battleground.OnBattlegroundEntered += e => UpdateContext(); SingularRoutine.OnBotEvent += (src, arg) => { if (arg.Event == SingularBotEvent.BotStarted || arg.Event == SingularBotEvent.BotChanged) { // check if any of the bot detection values have changed which we use to // .. conditionally build trees DescribeContext(); if (UpdateContextStateValues()) { RebuildBehaviors(); } } }; _contextEventSubscribed = true; } DetermineCurrentWoWContext(); // Can't update the context when it doesn't exist. if (CurrentWoWContext == WoWContext.None) { return; } if (CurrentWoWContext != _lastContext && OnWoWContextChanged != null) { // store values that require scanning lists UpdateContextStateValues(); DescribeContext(); try { OnWoWContextChanged(this, new WoWContextEventArg(CurrentWoWContext, _lastContext)); } catch { // Eat any exceptions thrown. } _lastContext = CurrentWoWContext; _lastMapId = Me.MapId; } else if (_lastMapId != Me.MapId) { DescribeContext(); _lastMapId = Me.MapId; } }
public ShamanHealSettings HealLookup(WoWContext ctx) { if (ctx == WoWContext.Battlegrounds) { return(Battleground); } if (ctx == WoWContext.Instances) { return(Instance); } return(Normal); }
public DruidHealSettings HealLookup(WoWContext ctx) { if (ctx == WoWContext.Battlegrounds) { return(Battleground); } if (ctx == WoWContext.Instances) { return(Styx.StyxWoW.Me.CurrentMap.IsRaid ? Raid : Instance); } return(Normal); }
/// <summary> /// check whether a healer DPS be cancelled /// </summary> /// <returns></returns> public static bool CancelHealerDPS() { // allow combat setting is false, so cast originated by some other logic, so allow it to finish if (!SingularSettings.Instance.HealerCombatAllow) { return(false); } // always let DPS casts while solo complete WoWContext ctx = SingularRoutine.CurrentWoWContext; if (ctx == WoWContext.Normal) { return(false); } // allow casts that are close to finishing to finish regardless bool castInProgress = Spell.IsCasting(); if (castInProgress && Me.CurrentCastTimeLeft.TotalMilliseconds < 333) { Logger.WriteDebug("CancelHealerDPS: suppressing /cancel since less than 333 ms cast remaining"); return(false); } // allow casts that are close to finishing to finish regardless castInProgress = Spell.IsChannelling(); if (castInProgress && Me.CurrentChannelTimeLeft.TotalMilliseconds < 333) { Logger.WriteDebug("CancelHealerDPS: suppressing /cancel since less than 333 ms channel remaining"); return(false); } // use a window less than actual to avoid cast/cancel/cast/cancel due to mana hovering at setting level string action = castInProgress ? "^Cancelling DPS" : "!do-not-dps"; if (Me.ManaPercent < (SingularSettings.Instance.HealerCombatMinMana - 3)) { Logger.Write(LogColor.Hilite, "{0} because my Mana={1:F1}% fell below Min={2}%", action, Me.ManaPercent, SingularSettings.Instance.HealerCombatMinMana); return(true); } // check if group health has dropped below setting WoWUnit low = HealerManager.FindLowestHealthTarget(); if (low != null && low.HealthPercent < SingularSettings.Instance.HealerCombatMinHealth) { Logger.Write(LogColor.Hilite, "{0} because {1} @ {2:F1}% health fell below minimum {3}%", action, low.SafeName(), low.HealthPercent, SingularSettings.Instance.HealerCombatMinHealth); return(true); } return(false); }
public MistweaverHealSettings MistHealSettingsLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) { return(StyxWoW.Me.GroupInfo.IsInRaid ? MistRaid : MistInstance); } if (ctx == WoWContext.Battlegrounds) { return(MistBattleground); } return(MistInstance); }
public ShamanRestoHealSettings RestoHealSettingsLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) { return(StyxWoW.Me.GroupInfo.IsInRaid ? RestoRaid : RestoInstance); } if (ctx == WoWContext.Battlegrounds) { return(RestoBattleground); } return(RestoInstance); }
private void cboHealContext_SelectedIndexChanged(object sender, EventArgs e) { WoWContext ctx = (WoWContext)cboHealContext.SelectedItem; bool isBG = ctx == WoWContext.Battlegrounds; bool isInst = ctx == WoWContext.Instances; bool isNorm = ctx == WoWContext.Normal; pgHealBattleground.Enabled = isBG; pgHealBattleground.Visible = isBG; pgHealInstance.Enabled = isInst; pgHealInstance.Visible = isInst; pgHealNormal.Enabled = isNorm; pgHealNormal.Visible = isNorm; }
public ShamanHealSettings(WoWContext ctx) : base("Shaman", ctx) { // bit of a hack. using SavedToFile setting to catch if we have // .. written settings yet. if not, do context specific initialization // .. here since we don't want same DefaultValue() for every context if (SavedToFile) { return; } SavedToFile = true; if (ctx == Singular.WoWContext.Battlegrounds) { HealingWave = 90; ChainHeal = 89; HealingRain = 88; GreaterHealingWave = 70; Ascendance = 40; SpiritLinkTotem = 48; HealingSurge = 50; AncestralSwiftness = 35; HealingStreamTotem = 87; HealingTideTotemPercent = 49; } else if (ctx == Singular.WoWContext.Instances) { HealingWave = 90; ChainHeal = 89; HealingRain = 88; GreaterHealingWave = 70; Ascendance = 40; SpiritLinkTotem = 48; HealingSurge = 50; AncestralSwiftness = 20; HealingStreamTotem = 87; HealingTideTotemPercent = 49; } // omit case for WoWContext.Normal and let it use DefaultValue() values }
public ShamanHealSettings(WoWContext ctx) : base("Shaman", ctx) { // bit of a hack. using SavedToFile setting to catch if we have // .. written settings yet. if not, do context specific initialization // .. here since we don't want same DefaultValue() for every context if (SavedToFile) return; SavedToFile = true; if (ctx == Singular.WoWContext.Battlegrounds) { HealingWave = 90; ChainHeal = 89; HealingRain = 88; GreaterHealingWave = 70; Ascendance = 40; SpiritLinkTotem = 48; HealingSurge = 50; AncestralSwiftness = 35; HealingStreamTotem = 87; HealingTideTotemPercent = 49; } else if (ctx == Singular.WoWContext.Instances) { HealingWave = 90; ChainHeal = 89; HealingRain = 88; GreaterHealingWave = 70; Ascendance = 40; SpiritLinkTotem = 48; HealingSurge = 50; AncestralSwiftness = 20; HealingStreamTotem = 87; HealingTideTotemPercent = 49; } // omit case for WoWContext.Normal and let it use DefaultValue() values }
/// <summary> /// check if Healer should be permitted to do straight DPS abilities (with purpose to damage and not indirect heal, buff, mana return, etc.) /// </summary> /// <returns></returns> public static bool AllowHealerDPS() { WoWContext ctx = SingularRoutine.CurrentWoWContext; if (ctx == WoWContext.Normal) { return(true); } if (SingularRoutine.CurrentHealContext == HealingContext.Raids) { if (TalentManager.CurrentSpec != WoWSpec.MonkMistweaver || !SingularSettings.Instance.HealerCombatAllow) { return(false); } } double rangeCheck = SingularSettings.Instance.MaxHealTargetRange * SingularSettings.Instance.MaxHealTargetRange; if (!SingularSettings.Instance.HealerCombatAllow && Unit.GroupMembers.Any(m => m.IsAlive && !m.IsMe && m.Distance2DSqr < rangeCheck)) { return(false); } if (Me.ManaPercent < SingularSettings.Instance.HealerCombatMinMana) { return(false); } WoWUnit low = FindLowestHealthTarget(); if (low != null && low.HealthPercent < SingularSettings.Instance.HealerCombatMinHealth) { return(false); } return(true); }
public ShamanHealSettings HealLookup( WoWContext ctx) { if (ctx == WoWContext.Battlegrounds) return Battleground; if (ctx == WoWContext.Instances) return Instance; return Normal; }
public WoWContextEventArg(WoWContext currentContext, WoWContext prevContext) { CurrentContext = currentContext; PreviousContext = prevContext; }
public bool Match(WoWClass cl, WoWSpec sp, WoWContext cont) { return(cl == _class && cont == _context); }
public Behavior(WoWClass cl, WoWSpec sp, WoWContext cont) { _class = cl; _spec = sp; _context = cont; }
public Behavior(WoWClass cl, WoWSpec sp, WoWContext cont) { _class = cl; _spec = sp; _context = cont; }
public static Composite GetComposite(WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount, bool silent = false) { if (context == WoWContext.None) { // None is an invalid context, but rather than stopping bot wait it out with donothing logic Logger.Write(Color.White, "No Active Context -{0}{1} for{2} set to DoNothingBehavior temporarily", wowClass.ToString().CamelToSpaced(), behavior.ToString().CamelToSpaced(), spec.ToString().CamelToSpaced()); behaviourCount = 1; return NoContextAvailable.CreateDoNothingBehavior(); } SilentBehaviorCreation = silent; behaviourCount = 0; if (_methods.Count <= 0) { // Logger.WriteDebug("Singular Behaviors: building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { // All behavior methods should not be generic, and should have zero parameters, with their return types being of type Composite. _methods.AddRange( type.GetMethods(BindingFlags.Static | BindingFlags.Public).Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0).Where( mi => mi.ReturnType.IsAssignableFrom(typeof (Composite)))); } Logger.WriteFile("Singular Behaviors: Added " + _methods.Count + " behaviors"); } var matchedMethods = new Dictionary<BehaviorAttribute, Composite>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) continue; // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) continue; // Check if our behavior matches with what we want. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { if (!silent) Logger.WriteFile("{0} {1} {2}", attribute.PriorityLevel.ToString().AlignRight(4), behavior.ToString().AlignLeft(15), mi.Name); CurrentBehaviorType = behavior; // if it blows up here, you defined a method with the exact same attribute and priority as one already found // wrap in trace class Composite comp = mi.Invoke(null, null) as Composite; string name = behavior.ToString() + "." + mi.Name + "." + attribute.PriorityLevel.ToString(); if (SingularSettings.Trace) comp = new CallTrace( name, comp); matchedMethods.Add(attribute, comp); CurrentBehaviorType = 0; } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return null; } var result = new PrioritySelector(); foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { result.AddChild(kvp.Value); behaviourCount++; } return result; }
public void ContextChange(object sender, LuaEventArgs args) { talent.Reset(); glyph.Reset(); spell.Reset(); line_cds.Clear(); PlayerAuras.Reset(); PetAuras.Reset(); _class = StyxWoW.Me.Class; //_spec = Me.Specialization; var oldctx = Context; Context = (StyxWoW.Me.CurrentMap.IsArena || StyxWoW.Me.CurrentMap.IsBattleground) ? WoWContext.PvP : WoWContext.PvE; if (Context != oldctx) SimcraftImpl.Write("Switching to " + Context + " Mode"); ooc = DateTime.Now; RebuildBehaviors(); }
public ShamanOffHealSettings OffHealSettingsLookup(WoWContext ctx) { if (ctx == WoWContext.Battlegrounds) return OffhealBattleground; return OffhealPVE; }
public static Composite GetComposite(WoWClass wowClass, TalentSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount) { behaviourCount = 0; if (_methods.Count <= 0) { Logger.Write("Building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { _methods.AddRange(type.GetMethods(BindingFlags.Static | BindingFlags.Public)); } Logger.Write("Added " + _methods.Count + " methods"); } var matchedMethods = new Dictionary <int, PrioritySelector>(); foreach (MethodInfo mi in _methods.Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0) .Where( mi => mi.ReturnType == typeof(Composite) || mi.ReturnType.IsSubclassOf(typeof(Composite)))) { //Logger.WriteDebug("[CompositeBuilder] Checking attributes on " + mi.Name); bool classMatches = false, specMatches = false, behaviorMatches = false, contextMatches = false, hasIgnore = false; int thePriority = 0; var theBehaviourType = BehaviorType.All; var theIgnoreType = BehaviorType.All; foreach (object ca in mi.GetCustomAttributes(false)) { if (ca is ClassAttribute) { var attrib = ca as ClassAttribute; if (attrib.SpecificClass != WoWClass.None && attrib.SpecificClass != wowClass) { continue; } //Logger.WriteDebug(mi.Name + " has my class"); classMatches = true; } else if (ca is SpecAttribute) { var attrib = ca as SpecAttribute; if (attrib.SpecificSpec != TalentSpec.Any && attrib.SpecificSpec != spec) { continue; } //Logger.WriteDebug(mi.Name + " has my spec"); specMatches = true; } else if (ca is BehaviorAttribute) { var attrib = ca as BehaviorAttribute; if ((attrib.Type & behavior) == 0) { continue; } //Logger.WriteDebug(mi.Name + " has my behavior"); theBehaviourType = attrib.Type; behaviourCount++; behaviorMatches = true; } else if (ca is ContextAttribute) { var attrib = ca as ContextAttribute; if (SingularSettings.Instance.UseInstanceRotation) { if ((attrib.SpecificContext & WoWContext.Instances) == 0) { continue; } } else if ((attrib.SpecificContext & context) == 0) { continue; } //Logger.WriteDebug(mi.Name + " has my context"); contextMatches = true; } else if (ca is PriorityAttribute) { var attrib = ca as PriorityAttribute; thePriority = attrib.PriorityLevel; } else if (ca is IgnoreBehaviorCountAttribute) { var attrib = ca as IgnoreBehaviorCountAttribute; hasIgnore = true; theIgnoreType = attrib.Type; } } if (behaviorMatches && hasIgnore && theBehaviourType == theIgnoreType) { behaviourCount--; } // If all our attributes match, then mark it as wanted! if (classMatches && specMatches && behaviorMatches && contextMatches) { Logger.WriteDebug("{0} is a match!", mi.Name); if (!hasIgnore) { Logger.Write(" Using {0} for {1} - {2} (Priority: {3})", mi.Name, spec.ToString().CamelToSpaced().Trim(), behavior, thePriority); } else { Logger.WriteDebug(" Using {0} for {1} - {2} (Priority: {3})", mi.Name, spec.ToString().CamelToSpaced().Trim(), behavior, thePriority); } Composite matched; try { matched = (Composite)mi.Invoke(null, null); } catch (Exception e) { Logger.Write("ERROR Creating composite: {0}\n{1}", mi.Name, e.StackTrace); continue; } if (!matchedMethods.ContainsKey(thePriority)) { matchedMethods.Add(thePriority, new PrioritySelector(matched)); } else { matchedMethods[thePriority].AddChild(matched); } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return(null); } var result = new PrioritySelector(); foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key)) { result.AddChild(kvp.Value); } return(result); // Return the composite match we found. (Note: ANY composite return is fine) return(matchedMethods.OrderByDescending(mm => mm.Key).First().Value); }
public static void InvokeInitializers(WoWClass wowClass, WoWSpec spec, WoWContext context, bool silent = false) { BehaviorType behavior = BehaviorType.Initialize; if (context == WoWContext.None) { return; } SilentBehaviorCreation = silent; // only load methods once if (_methods.Count <= 0) { // Logger.WriteDebug("Singular Behaviors: building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { // All behavior methods should not be generic, and should have zero parameters, with their return types being of type Composite. _methods.AddRange( type.GetMethods(BindingFlags.Static | BindingFlags.Public).Where( mi => !mi.IsGenericMethod && mi.GetCustomAttributes(typeof(BehaviorAttribute)).Any()).Where( mi => typeof(Composite).IsAssignableFrom(mi.ReturnType) || mi.ReturnType == typeof(Task <bool>))); } Logger.WriteFile("Singular Behaviors: Added " + _methods.Count + " behaviors"); } // find all initialization methods for this class/spec/context var matchedMethods = new Dictionary <BehaviorAttribute, MethodInfo>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) { continue; } // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) { continue; } // Check if our Initialization behavior matches. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { if (matchedMethods.ContainsKey(attribute)) { Logger.Write(LogColor.Hilite, "PROGRAM ERROR: duplicate behaviors. Notify Singular Devs!!!"); Logger.WriteDiagnostic("PROGRAM ERROR: duplicate behaviors. Notify Singular Devs!!!"); Logger.WriteDiagnostic("Error for Attribute: class={0} spec={1} type={2} context={3} priority={4} ", attribute.SpecificClass, attribute.SpecificSpec, attribute.Type, attribute.SpecificContext, attribute.PriorityLevel ); Logger.WriteDiagnostic(" exists {0}:{1}", matchedMethods[attribute].DeclaringType, matchedMethods[attribute].Name ); Logger.WriteDiagnostic(" adding {0}:{1}", mi.DeclaringType, mi.Name ); } matchedMethods.Add(attribute, mi); } } } // invoke each initialization behavior in priority order foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { CurrentBehaviorType = behavior; CurrentBehaviorPriority = kvp.Key.PriorityLevel; CurrentBehaviorName = kvp.Value.Name; string invokeInfo = string.Format("{0} {1} {2}", kvp.Key.PriorityLevel.ToString().AlignRight(5), behavior.ToString().AlignLeft(15), kvp.Value.Name); if (!silent) { Logger.WriteFile(invokeInfo); } kvp.Value.Invoke(null, null); CurrentBehaviorType = 0; CurrentBehaviorPriority = 0; CurrentBehaviorName = string.Empty; } return; }
private static bool IsMatchingMethod(BehaviorAttribute attribute, WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context) { if (attribute.SpecificClass != wowClass && attribute.SpecificClass != WoWClass.None) { return(false); } if ((attribute.Type & behavior) == 0) { return(false); } if ((attribute.SpecificContext & context) == 0) { return(false); } if (attribute.SpecificSpec != (WoWSpec)int.MaxValue && attribute.SpecificSpec != spec) { return(false); } /* Logger.WriteDebug("IsMatchingMethod({0}, {1}, {2}, {3}) - {4}, {5}, {6}, {7}, {8}", wowClass, spec, behavior, * context, attribute.SpecificClass, attribute.SpecificSpec, attribute.Type, attribute.SpecificContext, * attribute.PriorityLevel); */ return(true); }
public static Composite GetComposite(WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount, bool silent = false) { if (context == WoWContext.None) { // None is an invalid context, but rather than stopping bot wait it out with donothing logic Logger.Write(LogColor.Hilite, "No Active Context -{0}{1} for{2} set to DoNothingBehavior temporarily", wowClass.ToString().CamelToSpaced(), behavior.ToString().CamelToSpaced(), spec.ToString().CamelToSpaced()); behaviourCount = 1; return(NoContextAvailable.CreateDoNothingBehavior()); } SilentBehaviorCreation = silent; behaviourCount = 0; var matchedMethods = new Dictionary <BehaviorAttribute, Composite>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) { continue; } // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) { continue; } // Check if our behavior matches with what we want. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { if (!silent) { Logger.WriteFile("{0} {1} {2}", attribute.PriorityLevel.ToString().AlignRight(4), behavior.ToString().AlignLeft(15), mi.Name); } CurrentBehaviorType = behavior; CurrentBehaviorPriority = attribute.PriorityLevel; CurrentBehaviorName = mi.Name; // if it blows up here, you defined a method with the exact same attribute and priority as one already found Composite comp; if (typeof(Composite).IsAssignableFrom(mi.ReturnType)) { comp = mi.Invoke(null, null) as Composite; } else { Beta.Assert(mi.ReturnType == typeof(Task <bool>)); comp = new ActionRunCoroutine(o => mi.Invoke(null, null) as Task <bool>); } string name = behavior + "." + mi.Name + "." + attribute.PriorityLevel; if (SingularSettings.Trace) { comp = new CallTrace(name, comp); } if (matchedMethods.ContainsKey(attribute)) { Logger.Write(LogColor.Hilite, "Internal Error: method '{0}' has attribute that already exists", name); Logger.WriteDiagnostic(" "); Logger.WriteDiagnostic("Dump Methods"); Logger.WriteDiagnostic("==========================="); foreach (var v in matchedMethods) { Logger.WriteDiagnostic("{0} {1} {2} {3}", v.Key.SpecificClass, v.Key.SpecificSpec, v.Key.SpecificContext, v.Key.PriorityLevel); } Logger.WriteDiagnostic("==========================="); Logger.WriteDiagnostic("{0} {1} {2} {3} == add attempt for {4}", attribute.SpecificClass, attribute.SpecificSpec, attribute.SpecificContext, attribute.PriorityLevel, name); Logger.WriteDiagnostic(" "); } matchedMethods.Add(attribute, comp); CurrentBehaviorType = 0; CurrentBehaviorPriority = 0; CurrentBehaviorName = string.Empty; } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return(null); } var result = new PrioritySelector(); foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { result.AddChild(kvp.Value); behaviourCount++; } return(result); }
public bool Match(WoWClass cl, WoWSpec sp, WoWContext cont) { return (cl == _class && cont == _context); }
public DruidHealSettings HealLookup(WoWContext ctx) { if (ctx == WoWContext.Battlegrounds) return Battleground; if (ctx == WoWContext.Instances) return Styx.StyxWoW.Me.CurrentMap.IsRaid ? Raid : Instance; return Normal; }
/// <summary> /// Ensures we have a composite for the given BehaviorType. /// </summary> /// <param name="error">true: report error if composite not found, false: allow null composite</param> /// <param name="type">BehaviorType that should be loaded</param> /// <returns>true: composite loaded and saved to hook, false: failure</returns> private bool EnsureComposite(bool silent, bool error, WoWContext context, BehaviorType type) { int count = 0; Composite composite; // Logger.WriteDebug("Creating " + type + " behavior."); composite = CompositeBuilder.GetComposite(Class, TalentManager.CurrentSpec, type, context, out count); // handle those composites we need to default if not found if (composite == null && type == BehaviorType.Rest) composite = Helpers.Rest.CreateDefaultRestBehaviour(); if ((composite == null || count <= 0) && error) { StopBot(string.Format("Singular does not support {0} for this {1} {2} in {3} context!", type, StyxWoW.Me.Class, TalentManager.CurrentSpec, context)); return false; } composite = AddCommonBehaviorPrefix(composite, type); // replace hook we created during initialization TreeHooks.Instance.ReplaceHook(HookName(type), composite ?? new ActionAlwaysFail()); return composite != null; }
// reqd ctor public HealerSettings(string className, WoWContext ctx) : base(Path.Combine(SingularSettings.SettingsPath, className + "-Heal-" + ctx.ToString() + ".xml")) { WoWContext = ctx; }
public WoWContextEventArg(WoWContext currentContext, WoWContext prevContext) { CurrentContext = currentContext; PreviousContext = prevContext; }
public ShamanHealSettings HealLookup( WoWContext ctx) { if (ctx == WoWContext.Instances) return StyxWoW.Me.CurrentMap.IsRaid ? Raid : Instance; return Battleground; }
// reqd ctor public HealerSettings(string className, WoWContext ctx) : base(Path.Combine(SingularSettings.SettingsPath, className + "-Heal-" + ctx.ToString() + ".xml")) { WoWContext = ctx; }
public static Composite GetComposite(WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount) { behaviourCount = 0; if (_methods.Count <= 0) { Logger.Write("Building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { // All behavior methods should not be generic, and should have zero parameters, with their return types being of type Composite. _methods.AddRange( type.GetMethods(BindingFlags.Static | BindingFlags.Public).Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0).Where( mi => mi.ReturnType.IsAssignableFrom(typeof(Composite)))); } Logger.WriteDebug("Added " + _methods.Count + " methods"); } var matchedMethods = new Dictionary <BehaviorAttribute, Composite>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) { continue; } // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) { continue; } // Check if our behavior matches with what we want. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { Logger.WriteDebug(string.Format("Matched {0} to behavior {1} for {2} {3} with priority {4}", mi.Name, behavior, wowClass.ToString().CamelToSpaced(), spec.ToString().CamelToSpaced(), attribute.PriorityLevel)); // if it blows up here, you defined a method with the exact same attribute and priority as one already found matchedMethods.Add(attribute, mi.Invoke(null, null) as Composite); } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return(null); } var result = new PrioritySelector(); foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { result.AddChild(kvp.Value); behaviourCount++; } return(result); }
public static Composite GetComposite(WoWClass wowClass, TalentSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount) { behaviourCount = 0; if (_methods.Count <= 0) { Logger.Write("Building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { _methods.AddRange(type.GetMethods(BindingFlags.Static | BindingFlags.Public)); } Logger.Write("Added " + _methods.Count + " methods"); } var matchedMethods = new Dictionary<int, PrioritySelector>(); foreach (MethodInfo mi in _methods.Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0) .Where( mi => mi.ReturnType == typeof(Composite) || mi.ReturnType.IsSubclassOf(typeof(Composite)))) { //Logger.WriteDebug("[CompositeBuilder] Checking attributes on " + mi.Name); bool classMatches = false, specMatches = false, behaviorMatches = false, contextMatches = false, hasIgnore = false; int thePriority = 0; var theBehaviourType = BehaviorType.All; var theIgnoreType = BehaviorType.All; foreach (object ca in mi.GetCustomAttributes(false)) { if (ca is ClassAttribute) { var attrib = ca as ClassAttribute; if (attrib.SpecificClass != WoWClass.None && attrib.SpecificClass != wowClass) { continue; } //Logger.WriteDebug(mi.Name + " has my class"); classMatches = true; } else if (ca is SpecAttribute) { var attrib = ca as SpecAttribute; if (attrib.SpecificSpec != TalentSpec.Any && attrib.SpecificSpec != spec) { continue; } //Logger.WriteDebug(mi.Name + " has my spec"); specMatches = true; } else if (ca is BehaviorAttribute) { var attrib = ca as BehaviorAttribute; if ((attrib.Type & behavior) == 0) { continue; } //Logger.WriteDebug(mi.Name + " has my behavior"); theBehaviourType = attrib.Type; behaviourCount++; behaviorMatches = true; } else if (ca is ContextAttribute) { var attrib = ca as ContextAttribute; if (SingularSettings.Instance.UseInstanceRotation) { if ((attrib.SpecificContext & WoWContext.Instances) == 0) continue; } else if ((attrib.SpecificContext & context) == 0) { continue; } //Logger.WriteDebug(mi.Name + " has my context"); contextMatches = true; } else if (ca is PriorityAttribute) { var attrib = ca as PriorityAttribute; thePriority = attrib.PriorityLevel; } else if (ca is IgnoreBehaviorCountAttribute) { var attrib = ca as IgnoreBehaviorCountAttribute; hasIgnore = true; theIgnoreType = attrib.Type; } } if (behaviorMatches && hasIgnore && theBehaviourType == theIgnoreType) { behaviourCount--; } // If all our attributes match, then mark it as wanted! if (classMatches && specMatches && behaviorMatches && contextMatches) { Logger.WriteDebug("{0} is a match!", mi.Name); if (!hasIgnore) { Logger.Write(" Using {0} for {1} - {2} (Priority: {3})", mi.Name, spec.ToString().CamelToSpaced().Trim(), behavior, thePriority); } else { Logger.WriteDebug(" Using {0} for {1} - {2} (Priority: {3})", mi.Name, spec.ToString().CamelToSpaced().Trim(), behavior, thePriority); } Composite matched; try { matched = (Composite) mi.Invoke(null, null); } catch (Exception e) { Logger.Write("ERROR Creating composite: {0}\n{1}", mi.Name, e.StackTrace); continue; } if (!matchedMethods.ContainsKey(thePriority)) { matchedMethods.Add(thePriority, new PrioritySelector(matched)); } else { matchedMethods[thePriority].AddChild(matched); } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return null; } // Return the composite match we found. (Note: ANY composite return is fine) return matchedMethods.OrderByDescending(mm => mm.Key).First().Value; }
public static void InvokeInitializers(WoWClass wowClass, WoWSpec spec, WoWContext context, bool silent = false) { BehaviorType behavior = BehaviorType.Initialize; if (context == WoWContext.None) { return; } SilentBehaviorCreation = silent; // only load methods once if (_methods.Count <= 0) { // Logger.WriteDebug("Singular Behaviors: building method list"); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { // All behavior methods should not be generic, and should have zero parameters, with their return types being of type Composite. _methods.AddRange( type.GetMethods(BindingFlags.Static | BindingFlags.Public).Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0).Where( mi => mi.ReturnType.IsAssignableFrom(typeof(Composite)))); } Logger.WriteFile("Singular Behaviors: Added " + _methods.Count + " behaviors"); } // find all initialization methods for this class/spec/context var matchedMethods = new Dictionary<BehaviorAttribute, MethodInfo>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) continue; // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) continue; // Check if our Initialization behavior matches. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { if (matchedMethods.ContainsKey(attribute)) { Logger.Write(LogColor.Hilite, "PROGRAM ERROR: duplicate behaviors. Notify Singular Devs!!!"); Logger.WriteDiagnostic("PROGRAM ERROR: duplicate behaviors. Notify Singular Devs!!!"); Logger.WriteDiagnostic("Error for Attribute: class={0} spec={1} type={2} context={3} priority={4} ", attribute.SpecificClass, attribute.SpecificSpec, attribute.Type, attribute.SpecificContext, attribute.PriorityLevel ); Logger.WriteDiagnostic(" exists {0}:{1}", matchedMethods[attribute].DeclaringType, matchedMethods[attribute].Name ); Logger.WriteDiagnostic(" adding {0}:{1}", mi.DeclaringType, mi.Name ); } matchedMethods.Add( attribute, mi); } } } // invoke each initialization behavior in priority order foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { CurrentBehaviorType = behavior; CurrentBehaviorPriority = kvp.Key.PriorityLevel; CurrentBehaviorName = kvp.Value.Name; string invokeInfo = string.Format("{0} {1} {2}", kvp.Key.PriorityLevel.ToString().AlignRight(5), behavior.ToString().AlignLeft(15), kvp.Value.Name); if (!silent) Logger.WriteFile(invokeInfo); kvp.Value.Invoke(null, null); CurrentBehaviorType = 0; CurrentBehaviorPriority = 0; CurrentBehaviorName = string.Empty; } return; }
public ShamanRestoHealSettings RestoHealSettingsLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) return StyxWoW.Me.GroupInfo.IsInRaid ? RestoRaid : RestoInstance; if (ctx == WoWContext.Battlegrounds) return RestoBattleground; return RestoInstance; }
private static bool IsMatchingMethod(BehaviorAttribute attribute, WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context) { if (attribute.SpecificClass != wowClass && attribute.SpecificClass != WoWClass.None) return false; if ((attribute.Type & behavior) == 0) return false; if ((attribute.SpecificContext & context) == 0) return false; if (attribute.SpecificSpec != (WoWSpec)int.MaxValue && attribute.SpecificSpec != spec) return false; Logger.WriteDebug("IsMatchingMethod({0}, {1}, {2}, {3}) - {4}, {5}, {6}, {7}, {8}", wowClass, spec, behavior, context, attribute.SpecificClass, attribute.SpecificSpec, attribute.Type, attribute.SpecificContext, attribute.PriorityLevel); return true; }
public HolyPriestHealSettings HolyHealLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) return StyxWoW.Me.CurrentMap.IsRaid ? HolyRaid : HolyInstance; return HolyBattleground; }
public static Composite GetComposite(object createFrom, WoWClass wowClass, TalentSpec spec, BehaviorType behavior, WoWContext context) { MethodInfo[] methods = createFrom.GetType().GetMethods(); var matchedMethods = new Dictionary<int, PrioritySelector>(); foreach (MethodInfo mi in methods.Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0) .Where( mi => mi.ReturnType == typeof(Composite) || mi.ReturnType.IsSubclassOf(typeof(Composite)))) { //Logger.WriteDebug("[CompositeBuilder] Checking attributes on " + mi.Name); bool classMatches = false, specMatches = false, behaviorMatches = false, contextMatches = false; int thePriority = 0; foreach (object ca in mi.GetCustomAttributes(false)) { if (ca is ClassAttribute) { var attrib = ca as ClassAttribute; if (attrib.SpecificClass != wowClass) { continue; } //Logger.WriteDebug(mi.Name + " has my class"); classMatches = true; } else if (ca is SpecAttribute) { var attrib = ca as SpecAttribute; if (attrib.SpecificSpec != spec) { continue; } //Logger.WriteDebug(mi.Name + " has my spec"); specMatches = true; } else if (ca is BehaviorAttribute) { var attrib = ca as BehaviorAttribute; if (attrib.Type != behavior) { continue; } //Logger.WriteDebug(mi.Name + " has my behavior"); behaviorMatches = true; } else if (ca is ContextAttribute) { var attrib = ca as ContextAttribute; if ((attrib.SpecificContext & context) == 0) { continue; } //Logger.WriteDebug(mi.Name + " has my context"); contextMatches = true; } else if (ca is PriorityAttribute) { var attrib = ca as PriorityAttribute; thePriority = attrib.PriorityLevel; } } // If all our attributes match, then mark it as wanted! if (classMatches && specMatches && behaviorMatches && contextMatches) { Logger.WriteDebug(string.Format("{0} is a match!", mi.Name)); Logger.Write(string.Format("Using {0} for {1} - {2} (Priority: {3})", mi.Name, spec.ToString().CamelToSpaced().Trim(), behavior, thePriority)); Composite matched = null; try { matched = (Composite) mi.Invoke(createFrom, null); } catch (Exception e) { Logger.Write("ERROR Creating composite: " + mi.Name); Logger.Write(e.StackTrace); continue; } if (!matchedMethods.ContainsKey(thePriority)) { matchedMethods.Add(thePriority, new PrioritySelector(matched)); } else { matchedMethods[thePriority].AddChild(matched); } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return null; } // Return a sorted list of our created composites return new PrioritySelector(matchedMethods.OrderByDescending(mm => mm.Key).Select(mm => mm.Value).ToArray()); }
private void UpdateContext() { // Subscribe to the map change event, so we can automatically update the context. if (!_contextEventSubscribed) { // Subscribe to OnBattlegroundEntered. Just 'cause. BotEvents.Battleground.OnBattlegroundEntered += e => UpdateContext(); SingularRoutine.OnBotEvent += (src, arg) => { if (arg.Event == SingularBotEvent.BotStarted || arg.Event == SingularBotEvent.BotChanged) { // check if any of the bot detection values have changed which we use to // .. conditionally build trees DescribeContext(); if (UpdateContextStateValues()) { RebuildBehaviors(); } } }; _contextEventSubscribed = true; } DetermineCurrentWoWContext(); // Can't update the context when it doesn't exist. if (CurrentWoWContext == WoWContext.None) return; if(CurrentWoWContext != _lastContext && OnWoWContextChanged!=null) { // store values that require scanning lists UpdateContextStateValues(); DescribeContext(); try { OnWoWContextChanged(this, new WoWContextEventArg(CurrentWoWContext, _lastContext)); } catch { // Eat any exceptions thrown. } _lastContext = CurrentWoWContext; _lastMapId = Me.MapId; } else if (_lastMapId != Me.MapId) { DescribeContext(); _lastMapId = Me.MapId; } }
private void UpdateContext() { // Subscribe to the map change event, so we can automatically update the context. if(!_contextEventSubscribed) { // Subscribe to OnBattlegroundEntered. Just 'cause. BotEvents.Battleground.OnBattlegroundEntered += e => UpdateContext(); _contextEventSubscribed = true; } var current = CurrentWoWContext; // Can't update the context when it doesn't exist. if (current == WoWContext.None) return; if(current != _lastContext && OnWoWContextChanged!=null) { try { OnWoWContextChanged(this, new WoWContextEventArg(current, _lastContext)); } catch { // Eat any exceptions thrown. } _lastContext = current; } }
public MistweaverHealSettings MistHealSettingsLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) return StyxWoW.Me.GroupInfo.IsInRaid ? MistRaid : MistInstance; if (ctx == WoWContext.Battlegrounds) return MistBattleground; return MistInstance; }
public static Composite GetComposite(WoWClass wowClass, WoWSpec spec, BehaviorType behavior, WoWContext context, out int behaviourCount, bool silent = false) { if (context == WoWContext.None) { // None is an invalid context, but rather than stopping bot wait it out with donothing logic Logger.Write( LogColor.Hilite, "No Active Context -{0}{1} for{2} set to DoNothingBehavior temporarily", wowClass.ToString().CamelToSpaced(), behavior.ToString().CamelToSpaced(), spec.ToString().CamelToSpaced()); behaviourCount = 1; return NoContextAvailable.CreateDoNothingBehavior(); } SilentBehaviorCreation = silent; behaviourCount = 0; var matchedMethods = new Dictionary<BehaviorAttribute, Composite>(); foreach (MethodInfo mi in _methods) { // If the behavior is set as ignore. Don't use it? Duh? if (mi.GetCustomAttributes(typeof(IgnoreBehaviorCountAttribute), false).Any()) continue; // If there's no behavior attrib, then move along. foreach (var a in mi.GetCustomAttributes(typeof(BehaviorAttribute), false)) { var attribute = a as BehaviorAttribute; if (attribute == null) continue; // Check if our behavior matches with what we want. If not, don't add it! if (IsMatchingMethod(attribute, wowClass, spec, behavior, context)) { if (!silent) Logger.WriteFile("{0} {1} {2}", attribute.PriorityLevel.ToString().AlignRight(4), behavior.ToString().AlignLeft(15), mi.Name); CurrentBehaviorType = behavior; CurrentBehaviorPriority = attribute.PriorityLevel; CurrentBehaviorName = mi.Name; // if it blows up here, you defined a method with the exact same attribute and priority as one already found // wrap in trace class Composite comp = mi.Invoke(null, null) as Composite; string name = behavior.ToString() + "." + mi.Name + "." + attribute.PriorityLevel.ToString(); if (SingularSettings.Trace) comp = new CallTrace( name, comp); if (matchedMethods.ContainsKey(attribute)) { Logger.Write(LogColor.Hilite, "Internal Error: method '{0}' has attribute that already exists", name); Logger.WriteDiagnostic(" "); Logger.WriteDiagnostic("Dump Methods"); Logger.WriteDiagnostic("==========================="); foreach (var v in matchedMethods) { Logger.WriteDiagnostic("{0} {1} {2} {3}", v.Key.SpecificClass, v.Key.SpecificSpec, v.Key.SpecificContext, v.Key.PriorityLevel); } Logger.WriteDiagnostic("==========================="); Logger.WriteDiagnostic("{0} {1} {2} {3} == add attempt for {4}", attribute.SpecificClass, attribute.SpecificSpec, attribute.SpecificContext, attribute.PriorityLevel, name); Logger.WriteDiagnostic(" "); } matchedMethods.Add(attribute, comp); CurrentBehaviorType = 0; CurrentBehaviorPriority = 0; CurrentBehaviorName = string.Empty; } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return null; } var result = new PrioritySelector(); foreach (var kvp in matchedMethods.OrderByDescending(mm => mm.Key.PriorityLevel)) { result.AddChild(kvp.Value); behaviourCount++; } return result; }
public DiscPriestHealSettings DiscHealLookup(WoWContext ctx) { if (ctx == WoWContext.Instances) return StyxWoW.Me.CurrentMap.IsRaid ? DiscRaid : DiscInstance; return DiscBattleground; }
public ContextAttribute(WoWContext context) { SpecificContext = context; }
public ContextAttribute(WoWContext context) { SpecificContext = context; }
public static Composite GetComposite(object createFrom, WoWClass wowClass, TalentSpec spec, BehaviorType behavior, WoWContext context) { MethodInfo[] methods = createFrom.GetType().GetMethods(); var matchedMethods = new Dictionary <int, PrioritySelector>(); foreach (MethodInfo mi in methods.Where( mi => !mi.IsGenericMethod && mi.GetParameters().Length == 0) .Where( mi => mi.ReturnType == typeof(Composite) || mi.ReturnType.IsSubclassOf(typeof(Composite)))) { //Logger.WriteDebug("[CompositeBuilder] Checking attributes on " + mi.Name); bool classMatches = false, specMatches = false, behaviorMatches = false, contextMatches = false; int thePriority = 0; foreach (object ca in mi.GetCustomAttributes(false)) { if (ca is ClassAttribute) { var attrib = ca as ClassAttribute; if (attrib.SpecificClass != wowClass) { continue; } //Logger.WriteDebug(mi.Name + " has my class"); classMatches = true; } else if (ca is SpecAttribute) { var attrib = ca as SpecAttribute; if (attrib.SpecificSpec != spec) { continue; } //Logger.WriteDebug(mi.Name + " has my spec"); specMatches = true; } else if (ca is BehaviorAttribute) { var attrib = ca as BehaviorAttribute; if (attrib.Type != behavior) { continue; } //Logger.WriteDebug(mi.Name + " has my behavior"); behaviorMatches = true; } else if (ca is ContextAttribute) { var attrib = ca as ContextAttribute; if ((attrib.SpecificContext & context) == 0) { continue; } //Logger.WriteDebug(mi.Name + " has my context"); contextMatches = true; } else if (ca is PriorityAttribute) { var attrib = ca as PriorityAttribute; thePriority = attrib.PriorityLevel; } } // If all our attributes match, then mark it as wanted! if (classMatches && specMatches && behaviorMatches && contextMatches) { Logger.WriteDebug(string.Format("{0} is a match!", mi.Name)); Logger.Write(string.Format("Using {0} for {1} - {2} (Priority: {3})", mi.Name, spec.ToString().CamelToSpaced().Trim(), behavior, thePriority)); Composite matched = null; try { matched = (Composite)mi.Invoke(createFrom, null); } catch (Exception e) { Logger.Write("ERROR Creating composite: " + mi.Name); Logger.Write(e.StackTrace); continue; } if (!matchedMethods.ContainsKey(thePriority)) { matchedMethods.Add(thePriority, new PrioritySelector(matched)); } else { matchedMethods[thePriority].AddChild(matched); } } } // If we found no methods, rofls! if (matchedMethods.Count <= 0) { return(null); } // Return a sorted list of our created composites return(new PrioritySelector(matchedMethods.OrderByDescending(mm => mm.Key).Select(mm => mm.Value).ToArray())); }