Local Multiplayer Game

Hello,
I’ve been working on a local-multiplayer game using socket which uses a server browser to look for any server up and running on your local network. I was just wondering if anybody has two iPads, I would love if you could kindly test my code and see if the whole multiplayer thing works, as I don’t have a second iPad like some.

Here is the code for testing:

function setup()
    scene = craft.scene()
    craft.scene.main = scene
    socket = require("socket")
    messenger = socket.udp()
    messenger:setoption("broadcast", true)
    messenger:settimeout(0)
    parameter.action("Host", createServer)
    client_data = {}
    clients = {}
    entities = {}
    servers = {}
    my_client = nil
    my_entity = nil
    my_server = nil
    -- Something to land on so the clients dont fall endlessly into the void
    ground = scene:entity()
    ground.model = craft.model(asset.builtin.Primitives.RoundedCube)
    ground.position = vec3(0, -2, 10)
    ground.scale = vec3(10, 0.1, 10)
    gbody = ground:add(craft.rigidbody, STATIC)
    ground:add(craft.shape.model, ground.model)
    -- Setup camera
    scene.camera.position = vec3(0, 8, -10)
    scene.camera.rotation = quat.eulerAngles(25, 0, 0)
end

function joinServer(ip, port)
    if my_client == nil then
        local client = socket.udp()
        client:setpeername(ip, port)
        client:settimeout(0)
        table.insert(clients, client)
        updateEntities(client)
        client:send("join")
        my_client = client
    end
end

function createServer()
    if my_server == nil then
        server = socket.udp()
        server:setsockname("*", 14285)
        server:setoption("broadcast", true)
        server:settimeout(0)
        my_server = server
    end
end

function updateEntities(client)
    if not entities[entity] then
        entity = scene:entity()
        entity.model = craft.model(asset.builtin.Primitives.Sphere)
        entity.position = vec3(0, 0, 10)
        body = entity:add(craft.rigidbody, DYNAMIC)
        entity:add(craft.shape.sphere, 1)
        entity.material = craft.material(asset.builtin.Materials.Specular)
        entity.material.diffuse = color(math.random(0, 255), math.random(0, 255), math.random(0, 255))
        entity.master = client
        body.linearDamping = 0.8
        my_entity = entity
        table.insert(entities, entity)
    end
end

function touched(touch)
    if touch.state == MOVING then
        if touch.deltaX > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(-30, 0, 0))
                end
            end
        elseif touch.deltaX < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(30, 0, 0))
                end
            end
        elseif touch.deltaY > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, 30))
                end
            end
        elseif touch.deltaY < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, -30))
                end
            end
        end
    end
end

