Good multiplayer game design?

Hello everyone! :smiley:
Alright, I’m making a multiplayer action game, you know, where people
connect to a server and kill each other. :slight_smile:
But I want to know how a good client-server should look like… I’ve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clients…
Or should I do something else? Thanks! :wink:

If you really want to do it properly you would use
the equivalent of ‘phase locking’. That’s like driving a car.

Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.

You cannot show the correct position at all times due to lag.
This is not an artifact either – it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is … eg blur vision or
something so the player can take the lag into account.

[of course when you see cows teleporting you know your
ping is down … but by then you’re dead :]On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:

Hello everyone! :smiley:
Alright, I’m making a multiplayer action game, you know, where people
connect to a server and kill each other. :slight_smile:
But I want to know how a good client-server should look like… I’ve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clients…
Or should I do something else? Thanks! :wink:


John Skaller
Felix, successor to C++: http://felix.sf.net

Personally, I would avoid visually representing each players lag in the
game world. This can lead to higher ping players being targeted simply
for that reason.
Base your movements off of time, and only update their movement and
actions when the client receives a packet.
Example:

Server sends packets describing players.
Clients receive packet and set state flags (such as velocity, direction,
and actions such as running, walking, etc)
Player A sees Player B running from left to right in front of him.
Player A’s client, based off of the player data for Player B (moving at
n speed in i, j, k direction representing 3d spatial movement, running
the “run” animation), Player B’s position is estimated.
1 second passes, in which time Player B has stopped moving.
Server sends packets describing players.
Player A’s client now adjusts, using an “easing” animation to go from
the “run” animation to the “standing” animation.

Additionally, take multi threaded server operation into serious
consideration. This is good for many reasons, but the most common of
which is most likely network latency.
A multi threaded server can easy cope with clients which are slow to
respond, or which may become unreachable in the process of a
game/connection.
Also, if this is going to be a “massively multi player” game, consider
using a master/slave setup for your server configuration (and
subsequently, server programming).
This allows what is considered “instancing” of various areas of the
playing field, and can often tie in to a dynamic LOD system quite well.
Also, it makes the server load for the primary server much
lower overall, since it has but one job: handling network traffic.

One more thing to consider is network bandwidth. While clients are
often capable of downloading data in speeds in excess of 5Mbit, not all
servers or clients are capable of such speeds.
Aim for a lowest common denominator. That will allow more clients at a
lower ping rate overall. A good estimation from my experience is no
more than 20 kilobytes per second.
This does rule out dial up users, but opens the door to almost any and
all broadband users. If you do aim for dial up users, remember that
while 56k modem users are capable of downloading at speeds of upwards of
5.5kilobytes per second, their upload speed can and will be greatly
effected by such. In this case, aim for no more than 3 kilobytes per
second for each upload and download. This can be easily accomplished
with packet scheduling (mind you, I’m not referring to OS specific
packet scheduling but scheduling built into your application.).

Hope that helps you on your way.
-Elden Armbrust

skaller wrote:> On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:

Hello everyone! :smiley:
Alright, I’m making a multiplayer action game, you know, where people
connect to a server and kill each other. :slight_smile:
But I want to know how a good client-server should look like… I’ve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clients…
Or should I do something else? Thanks! :wink:

If you really want to do it properly you would use
the equivalent of ‘phase locking’. That’s like driving a car.

Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.

You cannot show the correct position at all times due to lag.
This is not an artifact either – it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is … eg blur vision or
something so the player can take the lag into account.

[of course when you see cows teleporting you know your
ping is down … but by then you’re dead :]

Elden Armbrust wrote:

Personally, I would avoid visually representing each players lag in the
game world. This can lead to higher ping players being targeted simply
for that reason.
Base your movements off of time, and only update their movement and
actions when the client receives a packet.
Example:

