LuaSocket questions

2

Comments

  • Posts: 2,042

    @Juce, I have code above to find your own ip if that's what you meant.

    @Jmv38, I have a two person painting app I'll share if you want

  • IgnatzIgnatz Mod
    Posts: 5,396

    Jmv38 +1

    I too would like to see a complete example that makes it easy to include in a project - maybe a little library?

  • Jmv38Jmv38 Mod
    edited March 2015 Posts: 3,295

    @JakAttak sure that would be great if you would share it!
    Btw, is it possible to connect 2 ipads not on the same wifi local network?

  • Posts: 835

    @Jmv38, From the testing i've done, i havent been able to do it, but there might be a way to do it

  • Posts: 154

    @JakAttak, i figured that you probably have, since you had shared your Multiplayer library :), but i was just experimenting and wanted to start with something simple.

    @Jmv38, yes i am writing a small library and will post here as soon as it's in a useable shape.

    It is possible to connect two ipads on two complety separate networks, but it requires a bit more work. I will include an example of that in my code.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    @-) Cant wait to see it...

  • Posts: 2,042

    @Jmv38, here it is:

    function setup()
        local connectionMade = function()
            output.clear()
            parameter.clear()
            print("Connected!")
    
            gameSetup()
        end
    
        multihandler = Multiplayer(receiveData, connectionMade)
    
        parameter.action("Host Game", function()
            multihandler:hostGame()
        end)
    
        parameter.action("Find Game", function()
            multihandler:findGame()
        end)
    
        parameter.action("Join Game", function()
            if other_ip then
                multihandler:joinGame(other_ip, other_port)
            else
                parameter.text("other_ip", "")
                parameter.text("other_port", "")
    
                print("Fill in the host's ip and port, then click join game again")
            end
        end)
    end
    
    function gameSetup()
        canvas = image(WIDTH, HEIGHT)
        parameter.color("pen_col", color(0, 255, 0))
        parameter.integer("pen_size", 2, 100, 10)
        parameter.action("clear", function()
            clear()
            multihandler:sendData("clear")
        end)
        pen_touch = nil
        last_point = vec2(0, 0)
    end
    
    function clear()
        canvas = image(WIDTH, HEIGHT)
    end
    
    function receiveData(d)
        if d == "clear" then
            clear()
        else
            local tb = loadstring("return " .. d)()
            drawPoint(tb.point, tb.last_point, tb.drawing_line, tb.pen_size, tb.pen_col)
        end
    end
    
    function drawPoint(point, lastPoint, drawingLine, penSize, penCol)
        pushStyle()
        setContext(canvas)    -- Start drawing to screen image
    
        fill(penCol) stroke(penCol)    -- Set draw color to color var
    
        strokeWidth(penSize)
        if drawingLine then
            line(point.x, point.y, lastPoint.x, lastPoint.y)    -- draw a line between the two points
        else
            ellipse(point.x, point.y, penSize)    -- Place a dot there
        end
    
        setContext()
        popStyle()
    end
    
    function draw()
        background(255, 255, 255, 255)
    
        multihandler:update()
    
        if multihandler.connected then
            sprite(canvas, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)    -- Draw the image onto the screen
        else
            fill(0)
            text("Waiting for connection...", WIDTH / 2, HEIGHT / 2)
        end
    end
    
    function vec2ToStr(vec)
        return "vec2" .. tostring(vec)
    end
    
    function colToStr(col)
        return "color(" .. col.r .. ", " ..  col.g .. ", " .. col.b.. ", " .. col.a .. ")"
    end
    
    function touched(t)
        if multihandler.connected then
            local p, lp, d, ps, pc = vec2(t.x, t.y), last_point, drawing_line, pen_size, pen_col
            if t.state == BEGAN then
                pen_touch = t.id
            end
            if t.id == pen_touch then
                drawPoint(vec2(t.x, t.y), last_point, drawing_line, pen_size, pen_col)
                drawing_line = true
                last_point = vec2(t.x, t.y)
            end
            if t.state == ENDED then
                drawing_line = false
                pen_touch = nil
            end
    
            multihandler:sendData("{ point = " .. vec2ToStr(p) .. ", last_point = " .. vec2ToStr(lp) .. ", drawing_line = " .. tostring(d) .. ", pen_size = " .. ps .. ", pen_col = " .. colToStr(pc) .. " }")
        end
    end
    

    Fairly simple stuff, just needs my Multiplayer class as a dependency

  • Jmv38Jmv38 Mod
    Posts: 3,295

    thanks, but how can we get the ip and port of another player?
    Could you start a game we could join for instance?

  • edited March 2015 Posts: 2,042

    @Jmv38, non-local networking is a little more complicated, but I do hope to add it later (I don't have access to two iPads right now so I can't do any more work.)

    Right now you can just start and join local games (when you start one, it will print your ip and port for the other player to join to )

  • Jmv38Jmv38 Mod
    edited March 2015 Posts: 3,295

    ok, thanks.
    I cant really test it cause codea wont run on my other ipad (it is an ipad1).

  • Wouldn't you need a server for non-local multiplayer? Im thinking of building a server anyways so I would be happy to lend a hand.

  • Posts: 547

    You only need a server if you want your game to be online 24/7

    The easiest way to get around connecting to non-local custom games, would be to require a login (this part would have to be on a server database tho) and having the ip of your device stored in the database everytime you connect (so that it updates if you change netwerk)

    Then when trying to join someone, you type in their name or so, and the database passes the ip to you

    But I'm sure there's other ways to do this :p

  • Posts: 1,358

    Hi All,

    Just a simple question, but it may have a complicated answer.

    We use http.request() to download information from the web by providing a url. I have downloaded raw data from a Gist on Github to use within my apps. I have been using Love 2D to help speed up the development process but find I can't use the same system. The reason is the url for the raw data is actually HTTPS which Love 2D doesn't support.

    The question is - is there any way to get round this?

    Thanks,

    Bri_G

    :D

  • @JakAttak from what I've seen from your posts here you seem to know your way around socket coding. I've just recently found out that codea can even use sockets and as with any new field of programming it's nearly impossible to teach ones self how to use it.
    With socket coding, how should I begin my code in regards to the bare necessities to get a socket running.

    Thanks in advance

  • A modified version that shows what the other device is typing in realtime.
    I have tested is and it works.

    function setup()
        socket = require("socket")
    --here you put the port of your socket. 
        local myip, myport = getLocalIP(), 5544
        print("Connect to " .. myip .. ":" .. myport)
    
        server = socket.udp()
        server:setsockname(myip, myport)
        server:settimeout(0)
    
        client = socket.udp()
    
    --ip must be with quotations and periods seperating the segments as such
    -- "111.222.3.4" (not actual ip address that im aware of) port is simple
    -- such as 5544, doesnt need quotations or anything.
    -- here you put the ip and port of the device you want to connect to. 
        client:setpeername("ip of other device", "port of other device")
        client:settimeout(0)
    
        parameter.text("msg_to_send", "")
        parameter.action("send message", sendMessage)
    end
    
    function getLocalIP()
        --you input your ip here
        local randomIP = "your ip, its need quotations and periods"
        --this port below is just a place holder it does nothing but it needs to be there
        local randomPort = "1991" 
        local randomSocket = socket.udp() 
        randomSocket:setpeername(randomIP,randomPort) 
    
        local localIP, somePort = randomSocket:getsockname()
    
        randomSocket:close()
        randomSocket = nil
    
        return localIP
    end
    
    function sendMessage()
        print("Client sent to server: '" .. msg_to_send .. "' at", os.date("%x, %X", os.time()))
    end
    
    function draw()
    --I modified the original so that the message is sent each frame, you see the other -- person's message typed out letter by letter as they type it.
    --It shows your message on top and the message being received on the bottom
        background(0, 0, 0, 255)
        client:send(msg_to_send)
        stroke(255, 255, 255, 255)
        fontSize(30)
        text(msg_to_send, 250, 600)
    
    
        local data, msg_or_ip, port_or_nil = server:receivefrom()
        if data then
            stroke(255, 255, 255, 255)
            fontSize(30)
            text(data, 250, 300)
    
    
        end
    end
    

    This is also modified from how @JakAttak originally made it so that it allows for two way data sending between devices in one program.
    Have fun

  • Posts: 2,042

    @Archimedes, sorry for the late reply I've been offline the last week, but it seems you've gotten the hang of it already. Nice work!

  • Thanks

  • Posts: 411

    @skycoder @toffer @ignatz what does the 'load' do in toffer's code above?

                local f,e = load(table.concat(buf,"\n"))
    
  • toffertoffer Mod
    Posts: 151

    @piinthesky - my example was a dumb repl. Codea listening for incoming string and eval it. The buf var is the buffer of strings and is evaluated each time a new string is sent by the client and cleared if the eval succeed. Lua 5.3 load is equivalent to Lua 5.1 loadstring.

  • Posts: 411

    thanks i missed that load is the new loadstring!

  • IgnatzIgnatz Mod
    Posts: 5,396

    I've written a post (below) showing (I hope) how to use @JakAttak's socket library. I plan to write another post (trying to) explain the library itself.

    https://coolcodea.wordpress.com/2015/04/21/211-making-multiplayer-games-part-1/

  • Jmv38Jmv38 Mod
    edited April 2015 Posts: 3,295

    great! Would you like we try your game over the internet? Just to check if the link works.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @Jmv38 - I'll message you.

  • Posts: 2,042

    @Ignatz, thanks for taking the time to do that! One thing I noticed in the write up you talk about joining two iPads that are not on the same WiFi network. Unfortunately my library actually doesn't fully support this (yet), though I think it should simply be a matter of getting the global ip as opposed to the local one. Definitely something I need to test once I can get my hands back on a second iPad.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @JakAttak - I realise that you can't search the Internet for another iPad playing your game. I guess what is really needed is a simple web server that stores ip addresses of hosts and gives them to guests.

  • @Ignatz I just built a server computer, I might be able to help though I can't guarantee I'll be able to get the server working.

  • Posts: 2,042

    To save anyone time trying to load my library or drawing example, I've uploaded it to a gist:

    https://gist.github.com/JakAttak/b418d23e99a8e996f998

  • edited November 2015 Posts: 2,020

    Apologies for bumping an old-ish thread. I've been wanting to try this for ages, but haven't been able to as I only have access to one iPad (and an iPhone).

    But now that Xcode 7 allows uploading of apps onto your devices without a developer subscription, I finally got round to trying it, by putting @JakAttak 's code as a standalone universal app onto my iPhone 4S! Thanks for putting this together @JakAttak . Code was running in Codea on an iPad Air (landscape, with the drawer open), and as an app on an iPhone 4S (fullscreen, portrait). I had to press the "clear" button to get the correct aspect ratio of the pixels on both devices, but other than that it worked great!

    This is definitely a thread to bookmark ^:)^

  • Posts: 2,020

    Has anyone tried this with a fast, reaction-based arcade game over LAN? In my tests there is a little bit of latency, ~5 frames maybe? I was wondering whether with a strictly LAN based multiplayer, is it normal to implement the kind of techniques for dealing with latency that you normally associate with web action multiplayers, such as client-side prediction, and interpolation between positions where there is disagreement?

    I was thinking of building something simple but where reactions are critical, like Pong, to test this, but was wondering whether anyone had done so already. My idea for how to structure this is: each device hosts the paddle that it "owns", the question is what to do with the ball.

    Final question: is there a way to measure the latency between the two devices (ie how long a message takes to arrive), or a way to have a synchronised clock running? I think you'd need to know that to do interpolation, as you'd need to know how far in the past the received position data is coming from.

  • IgnatzIgnatz Mod
    Posts: 5,396

    I've only tried this once between pairs of iPads, and found there could be considerable delays sometimes in updating one or the other, which made it impractical for real time gaming.

  • Posts: 2,020

    @Ignatz was that over a local network?

  • IgnatzIgnatz Mod
    Posts: 5,396

    yes, local broadband wifi, I didn't think our current code worked over the net

  • edited November 2015 Posts: 446

    Ignatz, as far as the iPad is concerned, there's no difference between local broadband and "the net": you are communicating via IP addresses in both instances. The finickity bit is port-forwarding from the router to the iPad so that the reverse connection can occur.

    Edit: if by "current code" you mean JakAttak's port-finder then yes, that won't work "over the net" as it (if I understand it right) is basically an ip+port scan. By restricting to a local network, you restrict the range of ips to scan to something reasonable. Scanning the entire internet is obviously a big task. But in principle, if you know the ip and port you can connect over the internet.

  • IgnatzIgnatz Mod
    Posts: 5,396

    Yes, JakAttak's code is what I was talking about (I do realise that IP addresses are just IP addresses..).

  • A couple months ago I set up my laptop as a makeshift server and then had my iPad send the "server" the x and y coordinates of the circle that I would drag around the screen. Then I had the server send the data it received back to the iPad and the iPad would take that data and use it to draw the circle. It's counterintuitive, but it shows how much lag there is when the iPad has to communicate with a server. When there was just one iPad the server did reasonably well (not great), but when two iPads were connected (each iPad recieving its circle's location and the other iPads circle's location) the lag was really bad. That being said I'm fairly certain that the lag is due to the iPad trying to keep up with an extremely large amount of data being sent at it, and it is not the server's fault or the socket's fault. This test was not fast or reaction based, but it proves that simply having the data be sent and received without any attempt to lighten the load is too much for the iPad to handle.

  • IgnatzIgnatz Mod
    Posts: 5,396

    I sent just a couple of numbers each frame, and the lag, while usually minimal, was sometimes very long, I don't know why.

  • Posts: 2,020

    I'm working on client-to-client pong between iPad and iPhone.

    I'm also wondering about the amount of data to send. I'm going to clip vec2s to 1 or 2 decimal places (when you print vec2s it defaults to 6 places or so). The other thing I read in one of those threads is that even fast actioners don't send information every frame, but rather every few frames, and use prediction and interpolation to fill the gaps. But that's for remote multiplayer, I was hoping that LAN would be quick enough to not require those techniques.

  • IgnatzIgnatz Mod
    Posts: 5,396

    I was sending only about 4 numbers, and still seeing prolonged freezing at times, on a fast LAN. I guess you'll just have to test it.

  • edited November 2015 Posts: 2,020

    All I can say is, coding a networked multiplayer game, even a very simple one, is hard.

  • Posts: 2,020

    A question: if I have a number of entities transmitting their position using socket.udp:sendto, is it OK to have multiple sendto calls per frame, or should I cache all of these events together and send them as a single sendto?

  • IgnatzIgnatz Mod
    Posts: 5,396

    I'm not sure anyone knows that, I would try both ways

  • @yojimbo2000, did you ever finish that pong game? If so, would you mind elaborating on how you were able to minimize lag? I have tried to program small networked games in the past, but they always end up being very laggy. However, these games were over long distances using server code set up in NodeJS - not sure if this is going to give me the best results. On faster machines in Java, for me this is no problem, but on Codea and on the iPad it seems to be quite hard. I suspect this is made harder because of the fixed speed with which the draw loop runs - currently in other languages I have been using a design pattern for a game loop from Game Programming Patterns that I quite liked - that is, have the rendering and the update loops separated such that the rendering loop runs at sporadic intervals while the update loop runs at a fixed time. I think this lends itself better to multiplayer because one can slow down the speed more easily with which updates must be sent because the game actually only updates itself that often; however, this may also be achievable in Codea to a lesser extent, I have yet to try. Also, I would expect it to be useful to minimize the amount of data sent, but I am not sure how to do this. I know that games like Minecraft have different types of packets for different events, but this seems quite complex to implement and I'm not sure I should look to Minecraft for an example of optimization. Does anyone know of a game that serves as a good example of networking, and how do they do it? Thanks, and sorry for reviving an old thread, but I thought this would be the best way to consolidate my questions.

  • Posts: 2,020

    Yeah, I don't mind sharing my pong code. The multiplayer is terrible though, I couldn't get it working at all and gave up. I'm sure it must be possible. The creators of the counter strike and quake engines have written papers on how they deal with the problem of lag (by interpolating).

    Pong

    So far we've been using udp. I wonder whether it might be worth exploring tcp. My understanding is that in theory tcp is slower, but it has better data integrity. ie its better to have a smaller quantity of good quality messages, then the connection getting lost and bunches of messages go missing. I didn't get that far though.

    I only have one iPad, so it was quite slow working. I used Xcode to deploy the other copy to my iPhone. But if you need to tweak something it's quite slow (This would be where a really good Dropbox syncing solution would be handy).

    If anyone could get this working, that'd be awesome.

    Repo is here:

    https://github.com/Utsira/Pong

    Installer:

    --# Main
    
    local url = "https://raw.githubusercontent.com/Utsira/Pong/master/Pong.codea/"
    
    local function install(data)
        --parse plist into list of tab files
        local array = data:match("<key>Buffer Order</key>%s-<array>(.-)</array>")
        local files = {}   
        for tabName in array:gmatch("<string>(.-)</string>%s") do
            table.insert(files, {name = tabName})
        end   
        --success function
        local function success(n, name, data)
            if not data then alert("No data", name) return end
            print("Loaded "..n.."/"..#files..":"..name)
            files[n].data = data
            for _,v in ipairs(files) do
                if not v.data then 
                    return --quit this function if any files have missing data
                end
            end
            --if all data is present then save...
            for i,v in ipairs(files) do
                saveProjectTab(v.name, v.data)
                print("Saved "..i.."/"..#files..":"..v.name)
            end
            for i,v in ipairs(files) do --load...
                load(v.data)() 
            end
            setup() --...and run
        end
        --request all the tab files
        for i,v in ipairs(files) do 
            local function retry(error) --try each file twice, in case of time-outs
                print(error, v.name.." not found, retrying")
                http.request(url..v.name..".lua", function(data) success(i, v.name, data) end, function(error2) alert(error2, v.name.." not found") end)
            end
            http.request(url..v.name..".lua", function(data) success(i, v.name, data) end, retry)
        end
    end
    http.request(url.."Info.plist", install, function (error) alert(error) end)
    
  • IgnatzIgnatz Mod
    Posts: 5,396

    I tried multiplayer with two iPads, and the lag was awful. There were times when nothing got through for minutes at a time, so it is utterly unreliable.

  • Posts: 2,020

    @Ignatz I'm sure this is a problem with our implementation. There are lots of approaches we haven't tried. I'm sure it must be possible with the tools we have. eg, as I mentioned above, as far as I can see, all the code here is udp, which apparently sacrifices integrity for speed. So, research questions:

    • would tcp be more reliable than udp?
    • what about opening multiple channels, via different ports?
    • experiment with sending data only a couple of times a second and doing the rest with interpolation

    etc

  • IgnatzIgnatz Mod
    Posts: 5,396

    I know very little about this stuff, or I would have tried to solve it. But I don't even know where to start!

  • Posts: 2,020

    I know very little about this stuff, or I would have tried to solve it. But I don't even know where to start!

    Me neither! Fire up the pong code on your 2 ipads and see what you come up with.

    These articles helped:

    http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/

    My thoughts:

    • It might be simplest to have an entirely server-client model: ie one iPad is the authority on where all the game objects are. I tried a mixed approach, but it's complicated.
    • Maybe go for good data over fast data, it's better a message arrives late than not at all
  • AnatolyAnatoly Mod
    Posts: 872

    Sorry for old-answer. Lock and delete my old request. So basically the video above ^. Need I have codea on both iPads and put on both the code or how it works?

  • Posts: 2,020

    Either 2 iPads with Codea

    Or

    1 iPad with Codea plus a Mac with Xcode allowing you to run the code in the iOS Simulator or letting you install it on an iPhone.

    (If only Codea were a universal app...)

Sign In or Register to comment.