Technology Demo

Networking Messages Demo

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Spot for images

Intro

This demo will give the basics of networking in Luster, showing you how to send messages.

Server or Client

In order to create a networked Luster application, you need to load the multiplayer plugin. To do this, open up the XML file and under Plugin Dependencies, select Add > com.darkwindmedia.multiplayer.

For our demonstration we need to be able to run the application twice, the first time setting the application to be a "server", and the second time to be a "client." To do this, we need to be able to listen for a key press for S or C to determine what type the application will be.

In order to make sure that the type can only be decided once, we have a boolean called typeDecided that will become false once the type is decided. We'll also have an event listener for a key press.

-- Boolean for if client/server has already been decided
self.typeDecided = true
    
-- Set up event listeners for determining client/server
self:addEventListener(luster.display.DisplayObject.KEY_DOWN, Function(self, self.onKeyDown))

Next, we need to handle the key press when it occurs, and so we'll define the onKeyDown function. It'll look like this:

function Root:onKeyDown(key)
   if self.typeDecided then
      if key == luster.KeyCodes.S then
         self.type = "server"
         self:createServer()
      elseif key == luster.KeyCodes.C then
         self.type = "client"
         self:createClient()
      end
      self.typeDecided = false
   end
end

Here, if a key hasn't already been pressed, then the createServer or createClient methods will be called. These two methods are detailed in the next section.

Peers

First we will cover the creation of a server. Both server and client are instances of com.darkwindmedia.multiplayer.Peer. Peer takes several arguments as parameters - maxConnections, sleepTime, sockets, and options. For this demo, we are only really worried about the first three arguments. MaxConnections is the maximum number of connections that the Peer can have - for a server, it is many, and for a client, it's always one. The sleepTime argument refers to how long, in milliseconds, the Peer will wait before checking for messages. We'll use 50 as our sleepTime because it's the default.

function Root:createServer()
   self.server = com.darkwindmedia.multiplayer.Peer(1,50,{{port = 5000}})
   self.server:activate()
   self.server.maxIncomingConnections = 1
   self.server:addEventListener(com.darkwindmedia.multiplayer.Peer.RECEIVED, Function(self, self.serverReceived))
end

Here, we create the server and then activate it. We tell it that the maximum number of incoming connections it can have at once is 1, and then add an event listener to listen for when messages are received.

Next we will work on creating the client. This is very similar to creating a new server, with a few exceptions. For the Peer, the only arguments needed are the maxConnections (which is always 1, because a client can only connect to the server) and the sleepTime of 50.

The client next gets activated the same as the server was, and has an eventlistener for receiving information. The client then connects to the port defined earlier in the server. "Localhost" is used because the interactions are going to be on the same computer for this demo.

function Root:createClient()
   self.client = com.darkwindmedia.multiplayer.Peer(1,50)
   self.client:activate()
   self.client:addEventListener(com.darkwindmedia.multiplayer.Peer.RECEIVED, Function(self, self.clientReceived))
   self.client:connect(luster.net.Address("localhost", 5000))
end

Received Information Handling

Now we can set up the two receive functions for the server and the client. We'll set up the server receive first.

When the two initially connect, a message is sent to both. The one sent to the server, of type 17, essentially says that the client has connected to the server. So, if the client has connected, then a buffer will be created to send a message back. For each buffer written to send a message, a byte must be written first - this first byte is the "type" for the new message. The lower numbers are reserved, so it's best to use 100 and above as the type for your buffer.

After that, information can be written to the buffer in any order you please. Here, we simply write a string ("From Server: Test string.") and then send. The parameters for the send function are the buffer we just wrote, four nils (these are for priority, reliability, channel, and address, but we won't need those for now) and then true for the "broadcast" boolean. This means it will send to all of the clients that are connected to it.

The next if statement is for when the client sends a message to the server, as it will be given the type 101.

function Root:serverReceived(type, index, sender, buffer)
   if type == 17 then
     local buffer = luster.util.ByteArray()
     buffer:writeByte(100)
     buffer:writeString("From Server: Test string.")
     self.server:send(buffer,nil,nil,nil,nil,true)
   end
   if type == 101 then
     trace(buffer:readString())
   end
end

The client received function is very similar to the above server function. It will read the buffer if the type is 100, which is the type that the server will be using, as defined earlier. It will read the string and then reply in much the same manner as the previous send for the server.

function Root:clientReceived(type, index, sender, buffer)
   if type == 100 then
      trace(buffer:readString())
      local sendBuffer = luster.util.ByteArray()
      sendBuffer:writeByte(101)
      sendBuffer:writeString("From Client: Received the information.")
      self.client:send(sendBuffer,nil,nil,nil,nil,true)
   end
end

This covers the basics of sending a message between applications. If you run the program, the trace statements will show that messages are being sent.