I’ve spoken to a few coders/owners of talkers privately this week, and its clear that the majority of you want “inline cname”. Whats been interesting about those conversations is the questions that you want covered. For most of you its “will it be easy to install and when can we download it?”, although one or two of you are interested in the “how is it done?”, “why is Spot’s version slower than Lokie’s?”, “Why doesn’t Silvers version work?”.
The first question is really easy to answer, it’ll be part of the big PGPlus patch/PGPlus Download I’ll put on the web once this is all done. If theres enough demand I’ll also split it out into a separate download.
Now for the fun technical stuff. Theres basically 3 ways to do inline coloured names. The first is really easy, and is the way most coders do it their first time. You start by installing Silvers cname code and placing nameof(p) in a few hundred places. Then you find the swear filter (its in parse.c) and a quick copy and paste drop that into some part of the code path and jobs done. Historically Trekkers Rest did it that way after a certain coder got drunk and was convinced having colours everywhere was a good idea (I’ve since sobered up!).
Now I hated inline cname so we let a year pass before I realise we can never get rid of that damn “”feature”” and coder pride means its time to do it properly. You can remove all of the nameof(p) calls, the hotwired swear filter, and replace it all with a simple check in process_output. For those of you that read the pstack_mid article you can see how a simple piece of state information allows you to ensure the correct colour after a replacement. You can take this even further by completely removing the default swear filter and moving that into process_output, and of course if you read the pstack_mid article theres a really great clue in how to stop people beating it with the old sh^Nit trick. For free you get to fix the swear filter, have a simple way of allowing users to switch on or off the swear and name filtering. Historically Trekkers Rest ended up doing it that way and TrueFriends when they acquired the code started by doing it that way.
The third way requires a little sideways thinking. lets forget the second way of doing things for a moment and look again at the first. Now I mentioned you could hotwire the old swear filter to do this job, I didn’t mention its a real pain if you leave it in the same place as the swear filter to allow users that hate the feature the ability to turn it off. But if you move it far enough down you can remove all the work that Silvers code requires and get an easy on/off switch. The logical place for that is in the tellplayer() function. Forgetting things like the emergency log and tell history… that would give you a tellplayer function that looks something like this in pcode:
void tellplayer(p, str)
tstr = process_dynatext(p, str);
tstr = process_cname(p, tstr);
tstr = process_output(p, tstr);
write_socket(p, tstr); /* yes I know process_output returns a file object, but lets keep things simple! */
I suppose we could waste a paragraph talking about some obvious optimisations. Instead of a players name, dynatext should use a players cname. Cname could precompute the client colour codes and save some work in process_output, and so forth….
Finished thinking about cool optimisations and how to save work?
Okay back to the present… no matter how good your optimisations are, method 2 will take 2/3rds the time of method 3. What we have is 3 linear search and replace routines each with their own specialised domain knowledge. Dynatext looks for sequences beginning with ‘<‘, cname/swear looks for words, process_output looks for ‘^’ and ‘\n’. From a holistic point of view they are all the same code!
The third method is about exploiting the fact that what we’re about to send to the user is really a sequence of tokens that require processing, and that instead of having 3 specialised pieces of code to handle that processing we can replace it with a single generalised piece of code. Not only is that far quicker and more memory efficient, but should we decide to add additional tokens (such as smileys, more colour codes, inline images, sound, non telnet support) we can deal with them in the same place.
And Truefriends uses an output system based on those ideas, oh and I renamed ‘cname’ to ‘filtered output code’ as cname no longer seemed appropriate.
Whilst most of you want me to now post a download link, my aims are somewhat different. I want people to understand the code, or at least the rationale behind some of the decisions that shaped it. And so this post is about saying “hey this is why my code performs better than someone else’s, this is the secret sauce I used to solve this problem in what I hope is the best way” and hopefully some of you will go off and experiment. The rest, well I’ve got a few cool projects between here and there that will not only improve your talker, but hopefully give you some further insights ready for when we tackle the feature most users instantly notice.