Garry's Mod Wiki

Revision Difference

Game_Movement#565179

<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. # User Command ⤶ ⤶ The client creates a user command (<page>CUserCmd</page>) which is created by looking at the player's keys and mouse activity. This is done in the <page>GM:CreateMove</page> and <page>GM:StartCommand</page> hooks. ⤶ This user command is then sent to the server where StartCommand is again run. In a multiplayer game the user command is also used directly locally to predict the player's movement. ⤶ StartCommand is a good place to change controls (prevent movement, etc) since everything else down the line depends on what happens there and it is run on both the client and server which is necessary to prevent clients from bypassing your changes.⤶ ⤶ ⤶ # 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). The CUserCmd here has already been used to make the CMoveData, editing the CUserCmd here for movement wont do anything as the engine already used it. It's passed through to write your own CMoveData modifications based on the CUserCmd. This is called on the server - and also in multiplayer - on the client. If prediction is happening properly then given an identical user command on client/server - the outputted move data should be identical too. # 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. ⤶ 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.⤶ ⤶ # 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.⤶ ⤶ # 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.⤶ ⤶ # 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.⤶ # Move The <page>GM:Move</page> hook does the brunt of the work. It should `only` change the move data structure. This is because SetupMove and Move can be called multiple times to work out prediction errors. So in this hook you would look at the MoveData structure, move its origin based on its other factors (buttons down, velocity etc). You'd also be doing things like collision detection here. 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.⤶ ``` 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. ⤶ ⤶ ```⤶ 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. 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.