Tool Flow part II

I finally got around to doing the second part of this article.

In the first part I was describing some of the cool things you can do with external tools in terms of what they do behind the scenes. In this part I want to focus more on the actual GUI’s that get presented, and what you can do to make them more effective.

The first thing to realise is that generally there are two types of tool GUI – one is something affects a data stream, but that doesn’t generate data. An example of that would be a tool that collates shaders together, or something that pre-processes a model from .3ds to game ready format. These tools are about throwing a few switches, selecting a bunch of files and pressing the Process button.

The second type is actual data generation. The actual building of shaders, or the definition of in game objects, or perhaps a visual scripting system.

The first kind of tool GUI’s (that of data collators) are often the result of a programmer who has realised he needs to present a front end for some data manipulation, and bangs something out in MFC at 3am to get the job done. It’s often bare bones, with everything you can do / all the switches and buttons on the main dialog.

The second type is often more thought out in terms of design, but is still often designed in a vacumn, ie it’s designed on it’s own with only an eye to what it’s ultimate function is by itself, not in relation to other tools.

Either way, most of these tools are designed from a function aspect, rather than a usage aspect. What I mean is that these days it is not enough that a tool does what it needs to, but that it presents it’s options and abilities in an easy to use fashion. Most UI’s are just the exposing of the back end functionality through a dialog front end, which I argue a) makes the front end very specific, b) makes it so you have to understand exactly what the back end does in order to use it properly and c) means that you have to climb into whatever spaghetti paradigm that programmer was thinking about when he wrote the system (which usually means you have to understand the difference between Objects and Instances and all that jazz).

In order to get the best out of a tool, it often means divorcing what the tools does from how you present it. Thats a conceptual jump which most tools guy don’t make (and usually for a reason – you need a tool, you make a tool, it does what it needs to do, you move on) and it’s usually the reason why tools are barely used for their intention, let alone loved by those using them.

So all that in mind, I present a few rules for making good tool UI’s. (Yeah, ok 1 and 2 aren’t really GUI things. Sue me:) )
NOTE – most of this stuff is directed at external tools – ie tools that run on a PC and not in the game engine. Some of this applies to both in game tools, but most do not.

Rules for good Tools

1. Make sure the tool is batchable. By that I mean the tool can be run in batch mode from a dos batch file (or python or whatever else you might want to run it from), and can take incoming params that specify individual files or a file name of batches of files to process. It also needs to spit out a text log of what happened in that process.

2. The tool needs to log whatever it is doing in terms of reaction and in terms of what it was asked to do – this enables debugging of the tool plus it also allows those using it to see what it’s doing and what the results are. This log needs to go to a file as well as some visual logging facility (I talked a bit about this last time in terms of having a separate app that just handles logging, allowing you to filter what logging you want to see).

3. All of your tools should do things like remembering screen positions and sizes of the dialogs when they were last shut down. You should also remember things like file list selections, child dialogs open and so on. Imagine it to be the same as a game save file – when you reload a game save file it restores you to the state you were in when you left the game. A tool should do the same.
NOTE – keep track of the resolution of the machine being used. If that changes, reset all the positions of dialogs to default. This avoids the “dialog off screen” problem you can run into if someone moves their screens around or changes resolutions.

4. All dialogs should be resizeable – this has implications since it means that you don’t want many buttons on screen because that means moving their positions and you don’t want to do that. So if you have buttons, make the top left in the dialog.

5. If you have a selectable control – what I mean by that is I have a drop down or list box of variable numbers of objects (particle definitions, game objects, whatever) then do NOT have the fields dialog on the same dialog. Hmm. That is confusing. Ok, so imagine you have a list box of particle effects. If you select one, you shouldn’t be filling in empty data fields on the same dialog as the list box – you should be generating a new child dialog with those details in them. As long as you don’t make this child dialog modal, it means you can have the details of many objects on screen, rather than just the one in the original design of having details displayed on the same dialog as the selection box.

6. Make everything as non modal as you can. People should be able to flip around having lots of dialogs open.

7. When you generate child dialogs (ie allowing more than one), allow interoperability between them. E.g. being able to copy a field (or fields) from child dialog a to child dialog b. This is HUGELY important.

8. When doing actual processing inside a tool, don’t be afraid to use other threads to do the processing. Then the tool you are using can still a) respond to you and b) can update in real time.

9. When setting up basic operations, take a good long look at what the data is you are asking for, and how it relates to the operation of a tool. What I mean by that is put the stuff that changes the most from usage to usage of a tool on the front dialog, and stick the rest on an “Advanced” tab. That which changes infrequently needs to be hidden, otherwise users will get confused in terms of “whats important and I need to address now” and whats not. Present what’s changing this time round and hide the rest.

10. Set up sensible defaults for all the other stuff. And don’t be afraid to do processing to figure out what those defaults actually are, rather than trying to set defaults for everyone.

11. Have view modes / permission modes for your tools. By that I mean have a modes where you can turn features off easily depending on who’s using the tools. Producers shouldn’t be modifying specifics of object definitions and so on. I’m quite keen on the idea of physically not even showing features and settings that a class of user shouldn’t be messing with – you don’t get producers telling you they should be able to tweak stuff they have no business tweaking if they don’t even know that feature is there. However the reality is that most of the time the best you can do is just turn this stuff off – otherwise it’s two sets of dialogs to maintain for any tool.

