One time events VS periodic events

Started by
6 comments, last by hplus0603 12 years ago
Hi there,

I am currently working on my first network-based game. The game is a real-time topdown RPG and uses a client-server architecture.
The basic architecture already works and right now I am trying to figure out what the best way to synchronize the world state might be. I often read that you would have a server loop that will send world state updates every 50ms. That sounds reasonable for continuous variables like positions, but what about one time events like spawning an entity or attacking?

My current idea is the following:

  • Every time a player connects, send him the whole world state immediately.
  • Every 50ms send an update for positions, life, mana and such things to all clients.
  • Handle one time events (entity spawning, attacking) immediately.


I am not sure if that is the right way to do it, but it would definitely be the easiest. The alternative I think would be to store those events and send them together with the current world snapshot, but I am not sure if that would be a good idea. I hope you can shed some light on this issue. Thanks a lot.

Greetings,
Pfaeff
Advertisement
If you are sticking to sending updates at 50ms itervals, then it would make your program simpler if you stuck to sending all data out on the intervals. What difference would 50ms make in sending out information about something that "just occured?" Now, you need to synchronize sending between different threads (assuming your program is threaded).

Keeping code as uniform as possible helps alot down the road. I don't see a 50 ms difference as causing any problems for players. My vote would be to keep the 50 ms sending of all data.
Wisdom is knowing when to shut up, so try it.
--Game Development http://nolimitsdesigns.com: Reliable UDP library, Threading library, Math Library, UI Library. Take a look, its all free.
The problem I have with this, is that I will have to somehow store those one time events to be able to transmit them to the clients later on. One way to do it would be to create the packets immediately and store them in some kind of buffer. The server will then send all the packets in the buffer during it's "tick" (meaning every 50ms).

The threads are currently being synchronized using a queue. Every packet gets stored in this queue which is synchronized. Then it is emptied by the server's main thread and the packets are processed. This way I only have to synchronize one single object.
What is your simulation tick? You really need to lock your simulation tick rate. Then, you can time stamp each event with the tick at which the event happens, and if your network rate is slower than your simulation tick rate, you just bunch up events for multiple ticks into one packet (with time stamps.)
Note that, for RTS-es, the typical way to do it is to use lock-step simulation, where only commands are sent from/to clients, and handled always in the same order by the same code on all machines, and thus deterministically simulated. This saves tons of bandwidth, at the expense of needing to delay execution of commands until everybody has gotten the command. (Guess why RTS games have a "Yes, Sir!" animation before units start moving? :-)
enum Bool { True, False, FileNotFound };
I have yet to decide on a suitable simulation tick rate. I guess it should be the same for the client and the server then (GUI updates and stuff posing an exception). My netcode should already be able to bundle multiple packets before sending them through the network, but I haven't used a packet sniffer to verify that functionality, yet ;-).
If I understand you correctly, what you suggest is the following (please correct me if I get this wrong):

  • Have a fixed simulation interval on the server and the client (and perhaps a slower network tick)
  • Count the elapsed ticks of the simulation
  • Whenever an event occurs, create the corresponding packet and put the current (simulation) tick count in it
  • Put that packet in a buffer
  • When the next network tick occurs, send all the packets in that buffer (in one go) to the clients


So would I have to synchronize the clocks between the server and the client? What is the client's benefit of knowing in which tick an event occured (better lag compensation I guess)? How would the client deal with those information?

Thank you.
You have to synchronize the ticks between client and server, but not necessarily the "clocks" (as in wall-clock time.)
For the client to show the same thing as what happens on the server, the client has to display each entity and event at the appropriate tick.
Note that this means the client will run "behind" the server -- it can't show the entities/events for tick T until it's received the server packet for tick T.
This, in turn, means that commands from the client to the server need to be forward timestamped, so they make it to the server before that tick happens on the server.
This means that there is input lag between client inputs and client actions.
How to deal with this lag, and display/hide/speculate/rewind/correct commands to get the right trade-off between latency, responsiveness, and correctness, is what networked game programming is really about.
The shuffling of bytes between client/server and the time stepping/tick numbering/events and properties sytems are just preliminary basics.
enum Bool { True, False, FileNotFound };
Thanks. If the server puts its current tick count in the packets (or bundles of packets) he is sending to the client, the client can then use that count as its new tick count. This way the ticks would be synchronized, am I right? During the time the packet is traveling through the net, the server will most likely be one or two ticks ahead and that is why packets from the clients have to be forward timestamped, if I understood you correctly.
What would/should happen if the server receives a packet that has a tick from the past? Is there any source where I can read more about such a system? I still don't really see the advantage of this approach towards sending the most recent data and treating it as the new world state, assuming the packets arriving in the correct order, like when using tcp, or some reliable protocoll on top of UDP.

EDIT: I think the client needs to know in which tick the event occurs, because otherwise he couldn't make a local prediction as the packet he receives from the server is already in the past, but how does the server benefit from knowing at which tick the client triggered a certain event, maybe for server side prediction?

the client can then use that count as its new tick count


Correct. Or, more likely, new "tick target" -- if there are many ticks in a packet, then the client wants to play ticks forward at the appropriate rate, not just play them all as soon as the packet comes in.

that is why packets from the clients have to be forward timestamped[/quote]

Correct.

the server receives a packet that has a tick from the past
[/quote]

Either the server throws it away, or the server does not progress time until all clients have provided their input for a particular tick.

The server needs to know which tick a command is intended for for at least three reasons:
1) To manage latency. If the player sends ticks "in the past" then the player should forward date more; if the player sends ticks "way into the future," then the client can forward date less.
2) If the client simulates in parallel to the server, then they need to agree on when the event happens, or they will diverge.
3) Other clients need to know when the event happens.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement