pygame and socket.recv

A

Aaron Brady

Hi,

I tried writing a small game on a pygame layer. The graphics are
fine, and at the moment, it is not graphics intensive. It is multi-
player, and for the communication, I am sending a pickle string across
a LAN, once per frame.

I'm observing some latency. It seems that socket.recv isn't
performing consistently. The server is using time.clock and
time.sleep to keep the frame rate at 40 frames per second. Latency
occurred regardless of whether the connection was ethernet or
wireless, although worse with wireless.

Does anyone have any hints or suggestions? I am on Windows XP.
 
T

Tim Wintle

I tried writing a small game on a pygame layer. The graphics are
fine, and at the moment, it is not graphics intensive. It is multi-
player, and for the communication, I am sending a pickle string across
a LAN, once per frame.

I'm observing some latency. It seems that socket.recv isn't
performing consistently.

Not sure I understand the question, are you blocking for the data to
come down the network before rendering the next frame?

For game programming I've always used select with non-blocking sockets
to receive data - and kept the transmissions to UDP to save time
(obviously you have to expect some data to be lost). Wire time is always
going to have too much latency for a message to be happily passed within
the time it takes to render a frame.

For syncing time I use a really simple algorithm - both machines send
each other their local [game] time every few seconds, and if the
received time is ahead of the local time then the receiving machine
updates it's time to match - that way they are always out by at most the
shortest time it takes for a packet to travel from one to the other.


Tim Wintle
 
A

Aaron Brady

I tried writing a small game on a pygame layer.  The graphics are
fine, and at the moment, it is not graphics intensive.  It is multi-
player, and for the communication, I am sending a pickle string across
a LAN, once per frame.
I'm observing some latency.  It seems that socket.recv isn't
performing consistently.

Not sure I understand the question, are you blocking for the data to
come down the network before rendering the next frame?

For game programming I've always used select with non-blocking sockets
to receive data - and kept the transmissions to UDP to save time
(obviously you have to expect some data to be lost). Wire time is always
going to have too much latency for a message to be happily passed within
the time it takes to render a frame.

For syncing time I use a really simple algorithm - both machines send
each other their local [game] time every few seconds, and if the
received time is ahead of the local time then the receiving machine
updates it's time to match - that way they are always out by at most the
shortest time it takes for a packet to travel from one to the other.

Tim Wintle

My game loop looks like this:

poll events, get 1 at most
send to server
wait for server reply
render entire frame

Yes, I am blocking for the data to come down the network.
Unfortunately, if I use any "prediction," I will have to go back and
un-render the previous frame, then redraw with the new information.

40 transmissions per second in each way can't be too much to ask, it's
just that they have to alternate, up one, down one.

I don't understand your solution. I can't picture it for my favorite
RTS game or the one I'm writing. Are you saying that the slower
machine just jumps ahead, and its user just doesn't have the
opportunity to make moves on the omitted frames?

I am using TCP, socket.SOCK_STREAM. UDP is a potential solution, but
it still doesn't fix my main loop.
 
T

Terry Reedy

Aaron said:
My game loop looks like this:

poll events, get 1 at most
send to server
wait for server reply
render entire frame

I am very sure that commercial 'real-time' (versus turn-based)
multiplayer games do not operate that way, at least not the ones I have
played.

I suspect that most do not operate by frames on the server, but rather
sent a more or less continuous series of events. NPC movements come
from the server (and can be given as vectors), other player movements
get echoed as sent to the server. The client uses the most current data
it has when it renders a frame. If the scene it too complex relative to
the client rendering capability, the frames jump and the motion is
choppy. If the info stream is interrupted, the scene may freeze a bit
even as the client continues to re-render to account for player motion.
Hope this helps a bit.
 
A

Aaron Brady

I am very sure that commercial 'real-time' (versus turn-based)
multiplayer games do not operate that way, at least not the ones I have
played.

I suspect that most do not operate by  frames on the server, but rather
sent a more or less continuous series of events.  NPC movements come
from the server (and can be given as vectors), other player movements
get echoed as sent to the server.  The client uses the most current data
it has when it renders a frame.  If the scene it too complex relative to
the client rendering capability, the frames jump and the motion is
choppy.  If the info stream is interrupted, the scene may freeze a bit
even as the client continues to re-render to account for player motion.
  Hope this helps a bit.

I am thinking a couple of things. Take a branch in the reasoning. On
arriving at the time to render the next frame, without any
announcement from the other side:

