Multiplayer Mode  C   P 

The multiplayer engine uses a client/server mechanism for playing a game over a local area network or the Internet. One of the connected machines - or more precisely, one of the running applications (there can be several on the same PC) - is the server that controls the game play. All others are clients that are assigned to the players.

Sending and receiving level updates is automatically handled by the engine; there's no script required for this. This way, every 3D game you create is already a network game once the engine is running in server or client mode. A dead reckoning algorithm ensures smooth movements of the entities, and minimum bandwidth use. Anything else but the level status update - for instance, input values from keys or joystick on the clients, or text strings for chatting or exchanging messages - is sent between clients and servers by simple script commands. Therefore writing a network game requires some additional code in the script. An example of a 3D online game can be found in the multiplayer workshop of the tutorial. A 2D multiplayer example - pong_multiplayer.c - can be found in the samples folder.

Some hints for programming a multiplayer game

For setting up a multiplayer network, first select the server machine. The server has the most communication to do and should be running on the machine with the fastest network connection. It must be started first, either using the -sv command line option, or the session_open command. The server can be a client at the same time - thus you won't need to dedicate a separate PC for it. When the server is running, further clients can connect or leave any time by starting the same application with the command line option -cl, or by using the session_connect command. The Commercial Edition  C  has a limit of one server and 8 clients per session; the Pro Edition  P  has no limits.

As soon as the connection is established, the predefined variable connection changes from 0 to 1, 2, or 3, dependent on whether the engine is running as server, client, or both. Normally the same script runs on the server and on clients, for sharing the same global variables and the same entity functions. The program can determine through the connection variable whether the application is running in server or client mode, and then execute different code. Any number of game sessions can run on the same local area network or the same Internet address. A client always connects to the session with the same name, which is the name of its script by default. Each client has also an individual player name, which is either given by the -pl command line option, or created by script (player_name) or by the engine.

Server and clients should always use the same script. This makes is easy to set up and maintain a multiplayer game. If you don't want to allow user of your game to start a server, make the server functions dependent on a special command line option, or on a validation code from a file that you just don't distribute to your end users.

Multiple servers running the same game, but different levels, can be started on the same machine or on several machines. Different session names and different port addresses must be used when starting multiple server instances. The client can switch fom one server session to another through the session_connect command. This way, a huge level can be split in multiple zones, which run on different server instances, or even on different machines. For observing what's happening on a dedicated server with no client, you can activate a console window that prints every server event (command line option -sv -diag).

All communication is normally handled by updating global variables, text strings, and entity properties between the between servers and clients. For sending there are several send_... instructions. Receipt of a message or special multiplayer events trigger an event function on the receiving machine. For instance, whenever a client connects to the server, the predefined on_server event on the server is triggered, with event_type set to EVENT_JOIN and a string pointer set to the client's name handed over as parameter to the event function. This mechanism is identical to entity event handling.

A reliable protocol is used for essential messages like joining or transmitting variables or strings, while a faster but unreliable protocol is used for frequent repeated messages like entity updates. The protocol, packet size, and other parameters can be customized and modified through the various dplay_.. variables, but normally their default setting is the best.

By default, entity actions run on the server only, and the server permanently updates all visual entity properties to the clients in time intervals given by dplay_entrate. One might be tempted to set dplay_entrate as low as possible for smoother entity movement. This would work on a LAN, but is not recommended for online games. For playing over the Internet, the bandwidth should be minimized by keeping dplay_entrate high, but controlling entity effects, animation, or sounds on the client side. The easiest way for this is running entity actions both on server and clients by setting dplay_localfunction before loading a level, and let them do different things depending on the connection status. Alternatively, the server can start a special client side function for an entity (proc_client). If a certain entity parameter, like entity.frame, is controlled on the client, it's corresponding NOSEND_.. flag must be set to exclude this parameter from the automatic update messages.

The dead reckoning algorithm linearly predicts rotation, velocity and acceleration of entities. This 'smoothes' entity movements on slow client/server systems with high latency time, but abrupt entity movement changes, like the stopping of an elevator or the ricocheting of a bullet, can mislead the algorithm and lead to an 'overshoot' effect. To prevent this, use the ent_sendnow instruction when an entities' speed or rotation changes abruptly.

Global variables and strings are not automatically synchronized between server and clients. Thus they may contain different values on server and clients, if not synchronized on purpose through send_var or send_string instructions. Care should be take here to only send values that have changed - otherwise you'll waste bandwidth.

If an entity was created by a client through the ent_create instruction, it will come into existence and start its action on the server. Each client can control his own player entity through send_skill instructions - normally the keyboard or joystick input is sent this way to the server and used there to move the client's player entity. If the client disconnects, he can't send further skill values, so his player entity will remain motionless. Event_disconnect can then be used to remove the entity.

A description of the engine's multiplayer protocol can be found under Client/Server Protocol.

Example (lite-C):

////////////////////////////////////////////////////////////////////////////
// simple LAN game
////////////////////////////////////////////////////////////////////////////
 
action player_move() // control the player on the client, move it on the server
{    
  var walk_percentage = 0;
  while (1) 
  {
    if (my.client_id == dplay_id) { // the following code runs on the player's client only
      my.skill1 = key_w - key_s; // forward/backward
      send_skill(my.skill1,SEND_UNRELIABLE|SEND_RATE); // send movement request to the server
      my.skill2 = key_a - key_d; // left/right rotation
      send_skill(my.skill2,SEND_UNRELIABLE|SEND_RATE); // send rotation request to the server
    }

    if (connection & CONNECT_SERVER) { // the following code runs on the server only
      my.pan += my.skill2*5*time_step;   // rotate the entity using its skill2
      var distance = c_move(me,vector(my.skill1*5*time_step,0,0), NULL, GLIDE); // move it using its skill1
      walk_percentage += 1.5 * distance;
      ent_animate(me,"walk",walk_percentage,ANM_CYCLE); // animate the entity
    }
    wait (1);
  }
}

function main() 
{
  if (!connection) 
    error("Start first the server, then the clients!");
  else 
    while (dplay_status < 2) wait(1); // wait until the session is opened or joined

  dplay_localfunction = 2; // run actions both on server and client
  level_load ("multiplayer6.wmb");
  vec_set(camera.x, vector (-600, 0, 100)); // set a proper camera position

  if (connection & CONNECT_SERVER)  // this instance of the game runs on the server
    ent_create ("redguard.mdl", vector (100, 50, 40), player_move); // then create the red guard!
  else // otherwise, it runs on a connected client
    ent_create ("blueguard.mdl", vector (-100,-50, 40),player_move); // create the blue guard
}
A description of this example, and hints for further optimizations can be found in the multiplayer workshop.

Hints for writing good online games

Online games have to overcome two basic internet bottlenecks: bandwidth and latency. In that regard the internet is like a conveyor belt. Bandwidth is the width of the conveyor belt and dictates how much data you can send along it at once. Latency is the length of the belt and states how long the clients have to wait for messages from the server to arrive, and vice versa.

Some remarks on MMORPGs

An often asked question: Please advise how to do a MMORPG with Gamestudio!

An online game with ten thousands of players is one of the most ambitious game projects. A MMORPG consists of a huge game world divided in zones that are distributed over several servers. Such a server park usually consists of a portal server, several zone servers, and one or more database servers. The user data is stored on the database server - for instance in a MySQL database - and updated by the zone servers. The access from the zone servers to the database must be provided through a script or DLL adapted to the database type and user data structure. The game engine handles the frontend (the clients) and the zone gameplay. The client switches between zones trough the session_connect command.

As you can see from the above description, creating a MMORPG - no matter with which engine - is definitely not a hobby project. It requires good knowledge of the structure of multiserver systems, and good programming knowledge (or some iron will to aquire such knowledge). The A7 network features are easy to use, but running a massive multiplayer online world still involves a lot of coding, a good team, and last but not least, good funding. It often makes sense to develop a simple one-server version of the game first as a prototype for acquiring the funds for a database license and a server park.

► latest version online