@dave1707, could you please test this with 3 iPads and just see if you can see two spheres moving around on the first iPad. 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 = {}, puppet_states = {}}
-- 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
myPlayerServer = nil
myPlayerClient = nil
playerIdx = 0
playerTick = 0
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
end
function joinRoom(ip, finding_room)
if server == false then
if ip ~= "*" 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("Address not allowed!")
end
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, please try again later!")
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()
-- We need to notify the server that we are leaving, so we send a packet to them
if server == false then
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 and string.find(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
local clientState
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
-- A connected peer has sent their client state to us, so we update our world state accordingly
local clientState = json.decode(string.sub(msg, 13, #msg))
local hasClientState = false
local existingState = nil
for i,s in pairs(server_info["world_state"]) do
if s.playerName == clientState.playerName then
hasClientState = true
existingState = s
end
end
if hasClientState == true then
if clientState.timestamp > existingState.timestamp then
existingState.playerX = clientState.playerX
existingState.playerY = clientState.playerY
end
else
if not server_info["world_state"][clientState] then
table.insert(server_info["world_state"], clientState)
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)
local playerTab = {playerName = "client", playerX = WIDTH/2, playerY = HEIGHT/2, timestamp = playerTick}
myPlayerClient = playerTab
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("*")
joinedRoom = false
other_ip = 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 == 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()
-- We now update the position of our player puppets, so it looks like the players are being updated in realtime
for i,p in pairs(server_info["world_state"]) do
ellipse(p.playerX, p.playerY, 35)
end
end
function touched(touch)
if touch.state == BEGAN or touch.state == MOVING then
-- Here we send a packet to the server every frame, telling them our player position so it can properly update the whole game
if joinedRoom == true then
if myPlayerClient then
myPlayerClient.playerX = CurrentTouch.x
myPlayerClient.playerY = CurrentTouch.y
local playerTab = {playerName = myPlayerClient.playerName, playerX = myPlayerClient.playerX, playerY = myPlayerClient.playerY, timestamp = playerTick}
player:send("client state"..json.encode(playerTab))
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
updatePlayers()
receiveData()
playerTick = playerTick + 1
end