1) Side A continues to model Side B as though no change in motion
occurred.
2) Side A discontinues its model of Side B until next transmission.

In 1, upon receiving the next update from B, it will have to retrace
its steps, "unmodel" the changes, and bring them up to date. This can
have retroactive cause-and-effect consequences on A as well, including
but not limited to, live-or-dead state, position, and velocity.

In 2, A's view of B looks jumpy-- B is halting, then jumping ten
tiles, then moving smoothly, then halting and jumping. Retroactive
changes are regardless possible.

This was a the-long-way-'round word search for the word 'retroactive',
which I'm glad is a word, incidentally. In either case, every time
one player's packets are delayed, every other player's screen will
alter state, more or less like they have been sleepwalking and just
come to. There is the additional problem of what to do with A's
interim actions. Reminds me of a diff-merge in source control! How
about king-of-the-hill precedence for contradiction resolution?

Then, the player whose packets are delayed has an advantage. B got to
make a change to another player's state, as well as proceed with
exclusive knowledge of it. B is the only one with an up-to-date model
of the game during the lag.

This could also apply to B instead, if the game structure makes the
others' besides B the valid current model. B is sleepwalking for the
length of his/er network delay, and his/er actions are discarded.
This may be more what players are accustomed to; the interface goes
dead, and issuing or rescinding orders isn't acknowledged or received.

Any momentary loss of "visibility" could be mitigated in a low-impact
game or simulation of physical motion, since it takes many Gs of
acceleration to avert most-- all but glancing-- collisions that are
destined in just a few frames. Mine is not such; position and
velocity are subject to arbitrary changes.

<jest> Maybe I just need more clicks per second, to give the user a
feeling of accomplishing something, even though the same percentage of
actions is successfully transmitted. Is satisfaction a simple
decaying proportion?</jest>

With discontinuities in position and momentum possible, is lockstep
frame-for-frame synchronization my best option? Or should I fall back
on a sturdier game model, where actions' consequences can't affect
other players for several frames? Blue... no! Yellow!
 
H

Hendrik van Rooyen

Hi,

I tried writing a small game on a pygame layer. The graphics are
fine, and at the moment, it is not graphics intensive. It is multi-
player, and for the communication, I am sending a pickle string across
a LAN, once per frame.

How big is this pickle - i.e. how many packets does it translate to
on the wire, given that an ethernet packet is less than 1500 bytes?

What is the maximum number of full size packets that a simple
echo server will echo per second on your setup? I predict that
you will find that this is far less than what a calculation based on
the bit rate will suggest...
I'm observing some latency. It seems that socket.recv isn't
performing consistently. The server is using time.clock and
time.sleep to keep the frame rate at 40 frames per second. Latency
occurred regardless of whether the connection was ethernet or
wireless, although worse with wireless.

What does "some latency" mean? - barely visible jitter, or a half
second freeze?

What do you do when the total round trip time takes longer
than your target of one fortieth of a second?

The fact that wireless is worse (54Mb/s? - down from 100Mb/s)
makes me think you are running out of bandwidth, or that the
LAN is busy and that the bandwidth is wasted on collisions.

What happens when you drop the frame rate to 20 per second?
(it is parameterised, isn't it?)
Does anyone have any hints or suggestions? I am on Windows XP.

What else is running on the machines at the same time? - your game
may be sucking at the hind tit of processor time...

- Hendrik
 
T

Tim Wintle

My game loop looks like this:

poll events, get 1 at most
send to server
wait for server reply
render entire frame

The look I'm suggesting is:

poll events
write to (non-blocking) socket
render frame
check non-blocking socket and add events to the event queue
Yes, I am blocking for the data to come down the network.
Unfortunately, if I use any "prediction," I will have to go back and
un-render the previous frame, then redraw with the new information.
Sounds like that may have to be re-factored slightly, afraid this is why
real-time networked games are tough to make.
40 transmissions per second in each way can't be too much to ask, it's
just that they have to alternate, up one, down one.
IMO It's very unlikely to be a bandwidth issue. It's more likely to just
be a latency issue.
I don't understand your solution. I can't picture it for my favorite
RTS game or the one I'm writing. Are you saying that the slower
machine just jumps ahead, and its user just doesn't have the
opportunity to make moves on the omitted frames?


a) How much to move etc. is decided based on some real-time solution
(not on the number of frames). Ideally all movement methods take a
parameter that is a delta in time. (i.e. 1/40th of a second)

b) That time is the time that is synced across machines - if machine B
has to put it's timer forward 1/50 of a second, you call all the methods
above with a timedelta of 1/50 before continuing.

c) Obviously things like which frame a sprite is on isn't really
necessary for the sake of a game, it's only game state variables that
would be required.

d) If you end up with jumping objects then you can create "ghost"
objects for the other player's objects. When you get the state of a
foreign object, update the real object with the properties, but draw the
sprite at the position of your ghost object - and every frame move the
ghost object towards the real one a little bit. That gets rid of the
effect of jumping from one place to another, but keeps collision
detection etc. correct wrt the other player.
 
A

Aaron Brady

How big is this pickle - i.e. how many packets does it translate to
on the wire, given that an ethernet packet is less than 1500 bytes?

The client sends a dictionary to the server. If it doesn't have any
news, it's an empty dictionary, ~10 bytes. If it does, it's one or
two entries, a short string to a short string or integer, ~40 bytes
total.

The server sends a dictionary back: { str: str, str: num, str: { int:
X, int: Y, ..., int: Z } }, where X, Y and Z are the dictionaries it
received from the individual clients, ~100 bytes total. I don't
anticipate this number growing past 1K at later stages in the game,
and I can always make it a fixed-length struct or CSV.
What is the maximum number of full size packets that a simple
echo server will echo per second on your setup?  I predict that
you will find that this is far less than what a calculation based on
the bit rate will suggest...

The test on localhost->localhost and back reached 700 cycles per
second. The test on localhost->other machine and back ranged 100-300
cycles per second, IIRC recently.
What does "some latency" mean? - barely visible jitter, or a half
second freeze?

I've got a rather amateur loop keeping the frame rate capped at 40
fps. The game won't exceed that, but when it drops /below/ it, it can
fall to 30 or 20 or 15 fps. That was just a per-second averaging
calculation; the bad freezes are about half a second. I'll try to get
a reading of individual calls to 'recv' that are themselves below the
threshold.

Here's the loop: wait half the time left, then half that, then half
that, and so on, until less than 1/1000th second is left.

while 1:
tcurr= time.clock( )
delay= ( ( tprev+ secsperframe )- tcurr )* 0.5
if delay< 0.001:
break
time.sleep( delay )
tprev= tcurr

I don't know if it could be responsible. Would a mutex or Queue be
better using a threading.Timer?
What do you do when the total round trip time takes longer
than your target of one fortieth of a second?

I want to know that too!
The fact that wireless is worse (54Mb/s? - down from 100Mb/s)
makes me think you are running out of bandwidth, or that the
LAN is busy and that the bandwidth is wasted on collisions.

Another party (friend, participant, colleague, etc.) and I tested it
with wires. It improved it, but didn't eliminate it.
What happens when you drop the frame rate to 20 per second?
(it is parameterised, isn't it?)

Yes. It still gets half-second freezes, and the aggregate per-second
average still reads as low as 15. Yes it's parameterized, in the
'secsperframe' variable, seconds per frame, or fps**-1.
What else is running on the machines at the same time? - your game
may be sucking at the hind tit of processor time...

On one test, one machine ran only the server, and the other machine
ran only one client! That is where the numbers I gave were
generated. When one machine runs a server and a client, it's not much
worse, though I didn't try that since I moved the delay loop to the
client side.

Thank you for your questions!
 
A

Aaron Brady

The look I'm suggesting is:

poll events
write to (non-blocking) socket
render frame
check non-blocking socket and add events to the event queue


Sounds like that may have to be re-factored slightly, afraid this is why
real-time networked games are tough to make.

+1 understatement of the week. Are you saying that there aren't that
many out there? I.e., if average and worst-case packet times were
faster, there would be more?
IMO It's very unlikely to be a bandwidth issue. It's more likely to just
be a latency issue.

The actual mechanics can't be that hard. If I had a dedicated pathway
that the OS didn't even intervene in, 40 fps would be a trifle; and I
would also have a custom OS. 'Doom 25: Now including operating
system!'
a) How much to move etc. is decided based on some real-time solution
(not on the number of frames). Ideally all movement methods take a
parameter that is a delta in time. (i.e. 1/40th of a second)

b) That time is the time that is synced across machines - if machine B
has to put it's timer forward 1/50 of a second, you call all the methods
above with a timedelta of 1/50 before continuing.

I must be writing a very peculiar game. Frame-for-frame matching is
important. The game space is a grid, a logical space, zero mass, not
a real one. I started to tell Terry yesterday that arbitrary
discontinuities in position and momentum are possible.

Your method ensures than an object is moving at a constant rate,
distance over time, as it is perceived by the player. I want
something like it, so that if I'm anticipating an upcoming turn, I can
press the key at the time I want, and the model on every machine is
informed, regardless of what the graphics did in the interim.
c) Obviously things like which frame a sprite is on isn't really
necessary for the sake of a game, it's only game state variables that
would be required.

Yes, this.
d) If you end up with jumping objects then you can create "ghost"
objects for the other player's objects. When you get the state of a
foreign object, update the real object with the properties, but draw the
sprite at the position of your ghost object - and every frame move the
ghost object towards the real one a little bit. That gets rid of the
effect of jumping from one place to another, but keeps collision
detection etc. correct wrt the other player.

It's just that if you register a collision in between the time that
one object has changed its position and momentum, and the time you
learn about it, you have to retroactively edit the collision, restore
hit points, and recalculate the other object's position and momentum,
to name a few. For example, if you hit some kind of power-up that
warps your position to another place, you can't get hit by a weapon
that is colliding with your old extrapolated place. Maybe each
collision has to take a branch: if the collision turns out to have
succeeded, proceed from state X->Y1, else from state X->Y2. That
sounds combinatoric, when multiple collisions may or may not be
interacting. { (X,Y)->(X1,Y1), (X,Y)->(X1,Y2), (X,Y)->(X2,Y1), (X,Y)->
(X2,Y1) }. Or, you could just freeze the models of some objects
pending update, and continue with the models of the rest.

This is all not to mention the balance between pre-transmission and
post-transmission calculations, which is a time-space trade-off IMCAC
if my calculations are correct.
 
H

Hendrik van Rooyen

8< ---- stuff showing small packets and adequate bandwidth ----------
I've got a rather amateur loop keeping the frame rate capped at 40
fps. The game won't exceed that, but when it drops /below/ it, it can
fall to 30 or 20 or 15 fps. That was just a per-second averaging
calculation; the bad freezes are about half a second. I'll try to get
a reading of individual calls to 'recv' that are themselves below the
threshold.

Here's the loop: wait half the time left, then half that, then half
that, and so on, until less than 1/1000th second is left.

while 1:
tcurr= time.clock( )
delay= ( ( tprev+ secsperframe )- tcurr )* 0.5
if delay< 0.001:
break
time.sleep( delay )
tprev= tcurr
This will hand control to the OS more than once. It may be
worth it to try making a target "completion date" and to then
sleep the difference between now and then, once.
I don't know if it could be responsible. Would a mutex or Queue be
better using a threading.Timer?

Good question - I don't know. I am just assuming that the OS is somehow
giving you short shrift in its task scheduling. Does anybody know what
the granularity of task swapping is in XP? - Forty per second is only 25
milliseconds - Is a task more or less guaranteed to get a bite at the cherry
in that time? We need a windoze expert to tell us what the minimum time is
for swapping a task out and in. If you are less than that time away from
your scheduled "completion date", it makes no sense to sleep...
I want to know that too!

Well if you were to know that it has happened, it would make
sense to do the stuff immediately, and to reschedule your
future target "completion dates"

8< -------- more stuff showing adequate bandwidth ----------------

- Hendrik
 
T

Tim Wintle

It's just that if you register a collision in between the time that
one object has changed its position and momentum, and the time you
learn about it, you have to retroactively edit the collision, restore
hit points, and recalculate the other object's position and momentum,
to name a few.

So it sounds like what you are trying to do is emulate shared RAM
between the two players!

The problem being that you have to effectively lock the variables on one
machine while the other one reacts.

I believe the answer normally used is the client-server architecture.

Choose one machine to act as the "server" somehow, then let that control
the entire game state. Both players pass events to this server method
(using non-blocking sockets), and render things in the position they
believe they are in.

I believe that is how all the current RTS games work, certainly how Red
Alert worked, and is how all FPS games work (e.g. in unreal there is
always a "server", and in single player mode the clients are simply bots
and the local client application.)

You might find the docs for Unreal networking (c. 1999) useful to
explain what they did better than I can.
http://unreal.epicgames.com/Network.htm
 
A

Aaron Brady

I don't know if this might be causing your problem, but most socket
implementations use quite a big buffer for incoming data by default. I
had a lot of trouble with another real-time networked application
until I realised this. Reducing this buffer to the minimum helped a
lot in my case. Also, I would strongly recommend using UDP instead of
TCP.

