Tuesday, August 25, 2009

JavaScript Particle Systems part 2: adding some life

The frame below shows a demonstration of the particle system we are about to build. Move your mouse through it to have some fun. If it doesn't work for you, click this link to open the same demo in a popup window.

Introduction

A few months ago I wrote an article that demonstrated how to create a very simple particle system in less than 50 lines of JavaScript code. That article has slowly been finding its way into the Google search indexes and by now it's becoming obvious that I'm not the only one who thinks particle systems deserve more attention and JavaScript is the perfect language to experiment with them. Back then I was quite pleased with being able to implement a fully functional particle system in less than 50 lines of (quite readable) JavaScript code. But I think we can agree that the particle system was not very exciting. Although the system contained all three required ingredients, the end result was a bit "static". From games and other places where particle systems are used, we are used to them being a lot more "alive". So that's the goal for this article: to add some life to our previous particle system, while still keeping it small. In this case I've increased my self-imposed limit to a 100 lines. A generous doubling from our previous system, so we'd better have some real interesting "life" to show for the increase. We'll add three behaviors to the particle sytem.
  • Gravity
  • Grow then shrink
  • Mouse control
Lot's of work to do, so let's get started with gravity straight away.

Gravity

In our first particle system, the particles would fall at a constant speed. The fall speed of each particle was determined at random when creating the particle.
      dy: Math.random() + 0.5
And then we just updated the y position every time:
      particles[i].y = particles[i].y + particles[i].dy;
I always find it very interesting to add some gravity-like behavior to systems I create. So how about making the particles fall at an increasing speed?
      p = particles[i];
      p.y += p.dy;
      p.dy += 0.1; // simulate gravity
So we increase the particle's y velocity every time we update its position. I realize that to make this work like real gravity I'd have to know the particle's mass and do a multiplication. But for this simple example just increasing the dy is already convincing enough. Since the particle will now drop at an ever increasing speed, it is nice to make it go up a bit at first:
      dy: -1 + Math.random()
So the particles will first move up a bit and then start falling down at an increasing speed. If all goes well, they'll move in a nice arc-like pattern. Again there is no real math or physics reason for these values, these just looked best to me. If you feel the need to make the system more physically correct, just download the source and go ahead. Let me know if you find an interesting combination.

Grow then shrink

Another thing I wasn't too happy with in the original particle system is the static size that the particles have. Each particle is created to be 3px in width and height. By the way: there was a bug in the original code such that the sizing didn't work in Internet Explorer. As my team often tells me: "you need to test more with IE Frank!" My bad. Let's hope I got it right this time. I changed the code to shrink the particle a bit in each update:
      p.s -= 0.1
This of course requires the particle to have a size when we create it:
      p.s: 3.0
With this setup the particle will slowly shrink from 3 pixels width and height to 0. Once the size of the particle reaches 0, we can kill it:
      if (p.ttl-- > 0 && p.s > 0) {
         updateParticleElement(p);
This leads to a working particle system, but somehow it's still a bit boring when all the particles start and shrink at the same speed. So let's make the size change random and instead of just shrinking, let's make the particles grow at first and then shrink until they die out. For the initialization the change is simple:
      p.ds: Math.random()+0.1,
This gives the particle a growth speed that is guaranteed to be positive. So instead of adding 0.1 each time we update the particle, we add the ds:
      p.s += p.ds;
If we leave this unchanged, the particle will grow forever - or at least until it's time to live runs out. To ensure the particle also starts shrinking at some point we give it a maximum size:
      if (p.s > 5) p.ds *= -1;
When the particle reaches its maximum size, we just flip the sign of the growth speed - so it becomes a shrink speed. After this the particle will keep shrinking until it reaches size zero at which point it dies out. By now I'm not really sure if the ttl property is still needed, as the particles already have an implicit time to live and get their randomness from the growth/shrink speed. But I left the ttl in as a safeguard against my own mistakes when manipulating the size. I wouldn't want to end up with an infinitely living and growing particle by mistake. If you would reconstruct the particle system at this point it is already quite lively and dynamic. Particles seem to be attracted by the bottom of your screen and particles seem to have a real life cycle, where they grow and shrink to die out. But this particle system is still a spectator sport. Let's see what happens when we give the user some control over what happens on screen.

Mouse control

As our last feature we want to give the user some control over the behavior of the particles. Specifically I want to accomplish two things:
  1. particles originate close to the position of the mouse cursor
  2. particles move roughly in the direction that the mouse is moving
To accomplish this we need to add four variables to the system.
      mx and my - the position of the mouse
      dmx and dmy - the direction and speed of the mouse's movement
These variables are global to the script, so they are not stored for each particle. These variables are updated whenever the user moves the mouse, by hooking the onmousemove event of the window. The mousemove handler is a bit tricky to read at first. But since the behavior of the particles only depends on the four variables mentioned here, I will not explain the mousemove handler of the code further. Now how do we use these variables when creating and updating a particle? The variables are actually only used when we create a new particle:
      x: mx,
      y: my,
      dx: dmx + Math.random(),
      dy: dmy + Math.random() - 1,
As you can see the code remain quite similar to how it was. We've just substituted our new "mouse dependent" variables for the previous hard coded and random values. We still make the dx and dy a bit random, since otherwise all particles would go in the same direction. The updating of the particles doesn't have to change for this behavior. The mouse just allows the user to control the position and the direction of the initial movement. After its creation each particle behaves as the rules of our system dictate, which ensures the particles still behave similar even with al their differing properties.

Summary

So in the first article we created a simple particle system in less then 50 lines of JavaScript code. The system was fully functional, but felt a bit static after you'd been looking at it for a while. In this second article we've added life to our particle system by adding by:
  1. making the environment a bit more "physical" with our simple gravity emulation
  2. making the life cycle of the particles more complex, by making them grow and then shrink and die out
  3. allowing the user to control the particles, by hooking their position and movement up to the mouse movement
All in all our particle system has now gotten quite complex. But weighing in at 90 lines, it is still well under my self-imposed limit of a 100 lines of code. I did my best to keep the code readable again and even added some constants to make it easier to change and debug the particle system. Now go ahead and play with the system. I find it's great fun to see how far up you can throw the particles. Remember: this is controlled by moving the mouse, so start pushing and pulling your mice!

The code

// constants
var NUM_PARTICLES = 50;
var FPS = 20;
var PARTICLE_LIFETIME = 4; // in seconds
var ANIMATION_LIFETIME = 300; // in seconds

// global variables
var container;
var particles = [];
var framecount = 0;
var mx = 20; // default origin, will be set to mouse position once the mouse moves
var my = 20;
var dmx = 1.0; // default movement, will be set to mouse movement once the mouse moves
var dmy = -1.0

function onMouseMove(e) {
 var IE = document.all?true:false
 var nmx, nmy;
 if (IE) { // grab the x-y pos.s if browser is IE
  nmx = event.clientX + document.body.scrollLeft
  nmy = event.clientY + document.body.scrollTop
 } else {  // grab the x-y pos.s if browser is NS
  nmx = e.pageX
  nmy = e.pageY
 }
 dmx = (nmx - mx) / 4;
 dmy = (nmy - my) / 4;
 mx = nmx;
 my = nmy;
}

function createParticle(container) {
 var p = {
  elm: createParticleElement(),
  x: mx,
  y: my,
  s: 0.0, // size
  dx: dmx + Math.random(),
  dy: dmy + Math.random() - 1,
  ds: Math.random()+0.1,
  ttl: PARTICLE_LIFETIME*FPS
 };
 container.appendChild(p.elm);
 updateParticleElement(p);
 return p;
}

function createParticleElement() {
 var elm = document.createElement('span');;
 elm.style.border = '1px solid blue';
 elm.style.position = 'absolute';
 return elm;
}
function updateParticleElement(p) {
 p.elm.style.width = p.elm.style.height = p.elm.minWidth = p.elm.minHeight = Math.floor(p.s) + 'px'; // doesn't work on IE
 p.elm.style.left = Math.floor(p.x) + 'px';
 p.elm.style.top = Math.floor(p.y) + 'px';
}

function updateParticles() {
 for (var i=particles.length-1; i >= 0; i--) {
  var p = particles[i];
  p.s += p.ds;
  if (p.s > 5) p.ds *= -1;
  p.x += p.dx;
  p.y += p.dy;
  p.dy += 0.1; // simulate gravity
  if (p.ttl-- > 0 && p.s > 0) {
   updateParticleElement(p);
  } else {
   container.removeChild(p.elm);
   particles[i] = createParticle(container);
  }
 }
 if (framecount++ < ANIMATION_LIFETIME*FPS) {
  setTimeout('updateParticles()', Math.floor(1000 / FPS));
 } else {
  alert("All done. Reload to watch again.");
 }
}

window.onload = function() {
 container = document.getElementById('particles');
 for (var i=0; i < NUM_PARTICLES; i++) {
  particles[i] = createParticle(container);
 }
 
 setTimeout('updateParticles()', Math.floor(1000 / FPS));
 document.onmousemove = onMouseMove;
}
Download it here. And the corresponding HTML:
<html>
    <head>
        <title>JavaScript Particle System</title>
        <script type="text/javascript" src="particles2.js"> </script>
    </head>
    <body>
        <div id="particles" style="width:640px; height: 480px; overflow: hidden"> </div>
    </body>
</html>
Download it here.

See also

Saturday, July 25, 2009

Seven rules to keep your twitter followers

With Jon's recent "top 40 list of CMS gurus" I suddenly got a lot of additional followers. And I added quite a few of those people to my twit-list too. From the first few days it looks like I might start unfollowing some soon, but there's definitely a few that are a great addition to the list. While scrolling through recent tweets, I sought what makes tweets interesting for me and things that I really don't like. So here is the list (in random order) of do's and don'ts to keep my as your follower on twitter.

1. Yet another link retweeter

"RT @cmswire Open Source for America: Change We Can Believe In? http://bit.ly/r9sj6 #opensource #oss"
"RT @cmswire 39 More Ways to Get Your CMS Twitter Fix http://bit.ly/YiV9I"
"RT @OpenText #OpenText Completes #Vignette Acquisition http://cli.gs/bUvzsN"


There's nothing wrong with retweeting something interesting you've heard somebody say. But if all you tweet is other people's tweets, I'd much rather listen to those other people.

2. Your opinion matters to me

Personal tweeting is fine. I love to hear what friends and family are doing. But from people that don't fall into those categories, I don't need:

"Ottawa Organic Market on Bank.... "

Don't just tell me that you're at an organic market in whatever city. If we're not emailing or calling each other at least once a week, chances are I don't care that much about your whereabouts. Sounds harsh? It's not meant to be harsh.

Because I apparently care enough about your opinion to follow your tweets. So how about you tell me your opinion on that market.

"the Ottawa organic market is really the best"

3. Challenge me

Even better, don't just tell me your opinion. Tease me to give you mine. It's OK to do a bit of trolling as long as long as you don't mind getting trolls back too.

"the Ottawa organic market is really the best, certainly beats the one in Amsterdam"

Now that's a great way start to a discussion. Because I really, really LOVE the organic market in Amsterdam.

4. Don't forget I'm eavesdropping

One of the worst things you can do to me on twitter is to start a 1-on-1 conversation with somebody where you forgot that I'm still there reading along.

"Sorry? Barbecue where? Are you kidding me?"

What barbecue are you talking about? Where is it? Am I invited too? If you don't want to let me know these things, why are you sending your private message as a public tweet?

Remember: if you want to have a private conversation, there is always still email or Google talk. Or even better dm in twitter.

But if you feel like you want to share your conversation with the world, give me enough context.

5. Give me context

If talking to someone in a public tweet, make it clear who you're talking to.

"@john123 glad you liked the post!"

It certainly beats the tweet about that barbecue. Because here I can at least check the other part of the conversation in john123's tweet stream. But still, giving me a bit of context goes a long way.

"@john123 glad you liked the post! http://is.gd/1JyHY"

One click and I'm at the post. But then again, why not just retweet the original and add your comment to it:

"glad you liked the post! RT @john123 good analogy on how to mix persuasive content with relational data in modern CMS. http://is.gd/1JyHY"

Phew... 138 characters, that's cutting it close. But it has as much context as you can add to your tweet.

6. Tell me something I can use

A friend was apparently enjoying a milkshake a bit too much and had to share it with the world:

"Just had the best strawberry milkshake ever"

I like reading it, because I always love to hear about good food - especially from someone whose taste buds I trust.

But how am I going to be able to do something with that? Tell me where you had that milkshake. Believe me, I'd love to know - even if it is a three hour drive.

"had the best strawberry milkshake ever at Mill Creek near Mineral, NoCal"

Honey start the car, we're going for a drive!

7. I don't need more spam^H^H^H^H marketing

Corporate tweeting is hot these days. There are many corporate twitter accounts that are easily recognizable, because they consist of the company's name. But there are also plenty of innocent-looking names that generate a remarkable number of tweets that simply reiterate how great product xyz is or how well product abc would solve the problem I'm (not) having).

