New!! The Archives have been cleaned up, fead links fixed, and printable versions restored! Also, don't miss the new comments on the front page!

Livin'
With The Sims:
theAntiELVIS explores the wild and wacky world that is Will Wright's The Sims,
asking the inevitable quesiton, "is The Sims the first step toward a virtual
life where everyone is Swedish?"

"A page of history is worth a pound of logic." - Oliver Wendell Holmes,
Jr.

oday,
we'll be taking another step into the realm of actor logic by starting
our discussion of multiplayer networking. In the next article
I'll introduce the first part of our networking implementation (such
as the low-level Winsock code and other odds and ends) to the code base,
but for today I'll be sticking purely with discussion, partially due
to personal time constraints and partially due to a deliberate desire
to get you guys thinking about all this well in advance of seeing what
ends up in the code. The low-level code will go in first, but
that's the easy stuff, comparatively speaking. All it needs to
do is handle sending packets of data from somebody to somebody else.

As for determining exactly
what data to send and who to send it to, that's another
story entirely, and this is where networking code is really made or
broken. We'll be handling this topic gradually over the course
of the rest of the project (since finetuning the data usually works
that way), but I'll do what I can to talk about some fundamentals here
in this article. Even if you never touch the COTC code base, the
stuff in this article will likely still apply if you plan on supporting
multiplayer networking in your own game project.

What's This Got To Do With
Cocktail Parties?

I've heard it said that the
rules of multiplayer programming are kinda like the rules of a cocktail
party. 1) It doesn't matter who you're talking to, as long
as people are talking. 2) You keep the conversation short
and sweet, or people will lose interest. 3) When someone
does lose interest, they still mutter a word or two on occasion
to feign interest and keep the conversation going, and 4)
All this work to keep up the conversation seems somewhat ludicrous considering
that nobody is saying anything truly important. :)

If you plan on supporting
multiplayer in your game, there are lot of rules and guidelines to follow.
A lot of these guidelines seem like common sense from the outside, but
once you get down to implementing things you sometimes have to watch
yourself to make sure you try and stick with them. Some of the
guidelines only carry the weight they do because of the bad experiences
that result when they're not followed, hence the quote at the top of
the article.

The first rule is undoubtedly
the most important. If you're thinking of supporting multiplayer,
plan for it early. Do not make the mistake that oh-so-many
developers / publishers / etc. have made over the past several years
by assuming that you can "toss in" multiplayer near the end of the project.
It does not work that way. Attempting to throw multiplayer
in at the last minute is virtually guaranteed to transform the last
phase of your project from a "normal" crunch hell into a full-blown
death march. Stop that nightmare before it happens, and plan ahead.
Get your basic networking mechanics (the low-level code, the decision
of peer-to-peer vs. client/server, and so forth) out of the way before
you dive head-on into game logic. The reason is simple: game logic
works differently when multiplayer is involved. If you're using
something like peer-to-peer, synchronization issues end up taking a
spotlight and you need quite a bit of code around the game logic stuff
to make sure things stay in check across all the players' machines.
If you're using client/server, the decisions regarding what differences
should exist between server and client machines (structures, variables,
and so forth) takes a front-row seat as well. And in all cases,
the breakdown of exactly what data needs to go over the network and
what doesn't is of major importance. Any way you look at it, multiplayer
needs to be planned beforehand. Ignoring this rule is committing
programmer hubris in the highest form. This also goes for your
publisher, if you have one. If you're not planning on multiplayer,
and if your publisher doesn't need multiplayer in the milestone spec
at the beginning of the project, then you might not need to worry about
any of this. But if you think, for an instant that they
are going to want to "feature creep" multiplayer support in at some
point during the project timeline, stop them before they do. The
"monkeys in suits" may not understand how important a choice this is,
but you should. Publishers and developers need to make a decision
on multiplayer from the start, and commit to it. If your publisher
won't commit to "yes we will have multiplayer" or "no we will not"...
to the point that there's no question about this in anybody's mind...
then prod them until they do. It's that important. I've
known way too many projects which either failed completely, or at a
minimum missed milestones by leaps and bounds, because of this mistake.

The rest of the rules are
more related to implementation, such as the second one: know your
data. Specifically, know what data really matters when it
comes to networking. Game actors (or entities, choose whatever
name you like) have a lot of stuff in them. Many multiplayer games
have actor structures with well over a hundred structure members.
The thing is, only a fraction of that data needs to be transmitted across
the network, depending on the specifics of the actor. In order
to be efficient, you have to know what data is relevant and how you
can most optimally get that data to other machines.

That rule often coincides
with rule number three: elimination is the best optimization.
Keeping packet size at a minimum makes the difference between life and
death in terms of network performance. You'll always have to compensate
for lag, but the less you send over, the less you need to compensate
for. Many people naively think that the best method of keeping
data packets small is to take the incoming data and use a generic compression
algorithm on it (RLE, LZW, whatever), thinking that it'll give them
optimal network efficiency. I have one thing to say to that: stierscheisse.
A one-size-fits-all compression routine will not work on actors which
have data that is anything but one-size-fits-all. The best way
to compress for multiplayer is to eliminate that which is unnecessary,
specific to the data that's being sent. For example, say
you have a dword in your actor structure that holds an ammo count.
If you know that the ammo can never be more than 999 in your game, then
why send more than 10 bits of the dword (a maximum of 1024) over the
network? Doing an RLE on a 32-bit value isn't guaranteed to fit
into 10 bits, but the raw value can if you take advantage of
information like this. Same thing goes for floating-point values.
If you know that three of your floats are components of a normalized
vector (i.e. they can only be between [-1,1]), and you want full float
precision, then you can bump the float into the range of +-[1,2] and
safely ignore the entire exponent block for those floats (8 out of 32
bits each) during network transmission. That's a whole byte lopped
off for each of those floats, with no loss of precision. If you
ARE willing to lose precision, you can save even more. Once again,
the key here is to know your data.

There's plenty of guidelines
beyond these three, but many of them depend on certain implementation
details (such as whether you use peer-to-peer or client/server, etc).
At the core though, a lot of them have their grounds in one of these,
so take them to heart. They seem obvious, but you'd be surprised
how many people neglect them. For our codebase we'll be implementing
a client/server model, so in addition to these three guidelines I'll
be going over some things specific to client/server as time goes on.

As you guys know, our project
doesn't have a rigid game chosen yet, and hence no rigid spec of what
an actor should be for our case. From what I know of the people
reading this series, though, almost all of you aren't nearly as concerned
with the project's game itself as you are with how it's being created.
I'm glad to see that, because it means the series is doing what it's
supposed to do... get you guys thinking on how this stuff applies to
you. Because of this, until the next article I want you
folks who are planning on putting networking in your game (a good 75%
of you are working on a game it seems) to take a bit of time now
and think about how you're going to do it. Like I said, you have
to plan early, so take some time to make a few choices before they bite
you. Are you going to go client/server, peer-to-peer, or something
more esoteric? What kind of stuff will your actors need in them?
Which machine(s) will need to keep track of those actors? How
small can you get the data you need to transmit over the network?
Put some thought into this stuff now, if you haven't already.
A lot of the data decisions depend on the game being made, so some of
this is stuff you simply have to work out on your own. Beginning
with the next article, and continuing throughout the rest of the project,
we'll see how COTC's codebase deals with these issues.