12. Use the windows defaults. Yes, just do it. Stop going on about Emacs and Key Bindings. Many people will use this tool and almost all of them will have used the defaults windows stuff of ctrl-c to copy and ctrl-v to paste. Just do what everyone else does and no one will complain.

13. Put some bloody help in there. I insist on properly formed contextual help in my tools, because often *any* explanation is better than none.
Note – one thing to include in help is some implication explanation. It’s not enough to say “This button turns on dynamic shadowing on this object” – you need to give the user some idea of what that means to frame rate.

14. Post processing implication data mining. If you are doing processing on data in a tool, it’s often nice to actually look at the output and do some diving from it. If you can tell from this particle definition that it’s going to generate a million plus particles, its probably a good idea to bring that to the attention of the person who just processed it, via both the log AND some in your face dialog.

15. Tools that manipulate in game visuals (like object placement tools, or particle definitions) need to have accurate preview. By that I mean that as you manipulate variables, you should see what the result will look like in engine. Many tools people spend time making a PC version of the engine then use parts of that (the renderer etc) in the tools. I’m less keen on doing that these days since that often means shaders have to be written three times – once for the 360, once for the PS3 and now once again for the PC. I’d rather see what it looks like in situ – ie with the same resolution and environment as it will be on the final product. This means real time communication between your tool and the game engine, or the writing of the tool in the game engine to begin with.
There are some situations where this really helps if the external tool is not really designed with game development in mind – maya can often choke on what a game engine can display with no problem, since the engine is designed for it and maya is not.

16. Tool interoperability. I’ve already talked about being able to cut and paste between dialogs – this bit is on one tool being able to talk to another. Take, for instance, a tool that packs your files together for a pack file. You have a nice big list of these files in some window. It’s great if you can double click on any file in that list, and the relevant file is loaded in it’s specific tool and brought up. This just makes everyones life easier.

17. Include whatever library systems you use as part of your tools. Going back to part 1, this can be a separate DLL that talks to your specific library system (P4, CVS, etc), and each tool individually talks to that using a common API. Then, if you switch from SVN to P4 or Alien Brain, you just replace that one API and you are done. No other tools need to change. Having to go external to check out files blows.

18. Keep the tools working. Everyone hates a crashing tool, and it often happens that even if you as a tools guy fix the crash, most of the users don’t realise it and just work around it, which blows. If it’s functional and non crashy to begin with then everyone is much happier from day 1.

19. Further to 18 – get something out there asap. Get someone using the tool as soon as you can. Don’t put it on general release, just get someone using it quickly. Now, in relation to point 18, that means give them something that is featurally stunted but functionally stable. IE give them something that doesn’t do a lot, but what it does do it does in a stable fashion.
By rolling out stuff incrementally, it a) makes you look good since you are actually giving tools to people in a timely and deliberate fashion, b) promotes morale and c) gives the people using the tool the essential feedback process while the tool is still being developed, which is massively necessary for a successful tool.
Producing a plan that takes 6 months, then burying yourself for 6 months before you produce the 100% completed plan at the end of 8 months (which is what always happens) is a fast way to either get the tool canceled or to produce something that is almost, but not quite what people actually need.

20. Get buy in on the tool design before you start. Now that means doing the full requirements and technical plan before you go in there, which is essential. But also realise that no plan survives intact contact with the enemy, which is why point 19 is so important. It’s good to have a destination to go towards and a plan to get there, but it’s equally important to be able to fix that which doesn’t work in the plan on the way. An ounce of prevention and all that….

In Engine or External?

There’s a school of thought that says that tools should be internal to the engine. If you are planning on shipping tools, I tend to agree with this. You get to use the real engine code and everything is tight.

However, if you aren’t going to ship your tools I am firmly of the belief that your game engine should have just that which you intend to ship in it and no more.

Obviously you will need hooks in the engine, but I personally only want the code in there necessary for playing the game, not lots of extra stuff that might or might not get tested and break tools without the developers ever realising it until they come to use them again.

This also makes batching tools very hard to make if they are in the game engine.

There is an argument for having external tool DLL’s that might or might not be loaded – this might work it might not. I’ve done it in the past and when it has worked, its worked beautifully. But it’s a bitch to set up and get right, and a real nightmare to maintain because it sets up certain dependancies between tools and actual in game functions. When the tools are 100% external you usually have one point of contact and not a myriad of functions to call, which makes tracking down game engine functional changes and tools breaking.

Final Thoughts

The bottom line here is to understand what the tool is for and do the job appropriately for that task, while understanding the bigger picture that this tool will fit in.

That means that while you may make the greatest particle definition tool in the world, if it’s meant to fit into a pipeline that requires it to work in batch mode, you’d better be thinking about how you do that when you start work.

It also means that having some overall rules about your entire tools system is a must – rules like “if we change any item in the tool suite, we can see the changes in the game either instantly, or at worst within 2 minutes of pressing the BUILD button”. Remember, iteration is king here.

Remember, at the end of the day you are making a Game and that the tool is there to facilitate that.

I hope this helps!

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>