I don't have a problem with these accounts. We're all luckily free to tweet whatever we want. But if you'd like to keep your followers: keep your marketing to content ratio below 20%.

8. I read your blog already

Some people see link tweets as the natural progression of feed readers. I don't. I still have a healthy 100 or something feeds that I follow, just because they regularly show content that I like to read.

In other words: if you have a blog that is of interest to me, chances are it's already in my Google reader. So if all that you are tweeting is links to your blog posts, following you is not really adding any value for me. Now where's that unfollow link?

Mind you: there's nothing wrong with tweeting about your own posts. In fact that's what I'll do once I click the publish button for this post too. But if you want to keep me as a follower, be sure to add some original content into your tweets too.

And yours?


Those are the rules that sprang to my mind as I was scrolling through the rapidly growing stream of tweets. Do you have any rules of your own? How can I make sure that you don't click the "unfollow" link on me?

Monday, July 6, 2009

Safari 4 on Windows crashes when you provide incorrect credentials

Sorry for the long title of this post. But it is the most accurate description of a problem we're having in a project at the moment. Safari 4 on Windows seems to crash in what I perceive to be a common use case. Here are the minimal steps that I came up with for reproducing the problem:


  1. create a new web site in IIS

  2. enable integrated authentication on this web site

  3. connect to the new web site with Safari 4 for Windows

  4. provide incorrect credentials



