Jump to content

  • Log In with Google      Sign In   
  • Create Account

Opinions on my multiplay solution


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 Xanather   Members   -  Reputation: 708

Like
0Likes
Like

Posted 06 November 2012 - 12:35 AM

Ive developed a prototype for a game I am developing, I am just wondering on what more experienced network programmers think on my approach.

General:
  • 2D game, not a shooter obviously.
  • Using TCP - prefixing all messages with message lengths, all handled in the download algorithm.
  • Enabled NO_DELAY
Server:
  • Server has a fixed game loop of 60 ticks each second
  • At the start of each loop the server downloads all available data from all clients and tries to process any full messages received (i.e. if message length has been reached, etc...). During this stage, if a message received is for example, "player X moving left", then the server checks if the received coordinates from where the player moved from is not using any sort of speed hack by comparing current position in server memory (etc.. etc.. handled all of this), then all other connected clients have their upload buffer added to with this new movement message.
  • During the middle of a game loop (where the game tick is processed) all new messages to upload are placed into their respectful client upload buffers. (i.e. a NPC moved left/right).
  • Just before the end of the game loop the server uploads all data in all uploads buffers of all connected clients.
  • At the end of the game loop, all connections are checked to see if everyone is still connected correctly.
  • There is only one thread which handles all of this

Client:
  • Client has a fixed game loop of 60 ticks each second
  • Also downloads everything at the start of the loop
  • Also uploads everything just before the end of the loop
  • Checks the server connection at the end of the game loop
  • There is also only one thread which handles all of this.
What do you think about this approach? Obviously read/write calls from the network stream cannot be blocking calls.
All replies appreciated, thanks :)

Sponsor:

#2 hplus0603   Moderators   -  Reputation: 5314

Like
1Likes
Like

Posted 06 November 2012 - 11:34 AM

That can work fine.
enum Bool { True, False, FileNotFound };

#3 Xanather   Members   -  Reputation: 708

Like
0Likes
Like

Posted 07 November 2012 - 06:16 AM

Ok, cool, thanks :)

#4 Sirisian   Crossbones+   -  Reputation: 1756

Like
1Likes
Like

Posted 08 November 2012 - 06:33 PM

Just know that 60 updates per second is a lot. Not sure if this is for the Internet, but with TCP you might see stuttering so you might want to lower that down to 10 to 20 in the future depending on your requirements.

#5 Xanather   Members   -  Reputation: 708

Like
0Likes
Like

Posted 09 November 2012 - 12:13 AM



Yeah, it is used over the internet. I thought about the frequency, but since the game I am making is not a similar to what a "shooter" game may use I thought why not.

Data is only sent when data actually needs to be sent, all messages are considered "important" and there's no need to constantly send out packets like that of what UDP connection may do.

Edited by Xanather, 09 November 2012 - 12:15 AM.


#6 KnolanCross   Members   -  Reputation: 1294

Like
1Likes
Like

Posted 16 November 2012 - 01:04 PM

My considerations:
- If you have some kind of id for each message, you mostly don't need to send the size of the message to the server (most of the messages will have an exact size).
- If you are using TCP, what do you mean by all connections are checked? I assume you are using select to implement this, since it is single-threaded, so the socket will be set and your receive will receive 0 bytes when a connection is finished or possibly a -1 if something went really wrong.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).


#7 Xanather   Members   -  Reputation: 708

Like
0Likes
Like

Posted 19 November 2012 - 10:35 AM

@KnolanCross
That idea about specific id not needing certain message lengths is interesting, might implement that.
For your second point it is important to note that I am only downloading data if .IsDataAvailable returns true (using .net TcpClient class) so the thread doesn't block. Only at the end of the loop each connection is checked by checking .Connected. This field only returns false though after a failed read/write, and just before the connections are checked necessary data is Uploaded to all clients meaning any failed uploads will render the .Connected field false.

What do you think about that?

#8 KnolanCross   Members   -  Reputation: 1294

Like
2Likes
Like

Posted 19 November 2012 - 11:03 AM

Don't really know how the .net API works so I can't really tell if there is a better way to do so.

The points I would check are:
- Assuming .IsDataAvailable blocks the thread, will it return true if a connection drops?
- What happens is if the clients don't ask for updates when its idle (I am not assuming this happens, but with your explanation I couldn't be 100% sure) or if no client is connected. Wouldn't your simulation stop then?

Whenever you have a blocking single threaded approach is mostly good to have a timeout in the blocking part to check if everything is ok and avoid the program to stay locked forever. Other than that everything looks fine.

If it is a non-blocking API, I would recomend you to move to a blocking one, since a non-blocking approach is away more expensive.

Edited by KnolanCross, 19 November 2012 - 11:04 AM.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).


#9 Xanather   Members   -  Reputation: 708

Like
0Likes
Like

Posted 20 November 2012 - 12:17 AM

Sorry .IsDataAvailable is called NetworkStream.DataAvailable.

Anyway on MSDN it says:

Use the DataAvailable property to determine if data is ready to be read. If DataAvailable is true, a call to Read returns immediately. If the remote host shuts down or closes the connection, DataAvailable may throw a SocketException.

So I thought checking DataAvailable would never throw a exception/block the thread unless the remote (client closes the connection) - but that wont happen anyway because Ive handled graceful disconnects.

For point 2: the client would eventually get disconnected from the server either way (say if a NPC moved nearby). On the client side a latency message is sent every 500ms so they would loose connection always if the servers drops.

Regarding having only one single thread: I just didn't want to create a new thread for each new client (255 clients mean 255 threads). Do you think it is safe to use the .net Task Parallel Libraries on the main thread if it is needed? I am also planning to move to .net 4.5 and make extensive use of the new .net Async methods soon. Ill just slap a async keyword on every method that has a chance to block.

Thanks for reply's btw, really helps Posted Image

Edited by Xanather, 20 November 2012 - 12:25 AM.


#10 hplus0603   Moderators   -  Reputation: 5314

Like
1Likes
Like

Posted 20 November 2012 - 10:19 AM

checking DataAvailable would never throw a exception/block the thread unless the remote (client closes the connection)


That is correct.

didn't want to create a new thread for each new client


That is also correct.

use of the new .net Async methods


You can do many cool things with those!

just slap a async keyword on every method that has a chance to block


That is not necessarily the right thing to do. Async development needs more careful design and planning than that.

enum Bool { True, False, FileNotFound };

#11 KnolanCross   Members   -  Reputation: 1294

Like
2Likes
Like

Posted 20 November 2012 - 11:32 AM

My point is that what it seems to me by your explanation is that your game loop depends on the receiving of messages or a disconect exception by the client. If none of those arrives, it will be in blocking state forever. You said that the client will send a message every 500 ms, but then you are assuming that the clients will play fair, this may lead to security issues.

Let me try to explain the problem this may cause with an example:
Assuming you will have multiple single threaded servers running multiple instances (each instance is a match where one or more players can play). I can create a hacked client that will:
1) Mimic the behavior of an original program until I get into a new world for myself. Up to here I am a normal client.
2) By the point I should start sending messages to the server, I just don't send anything.
3) The server is in a blocking state, waiting for info that will never arrive.

In this scenario the client will not be dropped because the hacked client can send TCP keepalive packages, which will keep the connection up. This is a "vandalism hacking attack" that your server may be susceptible.
You should set a server-side timeout on this so it will take actions every few ms even if no client sent any messages to avoid this kind of attack. As I said, I don't know anything about C# (I am a C/python programmer), but I believe the method you should look is this one:
http://msdn.microsof...8(v=vs.80).aspx (NetworkStream.ReadTimeout)

Edited by KnolanCross, 20 November 2012 - 11:33 AM.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).


#12 Xanather   Members   -  Reputation: 708

Like
0Likes
Like

Posted 20 November 2012 - 09:07 PM

Well, that does make sense, but the latency messages arn't necessarily "keepalive" message.

About a hacker trying to crash the server; all the establish-connection related stuff IS in a separate thread (should have probably said that xD), after the client/server handshake with a sequence of bytes then both the client/server go into "gameplay" mode, changing from the "login" mode (the server adds the client to the list of clients for the client to be iterated though on the main thread), the game state also changes on the client side and the client can now play. After that I don't think there are any game related messages that can actually freeze the server. The hacker could surely freeze the thread in the separate "establish-connection" thread, but that'd be pointless lol (but they could also create a infinite amount of pointless threads by doing this, I actually thought of this and will probably implement a timeout value so the hacked client just gets dropped, liked you said).

That is not necessarily the right thing to do. Async development needs more careful design and planning than that.

Haha yeah I know xD

Thanks,
Xanather.

Edited by Xanather, 21 November 2012 - 12:08 AM.


#13 KnolanCross   Members   -  Reputation: 1294

Like
0Likes
Like

Posted 21 November 2012 - 09:27 AM

Not only that (creating loads of useless threads), sometimes you have small interpolated actions based on last time difference.
For instance, on a general approach, you have the movement calculated in something similar to (this example is a client server game I coded for college some time ago):

[source lang="python"] def calcNewPosition(self, movespeed, timeInterval, ang): posTuple = self.getPos() x = posTuple[0] + (movespeed * (timeInterval) * sin(radians(ang))) y = posTuple[1] + (movespeed * (timeInterval) * cos(radians(ang))) z = posTuple[2] return (x, y, z)[/source]
If the client can "freeze" the server, it may make the time inverval vary so much that it will end up "teleporting" in the game. If this happens, the collision calculation won't be effective and the character may end up being able to cross walls, fly or just create some unhandled situation that may end up with a crash.

Edited by KnolanCross, 21 November 2012 - 09:30 AM.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS