@Creator27 Still got the error with tab.ip . Removed tab and still getting nil for result.
@dave1707, I really don’t know what’s going on. It works perfectly fine for me. Have you checked to see if the server on iPad #1 is even receiving a message in the first place?
@Creator27 On ipad1, where I do CreateRoom, I get a message “requesting server info” when I do FindRoom on iPad2. I put a print statement “sending server info” on ipad1 to show it was sending server info back to iPad2. I wasn’t receiving anything back on iPad2, the “result” was still nil.
@Creator27 Here’s a copy of my code showing how I keep reading messages using the “repeat until” loop. I commented out some code so it would work using 1 iPad. Tap the screen to send 10 messages each time. You can increase the “for loop” count if you want to try more messages. I sent and received 1000 messages with no trouble.
viewer.mode=STANDARD
function setup()
fill(255)
delay=0
rdev=remoteDevice()
msgRcvd,msgSent=0,0
nbr,tt=0,0
end
function draw()
background()
rdev:getIp()
-- keep reading messages until there's no more data
repeat
rdev:receiveTheirMessage()
until noData
text("Messages sent "..msgSent,WIDTH/2,HEIGHT-30)
text("Messages received "..msgRcvd,WIDTH/2,HEIGHT-60)
text("Tap screen to send messages",WIDTH/2,HEIGHT/2)
end
function touched(t)
if t.state==BEGAN then
output.clear()
-- send messages
for z=1,10 do
str=string.format("sent message %4d abcdefghijklmnopqrstuvwxyz",msgSent+1)
rdev:sendMessage(str)
end
end
end
remoteDevice=class()
function remoteDevice:init()
self.socket=require("socket")
self.myIp="0.0.0.0"
self.theirIp="0.0.0.0"
self:getMyIp()
self:setMySocket()
self:setTheirSocket()
self:getTheirIp()
end
function remoteDevice:getIp()
if not gotMyIp or not gotTheirIp then
if delay>60 then
delay=0
if not gotMyIp then
rdev:getMyIp()
end
if not gotTheirIp then
rdev:getTheirIp()
end
end
delay=delay+1
end
end
function remoteDevice:setMySocket()
self.server=self.socket.udp()
self.server:setsockname(self.myIp,5544)
self.server:settimeout(0)
end
function remoteDevice:setTheirSocket()
self.client=self.socket.udp()
self.client:settimeout(0)
end
function remoteDevice:getMyIp()
self.server=self.socket.udp()
self.server:setpeername("1.1.1.1",80)
self.myIp,self.myPort=self.server:getsockname()
self.ip1,self.ip2=string.match(self.myIp,"(%d+.%d+.%d+.)(%d+)")
print("my IP = "..self.ip1..self.ip2)
gotMyIp=true
end
function remoteDevice:getTheirIp()
self.client=self.socket.udp()
self.client:settimeout(0)
-- send a message to everyone on this network except to myself
for z=1,255 do
-- commented below code to allow a message to myself
--if z~=tonumber(self.ip2) then
self.client:setpeername(self.ip1..z,5544)
self.client:send("get their ip")
--end
end
end
function remoteDevice:receiveTheirMessage()
noData=true
local data,msg,port=self.server:receivefrom()
if data~=nil then
noData=false
msgRcvd=msgRcvd+1
if data=="get their ip" then
self.client=self.socket.udp()
self.client:settimeout(0)
self.client:setpeername(msg,5544)
self.client:send("got their ip"..self.myIp)
print("message-> get their ip")
elseif string.sub(data,1,12)=="got their ip" then
self.theirIp=msg
print("their IP = "..self.theirIp)
gotTheirIp=true
print("message-> got their ip")
elseif string.sub(data,1,12)=="sent message" then
print(data)
end
end
end
function remoteDevice:sendMessage(tempStr)
msgSent=msgSent+1
self.client = self.socket.udp()
self.client:setpeername(self.theirIp,5544)
self.client:settimeout(0)
self.client:send(tempStr)
end
@dave1707, try changing the findRoom function to this:
function findRoom()
print("Attempting to find a room...")
finding_room = true
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
local ip1, ip2 = string.match(ip, "(%d+.%d+.%d+.)(%d+)")
-- We need to use our listener socket and broadcast a request message to every server on the network
listener:setsockname("*", "14285")
-- Turn on broadcast messaging
listener:setoption("broadcast", true)
for z = 1, 255 do
listener:sendto("requesting server info", ip1..z, "14285")
end
-- Turn off broadcast messaging after
listener:setoption("broadcast", false)
current_time = os.time()
end
@Creator27 I get
Attempting to find a room…
then
Attempting to join the room…
and nothing else.
I do Find Room on the second iPad. I Create Room on the first iPad.
@dave1707, I really don’t know what has happened, but the only thing I can think of right now is to remove these lines of code from the findRoom function:
listener:setoption("broadcast", true)
And this:
listener:setoption("broadcast", true)
@Creator27 Same result as above. If I get time later, I’ll put in some print statements to see what’s happening.
The variable result in receiveData() continuously prints nil when Find Room is pressed.
@dave1707, this is not gonna work, but I slightly reworked the findRoom function and the receiveData function. Here it is:
function setup()
socket = require("socket")
parameter.action("Create Room", createRoom)
parameter.action("Join Room", function()
if other_ip then
joinRoom(other_ip, false)
else
parameter.text("IP", "", function(t)
other_ip = t
end)
end
end)
parameter.action("Find Room", function()
findRoom()
end)
client = socket.udp()
client:settimeout(0)
listener = socket.udp()
listener:settimeout(0)
-- We need to create a table that can hold information about our server, if you end up making one
server_info = {players = 0, clients = {}}
other_ip = nil
current_time = nil
current_room_count = 1
tick = 0
finding_room = false
server = false
end
function createRoom()
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
client:setsockname("*", "14285")
local ip2, port2 = client:getsockname()
client:setoption("broadcast", true)
your_ip = ip2
your_port = port2
print("Room created!")
print("Connect to "..ip)
server = true
end
function joinRoom(ip, finding_room)
if server == false then
if finding_room == false then
print("Attempting to join the room...")
end
-- The port for all the servers is the same, so we only need the IP address of the server
client:setpeername(ip, "14285")
client:send("connection confirmation")
current_time = os.time()
else
print("You are already hosting a room!")
end
end
function findRoom()
if server == false then
print("Attempting to find a room...")
finding_room = true
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
local ip1, ip2 = string.match(ip, "(%d+.%d+.%d+.)(%d+)")
for z = 1, 255 do
client:setpeername(ip1..z, "14285")
client:send("requesting server info")
end
client:setpeername("*")
client:setsockname("*", "14285")
current_time = os.time()
else
print("You are already hosting a room!")
end
end
function receiveData()
if server == true then
local msg, ip, port = client:receivefrom()
if msg ~= nil then
if msg == "connection confirmation" then
if server_info["players"] < 32 then
-- We can now add 1 more to our player count
server_info["players"] = server_info["players"] + 1
-- We now need to store the clients IP and port, so we can send them messages later
local uid = {ip = ip, port = port}
if not server_info["clients"][uid] then
table.insert(server_info["clients"], uid)
end
client:sendto("valid confirmation", ip, port)
-- We can now send everyone that has joined this room a packet telling them the amount of players in the room
for i,c in pairs(server_info["clients"]) do
client:sendto("player count"..tostring(server_info["players"]), c.ip, c.port)
end
else
-- We don't have enough room for another player, so we send the peer a message telling them to disconnect
local reason = "Max players inside the room!"
client:sendto("invalid confirmation"..reason, ip, port)
end
elseif msg == "requesting server info" then
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local our_ip, our_port = udp:getsockname()
udp:close()
-- We now know that somebody is trying to find a server, so we send a packet back to them with our server IP and port
local uid = {ip = our_ip}
client:sendto("server info"..json.encode(uid), ip, port)
end
end
else
if finding_room == false then
local result = client:receive()
if result == "valid confirmation" then
-- We know that we successfully joined the room, and we can now receive messages from the sever!
print("Successfully joined the room!")
current_time = nil
elseif result and string.find(result, "player count") then
-- We now know the current amount of players in our room, for now at least
local count = string.sub(result, 13, #result)
print("Player count: "..count)
elseif result and string.find(result, "invalid confirmation") then
-- We can now see the reason for our invalid confirmation and display it
local reason = string.sub(result, 21, #result)
print("Could not join the room: "..reason)
current_time = nil
-- We can now also remove the address and port set for our peer
client:setpeername("*")
elseif result == nil then
if current_time then
if finding_room == false then
if os.time() > current_time + 5 then
-- If we get no response back for 5 seconds or more, we know it didn't work
print("Failed to connect, please try again later")
current_time = nil
end
end
end
end
else
local result, ip, port = client:receivefrom()
if result and string.find(result, "server info") then
-- Now we can attempt to join the room with the given IP address
local tab = json.decode(string.sub(result, 12, #result))
if finding_room == true then
joinRoom(tab.ip, true)
finding_room = false
end
else
if finding_room == true then
if current_time and os.time() > current_time + 5 then
-- If we get no response back for 5 seconds or more, we know it didn't work
print("Failed to find a room!")
current_time = nil
end
end
end
end
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
receiveData()
tick = tick + 1
end
@Creator27 You’re correct, it didn’t work. Got this error when pressing Find Room.
Main:70: attempt to index a nil value (global ‘player’)
stack traceback:
Main:70: in function ‘findRoom’
Main:14: in function Main:13
@dave1707, I’ve fixed the error. I used the term “player” because when I wrote the code, I allowed it to send messages to myself for testing purposes.
@Creator27 Tried the new code. When I pressed Find Room, I got:
Attempting to find a room…
Successfully joined the room!
Player count: 1
Tried the code on a third iPad. When I pressed Find Room, it printed the above lines with
Player count: 2 printing on both iPads.
@dave1707, that’s awesome! After all this time, my code works!
@Creator27 It probably would have been a lot easier if you had access to 2 iPads. Good job.
@dave1707, I have added some code that allows a player to leave the room at any time. To test if it works, I also implemented a text box and a button that shows up if you create a server. Whatever is written in the text box will be sent to every player currently connected to your server if you press the “Send Message” button. Here’s the code:
function setup()
socket = require("socket")
parameter.action("Create Room", createRoom)
parameter.action("Join Room", function()
if other_ip then
joinRoom(other_ip, false)
else
if server == false then
parameter.text("IP", "", function(t)
other_ip = t
end)
else
print("You are already hosting a server!")
end
end
end)
parameter.action("Find Room", function()
if server == false then
findRoom()
else
print("You are already hosting a server!")
end
end)
client = socket.udp()
client:settimeout(0)
listener = socket.udp()
listener:settimeout(0)
-- We need to create a table that can hold information about our server, if you end up making one
server_info = {players = 0, clients = {}}
-- We also need to create a table that can hold info that the client has
client_info = {serverIp = ""}
other_ip = nil
current_time = nil
current_room_count = 1
tick = 0
finding_room = false
server = false
msgToSend = ""
joinedRoom = false
end
function createRoom()
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
client:setsockname("*", "14285")
local ip2, port2 = client:getsockname()
client:setoption("broadcast", true)
your_ip = ip2
your_port = port2
print("Room created!")
print("Connect to "..ip)
server = true
parameter.text("Message To Send", "", function(t)
msgToSend = t
end)
parameter.action("Send Message", function()
if msgToSend ~= "" then
sendMessage(msgToSend)
end
end)
end
function joinRoom(ip, finding_room)
if server == false then
if finding_room == false then
print("Attempting to join the room...")
end
-- The port for all the servers is the same, so we only need the IP address of the server
client:setpeername(ip, "14285")
client:send("connection confirmation")
current_time = os.time()
else
print("You are already hosting a server!")
end
end
function findRoom()
if server == false then
print("Attempting to find a room...")
finding_room = true
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
local ip1, ip2 = string.match(ip, "(%d+.%d+.%d+.)(%d+)")
for z = 1, 255 do
client:setpeername(ip1..z, "14285")
client:send("requesting server info")
end
client:setpeername("*")
client:setsockname("*", "14285")
current_time = os.time()
else
print("You are already hosting a room!")
end
end
function sendMessage(msg)
if server == true then
for i,c in pairs(server_info["clients"]) do
client:sendto(tostring(msg), c.ip, c.port)
end
end
end
function leaveRoom()
if server == false then
-- We need to notify the server that we are leaving, so we send a packet to them
client:send("disconnection confirmation")
end
end
function receiveData()
if server == true then
local msg, ip, port = client:receivefrom()
if msg ~= nil then
if msg == "connection confirmation" then
if server_info["players"] < 32 then
-- We can now add 1 more to our player count
server_info["players"] = server_info["players"] + 1
-- We now need to store the clients IP and port, so we can send them messages later
local uid = {ip = ip, port = port}
if not server_info["clients"][uid] then
table.insert(server_info["clients"], uid)
end
client:sendto("valid confirmation", ip, port)
-- We need to send the joining client our IP, so they can send messages to us later
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local our_ip, our_port = udp:getsockname()
udp:close()
client:sendto("server ip"..our_ip, ip, port)
-- We can now send everyone that has joined this room a packet telling them the amount of players in the room
for i,c in pairs(server_info["clients"]) do
client:sendto("player count"..tostring(server_info["players"]), c.ip, c.port)
end
else
-- We don't have enough room for another player, so we send the peer a message telling them to disconnect
local reason = "Max players inside the room!"
client:sendto("invalid confirmation"..reason, ip, port)
end
elseif msg == "requesting server info" then
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local our_ip, our_port = udp:getsockname()
udp:close()
-- We now know that somebody is trying to find a server, so we send a packet back to them with our server IP and port
local uid = {ip = our_ip}
client:sendto("server info"..json.encode(uid), ip, port)
elseif msg == "disconnection confirmation" then
-- We know that one of the clients connected to this server wants to leave, so we send a packet back telling them that we have been notified
client:sendto("notified of disconnection", ip, port)
local uid = {ip = ip, port = port}
local clientInfo
for i = 1, #server_info["clients"] do
if server_info["clients"][i] == uid then
clientInfo = i
end
end
table.remove(server_info["clients"], clientInfo)
-- We also need to deduct the player count
server_info["players"] = server_info["players"] - 1
end
end
else
if finding_room == false then
local result = client:receive()
if result == "valid confirmation" then
-- We know that we successfully joined the room, and we can now receive messages from the server!
print("Successfully joined the room!")
current_time = nil
-- We now create a button that allows the player to leave the room
parameter.action("Leave Room", function()
leaveRoom()
end)
elseif result and string.find(result, "server ip") then
-- Now that we have the servers IP address, we can message them later if we need to
local serverIp = string.sub(result, 10, #result)
client_info["serverIp"] = serverIp
elseif result and string.find(result, "player count") then
-- We now know the current amount of players in our room, for now at least
local count = string.sub(result, 13, #result)
print("Player count: "..count)
elseif result and string.find(result, "invalid confirmation") then
-- We can now see the reason for our invalid confirmation and display it
local reason = string.sub(result, 21, #result)
print("Could not join the room: "..reason)
current_time = nil
-- We can now also remove the address and port set for our peer
client:setpeername("*")
elseif result == "notified of disconnection" then
-- We know that we can now safely leave the server
client:setpeername("*")
print("Successfully left the room!")
elseif result then
-- We know that it's just a random test message from the server
print("Server sent a message: "..result)
elseif result == nil then
if current_time then
if finding_room == false then
if os.time() > current_time + 5 then
-- If we get no response back for 5 seconds or more, we know it didn't work
print("Failed to connect, please try again later")
current_time = nil
end
end
end
end
else
local result, ip, port = client:receivefrom()
if result and string.find(result, "server info") then
-- Now we can attempt to join the room with the given IP address
local tab = json.decode(string.sub(result, 12, #result))
if finding_room == true then
joinRoom(tab.ip, true)
finding_room = false
end
else
if finding_room == true then
if current_time and os.time() > current_time + 15 then
-- If we get no response back for 15 seconds or more, we know we couldn't find a room
print("Failed to find a room!")
current_time = nil
end
end
end
end
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
receiveData()
tick = tick + 1
end
@Creator27
I successfully created a room.
I successfully joined a room.
I left the room.
I rejoined the room.
I sent a message to the joined room.
Looks like everything is working.
@dave1707, if this code works you should be able to see every player currently connected to the server, and their positions should also be updated as well. Here’s the code:
function setup()
socket = require("socket")
parameter.action("Create Room", createRoom)
parameter.action("Join Room", function()
if other_ip then
joinRoom(other_ip, false)
else
parameter.text("IP", "", function(t)
other_ip = t
end)
end
end)
parameter.action("Find Room", function()
findRoom()
end)
client = socket.udp()
client:settimeout(0)
listener = socket.udp()
listener:settimeout(0)
-- We need to create a table that can hold information about our server, if you end up making one
server_info = {players = 0, clients = {}, world_state = {}}
-- We also need to create a table that can hold info that the client has
client_info = {serverIp = "", world_state = {}}
other_ip = nil
current_time = nil
current_room_count = 1
tick = 0
finding_room = false
server = false
joinedRoom = false
end
function createRoom()
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local ip, port = getLocalIP()
client:setsockname("*", "14285")
local ip2, port2 = client:getsockname()
client:setoption("broadcast", true)
your_ip = ip2
your_port = port2
print("Room created!")
print("Connect to "..ip)
server = true
local playerTab = {playerName = "server", playerPos = vec2(50, 50)}
table.insert(server_info["world_state"], playerTab)
end
function joinRoom(ip, finding_room)
if server == false then
if finding_room == false then
print("Attempting to join the room...")
end
-- The port for all the servers is the same, so we only need the IP address of the server
client:setpeername(ip, "14285")
client:send("connection confirmation")
current_time = os.time()
else
print("You are alrady hosting a server!")
end
end
function findRoom()
if server == false then
print("Attempting to find a room...")
finding_room = true
local ip, port = getLocalIP()
local ip1, ip2 = string.match(ip, "(%d+.%d+.%d+.)(%d+)")
local success, err = pcall(function()
for z = 1, 255 do
client:setpeername(ip1..z, "14285")
client:send("requesting server info")
end
client:setpeername("*")
client:setsockname("*", "14285")
end)
if success == false then
-- The only error you could possibly get in this case is no internet connection, so we print it
print("No internet connection!")
return
end
current_time = os.time()
else
print("You are already hosting a server!")
end
end
function sendMessage(msg)
if server == true then
for i,c in pairs(server_info["clients"]) do
client:sendto(tostring(msg), c.ip, c.port)
end
end
end
function leaveRoom()
if server == false then
-- We need to notify the server that we are leaving, so we send a packet to them
client:send("disconnection confirmation")
end
end
function resetParameters(params, args)
parameter.clear()
for i = 1, #params do
parameter.action(params[i], args[i])
end
end
function getLocalIP()
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
return ip, port
end
function receiveData()
if server == true then
local msg, ip, port = client:receivefrom()
if msg ~= nil then
if msg == "connection confirmation" then
if server_info["players"] < 32 then
-- We can now add 1 more to our player count
server_info["players"] = server_info["players"] + 1
-- We now need to store the clients IP and port, so we can send them messages later
local uid = {ip = ip, port = port}
if not server_info["clients"][uid] then
table.insert(server_info["clients"], uid)
end
client:sendto("valid confirmation", ip, port)
-- We need to send the joining client our IP, so they can send messages to us later
local our_ip, our_port = getLocalIP()
client:sendto("server ip"..our_ip, ip, port)
-- We can now send everyone that has joined this room a packet telling them the amount of players in the room
for i,c in pairs(server_info["clients"]) do
client:sendto("player count"..tostring(server_info["players"]), c.ip, c.port)
end
else
-- We don't have enough room for another player, so we send the peer a message telling them to disconnect
local reason = "Max players inside the room!"
client:sendto("invalid confirmation"..reason, ip, port)
end
elseif msg == "requesting server info" then
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local our_ip, our_port = getLocalIP()
-- We now know that somebody is trying to find a server, so we send a packet back to them with our server IP and port
local uid = {ip = our_ip}
client:sendto("server info"..json.encode(uid), ip, port)
elseif msg == "disconnection confirmation" then
-- We know that one of the clients connected to this server wants to leave, so we send a packet back telling them that we have been notified
client:sendto("notified of disconnection", ip, port)
local uid = {ip = ip, port = port}
local clientInfo
for i = 1, #server_info["clients"] do
if server_info["clients"][i] == uid then
clientInfo = i
end
end
table.remove(server_info["clients"], clientInfo)
-- We also need to deduct the player count
server_info["players"] = server_info["players"] - 1
elseif msg and string.find(msg, "client state") then
-- If we don't currently have the client state, we can simply add it into our world state
local tab = json.decode(string.sub(msg, 13, #msg))
if not server_info["world_state"][tab] then
table.insert(server_info["world_state"], tab)
end
elseif msg and string.find(msg, "state update") then
-- We can now update the client state, and then send that state to everybody else
local tab = json.decode(string.sub(msg, 13, #msg))
local existingTab
for i,t in pairs(server_info["world_state"]) do
if t.playerName == tab.playerName then
existingTab = t
-- We now edit the X and Y positions of the client state on server-side
existingTab.playerX = tab.playerX
existingTab.playerY = tab.playerY
local uid = {ip = ip, port = port}
for i,c in pairs(server_info["clients"]) do
client:sendto("client state"..json.encode(existingTab), c.ip, c.port)
end
end
end
end
end
else
if finding_room == false then
local result = client:receive()
if result == "valid confirmation" then
-- We know that we successfully joined the room, and we can now receive messages from the server!
print("Successfully joined the room!")
joinedRoom = true
current_time = nil
parameter.clear()
-- We now create a button that allows the player to leave the room
local paramName = {"Leave Room"}
local paramArgs = {function() leaveRoom() end}
resetParameters(paramName, paramArgs)
-- We now create a player for ourselves and send it to the server to be added to it's world state
local playerTab = {playerName = "client", playerX = 50, playerY = 50}
table.insert(client_info["world_state"], playerTab)
client:send("client state"..json.encode(playerTab), client_info["serverIp"], "14285")
elseif result and string.find(result, "server ip") then
-- Now that we have the servers IP address, we can message them later if we need to
local serverIp = string.sub(result, 10, #result)
client_info["serverIp"] = serverIp
elseif result and string.find(result, "player count") then
-- We now know the current amount of players in our room, for now at least
local count = string.sub(result, 13, #result)
print("Player count: "..count)
elseif result and string.find(result, "invalid confirmation") then
-- We can now see the reason for our invalid confirmation and display it
local reason = string.sub(result, 21, #result)
print("Could not join the room: "..reason)
current_time = nil
-- We can now also remove the address and port set for our peer
client:setpeername("*")
elseif result == "notified of disconnection" then
-- We know that we can now safely leave the server
client:setpeername("*")
print("Successfully left the room!")
local paramNames = {"Create Room", "Join Room", "Find Room"}
local paramArgs = {createRoom, function()
if other_ip then
joinRoom(other_ip, false)
else
parameter.text("IP", "", function(t)
other_ip = t
end)
end
end, findRoom}
resetParameters(paramNames, paramArgs)
elseif result and string.find(result, "client state") then
-- We can now accurately modify the client's world state, and update them if needed in realtime
local tab = json.decode(string.sub(result, 13, #result))
for i,t in pairs(client_info["world_state"]) do
if t.playerName == tab.playerName then
t.playerX = tab.playerX
t.playerY = tab.playerY
end
end
elseif result == nil then
if current_time then
if finding_room == false then
if os.time() > current_time + 5 then
-- If we get no response back for 5 seconds or more, we know it didn't work
print("Failed to connect, please try again later")
current_time = nil
end
end
end
end
else
local result, ip, port = client:receivefrom()
if result and string.find(result, "server info") then
-- Now we can attempt to join the room with the given IP address
local tab = json.decode(string.sub(result, 12, #result))
if finding_room == true then
joinRoom(tab.ip, true)
finding_room = false
end
else
if finding_room == true then
if current_time and os.time() > current_time + 15 then
-- If we get no response back for 15 seconds or more, we know we couldn't find a room
print("Failed to find a room!")
current_time = nil
end
end
end
end
end
end
function updatePlayers()
if joinedRoom == true then
-- We will continuously send the server our client state, so the server can make realtime changes
local playerTab = {playerName = "client", playerX = CurrentTouch.x, playerY = CurrentTouch.y}
client:send("state update"..json.encode(playerTab), client_info["serverIp"], "14285")
end
for i,t in pairs(client_info["world_state"]) do
ellipse(t.playerX, t.playerY, 30)
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
receiveData()
updatePlayers()
tick = tick + 1
end
@Creator27 Ran the code on 2 iPads. Created Room on 1st iPad, Find Room on 2nd iPad. Player Count 1 showed on 2nd iPad but not on 1st iPad. Moved my finger on 2nd iPad and a circle followed my finger, but with a large delay. Nothing ever appeared on 1st iPad other than Created Room and IP address.
@dave1707, I have updated the code. Also, try and use 3 iPads instead of 2 to test this. Here it is:
function setup()
socket = require("socket")
parameter.action("Create Room", createRoom)
parameter.action("Join Room", function()
if other_ip then
joinRoom(other_ip, false)
else
parameter.text("IP", "", function(t)
other_ip = t
end)
end
end)
parameter.action("Find Room", function()
findRoom()
end)
client = socket.udp()
client:settimeout(0)
listener = socket.udp()
listener:settimeout(0)
-- We need to create a table that can hold information about our server, if you end up making one
server_info = {players = 0, clients = {}, world_state = {}}
-- We also need to create a table that can hold info that the client has
client_info = {serverIp = "", world_state = {}}
other_ip = nil
current_time = nil
current_room_count = 1
tick = 0
finding_room = false
server = false
joinedRoom = false
myPlayer = nil
end
function createRoom()
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local ip, port = getLocalIP()
client:setsockname("*", "14285")
local ip2, port2 = client:getsockname()
client:setoption("broadcast", true)
your_ip = ip2
your_port = port2
print("Room created!")
print("Connect to "..ip)
server = true
local playerTab = {playerName = "server", playerX = 50, playerY = 50}
myPlayer = playerTab
table.insert(server_info["world_state"], playerTab)
end
function joinRoom(ip, finding_room)
if server == false then
if finding_room == false then
print("Attempting to join the room...")
end
-- The port for all the servers is the same, so we only need the IP address of the server
client:setpeername(ip, "14285")
client:send("connection confirmation")
current_time = os.time()
else
print("You are already hosting a server!")
end
end
function findRoom()
if server == false then
print("Attempting to find a room...")
finding_room = true
local ip, port = getLocalIP()
local ip1, ip2 = string.match(ip, "(%d+.%d+.%d+.)(%d+)")
local success, err = pcall(function()
for z = 1, 255 do
client:setpeername(ip1..z, "14285")
client:send("requesting server info")
end
client:setpeername("*")
client:setsockname("*", "14285")
end)
if success == false then
-- The only error you could possibly get in this case is no internet connection, so we print it
print("No internet connection!")
return
end
current_time = os.time()
end
end
function sendMessage(msg)
if server == true then
for i,c in pairs(server_info["clients"]) do
client:sendto(tostring(msg), c.ip, c.port)
end
end
end
function leaveRoom()
-- We need to notify the server that we are leaving, so we send a packet to them
client:send("disconnection confirmation")
end
function resetParameters(params, args)
parameter.clear()
for i = 1, #params do
parameter.action(params[i], args[i])
end
end
function getLocalIP()
local udp = socket.udp()
udp:setpeername("192.167.188.122", "14285")
local ip, port = udp:getsockname()
udp:close()
return ip, port
end
function receiveData()
if server == true then
local msg, ip, port = client:receivefrom()
if msg ~= nil then
if msg == "connection confirmation" then
if server_info["players"] < 32 then
-- We can now add 1 more to our player count
server_info["players"] = server_info["players"] + 1
-- We now need to store the clients IP and port, so we can send them messages later
local uid = {ip = ip, port = port}
if not server_info["clients"][uid] then
table.insert(server_info["clients"], uid)
end
client:sendto("valid confirmation", ip, port)
-- We need to send the joining client our IP, so they can send messages to us later
local our_ip, our_port = getLocalIP()
client:sendto("server ip"..our_ip, ip, port)
-- We can now send everyone that has joined this room a packet telling them the amount of players in the room
for i,c in pairs(server_info["clients"]) do
client:sendto("player count"..tostring(server_info["players"]), c.ip, c.port)
end
-- We also need to send the joining client a packet telling them to add our client state so they can see us too
client:sendto("create state"..json.encode(myPlayer), ip, port)
else
-- We don't have enough room for another player, so we send the peer a message telling them to disconnect
local reason = "Max players inside the room!"
client:sendto("invalid confirmation"..reason, ip, port)
end
elseif msg == "requesting server info" then
-- We need to find your address, so we create a new UDP socket and assign it a random IP
local our_ip, our_port = getLocalIP()
-- We now know that somebody is trying to find a server, so we send a packet back to them with our server IP and port
local uid = {ip = our_ip}
client:sendto("server info"..json.encode(uid), ip, port)
elseif msg == "disconnection confirmation" then
-- We know that one of the clients connected to this server wants to leave, so we send a packet back telling them that we have been notified
client:sendto("notified of disconnection", ip, port)
local uid = {ip = ip, port = port}
local clientInfo
for i = 1, #server_info["clients"] do
if server_info["clients"][i] == uid then
clientInfo = i
end
end
table.remove(server_info["clients"], clientInfo)
-- We also need to deduct the player count
server_info["players"] = server_info["players"] - 1
elseif msg and string.find(msg, "client state") then
-- If we don't currently have the client state, we can simply add it into our world state
local tab = json.decode(string.sub(msg, 13, #msg))
if not server_info["world_state"][tab] then
table.insert(server_info["world_state"], tab)
end
elseif msg and string.find(msg, "state update") then
-- We can now update the client state, and then send that state to everybody else
local tab = json.decode(string.sub(msg, 13, #msg))
local existingTab
for i,t in pairs(server_info["world_state"]) do
if t.playerName == tab.playerName then
existingTab = t
-- We now edit the X and Y positions of the client state on server-side
existingTab.playerX = tab.playerX
existingTab.playerY = tab.playerY
local uid = {ip = ip, port = port}
for i,c in pairs(server_info["clients"]) do
client:sendto("client state"..json.encode(existingTab), c.ip, c.port)
end
end
end
end
end
else
if finding_room == false then
local result = client:receive()
if result == "valid confirmation" then
-- We know that we successfully joined the room, and we can now receive messages from the server!
print("Successfully joined the room!")
joinedRoom = true
current_time = nil
parameter.clear()
-- We now create a button that allows the player to leave the room
local paramName = {"Leave Room"}
local paramArgs = {function() leaveRoom() end}
resetParameters(paramName, paramArgs)
-- We now create a player for ourselves and send it to the server to be added to it's world state
local playerTab = {playerName = "client", playerX = 50, playerY = 50}
myPlayer = playerTab
table.insert(client_info["world_state"], playerTab)
client:send("client state"..json.encode(playerTab), client_info["serverIp"], "14285")
elseif result and string.find(result, "server ip") then
-- Now that we have the servers IP address, we can message them later if we need to
local serverIp = string.sub(result, 10, #result)
client_info["serverIp"] = serverIp
elseif result and string.find(result, "player count") then
-- We now know the current amount of players in our room, for now at least
local count = string.sub(result, 13, #result)
print("Player count: "..count)
elseif result and string.find(result, "invalid confirmation") then
-- We can now see the reason for our invalid confirmation and display it
local reason = string.sub(result, 21, #result)
print("Could not join the room: "..reason)
current_time = nil
-- We can now also remove the address and port set for our peer
client:setpeername("*")
elseif result == "notified of disconnection" then
-- We know that we can now safely leave the server
client:setpeername("*")
myPlayer = nil
print("Successfully left the room!")
local paramNames = {"Create Room", "Join Room", "Find Room"}
local paramArgs = {createRoom, function()
if other_ip then
joinRoom(other_ip, false)
else
parameter.text("IP", "", function(t)
other_ip = t
end)
end
end, findRoom}
resetParameters(paramNames, paramArgs)
elseif result and string.find(result, "client state") then
-- We can now accurately modify the client's world state, and update them if needed in realtime
local tab = json.decode(string.sub(result, 13, #result))
for i,t in pairs(client_info["world_state"]) do
if t.playerName == tab.playerName then
t.playerX = tab.playerX
t.playerY = tab.playerY
end
end
elseif result and string.find(result, "create state") then
-- The server has instructed us to create a client state for them, so we do just that
local playerTab = json.decode(string.sub(result, 13, #result))
table.insert(client_info["world_state"], playerTab)
elseif result == nil then
if current_time then
if finding_room == false then
if os.time() > current_time + 5 then
-- If we get no response back for 5 seconds or more, we know it didn't work
print("Failed to connect, please try again later")
current_time = nil
end
end
end
end
else
local result, ip, port = client:receivefrom()
if result and string.find(result, "server info") then
-- Now we can attempt to join the room with the given IP address
local tab = json.decode(string.sub(result, 12, #result))
if finding_room == true then
joinRoom(tab.ip, true)
finding_room = false
end
else
if finding_room == true then
if current_time and os.time() > current_time + 15 then
-- If we get no response back for 15 seconds or more, we know we couldn't find a room
print("Failed to find a room!")
current_time = nil
end
end
end
end
end
end
function updatePlayers()
if myPlayer then
myPlayer.playerX = CurrentTouch.x
myPlayer.playerY = CurrentTouch.y
local playerTab = {playerName = myPlayer.playerName, playerX = myPlayer.playerX, playerY = myPlayer.playerY}
end
if joinedRoom == true then
client:send("state update"..json.encode(myPlayer), client_info["serverIp"], "14285")
end
if server == true then
for i,c in pairs(server_info["clients"]) do
client:sendto("client state"..json.encode(myPlayer), c.ip, c.port)
end
end
for i,t in pairs(client_info["world_state"]) do
ellipse(t.playerX, t.playerY, 30)
end
for i,e in pairs(server_info["world_state"]) do
ellipse(e.playerX, e.playerY, 30)
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
receiveData()
updatePlayers()
tick = tick + 1
end
@Creator27 When I ran this with 2 iPads, there were eventually 2 circles on each iPad. Moving my finger on ipad 2, caused the circle on iPad 1 move, but there was a slight delay. When I moved my finger on iPad 1, the circle wouldn’t move on iPad 2 until I moved my finger on iPad 2, but the was a long delay before the circle from ipad 1 would move. When I tried with 3 iPads, things didn’t work very well. Two circles were constantly blinking and there were large delays with the movement. One of the circles wouldn’t move.