When vehicles replicate, the correct vehicle & player animations often do not play

Issue #342 resolved
Matt Hands created an issue

When a vehicle is received through replication to a net client, e.g. player just connected or came within range, the vehicle and it's VehicleWeapons may need to player vehicle and/or player animations to be in the correct display position. There is currently no specific attempt to make this happen and it's very patchy.

Result is that client player may see an unbuttoned vehicle occupant as buttoned up. And occupant's hit points will not match between server and client. Client player can register hits in mid air where the exposed but invisible occupant really is.

Comments (6)

  1. Matt Hands reporter

    Net clients rely on detecting changed values of DriverPositionIndex being replicated by the server. Each client compares the new DPI to its own SavedPositionIndex and triggers up/down anims for the vehicle/WV/player as required. And a net client that receives (spawns really) a vehicle through replication does receive the current DPI and processes it in PostNetReceive().

    The problem is the client will have a SavedPositionIndex of 0 by default. When the DPI value above is received, it sets its LastPositionIndex to match the SPI, i.e. always zero). Using the example of a turret, with a commander unbuttoned: If it's a simple turret, with no cupola or peri, then the commander will be in DPI 1, which the client will receive. It works out that an up anim would be appropriate and plays the up anim from the LPI of 0. That works, as the up anim from pos 0 is to unbutton. But if the turret does have a cupola or peri, the commander will be in DPI 2 when unbuttoned. The client still tries to play an up anim from pos 0 - but there isn't one; this time the unbutton anim is from pos 1.

    Result: net client has turret in incorrect anim position, showing hatch closed and commander buttoned. Everyone else who hasn't just received the vehicle through replication, will see him unbuttoned. And the server will know he is unbuttoned and will have his hit points in the unbuttoned position. So if the net client fires into mid air above the commander's hatch, he will see blood splats and kill the invisible commander.

    Needs some smarter code in initialisation to set the correct animation when the vehicle is replicated, both for vehicle and occupant's player pawn.

  2. Matt Hands reporter

    Have it coded and will commit tomorrow evening. Should cover all animations to put the vehicle/weapon mesh in the correct starting position upon replication. But will have to go through later and add all the specific player idle anims. More important - and quicker - to get the vehicle mesh in the correct unbuttoned/raised position.

  3. Matt Hands reporter

    Functionality implemented in commit 1f20749. Uses recently added RaisedPositionIndex in cannon pawns and adds RaisedPositionIdleAnim & RaisedPosPlayerdleAnim.

    Functionality should be sound, but need to add individual raised player idle anims for tank drivers and commanders. For now, hatches should be open & player in raised position, when vehicle replicates to net client. But player will not be in correct pose, which may be subtle or may look very wrong. However, we at least should be able to see net client detecting raised position & animating vehicle mesh to suit. AT gunners will still show crouched upon replication even if supposed to be standing, because it's their pose that makes them stand, not moving an attachment bone on the gun.

    Maybe an hours work to go through and add player anims individually.

    MG pawns use same functionality as cannon pawns, but have default RaisedPositionIndex of 255 in def props, meaning never raised. Set in subclasses as required.

    Tanks etc use similar functionality but simply use existing UnbuttonedPositionIndex, as I can only see if applying to a driver's hatch open, where as cannons are more varied. Tanks use UnbuttonedIdleAnim & UnbuttonedDriverIdleAnim. Haven't implemeneted for wheeled vehicles as I don't see a need for it, but will check through them later.

  4. Matt Hands reporter

    Much better, generic implementation of fix in commit 3f6a30c.

    Came to me while driving to work yesterday ! A much better & simpler alternative, instead of setting RaisedPositionIndex , RaisedPositionIdleAnim & RaisedPosPlayerdleAnim (or equivalent) for each vehicle & weapon pawn. New SetPlayerPosition() function handles it all on net client, once has necessary actor refs, triggered from either PostNetBeginPlay or PostNetReceive, as previously. But now generically determines and handles vehicle & player idle animations for ANY player position (when vehicle replicated to net client).

    If player is present and not in initial, neutral starting position, the new function steps down through each player position, from the current one to the initial one. It looks for the vehicle/gun transition anim and player transition anim that are closest to the player's current position. It then plays those anims to put the vehicle/gun and the player in correct position, following replication. But it uses SetAnimFrame(1.0) to snap both anims to the end of the animation - effectively turning each transition anim into a ready made idle anim, without having to set them all individually !

    Removes variables: RaisedPositionIndex , RaisedPositionIdleAnim & RaisedPosPlayerdleAnim, UnbuttonedIdleAnim & UnbuttonedDriverIdleAnim. Except RaisedPositionIndex is retained in cannon pawn, but now only to determine whether to play shoot open or closed firing anim on cannon.

    One outstanding, annoying bug, which would also have affected previous functionality: When net client receives vehicle with occupant, event StartDriving() gets called on the 'Driver' DHPawn, which sometimes that gets triggered AFTER my new functionality. StartDriving() starts looping the DriveAnim on the Driver pawn, which is for its initial vehicle position. If this happens AFTER my stuff, the Driver can ends up in the wrong pose (vehicle/gun anim is always correct). Need to add a check somewhere to stop DriveAnim playing if just replicated and player is not in initial vehicle position.

  5. Matt Hands reporter

    Should be fully fixed/implemented in commit d7a09a7.

    Been something of a marathon epic ! So many issues ...... Previous SetPlayerPosition() clientside function in various vehicle classes solves the problem most of the time. And functionality is automatic, in that it calculates the appropriate anims for the vehicle and player, based on current position, and effectively turns anims into idle anims by skipping to the end.

    But I've found that the Driver actor is another one of those vital actors that arrive on a net client in a random order through replication, adding to the holy trinity of vehicle, VWPawn and vehwep. Sometimes a VWPawn has it's VehicleBase and Gun, but doesn't yet have the Driver actor - the player pawn. But the delayed Driver replication problem actually affects vehicles more, because a VWPawn already waits until it receives its Gun actor, and that delay is usually enough to coincidentally have received the Driver too - but not always.

    A vehicle doesn't have to wait for a Gun actor to replicate, so SetPlayerPosition() was being called from PostNetBeginPlay, as soon as the actor replicated. That often meant it hadn't received its Driver yet, so the functionality failed.

    The solution is to rely on the vehicle having bDriving=true, which is reliable even if the Driver actor hasn't replicated yet. On a net client, if bDriving is true in PostNetBeginPlay, we now set a new bNeedToInitializeDriver flag. Then in PostNetReceive, we look for the Driver arriving if bNeedToInitializeDriver is set. That becomes the trigger to do any driver-related setup - in this case to call SetPlayerPosition() to play the correct anims on the vehicle & driver. Added same to cannons & MGs, because although they usually work, it's only a coincidence because of the delay waiting for Gun, and sometimes it can go wrong.

    Also, to stop the problem of the DHPawn's StartDriving event overriding the correct Driver anim with the default DriveAnim, I now use bClientPlayedDriveAnim & bClientSkipDriveAnim in DHPawn. StartDriving records that it has played DriveAnim on a net client at least once, so the vehicle knows that it isnt going to get overridden. But if bClientPlayedDriveAnim is false and the vehicle plays a different Driver anim in SetPlayerPosition(), the vehicle flags bClientSkipDriveAnim on the DHPawn. That stops the initial DriveAnim from playing, and is then reset so it has no further effect.

    Finally, where a VWPawn's SetPlayerPosition() detaches & re-attaches the Driver, it now only does so if the DHPawn's StartDriving has flagged bNeedToAttachDriver. DHPawn does that if it failed to attach the driver, because the VWPawn didn't have its Gun actor.

  6. Matt Hands reporter

    Added similar player attachment method to vehicle rider pawn as for other vehicle positions, in commit 38956f3.

    Didn't think this was necessary as rider pawn doesn't have the complication of VehicleWeapon actor. But I noticed an accessed none error pop up in the log, on the rider pawn's VehicleBase. Rider uses modified AttachDriver() function that attaches the player to the VehicleBase instead of the Gun. So a similar problem can arise if the client hasn't received the VehicleBase actor when AttachDriver() gets called.

    Same fix in PostNetReceive() when net client has received both Driver & VehicleBase, but only if AttachDriver() failed & flagged bNeedToAttachDriver.

  7. Log in to comment