Should something like inventory management and SavedMove_Character interact together as best practice?

Hello, this is a sanity check on myself. Input would be appreciated, no pun intended.

Given that a player character may have different items equipped in their inventory that may influences their movement, does it make sense to handle the equipped item change in the SavedMove system?

The setup would be that when equipment would change (keypress for example), it would trigger the Character to tell the movement component to set an id for that item in the inventory. This gets saved SavedMove_Character, along with the logic to copy it into CharacterNetworkMoveData so that it is replicated to the server. Keep in mind: the point of the system is that the server has authority so this “move” is a request from the player and a prediction that it will be accepted by the server. So the client is predicting that their item gets equipped, which will affect any current or future movement that may occur, and the server will receive the “move” which in this context is both any movement AND the item being equipped.
Thus it will be able to perform the exact same change of equipment and movement logic along with propagating that item equip to any other systems (ie replicating it to other connected players) all within the SAME frame. The replication from the server to other players would simply be a property on the actor that the server sets whiles handling the movement. Any corrections that the server needs to make (eg you cannot equip this item) will simply enforce that the MoveResponse to the client is flagged as a bad “move”. This triggers the RPC handling of it on the client to do a correction of position which will be overridden to also support correcting the equipped item(s) the local player has mispredicted, and subsequent unack’ed moves that get replayed back to also handle this correction via overriding SavedMove_Character::PrepMoveFor.

Is this a sound design for UE4+? This is how I’ve implemented it in other engines in the past, similarly anyway, when it comes to predicting movement and swapping actions. It’s just in Unreal Engine 4 weirdly to me there is a very strict dependency between the CharacterMovementComponent and the SavedMove_Character because the Saved"Move" also is equipped to handle more than just movement prediction.

Another example could be abilities. Even if you’re not moving but want to replicate something that is important to client prediction (maybe it will affect movement in the future or to other players? Maybe not?) - it seems best to put it into SavedMove_Character. Am I not mistaken?

For devil’s advocate, let us say that I decided to put the change of equipment “action” into an RPC instead and eliminate everything in the saved move. I’m not aware of any guarantee for order of operations on the server side when that move gets read in versus when the RPC for change of equipment may occur. There’s also the obvious issue of reliability, which move RPCs are not! For example, if I change equipment (RPC A) and move in the same frame (RPC B) locally, the server may process B before A somehow whether there is packet loss or some kind of actor priority setup going wonky even if RPC A is set to be reliable. That would surely interfere with prediction of movement or abilities for players, which moves are not reliable and the equipment change has to be. So in summary, it seems best (to my understanding) to put everything related to prediction, at least as far as possibly determinism for order of operations and potentially affecting movement, in SavedMove_Character.

I wouldn’t mess with SaveMove.
The likelihood of an RPC equipment change resulting in a movement correction is small. Small enough that even if it happened the servers correction would be pixels.

Changes to inventory happen on the server (should be). So locally you shouldn’t be changing equipment, nor any effects (movement) until the server makes the change itself and reps it back to you.

I don’t have any idea as to what type of game you are making, but for sake of discussion lets say an open world shooter.

For this type of game I like to use montages for picking up items. Have an anim notify execute the pickup rpc.

e.g. Pickup input → montage → anim notify → call pickup event.

I don’t worry about dropping. Simple UI drag-n-drop. server response/change is milliseconds.

The same process can be used for equipment swap…say changing weapons. New weapon is heavier, thus making the character move slower (max walk/crouch speed).

input to swap: montage → anim notify → attach weapon → RPC server → end of montage change movement speed (locally).

1 Like

No UI to hide latency and maybe there aren’t any animations to play, ie - the swap is instant and responsive as possible. That would require prediction.

If you’re moving fast, press a button to equip something, you have to predict it if it slows you down (or speeds you up more). You mispredict on the change and every frame of movement compounds the difference up until the server adjustment. Even a reasonable 100ms connection can have a significant banding correction that feels bad after you press the button. Add packet loss to that and you’re teleporting (more than usual anyway). A dropped packet at minimum is rtt + 1/2 rtt delay. maybe even longer in unreal since I’m not familiar with how often it resends reliable rpcs?

I suppose I could arbitrarily add a delay of 100ms to the equipment change before it engages any slowdown, but that impacts responsiveness.

I have a larger concern with order of operations no longer being deterministic (gauranteed ordering) with movement when using the RPC, correct me if I’m wrong. Maybe switching equipment enables you to perform new abilities or affects other ones that you’ve got “queued” as part of a combination of inputs, the RPC for the equipment swap that would enable that input combination could potentially not be received by the time the server processes the input combination.

Random example: Street fighter required Ryu to press another button to switch equipment before performing a hyduken combo. A skilled player would add that extra input to switch equipment into their combination of inputs as fast as possible. Since the RPC for the equipment swap is not related to the move RPC where the input for the hyduken combo is sent, the likely hood of mispredicting is much higher. If anything were to influence the order of sequencing, whether it’s the RPC is dropped but the bundled input the next frame is received (which would lack the RPC), or another player is doing something that would cancel out the hyduken combo, the determinism in the order of input operations is up in the air.

Maybe I switch equipment and input a “defense blocking” combination. Another player could be interfering with me and as a player I wanted my defence to be with my equipment swap. That could spell trouble it feels, but I’ll have to test both methods I guess to truly find out.

My project utilizes server side inventory management and deterministic movement speeds based the item carried and the overall fill capacity (think weight) of inventory. As I add/remove items the movement speed of the character is modified. This is all compounded by stance based speeds (crouch, stand, prone), movement mode (walking, swimming, flying), and then if they are equipped (armed, unarmed, type of item etc). Aiming down sights also has an effect on movement speed, yaw and pitch rotation speeds.

Thus far I haven’t noticed any issues with server corrections. You’ll never get 100% accurate sync with the server.

Fair enough, thanks for the input. there will not be full sync for sure, but trying to keep input and event ordering is really important to me and the experience. I’ve reproduced the issues pretty easily with packet simulation and RPCs so it’s more of a which tool gets the job to reduce it’s impact for players across a wide amount of connection qualities. I assume 150ms and packet loss potential as a base experience to cover a wide audience.

The anim delay you mentioned or an artificial delay covering the RPC ack may be sufficient for some of my cases, and the saved move may be best for the ultra sensitive ones when high speeds are involved. I’ll try a combination of the methods and see how it works out for now! Thanks again.