Server sends packets describing players.
Clients receive packet and set state flags (such as velocity, direction,
and actions such as running, walking, etc)
Player A sees Player B running from left to right in front of him.
Player A’s client, based off of the player data for Player B (moving at
n speed in i, j, k direction representing 3d spatial movement, running
the “run” animation), Player B’s position is estimated.
1 second passes, in which time Player B has stopped moving.
Server sends packets describing players.
Player A’s client now adjusts, using an “easing” animation to go from
the “run” animation to the “standing” animation.

Additionally, take multi threaded server operation into serious
consideration. This is good for many reasons, but the most common of
which is most likely network latency.
A multi threaded server can easy cope with clients which are slow to
respond, or which may become unreachable in the process of a
game/connection.
Also, if this is going to be a “massively multi player” game, consider
using a master/slave setup for your server configuration (and
subsequently, server programming).
This allows what is considered “instancing” of various areas of the
playing field, and can often tie in to a dynamic LOD system quite well.
Also, it makes the server load for the primary server much
lower overall, since it has but one job: handling network traffic.

One more thing to consider is network bandwidth. While clients are
often capable of downloading data in speeds in excess of 5Mbit, not all
servers or clients are capable of such speeds.
Aim for a lowest common denominator. That will allow more clients at a
lower ping rate overall. A good estimation from my experience is no
more than 20 kilobytes per second.
This does rule out dial up users, but opens the door to almost any and
all broadband users. If you do aim for dial up users, remember that
while 56k modem users are capable of downloading at speeds of upwards of
5.5kilobytes per second, their upload speed can and will be greatly
effected by such. In this case, aim for no more than 3 kilobytes per
second for each upload and download. This can be easily accomplished
with packet scheduling (mind you, I’m not referring to OS specific
packet scheduling but scheduling built into your application.).

Hope that helps you on your way.
-Elden Armbrust

skaller wrote:

Hello everyone! :smiley:
Alright, I’m making a multiplayer action game, you know, where people
connect to a server and kill each other. :slight_smile:
But I want to know how a good client-server should look like… I’ve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clients…
Or should I do something else? Thanks! :wink:

If you really want to do it properly you would use
the equivalent of ‘phase locking’. That’s like driving a car.

Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.

You cannot show the correct position at all times due to lag.
This is not an artifact either – it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is … eg blur vision or
something so the player can take the lag into account.

[of course when you see cows teleporting you know your
ping is down … but by then you’re dead :]

Oohh… So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? I’ll try that, thanks! ;-)>>On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:

Leo M. Cabrera wrote:

Elden Armbrust wrote:

Personally, I would avoid visually representing each players lag in the
game world. This can lead to higher ping players being targeted simply
for that reason.
Base your movements off of time, and only update their movement and
actions when the client receives a packet.
Example:

Server sends packets describing players.
Clients receive packet and set state flags (such as velocity, direction,
and actions such as running, walking, etc)
Player A sees Player B running from left to right in front of him.
Player A’s client, based off of the player data for Player B (moving at
n speed in i, j, k direction representing 3d spatial movement, running
the “run” animation), Player B’s position is estimated.
1 second passes, in which time Player B has stopped moving.
Server sends packets describing players.
Player A’s client now adjusts, using an “easing” animation to go from
the “run” animation to the “standing” animation.

Additionally, take multi threaded server operation into serious
consideration. This is good for many reasons, but the most common of
which is most likely network latency.
A multi threaded server can easy cope with clients which are slow to
respond, or which may become unreachable in the process of a
game/connection.
Also, if this is going to be a “massively multi player” game, consider
using a master/slave setup for your server configuration (and
subsequently, server programming).
This allows what is considered “instancing” of various areas of the
playing field, and can often tie in to a dynamic LOD system quite well.
Also, it makes the server load for the primary server much
lower overall, since it has but one job: handling network traffic.

One more thing to consider is network bandwidth. While clients are
often capable of downloading data in speeds in excess of 5Mbit, not all
servers or clients are capable of such speeds.
Aim for a lowest common denominator. That will allow more clients at a
lower ping rate overall. A good estimation from my experience is no
more than 20 kilobytes per second.
This does rule out dial up users, but opens the door to almost any and
all broadband users. If you do aim for dial up users, remember that
while 56k modem users are capable of downloading at speeds of upwards of
5.5kilobytes per second, their upload speed can and will be greatly
effected by such. In this case, aim for no more than 3 kilobytes per
second for each upload and download. This can be easily accomplished
with packet scheduling (mind you, I’m not referring to OS specific
packet scheduling but scheduling built into your application.).

Hope that helps you on your way.
-Elden Armbrust

skaller wrote:

Hello everyone! :smiley:
Alright, I’m making a multiplayer action game, you know, where people
connect to a server and kill each other. :slight_smile:
But I want to know how a good client-server should look like… I’ve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clients…
Or should I do something else? Thanks! :wink:

If you really want to do it properly you would use
the equivalent of ‘phase locking’. That’s like driving a car.

Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.

You cannot show the correct position at all times due to lag.
This is not an artifact either – it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is … eg blur vision or
something so the player can take the lag into account.

[of course when you see cows teleporting you know your
ping is down … but by then you’re dead :]

Oohh… So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? I’ll try that, thanks! :wink:

That’s the model I use (for the most part).
Just in case you were wondering why, I can explain:
Say there are 16 players playing a game, connected to a single threaded
server application.
Player 9 suddenly loses power at his home/apartment/etc. Due to the
nature of TCP/IP (which is the norm, and what I assume you’ll be using),
when the server attempts to send a packet to the client, it will try to
get an ACK packet back. However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.
However, the remaining players will ALSO have to wait the same length of
time to receive data packets from the server, since it cannot do
anything else besides wait for that client which is no longer
reachable. In addition to being able to manage your connections on a
per thread basis, you eliminate the need to manage the connections by
priority. This way, you can simply go about sending and receiving data
on a per thread basis nearly without worry as to what the client is
doing. Depending on the threading package/API you’ll be using you may
have the ability to manage errant threads nicely. (i.e. Kill a thread
that is no longer responding due to being hung/blocked/etc)
Oh yes, and one other nice little tidbit of information: When running an
application such as that I’ve described above you should see a marked
and in some cases impressive increase in speed and/or efficiency when
running on a 64 bit processor (especially those with HT or similar
technology).

Perhaps I’ll write up a “network game theory” paper and link it in a
post here or something (or even in the message itself).

Good luck
-Elden Armbrust>>> On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:

[greatly shortend]

Oohh… So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? I’ll try that, thanks! :wink:

That’s the model I use (for the most part).
Just in case you were wondering why, I can explain:
Say there are 16 players playing a game, connected to a single threaded
server application.
Player 9 suddenly loses power at his home/apartment/etc. Due to the
nature of TCP/IP (which is the norm, and what I assume you’ll be using),
when the server attempts to send a packet to the client, it will try to
get an ACK packet back. However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.

If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.

Also, having a kernel thread for each player doesn’t scale well. MMO’s
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isn’t a big deal, but it’ll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.

Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which client’s data will be read on the next
recv() call so a single-threaded server is the simplest solution.On Sun, 26 Mar 2006, Elden Armbrust wrote:


Jeff Jackowski
http://ro.com/~jeffj/

However, due to the client no longer being

reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.

If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.

Also, having a kernel thread for each player doesn’t scale well. MMO’s
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isn’t a big deal, but it’ll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.

Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which client’s data will be read on the next
recv() call so a single-threaded server is the simplest solution.

Thanks you for the free advertisement for Felix! I couldn’t have
stated this better.

Felix threads scale: several million is no problem on an average PC.
They’re synchronous, so generally don’t require locks: synchronisation
is automatic and handled by channels. Switching is basically just
a single C++ virtual function call, so it’s quite quick.

