Today’s guest tutorial comes to you courtesy of Mark Steelman, founder of Steelman Games LLC. Mark is currently working on a turn-based RPG incorporating local multiplayer called Legend of Us Roleplaying Game. Before becoming an indie developer, Mark worked for four years at Electronic Arts as a game designer. You can follow the progress of his projects on Facebook, Google+, or by subscribing to his newsletter.


Make Devices Find Each Other with UDP

As noted in the introduction, I’m building a turn-based role-playing game using Corona SDK. As part of the design, I wanted local multiplayer and I also wanted it to be cross-platform. After a lot of research, I figured out how to accomplish this and, in this tutorial, I will share some of what I learned. Even better: this architecture will work for both turn-based and action games, so stick around if you’re making an action game!

This tutorial assumes that you have a basic understanding of Corona SDK, Lua, and peer-to-peer networking. We are going to use LuaSocket which is included in Corona SDK under the socket library. Because this design is intended for cross-platform multiplayer, it’s not going to use any native systems. While it does assume that the player has a Local Area Network (LAN), that network doesn’t need to be connected to the internet.

Including LuaSocket

In order to use LuaSocket, you must first include it:

That’s the easy part – let’s continue…

UDP and TCP

First, let me give a brief explanation of UDP and TCP. Both of these are protocols which allow computers to talk to each other and each one has certain advantages and disadvantages. However, I’m only going to cover features that are relevant to the tutorial.

UDP has the ability to send messages to an address without knowing if anything is there. It doesn’t check to see if the message made it anywhere — it simply transmits the message. UDP also allows you to listen to an address without being connected to a computer at that address.

TCP is a reliable protocol. It sends messages to another computer that it’s connected to via a TCP socket. If the other computer responds that there was a problem with the message, it sends the message again.

Knowing this, you might ask “Why would anyone use UDP when TCP is so reliable?” Well, there are several reasons, but the reason most relevant to this tutorial is the fact that you must know the IP address of the server in order to use TCP. Any network which you can join without visiting the LAN administrator is assigning you a random IP address using DHCP. This means that we’ll need to discover the IP address of the server on our own. Fortunately, UDP can help with that.

Advertise the Server

For local multiplayer to work, one of the devices must act as the server/host. The host doesn’t need to have special privileges in your game, but the primary record of the game in progress will be stored on this device. In the language of role-playing games, let’s call this player the game master. This game master is going to announce his/her presence to the local network via some method. I utilize an “Invite” button which calls the following function upon being pressed.

Here are some notes about this code:

  • Multicast is a device feature which allows one device to communicate with several. iPhones and iPads have it, but I’ve been told that iPods do not. I haven’t tried it on any Android devices, so maybe somebody can test it and report their results in the comments section. As a result of this inconsistency, we also use broadcast. “Why don’t we just use broadcast?” you might ask. Well, the catch with broadcast is that the LAN has to allow broadcasts. By using both, we are maximizing the chance of finding each other.
  • The “pulse” of the timer is ten times per second. I don’t recommend setting your timer pulse faster than that unless you have a good reason — after all, your game needs time to do other things. This is a standard pulse speed for most action games including MMOs.
  • The port you choose can be anything between 1 and 65535, however, applications almost always block the port that they use and you’ll get an error if you try to bind to a port that is currently in use. Likewise, if you bind to a port, you need to unbind/close the port when you end the game so you don’t block it indefinitely on the players device. Lower number ports are used by commonly run applications, so it’s best to use a port between 1024 and 65535.
  • The settimeout() function allows you to tell the socket how long to wait for a message before moving on. Default is to wait indefinitely, meaning that your game freezes until it gets a message. Setting it to 0 tells it to just check and if there’s nothing to receive and move on to the next task.

Finding the Server

The client will need to know its own IP address for the next step. Fortunately, UDP in LuaSocket can help with that:

The IP address in the above function is arbitrary — I used the Google address because I know it. You don’t even need to be connected to the internet for this function to return your IP address, but you must at least be on a local network.

Listening for the Server

Now we are prepared to listen for the server. We will recognize the server because of the message AwesomeGameServer. Obviously, this could be any string; we are just going to match strings.

I put a lot of inline comments above, but I’ll elaborate on a few things:

  • Notice that we account for the fact that not all devices have Multicast.
  • The receivefrom() function is going to just pull in anything that’s at that address, so we need to filter it. This is why we have the string message to compare with.
  • When two devices find each other, it can get painful if they both have a short duration. I like to make the server wait much longer than the clients. If the server is advertising, the client finds them pretty quick. Basically, I just want to avoid “Can you try that again? I missed it.”
  • In this example, I’m passing in a reference to the button that the player pressed to activate the function. I do this because so the player can push it again and stop broadcasting. If you don’t want to do that, you don’t need the button reference.