At this point Safari 4 crashes on my system.

Providing correct credentials allows us to continue. But in the application my team is building, we will often encounter another authentication problems later on.

  • Safari pops up a log on box when we open a page from the same web site in an iframe. No matter which credentials we provide, we can't continue.


I've been searching whether this is a known problem for a while now. But I haven't found a single page that points out the problem we encountered here. Hence this simple write-up.

Has anyone had similar problems with Safari on Windows? If so, is there any way to work around the problem? Because as it is, we can't really support our application on Safari 4 on Windows. :-/

Saturday, May 16, 2009

Particle systems in JavaScript

Particle systems have always held some magic for me. Or maybe I should explain it more clearly: anything that resembles physics in a game-like fashion has always held some magic to me. In this post we'll look at how to create a simple particle system in JavaScript.

Pod racers


A few years ago when I wrote a small 3D pod racer for my own amusement. If you don't know what pod racers are, have a look at this video:



My game looked nothing like that of course. I'm a developer, not an artist. And besides I spent lots of time playing with the physics of the pod: where are the thrusters on my pod? How much force do the thrusters give? Does the force get exponentially bigger when the pod gets closer to the track? Fun stuff.

I also added a particle system to my pod. After all, those thrusters are bound to give off some exhaust fumes and this was a great way to give an indication of speed. And of course it was a great way for me to get started on particle systems.

As it turns out particle systems are really quite simple things. I had a blast playing with the parameters and figuring out how to create a most interesting effects.

Of course the pod racer was never finished and the source code has long been lost. That's why today we'll create a completely new particle system. In less than 100 lines of JavaScript. Granted it will only be 2D this time. But believe me, I've already been staring at the flow of particles longer now than it took me to write the script.

parts of a particle system



Let's get started with the three things that make up a particle system:

  1. an array of particle data structures

  2. a function that updates all particles each frame

  3. some form of lifetime management for the particles


Parts of a particle


First comes the particle data structure. What makes up a particle? If you've ever seen a particle system in its bare essentials, you'll have noticed that it consists of multiple small elements on your screen that each move on their own account, yet in a predictable and similar way.

This already means quite a few things. A particle apparently has a location on the screen. And since it moves, it must also have a direction.

var particle = {
x: 0.0,
y, 0.0,
dx, 0.5,
dy: 0.5
}

So this is a particle that is at position (0,0) and moves half a pixel to the right and bottom every time.

Creating an array of these objects is of course really simple.

function createParticle() {
return {
x: 0.0,
y, 0.0,
dx, 0.5,
dy: 0.5
}
}

var particles = [];
for (var i=0; i < 10; i++) {
particles.push(createParticle());
}

But of course these are really boring particles. They're all the same. Let's make the particles unique by adding a bit of randomness:

function createParticle() {
return {
x: 0.0,
y, 0.0,
dx, Math.random() + 0.5,
dy: Math.randon() + 0.5
}
}

var particles = [];
for (var i=0; i < 10; i++) {
particles.push(crateParticle());
}

So this creates 10 particles. They all start from the same location on the screen, yet move out in a different directory.

With that out of the way, let's move on to the behavior of the particles.

Particle behavior


As I said in the previous section, particles move in a predictable way. So we'll need a function that updates the position of each particle every frame.