Felix also does non-blocking async socket I/O behind the scenes
automatically using the fastest available event source for your
platform: IO completion ports for Windows, epoll on Linux,
Kqueue on BSD and OSX, falling back to select() as a last resort.

This is all transparent to the application programmer.

The current library only runs TCP (guess I’ll have to hassle the
async I/O developer to put UDP in … :slight_smile:

A binding to SDL and OpenGL is part of the core system. Bindings to any
C or C++ you like are easily created directly in the language,
and rarely require any executable glue logic, since the system
uses the same object model as C/C++ (and in fact generates C++).

Pre-emptive threading is also supported if you really need it.
However most people use pthreads for control inversion and
to convert blocking I/O to non-blocking I/O neither of which
actually require concurrency, and both of which are supported
directly in the core system.

Bugs and problems are fixed almost as fast as with SDL.
[Give me a break! Sam fixes your bug before you report it,
that’s hard to compete with :]On Sun, 2006-03-26 at 21:08 -0600, Jeff Jackowski wrote:

On Sun, 26 Mar 2006, Elden Armbrust wrote:


John Skaller
Felix, successor to C++: http://felix.sf.net

Jeff Jackowski wrote:

[greatly shortend]

Oohh… So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? I’ll try that, thanks! :wink:

That’s the model I use (for the most part).
Just in case you were wondering why, I can explain:
Say there are 16 players playing a game, connected to a single threaded
server application.
Player 9 suddenly loses power at his home/apartment/etc. Due to the
nature of TCP/IP (which is the norm, and what I assume you’ll be using),
when the server attempts to send a packet to the client, it will try to
get an ACK packet back. However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.

If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.

That is true that the blocking sockets are the cause for that, but I
can’t agree that UDP gives a better performance.
A faster performance, almost definitely.
An application using UDP cannot know whether data sent to a peer
application is received by the other end or not.
Additionally, for those that reach the destination, there is no
guarantee on the ordering of the data, and the receiver may get
duplicated copies of the same data. This can lead to congestion, or
even “flooding” of the client system if the upstream of
the server is significantly large enough. (Which is not uncommon with
game servers)

Also, having a kernel thread for each player doesn’t scale well. MMO’s
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isn’t a big deal, but it’ll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.

Hence the reason i stated that I use that model mostly, and used an
example of 16 players rather than 16,000.
Also, 64 bit CPUs are capable of an exceptionally larger number of
threads than a standard 32 bit CPU, which was why
I mentioned them.

Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which client’s data will be read on the next
recv() call so a single-threaded server is the simplest solution.

UDP (in my opinion) isn’t exceptionally well suited to time critical
applications such as games. Granted, some developers feel differently.
However, in a game where you want to be certain the data is arriving the
way you want it to, TCP is ideal.
Dan Kegle has a great page describing different setups for large
servers. While the site is a bit older now, he keeps it up to date
and the information is still valid for larger server applications. If
the server is to be an MMO style server, it’s definitely worth checking out.
The site is at http://www.kegel.com/c10k.html

-Elden Armbrust> On Sun, 26 Mar 2006, Elden Armbrust wrote:

skaller wrote:> On Sun, 2006-03-26 at 21:08 -0600, Jeff Jackowski wrote:

On Sun, 26 Mar 2006, Elden Armbrust wrote:

However, due to the client no longer being

reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.

If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.

Also, having a kernel thread for each player doesn’t scale well. MMO’s
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isn’t a big deal, but it’ll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.

Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which client’s data will be read on the next
recv() call so a single-threaded server is the simplest solution.

Thanks you for the free advertisement for Felix! I couldn’t have
stated this better.

Felix threads scale: several million is no problem on an average PC.
They’re synchronous, so generally don’t require locks: synchronisation
is automatic and handled by channels. Switching is basically just
a single C++ virtual function call, so it’s quite quick.

Felix also does non-blocking async socket I/O behind the scenes
automatically using the fastest available event source for your
platform: IO completion ports for Windows, epoll on Linux,
Kqueue on BSD and OSX, falling back to select() as a last resort.

This is all transparent to the application programmer.

The current library only runs TCP (guess I’ll have to hassle the
async I/O developer to put UDP in … :slight_smile:

A binding to SDL and OpenGL is part of the core system. Bindings to any
C or C++ you like are easily created directly in the language,
and rarely require any executable glue logic, since the system
uses the same object model as C/C++ (and in fact generates C++).

Pre-emptive threading is also supported if you really need it.
However most people use pthreads for control inversion and
to convert blocking I/O to non-blocking I/O neither of which
actually require concurrency, and both of which are supported
directly in the core system.

Bugs and problems are fixed almost as fast as with SDL.
[Give me a break! Sam fixes your bug before you report it,
that’s hard to compete with :]

pthreads? Aren’t those Linux-only? :stuck_out_tongue: (I’m using SDL threads)
But anyways, I’ll only allow about 10 to 20 players per server, so I can
allow one thread for each player… And… I would really like for
dial-up users to be able to play… I’ll be sending and receiving the
following struct to and from the users (in the thread):

===================
struct Player
{
// Player’s rotation, X-position, and Y-position
int Rotation, xPos, yPos;
// Person’s name
char Name[NAMELENGTH];
// Team: true = red, false = blue
bool Team;
// Player’s IPv4 address (text representation)
char IPAddress[16];
// IP address
IPAddress IP;
// Socket descriptor
TCPSocket SockDesc;
};

How much is that? 49 bytes (plus the last 2 variables)? Will a dial-up
connection handle it? Also… For the threads, what processor speed
and/or megabytes of RAM will the server need? I would like it if my old
IBM comp (350MHz P2, 192 MB RAM) was the server… :slight_smile:
Thanks you all! :wink:

pthreads? Aren’t those Linux-only? :stuck_out_tongue: (I’m using SDL threads)

No. The p stands for POSIX, and there is a Win32 implementation. Still,
unless there is a reason not to, you should stick with SDL threads.

But anyways, I’ll only allow about 10 to 20 players per server, so I can
allow one thread for each player… And… I would really like for
dial-up users to be able to play… I’ll be sending and receiving the
following struct to and from the users (in the thread):

===================
struct Player
{
// Player’s rotation, X-position, and Y-position
int Rotation, xPos, yPos;
// Person’s name
char Name[NAMELENGTH];
// Team: true = red, false = blue
bool Team;
// Player’s IPv4 address (text representation)
char IPAddress[16];
// IP address
IPAddress IP;
// Socket descriptor
TCPSocket SockDesc;
};

How much is that? 49 bytes (plus the last 2 variables)?

Probably more when you account for padding. Sort the elements from largest
to smallest in the struct to limit the padding and save memory. Also, by
writting each element to the buffer to send instead of the whole struct,
you can avoid sending a struct with padding over the network. This also
increases the portability of the code because different compilers and
different platforms may align the data differently (it’s 4-byte aligned on
most systems today, but a 64-bit system may use 8-byte alignment). By
writting each element yourself, you can also avoid writting data that
seldom changes except for when it does change, like the player’s name.
Plus, you can limit the bytes used for a string, like the name, to
strlen(string) + 1 bytes (less if you get fancy about it, but there isn’t
a great need).

Will a dial-up
connection handle it?

That depends on how often you send updates. Also plan on a 100+ms latency
introduced by the modem.

Also… For the threads, what processor speed
and/or megabytes of RAM will the server need? I would like it if my old
IBM comp (350MHz P2, 192 MB RAM) was the server… :slight_smile:

It depends on what your server is doing. If it does little more than
repeat data to all the clients, than the old system you describe can
handle it. Given that struct, I doubt your server will need to do so much
that the old system would have trouble.On Sun, 26 Mar 2006, Leo M. Cabrera wrote:


Jeff Jackowski
http://ro.com/~jeffj/

This also
increases the portability of the code because different compilers and
different platforms may align the data differently

Oh crap! Yeah, I forgot about the portability of structs… I now
remember from when I learned about binary files… :stuck_out_tongue:

That depends on how often you send updates. Also plan on a 100+ms latency
introduced by the modem.

Does that mean that I have to wait 100ms at the beginning of the
send/receive function thread?

I also have a question now… How do I send the data to the clients? I
was thinking of sending an integer saying how much players it’s going to
receive, and then send them… Is that alright? Thanks! :wink:

PS: I’m so happy about this game! I hope it comes out well… :slight_smile:

Leo M. Cabrera wrote:
[Message trimmed]

pthreads? Aren’t those Linux-only? :stuck_out_tongue: (I’m using SDL threads)
But anyways, I’ll only allow about 10 to 20 players per server, so I can
allow one thread for each player… And… I would really like for
dial-up users to be able to play… I’ll be sending and receiving the
following struct to and from the users (in the thread):

===================
struct Player
{
// Player’s rotation, X-position, and Y-position
int Rotation, xPos, yPos;
// Person’s name
char Name[NAMELENGTH];
// Team: true = red, false = blue
bool Team;
// Player’s IPv4 address (text representation)
char IPAddress[16];
// IP address
IPAddress IP;
// Socket descriptor
TCPSocket SockDesc;
};

How much is that? 49 bytes (plus the last 2 variables)? Will a dial-up
connection handle it? Also… For the threads, what processor speed
and/or megabytes of RAM will the server need? I would like it if my old
IBM comp (350MHz P2, 192 MB RAM) was the server… :slight_smile:
Thanks you all! :wink:

Well, 49 bytes is quite small…however…

You’re not sending any animation data (if there is any). Also, I can’t
seem to grasp your reasoning for sending the IP adress every update, let
alone more than once.
Once you have the IP in memory, it shouldn’t be necessary to send it
over the network any longer unless it changes mid-game. If that
happens, the client will most likely lose connectivity
anyways. Also, the team (as far as I know, I’m not sure about your
setup) shouldn’t need to be sent each update either.
If you were to leave out the IP addresses, the team boolean, and the
TCPSocket type, replacing them with a single char as an identifier,
you’d be left with a structure (not including padding) of
4 + 4 + 4 + NAMELENGTH

So if NAMELENGTH was 32 bytes, that would leave you at 44 bytes per
packet. A 56k modem client could handle ~90 updates per second (plus a
little overhead for padding, etc)
With a proper scheduling setup, you could update 50-100 milliseconds,
which would put you at 440 to 880 bytes per second (not including
overhead) per player.
It’s highly likely that if you program carefully (i.e. being very
careful to avoid even the smallest memory leak), your 350mhz machine
could potentially handle 32 players 24/7 for quite a while.
If the internet connection is fast enough, that is. For a 32 player game
you would need ~880 * 32 upstream and downstream, which would be
approximately 29kilobytes per second downstream, (~880 * 31) * 32, or
~870 kilobytes per second upstream (31 other players data sent to each
of the 32 players). To reduce the amount of upstream bandwidth you’d
need, you could update less, and reduce the size of the struct.

I would strongly recommend against sending a a character string with the
players name during updates. At a 500ms update cycle and a 12 byte
structure (dropping the name) you can realize an server upstream
requirement of only ~24 kilobytes per second for a 32 player game. This
is why I made such an issue of a good scheduling system for your data
transmission. The slightest miscalculation can lead to poor network
performance. Your current struct (at 49 bytes PLUS the last 2
variables) will most likely create horrible lag if hosted on anything
but a 10 Megabit connection.
Another thing to consider is using a char*3 to represent the rotation of
the character, and converting the resulting data to degrees for use in
your program.
That will shave 1 byte from the structure every update.

I hope that helps but things in a bit of perspective. Please, if my
math is way off on anything, let me know. Just remember that most
everything is an estimation and not a hard number. :slight_smile:
Good luck

-Elden Armbrust

This also
increases the portability of the code because different compilers and
different platforms may align the data differently

Oh crap! Yeah, I forgot about the portability of structs… I now
remember from when I learned about binary files… :stuck_out_tongue:

That depends on how often you send updates. Also plan on a 100+ms latency
introduced by the modem.

Does that mean that I have to wait 100ms at the beginning of the
send/receive function thread?

No, I just ment that your game should work OK with the greater latency. I
can send data across the US in about 100ms, or across town with a modem in
100 to 150ms.

Since it seems like your trying to keep the networking part pretty simple,
I shouldn’t have made an issue out of it. Worry about it after you’ve got
the networking code running and the latency is a problem. If it isn’t a
problem, don’t worry :slight_smile:

I also have a question now… How do I send the data to the clients? I
was thinking of sending an integer saying how much players it’s going to
receive, and then send them… Is that alright? Thanks! :wink:

That is certainly the easiest way. Even better is trying to send only data
that has changed. If the gainularity there is all the info on one player
then only when a player does something will the data be sent. That’ll help
support modem users.

To support that scheme, you may need to tell clients about new players
entering the game and existing ones leaving the game. Then it can be
useful to send messages. Based on the message type, the client or server
will process the data differently. Then you can have connect, disconnect,
and player update messages. It’s pretty common to use some sort of message
system rather than sending data for all players to all clients every time
through some update loop.

PS: I’m so happy about this game! I hope it comes out well… :slight_smile:

:slight_smile: Good luck, and have fun with it!On Mon, 27 Mar 2006, Leo M. Cabrera wrote:


Jeff Jackowski
http://ro.com/~jeffj/

pthreads? Aren’t those Linux-only? :stuck_out_tongue: (I’m using SDL threads)

P for ‘pre-emptive’ :slight_smile:

How much is that? 49 bytes (plus the last 2 variables)? Will a dial-up
connection handle it?

I played D2 for years on a 32K dial up connection with 500 ms
latency (due to server being half way around the world).
PvM was quite playable – not crash hot for PvP though.

The thing is a 56K dialup running 56K upload is the same
speed as 256K download ADSL. So I guess dialup will be
fine for the clients at least.On Sun, 2006-03-26 at 23:33 -0500, Leo M. Cabrera wrote:


John Skaller
Felix, successor to C++: http://felix.sf.net

[…]

Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which client’s data will be read on the next
recv() call so a single-threaded server is the simplest solution.

Thanks you for the free advertisement for Felix! I couldn’t have
stated this better.

[…]

The current library only runs TCP (guess I’ll have to hassle the
async I/O developer to put UDP in … :slight_smile:

I wrote some posix style stuff to do that (no win32 yet), but haven’t
yet tried it out with the demuxers. It’s one of the many felix add-ons
that I’ve got on the boil, including posix async io (aio_), epoll demuxer
and even an sdl_net demuxer* - a proposito of this, sdl_net’s
SDLNet_CheckSockets only checks for read-readiness and not write.
What’s with that?

  • lazy man’s way of getting a classic mac/OpenTransport socket impl.

Pre-emptive threading is also supported if you really need it.
However most people use pthreads for control inversion and
to convert blocking I/O to non-blocking I/O neither of which
actually require concurrency, and both of which are supported
directly in the core system.

It’s felix’s reason for existing. However, if you’re not feeling
adventurous enough to code in a great new language and you’re stuck in
windows (>=nt4) and don’t want to worry about concurrency,
you can use fibers (co-operative threads). Nice to see that someone’s
finally wrapped up the old longjmp/setjmp/jmpbuf-fiddle dance.> From: skaller

Yeah, alright, so all I’ll send is 33 bytes, the rotation, x/y axes,
name, and team flag. (I’ll have to send some more data later on, such as
being on a vehicle or not, weapon, etc… :-P)
But, how do I make it only send data when it has changed? Do I make the
client send a boolean flag before anything else, and if it’s false, then
quit receiving data from that user and go to the next one? Thanks you
all! :wink:

But, how do I make it only send data when it has changed?

Save previous state, compare, send delta if any.________________________________________________________________________
Gabriel Gambetta
Mystery Studio - http://www.mysterystudio.com
Gabriel on Graphics - http://gabrielongraphics.blogspot.com

Umm… err… umm… Argh, I messed up. :frowning:
After fixing some compiler errors, I ran the server, and then the
client. I put a test cout line on the find connections loop, and it
detects the client, but after about 1 second of the client connecting,
the client’s screen loads and the server gets a segmentation fault…
(Note: Both progs are running on the same PC. Maybe that’s the problem?)
If I disable the data trading on both server and client, the client’s
screen loads immediately and the server doesn’t crash. I’ve got no idea
why this is… :-\

I’ve uploaded the files to my host:
http://www.sulfurmidis.com/help/

The send/receive functions in the client are:
SockHnd::RecvPlayerData() (Network.cpp)
SockHnd::SendMyData() (Network.cpp)

For the server, they are:
SockHnd::RecvFromPlayers() (SocketHandling.cpp)
SockHnd::SendToPlayer(int p) (SocketHandling.cpp)

SockHnd::FindConnections() finds connections in the server. :stuck_out_tongue:

Can you figure what the problem is? All my data is sent in the same
order in both progs… Thanks! :wink:

Note: I’ll add multiple threads for each user as soon as this gets
fixed. :slight_smile:

Umm… err… umm… Argh, I messed up. :frowning:
After fixing some compiler errors, I ran the server, and then the
client. I put a test cout line on the find connections loop, and it
detects the client, but after about 1 second of the client connecting,
the client’s screen loads and the server gets a segmentation fault…

Sounds like it’s time to use a debugger. By running the server in a
debugger, you’ll see where it crashes by looking at the call stack. If
you’re using gcc, be sure to give it -g to add debugging info. Use watches
to see the value stored in variables and breakpoints to see how the
program’s flow of execution progresses. Insight, Eclipse (with the C/C++
development plugin), and Visual Studio all have good debuggers.On Tue, 28 Mar 2006, Leo M. Cabrera wrote:

(Note: Both progs are running on the same PC. Maybe that’s the problem?)
If I disable the data trading on both server and client, the client’s
screen loads immediately and the server doesn’t crash. I’ve got no idea
why this is… :-\

I’ve uploaded the files to my host:
http://www.sulfurmidis.com/help/

The send/receive functions in the client are:
SockHnd::RecvPlayerData() (Network.cpp)
SockHnd::SendMyData() (Network.cpp)

For the server, they are:
SockHnd::RecvFromPlayers() (SocketHandling.cpp)
SockHnd::SendToPlayer(int p) (SocketHandling.cpp)

SockHnd::FindConnections() finds connections in the server. :stuck_out_tongue:

Can you figure what the problem is? All my data is sent in the same
order in both progs… Thanks! :wink:


Jeff Jackowski
http://ro.com/~jeffj/

Hmm… Weird, the error seems to be on the size() method of
std::vector… But how can it cause errors? :-/===============
Find
if (this->players.size() >= MAXPLAYERS)
Find again
for (int p = 0; p < this->players.size(); p++)
Find again
for (int p = 0; p < this->players.size(); p++)
No more

What the heck is wrong? :frowning: I’m sure this is one of those errors you
can’t figure out but then when you do, you say “Heck! I’m so stupid!”.
Can anyone see what’s wrong? Thanks! :wink: