Tutorial: Online Multiplayer with PodSixNet

This forum is currently in read-only mode.
  • Here's some more information about how I'm switching layouts:

    1. I check if both client and server are ready (via connection.Send({"action": readyToggle"}) and myserver.SendToAll({action": readyToggle"}) ) Client and Host can both change their ready status by checking a box, and each of the readyToggle functions update global vars corresponding to that.

    2. The host checks if both ClientReady and HostReady are true (the globals mentioned above). If they are, it sets a global "starting" to 1.

    3. When 'starting' is 1, the Host does:

    myserver.SendToAll({"action": "ready"}), which just sets the Client's 'starting' to 1 as well

    then it does myserver.Pump() and System.GoToLayout("Layout1")

    4. At this point the Client's 'starting' is 1, which just calls a GoToLayout on the Client but without pumping any connections (so same as above except no myserver.Pump() or any other .Pump().

    5. Both Client and Server are able to get to the new Layout, at which point I get the error message I mentioned.

    6. In the new layout the first round of the game starts and both the host and the Client immediately call a readyToggle2 action which repeats every so often as it is checking to see if the Client and Host ready states (if they submitted their game orders, it's turn based game).

    7. These actions are followed by myserver.Pump() (the one causing the problems I think) and connection.Pump and myclient.Pump(), with the myclient.Pump in a try/except block

  • Also, is there no way to not even acknowledge incoming connections after I've gotten one player connected?

    Yes, you can just do:

    def Connected(self, player, addr):

    if len(self.players) < 2:

    add the player...and do stuff

    Once the player count reaches 2 the connection will be received but not processed. As far as not even receiving it goes, that would require some changes to the library.

    7. These actions are followed by myserver.Pump() (the one causing the problems I think) >>> and connection.Pump and myclient.Pump(), with the myclient.Pump in a try/except block

    Are you sure that the host acting as the server is not incorrectly acting as client too? I'm assuming you have that code in separate groups, etc (a server group and a client group).

    Have you run wireshark to see what the packets look like right before the disconnect occurs?

    When the server and client switch layouts there will be some desynchronization...the key is to get everybody synchronized again before starting processing events for the next layout.

    You can also do some tests...make sure that the server has switched to Layout 2.. then wait 10 seconds and switch the client, etc... different stuff to be sure the server is ready to process packets in the second layout. Above that, I might have to see a .cap.

  • Just in case this is useful to others, I was able to track down the problem with the help of scidave. Apparently trying to do connection.Send() over and over while the server is switching layouts causes the connection to close. The solution was to shut the client up while the server was changing layouts.

  • Hmm, another question. I'm trying to do the following:

    For Each Units (Event)
    
    myserver.SendToAll({"action": "updateUnits", "Home": SOL.Units.Value('Home'), "Type": SOL.Units.Value('Type'), "AttackTarget": SOL.Units.Value('AttackTarget'), "MoveTarget": SOL.Units.Value('MoveTarget'), "HP": SOL.Units.Value('HP'), "Team": SOL.Units.Value('Team'), "SpecialsTarget": SOL.Units.Value('SpecialsTarget')})
    
    myserver.SendToAll({"action": "updateOrder", "Order": SOL.Units.Value('Order')})
    
    Trigger Once while True (event)
    
    myserver.SendToAll({"action": "processSync"})
    [/code:alye2eyf]
    
    If I comment out the two myserver.SendToAll() calls at the top (updateUnits and updateOrder) the third one works (processSync).  However, if they are all uncommented, processSync does not seem to go through.  It gets called, but the client on the other side does not receive it.  Is there a limit to what I can send ?  And how can I make sure that stuff gets there if I want to send a bunch of data?
  • I'm not sure how you are updating your info, but one thing that might help is to do a "SendtoOthers" call versus a "SendtoAll". If one client has already moved and you just need to send that status to the other client (but don't need extra network traffic) you can do a:

    # this send to all clients but yourself
       def SendToOthers(self, data, player):
          for p in self.players:
             if p != player:
                p.Send(data)
    [/code:2v51d0ib]
    
    You call it like(within a Python class):
    self._server.SendToOthers(data,self)
    
    From a Python script within Construct...I'm not positive how it would be called without some testing (not sure if it is a number or Class instance address).  You can look at the Dungeon Server example from the tut for this.
    
    Not sure though that will solve the problem.  Perhaps it is just too much data to be sent during one tick.  The myserver calls are asynchronous to Construct events....so Construct isn't going to wait for one call to finish before it does the next action.  So Construct  is going to loop through all the Units very rapidly firing off a myserver.SendToAll calls almost all at the same time..which might be creating a bottleneck.  So maybe there is a way to experiment with breaking up not sending as much data each time or adding a slight pause (Wait plugin?..not sure how buggy it is) after each SendToAll in the "For Each Units" loop.  How many units do you have?
    
    As far as a limit:  You shouldn't be trying to send more than 1500 bytes at a time (the Maximum Transmission Unit (MTU) over most networks.  Although, I would suspect PodSixNet would handle that transparently, but I didn't check.
    
    Give the above a thought and let me know how it goes.
  • There's only one client allowed so that shouldn't matter.  I assumed that it must be the fact that the calls are not waiting for stuff to go through before moving on, and that the client was missing some of the incoming data that way (the server was sending it as I tested, but teh client was not getting it) because it was not waiting for the server's info to all come in, but was instead busy trying to do its own data sending to the server.  <div>

    </div><div>I was able to fix the problem by having the client and server do their networking stuff one at a time, such that they wait for each other to be done with sending stuff stuff before sending their own information.  Since it's a turn-based game this works.  I didn't do this originally because the data sent back and forth was independent and I thought it would be faster to have both client and server send to each other at the same time, but apparently when sending a ton of data that way, it doesn't work.  Still haven't tested it with high latency (ran both server and client on same machine) but it seems all the data is getting transferred now.</div><div>

    </div><div>I think all of the networking features in my game are working now :)  Thanks again for the help and the amazing tutorial, I didn't think it would only take such a short time to get the multiplayer operational!</div>

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • What's the difference between a TCP protocol module and a UDP one?

  • Juryiel

    Glad to hear!

    Guif0DA

    TCP is connection oriented, stateful, and reliable. Packets are sequenced and arrive in order. If a packet is dropped by the target computer all other packets must wait in a queue until the dropped one is resent and processed. Thus why TCP is not ideal for fast online games.

    UDP is connectionless and unreliable. In the scenario above, UDP would not have a problem as the next packet (technicaly a datagram) would be processed immediately. Most game engines have an additional layer on top of UDP to add some reliability and statefullness, when needed.

  • Hi everyone!

    First of all, networking is a new thing for me.

    scidave wrote:

    "Adding text based online using PodSixNet would be as simple as taking the chat example and expanding it a little bit.

    The only part that isn't easy is initiating connections with your opponents. Right now you need a internet facing server (or you have to manually configure port forwarding on your computer)..."

    Who need to set up 'port forwarding'? The server, the clients, or both...

    What is an 'internet facing server'? (related to construct+PodSixNet)

    Do I have to pay for it?

    Thanks for reading this post.

  • Only the server needs to have port forwarding setup.

    An internet facing server is an computer that can be accessed from the internet by IP address or Domain name. It could be your home computer (where you enable port forwarding on your router) or it could be a dedicated server.

    You don't need to pay if you want to go the simple port forwarding approach.

    Here is a link that shows port forwarding:

    associatedcontent.com/article/1556120/how_to_enable_port_forwarding_on_a.html

  • Does this work with C2, or just Construct?

  • WonkaVee

    Just Construct Classic <img src="smileys/smiley6.gif" border="0" align="middle" />

  • It is pretty interesting though, this makes me want to load up CC and experiment.

    Anyone has any brief information on how secure this is? The speed? comparison to other networking sockets etc.

  • Hey Rory,

    PodSixNet is fairly efficient since it has a built in encoder/serialization. It is only TCP so isn't going to be useful for shooters or other fast real-time gaming. You can host the server (if you want to only use Python) on any system that supports Python (Linux, Windows, etc).

    I'm not sure what you mean by secure..it can be made as secure from cheating based on how much you host on the server and what type of checking you program in.

    If you are interested in faster performance look at the Plugin I made as a wrapper around Enet. It is posted in the work in progress plugin section. I will warn you that there are some bugs so it is not as stable as PodSixNet, but it is based on UDP so is much faster. It could be made even faster if compression was added.

  • Hey Rory,

    PodSixNet is fairly efficient since it has a built in encoder/serialization. It is only TCP so isn't going to be useful for shooters or other fast real-time gaming. You can host the server (if you want to only use Python) on any system that supports Python (Linux, Windows, etc).

    I'm not sure what you mean by secure..it can be made as secure from cheating based on how much you host on the server and what type of checking you program in.

    If you are interested in faster performance look at the Plugin I made as a wrapper around Enet. It is posted in the work in progress plugin section. I will warn you that there are some bugs so it is not as stable as PodSixNet, but it is based on UDP so is much faster. It could be made even faster if compression was added.

    I am new to this and have admittedly yet to tackle what networking library I would use with Python, I will get to that I'm getting my object tracking sorted first, however I'd wonder why you think compression would increase the speed? This is not a problem of bandwidth but with latency?

    Anyway I very much appreciate your posts, I will start with this when I get to networking

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)