[hlcoders] Player Physics

2006-03-31 Thread John Sheu
I'm going to put this here both as a note to myself and as a way of
getting commentary on this from anybody who is interested in player
physics, server-side.  Please do correct me if anything is wrong here.

So how does player physics work?

At the very base are the CUserCmds that are fed into the server.
CServerGameClients (I will be referring to these by implementation, not
interface) gets these through ProcessUsercmds() and passes them on to
CBasePlayer's ProcessUsercmds().  They're buffered there.

Now there comes a time when GameFrame() is called in CServerGameDLL.
The call chain of interest is:

CServerGameDLL::GameFrame()
Physics_RunThinkFunctions()
Physics_SimulateEntity()
CBasePlayer::PhysicsSimulate()

Now is where the CUserCmds are actually used.  For each CUserCmd, this
happens:

  Each CUserCmd is passed into CBasePlayer::PlayerRunCommand().
  CPlayerMove::RunCommand() is called, calling these three:

CBasePlayer::SetupMove() [prepares the CMoveData]
CGameMovement::ProcessMovement() [updates pos, vel, etc.]
CBasePlayer::FinishMove() [copies the updated data back]

  The VPhysics shadow object is updated with new pos and vel.

Ok then, all CUserCmds are processed.  Then, CServerGameDLL::GameFrame()
calls IGameSystem::FrameUpdatePostEntityThinkAllSystems(), and this
happens:

CPhysicsHook::FrameUpdatePostEntityThink()
PhysFrame()

In this function, the entire physics environment is first simulated.
Then, CBasePlayer::VPhysicsShadowUpdate() is called.  This is where the
fun stuff is, where the player entity's position is reconciled with what
the physics system thinks it is.

Then, after all this, data is sent off to the client, yadda yadda.


  SO  


What's the moral of the story?  Here's what I get out of the code:

For player movement, what happens is that player's aren't really
physically simulated at all!  Everything (movement, gravity, swimming,
etc.) is handled by the CGameMovement class.  With every CUserCmd:

1.  CGameMovement simulates the player and derives new pos/vel.
2.  A physics shadow object is updated with the new pos/vel.

This happens for every CUserCmd.  Then, after all the CUserCmds have
been processed that frame, the physics simulation actually occurs.  At
this time, _all the VPhysics shadow updates for that frame are processed
at once_.  Let's say, there were 3 CUserCmds from the player processed
this frame, then the 3 shadow state updates will happen sequentially in
the same frame.

After physics simulation occurs, the player entity is reconciled with
the VPhysics entity.  Any VPhysics damage or position/velocity
differences are copied back into the entity.  Then the ent data is
packaged and shot off to the clients.


  QUESTIONS  

1.  Are we guaranteed only 1 CUserCmd processed per frame?


  OTHER THOUGHTS 


I haven't seen any GoldSrc code before, but I suspect that the only way
to _exactly_ reproduce GoldSrc player physics would be some crazy coding
in VPhysicsShadowUpdate(), or even stripping the player of VPhysics
simulation entirely.  You'll likely do a _lot_ of copy-pasting of
GoldSrc code either way.  I think, to be honest, that you'll have to go
the latter route (nuking VPhysics) because there's no way that VPhysics
will exactly reproduce GoldSrc physics.  You'll have to do it all in
CGameMovement.


John Sheu


___
To unsubscribe, edit your list preferences, or view the list archives, please 
visit:
http://list.valvesoftware.com/mailman/listinfo/hlcoders



Re: [hlcoders] Player Physics

2006-03-31 Thread Jorge Rodriguez

Wow! For once, an informative, accurate and thoughtful post in a list
that usually contains nothing but cruft! You caught me off guard.
Thanks, John.

John Sheu wrote:


  QUESTIONS  

1.  Are we guaranteed only 1 CUserCmd processed per frame?



I don't think so. I think that in high-lag situations the net code may
receive more then one user command in the space of one frame. There's
definitely the capacity to process more then one command, so I assume
that Valve wrote that because there is a possibility of that happening.


  OTHER THOUGHTS 


I haven't seen any GoldSrc code before, but I suspect that the only way
to _exactly_ reproduce GoldSrc player physics would be some crazy coding
in VPhysicsShadowUpdate(), or even stripping the player of VPhysics
simulation entirely.  You'll likely do a _lot_ of copy-pasting of
GoldSrc code either way.  I think, to be honest, that you'll have to go
the latter route (nuking VPhysics) because there's no way that VPhysics
will exactly reproduce GoldSrc physics.  You'll have to do it all in
CGameMovement.



Actually, CGameMovement is pretty much a direct port to C++ of HL1's C
pm_shared code. Most of the physics and alot of the code has been
retained. The only real functional difference between HL1 and HL2
movement code is the player vphysics shadow, and all that does is move
the player around a little bit if his movement interferes with vphysics.
To get movement code identical to HL1, effectively all you would need to
do is remove the code from VPhysicsShadowUpdate(), but then your player
would lose all interaction with physics objects, and why would you want
that?

--
Jorge Vino Rodriguez


___
To unsubscribe, edit your list preferences, or view the list archives, please 
visit:
http://list.valvesoftware.com/mailman/listinfo/hlcoders



Re: [hlcoders] Player Physics

2006-03-31 Thread John Sheu
On Fri, 2006-03-31 at 15:09 -0500, Jorge Rodriguez wrote:
 Wow! For once, an informative, accurate and thoughtful post in a list
 that usually contains nothing but cruft! You caught me off guard.
 Thanks, John.

All hope is not dead on teh intarnets.

A few notes:

Correction: the shadow is not updated for every CUserCmd, but for every
_batch_ of commands.

If the user's commands are dropped for some reason, then the player is
not simulated at all server-side.  (His physics shadow doesn't move, but
it still exists).  When the commands finally to arrive, they are then
all simulated in the timespace of a single frame.

What exactly are the non-obvious differences between the
Player/Vehicle/Shadow/Motion controllers?

 Actually, CGameMovement is pretty much a direct port to C++ of HL1's C
 pm_shared code. Most of the physics and alot of the code has been
 retained. The only real functional difference between HL1 and HL2
 movement code is the player vphysics shadow, and all that does is move
 the player around a little bit if his movement interferes with vphysics.
 To get movement code identical to HL1, effectively all you would need to
 do is remove the code from VPhysicsShadowUpdate(), but then your player
 would lose all interaction with physics objects, and why would you want
 that?

That was essentially my point.  It's not my problem, though, it's KMod's
problem.  I just brought it up because I noticed a few mailings on this
list from them.

John Sheu


___
To unsubscribe, edit your list preferences, or view the list archives, please 
visit:
http://list.valvesoftware.com/mailman/listinfo/hlcoders



RE: [hlcoders] Player Physics

2006-03-31 Thread Jay Stelly

This is a pretty good summary, but you're missing a couple of things:

 For player movement, what happens is that player's aren't
 really physically simulated at all!

But your own explanation says this isn't true:

 After physics simulation occurs, the player entity is
 reconciled with the VPhysics entity.  Any VPhysics damage or
 position/velocity differences are copied back into the
 entity.

So reconciliation could mean that the vphysics data is copied over to
the game - which means the original game simulation is replaced with the
physics simulation.  It could also mean that the vphysics data is thrown
away, or blended into the result.  It's much more correct to say that
the players are always simulated in game code AND vphysics code.  Then
the results are selected or blended based on heuristics.  Gravity runs
in both simulations - the output position of the game physics provides
the input direction for the vphysics simulator.

 Correction: the shadow is not updated for every CUserCmd, but
 for every _batch_ of commands.

correct.

 When the commands
 finally to arrive, they are then all simulated in the
 timespace of a single frame.

not correct.
float flSecondsToArrival = ( ctx-numcmds +
ctx-dropped_packets + additionalTick ) * TICK_INTERVAL;

The shadow is updated once, but the resulting output target is reached
over some amount of future ticks.

 What exactly are the non-obvious differences between the
 Player/Vehicle/Shadow/Motion controllers?

Player and shadow controllers are nearly identical.  The idea is to
solve an overdetermined system for impulses that will cause the physics
object to arrive at the target position  orientation at some point in
the future (usually the beginning of the next tick).  Vehicle
controllers include a vehicle suspension, steering, and engine model -
and are generally forward controllers (you give them input and they
generate physics, they don't solve for impulses).

Motion controllers are just generic hooks to let you introduce your own
impulses to the object at the time that it is integrated.  You implement
IMotionEvent and add velocity to the object to steer it.  A shadow
controller is a motion controller with some specific behavior that
chases targets.

  To get movement code identical to HL1, effectively all you
 would need
  to do is remove the code from VPhysicsShadowUpdate(), but then your
  player would lose all interaction with physics objects, and
 why would
  you want that?

sv_turbophysics is effectively this plus some forces that push you out
of moving physics objects.  Short of predicting the simulation on the
client, this is a reasonable tradeoff once latency is high enough.

Jay

___
To unsubscribe, edit your list preferences, or view the list archives, please 
visit:
http://list.valvesoftware.com/mailman/listinfo/hlcoders



RE: [hlcoders] Player Physics

2006-03-31 Thread John Sheu
On Fri, 2006-03-31 at 18:19 -0800, Jay Stelly wrote:
 So reconciliation could mean that the vphysics data is copied over to
 the game - which means the original game simulation is replaced with the
 physics simulation.  It could also mean that the vphysics data is thrown
 away, or blended into the result.  It's much more correct to say that
 the players are always simulated in game code AND vphysics code.  Then
 the results are selected or blended based on heuristics.  Gravity runs
 in both simulations - the output position of the game physics provides
 the input direction for the vphysics simulator.

Perhaps I should have clarified.  As I see it, the CGameMovement code
computes an end position, given a start position, and feeds that target
into the VPhysics system.  The VPhysics system then does its best to
reach that target.  The difference between the VPhysics position and the
CGameMovement position is then heuristically reconciled.

 The shadow is updated once, but the resulting output target is reached
 over some amount of future ticks.

That's what I meant; perhaps I should have said that explicitly.

 Player and shadow controllers are nearly identical.  The idea is to
 solve an overdetermined system for impulses that will cause the physics
 object to arrive at the target position  orientation at some point in
 the future (usually the beginning of the next tick).  Vehicle
 controllers include a vehicle suspension, steering, and engine model -
 and are generally forward controllers (you give them input and they
 generate physics, they don't solve for impulses).

 Motion controllers are just generic hooks to let you introduce your own
 impulses to the object at the time that it is integrated.  You implement
 IMotionEvent and add velocity to the object to steer it.  A shadow
 controller is a motion controller with some specific behavior that
 chases targets.

Those two paragraphs are worth their weight in gold.  Thanks Jay :)

John Sheu


___
To unsubscribe, edit your list preferences, or view the list archives, please 
visit:
http://list.valvesoftware.com/mailman/listinfo/hlcoders



RE: [hlcoders] Player Physics

2006-03-31 Thread John Sheu
A few more questions:

So, as I understand it, how the player controller works:

If there is no backlog of CUserCmds, then the player is simulated by
CGameMovement and VPhysics for one tick, and at the end of the frame the
two are reconciled.

If there is a backlog of CUserCmds, then the player is simulated by the
CGameMovement as before.  The player shadow is given a set of
intermediate targets (based on the positions calculated at the end of
every batch of CUserCmds), and then this is VPhysics-simulated in one
frame, but with a time delta to match the difference between the first
simulated backlogged frame and the last simulated backlogged frame.

Given that, as said, the player and shadow controllers are almost
identical, I conclude that the shadow controller works as well by
setting a bunch of intermediate states and associating a time with
each of them, then simulating it all in one frame.  Is that correct?

Also, am I right in assuming that the underlying IPhysicsObject
functions still work?  (e.g., SetVelocity(), etc.)?


___
To unsubscribe, edit your list preferences, or view the list archives, please 
visit:
http://list.valvesoftware.com/mailman/listinfo/hlcoders