Workshop 1: Connections

In this Workshop you will learn, how to build up/breakdown a connection and how to use the connection events!

Initializing a server


Let's see how a server is initialized and why we need events:

//Lite-C:

function client_connected(var sender, char* msg, var length)
{
//...
}

function client_disconnected(var sender, char* msg, var length)
{
//...
}
function init_server()
{
enet_init();
enet_svset_event(EVENT_CONNECTED, client_connected);
enet_svset_event(EVENT_DISCONNECTED, client_disconnected);
enet_init_server(2300, 4, "PaSsWoRd!");
}

Ok, let's talk about the function init_server(). First of all ENet is initialized, because our server will use ENet. After that we assign the functions client_connected() and client_disconnected() to the CONNECTED and DISCONNECTED events. After that we initialize the server. The server listens to port 2300 and allows max. 4 connections. Additionally only clients that sent the correct password can connect.
So far, so good! But what are the 2 events for? It's simple: The function that is assigned to the EVENT_CONNECTED, client_connected(), will be called if a client connects. Logical the function that is assigned to the DISCONNECTED_EVENT will be called if a client disconnects. Every function that is assigned to an event should have the parameters "var sender, char* msg, var length". sender in our case will hold the ClientID (more to come) that connected/disconnected and msg and length aren't used.

If a server should be closed enet_destroy_host() can be used!

You can initialize only one server per application (window). But you can open more applications with each of them having a server running. But be aware that every server has to listen to a different port! More than one server is used in multizones (HowTo 3).

Initializing a client


Let's see how a client is initialized:

//Lite-C:

function connected(var sender, char* msg, var length)
{
//...
}

function disconnected(var sender, char* msg, var length)
{
//...
}
function init_client()
{
enet_init();
enet_clset_event(EVENT_CONNECTED, connected);
enet_clset_event(EVENT_DISCONNECTED, disconnected);
enet_init_client("localhost", 2300, "PaSsWoRd!");
}

As you can see, the code isn't really different to the one in which the server is initialized. The EVENT_CONNECTED is called if a connection to the server is established and EVENT_DISCONNECTED is called if the connection is lost. The parameters sender and msg aren't used. With enet_init_client() a client is initialized. The client connects over the port 2300 with a server that was started on the same machine (=> "localhost").

In contrast to the servers, clients can be initialized on the same machine without using different ports. But only one client per application can be started.

The connection to a client can only be disconnected by the server. The server has to call enet_disconnect_client() for that. The client can only disconnect if it calls enet_destroy_host(). The disadvantage is that it will take a given timeout before the Client Disconnected Event is called on the server!

Sending data


Now that you know how a connection between a server and a client can be done, you are only one function call away from sending data. There is one function that can be used for sending nearly all kind of data:

//Lite-C:
var test_var = 0;

function client_to_server()
{
test_var = 10;
enet_sendto(test_var, SERVER);
}

function send_to_client0()
{
test_var = 20;
enet_send_var(test_var, 0);
}

If the function client_to_server() is called on the client, the variable test_var is set to 10 and then sent to the server => test_var is 10 on the client and on the server. If more clients will connect later or are already connected, then test_var will still be 0 on the other clients. This is, because the new value of the variable is only sent to the server. For sending a variable to all connected clients, BROADCAST has to be used for the second parameter.
If the second function is called on the server, the value 20 of the variable test_var is sent to the client with the ClientID 0. The ClientID is returned by the function enet_get_clientid() on the clients. You can get the ClientID on the server for example through the Client Connected Event. After calling send_to_client0() test_var is 20 on the server and on the client with the ClientID 0.
The function could also be started by a client. test_var would be 20 on the sender then and on the client 0.

All in all, with the second parameter the receiver of the data can be set where SERVER is always the server and BROADCAST is always a broadcast (=sending at all).

Attention: If a server and a client exchange data and a new client connects, the new data won't be updated on the new client automatically! => in our example, test_var would still hold 0, although on all the other clients test_var would be 10. But the new data can be sent easily from the server to the client, when the Client Connected Event is called on the server.

Closing words


With this knowledge you can already create easy multiplayer games like a simple 2D game (like Pong). An appropriate example can be found on the download site of ANet. But please note that the code is optimized to produce less traffic. Because of this it's more difficult to read than a "normal" code.
The next step should be to read the second workshop "Simple 3D Chat". With this workshop the just learned will be refreshed and applied in a practical example. Additionally you will learn how to use entities in a multiplayer game and how to create a simple chat. Also things like level changing and Dead-Reckoning will be discussed.