Basic Networking with AGK by Kevin Summers

Using a Top 10 High Score list as an example, this tutorial will attempt to demonstrate the following.

The Server App

To set up a server listening on a network requires only one command. This command sets up a network called myNetwork using the client name Server and listens for TCP connections on port 4100. For connections coming in to the server from the Internet, you will have to set up your router to forward that port to the machine running your server app.

INetID = HostNetwork("myNetwork", "Server", 4100)

Now that we are listening on the network, we need to add a little maintenance routine to clean up after clients that have disconnected. This routines checks to see if a client that was previously connected has disconnected, and it deletes the associated client ID making room for the next client connection.

for x = 1 to 50
    if x = 1
        id = GetNetworkFirstClient(iNetID)
    else
        id = GetNetworkNextClient(iNetID)
    endif
    if id = 0 then exit
    if GetNetworkClientDisconnected(iNetID, id) = 1
        DeleteNetworkClient(iNetID, id)
    endif
next x

Now we are ready to check for incoming messages. We'll ask the network if there are any in the queue and grab it if there are. Then check the client ID to make sure it's coming from a client and not the server. (the server uses client ID 1)

When we have received a packet, we check the first data item, which in this case happens to be a float. We are using that float to determine what action to take. For this app, if the float equals 1.0, then we are sending the high score list to the client. If it equals 1.1, then the client has sent a high score to the server to be considered for placement in the top 10.

msg = GetNetworkMessage(iNetID)
if msg > 0
    ClientID = GetNetworkMessageFromClient(msg)
        if ClientID > 1
            f# = GetNetworkMessageFloat(msg)
            if f# = 1.0 // Send High Score List
                newMsg = CreateNetworkMessage()
                AddNetworkMessageFloat(newMsg, 1.0)
                for x = 1 to 10
                    AddNetworkMessageString(newMsg, HiScores[x].init$)
                    AddNetworkMessageInteger(newMsg, HiScores[x].score)
                next x
                SendNetworkMessage(iNetID, ClientID, newMsg)
                DeleteNetworkMessage(newMsg)
            endif
            if f# = 1.1
                // Receive Score from Client
                temp$ = GetNetworkMessageString(msg)
                score = GetNetworkMessageInteger(msg)
                // See if the submitted score is high enough for the top 10
                // If it is, place it where it belongs and shuffle the rest
                // of the scores down one position.
                for x = 1 to 10
                    if score > HiScores[x].score then exit
                next x
            if x < 11
                for y = 10 to x+1 step -1
                    HiScores[y].init$ = HiScores[y-1].init$
                    HiScores[y].score = HiScores[y-1].score
                next y
                HiScores[x].init$ = init$
                HiScores[x].score = score
            endif
        endif
    endif
    DeleteNetworkMessage(msg)
endif

The Client App

For the sake of simplicity I'll only be showing the subroutines that handle network communications. It will be up to you to create the game that ultimately feeds this the player's initials and score.

The SendHighScore subroutine.

For the client to connect to the server requires just one command. It specifies the IP address of the server, the port, and a client name. The client name when connecting to a server must be different than any other client name currently connected to the server, so we're using a Random number to keep it unique.

InetID = JoinNetwork("192.168.100.5", 4100, "Client"+str(Random()))

Then we enter a loop that checks to see if we have connected, and times out in 4 seconds if we don't. Remember to give enough time for a connection to happen. On devices such as cell phones, congestion and poor signal, are very common and can produce long delays.

// If we don't connect within 4 seconds, print an error and exit
t# = timer()
do
    c = GetNetworkNumClients(iNetID)
    if c > 1 then exit
    if timer() - t# > 4.0
        print("Server could not be reached.")
        exit
    endif
    sync()
loop

Once the connection is established, we assemble the network packet, and send it off to the server.

If c > 1
    ServerID = GetNetworkServerID(iNetID)
    newMsg = CreateNetworkMessage()
    AddNetworkMessageFloat(newMsg, 1.1)
    // Add the packet identifier
    AddNetworkMessageString(newMsg, init$)
    // Add the player's initials
    AddNetworkMessageInteger(newMsg, score) // Add the player's score
    SendNetworkMessage(iNetID, ServerID, newMsg)
    // Send it to the server
    DeleteNetworkMessage(newMsg)
    CloseNetwork(iNetID)
endif

The GetHighScores subroutine

The first part of this routine is identical to the SendHighScore subroutine.

InetID = JoinNetwork("192.168.100.5", 4100, "Client"+str(Random()))
// If we don't connect within 4 seconds, print an error and exit
t# = timer()
do
    c = GetNetworkNumClients(iNetID)
    if c > 1 then exit
    if timer() - t# > 4.0
        print("Server could not be reached.")
        exit
    endif
    sync()
loop

Once the connection is established, we send off just the float in a packet by itself. This tells the server we want it to send the full high score list. Then we enter a loop waiting for the packet to arrive from the server.

If c > 1
    ServerID = GetNetworkServerID(iNetID) // get server's ID
    newMsg = CreateNetworkMessage() // add the packet identifier
    AddNetworkMessageFloat(newMsg, 1.0) // send it to the server
    SendNetworkMessage(iNetID, ServerID, newMsg)
    DeleteNetworkMessage(newMsg)
    msg = 0
    t# = timer()
    while msg = 0
        msg = GetNetworkMessage(iNetID)
        if timer() - t# > 2.0 then exit
        sync()
    endwhile
    if msg > 0
        f# = GetNetworkMessageFloat(msg)
        if f# = 1.0
        for x = 1 to 10
            HiScores[x].init$ = GetNetworkMessageString(msg)
            HiScores[x].score = GetNetworkMessageInteger(msg)
        next x
    endif
    endif
    DeleteNetworkMessage(msg)
    CloseNetwork(iNetID)
endif