Announcement

Collapse
No announcement yet.

Networked "Physics-Vehicle Movement Component": existing examples or implementation hints?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    #16
    Not solved yet, currently working on a Radar system before coming back to this... needed a break The code above is part of a pretty basic PawnMovementComponent of my own, though honestly what I've done could just be done as part of the Pawn right now. I just wasn't sure how tarted up it was going to get, especially when it comes to pathing and prediction etc.

    You're pretty much right, the Replicated Movement and Client simulation are fighting each other, which is why I get the latency from the controls. Other than that though, it all works. The trick is that the Physics function is being called on tick both Client & Server side, so that keeps them from going out of sync since velocity and angular velocity are always being updated. I also handle damping and drag in there as well, so when a collision happens, the drag affects the calculation on both ends and causes position/rotation updates to be sent out from the server, causing them to remain in sync. If I switch off the movement simulation and a collision occurs client-side, they stay out of sync until the server sends a position update.

    I really want to look more into CMC's system, since I want to implement based-movement (e.g., moving with the object I'm hovering on) and imparted velocity. This is still just the beginning Any progress I make though, I'll post here in one form or another!

    Unfortunately since Unreal doesn't use deterministic / seeded physics, I have to use replicated movement or otherwise I just risk client-side collisions not being handled the same way.

    Comment


      #17
      Originally posted by TheJamsh View Post
      Not solved yet, currently working on a Radar system before coming back to this... needed a break The code above is part of a pretty basic PawnMovementComponent of my own, though honestly what I've done could just be done as part of the Pawn right now. I just wasn't sure how tarted up it was going to get, especially when it comes to pathing and prediction etc.

      You're pretty much right, the Replicated Movement and Client simulation are fighting each other, which is why I get the latency from the controls. Other than that though, it all works. The trick is that the Physics function is being called on tick both Client & Server side, so that keeps them from going out of sync since velocity and angular velocity are always being updated. I also handle damping and drag in there as well, so when a collision happens, the drag affects the calculation on both ends and causes position/rotation updates to be sent out from the server, causing them to remain in sync. If I switch off the movement simulation and a collision occurs client-side, they stay out of sync until the server sends a position update.

      I really want to look more into CMC's system, since I want to implement based-movement (e.g., moving with the object I'm hovering on) and imparted velocity. This is still just the beginning Any progress I make though, I'll post here in one form or another!

      Unfortunately since Unreal doesn't use deterministic / seeded physics, I have to use replicated movement or otherwise I just risk client-side collisions not being handled the same way.
      Okay thanks, I'll have to spend some time parsing this thread and your post.

      How have you setup your component hierarchy for the hover tanks, and how do you ensure that they rotate around the right point? For reference, when I apply torque to my root bone: http://i.gyazo.com/542581caffce3ab890b2c906e9829f94.gif Just wondering if your tanks are skeletal/static meshes attached to a basic sphere or something, and then offset, with the torque/force added to that sphere rather than the mesh, so you can tweak the point around which it rotates? Not sure which way to go with this part.

      EDIT: The above was made in a rush, hope it makes sense. I ask only because your project is an example of the type of physics-driven movement not many are doing. The rotation in my gif is how it used to work in my old game, and it'd be a nice thing to fix
      Last edited by HateDread; 07-11-2015, 05:31 AM.

      Comment


        #18
        The root object of my Tanks are the meshes themselves, so there's no trickery

        What I do is multiply my Torque / Angular velocity values by the Front, Right and Up vectors (depending which axis I want to rotate around), which ensures it always pivots around it's correct axes, and also prevents any 'gimbal lock' issues that you'd otherwise have to use Quats for. In the example code above for example:

        Code:
        Alpha += Up * SteerVal;
        I'm adding to Angular Acceleration (Alpha) here, which is just the Up axis of the actor (well, the UpdatedComponent) multiplied by whatever the steer value currently is (pretty much straight off of the mouse).

        I get the axes like this btw (every frame):

        Code:
                FVector Front = UpdatedPrimitive->GetForwardVector();
        	FVector Right = UpdatedPrimitive->GetRightVector();
        	FVector Up = UpdatedPrimitive->GetUpVector();

        Comment


          #19
          Originally posted by TheJamsh View Post
          The root object of my Tanks are the meshes themselves, so there's no trickery

          What I do is multiply my Torque / Angular velocity values by the Front, Right and Up vectors (depending which axis I want to rotate around), which ensures it always pivots around it's correct axes, and also prevents any 'gimbal lock' issues that you'd otherwise have to use Quats for. In the example code above for example:

          Code:
          Alpha += Up * SteerVal;
          I'm adding to Angular Acceleration (Alpha) here, which is just the Up axis of the actor (well, the UpdatedComponent) multiplied by whatever the steer value currently is (pretty much straight off of the mouse).

          I get the axes like this btw (every frame):

          Code:
                  FVector Front = UpdatedPrimitive->GetForwardVector();
          	FVector Right = UpdatedPrimitive->GetRightVector();
          	FVector Up = UpdatedPrimitive->GetUpVector();
          Okay cool. Just thought you might've done so to make your tanks rotate as desired. Any tips for configuring pawn/mesh rotation? As in, center of mass / axis of rotation stuff.

          Just looking into making my own pawn movement component, and looking at the character's; it doesn't seem to itself be replicated? I would've thought it'd be receiving RPCs and replicated variables in order to handle it internally and adjust the character's position, but it seems not! Seems totally crazy to me. Am I right in thinking that the the pawn/character should handle the RPC/replication, and then hand that off to the movement component to let it do correction/smoothing?

          Comment


            #20
            Originally posted by HateDread View Post
            Okay cool. Just thought you might've done so to make your tanks rotate as desired. Any tips for configuring pawn/mesh rotation? As in, center of mass / axis of rotation stuff.
            Not really! I made the Center of my mesh at 0, 0, 0 in the model which works well for me!

            Originally posted by HateDread View Post
            Just looking into making my own pawn movement component, and looking at the character's; it doesn't seem to itself be replicated? I would've thought it'd be receiving RPCs and replicated variables in order to handle it internally and adjust the character's position, but it seems not! Seems totally crazy to me. Am I right in thinking that the the pawn/character should handle the RPC/replication, and then hand that off to the movement component to let it do correction/smoothing?
            It's been a while since I looked but you might be right, the issue is that Clients can only call RPCS on objects that they 'Own'. However I have been sending RPC's in a component of my own in another case without issue, so I think so long as you own the Actor that owns the Component, you're fine. It might just be the way they did it since it worked better for them, or possibly when they implemented it, you couldn't call RPC's on Actor Components! No idea on that one though...

            Comment


              #21
              Originally posted by TheJamsh View Post
              Not really! I made the Center of my mesh at 0, 0, 0 in the model which works well for me!



              It's been a while since I looked but you might be right, the issue is that Clients can only call RPCS on objects that they 'Own'. However I have been sending RPC's in a component of my own in another case without issue, so I think so long as you own the Actor that owns the Component, you're fine. It might just be the way they did it since it worked better for them, or possibly when they implemented it, you couldn't call RPC's on Actor Components! No idea on that one though...
              Ahh yeah fair call.

              I've been looking into client-side prediction and server reconciliation for physics-based games in UE4, and it's been pretty difficult.

              For example, when you receive an authoritative update from the server, you'd need to roll-back to it and re-simulate your inputs from that time onwards. How are you doing this in your game? I got it working by using my own physics (i.e. something dumb like position += velocity * DeltaSeconds) and a fixed timestep (DeltaSeconds in that formula is always 0.016666666f or similar). It'd be nice to use PhysX for this, but I couldn't see a way to manually resimulate x number of physics frames within one Tick, and physics updates are occurring at different rates/timesteps due to variable framerates between server and client. Because of this, the server and client should often disagree about where the client should end up, and so you'd often be correcting the results on the client's end.

              Would be interesting to hear how you've gone!

              Comment


                #22
                Yeah see that's where my problem comes from. In my example it's technically already doing the 'prediction' client-side, since the client moves to a location instantly (in theory anyway) and the Server does the same with the same input data, albeit a few milliseconds later (in LAN at least).

                The server does the move then hard-sets the location on the Client, so in theory they should be 'close' to in-sync so the player won't notice the discrepancy. Over a network connection my example probably isn't going to hold up.

                Unfortunately since Unreal doesn't use Deterministic Physics (which I can understand, since it's bloody hard), it's also impossible to completely leave the movement up to the physics engine and just provide input in the hope they will remain the same. Even with the same fixed time-step and latency offsets, you'll still get slight differences. Especially when collisions occur too. I figured that the replication code for WheeledVehicleMovement would hold up but unfortunately I don't think it will for very long, especially when I'm not testing via LAN or on the same PC.

                I will start work on this again soon, since I'd like to get a demo of my game out asap. Unfortunately Quadtrees are taking up my time atm

                Comment


                  #23
                  Originally posted by TheJamsh View Post
                  Yeah see that's where my problem comes from. In my example it's technically already doing the 'prediction' client-side, since the client moves to a location instantly (in theory anyway) and the Server does the same with the same input data, albeit a few milliseconds later (in LAN at least).

                  The server does the move then hard-sets the location on the Client, so in theory they should be 'close' to in-sync so the player won't notice the discrepancy. Over a network connection my example probably isn't going to hold up.

                  Unfortunately since Unreal doesn't use Deterministic Physics (which I can understand, since it's bloody hard), it's also impossible to completely leave the movement up to the physics engine and just provide input in the hope they will remain the same. Even with the same fixed time-step and latency offsets, you'll still get slight differences. Especially when collisions occur too. I figured that the replication code for WheeledVehicleMovement would hold up but unfortunately I don't think it will for very long, especially when I'm not testing via LAN or on the same PC.

                  I will start work on this again soon, since I'd like to get a demo of my game out asap. Unfortunately Quadtrees are taking up my time atm
                  Yepp, that'll fall apart in some LAN configurations - when I was developing my old space game, I had a lot of problems with packet ordering (it was at a college, with an 'interesting' setup that ran all connections through several firewalls and routers elsewhere in the building and then back). If you just hard-set your positions, that's gonna get gross. It will be impossible over the internet.

                  The idea isn't that the server and client are absolutely matched and deterministic when it comes to physics simulations. Instead, you just want to get them as close as possible.
                  When you 'provide' the input to the server, you include the timestamp the input was recorded, as well as storing that input in a local buffer. When the server sends back physics info, it includes that timestamp, as if to say "here's your new physics data, and THIS is the latest input I've processed from you". The client gets this info, and uses that position as the starting point, resimulating every input in the buffer from that returned timestamp onwards. The position after the input is all resimulated is where the client 'should' be. The difference between where it originally thought it should be and that position that it calculates from the input buffer needs to be as small as possible - you'll end up lerping between them to cover any slight mistakes.

                  Hopefully that makes sense. It's a more clumsy description of client-side prediction and server reconciliation than what's available here.

                  Comment


                    #24
                    You've probably seen this already btw, but Rama has put up a post on how he handled replicated Physics movement. I'm going to snoop over his code tonight and see how it all works.

                    https://forums.unrealengine.com/show...lating-Physics!

                    Comment


                      #25
                      Originally posted by TheJamsh View Post
                      You've probably seen this already btw, but Rama has put up a post on how he handled replicated Physics movement. I'm going to snoop over his code tonight and see how it all works.

                      https://forums.unrealengine.com/show...lating-Physics!
                      Yeah I've seen that before. Isn't it client-authoritative? If it's just talking about the physics of others in the world around you... that ain't so hard Even good ol' buffer interpolation will get you there. The trick is server-authoritative physics without having the local client feel like ****.

                      EDIT: He's not wrong with the applying impulses part, though. Jump down to 'Network Physics' and you'll see that Nvidia recommends that approach over setting a position. Just gotta weigh the cost of that against a simple interpolation.
                      Last edited by HateDread; 07-21-2015, 06:50 AM.

                      Comment


                        #26
                        Yeah I just read over the code and unfortunately it does mean that it's client-authoritative - which is fine for most people but for anything AAA or with a focus on Multiplayer it's probably going to invite cheating. Also means it's probably not suitable for me...

                        Thanks for that link from nVidia, that's actually pretty useful! Never really considered that SetActorPosition() would cause it to be re-inserted into the broadphase collision check but that makes perfect sense really. It also looks as if they're saying that using AngularVelocity to drive the updates. I guess this is because it's more likely to change between updates than the other factors. One slight caveat of nVidia's notes there is that it requires the latency of your packets (easy enough to get in Unreal mind, UT already does that in it's PlayerController) - and you need to maintain your FPS while those corrections are taking place too which is probably the biggest hit. This does mean locking your frame rate most likely unless you can get the system to work with variable FPS. Mind you, if FPS is varying by that much at the time anyway I doubt the slight movement or jitter of your craft or pawn is going to be the most noticeable artefact.

                        In my somewhat unique case, I HAVE to send the input from the keyboard anyway because it's used to drive other effects like Particles (engine thrusters etc) and audio for the engine for other players. That's fine though since that can be made an unreliable RPC, and I'm hoping that I can massively quantize that data and pack it into a tiny cost for replication. That overhead is probably minimal if anything.

                        This is certainly an interesting problem...

                        Comment


                          #27
                          Originally posted by TheJamsh View Post
                          Yeah I just read over the code and unfortunately it does mean that it's client-authoritative - which is fine for most people but for anything AAA or with a focus on Multiplayer it's probably going to invite cheating. Also means it's probably not suitable for me...

                          Thanks for that link from nVidia, that's actually pretty useful! Never really considered that SetActorPosition() would cause it to be re-inserted into the broadphase collision check but that makes perfect sense really. It also looks as if they're saying that using AngularVelocity to drive the updates. I guess this is because it's more likely to change between updates than the other factors. One slight caveat of nVidia's notes there is that it requires the latency of your packets (easy enough to get in Unreal mind, UT already does that in it's PlayerController) - and you need to maintain your FPS while those corrections are taking place too which is probably the biggest hit. This does mean locking your frame rate most likely unless you can get the system to work with variable FPS. Mind you, if FPS is varying by that much at the time anyway I doubt the slight movement or jitter of your craft or pawn is going to be the most noticeable artefact.

                          In my somewhat unique case, I HAVE to send the input from the keyboard anyway because it's used to drive other effects like Particles (engine thrusters etc) and audio for the engine for other players. That's fine though since that can be made an unreliable RPC, and I'm hoping that I can massively quantize that data and pack it into a tiny cost for replication. That overhead is probably minimal if anything.

                          This is certainly an interesting problem...
                          I'm not sure where you got the "One slight caveat of nVidia's notes there is that it requires the latency of your packets (easy enough to get in Unreal mind, UT already does that in it's PlayerController) - and you need to maintain your FPS while those corrections are taking place" parts, though. Why is it that your FPS needs to be constant?

                          And you should be sending your input anyway - that's how you drive the physics on the server from the client! You send the inputs whilst simulating them yourself, and the server simulates them once it receives them.

                          Comment


                            #28
                            Well according to their suggestion/implementation as I understand it, if a packet is delayed by say 250 ms - at that point in their example the car could be far enough away from the correct position that moving it over too few frames would break the illusion, and doing it over too many frames would mean that you'll still be blending to the old position when you get the next packet, so you'll constantly be slightly out of sync if you don't time the blending between packet updates. It could become that you're actually never in the right position for any of those frames because you're spending all your time blending to the next packet.

                            The idea is that they work out how long they have to blend to the correct position over time so that it's a) smooth and b) accurate. Divide 250ms / 60 frames and you get 15 frames to perform the update, so you blend to the position over the next 15 frames, at which point you should have the next packet of data. Problem is that if your framerate isn't pretty consistent and your latency isn't either, you'll never really get the 'time I have to blend' correct.

                            Really this isn't a problem since if you're shipping something, it nearly always makes sense to lock the framerate anyway (which BTW drives me insane when people complain about capping at 60 in some games). Most people probably have a stable enough connection that packet latency will stay fairly constant for a game session anyway too. There will definitely be some slight discrepancies though.

                            Also, correct on the input. I got confused looking at Rama's implementation and this one at the same time

                            Comment


                              #29
                              Originally posted by TheJamsh View Post
                              Well according to their suggestion/implementation as I understand it, if a packet is delayed by say 250 ms - at that point in their example the car could be far enough away from the correct position that moving it over too few frames would break the illusion, and doing it over too many frames would mean that you'll still be blending to the old position when you get the next packet, so you'll constantly be slightly out of sync if you don't time the blending between packet updates. It could become that you're actually never in the right position for any of those frames because you're spending all your time blending to the next packet.

                              The idea is that they work out how long they have to blend to the correct position over time so that it's a) smooth and b) accurate. Divide 250ms / 60 frames and you get 15 frames to perform the update, so you blend to the position over the next 15 frames, at which point you should have the next packet of data. Problem is that if your framerate isn't pretty consistent and your latency isn't either, you'll never really get the 'time I have to blend' correct.

                              Really this isn't a problem since if you're shipping something, it nearly always makes sense to lock the framerate anyway (which BTW drives me insane when people complain about capping at 60 in some games). Most people probably have a stable enough connection that packet latency will stay fairly constant for a game session anyway too. There will definitely be some slight discrepancies though.

                              Also, correct on the input. I got confused looking at Rama's implementation and this one at the same time
                              Hmm, I haven't gotten that far in, although I feel like our games wouldn't necessarily need it - you can just use the ol' Entity Interpolation method (my goal), for example, and smoothly interpolate (even using splines with velocities as part of the control points). Cars would definitely be harder, since it's more difficult to seem realistic if they 'correct' from one position to another, particularly horizontally - my space ships and your hover tanks kinda move that way already.

                              The more I look into methods like the above, and considerations such as fixed timestep physics, having a synced network time for the interpolation buffer, and so on, the more I realize we're gonna need to get in there in the engine and make some changes. First, though, how are you guys all handling the movement of other players? I know you haven't done it over the internet yet, TheJamsh, but you have, piinecone, and I'd be interested in how.

                              Tough stuff!

                              Comment


                                #30
                                Sorry I've been a bit quiet in my own thread - I have some research deadlines (plus wedding + honeymoon) that have been eating up my time. I'm glad to see this discussion going though.

                                TheJamsh - my recollection is that it will be helpful for you to look into CMC for another reason, which is I think they have some code to resolve the replication/prediction fighting. Something along the lines of replication being applied to a proxy rather than the local physics object. (Unless I'm completely forgetting which codebase I saw that in, which is possible, since it's been a while since I looked at this first hand).

                                Comment

                                Working...
                                X