Winsock Tutorial using the dll made by 39ster

2 player pong

In this tutorial i will teach you how to use my winsock dll to create a online game. I will use
Pong as my example game.

Initializing the dll.
For the dll to function you need to link the functions inside the dll to your game. To do this simply put in the
creation code of the first room:
dllinit(0, true, false);

If the first argument is a number then the dll will load the dll file "39dll.dll". If this is a string then the string will be
the name of the dll. e.g If the first argument is "sock.dll" then the dll file must be named "sock.dll" and it will load it
using that filename.
The second argument is true if you want to use winsock. In this case we do. The third argument should only be
true if we want to use the file functions. In this example this is not needed so we wont load those functions from the
dll.

Setting up the server.
To create a multiplayer game, one person needs to host the server and the other person needs to connect.
To set up a server using my dll you first need to create an object which controls the setting up of the server
and accepting any new connection. What you will need to do is create a menu that has 2 buttons. The first
button says "Host" and the second button should say "Connect". When the user selects host, make it execute
this code "global.master = true;" and make the room change to a room called "rmWaiting". Create a new 
object and call it "objWait". In the create event of this object add this code:

listen = tcplisten(14804, 2, true);
if(listen <= 0)
{
  show_message("Failed to listen on port 14804");
  game_end();
}

What that piece of code does is create a listening socket that will listen for any incomming connections on port
14804. The port number can be whatever you want but i have used 14804. The second argument is the maximum
allowed connections in the waiting list. This is not the maximum allowed people in the game. When someone tries
to connect they are put on the waiting list until the server accepts them. The last argument is set to true because
we want the listening socket to not freeze the game when you are using the tcpaccept script and no one is has tried
to connect. The script will return a socket identifier number that is bigger than 0 if we succeded. A number <= 0 is returned
if an error occured.
The next line checks if we are succesfully listening on port 14804. If the socket identifier is smaller than or equal to 0 then
an error occur so we end the game.

Accepting new connections. 
To accept new connections you need to create a step event for the "objWait" object we created. In the step event add this code:

client = tcpaccept(listen, true);
if(client <= 0) exit;
global.otherplayer = client;
room_goto(rmGame);

The first line checks the waiting list to see if someone tried to connect to the listen socket. If no one connected then it returns a
number smaller than 1. If someone did connect then it creates a new socket and returns its id. This socket will now be used to
send and recieve data from the person who just connected. The second argument in tcpaccept means the new socket will
be non-blocking. In this case when you are trying to recieve a message it will not freeze the game if their is no message to be
recieved.
The second line checks if tcpaccept returned an error. If it did then it exits the script.
The third line and fourth line will only be executed if their was no error. The thrid line sets the global variable "global.otherplayer"
to the socket id that tcpaccept() returned.
The fourth line goes to the playing room. (you needed to create that room btw).

Connecting to the server.
To join a multiplayer game we need to connect to a server. In the room where you have the button "Host" and the button "Connect", make
it so when the player clicks connect it executes this code:
global.master = false;
server = tcpConnect("127.0.0.1", 14804, true);
if(server <= 0)
{
  show_message("Unable to connect to server");
  game_end();
}
global.otherplayer = server;
room_goto(rmGame);

The first line sets the global variable "master" to false. This is because we are not the server. We are the client connecting to the
server. The second line makes the actual connection to the server.
The first argument in tcpConnect is the ip address you want to connect to. If you are just testing locally use the address "127.0.0.1".
The second argument is the port number to connect to. The third argument is wether to use blocking or non blocking mode. We
set it true which means non-blocking. This makes it so whenever we try and send or recieve a message, the game doesnt freeze
until the operation finished. If tcpConnect succesfully connected and was accepted by the server, the variable "server" should now
contain the socket id. If an error occured a number < 1 will be returned.

The next line checks if an error occured. An error could be because the server doesnt exist or the server didnt accept us. If an
error did occur then the game will end.

If no error occurs then the global variable "otherplayer" now becomes the socket id that the variable "server" has. Then the game will
start when we use room_goto().

Sending and recieving messages
For our game to work we need to know the y position of the paddle that the other player controls and the client needs to know the x, y
position of the ball which will be controlled by the server.

Sending
In the paddle which is controlled by you, you must send your Y co-ordinate to the other player so they can draw your paddle in the
right position. To do this, put this code in both the keyboard UP event and the keyboard DOWN event:

clearbuffer();
writebyte(0);
writeshort(y);
sendmessage(global.otherplayer);

The first line clears the internal buffer of any data. This is used in case there is data already in the buffer. The second line writes the byte
that represents the Message Id. In this game the message id 0 will indicate the message containing the Y position.
The next line writes the actual Y position to the buffer. We have used the data type "short" because a short can be any number between
-32000 to +32000. A short utilizes 2 bytes. If we had used one byte to represent the Y position and the Y position is bigger than 255 it will end up being not what you
wanted. The last line sends all the data in the internal buffer to the other player. In this case the data is the Message Id byte and the 2 bytes
used for the Y position.

Now we need to send the x, y position to the other player if we are the server. To do this put in the step event of the ball object:

if(!global.master)exit;
clearbuffer();
writebyte(1);
writeshort(x);
writeshort(y);
sendmessage(global.otherplayer);

The first line checks to see if we are the server. If we are NOT the server then exit the screen and do not execute the code below.
If however we are the server then first clear the internal buffer. Now write the Message Id "1" which will indicate the message is
the balls position. Now write a short which represents the x co-ordinate and write another short which represents the y co-ordinate.
Now just send the message to the other player.

Recieving a message.
In the paddle that you do not control..the one which is controlled by the other player, put this code in the step event:
var size;
while(true)
{
  size = receivemessage(global.otherplayer);
  if(size < 0) break;
  if(size == 0)
  {
    show_message("The other player left the game");
    game_end();
  }
  messageid = readbyte();
  switch(messageid)
  {
    case 0:
      y = readshort();
    break;
    
    case 1:
      objBall.x = readshort();
      objBall.y = readshort();:
    break;
  }
}

First this creates an infinite loop using while(true). The first line of the loop recieves any messages from the other player and sets the
variable "size" to how much bytes we recieved. The second line checks to see if no message was recieved. If no message was recieved
then exit the infinite loop. The third line checks to see if the other player disconnected from the game. If the message size == 0 
that means the player left the game.
If the player did leave, then end the game. If we did recieve a message then all data from the message is placed inside the internal buffer.
We can now use the buffer scripts to return the data from the message. The first part returns the message ID.
After that it uses the switch() statement to check what the ID equals. If the ID is 0 then this means the message is for the other players
y co-ordinate. We simply use readshort() to return the y position. Remember because we wrote the Y position as a short, we now must
read the Y position using a short.

If the Message ID equals 1, which represents the balls x, y position then use readshort() to set the balls x position to the right place and
readshort() again to set the balls y position in the right place.

Freeing the dll
If you dont want any nasty error messages when your game ends then you must free the dll from memory. To do this first create an object
that will be in every room. Now in the game end event of that object just put dllfree(). This will free winsock and free all memory used
by the internal buffer.