BTW, does anyone know if any good bibliography about real-time
networked games, or real-time networked general applications?

I switched to UDP. My average round-trip time is at 50 trips/sec, but
my worst round-trip time is still in the 10-20 range.

I also tried buffer sizes of 2**8 and 2**12, with about the same
results.

So, UDP might free up some processor time, but it still leaves me with
the problem of retroactive model updates.
 
A

Aaron Brady

So it sounds like what you are trying to do is emulate shared RAM
between the two players!

The problem being that you have to effectively lock the variables on one
machine while the other one reacts.

I believe the answer normally used is the client-server architecture.

Choose one machine to act as the "server" somehow, then let that control
the entire game state. Both players pass events to this server method
(using non-blocking sockets), and render things in the position they
believe they are in.

I believe that is how all the current RTS games work, certainly how Red
Alert worked, and is how all FPS games work (e.g. in unreal there is
always a "server", and in single player mode the clients are simply bots
and the local client application.)

You might find the docs for Unreal networking (c. 1999) useful to
explain what they did better than I can.http://unreal.epicgames.com/Network.htm

I don't think you did the link justice in your introduction of it. I
don't think I did your post justice... by ignoring it.

Here is a quote from the paper:
"""
Player Prediction

This approach is purely predictive, and it gives one the best of both
worlds: In all cases, the server remains completely authoritative.
Nearly all the time, the client movement simulation exactly mirrors
the client movement carried out by the server, so the client's
position is seldom corrected. Only in the rare case, such as a player
getting hit by a rocket, or bumping into an enemy, will the client's
location need to be corrected.
"""

Please excuse me briefly; the FBI is beating down my door for quoting
it.

Regardless, I think it was the 'correction', per se, step that I was
interested in. Does it suffice to merely wait until recovering from
the lag to notify the player s/he's dead, and proceed normally
otherwise?

Should the keystroke that the player hit during lag be delivered asap,
or 'in time' with how many seconds elapsed since the last known
frame? My game in particular, I have a hunch, relies on more precise
timing than you might expect in a game.
So it sounds like what you are trying to do is emulate shared RAM
between the two players!

No, that's my other project ;)
 
A

Aaron Brady

The look I'm suggesting is:

poll events
write to (non-blocking) socket
render frame
check non-blocking socket and add events to the event queue


Sounds like that may have to be re-factored slightly, afraid this is why
real-time networked games are tough to make. snip

a) How much to move etc. is decided based on some real-time solution
(not on the number of frames). Ideally all movement methods take a
parameter that is a delta in time. (i.e. 1/40th of a second)

b) That time is the time that is synced across machines - if machine B
has to put it's timer forward 1/50 of a second, you call all the methods
above with a timedelta of 1/50 before continuing.

Tim Wintle's link has an interesting illustration of this:

"""
Basic Concepts
The Update Loop

For example, Doom's movement physics looks like "Position +=
PositionIncrment" while Unreal's looks like "Position += Velocity *
DeltaTime". This enables greater frame rate scalability.
"""

.... Perhaps you've heard of him.
 
D

Dennis Lee Bieber

frame? My game in particular, I have a hunch, relies on more precise
timing than you might expect in a game.

If it is that tight, I have two suggestions -- neither one you will
like.

ONE, don't use Python. Python is not a real-time language (heck --
don't use UNIX/Linux or Windows either, as they are not real-time OS's)

TWO, don't TCP or UDP...

If you can't fit all clients physically/logically into the server
code space (implies a computer with a display/keyboard per "client"),
you'll need some multi-processor shared memory scheme -- including a
simulation clock shared by all processors... Don't know if the hardware
is still available (I seem to recall my workplace is worried about
spares) but there were such things as a fiber-optic ring memory card;
whatever is written to the memory space on one machine is distributed to
all machines on the fiber ring.

You'd use this mirrored memory to contain the state of all movable
objects in the game, and maybe use the first word as the game clock.
Clients would read the entire memory block (two or three times --
basically, if the clock value differs between the first two reads you do
a third read, which should now have a repeated clock value indicative of
a stable status block). Possibly each client will have a block of memory
for sending its updates to the server, which will echo the server clock
to indicate "done for this <tick>"

Not cheap <G>

http://www.gefanuc.com/products/family/reflective-memory
http://www.gefanuc.com/products/2239

No, that's my other project ;)

Heh... see above... of just google "reflective memory"
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,130
Latest member
MitchellTe
Top