function draw()
    -- Check if any "server messengers" have broadcasted anything
    if my_server ~= nil then
        local data_received, msgOrIp, portOrNil = my_server:receivefrom()
        if data_received ~= nil then
            if data_received == "checking for available servers" then
                -- If yes, we know there is another server and we can send something back
                my_server:sendto("server available", msgOrIp, portOrNil)
            elseif data_received == "join" then
                my_server:sendto("server entities list: "..#entities, msgOrIp, portOrNil)
            end
        end
    end
    -- Here, we check if our messenger has received anything back from any server on the network
    local data, ip, port = messenger:receivefrom()
    if data ~= nil then
        if data == "server available" then
            local uid = {ip = ip, port = port}
            if not servers[uid] then
                table.insert(servers, uid)
            end
        end
    end
    -- Here, we loop through every set of server information our messenger has received, and we use that information to create buttons that will create a client connected to that server if pressed
    for i,s in pairs(servers) do
        parameter.action("Join: "..tostring(s.ip).." - "..tostring(s.port), function() joinServer(s.ip, s.port) end)
    end
    -- We can loop through every client currently connected to the server, and see if the server has sent the amount of entities (this will only happen if you have just joined the server)
    for i,c in pairs(clients) do
        local data = c:receive()
        if data ~= nil then
            if string.find(data, "server entities list") then
                local amount = string.sub(data, 22, #data)
                for i = 1, tonumber(amount) do
                    if not entities[i].master == c then
                        updateEntities(c)
                    end
                end
            end
        end
    end
    -- Continuously send UDP broadcasts across the whole network
    messenger:sendto("checking for available servers", "255.255.255.255", "14285")
end

Thanks in advance,
Creator27 :slight_smile:

@Creator27 Tried your code on 2 iPads. A ball showed up on each field on each iPad, but I could only move the ball on the iPad that I was moving my finger on. It didn’t look like there was any communication between the 2 iPads, but then I’m not sure what was supposed to be happening anyways.

I created a multiplayer game a few years ago, here’s the link. The updated code is at the bottom of the link.

https://codea.io/talk/discussion/8334/multiplayer-games-using-sockets#latest

@dave1707, first off thank you for testing my game it means a lot especially since I haven’t dabbled in as much multiplayer networking stuff. I haven’t done much, but the aim of the game at the moment is just moving the ball controlled by the client you joined as, which seeing from what you said is working so that’s GREAT! Just one thing, when you joined on the second iPad, were there 2 balls instead of just one?

@dave1707, also if it isn’t too much of a hassle for you, could you screen record what happens and post both recordings on this discussion so I can actually see what happened and what I can improve on??

Thank you,
Creator27 :slight_smile:

@Creator27 There was just one ball per iPad. I could move each ball around on each iPad but that was about it. There’s no point in a recording because you can just load the program on one iPad and move the ball. That’s all it was doing on each iPad.

@Creator27 Maybe they are communicating somewhat. If I run you code on just 1 iPad, it doesn’t show the ball. When both iPads are running, there’s an iP address that shows.

PS. What is supposed to happen with your code.

@dave1707, I don’t know if what I’m about to suggest will do anything, but try and remove this piece of code below:

if not entities[i].master == c then
      updateEntities(c)
end

And instead just write:

updateEntities(c)

@Creator27 Sometimes I get 2 balls on one of the iPad, but I still don’t think it’s working. Are there supposed to be 2 balls on both iPads and the object is to push the other ball off the field. Neither iPad is controlling a ball on the other iPad.

Okay that means it’s still working, can you screen record and show me what’s happening please??
Thank you

@Creator27 It won’t let me post a video, too big. I’ll try a shorter one.

PS. It won’t let me, .mov not allowed.

@dave1707, I forgot to mention that yes I’m aiming to get 2 or however many players showing on both iPads and I’ve updated my code so that it hopefully does exactly that. Here it is:


function setup()
    scene = craft.scene()
    craft.scene.main = scene
    socket = require("socket")
    messenger = socket.udp()
    messenger:setoption("broadcast", true)
    messenger:settimeout(0)
    parameter.action("Host", createServer)
    client_data = {}
    clients = {}
    entities = {}
    servers = {}
    my_client = nil
    my_entity = nil
    my_server = nil
    -- Something to land on so the clients dont fall endlessly into the void
    ground = scene:entity()
    ground.model = craft.model(asset.builtin.Primitives.RoundedCube)
    ground.position = vec3(0, -2, 10)
    ground.scale = vec3(10, 0.1, 10)
    gbody = ground:add(craft.rigidbody, STATIC)
    ground:add(craft.shape.model, ground.model)
    -- Setup camera
    scene.camera.position = vec3(0, 8, -10)
    scene.camera.rotation = quat.eulerAngles(25, 0, 0)
end

function joinServer(ip, port)
    if my_client == nil then
        local client = socket.udp()
        client:setpeername(ip, port)
        client:settimeout(0)
        table.insert(clients, client)
        updateEntities(vec3(0, 0, 10))
        client:send("join")
        my_client = client
    end
end

function createServer()
    if my_server == nil then
        server = socket.udp()
        server:setsockname("*", 14285)
        server:setoption("broadcast", true)
        server:settimeout(0)
        my_server = server
    end
end

function updateEntities(pos)
    if not entities[entity] then
        entity = scene:entity()
        entity.model = craft.model(asset.builtin.Primitives.Sphere)
        entity.position = pos
        body = entity:add(craft.rigidbody, DYNAMIC)
        entity:add(craft.shape.sphere, 1)
        entity.material = craft.material(asset.builtin.Materials.Specular)
        entity.material.diffuse = color(math.random(0, 255), math.random(0, 255), math.random(0, 255))
        body.linearDamping = 0.8
        my_entity = entity
        table.insert(entities, entity)
    end
end

function touched(touch)
    if touch.state == MOVING then
        if touch.deltaX > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(-30, 0, 0))
                end
            end
        elseif touch.deltaX < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(30, 0, 0))
                end
            end
        elseif touch.deltaY > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, 30))
                end
            end
        elseif touch.deltaY < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, -30))
                end
            end
        end
    end
end

function draw()
    -- Check if any "server messengers" have broadcasted anything
    if my_server ~= nil then
        local data_received, msgOrIp, portOrNil = my_server:receivefrom()
        if data_received ~= nil then
            if data_received == "checking for available servers" then
                -- If yes, we know there is another server and we can send something back
                my_server:sendto("server available", msgOrIp, portOrNil)
            elseif data_received == "join" then
                local uid = {ip = ip, port = port}
                if not client_data[uid] then
                    table.insert(client_data, uid)
                end
            end
        end
    end
    -- Here, we check if our messenger has received anything back from any server on the network
    local data, ip, port = messenger:receivefrom()
    if data ~= nil then
        if data == "server available" then
            local uid = {ip = ip, port = port}
            if not servers[uid] then
                table.insert(servers, uid)
            end
        end
    end
    -- Here, we loop through every set of server information our messenger has received, and we use that information to create buttons that will create a client connected to that server if pressed
    for i,s in pairs(servers) do
        parameter.action("Join: "..tostring(s.ip).." - "..tostring(s.port), function() joinServer(s.ip, s.port) end)
    end
    -- We can loop through every client currently connected to the server, and see if the server has sent the amount of entities (this will only happen if you have just joined the server)
    for i,c in pairs(clients) do
        local data = c:receive()
        if data ~= nil then
            if string.find(data, "server entity position list") then
                local tab = json.decode(data)
                updateEntities(vec3(tab.x, tab.y, tab.z))
            end
        end
    end
    -- For every client, we need to make sure when somebody new joins we show their character to that client on the server
    for i,e in pairs(entities) do
        for i,c in pairs(client_data) do
            positions = {x = e.position.x, y = e.position.y, z = e.position.z}
            my_server:sendto(json.encode(positions).."server entity position list", tostring(c.ip), tostring(c.port))
        end
    end
    -- Continuously send UDP broadcasts across the whole network
    messenger:sendto("checking for available servers", "255.255.255.255", "14285")
end

Thank you :slight_smile:

@Creator27 Tried the new code. Even though both iPads show joined, there is only 1 ball showing on the field. The ball for the other iPad isn’t showing up.

@dave1707, I updated the code. Here it is:

function setup()
    scene = craft.scene()
    craft.scene.main = scene
    socket = require("socket")
    messenger = socket.udp()
    messenger:setoption("broadcast", true)
    messenger:settimeout(0)
    parameter.text("Server Name", "")
    parameter.action("Host", createServer)
    client_data = {}
    clients = {}
    entities = {}
    servers = {}
    my_client = nil
    my_entity = nil
    my_server = nil
    server_name = ""
    connected = false
    -- Something to land on so the clients dont fall endlessly into the void
    ground = scene:entity()
    ground.model = craft.model(asset.builtin.Primitives.RoundedCube)
    ground.position = vec3(0, -2, 10)
    ground.scale = vec3(10, 0.1, 10)
    gbody = ground:add(craft.rigidbody, STATIC)
    ground:add(craft.shape.model, ground.model)
    -- Setup camera
    scene.camera.position = vec3(0, 8, -10)
    scene.camera.rotation = quat.eulerAngles(25, 0, 0)
end

function joinServer(ip, port)
    if my_client == nil then
        local client = socket.udp()
        client:setpeername(ip, port)
        client:settimeout(0)
        table.insert(clients, client)
        updateEntities(vec3(0, 0, 10), client)
        client:send("join")
        my_client = client
    end
end

function createServer()
    if my_server == nil then
        server = socket.udp()
        server:setsockname("*", 14285)
        server:setoption("broadcast", true)
        server:settimeout(0)
        my_server = server
        server_name = Server_Name
    end
end

function updateEntities(pos, client)
    if not entities[entity] then
        entity = scene:entity()
        entity.model = craft.model(asset.builtin.Primitives.Sphere)
        entity.position = pos
        body = entity:add(craft.rigidbody, DYNAMIC)
        entity:add(craft.shape.sphere, 1)
        entity.material = craft.material(asset.builtin.Materials.Specular)
        entity.material.diffuse = color(math.random(0, 255), math.random(0, 255), math.random(0, 255))
        body.linearDamping = 0.3
        my_entity = entity
        if client ~= nil then
            entity.master = client
        end
        table.insert(entities, entity)
    end
end

function touched(touch)
    if touch.state == MOVING then
        if touch.deltaX > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(-30, 0, 0))
                end
            end
        elseif touch.deltaX < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(30, 0, 0))
                end
            end
        elseif touch.deltaY > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, 30))
                end
            end
        elseif touch.deltaY < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, -30))
                end
            end
        end
    end
end

function draw()
    -- Check if any "server messengers" have broadcasted anything
    if my_server ~= nil then
        local data_received, msgOrIp, portOrNil = my_server:receivefrom()
        if data_received ~= nil then
            if data_received == "checking for available servers" then
                -- If yes, we know there is another server and we can send something back
                my_server:sendto("server available", msgOrIp, portOrNil)
            elseif data_received == "join" then
                print("A client has successfully joined the server!")
                local uid = {ip = ip, port = port}
                if not client_data[uid] then
                    table.insert(client_data, uid)
                end
            end
        end
    end
    -- Here, we check if our messenger has received anything back from any server on the network
    local data, ip, port = messenger:receivefrom()
    if data ~= nil then
        if data == "server available" then
            local uid = {ip = ip, port = port}
            if not servers[uid] then
                table.insert(servers, uid)
            end
        end
    end
    -- Here, we loop through every set of server information our messenger has received, and we use that information to create buttons that will create a client connected to that server if pressed
    for i,s in pairs(servers) do
        parameter.action(server_name..": "..tostring(s.ip).." - "..tostring(s.port), function() joinServer(s.ip, s.port) end)
    end
    -- We can loop through every client currently connected to the server, and see if the server has sent the amount of entities (this will only happen if you have just joined the server)
    for i,c in pairs(clients) do
        local data = c:receive()
        if data ~= nil then
            if string.find(data, "server entity position list") then
                local tab = json.decode(data)
                updateEntities(vec3(tab.x, tab.y, tab.z))
            elseif string.find(data, "server entity position update") then
                local tab = json.decode(data)
                for i,e in pairs(entities) do
                    if not string.find(data, tostring(e)) then
                        if my_entity ~= e then
                            e.position = vec3(tab.x, tab.y, tab.z)
                        end
                    end
                end
            end
        end
    end
    -- For every client, we need to make sure when somebody new joins we show their character to that client on the server
    if connected == false then
        for i,e in pairs(entities) do
            for i,c in pairs(client_data) do
                for i,cl in pairs(clients) do
                    positions = {x = e.position.x, y = e.position.y, z = e.position.z}
                    my_server:sendto(json.encode(positions).."server entity position list", tostring(c.ip), tostring(c.port))
                    connected = true
                end
            end
        end
    else
        for i,e in pairs(entities) do
            for i,c in pairs(client_data) do
                positions = {x = e.position.x, y = e.position.y, z = e.position.z}
                my_server:sendto(json.encode(positions).."server entity position update"..tostring(e), tostring(c.ip), tostring(c.port))
            end
        end
    end
    -- Continuously send UDP broadcasts across the whole network
    messenger:sendto("checking for available servers", "255.255.255.255", "14285")
end

@Creator27 Tried your latest code. Still only shows 1 sphere even though both iPads joined. Here’s an image.

@dave1707, did you host 2 servers or one because if not that’s another problem I gotta fix.

I’ve tried to prevent any server button duplication, so here’s what I call “My code: The 3rd Iteration”:

function setup()
    scene = craft.scene()
    craft.scene.main = scene
    socket = require("socket")
    messenger = socket.udp()
    messenger:setoption("broadcast", true)
    messenger:settimeout(0)
    parameter.text("Server Name", "")
    parameter.action("Host", createServer)
    client_data = {}
    clients = {}
    entities = {}
    servers = {}
    my_client = nil
    my_entity = nil
    my_server = nil
    server_name = ""
    connected = false
    -- Something to land on so the clients dont fall endlessly into the void
    ground = scene:entity()
    ground.model = craft.model(asset.builtin.Primitives.RoundedCube)
    ground.position = vec3(0, -2, 10)
    ground.scale = vec3(10, 0.1, 10)
    gbody = ground:add(craft.rigidbody, STATIC)
    ground:add(craft.shape.model, ground.model)
    -- Setup camera
    scene.camera.position = vec3(0, 8, -10)
    scene.camera.rotation = quat.eulerAngles(25, 0, 0)
end

function joinServer(ip, port)
    if my_client == nil then
        local client = socket.udp()
        client:setpeername(ip, port)
        client:settimeout(0)
        table.insert(clients, client)
        updateEntities(vec3(0, 0, 10), client)
        client:send("join")
        my_client = client
    end
end

function createServer()
    if my_server == nil then
        server = socket.udp()
        server:setsockname("*", 14285)
        server:setoption("broadcast", true)
        server:settimeout(0)
        my_server = server
        server_name = Server_Name
    end
end

function updateEntities(pos, client)
    if not entities[entity] then
        entity = scene:entity()
        entity.model = craft.model(asset.builtin.Primitives.Sphere)
        entity.position = pos
        body = entity:add(craft.rigidbody, DYNAMIC)
        entity:add(craft.shape.sphere, 1)
        entity.material = craft.material(asset.builtin.Materials.Specular)
        entity.material.diffuse = color(math.random(0, 255), math.random(0, 255), math.random(0, 255))
        body.linearDamping = 0.3
        my_entity = entity
        if client ~= nil then
            entity.master = client
        end
        table.insert(entities, entity)
    end
end

function touched(touch)
    if touch.state == MOVING then
        if touch.deltaX > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(-30, 0, 0))
                end
            end
        elseif touch.deltaX < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(30, 0, 0))
                end
            end
        elseif touch.deltaY > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, 30))
                end
            end
        elseif touch.deltaY < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, -30))
                end
            end
        end
    end
end

function draw()
    -- Check if any "server messengers" have broadcasted anything
    if my_server ~= nil then
        local data_received, msgOrIp, portOrNil = my_server:receivefrom()
        if data_received ~= nil then
            if data_received == "checking for available servers" then
                -- If yes, we know there is another server and we can send something back
                my_server:sendto("server available", msgOrIp, portOrNil)
            elseif data_received == "join" then
                print("A client has successfully joined the server!")
                local uid = {ip = msgOrIp, port = portOrNil}
                if not client_data[uid] then
                    table.insert(client_data, uid)
                end
                my_server:sendto(json.encode(positions).."server entity position list", tostring(ip), tostring(port))
            end
        end
    end
    -- Here, we check if our messenger has received anything back from any server on the network
    local data, ip, port = messenger:receivefrom()
    if data ~= nil then
        if data == "server available" then
            parameter.action(server_name..": "..tostring(ip).." - "..tostring(port), function() joinServer(ip, port) end)
        end
    end
    -- We can loop through every client currently connected to the server, and see if the server has sent the amount of entities (this will only happen if you have just joined the server)
    for i,c in pairs(clients) do
        local data = c:receive()
        if data ~= nil then
            if string.find(data, "server entity position list") then
                local tab = json.decode(data)
                updateEntities(vec3(tab.x, tab.y, tab.z))
            elseif string.find(data, "server entity position update") then
                local tab = json.decode(data)
                for i,e in pairs(entities) do
                    if not string.find(data, tostring(e)) then
                        if my_entity ~= e then
                            e.position = vec3(tab.x, tab.y, tab.z)
                        end
                    end
                end
            end
        end
    end
    -- For every client, we need to make sure when somebody new joins we show their character to that client on the server
    if connected == true then
        for i,e in pairs(entities) do
            for i,c in pairs(client_data) do
                positions = {x = e.position.x, y = e.position.y, z = e.position.z}
                my_server:sendto(json.encode(positions).."server entity position update"..tostring(e), tostring(c.ip), tostring(c.port))
            end
        end
    end
    -- Continuously send UDP broadcasts across the whole network
    messenger:sendto("checking for available servers", "255.255.255.255", "14285")
end

@Creator27 Same thing with the new code. Only one ball shows.

Alright, I’m going to recode the entire thing and see if I can find a fix.

@dave1707, I’ve entirely recorded it and here it is:

function setup()
    scene = craft.scene()
    craft.scene.main = scene
    socket = require("socket")
    messenger = socket.udp()
    messenger:setoption("broadcast", true)
    messenger:settimeout(0)
    parameter.text("Server Name", "")
    parameter.action("Host", createServer)
    client_data = {}
    clients = {}
    entities = {}
    servers = {}
    my_client = nil
    my_entity = nil
    my_server = nil
    server_name = ""
    connected = false
    -- Something to land on so the clients dont fall endlessly into the void
    ground = scene:entity()
    ground.model = craft.model(asset.builtin.Primitives.RoundedCube)
    ground.position = vec3(0, -2, 10)
    ground.scale = vec3(10, 0.1, 10)
    gbody = ground:add(craft.rigidbody, STATIC)
    ground:add(craft.shape.model, ground.model)
    -- Setup camera
    scene.camera.position = vec3(0, 8, -10)
    scene.camera.rotation = quat.eulerAngles(25, 0, 0)
end

function joinServer(ip)
    if my_client == nil then
        local client = socket.udp()
        client:setpeername(ip, "14285")
        client:settimeout(0)
        table.insert(clients, client)
        updateEntities(vec3(0, 0, 10), client)
        positions = {x = entity.position.x, y = entity.position.y, z = entity.position.z}
        client:send("join"..json.encode(positions))
        my_client = client
    end
end

function createServer()
    if my_server == nil then
        server = socket.udp()
        server:setsockname("*", 14285)
        server:setoption("broadcast", true)
        server:settimeout(0)
        my_server = server
        server_name = Server_Name
    end
end

function updateEntities(pos, client)
    if not entities[entity] then
        entity = scene:entity()
        entity.model = craft.model(asset.builtin.Primitives.Sphere)
        entity.position = pos
        body = entity:add(craft.rigidbody, DYNAMIC)
        entity:add(craft.shape.sphere, 1)
        entity.material = craft.material(asset.builtin.Materials.Specular)
        entity.material.diffuse = color(math.random(0, 255), math.random(0, 255), math.random(0, 255))
        body.linearDamping = 0.3
        my_entity = entity
        if client ~= nil then
            entity.master = client
        end
        table.insert(entities, entity)
    end
end

function touched(touch)
    if touch.state == MOVING then
        if touch.deltaX > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(-30, 0, 0))
                end
            end
        elseif touch.deltaX < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(30, 0, 0))
                end
            end
        elseif touch.deltaY > 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, 30))
                end
            end
        elseif touch.deltaY < 0 then
            for i,e in pairs(entities) do
                if e == my_entity then
                    e:get(craft.rigidbody):applyForce(vec3(0, 0, -30))
                end
            end
        end
    end
end

function draw()
    messenger:sendto("checking for servers", "255.255.255.255", "14285")
    if my_server ~= nil then
        local data, ip, port = my_server:receivefrom()
        if data == "checking for servers" then
            my_server:sendto("server available"..my_server:getsockname(), ip, tostring(port))
        elseif data ~= nil then
            if string.find(data, "join") then
                local tab = json.decode(data)
                for i,c in pairs(client_data) do
                    my_server:sendto("new client: "..json.encode(tab), c.ip, c.port)
                end
            end
        end
    end
    local data = messenger:receive()
    if data ~= nil then
        if string.find(data, "server available") then
            local address = string.sub(data, 17, #data)
            parameter.action(address, function() joinServer(address) end)
        end
    end
    for i,c in pairs(clients) do
        local data = c:receive()
        if data ~= nil then
            if string.find(data, "new client") then
                local tab = json.decode(data)
                updateEntities(vec3(tab.x, tab.y, tab.z))
            end
        end
    end
end

@Creator27 Still needs work.