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