tag:robotlegs.tenderapp.com,2009-10-18:/discussions/suggestions/7-macro-commands-and-command-chainingRobotlegs: Discussion 2018-10-18T16:35:07Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392009-12-21T15:56:32Z2009-12-21T15:56:32ZMacro Commands and Command chaining<div><p>MacroCommand would be a prime candidate for a utility (add-on).
I don't these types of utilities getting added to the core
framework or the MVCS implementation.</p></div>Joel Hookstag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392009-12-21T18:23:10Z2010-07-15T13:27:24ZMacro Commands and Command chaining<div><p>Hi Will,</p>
<p>We've had some chats on the discussion group around Commands -
but mostly around Async Commands. As Joel mentions, an
extension/addon would be the way to go here. I've got a bit of a
case of "analysis paralysis" trying to figure out the best way to
approach:</p>
<p>Command History (undo/redo)<br>
Asynchronous Commands<br>
Command Chaining / Macro Commands</p>
<p>If you have an immediate need for Macro Commands, this can be
achieved easily by extending Command into MacroCommand and adding a
method like this:</p>
<pre>
<code> protected function callCommand(commandClass:Class, event:Event = null):void
{
var command:Object;
if (event)
{
var eventClass:Class = Object(event).constructor;
injector.mapValue(eventClass, event);
command = injector.instantiate(commandClass);
injector.unmap(eventClass);
}
else
{
command = injector.instantiate(commandClass);
}
command.execute();
}</code>
</pre>
<p><strong>UPDATE:</strong> Robotlegs 1.1.x introduces
ICommandMap.execute() which makes the info above unnecessary -
commands can be directly executed through the Command Map without
being bound to events. ICommandMap.detain() and release() have also
been introduced to easily enable Async Commands.</p></div>Shaun Smithtag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-03-16T10:37:59Z2010-03-16T10:38:01ZMacro Commands and Command chaining<div><p>Well this isn't very elegant, but seems to produce the expected
results (ie., calling them in the right order) if you aren't after
asynchronous command stringing. In your MacroCommand, use the
following (the oneshot parameter will unmap the simple commands so
there should be no conflict with anything else):</p>
<p>`override public function execute():void {</p>
<pre>
<code>commandMap.mapEvent("macro", SimpleCommand1, null, true);
commandMap.mapEvent("macro", SimpleCommand2, null, true);
dispatch(new Event("macro"));</code>
</pre>
<p>}`</p></div>Rigard Krugertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-04-20T04:37:47Z2010-04-20T04:37:48ZMacro Commands and Command chaining<div><p>Is there any addon or util for robotlegs, where Async Macro
Command is implemented? And where I can find it?</p></div>Denis Borisenkotag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-15T13:06:11Z2010-07-15T13:06:12ZMacro Commands and Command chaining<div><p>I really love the robotlegs framework! But i am also missing the
Async Macro command like this one for PureMVC: <a href=
"http://code.google.com/p/asynccommand/">http://code.google.com/p/asynccommand/</a><br>
Is there still no Util for this?</p></div>Kimitag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-15T13:31:02Z2010-07-15T13:31:02ZMacro Commands and Command chaining<div><p>Probably not quite the answer you were looking for, but
Robotlegs 1.1.x introduces ICommandMap.execute() - commands can be
directly executed through the Command Map without being bound to
events. ICommandMap.detain() and release() have also been
introduced to easily enable Async Commands.</p>
<p>Personally I only develop things when I need them, and so far I
haven't had a need for the PureMVC style Async Macro commands.</p>
<p>If anyone does develop a nice utility for this we'd be happy to
make it official by forking it into the Robotlegs GitHub
account.</p></div>Shaun Smithtag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-15T13:56:41Z2010-09-19T12:42:44ZMacro Commands and Command chaining<div><p>Would I be correct in assuming that calling execute does not require the executing command to be added to the ICommandMap beforehand? It will simply be instantiated, injected and executed (assuming it extends Command)?</p>
<p>Also, is there any examples of using detain() and release()?</p></div>willdadytag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-15T14:07:26Z2010-07-15T14:07:26ZMacro Commands and Command chaining<div><p>Hi Will,</p>
<p>Yes, that's correct. Except that Robotlegs <strong>does
not</strong> require you to extend Command - any class that
declares an execute() method will work. Extending Command simply
gives you some commonly needed dependencies; you could easily
inject these yourself by declaring dependencies on the things you
need.</p>
<p>Regarding detain() and release():</p>
<pre>
// In some command
override public function execute():void
{
// hold on tight! pls don't GC me, kthnxbye
commandMap.detain(this);
// kick off some async process
}
protected function someCallback():void
{
// it's time to let go, yo
commandMap.release(this);
}
</pre></div>Shaun Smithtag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-27T08:30:16Z2010-07-27T08:32:52ZMacro Commands and Command chaining<div><p>When using commandMap.execute(myCommand, payload), how should
myCommand get access to the payload?</p>
<p>Is there an example anywhere?</p></div>stevebtag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-27T08:40:00Z2010-07-27T08:40:00ZMacro Commands and Command chaining<div><p>Hi Steve,</p>
<p>I don't use that approach, but I think it matches the usual
robotlegs way, so you'd simply do</p>
<p>[Inject] public var payload:PayloadType</p>
<p>in the command, and the injection should be fulfilled. (I'm
assuming that the manual execute leverages the existing
auto-execute functionality).</p>
<p>Give that a go, and if it's not working then I'll look into the
code deeper for you.</p>
<p>Thanks</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-07-27T18:15:27Z2011-05-02T13:30:52ZMacro Commands and Command chaining<div><p>That works fine. Thanks!</p>
<p>On Tue, Jul 27, 2010 at 9:42 AM, Stray <<br>
<a href=
"mailto:tender+dec08feac1705da790358e24ad9f2fa96452643ce@tenderapp.com">
tender+dec08feac1705da790358e24ad9f2fa96452643ce@tenderapp.com</a><<a href="mailto:tender%2Bdec08feac1705da790358e24ad9f2fa96452643ce@tenderapp.com">tender%2Bdec08feac1705da790358e24ad9f2fa96452643ce@tenderapp.com</a>></p>
<blockquote>
<p>wrote:</p>
</blockquote></div>stephen brydgestag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-11T16:48:09Z2010-08-14T17:57:47ZMacro Commands and Command chaining<div><p>Any updates on someone making a plugin for macro/sequenced commands? I would love to get my hands on that.</p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-11T16:55:06Z2010-08-14T17:57:47ZMacro Commands and Command chaining<div><p>If no one has an implementation already, please let me know and I make a fork and implement it.</p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-11T17:00:31Z2010-08-11T17:00:31ZMacro Commands and Command chaining<div><p>There is no RL specific implementation, but you could technically use external libraries to achieve this sort of functionality. There is no ned to fork Robotlegs to build this sort of thing. It is appropriate for an external utility, as is the general practice for extending/adding to Robotlegs.</p>
<p>It'd be great if you picked it up. Keep us updated.</p></div>Joel Hookstag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-13T14:52:02Z2010-08-13T14:52:02ZMacro Commands and Command chaining<div><p>Hey guys,</p>
<p>Riddle me this. So I'm working on a macro command (both sequence and parallel) where you would register subcommands in a manner somewhat like so:</p>
<p>If it's asynchronous:<br />
addCommand(new MyGoEvent(MyEvent.GO), MyCompleteEvent.COMPLETE, MyCompleteEvent);</p>
<p>If it's synchronous:<br />
addCommand(new MyGoEvent(MyEvent.GO));</p>
<p>When it's the command's turn to execute, the macro simply dispatches the event (it assumes you've wired up the command in the context). If it's asynchronous, the macro command watches for the specified completion event to determine that the command has completed execution.</p>
<p>That's all good. Where is gets a little tricky though is when you have a nested command setup like this:</p>
<ul>
<li>ParallelCommand
<ul>
<li>CommandB</li>
<li>SequenceCommand
<ul>
<li>CommandA</li>
<li>CommandB</li>
<li>CommandC</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The sequence command is nested within the parallel command. If both instances of CommandB are executing at the same time and one completes, the parallel and sequence commands don't know if the completion event corresponds to the instance of CommandB that that macro "encapsulates". In other words, maybe the CommandB that the sequence command initiated completed but the parallel command thinks the completion event pertains to the CommandB that the parallel command initiated.</p>
<p>I realize this issue is presented in RobotLegs in general and isn't specific to macro commands, but I'd optimally like to handle it without forcing CommandB to extend any specific class or dispatch a specific event that supports a token.</p>
<p>Thoughts?</p></div>Aaron Hardytag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-13T17:10:32Z2010-08-14T17:57:47ZMacro Commands and Command chaining<div><p>I just pushed my first run at Async and Batch commands up to github</p>
<p>In it you can run Sequence, Parallel, Composite, and Async commands.</p>
<p>I have documented it out pretty well. Please take a look and give any feedback and tell me what you think!</p>
<p>Library: <a href="http://github.com/cbrammer/RobotLegsMacroCommands">http://github.com/cbrammer/RobotLegsMacroCommands</a></p>
<p>Example: <a href="http://github.com/cbrammer/RobotLegsMacroCommandsExample">http://github.com/cbrammer/RobotLegsMacroCommandsExample</a></p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-13T19:16:08Z2010-08-13T19:16:08ZMacro Commands and Command chaining<div><p>Awesome Chase, it might be a good time to change the name of the repo - robotlegs-utilities-CommandLib (or something) just to be in line with the "official" repo scheme for naming things.</p>
<p>Robotlegs isn't camel-case (sorry to pick, it is a tic of mine ;) )</p></div>Joel Hookstag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-13T19:42:46Z2010-08-14T17:57:47ZMacro Commands and Command chaining<div><p>Cool, thanks for the feedback. Let me know if you have any other feed back, I just changed the name of the Repo (and the package names to match) to:</p>
<p>Library: <a href="http://github.com/cbrammer/robotlegs-utilities-CommandLib">http://github.com/cbrammer/robotlegs-utilities-CommandLib</a></p>
<p>Example: <a href="http://github.com/cbrammer/robotlegs-utilities-CommandLibExample">http://github.com/cbrammer/robotlegs-utilities-CommandLibExample</a></p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-14T04:47:31Z2010-08-14T04:47:31ZMacro Commands and Command chaining<div><p>Awesome, thanks :></p>
<p>I haven't had a chance to review the code yet. I am on a roadtrip with my wife and kids, but just from a glance it looks very clean and simple. I'd like to see it unit tested if you have the stomach for that sort of thing. Keeps in the spirit of the framework that way!</p></div>Joel Hookstag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-14T12:04:30Z2010-08-14T12:07:06ZMacro Commands and Command chaining<div><p>@Chase</p>
<p>Thanks for sharing your code with us. Nice work. There was a real need for such a utility.</p>
<p>Taking a closer look at your code:</p>
<p>MacroItemDescriptor.as<br />
/<em>*
* Keeps track if the command has started execution yet
</em>/ <br />
internal var executed:Boolean;<br />
</p>
<p>/<em>*
* Keeps track if the command has finished exectution yet
</em>/ <br />
internal var executionFinished:Boolean;<br />
</p>
<p>/<em>*
* Keeps track if the command completed successfully or not
</em>/ <br />
internal var executedSuccessfully:Boolean; <br />
</p>
<p>Maybe the naming of those vars is a bit confusing. If executed describes the start of the command’s execution, I would name it executionStarted or simply executing.<br />
What do you think?</p>
<p>@Aaron</p>
<p>is your solution something you’d like to share with us?</p>
<p>Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-14T15:28:02Z2010-08-14T15:28:02ZMacro Commands and Command chaining<div><p>@Ondina Yeah it's been crunch time on a project I'm on but when I get a break I'll dig into the issue a bit more.</p>
<p>@Chase I don't think you need those properties that Ondina mentioned. What's the purpose of them? If it's just for looping back over each of them in ParallelCommand, just handle it differently. You don't have to loop back through all the commands and see if they failed each time a command executes. When a subcommand calls your ParallelCommand's subcommandIncomplete() function, just mark your ParallelCommand as "having a least one failure" and be done with it.</p></div>Aaron Hardytag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-14T19:33:51Z2010-08-14T19:33:51ZMacro Commands and Command chaining<div><p>@Joel Thanks! I will add in some unit testing soon (hopefully in the next few days)</p>
<p>@Ondina So, thanks to your comment I think I come up with some changes that are better than they where before. Now there is an "executionStatus" var that has: waiting, executing, completed, failed.</p>
<p>In addition to that, I made it so that each command can watched for each of these execution status changes. I didn't want anything that extends command (Async, Macro, Parallel, Sequence) to dispatch events themselves, because Command itself doesn't do that and I don't think it is intended too. So, when each command is added, it returns the subcommandDescriptor class that contains all of the data about the command to be executed (Cmd Class, Payload, etc..) as well as the status of that commands execution. That subcommandDescriptor now dispatches events on any status changes. There are updated examples of this in the example project.</p>
<p>@Aaron I actually definitely need some type of indicator telling me what the status of each command. For example, that way I can wait for all parallel subcommands to complete their execution before the parallel command can recognize it is done. Hopefully with the change to using "executionStatus" will resolve any confusion though.</p>
<p>I also want to keep that status of each command on its subcommandDescriptor. That way when the subcommandDescriptor dispatches events about the status of its command, it is the only source of authority for the actual status.</p>
<p>Thanks for the help on marking a flag for having at least one failure, I just pushed a commit that incorporates that.</p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-14T20:26:28Z2010-08-14T20:26:28ZMacro Commands and Command chaining<div><p>Heads up if you guys want to review it, I just added in the ability to add programmatically created commands, and programmatically create batch commands</p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-15T04:44:31Z2010-08-15T04:44:31ZMacro Commands and Command chaining<div><p>Alright, here's my take on it:</p>
<p><a href="http://github.com/Aaronius/robotlegs-utilities-Macrobot">http://github.com/Aaronius/robotlegs-utilities-Macrobot</a><br />
<a href="http://github.com/Aaronius/robotlegs-utilities-MacrobotDemo">http://github.com/Aaronius/robotlegs-utilities-MacrobotDemo</a></p>
<p>This will give you a quick view of a complex macro command:</p>
<p><a href="http://github.com/Aaronius/robotlegs-utilities-MacrobotDemo/blob/master/src/org/robotlegs/utilities/macrobot/sample/commands/MyMacroCommand.as">http://github.com/Aaronius/robotlegs-utilities-MacrobotDemo/blob/ma...</a></p>
<p>Docs and tests forthcoming.</p></div>Aaron Hardytag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-16T06:48:31Z2010-08-16T06:55:48ZMacro Commands and Command chaining<div><p>I asked for it!!<br />
Now I have a hard time deciding which one to use.<br />
I think both solutions are good. Two very interesting approaches.</p>
<p>@Chase the SubcommandExecutionStatus looks very good</p>
<p>@Aaron I like the name Macrobot (Mac Robot / Macro Bot / Macro Robot) I will play around with your example as well and come back with questions or comments.</p>
<p>Hopefully other people will give input on these 2 approaches as well.<br />
Cheers</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-16T11:36:02Z2010-08-16T11:36:24ZMacro Commands and Command chaining<div><p>I'll wait on community feedback before investing time learning on of them :)</p></div>Nikos tag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-17T01:20:07Z2010-08-17T01:20:07ZMacro Commands and Command chaining<div><p>Alright! I just finished up Unit Testing my library. The unit tests are available here:</p>
<p><a href="http://github.com/cbrammer/robotlegs-tests-CommandLib">http://github.com/cbrammer/robotlegs-tests-CommandLib</a></p>
<p>I also update the project name of the example to fit into the RL naming scheme better to:</p>
<p><a href="http://github.com/cbrammer/robotlegs-demos-CommandLib">http://github.com/cbrammer/robotlegs-demos-CommandLib</a></p>
<p>@Ondina Thanks, I think it is a good way to handle individual command instance triggers</p>
<p>@Aaron, I don't think that there really needs to be two different libraries, I would like to merge our two and collaborate on any differences. Eh? Feel free to fork mine and I think that it could result it a better finished product.</p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-17T04:29:59Z2010-08-17T04:33:10ZMacro Commands and Command chaining<div><p>Chase, I'd love to have a single library but I'm having difficulty finding something to merge from CommandLib that would improve the codebase of Macrobot. There are some fundamental elements of CommandLib that are impairing:</p>
<ul>
<li>The developer has to extend AsyncCommand if they're going to do anything asynchronously (rather than implementing an interface).</li>
<li>Stores unnecessary information regarding command status (I mentioned this in my previous comment).</li>
<li>Manipulates arrays unnecessarily.</li>
<li>Uses events unnecessarily.</li>
<li>Loops through arrays unnecessarily.</li>
<li>Exposes and touches command descriptors in more classes than necessary.</li>
</ul>
<p>I did some quick benchmarking in an AS project by executing 1000 commands (that extend AsyncCommand but are not truly asynchronous--to keep timer overhead out of the equation). I found the following on average:</p>
<p>SEQUENCE:<br />
Macrobot: 23ms<br />
CommandLib: 31ms</p>
<p>PARALLEL:<br />
Macrobot: 21ms<br />
CommandLib: 212ms</p>
<p>I also attempted to run a nested command benchmark by running a sequence command with 100 child parallel commands with each parallel command having 10 async commands like this:</p>
<p>`</p>
<pre><code> var parallel:ParallelCommand;
for (var i:uint = 0; i < 100; i++)
{
parallel = new ParallelCommand();
for (var j:uint = 0; j < 10; j++)
{
parallel.addCommand(MyCommand);
}
addProgramaticCommand(parallel);
}</code></pre>
<p>`</p>
<p>It broke on CommandLib though because the library only injects into non-"programmatic" commands and since ParallelCommand (programmatic in this case) is dependent upon commandMap being injected, it throws a null pointer.</p>
<p>Macrobot runs the procedure in 27ms.</p>
<p>There's also twice as much code in CommandLib with no additional functionality in my understanding. I want to be sensitive but I don't want to beat around the bush either. I would literally be copying all my code into your repo. If you see anything that would improve Macrobot though I'm all ears.</p></div>Aaron Hardytag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-17T08:37:00Z2010-08-17T08:37:00ZMacro Commands and Command chaining<div><p>Hrmm, well, I made some changes, and got CommandLib to do that same test for Parallel Command, and i was able to take it down to about 8ms average, so about 3 times as fast.<br />
</p>
<p>Also, a large reason why I have more code, is because I comment it out so much. If I wanted to abbreviate everything I could condense it much more.</p>
<p>Congrats, you stepped in and finished something I volunteered to tackle, way to go champ.</p>
<p>BUT, you obviously aren't interesting in anything other people can offer. Best of luck working well with others in the future, I will stay clear.</p>
<p>Everyone, I retract any solutions I had to offer.</p></div>cbrammertag:robotlegs.tenderapp.com,2009-10-18:Comment/7501392010-08-17T12:39:01Z2010-08-17T12:39:01ZMacro Commands and Command chaining<div><p>Hey guys, thank you both for tackling this - it's always great to see people put effort into open source endeavors. I'm a little saddened by the direction the conversation has taken however.</p>
<p>I haven't had a chance to review either codebase, and even if I had, I'm not the best person to do so because I haven't come across a direct need for this kind of utility in any of my projects (so far). With that in mind:</p>
<p>@Chase: I wouldn't be too offended by Aaron's review. In fact, getting a code review, even if all the points are negative, is almost always a good thing. It takes guts to put code online for criticism, I understand that. But you have to follow that up with the ability to accept criticism gracefully. He could have been more sensitive, yes, but ultimately it's up to you to decide how you accept criticism: either you take it personally, or you use it to improve your code.</p>
<p>@Aaron: As I said, I haven't actually reviewed either codebase, but for any RL utility to be taken seriously it must have a set of unit tests to prove that it works.</p>
<p>Personally, I hope that you'll both reconcile your differences and decide to collaborate. But, even if you don't, I still think this is a good opportunity to sharpen your solutions by competing (in a healthy manner of course!).</p></div>Shaun Smith