RTS3 is
the codename for Ensemble's next-generation strategy game. The RTS3
design builds on the successful formula used in the Age of Empires series
games, and calls for a number of new features and multiplayer requirements.
Builds
on the feature set of Age of Empires 1 and 2. Design
requirements such as internet play, large diverse maps, and thousands
of controllable units are a given.
3D
-- RTS3 is a fully 3D game, with interpolated animation and non-faceted
unit position and rotation.
More
players -- possible support for more than eight players.
TCP/IP
support -- 56k TCP/IP internet connection is our primary target.
Home
network support -- Support end-user home network configurations including
firewalls and NAT setups.
With RTS3,
we made the decision early on to go with the same underlying network
model as Age of Empires 1 and 2 -- the synchronous simulation
-- because the RTS3 design played to the strengths of this architecture
in the same ways. With AOE/AOK, we relied on DirectPlay for transport
and session management services, but for RTS3 we decided to create a
core network library, using only the most basic socket routines as our
foundation and building from there.
The move
to a fully 3D world meant that we had to be more sensitive to issues
of frame-rate and overall simulation smoothness in multiplayer. However,
it also meant that our simulation update times and frame-rate would
be even more prone to variation, and that we would be devoting more
time overall to rendering. In the Genie engine, unit rotations were
faceted and animations were frame-rate locked -- with BANG! we allowed
for arbitrary unit rotation and smooth animation which meant that the
game would be visually much more sensitive to the effects of latency
and see-sawing update rates.
Coming
out of development on Age of Kings, we wanted to address those
critical areas where more up-front design and tool-set work would give
the biggest payoff in terms of debugging time. We also realized how
important the iterative play-testing process was to the design of our
games, and so bringing the multiplayer game online as early as possible
was high priority.
An
OO approach. RTS3's network architecture is strongly object
oriented (see Figure 6). The requirements of supporting multiple network
configurations really played to the strengths of OO design in abstracting
out the specifics of platform, protocol, and topology behind a set of
common objects and systems.
The protocol
specific and topology specific versions of the network objects have
as little code as possible. The bulk of the functionality for these
objects has been isolated in the higher-level parent objects. To implement
a new protocol, we extend only those network objects that need to have
protocol specific code (such as client and session, which need to do
some things different based on the protocol). None of the other objects
in the system (such as Channels, TimeSync, etc.) need change because
they interface with client and session only through their high level
abstract interfaces.
We also
employ the use of aggregation to implement multi-dimensional derivation
(such as with channels, that have an ordered/non-ordered axis of derivation,
as well as a peer/repeater axis of derivation) behind a single generic
interface. Virtual methods are also used for non-intensive notifications,
rather than using callback functions.
Peer
topology. The Genie engine supported a peer-to-peer network
topology, in which all clients in the session connect to all the other
clients in a star configuration. With RTS3 we have continued the use
this topology because of its inherent benefits when applied to the synchronous
simulation model.
The peer
topology implies a star configuration of connected clients in a session
(Figure 7). That is, all clients connect to all other clients. This
is the setup that Age 1 and 2 utilized.
Figure 7. A "star" configuration of peer-to-peer clients
in a session.
Peer-to-peer
strengths:
Reduced
latency due to the direct client-client nature of the system, rather
than a client-server-client roundtrip for messages.
No
central point of failure -- if a client (even the host) disconnects
from the session, the game can continue.
Peer-to-peer
weaknesses:
More
active connections in the system (Summation n=0 to k-1 (n)) -- means
more potential failure points and latency potential.
Impossible
to support some NAT configurations with this approach.
Net.lib.
Our goal when designing the RTS3 communications architecture was to
create a system that was tailored for strategy games, but at the same
time we wanted to build something that could be used for in-house tools
and extended to support our future games. To meet this goal, we created
a layered architecture that supports game-level objects such as a client
and a session, but also supports lower level transport objects such
as a link or a network address.
Figure 8. The four service layers of the network model.
RTS3 is
built upon our next-generation BANG! engine, which uses a modular architecture
with component libraries such as sound, rendering, and networking. The
network subsystem fits in here as a component that links with the BANG!
engine (as well as various in-house tools). Our network model is divided
up into four service layers that look almost, but not entirely, unlike
the OSI Network Model, if you applied it to games (see Figure 8).
Socks,
Level 1
The first
level, Socks, provides the fundamental socket level C API, and is abstracted
to provide a common set of low level network routines on a variety of
operating systems. The interface resembles that of Berkley sockets.
The Socks level is primarily used by the higher levels of the network
library, and not really intended to be used by the application code.
Link,
Level 2
Level
2, the Link Level, offers transport layer services. The objects in this
level, such as the Link, Listener, NetworkAddress, and Packet represent
the useful elements needed to establish a connection and send some messages
across it (see Figure 9).
Packet:
This is our fundamental message structure -- an extensible object
that automatically manages its own serialization/de-serialization
(via pure virtual methods) when sent across a link object.
Link:
a connection between two network endpoints. This can also be a loopback
link, in which case the endpoints both reside on the same machine.
Send and receive methods on a link know how to operate with Packets
and also with void* data buffers.
Listener:
a link generator. This object listens for incoming connections, and
spawns a link when a connection is established.
Data
stream: this is an arbitrary meter-able data stream across a given
link -- used to implement file transfer, for example.
Net
Address: a protocol independent network addressing object
Ping:
a simple ping class. Reports on the network latency present in a given
link.
Figure 9. The Link level.
Multiplayer,
Level 3
The multiplayer
level is the highest level of objects and routines available in the
net.lib API. This is the layer that RTS3 interfaces with as it collects
lower level objects, such as links, into more useful concepts/objects
such as clients and sessions.
The most
interesting objects in the BANG! network library are probably those
that live at the multiplayer level. Here, the API presents a set of
objects that the game level interacts with, and yet we maintain a game-independent
approach in the implementation.
Client:
this is the most basic abstraction of a network endpoint. This can
be configured as a remote client (link) or local client (loopback
link). Clients are not created directly, but are instead spawned by
a session object.
Session:
this is the object responsible for the creation, connection negotiation,
collection and management of clients. The session contains all the
other multiplayer-level objects. To use this object, the application
simply calls host() or join(), giving it either a local address, or
remote address respectively and the session handles the rest. These
responsibilities include automatically creating/deleting clients,
notification of session events, and the dispatch of traffic to the
appropriate objects.
Channel
and Ordered Channel: this object represents a virtual message
conduit. Messages sent across a channel will be automatically separated
out and received on the corresponding channel object on remote clients.
An ordered channel works with the TimeSync object to guarantee that
the ordering of messages received on that channel will be identical
on all clients.
Shared
Data: Represents a collection of data shared across all clients.
You extend this object to create specific instances that contain your
own data types, and then use the built in methods to enable the automatic
and synchronous updating of these data elements across the network.
Time
Sync: Manages the smooth progression of synchronized network time
across all clients in a session.
Game
Communications, Level 4
The communications
level is the RTS3 side of things. This is the main collection of systems
through which the game interfaces with the network library, and it actually
lives within the game code itself. The communications layer provides
a plethora of useful utility functions for the creation and management
of multiplayer-level network objects and attempts to boil down the game's
multiplayer needs into a small easy to use interface.
I have a couple of bones to pick over this article actually (despite it being written in 2001).
1) LAN play with AoE1 with TCP/IP was slooow compared to IPX, why was this?
2) I was playing Rise of Nations with a friend of mine on a LAN, and I believe, having played AoE2 to death, that RoN was heavily based upon AoE2. We won an Axis vs Allies game against 3 AI opponents (we were Germany/Japan) which was absolutely fantastic, and as a way of extending the fun we decided to watch the replay. It was fine at first but at some stage, just prior to the turning of the tide in our favour, history was changed -- my side stopped doing anything (whilst my mate's side carried on) and and the AI pushed... and the Allies won...
Oh man. I can remember playing AoE for HOURS on "The Zone"... It didn't always work great, but I was more than happy with it. It was a big step forward. Ah, I loved it back then, no 12 year old's screaming into my headphones.
1) LAN play with AoE1 with TCP/IP was slooow compared to IPX, why was this?
2) I was playing Rise of Nations with a friend of mine on a LAN, and I believe, having played AoE2 to death, that RoN was heavily based upon AoE2. We won an Axis vs Allies game against 3 AI opponents (we were Germany/Japan) which was absolutely fantastic, and as a way of extending the fun we decided to watch the replay. It was fine at first but at some stage, just prior to the turning of the tide in our favour, history was changed -- my side stopped doing anything (whilst my mate's side carried on) and and the AI pushed... and the Allies won...
What's with that? :)