function update() {
for (var i=0; i < particles.length; i++) {
particles[i].x = particles[i].x + particles[i].dx;
particles[i].y = particles[i].y + particles[i].dy;
}
}

And of course we'll need to call this function periodically:

setInterval("update()", 50);

Calling the update function every 50ms results in a 20 frames per seconds. This will give us quite smooth animation, without being too taxing for todays browsers/PCs.

lifetime management


We're almost done here. But if we would start this particle system now, the particles would just move away from each other indefinitely. That won't be very interesting to look at.

What we need to add is some way for the particles to die and for new particles to be born. The simplest way to do this for now is by giving each particle a lifetime counter at birth and just decrease that with every update.

Let's first update our createParticle function:

function createParticle() {
return {
x: 0.0,
y, 0.0,
dx, Math.random() + 0.5,
dy: Math.random() + 0.5,
ttl: Math.floor(Math.random()*50) + 50 // time to live in frames
}
}

We now defined that each particle will live between 50 and 100 frames. With a framerate of 20 frames per second, that will give the particles a lifetime of between 2.5 and 5 seconds.

Let's use this new property in our update function:

function update() {
for (var i=0; i < particles.length; i++) {
particles[i].ttl = particles[i].ttl - 1;
if (particles[i].ttl > 0) {
particles[i].x = particles[i].x + particles[i].dx;
particles[i].y = particles[i].y + particles[i].dy;
} else {
particles[i] = createParticle();
}
}
}

See the nice little trick we do here? We don't delete the particle, we just replace it with a new one. Of course the new particle will start at the origin again and will have its own direction and speed.

This way we will always have the same number of particles in our system.

visualize the particle system


I was not completely honest at the start here. There is actually one more step we have to take before we can see our particle system in action. After all what good is a particle system if you can't see it.

Up until now the particle system we've created is completely agnostic to the output system. If you use JavaScript for scripting your DirectX game, you might render these particles onto a DirectDraw surface. If you feel really "Linuxy" you might render them onto a 24x40 character display. But for our purposes here, we'll render the particles using HTML.

I'll just show the modified fragments here. For the complete script, refer to the end of the article.

We visualize each particle as a simple HTML span with a blue border:

function createParticle(span) {
return {
elm: span ? span : createParticleElement(),
...
}
}
function createParticleElement() {
var elm = document.createElement('span');
elm.style.border = '1px solid blue';
elm.style.position = 'absolute';
elm.style.width = elm.style.height = '3px';
container.appendChild(elm);
return elm;
}

When updating the particle, we also have to update its span. When the particles dies, we re-use the span for the new particle:

if (particles[i].ttl > 0) {
...
particles[i].elm.style.left = Math.floor(particles[i].x) + 'px';
particles[i].elm.style.top = Math.floor(particles[i].y) + 'px';
} else {
particles[i] = createParticle(particles[i].elm);
}

demo


The frame below shows a demonstration of the particle system we just built. If it doesn't work for you, click this link to open the same demo in a popup window.

next steps


As you can see this particle system is about as simple as it can be. Real particle systems in games and simulations are of course much more complex. But the basic ingredients stay the same:

  1. an array of particle data structures

  2. a function that updates all particles each frame

  3. some form of lifetime management for the particles


If there is interest in it, I would like to make this post the first of a series where we investigate particle systems. If that is the case, the next step will be to make the particle system a bit more interesting by adding some "physics-like" behavior to it.

the finished script


This is the complete script needed to run this particle system. If you count them, you'll see that it is only 47 lines of code. So you can create an (admittedly simple) particle system in less than 50 lines of code.

var container;
var particles;

function createParticle(span) {
return {
elm: span ? span : createParticleElement(),
x: 0.0,
y: 0.0,
dx: Math.random() + 0.5,
dy: Math.random() + 0.5,
ttl: Math.floor(Math.random()*50) + 50 // time to live in frames
}
}

function createParticleElement() {
var elm = document.createElement('span');
elm.style.border = '1px solid blue';
elm.style.position = 'absolute';
elm.style.width = elm.style.height = '3px';
container.appendChild(elm);
return elm;
}

function update() {
for (var i=0; i < particles.length; i++) {
if (i == 0) console.log(i+' '+particles[i].ttl);
particles[i].ttl = particles[i].ttl - 1;
if (particles[i].ttl > 0) {
particles[i].x = particles[i].x + particles[i].dx;
particles[i].y = particles[i].y + particles[i].dy;
particles[i].elm.style.left = Math.floor(particles[i].x) + 'px';
particles[i].elm.style.top = Math.floor(particles[i].y) + 'px';
} else {
particles[i] = createParticle(particles[i].elm);
}
}
}

