   Hoping for second opinion on RTS/RPG networking model
  Okay, I'm thinking about the following situation: - Client/Server topology - 1 to 10 clients per server - All data sent over TCP/IP in binary format - Up to roughly 200 entities of interest to any given client at any given time, typical figure is 1/3rd to 1/2 of that - Entity movement is generally slow, linear, and predictable (eg. direction and velocity only changes once per second or two) - No twitch gameplay (RPG or RTS, not FPS, no significant physics)I'm hoping to get that working with minimal popping/snapping but with reasonable synchronisation across all machines, probably running slightly in the past (100-500ms?) on everybody's machine to facilitate this.I don't want a lock-step system, mostly so that each client only knows about the entities I want it to know about. (Also discussed here recently.)I'm thinking of broadcasting messages consisting of entity-position/direction/velocity/server-timestamp, plus maybe some forward-dated messages with zero velocity acting as 'stop here' commands to reduce overshoot. This would be done maybe 1 or 2 times per second per entity. Does that sound reasonable? I'm hoping that by sending velocities and running everything in the past I can get smooth-looking motion, since the direction of movement is quite predictable, and can avoid needing to do good forward prediction.Regarding the approach of simulating the past, what sort of delay is reasonable for this? I was probably going to start with about 250ms, hopefully more than allowing for the various obvious causes of latency (eg. per-connection polling frequency on the server, actual net latency, and per-connection polling frequency on the client). I'm happy for people to see occasional position corrections, as long as the vast majority of players get a smooth game the vast majority of the time.Any obvious mistakes I'd be making? Anything I need to consider that I've forgotten? I've "only" worked on MMOs before, so this is slightly different. ;)   
  Yes, that sounds reasonable. You don't need to post-date "stop" messages; just synthesize them on each client. When you send a "entity, position, velocity" message, include a duration for how long that is valid. Or even just make that duration a constant per object type, to avoid sending anything at all.The amount of time in the past you want to run at is easy: It's the one-trip transmission latency from the server to the client. Input commands for players will additionally be delayed by the reverse transmission latency, so gap from "action" to "response" will be your ping time.;  Ah, of course. I was thinking that I could send start and end locations with start and end times and linearly interpolate across that, but obviously a duration carries the same information in these circumstances.Estimating the round trip time for a given client is easy enough, but what about when that varies over the session? I'm trying to work out if I'd need to contract or dilate time locally, which sounds a bit tricky. If someone has a good ping at the start but it gets worse, they'll have messages coming in late throughout. Am I overthinking it?   ;  The bottom line is that if someone is lagging, there is nothing you can do. You can only plan for each possibility.   ;  But my point is that I have to do something, as I'd be the person writing the client which decides what to display at that time. ;)   ;  Well, you can either stop a person from all forward prediction once they reach some threshold, or you can treat them like they are not lagging. Either way, you will get rubber banding. In one case, you will get rubber banding on the server to all other clients, and the other you will get it on the client who is lagging. Remember, most users on the internet now have broadband connections and do not lag much. After a user sends no packets, you should disconnect them. Other than those options, there isn't really anything you can do.The funny thing is, all of your clients will lag to some degree: 10 ms ping, or 300 ms ping. You have to decide how much is too much through testing. So, dealing with internet lag is a complicated question. What about packet loss? Do you disconnect someone if they reach 20% packet loss over a 10 second period or over a 30 second period.Most of these problems can be answered by seeing how important your internet connection is to gameplay. Some games you can play with a 700 ms ping and there is no noticable lag, others need 100 and below.I am giving you more questions than answers, but I hope that you may form some answers through my questions :P;Quote:Original post by smasherprogWell, you can either stop a person from all forward prediction once they reach some threshold, or you can treat them like they are not lagging.But I explained above that I am pretty much avoiding doing forward prediction. The idea of showing the player's past position is that I can move players from one authoritative position to another. I'm not averse to doing a small amount of extrapolation on the occasions when a message is late to arrive, but that's all.Quote:Remember, most users on the internet now have broadband connections and do not lag much.It's not really about lag but about jitter. Ping times will vary over the course of a session, which means the gap between remote time and local time will grow and shrink. It's dealing with that which I am trying to work out.Quote:I am giving you more questions than answers, but I hope that you may form some answers through my questions :PI'm not sure how much of the rest of what you said is relevant to my problem, sorry!   ;  I suggest you make the client-calculated delay something like:"X milliseconds plus a leaky integrator based estimate of the calculated round trip time."X might be in the 10 .. 100 range depending on a robustness-vs-responsivness trade-off. This lets you make the response time reasonably responsive, while still having some buffer for when the delay jumps.The leaky integrator probably also wants to be more sensitive to higher times than lower. It might look something like:float update_estimate(float estimate, float new_sample) {  if (new_sample > estimate) {    return estimate * 0.5f + new_sample * 0.5f;  }  return estimate * 0.95f + new_sample * 0.05f;};  Yeah, that seems like a sensible way to adjust the time, but it introduces discontinuities into the simulated timeline, meaning I need another layer of interpolation on the top to smooth it out, no?For example: I send an entity,position,velocity,duration message where the duration is 1 second. Then, during that second, the detected latency changes and the clock moves back or forwards a bit. Moving that entity naively for that velocity and duration is now going to undershoot or overshoot. Right? That's the bit that I can't quite get my head around.I suppose I can multiply out the positions + velocities into expected positions at certain times, but I'll still need more corrective interpolation on top of that to deal with the aforementioned discontinuities.I'm sure there is a simple solution to this, probably just involving 1 more blend operation, but I just can't quite put my finger on what it is.   ;  What's going to happen is that your delta-time for a time step will be smaller or bigger (if you use variable time step), or the delay before the next fixed-size time-step is taken will be smaller or bigger. You have to separate wallclock time ("time") from simulation time ("steps," for example). The server offset is the value that correlates the two, but it doesn't affect the steps directly.So, yes, a time adjustment will cause a momentary time dilation artifact, which will likely be seen as a small momentary twitch or jump in velocity. That's why you want to adjust the clock softly, not in a big jump (amortizing the jump over (wallclock) time).   