• Visit Rebornbuddy
  • Coroutine support

    Discussion in 'Community Developer Forum' started by Teo, Aug 27, 2015.

    1. Teo

      Teo Member

      Joined:
      Oct 6, 2012
      Messages:
      35
      Likes Received:
      1
      Trophy Points:
      8
      To avoid cluttering the Combat Routine, might as well continue the discussion here.

      As the BuddyWing bot stands currently, it is now equipped to support switching the Combat Routines to full use of coroutines.

      The version of TreeSharp used in BuddyWing appears to be lacking compared to the one in RebornBuddy for instance.

      Aevitas, are there any plans to make BuddyWing more in sync with the other bots provided here?

      If not, is there a way to completely override the CombatRoutine properties OutOfCombat, Pull and Combat and move them away from Composites (into something that implements threads or async instead?)
       
    2. Cryogenesis

      Cryogenesis Moderator Moderator

      Joined:
      Jul 13, 2010
      Messages:
      2,128
      Likes Received:
      13
      Trophy Points:
      38
    3. Aevitas

      Aevitas Well-Known Member Staff Member Buddy Core Dev

      Joined:
      Mar 2, 2010
      Messages:
      2,307
      Likes Received:
      36
      Trophy Points:
      48
      The way at least HB does it is provide TreeSharp extensions that allow coroutines to be ran. I'm not sure what you guys are looking to achieve through the use of coroutines, as the routines themselves are actually fairly simplistic for BW. It's not some sort of magical cure that will make all problems go away which seems to be what I gather from the thread that was linked above.

      Sure, I can add coroutines to BW and provide support from a core point of view, but you'd still end up using ActionRunCoroutine et al to fire them up - OutOfCombat, Pull will still remain composites either way.
       
    4. pindleskin

      pindleskin Community Developer

      Joined:
      Oct 24, 2012
      Messages:
      1,124
      Likes Received:
      2
      Trophy Points:
      38
      What do we actually gain with cororoutine and what is that?
       
    5. Praline

      Praline Member

      Joined:
      Aug 17, 2015
      Messages:
      150
      Likes Received:
      2
      Trophy Points:
      18
      ...ours not to reason why, ours but to do and die...
      haha - sorry could not resist, but your question did make me smile cause I was wondering the same. :)
       
    6. Teo

      Teo Member

      Joined:
      Oct 6, 2012
      Messages:
      35
      Likes Received:
      1
      Trophy Points:
      8
      Without knowing what lies behind ActionRunCoroutine I can only guess, but wont coroutines make most task multithreaded/asynchronous, meaning that the bot wont freeze/lag the client as much.

      Again this is just a guess. Ama,
      alltrueist or Jon310 might be able to answer in more detail.
       
    7. Wheredidigo

      Wheredidigo Community Developer

      Joined:
      Dec 15, 2013
      Messages:
      417
      Likes Received:
      8
      Trophy Points:
      18
      Let me first start by saying that I ran across this thread while searching for something else, so please know that I don't play SWTOR or use BuddyWing at all.

      With that out of the way....I am an active Community Developer for the RebornBuddy product and was one of the developers selling the Righteous Combat Routine for HonorBuddy before Bossland changed the contracts on everyone.

      Let me point you in the right direction on Coroutines.

      The absolute BEST thing about them is the ability to debug the code you write with them A LOT easier than with a traditional TreeSharp implementation.

      The next thing you need to know is that a Coroutine IS a Composite.

      So you'll still have code that looks like this:

      [HIDE]
      Code:
      public override Composite CombatBehavior { get { return new ActionRunCoroutine(ctx => Combat.Fight()); } }
      [/HIDE]

      Where Combat.Fight(); returns a Task<bool>

      As an Example...here is the Combat.Fight() from the code above...

      [HIDE]
      Code:
      internal static async Task<bool> Fight()
      {
      	if (Core.Me.IsCasting || !Core.Me.HasTarget || !Core.Me.CurrentTarget.IsValidAttackUnit()) return false;
      	
              //Get the current target
      	var target = Core.Me.CurrentTarget;
      	
              //if I'm not in Cleric Stance, put it on since I want to cast a DPS spell
      	if (!Core.Me.HasAura(Spells.ClericStance.Name))
      	{
              	return await Spells.ClericStance.Cast(Core.Me);
              }
      
      	//if there is less than 4 seconds left on Aero2, refresh it
      	if (!target.HasAura(Auras.Aero2, true, 4000) && await Spells.Aero2.Cast(target)) return true;
      
      	//if there is less than 4 seconds left on Aero, refresh it
      	if (!target.HasAura(Auras.Aero, true, 4000) && await Spells.Aero.Cast(target)) return true;
      
      	//if target is within 5y of me, use Fluid Aura
      	if (Core.Me.Distance(target.Location) <= 5 && await Spells.FluidAura.Cast(target)) return true;
      
      	//cast stone2 if nothing else needs to be casted
      	return await Spells.Stone2.Cast(target);
      }
      [/HIDE]

      The above code is how a Coroutine would work in a Combat Routine. Everything in the above code can be debugged easily by adding a breakpoint on any of those lines to be able to see exactly what it is doing. Something that is a little harder to do in a typical TreeSharp implementation.

      Something else that should be pointed out is that you can work within both contexts if you chose. Here is another example:

      [HIDE]
      Code:
      internal Composite Coro => _coro ?? (_coro = new Decorator(p => AuthenticationProvider.Client.IsAuthenticated && BotManager.Current.EnglishName == "Fate Bot" && NeedToStart, new ActionRunCoroutine(p => Start())));
      [/HIDE]

      Notice how I'm setting the Composite to a Decorator(TreeSharp) so that I can check a boolean condition so that the context of my ActionRunCoroutine only actually triggers when that boolean condition is true.

      The above logic is something I use in Plugins as part of a LogicBase class so that when I make a new behavior, it just inherits this and overrides NeedToStart and the Start() method.

      I apologize if this is all too lengthy of an explanation, but it's really hard to see the benefits of using Coroutines instead of TreeSharp's without seeing what a Coroutine implementation actually looks like.

      If you want more insight on Coroutines, I highly recommend reading this post (must be logged in to navigate to it) https://www.thebuddyforum.com/honorbuddy-forum/community-developer-forum/162972-using-coroutines-logic-development.html

      And if you are interested in more Coroutine logic building, feel free to send me a PM.

      -Wheredidigo
       
    8. Teo

      Teo Member

      Joined:
      Oct 6, 2012
      Messages:
      35
      Likes Received:
      1
      Trophy Points:
      8
      Thanks Wheredidigo. Hopefully that thread you posted is enough evidence for Aevitas to add coroutine support to buddywing
       
    9. Cryogenesis

      Cryogenesis Moderator Moderator

      Joined:
      Jul 13, 2010
      Messages:
      2,128
      Likes Received:
      13
      Trophy Points:
      38
      But is debug the only plus or are there more?
      Like Speed, stability and the likes?
       
    10. Teo

      Teo Member

      Joined:
      Oct 6, 2012
      Messages:
      35
      Likes Received:
      1
      Trophy Points:
      8
      Using as an example the existing Cooldown routine for Marauder Fury, this:
      Code:
              public override Composite Cooldowns        {
                  get
                  {
                      return new LockSelector(
                          Spell.Buff("Cloak of Pain", ret => Me.HealthPercent <= 50),
                          Spell.Buff("Undying Rage", ret => Me.HealthPercent <= 10),
                          Spell.Buff("Saber Ward", ret => Me.HealthPercent <= 30)
                          );
                  }
              }
      
      would become:
      Code:
              public override async Task<bool> Cooldowns()
              {
                  if (Me.HealthPercent <= 50 && await Spell.Buff("Cloak of Pain"))
                      return true;
                  if (Me.HealthPercent <= 10 && await Spell.Buff("Undying Rage"))
                      return true;
                  if (Me.HealthPercent <= 30 && await Spell.Buff("Saber Ward"))
                      return true;
                  return false;
              }
      
      This might look slightly complicated as it will need Spell.Buff and Spell.Cast to be changed to support it, but, it eliminates the use of the LockSelector in Cooldowns as well as the use of 2x Decorator and 2x Action objects in Spell.Buff and Spell.Cast.

      It will be faster as no matter how optimized the BehaviourTree is, a Decorator can't compete with a simple If statement.

      This is a really simple example. The first post in the thread posted goes into a lot more detail. Can't understand most of it but am slowly getting there :).
       
    11. alltrueist

      alltrueist Active Member

      Joined:
      Dec 10, 2012
      Messages:
      1,424
      Likes Received:
      16
      Trophy Points:
      38
      The actual coding of the rotations would be a piece of cake. I'm able to do rotation coding for classes I don't even play (and I have zero knowledge of coding). The issue is that we'd need someone to code all the Unit.cs, HealingManager.cs, Targeting.cs stuff, because there's no way I can fake my way through that quagmire.
       

    Share This Page