window.onload = function() {
container = document.getElementById('container');
particles = [];
for (var i=0; i < 10; i++) {
particles.push(createParticle());
}

setInterval("update()", 50);
}

Download it here

The corresponding HTML:

<html>
<head>
<title>JavaScript Particle System</title>
<script type="text/javascript" src="particles.js"> </script>
</head>
<body>
<div id="container" style="width:320px; height: 200px"> </div>
</body>
</html>

Download it here

Friday, April 17, 2009

mstsc /console doesn't work anymore

Summary: instead of calling mstsc /console /v:servername you should now use mstsc /admin /v:servername.


This post should really go under the category: what were they thinking?

In our company we use a product that for licensing reasons really wants to make sure that only a single instance of the application is running. One of the things the developers have done to ensure this, is not allowing the application to be started on a remote desktop session. Otherwise: you could install the program on a single machine and let multiple users initiate remote sessions on that machine and this violate the license agreement. Now I'm not saying I agree with this type of licensing setup, but the software is pretty good and we want to make sure we're not doing anything illegal with it.

So what we came up with was setting up a server with the software and then asking developers needing the tool to connect to the console session on that server using Windows' Remote Desktop Connection. The console session is (from the little that I understand of it) the first session that is started on a machine. So even on a terminal services server, there is only one console session. Connecting to it is quite simple from a command prompt:

mstsc /console v:machinename

The chances of two of our users needing access to the tool at the same time are pretty slim, so this setup actually worked for us quite well for the last year or so. Until last week that is.

Suddenly I was getting reports from one of my team members that he couldn't start the tool due to a licensing error. He checked and double checked, but seemed quite sure that he was using the correct command line. I walked up to the server myself and tried to start the tool - it started without problems. So I left the tool running for him and told him to try again. He did... and said the tool wasn't there when he connected!

Anyone with enough experience with multi-session machines knows that this means the remote desktop was in another session than the one I started the application in. But how could that be? My team member clearly told mstsc to connect to the console session.

A few Google searches later, I found the answer. Now keep in mind: the problem occurred and was solved last week. But just writing about it here, still makes me angry - very angry with some people at Microsoft.

What happened is that a team at Microsoft found out that there was a security issue with the way terminal services worked. So they changed the logic of console vs. administrative sessions for security reasons. Nothing wrong with that - I appreciate security as much as the next guy.

So they now separate the real session 0 from the first GUI session. Sounds good. I am no security expert so I don't know if it helps, but I'll take their word for it. But they didn't stop at that. Somebody then also decided that the /console option of the remote desktop client should not be called /console anymore. After all you might not be always be able to connect to the console anymore - on newer servers it would connect you to the first, typically administrative GUI. So they relabeled the "console" session to the "administrative" session. Relabeling is not wrong - I appreciate clarity as much at the next guy.

So instead of calling mstsc /console /v:servername you should now use mstsc /admin /v:servername. All clear - nothing wrong with that.

All of this so far is fine and can be explained to anyone. But this of course leaves one decision to be made: what do you do with the existing /console option? What do you do with all those existing scripts that might already use mstsc /console in the expectation that they end up connected to the console session?

And this is where they did something that I don't understand, that I really, REALLY, REEEAAAALLLY don't understand. They decided to in some cases start ignoring the /console option. So with some versions of the remote desktop client, using mstsc /console will end you up in the console/admin session. And in other versions of the remote desktop client, using the same command will end you up in a completely normal session.

Even after a week of thinking about it, I still don't understand why somebody would decide to silently start ignoring the /console a command line switch that users might depend on. The switches of a command line tool are pretty much the API that you expose to the outside world. Whole build scripts have been built against command line tools based solely on the fact that the switches that are there will not change. Switches might be added, but nothing ever gets dropped. Except at Microsoft I guess. There some genius decides that in some cases they would start silently ignoring the /console option on the command line. See this post on the exact behavior in all cases or read this one for non-Windows-2008 servers. Don't expect to understand the logic after that, but at least it is clear that they've spent a lot of time on this change. And after last week: so have I.

I know not to expect an apologetic phone call from Redmond on this, nor do I really expect them to change the behavior of the mstsc client. Instead I'll just warn my fellow programmers and be on the lookout for remote desktop sessions that don't behave like I expect them to.

Ok... time to breath in and breath out, count to ten and do my exercises. And get back to work of course. Now what was I working on?