So, at this point, we know how to let the game master be discovered by the players. The essential IP address required to use TCP is attached to the UDP message. Now that we have the game master’s IP address, we can connect to their device using TCP.

Swapping Strings

Now we’ll discuss how to create a TCP server, connect to it, and send messages back and forth.

First, let’s discuss what TCP will provide and what it won’t. Like I said above, once we have a connection between devices, they’ll be able to send messages back and forth. These messages will just be strings. Imagine it like a text message app — in this case, the app on one device sends texts to the app on another device. These messages are then interpreted by the apps on each device and some action occurs.

Security

This tutorial will not go in depth about security, but a couple points should be covered:

  • The server and client can only control each other as far as you allow it. As I’ve iterated several times now, TCP just sends and receives text strings. For a Pac-Man clone that could be controlled by a second device, about the only information the server would need is “BEGIN”, “UP”, “DOWN”, “LEFT”, and “RIGHT” — all else could simply be ignored.
  • You should never try to make your app accept functions that have been turned into a string. Let the client and the server have their own functions and just use the transmitted text to call the functions. If your app accepts functions, you open up a very serious security vulnerability, so don’t do it! Instead, just pass commands with parameters.

In any case, don’t lie awake at night worrying about this. Neither iOS nor Android will let you damage someone’s device with such foolishness, but it may ruin the install of your game!

Starting the Server

The server runs in a periodic loop. On each iteration of the loop, it checks to see if any clients want to join and whether connected clients sent a message. If the buffer has any messages to send out, it sends them. Here’s a basic TCP server module with further explanation following:

And that is a basic server. Let’s start at the top with some explanation:

  • socket.bind() creates a server object which you bind to the port of your choice. I used 11111, but you can use any that we listed in the earlier section. Remember to close the TCP object when you shut down the server via the stopServer() function!
  • settimeout( 0 ) tells LuaSocket to move on if there’s no information waiting at the socket.
  • accept() returns a client object which represents the connection to the other device. Each client will get their own object and each one will need to be closed when the game is done. We do this in the function at the bottom called stopServer().
  • socket.select() goes through our list of client connections to see which are available. Any that are not available are ignored but not closed.
  • receive() receives one line of data. You can designate a line of data in a string by putting n at the end. It’s simple and you’ll be able to create bite-sized pieces of data. This function is structured so that you end up with a numbered table of string lines. They are numbered in the order that they were received, but you can’t rely on the lines you send being received in the order you sent them. If this is important, and it often is, you’ll need to create a way for the server to know if a line is in the right order.
  • Next we go through the list of lines and interpret them. This is usually just a series of ifthen statements with a liberal use of the string library.
  • Finally, we send whatever is in the buffer. The buffer is another list of strings. Again, you can’t absolutely control the order in which they are received. You don’t have to use a buffer, but when you are using a multi-use device like a phone as a server, it’s a good idea. You may just :send() to a client socket at any time but the only way the device knows that the message didn’t go through is if the other device responds. If the other device is taking a call, it will ignore your message and the message will be lost. If you implement a buffer, it sends the message every pulse until something happens that removes the message from the buffer, however you’ll need to implement a way of knowing when to remove items from the buffer.

Connecting to the Server

Connecting to the server is much simpler:

To elaborate on this slightly:

  • socket.connect is pretty self explanatory: attempt to connect to the server at that address.
  • settimeout( 0 ) again lets the socket know that you want it to just check the socket and move on if there’s no incoming message.
  • Nagle’s algorithm is a standard function that causes the socket to aggregate data until the data is of a certain size, then send it. If you are just going to send “UP” and you want it sent right away, you’ll want this off.

What’s not included in this example is a method to determine if the client is connecting for the first time or reconnecting (return session). This is outside the scope of this tutorial, but one option is to use a session ID which the client gets the first time it connects to the server. In this case, both the client and the server save the ID. Then, if the client loses the connection, this ID is sent upon reconnection and the server can update the client’s data with the new client socket.

Client Loop

The final piece of the puzzle is the client loop. This will look very much like the server loop, but it never tries to accept connections.

Note that the client is always responsible for making the connection to the server. The server never tries to reach the client — it has enough to handle already. Beyond that, there isn’t anything clarify that wasn’t already covered in the server loop section.

Conclusion

I hope this tutorial helps you achieve your multiplayer dreams! While it’s not intended to be a comprehensive tutorial on networking, what I accomplished should help you get two devices talking with each other using TCP.

Thank you for reading and remember to check out Legend of Us Roleplaying Game which inspired me to figure all of this out.

Excerpt from – 

Tutorial: Local Multiplayer with UDP/TCP