Revision Difference
Game_Movement#565911
<cat>Dev.GameModes</cat>
Getting your head around how the game movement system works isn't easy. This page will try to clarify on what goes on.
Getting your head around how the game movement system works isn't easy. This page will try to clarify what goes on.
# Client vs Server vs Singleplayer
Clients connected to a server usually use <page>Prediction</page> to guess what the server will do before it actually does it. You should understand how prediction works before continuing, if you are planning to work with multiplayer. For singleplayer, prediction (interpolation) does still apply, since the client can have a framerate faster than the tickrate of the game, but it can otherwise be ignored.
Clients connected to a server usually use <page>Prediction</page> to guess what the server will do before it actually does it. You should understand how prediction works before continuing, if you are planning to work with multiplayer.
⤶
Prediction is disabled in singleplayer, since it isn't necessary to guess what the server will do. Most predicted hooks (i.e., hooks that are called while prediction is running) do not run in singleplayer for this reason.⤶
⤶
Interpolation is used in both singleplayer and multiplayer to smoothly blend game ticks together, since the client can have a framerate faster than the tickrate of the game; it operates separately to prediction, and is how singleplayer gameplay can still be smooth without prediction.⤶
If prediction is disabled in multiplayer, *all client side simulation is disabled*, and you can ignore any parts below that reference it. The user's input and other data is sent to the server, and the client is not updated until it receives the player's new state from the server.
# User Command
The game keeps track of player input via user command (<page>CUserCmd</page>) structure. These structures are built using the player's keys and mouse activity. This user command is then stored in a queue in the engine.
The game keeps track of player input and other state via user command (<page>CUserCmd</page>) structures. These structures are built using the player's keys, mouse activity, position, view angles, velocity, and more. This user command is then stored in a queue in the engine, to later be sent to and played back on the server.
# CreateMove
Every frame, the client runs the CreateMove function internally. This creates a new user command, reads the keyboard and mouse input, transfers that information into the command, and lets the player and other objects run their own internal CreateMove functions to modify that information. Then, control is passed to the <page>GM:CreateMove</page> hook.
This hook runs after all the internal checks and updates have completed, so the command structure should have all the information you need to handle local player input. However, since it only runs on the client, it can be easily overridden. If you rely on the player being in a specific state serverside, you shoud enforce your changes on the server using the next hook instead of this one.
Note this function is not related to <page>CMoveData</page> referenced below, move data has not been set up yet.
Every frame, the client runs the CreateMove function internally. This prepares an empty user command, reads the keyboard and mouse input, transfers that information into the command, and lets the player and other objects run their own internal CreateMove functions to modify that information. Then, control is passed to the <page>GM:CreateMove</page> hook.
This hook runs after all the internal checks and updates have completed, so the command structure should have all the information you need to handle local player input. However, since it only runs on the client, it can be easily overridden. If you rely on the player being in a specific state serverside, you shoud enforce your changes on the server using one of the below hooks instead of this one.
Note the name of this function is not related to <page>CMoveData</page> or similar classes and functions, it is a reference to "player movement" in general and is completely separate to the "move system".
# StartCommand
In a multiplayer game with prediction enabled, some physics, such as player physics, are simulated on the client. This simulation will also predict the results of the queued user commands. The <page>GM:StartCommand</page> hook is what is called internally as the first step of client prediction.
In both singleplayer and multiplayer, non-predicted user commands are sent from the client to the server (your game can be both the client and the server, such as in singleplayer) where StartCommand is again run. This process runs in parallel to client prediction.
In both cases, all available queued user commands are processed sequentially. This hook is a good place to change controls (prevent movement, etc) since everything else down the line depends on what happens here, and it is run on both the client and server which is necessary to prevent clients from bypassing your changes. Note however that doing two different things on the client and server in this hook will result in prediction errors, if the client is predicting.
In both cases, all available queued user commands are processed sequentially. This hook is a good place to change controls (prevent movement, etc) that should apply to both server and client, since everything else down the line depends on what happens here. It's necessary to update both realms since updating only the client (in CreateMove) would allow it to theoretically bypass whatever changes were made before the user command packet is sent to the server.
⤶
Note however that doing two different things on the client and server in this hook will result in prediction errors, if the client is predicting.⤶
# SetupMove
The <page>GM:SetupMove</page> hook is used to transfer data from the user command to a <page>CMoveData</page> structure, and set the origin/velocity of the entity you're moving (probably the player).
**Changes to the user command here are ignored.** Internally, it has already been read and its values used to create the move data. It's still provided as an argument however, to allow you to easily make your own move data modifications based on the user command.
⤶
This is called on the server, and on the client in multiplayer. If prediction is happening properly, then given an identical user command on the client and server, the resulting move data should be identical too.
The <page>GM:SetupMove</page> hook is used to transfer data from the user command to the global <page>CMoveData</page> structure, and set the origin/velocity of the entity you're moving (probably the player).
**Changes to the user command in this hook are ignored.** Internally, it has already been read and its values used to update the move data. It's still provided as an argument however, to allow you to easily make your own move data modifications based on the user command.
⤶
Like StartCommand, this and later move hooks are called on both the server and client. However, unlike StartCommand, they won't be called on the client in singleplayer, since prediction is disabled and the server can be trusted to make timely updates.
⤶
Also like StartCommand, it's important the client and server be doing the same thing, else prediction errors may occur. Given an identical user command, the resulting move data should be identical too, regardless of realm.⤶
# Move
The <page>GM:Move</page> hook does the brunt of the work. Physics calculations, collision checks, and other intensive work should be done here. The results of these checks should be written to the move data structure.
So in this hook you would, for example, look at the MoveData structure, move its origin based on its other factors (buttons down, velocity, etc), while taking into account collision with the floor and walls.
Note that you should *only* change the move data structure, and not the entity that will be moved. This is because these hooks can be called multiple times to work out prediction errors.
Note that you should *only* change the move data structure, and not the entity that will be moved. This is because these hooks can be called multiple times to work out prediction errors. While the engine is handling prediction, entities are moved around by the engine, and many properties will be overwritten when prediction is completed.
```
function GM:Move( ply, mv )
-- Get some variables for easy access
local ang = mv:GetMoveAngles()
local pos = mv:GetOrigin()
-- If Jump is pressed, move pos forwards
if ( mv:KeyDown( IN_JUMP ) ) then pos:Add( ang:Forward() * FrameTime() * 0.001 ) end
-- Save the calculations back into the origin
mv:SetOrigin( pos )
-- Don't do the default
return true
end
```
# FinishMove
The <page>GM:FinishMove</page> hook is where you should apply the changes from the move data onto your entity. Unlike the other hooks which may run multiple times on the client to calculate prediction, this hook is called only once after prediction is completed.
```
function GM:FinishMove( ply, mv )
--
-- Move the player to the worked out position
--
ply:SetNetworkOrigin( mv:GetOrigin() )
-- Don't do the default
return true
end
```
# The Drive System
The <page>drive</page> system was invented to make this all more modular, and make it so you can control not only the player, but other objects too.
Garry's Mod
Rust
Steamworks
Wiki Help