Garry's Mod Wiki

Revision Difference

Prediction#548549

<cat>Dev</cat>⤶ <cat>Dev.GameModes</cat>⤶ Prediction is a technique commonly used in multiplayer games to make the player not feel the lag by simulating their actions as they're sent to the server. For a list of predicted hooks, . # When I shoot at a player, is that prediction? No that’s <page text="lag compensation">Player:LagCompensation</page>, it’s used in conjunction with prediction mainly for weapons. # Why do we need prediction? Without prediction any action the player executes would need to be acknowledged by the server first, and then sent back to the player. With prediction the server validates the commands as usual , but in the mean time allows the player to freely move around the world. # Now explain that to me in layman's terms Basically, if you don't want your weapon or movement system to break for players with high ping ( making their view shake and teleport around ) or whenever there's a connection hiccup, you better have prediction support. # How is it implemented? Every tick, the player generates a <page>CUserCmd</page>, which contains information on what buttons the player pressed and such. As they're sending it to the server, the client starts simulating the movement before a response is received from the server. The global variable <page>Global.CurTime</page>() is always in sync with the server depending on the player’s ping, in general you should use this for anything delay based in prediction. In singleplayer, the client skips the prediction simulation as he’s also the server, so the response time is pretty much nil (however prediction is still applied when hosting a Listen server ). That means that hooks such as <page>GM:Move</page> and <page>WEAPON:PrimaryAttack</page> are **NOT** called clientside in singleplayer, because there’s no need to. The only exception to this rule is <page>WEAPON:Think</page> since Garry added a hack to make it call clientside even in singleplayer. # How powerful is prediction? Prediction does not solve everything, it still has heavy limitations which will only be fixed as internet connections will get better and better. Prediction is here to merely mask them while still trying to provide a smooth experience. For instance, let's say you have a ping of 300 and you're equipped with a shield weapon that requires you to hold the mouse down to gain invulnerability. With prediction you're going to see the effects immediately , but on the server your weapon hasn't done anything yet, due to the packets still arriving. If a player shoots you during that timespan, you're going to die, and the server won't listen to your "but I was shielded already" complaint. # Common Questions ## Why are the clientside predicted hooks called more times than the server ones? Because in order to smooth out the experience the client simulates multiple times at different intervals, interpolating the results. The client doesn’t send all of them though (it mainly depends on the client’s update rate), usually it only sends the first one ( and <page>Global.IsFirstTimePredicted</page> returns true ), the others are for smoothing. ## What is Global.IsFirstTimePredicted? <page>Global.IsFirstTimePredicted</page> returns whether the command from this prediction is going to be sent to the server, if it’s false it means that it’s just one used for smoothing out the simulation, as explained just above. This always returns true serverside, as of course the server has no need to smooth it out. Predicted variables need to be set regardless if the function returns true or false. The function is already used internally for SendWeaponAnim and EmitSound, so you should only use it to encase effect dispatches like this. ``` function SWEP:PrimaryAttack() self:EmitSound( "Weapon_Pistol.Single" ) self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) self:SetNextPrimaryFire( CurTime() + 0.5 ) if ( IsFirstTimePredicted() ) then local effect = EffectData() effect:SetOrigin( self:GetOwner():GetEyeTrace().HitPos ) util.Effect( "Explosion" , effect ) end end ``` Do **NOT** use the function like this. ``` -- THIS IS AN EXAMPLE OF WHAT _NOT_ TO DO function SWEP:PrimaryAttack() if ( not IsFirstTimePredicted() ) then return end self:EmitSound( "Weapon_Pistol.Single" ) self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) self:SetNextPrimaryFire( CurTime() + 0.5 ) local effect = EffectData() effect:SetOrigin( self:GetOwner():GetEyeTrace().HitPos ) util.Effect( "Explosion" , effect ) end ``` This only breaks the prediction on the weapon. ## Why is my weapon glitching out when firing or when the user lags!? You're most likely using timers and/or non networked variables for something that should be predicted. You see, with <page>Entity:NetworkVar</page> the variables will be restored when there's any prediction error. This does **NOT** happen if you use variables such as self.NextFire, which are most likely cause for your prediction errors. ## Can I still use timer.Simple for my burst fire? No , you really shouldn't, just do your logic inside of the weapon’s Think hook instead. Timers are not reliable at all during prediction, and they wouldn't be restored when the server tells you what’s wrong during a prediction error. Also lag compensation **does not work** in a timer, so there's another reason why you shouldn't do that. For instance, here's how you'd replace a timer for an idle animation. ``` function SWEP:SetupDataTables() self:NetworkVar( "Float" , 0 , "NextIdle" ) end function SWEP:Initialize() self:SetNextIdle( 0 ) end function SWEP:PrimaryAttack() self:SetNextPrimaryFire( CurTime() + 1 ) self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) self:SetNextIdle( CurTime() + self:SequenceDuration() ) end function SWEP:Think() if self:GetNextIdle() ~= 0 and self:GetNextIdle() < CurTime() then self:SendWeaponAnim( ACT_VM_IDLE ) self:SetNextIdle( 0 ) end end ``` ## That's stupid, it's redundant code, timers are like 1 line of code! Timers already work like that internally, except in this case they would have prediction support. ## Isn't it expensive to have multiple checks like that in a think hook? No, comparing two floats is nothing compared to firing a trace in a HUDDraw hook. ## What is Global.SuppressHostEvents? This function prevents the player from receiving duplicated effects during prediction. When you're doing a weapon attack you're going to emit an effect ( for instance the explosion from the example above ) on both client and server. For other players, these are only going to be sent once, but since the predicting player is also emitting those on his client, the server prevents that from happening by discarding whatever the player is about to send to himself during that attack. However, this can also be done using the <page>CRecipientFilter</page> feature of <page>util.Effect</page>, adding the players by PVS and only removing the owner of the weapon on the server. **<page>Global.SuppressHostEvents</page> already encases predicted weapon calls such as <page>WEAPON:PrimaryAttack</page> and <page>WEAPON:Think</page>, and you shouldn't need to use it.** ## What should be called serverside and what shouldn’t with prediction? This depends mostly on what you’re doing, if you’re creating an entity, that should obviously be only serverside. If you’re affecting other entities like doors and other players then that should be serverside as well. If you’re affecting an entity that has <page>Entity:SetPredictable</page> enabled (which is the normal case for weapons, and entities used in the drive system garry made), such as modifying the internal or custom DT vars then that should be shared. # Useful commands `cl_showerror` (doesn’t require cheats, takes 0,1,2) Shows prediction errors caused by an entity, setting it to 1 shows the messages on the player’s hud on the top right (where the old Lua errors hud used to be). Setting it to 2 is what you generally want, it enables the printing of the error, the affected variable and the difference from the server. `cl_predictionlist` (requires cheats, takes 0 or 1) Shows all the entities currently being predicted on the client, entity index, classname and it's origin ( either predicted or client created) It's not that useful alone though. `cl_pdump` (requires cheats, takes an entity index number) Shows all the dt vars currently being networked to the client, there's a legend on the bottom right. # Prediction examples There will be some prediction examples linked down below at some point. This will be filled when I get some good examples. For movement related stuff, read the <page>Game Movement</page> page